@checkstack/healthcheck-http-backend 0.2.5 → 0.3.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 CHANGED
@@ -1,5 +1,29 @@
1
1
  # @checkstack/healthcheck-http-backend
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3dd1914: Migrate health check strategies to VersionedAggregated with \_type discriminator
8
+
9
+ All 13 health check strategies now use `VersionedAggregated` for their `aggregatedResult` property, enabling automatic bucket merging with 100% mathematical fidelity.
10
+
11
+ **Key changes:**
12
+
13
+ - **`_type` discriminator**: All aggregated state objects now include a required `_type` field (`"average"`, `"rate"`, `"counter"`, `"minmax"`) for reliable type detection
14
+ - The `HealthCheckStrategy` interface now requires `aggregatedResult` to be a `VersionedAggregated<AggregatedResultShape>`
15
+ - Strategy/collector `mergeResult` methods return state objects with `_type` (e.g., `{ _type: "average", _sum, _count, avg }`)
16
+ - `mergeAggregatedBucketResults`, `combineBuckets`, and `reaggregateBuckets` now require `registry` and `strategyId` parameters
17
+ - `HealthCheckService` constructor now requires both `registry` and `collectorRegistry` parameters
18
+ - Frontend `extractComputedValue` now uses `_type` discriminator for robust type detection
19
+
20
+ **Breaking Change**: State objects now require `_type`. Merge functions automatically add `_type` to output. The bucket merging functions and `HealthCheckService` now require additional required parameters.
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies [3dd1914]
25
+ - @checkstack/backend-api@0.7.0
26
+
3
27
  ## 0.2.5
4
28
 
5
29
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/healthcheck-http-backend",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "scripts": {
@@ -156,8 +156,8 @@ describe("RequestCollector", () => {
156
156
  let aggregated = collector.mergeResult(undefined, runs[0]);
157
157
  aggregated = collector.mergeResult(aggregated, runs[1]);
158
158
 
159
- expect(aggregated.avgResponseTimeMs).toBe(75);
160
- expect(aggregated.successRate).toBe(100);
159
+ expect(aggregated.avgResponseTimeMs.avg).toBe(75);
160
+ expect(aggregated.successRate.rate).toBe(100);
161
161
  });
162
162
 
163
163
  it("should calculate success rate correctly", () => {
@@ -199,7 +199,7 @@ describe("RequestCollector", () => {
199
199
  let aggregated = collector.mergeResult(undefined, runs[0]);
200
200
  aggregated = collector.mergeResult(aggregated, runs[1]);
201
201
 
202
- expect(aggregated.successRate).toBe(50);
202
+ expect(aggregated.successRate.rate).toBe(50);
203
203
  });
204
204
  });
205
205
 
@@ -7,8 +7,10 @@ import {
7
7
  type CollectorStrategy,
8
8
  mergeAverage,
9
9
  mergeRate,
10
- averageStateSchema,
11
- rateStateSchema,
10
+ VersionedAggregated,
11
+ aggregatedAverage,
12
+ aggregatedRate,
13
+ type InferAggregatedResult,
12
14
  } from "@checkstack/backend-api";
13
15
  import {
14
16
  healthResultNumber,
@@ -80,32 +82,24 @@ const requestResultSchema = healthResultSchema({
80
82
 
81
83
  export type RequestResult = z.infer<typeof requestResultSchema>;
82
84
 
83
- // UI-visible aggregated fields (for charts)
84
- const requestAggregatedDisplaySchema = healthResultSchema({
85
- avgResponseTimeMs: healthResultNumber({
85
+ // Aggregated result fields definition
86
+ const requestAggregatedFields = {
87
+ avgResponseTimeMs: aggregatedAverage({
86
88
  "x-chart-type": "line",
87
89
  "x-chart-label": "Avg Response Time",
88
90
  "x-chart-unit": "ms",
89
91
  }),
90
- successRate: healthResultNumber({
92
+ successRate: aggregatedRate({
91
93
  "x-chart-type": "gauge",
92
94
  "x-chart-label": "Success Rate",
93
95
  "x-chart-unit": "%",
94
96
  }),
95
- });
96
-
97
- // Internal state for incremental aggregation (not shown in charts)
98
- const requestAggregatedInternalSchema = z.object({
99
- _responseTime: averageStateSchema.optional(),
100
- _success: rateStateSchema.optional(),
101
- });
97
+ };
102
98
 
103
- // Combined schema for storage
104
- const requestAggregatedSchema = requestAggregatedDisplaySchema.and(
105
- requestAggregatedInternalSchema,
106
- );
107
-
108
- export type RequestAggregatedResult = z.infer<typeof requestAggregatedSchema>;
99
+ // Type inferred automatically from field definitions
100
+ export type RequestAggregatedResult = InferAggregatedResult<
101
+ typeof requestAggregatedFields
102
+ >;
109
103
 
110
104
  // ============================================================================
111
105
  // REQUEST COLLECTOR
@@ -131,9 +125,9 @@ export class RequestCollector implements CollectorStrategy<
131
125
 
132
126
  config = new Versioned({ version: 1, schema: requestConfigSchema });
133
127
  result = new Versioned({ version: 1, schema: requestResultSchema });
134
- aggregatedResult = new Versioned({
128
+ aggregatedResult = new VersionedAggregated({
135
129
  version: 1,
136
- schema: requestAggregatedSchema,
130
+ fields: requestAggregatedFields,
137
131
  });
138
132
 
139
133
  async execute({
@@ -182,17 +176,12 @@ export class RequestCollector implements CollectorStrategy<
182
176
  existing: RequestAggregatedResult | undefined,
183
177
  newRun: HealthCheckRunForAggregation<RequestResult>,
184
178
  ): RequestAggregatedResult {
185
- const responseTime = mergeAverage(
186
- existing?._responseTime,
187
- newRun.metadata?.responseTimeMs,
188
- );
189
- const success = mergeRate(existing?._success, newRun.metadata?.success);
190
-
191
179
  return {
192
- avgResponseTimeMs: responseTime.avg,
193
- successRate: success.rate,
194
- _responseTime: responseTime,
195
- _success: success,
180
+ avgResponseTimeMs: mergeAverage(
181
+ existing?.avgResponseTimeMs,
182
+ newRun.metadata?.responseTimeMs,
183
+ ),
184
+ successRate: mergeRate(existing?.successRate, newRun.metadata?.success),
196
185
  };
197
186
  }
198
187
  }
@@ -218,7 +218,7 @@ describe("HttpHealthCheckStrategy", () => {
218
218
  aggregated = strategy.mergeResult(aggregated, runs[1]);
219
219
  aggregated = strategy.mergeResult(aggregated, runs[2]);
220
220
 
221
- expect(aggregated.errorCount).toBe(2);
221
+ expect(aggregated.errorCount.count).toBe(2);
222
222
  });
223
223
 
224
224
  it("should return zero errors when all runs succeed", () => {
@@ -245,7 +245,7 @@ describe("HttpHealthCheckStrategy", () => {
245
245
  let aggregated = strategy.mergeResult(undefined, runs[0]);
246
246
  aggregated = strategy.mergeResult(aggregated, runs[1]);
247
247
 
248
- expect(aggregated.errorCount).toBe(0);
248
+ expect(aggregated.errorCount.count).toBe(0);
249
249
  });
250
250
  });
251
251
  });
package/src/strategy.ts CHANGED
@@ -2,12 +2,14 @@ import {
2
2
  HealthCheckStrategy,
3
3
  HealthCheckRunForAggregation,
4
4
  Versioned,
5
+ VersionedAggregated,
6
+ aggregatedCounter,
7
+ mergeCounter,
5
8
  z,
9
+ type InferAggregatedResult,
6
10
  type ConnectedClient,
7
- mergeCounter,
8
11
  } from "@checkstack/backend-api";
9
12
  import {
10
- healthResultNumber,
11
13
  healthResultString,
12
14
  healthResultSchema,
13
15
  } from "@checkstack/healthcheck-common";
@@ -58,15 +60,15 @@ const httpResultMetadataSchema = healthResultSchema({
58
60
 
59
61
  type HttpResultMetadata = z.infer<typeof httpResultMetadataSchema>;
60
62
 
61
- /** Aggregated metadata for buckets */
62
- const httpAggregatedMetadataSchema = healthResultSchema({
63
- errorCount: healthResultNumber({
63
+ /** Aggregated field definitions for bucket merging */
64
+ const httpAggregatedFields = {
65
+ errorCount: aggregatedCounter({
64
66
  "x-chart-type": "counter",
65
67
  "x-chart-label": "Errors",
66
68
  }),
67
- });
69
+ };
68
70
 
69
- type HttpAggregatedMetadata = z.infer<typeof httpAggregatedMetadataSchema>;
71
+ type HttpAggregatedResult = InferAggregatedResult<typeof httpAggregatedFields>;
70
72
 
71
73
  // ============================================================================
72
74
  // STRATEGY
@@ -76,7 +78,7 @@ export class HttpHealthCheckStrategy implements HealthCheckStrategy<
76
78
  HttpHealthCheckConfig,
77
79
  HttpTransportClient,
78
80
  HttpResultMetadata,
79
- HttpAggregatedMetadata
81
+ typeof httpAggregatedFields
80
82
  > {
81
83
  id = "http";
82
84
  displayName = "HTTP/HTTPS Health Check";
@@ -112,21 +114,18 @@ export class HttpHealthCheckStrategy implements HealthCheckStrategy<
112
114
  schema: httpResultMetadataSchema,
113
115
  });
114
116
 
115
- aggregatedResult: Versioned<HttpAggregatedMetadata> = new Versioned({
117
+ aggregatedResult = new VersionedAggregated({
116
118
  version: 1,
117
- schema: httpAggregatedMetadataSchema,
119
+ fields: httpAggregatedFields,
118
120
  });
119
121
 
120
122
  mergeResult(
121
- existing: HttpAggregatedMetadata | undefined,
123
+ existing: HttpAggregatedResult | undefined,
122
124
  newRun: HealthCheckRunForAggregation<HttpResultMetadata>,
123
- ): HttpAggregatedMetadata {
125
+ ): HttpAggregatedResult {
124
126
  const hasError = !!newRun.metadata?.error;
125
127
  return {
126
- errorCount: mergeCounter(
127
- existing ? { count: existing.errorCount } : undefined,
128
- hasError,
129
- ).count,
128
+ errorCount: mergeCounter(existing?.errorCount, hasError),
130
129
  };
131
130
  }
132
131