@checkstack/healthcheck-backend 0.12.0 → 0.13.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,113 @@
1
1
  # @checkstack/healthcheck-backend
2
2
 
3
+ ## 0.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 26d8bae: Distributed satellite health checks and Assignment IDE page
8
+
9
+ **Satellite System**
10
+
11
+ - New `satellite-backend`, `satellite-common`, `satellite-frontend`, and `satellite` agent packages for distributed health check execution
12
+ - WebSocket-based satellite connectivity with authentication, heartbeats, and live configuration push
13
+ - Satellite management UI with create dialog, status badges, and list page
14
+
15
+ **Live Configuration Updates**
16
+
17
+ - Added `assignmentChanged` hook to `healthcheck-backend` for cross-plugin communication
18
+ - `satellite-backend` subscribes to assignment changes and pushes config updates to connected satellites in real-time
19
+
20
+ **Assignment IDE Page**
21
+
22
+ - Replaced the 1028-line modal-based `SystemHealthCheckAssignment` component with a full-page IDE layout
23
+ - New modular components: `AssignmentTree`, `GeneralPanel`, `ThresholdsPanel`, `RetentionPanel`, `ExecutionPanel`
24
+ - Added unassign capability and sorted assignment lists for stable ordering
25
+
26
+ **Shared IDE Primitives**
27
+
28
+ - Extracted `IDETreeNode`, `IDETreeSection`, `IDEStatusBar`, `IDELayout` to `@checkstack/ui` for cross-plugin reuse
29
+ - Migrated existing health check IDE editor to use shared primitives
30
+
31
+ **Infrastructure**
32
+
33
+ - Added `Dockerfile.satellite` for containerized satellite deployment
34
+ - WebSocket route registry in `@checkstack/backend` and `@checkstack/backend-api`
35
+
36
+ - 26d8bae: Source attribution and filtering for satellite health checks
37
+
38
+ **Source Attribution**
39
+
40
+ - Fixed satellite result attribution: runs from satellites now correctly display their source instead of defaulting to "Local"
41
+ - Added `sourceId` and `sourceLabel` to both public and detailed history API responses
42
+
43
+ **Source Filtering**
44
+
45
+ - Added `sourceFilter` parameter to `getHistory`, `getDetailedHistory`, and `getDetailedAggregatedHistory` RPC endpoints
46
+ - Source filter supports "local" (core-only), specific satellite UUID, or all sources
47
+ - Filter applies to all three aggregation tiers (raw, hourly, daily)
48
+
49
+ **Frontend**
50
+
51
+ - System detail accordion shows source filter buttons (All / Local / per-satellite) next to date range filter
52
+ - Filter applies to both charts and recent runs table
53
+ - Source column added to the recent runs table with Local/Remote badges
54
+ - Health check history detail page includes per-satellite source filter buttons
55
+
56
+ ### Patch Changes
57
+
58
+ - Updated dependencies [26d8bae]
59
+ - Updated dependencies [26d8bae]
60
+ - @checkstack/healthcheck-common@0.11.0
61
+ - @checkstack/satellite-backend@0.2.0
62
+ - @checkstack/backend-api@0.12.0
63
+ - @checkstack/catalog-backend@0.2.24
64
+ - @checkstack/command-backend@0.1.19
65
+ - @checkstack/integration-backend@0.1.19
66
+ - @checkstack/queue-api@0.2.13
67
+
68
+ ## 0.12.1
69
+
70
+ ### Patch Changes
71
+
72
+ - d1a2796: Enforce stricter code quality standards and eliminate AI slop anti-patterns.
73
+
74
+ **New utility**
75
+
76
+ - `extractErrorMessage(error, fallback?)` in `@checkstack/common` for consistent error extraction
77
+
78
+ **ESLint rules**
79
+
80
+ - `react-hooks/rules-of-hooks` and `exhaustive-deps` for hook correctness
81
+ - `no-console` in frontend packages — forces `toast` over silent `console.error`
82
+ - `no-restricted-syntax` banning `instanceof Error` — forces `extractErrorMessage`
83
+ - Custom `no-eslint-disable-any` rule preventing `@typescript-eslint/no-explicit-any` circumvention
84
+
85
+ **Refactoring**
86
+
87
+ - Replace 141 `instanceof Error` boilerplate patterns across the codebase
88
+ - Replace swallowed `console.error` with user-visible `toast.error()` feedback
89
+ - Remove 15 redundant `as` type casts in IntegrationsPage and ProviderConnectionsPage
90
+ - Consolidate 3 identical callback handlers into `handleDialogClose`
91
+ - Fix conditional React hook call in `FormField.tsx`
92
+ - Fix unstable useMemo deps in `Dashboard.tsx`
93
+ - Replace `useEffect`→`setState` with derived `useMemo` in `RegisterPage.tsx`
94
+ - Rewrite `keystore.test.ts` with typed `DrizzleMockChain` (eliminating 7 `any` suppressions)
95
+ - Delete obvious comments in `encryption.ts` and Teams `provider.ts`
96
+
97
+ - Updated dependencies [d1a2796]
98
+ - Updated dependencies [3c34b07]
99
+ - @checkstack/common@0.6.5
100
+ - @checkstack/backend-api@0.11.1
101
+ - @checkstack/catalog-backend@0.2.23
102
+ - @checkstack/integration-backend@0.1.18
103
+ - @checkstack/catalog-common@1.3.1
104
+ - @checkstack/healthcheck-common@0.10.1
105
+ - @checkstack/command-backend@0.1.18
106
+ - @checkstack/incident-common@0.4.7
107
+ - @checkstack/maintenance-common@0.4.9
108
+ - @checkstack/signal-common@0.1.9
109
+ - @checkstack/queue-api@0.2.12
110
+
3
111
  ## 0.12.0
4
112
 
5
113
  ### Minor Changes
@@ -0,0 +1,8 @@
1
+ DROP INDEX "health_check_aggregates_bucket_unique";--> statement-breakpoint
2
+ ALTER TABLE "health_check_aggregates" ADD COLUMN "source_id" text;--> statement-breakpoint
3
+ ALTER TABLE "health_check_aggregates" ADD COLUMN "source_label" text;--> statement-breakpoint
4
+ ALTER TABLE "health_check_runs" ADD COLUMN "source_id" text;--> statement-breakpoint
5
+ ALTER TABLE "health_check_runs" ADD COLUMN "source_label" text;--> statement-breakpoint
6
+ ALTER TABLE "system_health_checks" ADD COLUMN "satellite_ids" jsonb;--> statement-breakpoint
7
+ ALTER TABLE "system_health_checks" ADD COLUMN "include_local" boolean DEFAULT true NOT NULL;--> statement-breakpoint
8
+ CREATE UNIQUE INDEX "health_check_aggregates_bucket_unique" ON "health_check_aggregates" USING btree ("configuration_id","system_id","bucket_start","bucket_size","source_id");
@@ -0,0 +1,469 @@
1
+ {
2
+ "id": "743f0b98-66a5-462e-8c35-4b2eb3093010",
3
+ "prevId": "b297253c-1c34-49b0-ad7e-4e06aff71d2d",
4
+ "version": "7",
5
+ "dialect": "postgresql",
6
+ "tables": {
7
+ "public.health_check_aggregates": {
8
+ "name": "health_check_aggregates",
9
+ "schema": "",
10
+ "columns": {
11
+ "id": {
12
+ "name": "id",
13
+ "type": "uuid",
14
+ "primaryKey": true,
15
+ "notNull": true,
16
+ "default": "gen_random_uuid()"
17
+ },
18
+ "configuration_id": {
19
+ "name": "configuration_id",
20
+ "type": "uuid",
21
+ "primaryKey": false,
22
+ "notNull": true
23
+ },
24
+ "system_id": {
25
+ "name": "system_id",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true
29
+ },
30
+ "bucket_start": {
31
+ "name": "bucket_start",
32
+ "type": "timestamp",
33
+ "primaryKey": false,
34
+ "notNull": true
35
+ },
36
+ "bucket_size": {
37
+ "name": "bucket_size",
38
+ "type": "bucket_size",
39
+ "typeSchema": "public",
40
+ "primaryKey": false,
41
+ "notNull": true
42
+ },
43
+ "run_count": {
44
+ "name": "run_count",
45
+ "type": "integer",
46
+ "primaryKey": false,
47
+ "notNull": true
48
+ },
49
+ "healthy_count": {
50
+ "name": "healthy_count",
51
+ "type": "integer",
52
+ "primaryKey": false,
53
+ "notNull": true
54
+ },
55
+ "degraded_count": {
56
+ "name": "degraded_count",
57
+ "type": "integer",
58
+ "primaryKey": false,
59
+ "notNull": true
60
+ },
61
+ "unhealthy_count": {
62
+ "name": "unhealthy_count",
63
+ "type": "integer",
64
+ "primaryKey": false,
65
+ "notNull": true
66
+ },
67
+ "latency_sum_ms": {
68
+ "name": "latency_sum_ms",
69
+ "type": "integer",
70
+ "primaryKey": false,
71
+ "notNull": false
72
+ },
73
+ "avg_latency_ms": {
74
+ "name": "avg_latency_ms",
75
+ "type": "integer",
76
+ "primaryKey": false,
77
+ "notNull": false
78
+ },
79
+ "min_latency_ms": {
80
+ "name": "min_latency_ms",
81
+ "type": "integer",
82
+ "primaryKey": false,
83
+ "notNull": false
84
+ },
85
+ "max_latency_ms": {
86
+ "name": "max_latency_ms",
87
+ "type": "integer",
88
+ "primaryKey": false,
89
+ "notNull": false
90
+ },
91
+ "p95_latency_ms": {
92
+ "name": "p95_latency_ms",
93
+ "type": "integer",
94
+ "primaryKey": false,
95
+ "notNull": false
96
+ },
97
+ "aggregated_result": {
98
+ "name": "aggregated_result",
99
+ "type": "jsonb",
100
+ "primaryKey": false,
101
+ "notNull": false
102
+ },
103
+ "tdigest_state": {
104
+ "name": "tdigest_state",
105
+ "type": "jsonb",
106
+ "primaryKey": false,
107
+ "notNull": false
108
+ },
109
+ "source_id": {
110
+ "name": "source_id",
111
+ "type": "text",
112
+ "primaryKey": false,
113
+ "notNull": false
114
+ },
115
+ "source_label": {
116
+ "name": "source_label",
117
+ "type": "text",
118
+ "primaryKey": false,
119
+ "notNull": false
120
+ }
121
+ },
122
+ "indexes": {
123
+ "health_check_aggregates_bucket_unique": {
124
+ "name": "health_check_aggregates_bucket_unique",
125
+ "columns": [
126
+ {
127
+ "expression": "configuration_id",
128
+ "isExpression": false,
129
+ "asc": true,
130
+ "nulls": "last"
131
+ },
132
+ {
133
+ "expression": "system_id",
134
+ "isExpression": false,
135
+ "asc": true,
136
+ "nulls": "last"
137
+ },
138
+ {
139
+ "expression": "bucket_start",
140
+ "isExpression": false,
141
+ "asc": true,
142
+ "nulls": "last"
143
+ },
144
+ {
145
+ "expression": "bucket_size",
146
+ "isExpression": false,
147
+ "asc": true,
148
+ "nulls": "last"
149
+ },
150
+ {
151
+ "expression": "source_id",
152
+ "isExpression": false,
153
+ "asc": true,
154
+ "nulls": "last"
155
+ }
156
+ ],
157
+ "isUnique": true,
158
+ "concurrently": false,
159
+ "method": "btree",
160
+ "with": {}
161
+ }
162
+ },
163
+ "foreignKeys": {
164
+ "health_check_aggregates_configuration_id_health_check_configurations_id_fk": {
165
+ "name": "health_check_aggregates_configuration_id_health_check_configurations_id_fk",
166
+ "tableFrom": "health_check_aggregates",
167
+ "tableTo": "health_check_configurations",
168
+ "columnsFrom": [
169
+ "configuration_id"
170
+ ],
171
+ "columnsTo": [
172
+ "id"
173
+ ],
174
+ "onDelete": "cascade",
175
+ "onUpdate": "no action"
176
+ }
177
+ },
178
+ "compositePrimaryKeys": {},
179
+ "uniqueConstraints": {},
180
+ "policies": {},
181
+ "checkConstraints": {},
182
+ "isRLSEnabled": false
183
+ },
184
+ "public.health_check_configurations": {
185
+ "name": "health_check_configurations",
186
+ "schema": "",
187
+ "columns": {
188
+ "id": {
189
+ "name": "id",
190
+ "type": "uuid",
191
+ "primaryKey": true,
192
+ "notNull": true,
193
+ "default": "gen_random_uuid()"
194
+ },
195
+ "name": {
196
+ "name": "name",
197
+ "type": "text",
198
+ "primaryKey": false,
199
+ "notNull": true
200
+ },
201
+ "strategy_id": {
202
+ "name": "strategy_id",
203
+ "type": "text",
204
+ "primaryKey": false,
205
+ "notNull": true
206
+ },
207
+ "config": {
208
+ "name": "config",
209
+ "type": "jsonb",
210
+ "primaryKey": false,
211
+ "notNull": true
212
+ },
213
+ "collectors": {
214
+ "name": "collectors",
215
+ "type": "jsonb",
216
+ "primaryKey": false,
217
+ "notNull": false
218
+ },
219
+ "interval_seconds": {
220
+ "name": "interval_seconds",
221
+ "type": "integer",
222
+ "primaryKey": false,
223
+ "notNull": true
224
+ },
225
+ "is_template": {
226
+ "name": "is_template",
227
+ "type": "boolean",
228
+ "primaryKey": false,
229
+ "notNull": false,
230
+ "default": false
231
+ },
232
+ "paused": {
233
+ "name": "paused",
234
+ "type": "boolean",
235
+ "primaryKey": false,
236
+ "notNull": true,
237
+ "default": false
238
+ },
239
+ "created_at": {
240
+ "name": "created_at",
241
+ "type": "timestamp",
242
+ "primaryKey": false,
243
+ "notNull": true,
244
+ "default": "now()"
245
+ },
246
+ "updated_at": {
247
+ "name": "updated_at",
248
+ "type": "timestamp",
249
+ "primaryKey": false,
250
+ "notNull": true,
251
+ "default": "now()"
252
+ }
253
+ },
254
+ "indexes": {},
255
+ "foreignKeys": {},
256
+ "compositePrimaryKeys": {},
257
+ "uniqueConstraints": {},
258
+ "policies": {},
259
+ "checkConstraints": {},
260
+ "isRLSEnabled": false
261
+ },
262
+ "public.health_check_runs": {
263
+ "name": "health_check_runs",
264
+ "schema": "",
265
+ "columns": {
266
+ "id": {
267
+ "name": "id",
268
+ "type": "uuid",
269
+ "primaryKey": true,
270
+ "notNull": true,
271
+ "default": "gen_random_uuid()"
272
+ },
273
+ "configuration_id": {
274
+ "name": "configuration_id",
275
+ "type": "uuid",
276
+ "primaryKey": false,
277
+ "notNull": true
278
+ },
279
+ "system_id": {
280
+ "name": "system_id",
281
+ "type": "text",
282
+ "primaryKey": false,
283
+ "notNull": true
284
+ },
285
+ "status": {
286
+ "name": "status",
287
+ "type": "health_check_status",
288
+ "typeSchema": "public",
289
+ "primaryKey": false,
290
+ "notNull": true
291
+ },
292
+ "latency_ms": {
293
+ "name": "latency_ms",
294
+ "type": "integer",
295
+ "primaryKey": false,
296
+ "notNull": false
297
+ },
298
+ "result": {
299
+ "name": "result",
300
+ "type": "jsonb",
301
+ "primaryKey": false,
302
+ "notNull": false
303
+ },
304
+ "source_id": {
305
+ "name": "source_id",
306
+ "type": "text",
307
+ "primaryKey": false,
308
+ "notNull": false
309
+ },
310
+ "source_label": {
311
+ "name": "source_label",
312
+ "type": "text",
313
+ "primaryKey": false,
314
+ "notNull": false
315
+ },
316
+ "timestamp": {
317
+ "name": "timestamp",
318
+ "type": "timestamp",
319
+ "primaryKey": false,
320
+ "notNull": true,
321
+ "default": "now()"
322
+ }
323
+ },
324
+ "indexes": {},
325
+ "foreignKeys": {
326
+ "health_check_runs_configuration_id_health_check_configurations_id_fk": {
327
+ "name": "health_check_runs_configuration_id_health_check_configurations_id_fk",
328
+ "tableFrom": "health_check_runs",
329
+ "tableTo": "health_check_configurations",
330
+ "columnsFrom": [
331
+ "configuration_id"
332
+ ],
333
+ "columnsTo": [
334
+ "id"
335
+ ],
336
+ "onDelete": "cascade",
337
+ "onUpdate": "no action"
338
+ }
339
+ },
340
+ "compositePrimaryKeys": {},
341
+ "uniqueConstraints": {},
342
+ "policies": {},
343
+ "checkConstraints": {},
344
+ "isRLSEnabled": false
345
+ },
346
+ "public.system_health_checks": {
347
+ "name": "system_health_checks",
348
+ "schema": "",
349
+ "columns": {
350
+ "system_id": {
351
+ "name": "system_id",
352
+ "type": "text",
353
+ "primaryKey": false,
354
+ "notNull": true
355
+ },
356
+ "configuration_id": {
357
+ "name": "configuration_id",
358
+ "type": "uuid",
359
+ "primaryKey": false,
360
+ "notNull": true
361
+ },
362
+ "enabled": {
363
+ "name": "enabled",
364
+ "type": "boolean",
365
+ "primaryKey": false,
366
+ "notNull": true,
367
+ "default": true
368
+ },
369
+ "state_thresholds": {
370
+ "name": "state_thresholds",
371
+ "type": "jsonb",
372
+ "primaryKey": false,
373
+ "notNull": false
374
+ },
375
+ "retention_config": {
376
+ "name": "retention_config",
377
+ "type": "jsonb",
378
+ "primaryKey": false,
379
+ "notNull": false
380
+ },
381
+ "satellite_ids": {
382
+ "name": "satellite_ids",
383
+ "type": "jsonb",
384
+ "primaryKey": false,
385
+ "notNull": false
386
+ },
387
+ "include_local": {
388
+ "name": "include_local",
389
+ "type": "boolean",
390
+ "primaryKey": false,
391
+ "notNull": true,
392
+ "default": true
393
+ },
394
+ "created_at": {
395
+ "name": "created_at",
396
+ "type": "timestamp",
397
+ "primaryKey": false,
398
+ "notNull": true,
399
+ "default": "now()"
400
+ },
401
+ "updated_at": {
402
+ "name": "updated_at",
403
+ "type": "timestamp",
404
+ "primaryKey": false,
405
+ "notNull": true,
406
+ "default": "now()"
407
+ }
408
+ },
409
+ "indexes": {},
410
+ "foreignKeys": {
411
+ "system_health_checks_configuration_id_health_check_configurations_id_fk": {
412
+ "name": "system_health_checks_configuration_id_health_check_configurations_id_fk",
413
+ "tableFrom": "system_health_checks",
414
+ "tableTo": "health_check_configurations",
415
+ "columnsFrom": [
416
+ "configuration_id"
417
+ ],
418
+ "columnsTo": [
419
+ "id"
420
+ ],
421
+ "onDelete": "cascade",
422
+ "onUpdate": "no action"
423
+ }
424
+ },
425
+ "compositePrimaryKeys": {
426
+ "system_health_checks_system_id_configuration_id_pk": {
427
+ "name": "system_health_checks_system_id_configuration_id_pk",
428
+ "columns": [
429
+ "system_id",
430
+ "configuration_id"
431
+ ]
432
+ }
433
+ },
434
+ "uniqueConstraints": {},
435
+ "policies": {},
436
+ "checkConstraints": {},
437
+ "isRLSEnabled": false
438
+ }
439
+ },
440
+ "enums": {
441
+ "public.bucket_size": {
442
+ "name": "bucket_size",
443
+ "schema": "public",
444
+ "values": [
445
+ "hourly",
446
+ "daily"
447
+ ]
448
+ },
449
+ "public.health_check_status": {
450
+ "name": "health_check_status",
451
+ "schema": "public",
452
+ "values": [
453
+ "healthy",
454
+ "unhealthy",
455
+ "degraded"
456
+ ]
457
+ }
458
+ },
459
+ "schemas": {},
460
+ "sequences": {},
461
+ "roles": {},
462
+ "policies": {},
463
+ "views": {},
464
+ "_meta": {
465
+ "columns": {},
466
+ "schemas": {},
467
+ "tables": {}
468
+ }
469
+ }
@@ -71,6 +71,13 @@
71
71
  "when": 1769077338943,
72
72
  "tag": "0009_late_argent",
73
73
  "breakpoints": true
74
+ },
75
+ {
76
+ "idx": 10,
77
+ "version": "7",
78
+ "when": 1776599270689,
79
+ "tag": "0010_colorful_shinobi_shaw",
80
+ "breakpoints": true
74
81
  }
75
82
  ]
76
83
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@checkstack/healthcheck-backend",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "checkstack": {
@@ -13,17 +13,18 @@
13
13
  "lint:code": "eslint . --max-warnings 0"
14
14
  },
15
15
  "dependencies": {
16
- "@checkstack/backend-api": "0.10.0",
17
- "@checkstack/catalog-backend": "0.2.20",
18
- "@checkstack/catalog-common": "1.2.11",
19
- "@checkstack/command-backend": "0.1.15",
20
- "@checkstack/common": "0.6.4",
21
- "@checkstack/healthcheck-common": "0.8.4",
22
- "@checkstack/incident-common": "0.4.6",
23
- "@checkstack/integration-backend": "0.1.15",
24
- "@checkstack/maintenance-common": "0.4.8",
25
- "@checkstack/queue-api": "0.2.9",
26
- "@checkstack/signal-common": "0.1.8",
16
+ "@checkstack/backend-api": "0.11.1",
17
+ "@checkstack/catalog-backend": "0.2.23",
18
+ "@checkstack/catalog-common": "1.3.1",
19
+ "@checkstack/command-backend": "0.1.18",
20
+ "@checkstack/common": "0.6.5",
21
+ "@checkstack/healthcheck-common": "0.10.1",
22
+ "@checkstack/incident-common": "0.4.7",
23
+ "@checkstack/integration-backend": "0.1.18",
24
+ "@checkstack/maintenance-common": "0.4.9",
25
+ "@checkstack/queue-api": "0.2.12",
26
+ "@checkstack/satellite-backend": "0.1.0",
27
+ "@checkstack/signal-common": "0.1.9",
27
28
  "@hono/zod-validator": "^0.7.6",
28
29
  "drizzle-orm": "^0.45.0",
29
30
  "hono": "^4.12.14",
@@ -34,8 +35,8 @@
34
35
  "devDependencies": {
35
36
  "@checkstack/drizzle-helper": "0.0.4",
36
37
  "@checkstack/scripts": "0.1.2",
37
- "@checkstack/test-utils-backend": "0.1.15",
38
- "@checkstack/tsconfig": "0.0.4",
38
+ "@checkstack/test-utils-backend": "0.1.18",
39
+ "@checkstack/tsconfig": "0.0.5",
39
40
  "@types/bun": "^1.0.0",
40
41
  "@types/tdigest": "^0.1.5",
41
42
  "date-fns": "^4.1.0",
package/src/hooks.ts CHANGED
@@ -32,4 +32,14 @@ export const healthCheckHooks = {
32
32
  totalChecks: number;
33
33
  timestamp: string;
34
34
  }>("healthcheck.system.healthy"),
35
+
36
+ /**
37
+ * Emitted when a health check ↔ system association changes.
38
+ * Subscribers (e.g., satellite-backend) can use this to push
39
+ * updated assignments to connected satellites.
40
+ */
41
+ assignmentChanged: createHook<{
42
+ systemId: string;
43
+ configurationId: string;
44
+ }>("healthcheck.assignment.changed"),
35
45
  } as const;