@checkstack/healthcheck-common 0.0.2 → 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/CHANGELOG.md +60 -0
- package/package.json +1 -1
- package/src/index.ts +3 -0
- package/src/rpc-contract.ts +13 -0
- package/src/schemas.ts +64 -0
- package/src/zod-health-result.ts +67 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# @checkstack/healthcheck-common
|
|
2
2
|
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- f5b1f49: Extended health check system with per-collector assertion support.
|
|
8
|
+
|
|
9
|
+
- Added `collectors` column to `healthCheckConfigurations` schema for storing collector configs
|
|
10
|
+
- Updated queue-executor to run configured collectors and evaluate per-collector assertions
|
|
11
|
+
- Added `CollectorAssertionSchema` to healthcheck-common for assertion validation
|
|
12
|
+
- Results now stored with `metadata.collectors` containing per-collector result data
|
|
13
|
+
|
|
14
|
+
- f5b1f49: Added JSONPath assertions for response body validation and fully qualified strategy IDs.
|
|
15
|
+
|
|
16
|
+
**JSONPath Assertions:**
|
|
17
|
+
|
|
18
|
+
- Added `healthResultJSONPath()` factory in healthcheck-common for fields supporting JSONPath queries
|
|
19
|
+
- Extended AssertionBuilder with jsonpath field type showing path input (e.g., `$.data.status`)
|
|
20
|
+
- Added `jsonPath` field to `CollectorAssertionSchema` for persistence
|
|
21
|
+
- HTTP Request collector body field now supports JSONPath assertions
|
|
22
|
+
|
|
23
|
+
**Fully Qualified Strategy IDs:**
|
|
24
|
+
|
|
25
|
+
- HealthCheckRegistry now uses scoped factories like CollectorRegistry
|
|
26
|
+
- Strategies are stored with `pluginId.strategyId` format
|
|
27
|
+
- Added `getStrategiesWithMeta()` method to HealthCheckRegistry interface
|
|
28
|
+
- Router returns qualified IDs so frontend can correctly fetch collectors
|
|
29
|
+
|
|
30
|
+
**UI Improvements:**
|
|
31
|
+
|
|
32
|
+
- Save button disabled when collector configs have invalid required fields
|
|
33
|
+
- Fixed nested button warning in CollectorList accordion
|
|
34
|
+
|
|
35
|
+
### Patch Changes
|
|
36
|
+
|
|
37
|
+
- Updated dependencies [f5b1f49]
|
|
38
|
+
- @checkstack/common@0.0.3
|
|
39
|
+
- @checkstack/signal-common@0.0.3
|
|
40
|
+
|
|
41
|
+
## 0.0.3
|
|
42
|
+
|
|
43
|
+
### Patch Changes
|
|
44
|
+
|
|
45
|
+
- cb82e4d: Improved `counter` and `pie` auto-chart types to show frequency distributions instead of just the latest value. Both chart types now count occurrences of each unique value across all runs/buckets, making them more intuitive for visualizing data like HTTP status codes.
|
|
46
|
+
|
|
47
|
+
Changed HTTP health check chart annotations: `statusCode` now uses `pie` chart (distribution view), `contentType` now uses `counter` chart (frequency count).
|
|
48
|
+
|
|
49
|
+
Fixed scrollbar hopping when health check signals update the accordion content. All charts now update silently without layout shift or loading state flicker.
|
|
50
|
+
|
|
51
|
+
Refactored health check visualization architecture:
|
|
52
|
+
|
|
53
|
+
- `HealthCheckStatusTimeline` and `HealthCheckLatencyChart` now accept `HealthCheckDiagramSlotContext` directly, handling data transformation internally
|
|
54
|
+
- `HealthCheckDiagram` refactored to accept context from parent, ensuring all visualizations share the same data source and update together on signals
|
|
55
|
+
- `HealthCheckSystemOverview` simplified to use `useHealthCheckData` hook for consolidated data fetching with automatic signal-driven refresh
|
|
56
|
+
|
|
57
|
+
Added `silentRefetch()` method to `usePagination` hook for background data refreshes without showing loading indicators.
|
|
58
|
+
|
|
59
|
+
Fixed `useSignal` hook to use a ref pattern internally, preventing stale closure issues. Callbacks now always access the latest values without requiring manual memoization or refs in consumer components.
|
|
60
|
+
|
|
61
|
+
Added signal handling to `useHealthCheckData` hook for automatic chart refresh when health check runs complete.
|
|
62
|
+
|
|
3
63
|
## 0.0.2
|
|
4
64
|
|
|
5
65
|
### Patch Changes
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -15,6 +15,8 @@ export interface HealthCheckStrategyDto {
|
|
|
15
15
|
configSchema: Record<string, unknown>;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
import type { CollectorConfigEntry } from "./schemas";
|
|
19
|
+
|
|
18
20
|
/**
|
|
19
21
|
* Represents a Health Check Configuration (the check definition/template).
|
|
20
22
|
* NOTE: This is derived from Zod schema but kept as interface for explicit type documentation.
|
|
@@ -25,6 +27,7 @@ export interface HealthCheckConfiguration {
|
|
|
25
27
|
strategyId: string;
|
|
26
28
|
config: Record<string, unknown>;
|
|
27
29
|
intervalSeconds: number;
|
|
30
|
+
collectors?: CollectorConfigEntry[];
|
|
28
31
|
createdAt: Date;
|
|
29
32
|
updatedAt: Date;
|
|
30
33
|
}
|
package/src/rpc-contract.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { z } from "zod";
|
|
|
8
8
|
import { permissions } from "./permissions";
|
|
9
9
|
import {
|
|
10
10
|
HealthCheckStrategyDtoSchema,
|
|
11
|
+
CollectorDtoSchema,
|
|
11
12
|
HealthCheckConfigurationSchema,
|
|
12
13
|
CreateHealthCheckConfigurationSchema,
|
|
13
14
|
UpdateHealthCheckConfigurationSchema,
|
|
@@ -53,6 +54,18 @@ export const healthCheckContract = {
|
|
|
53
54
|
})
|
|
54
55
|
.output(z.array(HealthCheckStrategyDtoSchema)),
|
|
55
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Get available collectors for a specific strategy.
|
|
59
|
+
* Returns collectors that support the given strategy's transport.
|
|
60
|
+
*/
|
|
61
|
+
getCollectors: _base
|
|
62
|
+
.meta({
|
|
63
|
+
userType: "authenticated",
|
|
64
|
+
permissions: [permissions.healthCheckRead.id],
|
|
65
|
+
})
|
|
66
|
+
.input(z.object({ strategyId: z.string() }))
|
|
67
|
+
.output(z.array(CollectorDtoSchema)),
|
|
68
|
+
|
|
56
69
|
// ==========================================================================
|
|
57
70
|
// CONFIGURATION MANAGEMENT (userType: "authenticated")
|
|
58
71
|
// ==========================================================================
|
package/src/schemas.ts
CHANGED
|
@@ -13,21 +13,85 @@ export const HealthCheckStrategyDtoSchema = z.object({
|
|
|
13
13
|
aggregatedResultSchema: z.record(z.string(), z.unknown()).optional(),
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
+
export type HealthCheckStrategyDto = z.infer<
|
|
17
|
+
typeof HealthCheckStrategyDtoSchema
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Collector DTO for frontend discovery.
|
|
22
|
+
* ID is fully-qualified: `pluginId.collectorId` (e.g., `collector-hardware.cpu`)
|
|
23
|
+
*/
|
|
24
|
+
export const CollectorDtoSchema = z.object({
|
|
25
|
+
/** Fully-qualified ID: pluginId.collectorId */
|
|
26
|
+
id: z.string(),
|
|
27
|
+
/** Human-readable name */
|
|
28
|
+
displayName: z.string(),
|
|
29
|
+
/** Optional description */
|
|
30
|
+
description: z.string().optional(),
|
|
31
|
+
/** JSON Schema for collector configuration */
|
|
32
|
+
configSchema: z.record(z.string(), z.unknown()),
|
|
33
|
+
/** JSON Schema for per-run result metadata (with chart annotations) */
|
|
34
|
+
resultSchema: z.record(z.string(), z.unknown()),
|
|
35
|
+
/** Whether multiple instances of this collector are allowed per config */
|
|
36
|
+
allowMultiple: z.boolean(),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export type CollectorDto = z.infer<typeof CollectorDtoSchema>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A single collector assertion with field, operator, and optional value.
|
|
43
|
+
*/
|
|
44
|
+
export const CollectorAssertionSchema = z.object({
|
|
45
|
+
/** Field path to assert on (from collector result schema) */
|
|
46
|
+
field: z.string(),
|
|
47
|
+
/** JSONPath expression for jsonpath-type assertions (e.g., $.status) */
|
|
48
|
+
jsonPath: z.string().optional(),
|
|
49
|
+
/** Comparison operator */
|
|
50
|
+
operator: z.string(),
|
|
51
|
+
/** Expected value (not needed for some operators like exists, isTrue) */
|
|
52
|
+
value: z.unknown().optional(),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export type CollectorAssertion = z.infer<typeof CollectorAssertionSchema>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* A collector configuration entry within a health check.
|
|
59
|
+
* Each entry includes the collector ID, its config, and per-collector assertions.
|
|
60
|
+
*/
|
|
61
|
+
export const CollectorConfigEntrySchema = z.object({
|
|
62
|
+
/** Fully-qualified collector ID (e.g., collector-hardware.cpu) */
|
|
63
|
+
collectorId: z.string(),
|
|
64
|
+
/** Collector-specific configuration */
|
|
65
|
+
config: z.record(z.string(), z.unknown()),
|
|
66
|
+
/** Per-collector assertions (schema derived from collector's resultSchema) */
|
|
67
|
+
assertions: z.array(CollectorAssertionSchema).optional(),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export type CollectorConfigEntry = z.infer<typeof CollectorConfigEntrySchema>;
|
|
71
|
+
|
|
16
72
|
export const HealthCheckConfigurationSchema = z.object({
|
|
17
73
|
id: z.string(),
|
|
18
74
|
name: z.string(),
|
|
19
75
|
strategyId: z.string(),
|
|
20
76
|
config: z.record(z.string(), z.unknown()),
|
|
21
77
|
intervalSeconds: z.number(),
|
|
78
|
+
/** Optional collector configurations */
|
|
79
|
+
collectors: z.array(CollectorConfigEntrySchema).optional(),
|
|
22
80
|
createdAt: z.date(),
|
|
23
81
|
updatedAt: z.date(),
|
|
24
82
|
});
|
|
25
83
|
|
|
84
|
+
export type HealthCheckConfiguration = z.infer<
|
|
85
|
+
typeof HealthCheckConfigurationSchema
|
|
86
|
+
>;
|
|
87
|
+
|
|
26
88
|
export const CreateHealthCheckConfigurationSchema = z.object({
|
|
27
89
|
name: z.string().min(1),
|
|
28
90
|
strategyId: z.string().min(1),
|
|
29
91
|
config: z.record(z.string(), z.unknown()),
|
|
30
92
|
intervalSeconds: z.number().min(1),
|
|
93
|
+
/** Optional collector configurations */
|
|
94
|
+
collectors: z.array(CollectorConfigEntrySchema).optional(),
|
|
31
95
|
});
|
|
32
96
|
|
|
33
97
|
export type CreateHealthCheckConfiguration = z.infer<
|
package/src/zod-health-result.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { z } from "zod";
|
|
|
10
10
|
* Numeric types:
|
|
11
11
|
* - line: Time series line chart for numeric metrics over time
|
|
12
12
|
* - bar: Bar chart for distributions (record of string to number)
|
|
13
|
+
* - pie: Pie chart for category distributions (record of string to number)
|
|
13
14
|
* - counter: Simple count display with trend indicator
|
|
14
15
|
* - gauge: Percentage gauge for rates/percentages (0-100)
|
|
15
16
|
*
|
|
@@ -21,6 +22,7 @@ import { z } from "zod";
|
|
|
21
22
|
export type ChartType =
|
|
22
23
|
| "line"
|
|
23
24
|
| "bar"
|
|
25
|
+
| "pie"
|
|
24
26
|
| "counter"
|
|
25
27
|
| "gauge"
|
|
26
28
|
| "boolean"
|
|
@@ -38,6 +40,8 @@ export interface HealthResultMeta {
|
|
|
38
40
|
"x-chart-label"?: string;
|
|
39
41
|
/** Unit suffix for values (e.g., 'ms', '%', 'req/s') */
|
|
40
42
|
"x-chart-unit"?: string;
|
|
43
|
+
/** Whether this field supports JSONPath assertions */
|
|
44
|
+
"x-jsonpath"?: boolean;
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
/**
|
|
@@ -50,6 +54,9 @@ export const healthResultRegistry = z.registry<HealthResultMeta>();
|
|
|
50
54
|
// TYPED HEALTH RESULT FACTORIES
|
|
51
55
|
// ============================================================================
|
|
52
56
|
|
|
57
|
+
/** Chart metadata (excludes x-jsonpath, use healthResultJSONPath for that) */
|
|
58
|
+
type ChartMeta = Omit<HealthResultMeta, "x-jsonpath">;
|
|
59
|
+
|
|
53
60
|
/**
|
|
54
61
|
* Create a health result string field with typed chart metadata.
|
|
55
62
|
*
|
|
@@ -62,7 +69,7 @@ export const healthResultRegistry = z.registry<HealthResultMeta>();
|
|
|
62
69
|
* });
|
|
63
70
|
* ```
|
|
64
71
|
*/
|
|
65
|
-
export function healthResultString(meta:
|
|
72
|
+
export function healthResultString(meta: ChartMeta) {
|
|
66
73
|
const schema = z.string();
|
|
67
74
|
schema.register(healthResultRegistry, meta);
|
|
68
75
|
return schema;
|
|
@@ -71,7 +78,7 @@ export function healthResultString(meta: HealthResultMeta) {
|
|
|
71
78
|
/**
|
|
72
79
|
* Create a health result number field with typed chart metadata.
|
|
73
80
|
*/
|
|
74
|
-
export function healthResultNumber(meta:
|
|
81
|
+
export function healthResultNumber(meta: ChartMeta) {
|
|
75
82
|
const schema = z.number();
|
|
76
83
|
schema.register(healthResultRegistry, meta);
|
|
77
84
|
return schema;
|
|
@@ -80,8 +87,65 @@ export function healthResultNumber(meta: HealthResultMeta) {
|
|
|
80
87
|
/**
|
|
81
88
|
* Create a health result boolean field with typed chart metadata.
|
|
82
89
|
*/
|
|
83
|
-
export function healthResultBoolean(meta:
|
|
90
|
+
export function healthResultBoolean(meta: ChartMeta) {
|
|
84
91
|
const schema = z.boolean();
|
|
85
92
|
schema.register(healthResultRegistry, meta);
|
|
86
93
|
return schema;
|
|
87
94
|
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Create a health result string field with JSONPath assertion support.
|
|
98
|
+
* The UI will show a JSONPath input field for this result.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* import { healthResultJSONPath } from "@checkstack/healthcheck-common";
|
|
103
|
+
*
|
|
104
|
+
* const resultSchema = z.object({
|
|
105
|
+
* body: healthResultJSONPath(),
|
|
106
|
+
* });
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export function healthResultJSONPath(meta: ChartMeta) {
|
|
110
|
+
const schema = z.string();
|
|
111
|
+
schema.register(healthResultRegistry, { ...meta, "x-jsonpath": true });
|
|
112
|
+
return schema;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ============================================================================
|
|
116
|
+
// METADATA RETRIEVAL - For toJsonSchema integration
|
|
117
|
+
// ============================================================================
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Unwraps a Zod schema to get the inner schema, handling:
|
|
121
|
+
* - ZodOptional
|
|
122
|
+
* - ZodDefault
|
|
123
|
+
* - ZodNullable
|
|
124
|
+
*/
|
|
125
|
+
function unwrapSchema(schema: z.ZodTypeAny): z.ZodTypeAny {
|
|
126
|
+
let unwrapped = schema;
|
|
127
|
+
|
|
128
|
+
if (unwrapped instanceof z.ZodOptional) {
|
|
129
|
+
unwrapped = unwrapped.unwrap() as z.ZodTypeAny;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (unwrapped instanceof z.ZodDefault) {
|
|
133
|
+
unwrapped = unwrapped.def.innerType as z.ZodTypeAny;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (unwrapped instanceof z.ZodNullable) {
|
|
137
|
+
unwrapped = unwrapped.unwrap() as z.ZodTypeAny;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return unwrapped;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get health result metadata for a schema.
|
|
145
|
+
* Automatically unwraps Optional/Default/Nullable wrappers.
|
|
146
|
+
*/
|
|
147
|
+
export function getHealthResultMeta(
|
|
148
|
+
schema: z.ZodTypeAny
|
|
149
|
+
): HealthResultMeta | undefined {
|
|
150
|
+
return healthResultRegistry.get(unwrapSchema(schema));
|
|
151
|
+
}
|