@checkstack/healthcheck-backend 1.17.0 → 1.19.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 +559 -0
- package/package.json +32 -29
- package/src/adaptive-timeout.test.ts +91 -0
- package/src/adaptive-timeout.ts +75 -0
- package/src/ai/system-signals-contributor.test.ts +2 -0
- package/src/automations.test.ts +47 -0
- package/src/automations.ts +19 -3
- package/src/health-notification-content.test.ts +89 -0
- package/src/health-notification-content.ts +138 -0
- package/src/healthcheck-gitops-kinds.test.ts +34 -2
- package/src/healthcheck-gitops-kinds.ts +17 -13
- package/src/index.ts +58 -6
- package/src/migration-chain-contract.test.ts +7 -1
- package/src/notification-policy.test.ts +19 -0
- package/src/notification-policy.ts +26 -0
- package/src/queue-executor.test.ts +391 -338
- package/src/queue-executor.ts +426 -362
- package/src/realtime-aggregation.ts +9 -2
- package/src/rollup-consumer.test.ts +191 -0
- package/src/rollup-consumer.ts +160 -0
- package/src/router.ts +46 -13
- package/src/schedule-jitter.test.ts +69 -0
- package/src/schedule-jitter.ts +50 -0
- package/src/schedule-reconciler.it.test.ts +453 -0
- package/src/schedule-reconciler.test.ts +418 -0
- package/src/schedule-reconciler.ts +304 -0
- package/src/service-batching.test.ts +106 -0
- package/src/service-bulk-counts.it.test.ts +144 -0
- package/src/service-bulk-run-stats.it.test.ts +197 -0
- package/src/service-ordering.test.ts +10 -2
- package/src/service-paused-filter.test.ts +27 -7
- package/src/service-rollup-worst-wins.test.ts +221 -124
- package/src/service.ts +557 -266
- package/src/slow-check-admission.test.ts +184 -0
- package/src/slow-check-admission.ts +101 -0
- package/src/slow-check-classifier.test.ts +155 -0
- package/src/slow-check-classifier.ts +137 -0
- package/src/slow-check-config.ts +102 -0
- package/src/status-page/rollup.test.ts +40 -0
- package/src/status-page/rollup.ts +27 -0
- package/src/status-page/widgets.test.ts +303 -0
- package/src/status-page/widgets.ts +155 -39
- package/src/suspect-lane.test.ts +50 -0
- package/src/suspect-lane.ts +61 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,564 @@
|
|
|
1
1
|
# @checkstack/healthcheck-backend
|
|
2
2
|
|
|
3
|
+
## 1.19.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 43e4484: Fix an N+1 in the catalog manager: the per-system "Health Checks" count badge
|
|
8
|
+
fired one `getSystemAssociations` request per system row, each holding a pooled
|
|
9
|
+
Postgres connection that contended with the background health-check run
|
|
10
|
+
executor and could exhaust the pool on large catalogs.
|
|
11
|
+
|
|
12
|
+
- Add `getBulkAssignedHealthCheckCounts({ systemIds })` to healthcheck, which
|
|
13
|
+
returns per-system assignment counts (0 for systems with no assignments) from
|
|
14
|
+
ONE grouped `COUNT(*) ... GROUP BY system_id` query. Read authorization
|
|
15
|
+
matches the per-system endpoint it replaces (`configuration.read` +
|
|
16
|
+
`catalog.system` read via `recordKey`), so a team-scoped user only sees counts
|
|
17
|
+
for systems they may read.
|
|
18
|
+
- `CatalogSystemActionsSlot` now passes `visibleSystemIds` (every system id in
|
|
19
|
+
the row's list) so a per-row filler can bulk-fetch for the whole visible set
|
|
20
|
+
in a single deduped request instead of one request per row. This mirrors how
|
|
21
|
+
`CatalogBrowseHealthSlot` / `SystemSignalsSlot` already pass `systemIds`.
|
|
22
|
+
- The health-check count badge now reads its count from that one deduped bulk
|
|
23
|
+
query. N visible rows cause 1 request instead of N.
|
|
24
|
+
|
|
25
|
+
State & scale: the counts are derived on read from the shared
|
|
26
|
+
`system_health_checks` table, so every pod returns the same answer; no
|
|
27
|
+
process-local or duplicated state is introduced.
|
|
28
|
+
|
|
29
|
+
- 43e4484: Name the failing health check in system-health notifications. The notification
|
|
30
|
+
body now names the check that drove the transition (in addition to the system
|
|
31
|
+
and environment), and a `healthcheck.healthcheck` subject is pushed alongside
|
|
32
|
+
the `catalog.system` subject, deep-linked to the check's run history. Recovery
|
|
33
|
+
notifications stay system-level. Adds a `createHealthcheckSubject` builder to
|
|
34
|
+
`healthcheck-common`.
|
|
35
|
+
|
|
36
|
+
Thanks to [@stuajnht](https://github.com/stuajnht) for the valuable feedback.
|
|
37
|
+
|
|
38
|
+
- 43e4484: Status pages can now publish only a subset of catalog environments. The page
|
|
39
|
+
builder gains a "Published environments" picker (empty = all environments, the
|
|
40
|
+
backward-compatible default). When a non-empty set is selected, the page omits
|
|
41
|
+
status, incidents, maintenances and uptime for systems that belong to none of
|
|
42
|
+
the selected environments.
|
|
43
|
+
|
|
44
|
+
- Status pages store an optional `publishedEnvironmentIds` set (new nullable
|
|
45
|
+
`published_environment_ids` column; NULL = all environments, so existing pages
|
|
46
|
+
are unchanged) exposed on `StatusPage`, `createStatusPage`, and
|
|
47
|
+
`updateStatusPage`.
|
|
48
|
+
- The scope is threaded onto `WidgetResolveContext.publishedEnvironmentIds` as
|
|
49
|
+
opaque strings and passed identically to `resolvePublic`,
|
|
50
|
+
`resolveScopedSystems`, and `resolveScopedSystemsDetailed` (and the email
|
|
51
|
+
subscribe clamp + fan-out), so what a page shows, offers for subscription, and
|
|
52
|
+
emails about all agree.
|
|
53
|
+
- Health widgets recompute per environment: they read the per-environment health
|
|
54
|
+
matrix and roll up only the selected environments. `getBulkRunStats` and
|
|
55
|
+
`getRunStats` gain an optional `environmentIds` filter so uptime counts only
|
|
56
|
+
runs recorded in the selected environments.
|
|
57
|
+
- Incident and maintenance widgets filter their feed and scope by intersecting
|
|
58
|
+
each item's affected systems with the environment-visible systems. Incidents
|
|
59
|
+
and maintenance windows carry no environment of their own, so a system in
|
|
60
|
+
several environments makes its items visible on a page publishing ANY of them
|
|
61
|
+
(the multi-environment caveat).
|
|
62
|
+
|
|
63
|
+
### Patch Changes
|
|
64
|
+
|
|
65
|
+
- 43e4484: fix(healthcheck): disabling an environment for an assignment now clears its stale slice from the rollup and overview immediately
|
|
66
|
+
|
|
67
|
+
Disabling an environment for a health-check assignment (removing it from the
|
|
68
|
+
assignment's `environmentIds`) stopped that environment from fanning out, but a
|
|
69
|
+
check that was FAILING there kept dragging the system health rollup/badge to
|
|
70
|
+
unhealthy and kept showing as a live failing row in the system overview. Because
|
|
71
|
+
the rollup is recomputed by an event-driven consumer subscribed to per-env health
|
|
72
|
+
CHANGES, and a disabled env produces no further runs (so no change event fires),
|
|
73
|
+
the stale unhealthy status was never recomputed away - it only cleared
|
|
74
|
+
incidentally, once the disabled env's runs aged out of the bounded run window
|
|
75
|
+
(which needs the assignment's OTHER active environments to produce enough newer
|
|
76
|
+
runs first). With a single active/failing env, it could persist until retention.
|
|
77
|
+
|
|
78
|
+
Scope: this reconciles environments DISABLED/removed ON THE ASSIGNMENT (its
|
|
79
|
+
`systemHealthChecks.environmentIds` selector - switching to Specific and
|
|
80
|
+
deselecting, or None).
|
|
81
|
+
|
|
82
|
+
Fixes:
|
|
83
|
+
|
|
84
|
+
- The rollup aggregation (`getSystemHealthStatus`) and the per-check status in
|
|
85
|
+
`getSystemHealthOverview` now consider only CURRENTLY-EFFECTIVE environment
|
|
86
|
+
slices, derived from the durable `systemHealthChecks.environmentIds` selector
|
|
87
|
+
(catalog-free, identical on every pod). A slice whose environment was disabled
|
|
88
|
+
for the assignment, or the stale env-less slice of a check that now fans out,
|
|
89
|
+
no longer contributes.
|
|
90
|
+
|
|
91
|
+
Known limitation: under an "all-environments" assignment (`environmentIds` is
|
|
92
|
+
`null`), an environment removed only from the system's CATALOG MEMBERSHIP (rather
|
|
93
|
+
than disabled on the assignment) can still contribute to the backend rollup/badge
|
|
94
|
+
until the assignment is re-evaluated, because the rollup read path is
|
|
95
|
+
intentionally catalog-free for horizontal-scale correctness (it must return the
|
|
96
|
+
same answer on every pod without a per-read catalog lookup). This is pre-existing;
|
|
97
|
+
the frontend overview, which can see membership, still orphans such a slice.
|
|
98
|
+
|
|
99
|
+
- Each environment is now windowed by its OWN query in the rollup, instead of a
|
|
100
|
+
single shared `LIMIT` across the mixed-env pool. The old shared window
|
|
101
|
+
truncated per-env evaluation for checks that fan out to many environments (or
|
|
102
|
+
with large threshold windows); every environment now gets its full evaluation
|
|
103
|
+
depth.
|
|
104
|
+
- Changing an assignment's environment set now triggers an immediate rollup
|
|
105
|
+
recompute for that system, so the persisted `health` entity (badge + SLO
|
|
106
|
+
downtime) converges at once rather than waiting for stale runs to age out.
|
|
107
|
+
- The system-overview frontend tucks a slice whose environment was disabled for
|
|
108
|
+
the assignment under "Old checks" (system membership alone could not detect it,
|
|
109
|
+
since the environment is still part of the system). `getSystemHealthOverview`
|
|
110
|
+
now returns each check's `environmentIds` selector to drive this.
|
|
111
|
+
|
|
112
|
+
Shared pure helpers `selectorIncludesEnvironment` / `isEnvSliceEffective` /
|
|
113
|
+
`selectEffectiveEnvKeys` are added to `@checkstack/healthcheck-common` so the
|
|
114
|
+
backend and frontend agree on effective-slice detection.
|
|
115
|
+
|
|
116
|
+
- 43e4484: Batch hot-path scoped-db reads/writes into single transactions to cut per-query round-trips.
|
|
117
|
+
|
|
118
|
+
The scoped-db proxy wraps every standalone query in its own `BEGIN → SET LOCAL search_path → query → COMMIT`, so a path issuing N sequential queries paid N round-trips and checked out a connection N times. These reads/writes now run under one `withScopedTransaction`, collapsing the batch to a single `SET LOCAL` on one connection. Behavior is unchanged:
|
|
119
|
+
|
|
120
|
+
- healthcheck: `getSystemHealthOverview`'s `1 + N·(2+E)` read fan-out.
|
|
121
|
+
- incident/maintenance: `getIncident`/`getMaintenance` (4 reads), `getManyEntityStates`, `listOpenIncidentsBySystem` / `getActiveMaintenancesBySystem`, `getMaintenanceWindowsForRange`; the `list*` / `*ForSystem` per-row `N+1` system lookups collapsed to a single set-based `inArray` read; maintenance `transitionStatus` update+insert made atomic; `addUpdate`/`editUpdate`/`addLink` use `.returning()` instead of a follow-up re-select.
|
|
122
|
+
- ai: `appendMessage`, memory `saveOrUpdate`.
|
|
123
|
+
- notification: `resolveInheritedGroups`.
|
|
124
|
+
- status-page: subscriber `verify` (4 reads) and `unsubscribe` (3 reads).
|
|
125
|
+
- announcement: `getActiveAnnouncements` / `dismissAnnouncement` / `createAnnouncement`.
|
|
126
|
+
- gitops: `upsertProvenance`.
|
|
127
|
+
|
|
128
|
+
- 43e4484: Eliminate N+1 RPC fan-outs in the public status-page widget resolvers.
|
|
129
|
+
|
|
130
|
+
Each of these widgets renders a PUBLIC page, so every per-item RPC was real
|
|
131
|
+
external DB load. Three bulk-by-id endpoints replace the per-item fetches:
|
|
132
|
+
|
|
133
|
+
- `healthcheck-common`: new `getBulkRunStats({ systemIds, startDate, endDate,
|
|
134
|
+
maxBuckets })` -> `{ stats: Record<systemId, RunStats> }`. The `systemHealth`
|
|
135
|
+
widget's uptime column now issues ONE request for all systems instead of one
|
|
136
|
+
`getRunStats` per system. Systems with no runs in the window are omitted, so
|
|
137
|
+
the resolver's output is unchanged.
|
|
138
|
+
- `incident-common`: new `getBulkIncidentUpdates({ incidentIds })` ->
|
|
139
|
+
`{ updates: Record<incidentId, IncidentUpdate[]> }`. The incidents widget now
|
|
140
|
+
fetches every selected incident's update timeline in ONE request instead of
|
|
141
|
+
one `getIncident` per incident.
|
|
142
|
+
- `maintenance-common`: new `getBulkMaintenanceUpdates({ maintenanceIds })` ->
|
|
143
|
+
`{ updates: Record<maintenanceId, MaintenanceUpdate[]> }` (symmetric with the
|
|
144
|
+
incident endpoint) for the maintenance widget.
|
|
145
|
+
|
|
146
|
+
The new update endpoints apply the same per-item audience filter as
|
|
147
|
+
`getIncident` / `getMaintenance`, so internal/logged-in updates and author
|
|
148
|
+
identity never leak to a non-manager caller. Each endpoint is keyed by the
|
|
149
|
+
resource id and gated with the record post-filter (`recordKey`) matching the
|
|
150
|
+
single endpoint's read scope, mirroring `getBulkSystemHealthStatus` /
|
|
151
|
+
`getBulkIncidentsForSystems`. Widget DTO output is unchanged - this is a pure
|
|
152
|
+
request-count optimization.
|
|
153
|
+
|
|
154
|
+
- 43e4484: Status page enhancements:
|
|
155
|
+
|
|
156
|
+
- Group-status widget can collapse its member rows while every member is
|
|
157
|
+
operational (auto-expanding on any issue or maintenance).
|
|
158
|
+
- New "Announcements" status-page widget, contributed fully externally by the
|
|
159
|
+
announcement plugin: it surfaces active `visibility: "all"` announcements
|
|
160
|
+
through a public-safe DTO (title/message/severity/timestamps only) and never
|
|
161
|
+
affects the page status rollup.
|
|
162
|
+
- Incident and maintenance widgets can scope by catalog GROUPS with per-system
|
|
163
|
+
exceptions. Scope is resolved at read time (`(systemIds ∪ members(groupIds)) −
|
|
164
|
+
excludedSystemIds`), so members added to a group later are reflected
|
|
165
|
+
automatically. The builder gets a nested group/system picker.
|
|
166
|
+
- Incident and maintenance items on a public page link to dedicated public
|
|
167
|
+
detail pages, gated server-side to items the page's published widgets actually
|
|
168
|
+
surface (no enumeration, no internal-field leak). The custom-domain public
|
|
169
|
+
bundle gains a minimal in-memory router for the two detail pages.
|
|
170
|
+
- Fix the custom-domain "Cannot connect to Checkstack backend" screen: a
|
|
171
|
+
configured-but-not-servable custom domain now serves the lean public
|
|
172
|
+
"not available" page instead of the admin shell; the public bundle skips the
|
|
173
|
+
cross-origin `/api/config` probe; CORS admits resolved custom domains; the
|
|
174
|
+
request origin is normalized for proxy scheme/port variance; and re-saving an
|
|
175
|
+
unchanged custom domain no longer clears its verification.
|
|
176
|
+
- Anonymous email subscriptions (double opt-in) for incident updates, opt-in per
|
|
177
|
+
status page (`emailSubscriptionsEnabled`, default off): a new
|
|
178
|
+
`status_page_subscribers` table, public subscribe/verify/unsubscribe
|
|
179
|
+
procedures with constant-time responses that fail closed when the page has not
|
|
180
|
+
enabled subscriptions, and team-scoped admin list/remove + an enable toggle in
|
|
181
|
+
the builder. Emails are delivered through a new `sendRawEmail` primitive in
|
|
182
|
+
notification-backend that sends to an arbitrary external address (no auth
|
|
183
|
+
account) via every enabled email strategy (SMTP), with a mandatory unsubscribe
|
|
184
|
+
link.
|
|
185
|
+
- Incident/maintenance update fan-out to subscribers via a new
|
|
186
|
+
`notificationAudienceExtensionPoint` in notification-backend. Every
|
|
187
|
+
notification funnelled through `notifyForSubscription` (incident, maintenance,
|
|
188
|
+
health - all unchanged) now also invokes each registered audience sink exactly
|
|
189
|
+
once, enriched with the affected systems and their catalog groups (resolved
|
|
190
|
+
from notification-backend's own resource-parent graph, never a domain import).
|
|
191
|
+
status-page-backend contributes a sink that, AT SEND TIME, matches each
|
|
192
|
+
notification's affected systems against the systems each published + public +
|
|
193
|
+
email-enabled page currently surfaces in its incident/maintenance widgets
|
|
194
|
+
(honoring group membership and per-system exclusions) and emails that page's
|
|
195
|
+
verified subscribers. Send-time scoping against the live layout is the privacy
|
|
196
|
+
boundary: a page only ever emails about systems its widgets surface right now.
|
|
197
|
+
Because `notifyForSubscription` is a single-pod point RPC, each notification
|
|
198
|
+
fans out exactly once cluster-wide.
|
|
199
|
+
- Subscriber reconcile on page deletion: the subscriber FK is `ON DELETE
|
|
200
|
+
CASCADE` and page deletion also explicitly purges subscribers (invalidating
|
|
201
|
+
pending verify/unsubscribe tokens) - no orphan rows, no post-deletion send.
|
|
202
|
+
Removing all systems from a page or disabling email is intentionally NOT a
|
|
203
|
+
prune: send-time scoping plus the email-enabled gate make those subscribers
|
|
204
|
+
dormant with no data loss, and re-enabling restores the audience without a
|
|
205
|
+
re-subscribe.
|
|
206
|
+
- Send-time scoping is single-source: the fan-out asks each event-feed widget for
|
|
207
|
+
its CURRENT effective system scope (the same live catalog group expansion the
|
|
208
|
+
widget renders from) instead of a parallel copy of group membership, so it can
|
|
209
|
+
never over- or under-deliver relative to what the page shows.
|
|
210
|
+
- `sendRawEmail` in notification-backend is now `userType: "service"` (was an
|
|
211
|
+
authenticated procedure gated on `notification.send`). Sending to an arbitrary
|
|
212
|
+
address is an open-relay / email-bomb primitive, so it is callable only by a
|
|
213
|
+
trusted backend-to-backend caller (the status-page subscriber mailer), never by
|
|
214
|
+
an end user.
|
|
215
|
+
- Incident/maintenance widgets gain an optional per-system PUBLIC label override
|
|
216
|
+
(`systemLabels`), the same override path the system-health widget uses, so the
|
|
217
|
+
public incident/maintenance detail pages present clean labels instead of raw
|
|
218
|
+
catalog names.
|
|
219
|
+
- The anonymous subscribe endpoint adds a coarse per-page quota (max new
|
|
220
|
+
subscribers per rolling hour, counted over durable rows so it holds across
|
|
221
|
+
pods) on top of the per-(page,email) cooldown, capping verification-email
|
|
222
|
+
amplification. The quota is CONFIGURABLE per status page (new nullable
|
|
223
|
+
`email_subscribers_hourly_quota` column; null uses the default of 50, so
|
|
224
|
+
existing pages are unchanged), validated as a positive integer up to 5000,
|
|
225
|
+
editable in the builder next to the email opt-in toggle and gated by the same
|
|
226
|
+
page-manage capability.
|
|
227
|
+
- Email verification is now per-page configurable and backed by a platform-global
|
|
228
|
+
once-per-address registry:
|
|
229
|
+
- New `email_verification_required` column (boolean, default true) on
|
|
230
|
+
`status_pages`, exposed on the admin StatusPage DTO + `updateStatusPage`
|
|
231
|
+
input (same page-manage gate) with a builder toggle. When OFF, a new
|
|
232
|
+
subscriber is created active immediately - no verification email, and the
|
|
233
|
+
address is NOT written to the global registry (the operator's trust choice
|
|
234
|
+
for e.g. an internal page).
|
|
235
|
+
- New `status_page_verified_emails` table: one row per normalized address that
|
|
236
|
+
has completed verification on ANY page. When a verification-required page is
|
|
237
|
+
subscribed by an already-globally-verified address, the row is created active
|
|
238
|
+
immediately and a COURTESY email (with one-click unsubscribe) is sent instead
|
|
239
|
+
of a verification email, so a malicious add is always caught. `verify` upserts
|
|
240
|
+
the address into this registry and activates every other pending row for the
|
|
241
|
+
same address in one update (confirm once, all pages).
|
|
242
|
+
- Fan-out is unchanged: it still gates on the per-row `verified` flag; the
|
|
243
|
+
registry only governs whether a NEW subscribe short-circuits to active.
|
|
244
|
+
|
|
245
|
+
BREAKING CHANGE: `sendRawEmail` is now service-only. Any (non-existent in-tree)
|
|
246
|
+
authenticated caller must invoke it through a trusted service client instead.
|
|
247
|
+
|
|
248
|
+
Thanks to [@stuajnht](https://github.com/stuajnht) for the valuable feedback.
|
|
249
|
+
|
|
250
|
+
- Updated dependencies [43e4484]
|
|
251
|
+
- Updated dependencies [43e4484]
|
|
252
|
+
- Updated dependencies [43e4484]
|
|
253
|
+
- Updated dependencies [43e4484]
|
|
254
|
+
- Updated dependencies [43e4484]
|
|
255
|
+
- Updated dependencies [43e4484]
|
|
256
|
+
- Updated dependencies [43e4484]
|
|
257
|
+
- Updated dependencies [43e4484]
|
|
258
|
+
- Updated dependencies [43e4484]
|
|
259
|
+
- Updated dependencies [43e4484]
|
|
260
|
+
- Updated dependencies [43e4484]
|
|
261
|
+
- Updated dependencies [43e4484]
|
|
262
|
+
- Updated dependencies [43e4484]
|
|
263
|
+
- Updated dependencies [43e4484]
|
|
264
|
+
- Updated dependencies [43e4484]
|
|
265
|
+
- Updated dependencies [43e4484]
|
|
266
|
+
- Updated dependencies [43e4484]
|
|
267
|
+
- Updated dependencies [43e4484]
|
|
268
|
+
- Updated dependencies [43e4484]
|
|
269
|
+
- Updated dependencies [43e4484]
|
|
270
|
+
- Updated dependencies [43e4484]
|
|
271
|
+
- Updated dependencies [43e4484]
|
|
272
|
+
- Updated dependencies [43e4484]
|
|
273
|
+
- Updated dependencies [43e4484]
|
|
274
|
+
- Updated dependencies [43e4484]
|
|
275
|
+
- Updated dependencies [43e4484]
|
|
276
|
+
- Updated dependencies [43e4484]
|
|
277
|
+
- Updated dependencies [43e4484]
|
|
278
|
+
- @checkstack/ai-backend@0.10.10
|
|
279
|
+
- @checkstack/automation-backend@0.11.1
|
|
280
|
+
- @checkstack/catalog-common@2.7.0
|
|
281
|
+
- @checkstack/catalog-backend@1.7.0
|
|
282
|
+
- @checkstack/healthcheck-common@1.16.0
|
|
283
|
+
- @checkstack/backend-api@0.31.1
|
|
284
|
+
- @checkstack/incident-common@1.10.0
|
|
285
|
+
- @checkstack/incident-backend@1.12.0
|
|
286
|
+
- @checkstack/maintenance-common@1.10.0
|
|
287
|
+
- @checkstack/notification-common@1.6.0
|
|
288
|
+
- @checkstack/status-page-backend@0.5.0
|
|
289
|
+
- @checkstack/gitops-backend@0.5.22
|
|
290
|
+
- @checkstack/secrets-backend@0.3.4
|
|
291
|
+
- @checkstack/status-page-common@0.6.0
|
|
292
|
+
- @checkstack/satellite-backend@0.8.4
|
|
293
|
+
- @checkstack/sdk@0.127.1
|
|
294
|
+
- @checkstack/command-backend@0.2.22
|
|
295
|
+
- @checkstack/script-packages-backend@0.4.1
|
|
296
|
+
|
|
297
|
+
## 1.18.0
|
|
298
|
+
|
|
299
|
+
### Minor Changes
|
|
300
|
+
|
|
301
|
+
- 8aae4e2: Count fanned-out environment slices in the dashboard's "X of Y checks failing".
|
|
302
|
+
|
|
303
|
+
The dashboard problem card counted CHECKS, so a system with a single check that
|
|
304
|
+
fans out to three environments showed "Unhealthy 1 of 1 checks failing" even
|
|
305
|
+
when only one of the three environments was failing. It now counts (check ×
|
|
306
|
+
environment) slices: that system reads "1 of 3 checks failing", and a system
|
|
307
|
+
with a three-environment check plus a single-environment check with one
|
|
308
|
+
environment failing reads "1 of 4 checks failing". An env-less check counts as a
|
|
309
|
+
single slice, so a system with no environments reads exactly as before.
|
|
310
|
+
|
|
311
|
+
The per-check status DTO (`SystemCheckStatus`, returned by
|
|
312
|
+
`getSystemHealthStatus` / `getBulkSystemHealthStatus` /
|
|
313
|
+
`getBulkSystemHealthMatrix`) gains two fields: `sliceCount` (environment slices
|
|
314
|
+
this check currently fans out to, always >= 1) and `failingSliceCount` (how many
|
|
315
|
+
of those slices are non-healthy). `deriveHealthcheckSignals` sums them across
|
|
316
|
+
checks for the honest numerator/denominator.
|
|
317
|
+
|
|
318
|
+
- d0eddc9: Rework health-check scheduling to one recurring job per
|
|
319
|
+
`(configuration, system, environment)` slice and add a slow-check bulkhead so a
|
|
320
|
+
slow or unreachable check can no longer starve the healthy ones.
|
|
321
|
+
|
|
322
|
+
Previously a single recurring job per `(configuration, system)` fanned out over
|
|
323
|
+
every environment sequentially inside one tick, so the job held a concurrency
|
|
324
|
+
slot for the sum of all its environments, and a slow environment stalled its
|
|
325
|
+
siblings. Now each environment slice is its own recurring job that holds a slot
|
|
326
|
+
only for its own probe. A convergence reconciler (k8s-controller style) derives
|
|
327
|
+
the desired per-env job set from Postgres + catalog membership and converges the
|
|
328
|
+
queue toward it (schedule missing, cancel orphans, reschedule interval changes),
|
|
329
|
+
so it is self-healing across pods and stays correct as catalog membership
|
|
330
|
+
changes. It runs at boot, and system-scoped after an assignment or GitOps
|
|
331
|
+
change. `run_now` enqueues one one-off job per effective environment.
|
|
332
|
+
|
|
333
|
+
The system rollup (the bare `<systemId>` health entity every badge, SLO rule and
|
|
334
|
+
dependency map reads) is recomputed by an event-driven, debounced consumer that
|
|
335
|
+
subscribes to per-environment health changes and recomputes once per system per
|
|
336
|
+
window, instead of inline on every tick. Notifications stay owned by the
|
|
337
|
+
per-environment runs, so the rollup notification is structurally deduplicated.
|
|
338
|
+
|
|
339
|
+
The bulkhead classifies each slice's recent runs: a slice whose last K runs were
|
|
340
|
+
slow transport failures (held its slot ~the full timeout) is admitted to a
|
|
341
|
+
capped, pod-local lane (single-flight per slice) and probed with a timeout shrunk
|
|
342
|
+
toward its own healthy-latency baseline, or DEFERRED (recording nothing, freeing
|
|
343
|
+
the slot) when the lane is full or a prior run is still in flight. The adaptive
|
|
344
|
+
timeout has four deadlock guardrails: no baseline means no shrink, the baseline
|
|
345
|
+
uses only healthy runs, every Nth suspect run re-probes at the full timeout, and
|
|
346
|
+
an absolute floor. A healthy slice is never gated and always runs at the full
|
|
347
|
+
timeout. A new `checkstack.healthcheck.deferred{reason}` counter records
|
|
348
|
+
bulkhead deferrals.
|
|
349
|
+
|
|
350
|
+
Measured with the scale harness (240 checks, 20% unreachable, concurrency 10, 5s
|
|
351
|
+
timeout, 35s): with the bulkhead off the queue backlog climbs unbounded to 774
|
|
352
|
+
while 60 slow checks pin slots; with it on the backlog stays bounded (drains to
|
|
353
|
+
0), completions roughly triple (288 → 862), and slot-pinning timeouts drop
|
|
354
|
+
(60 → 12) as 207 suspect runs are deferred.
|
|
355
|
+
|
|
356
|
+
`@checkstack/test-utils-backend` gains a `withTransactionMock` helper that adds a
|
|
357
|
+
`.transaction(cb)` passthrough to a mock database, so tests can exercise code
|
|
358
|
+
that batches reads/writes through `withScopedTransaction`.
|
|
359
|
+
|
|
360
|
+
BREAKING CHANGE: the internal `HealthCheckJobPayload` now requires an
|
|
361
|
+
`environmentId` field and recurring health-check job IDs are per-environment
|
|
362
|
+
(`healthcheck:<config>:<system>[:<env>]`). This is an internal queue contract
|
|
363
|
+
with no external package API surface; on upgrade the reconciler cancels the
|
|
364
|
+
old-format jobs and schedules the per-environment set at boot.
|
|
365
|
+
|
|
366
|
+
- 8aae4e2: Show the last successful run per check (or per check+environment when fanned
|
|
367
|
+
out) in the system overview.
|
|
368
|
+
|
|
369
|
+
Each overview row that is currently degraded or unhealthy now shows when it was
|
|
370
|
+
last healthy (for example "Healthy until 2h ago", or "Never healthy" when it has
|
|
371
|
+
never succeeded), so operators can see at a glance since when a system has been
|
|
372
|
+
degraded or unhealthy without opening the drawer.
|
|
373
|
+
|
|
374
|
+
`getSystemHealthOverview` gains a `lastSuccessfulRunAt` field at both the check
|
|
375
|
+
level (most recent healthy run across all of the check's environments) and per
|
|
376
|
+
environment (`perEnvironment[].lastSuccessfulRunAt`). It is computed with a
|
|
377
|
+
dedicated max-per-environment aggregate query OUTSIDE the bounded sparkline
|
|
378
|
+
window, so it stays accurate even when a check has been failing for far longer
|
|
379
|
+
than the last runs shown in the sparkline.
|
|
380
|
+
|
|
381
|
+
### Patch Changes
|
|
382
|
+
|
|
383
|
+
- 8aae4e2: Stop sending a duplicate notification when a fanned-out system goes unhealthy.
|
|
384
|
+
|
|
385
|
+
A health check that fans out across environments notified once per environment
|
|
386
|
+
("... is unhealthy in environment X") AND once more for the system rollup
|
|
387
|
+
("... is unhealthy") in the same tick, so operators received two notifications
|
|
388
|
+
describing the same outage. The rollup transition is always driven by the very
|
|
389
|
+
environment(s) that already notified, so the rollup notification is now
|
|
390
|
+
suppressed whenever any environment notified this tick. It is still sent as a
|
|
391
|
+
fallback when no environment notified (e.g. every per-env delivery was
|
|
392
|
+
suppressed by policy/maintenance or threw), so a real status change is never
|
|
393
|
+
left entirely unannounced, and a system with no environments is unaffected.
|
|
394
|
+
|
|
395
|
+
Only the redundant user-facing notification is dropped: the rollup state
|
|
396
|
+
transition is still recorded and the `SYSTEM_STATUS_CHANGED` signal is still
|
|
397
|
+
broadcast, so SLO downtime, the dependency graph, the frontend, and automations
|
|
398
|
+
(which subscribe to the per-env and rollup entity changes) are unchanged.
|
|
399
|
+
|
|
400
|
+
- d0eddc9: Cut health-check connection churn and de-cluster the scheduling "thundering
|
|
401
|
+
herd" so per-run durations stop varying wildly for the same check against the
|
|
402
|
+
same target. Grounded in live OpenTelemetry phase histograms: per-run wall time
|
|
403
|
+
was dominated by TCP/TLS connection setup under a self-inflicted burst, not by
|
|
404
|
+
slow targets, CPU, or the database.
|
|
405
|
+
|
|
406
|
+
- **In-memory queue now honors `startDelay` in `scheduleRecurring`.** It was
|
|
407
|
+
silently dropped, so every recurring job (health checks included) fired
|
|
408
|
+
immediately on boot and then on a boot-anchored interval grid - keeping all
|
|
409
|
+
equal-interval checks phase-aligned forever. `scheduleRecurring` now defers the
|
|
410
|
+
first execution by `startDelay` and anchors the recurrence to that first fire,
|
|
411
|
+
matching the queue contract and the BullMQ backend's intent. Jobs scheduled
|
|
412
|
+
without `startDelay` are unchanged (first run is immediate).
|
|
413
|
+
- **The BullMQ queue now honors `startDelay` in `scheduleRecurring` too.** It also
|
|
414
|
+
dropped `startDelay`, and its `every` scheduler captures the grid phase from
|
|
415
|
+
whenever `upsertJobScheduler` first runs - so a bootstrap loop scheduling many
|
|
416
|
+
equal-interval jobs at ~the same instant handed them all the same phase.
|
|
417
|
+
`scheduleRecurring` now pins the first fire to `now + startDelay` via the
|
|
418
|
+
scheduler's `startDate`, which shifts the whole recurrence, so the same jittered
|
|
419
|
+
`startDelay` de-clusters checks on the Redis backend identically to the
|
|
420
|
+
in-memory one. Cron schedules (absolute times) are unaffected.
|
|
421
|
+
- **The health-check scheduler jitters each check's first fire** by a small,
|
|
422
|
+
deterministic fraction of its interval (stable across restarts, keyed on the
|
|
423
|
+
check). A synchronized set of checks now spreads across the interval instead of
|
|
424
|
+
hammering their targets at the same instant. Because the queue anchors the
|
|
425
|
+
recurrence to the first fire, this offset persists for every subsequent run.
|
|
426
|
+
- **The HTTP collector refreshes its TCP/TLS connect-timing probe in the
|
|
427
|
+
background, per origin, and never awaits it.** Bun's `fetch` already pools and
|
|
428
|
+
reuses connections across runs (verified: warm reuse survives 20s+ idle gaps),
|
|
429
|
+
but the timing probe opened a fresh handshake on EVERY run - mis-reporting the
|
|
430
|
+
reused request's real latency and doubling the connection count under a burst.
|
|
431
|
+
The probe now refreshes a per-origin sample at most once per TTL (60s) and runs
|
|
432
|
+
fully in the background: it is NEVER on a request's critical path. Pinned to one
|
|
433
|
+
resolved IP, the probe can be far slower than the reused fetch (e.g. an
|
|
434
|
+
intermittent IPv6 SYN retry the real request never pays), and per the collector
|
|
435
|
+
contract best-effort timing must never delay the check - the previous code
|
|
436
|
+
`await`ed it, so a slow probe's refresh run showed up as a latency outlier. The
|
|
437
|
+
`connect`/`tls` phases are now explicitly a cached, per-host estimate.
|
|
438
|
+
- **The run detail UI now labels the estimate.** The timing-breakdown caption
|
|
439
|
+
clarifies that DNS, wait, and transfer are measured on the request, while
|
|
440
|
+
connection and TLS setup are an estimate sampled from a periodic per-host probe
|
|
441
|
+
and cached briefly (about a minute), so an operator does not read the cached
|
|
442
|
+
connect/TLS value as a per-run measurement.
|
|
443
|
+
|
|
444
|
+
Behaviour is otherwise unchanged: health status and assertions are the same;
|
|
445
|
+
there are simply far fewer connections, the herd is spread out, and the timing
|
|
446
|
+
breakdown can no longer be inflated by a slow best-effort probe. No configuration
|
|
447
|
+
or API changes.
|
|
448
|
+
|
|
449
|
+
- d0eddc9: Cut the per-tick database work of the health-check executor by batching
|
|
450
|
+
scoped-database queries, and fix a dashboard "Recent activity" rendering bug.
|
|
451
|
+
|
|
452
|
+
The scoped-database proxy has to wrap every standalone query in its own
|
|
453
|
+
transaction so `SET LOCAL search_path` applies to it, which means a hot path
|
|
454
|
+
issuing many sequential queries pays the `BEGIN` / `SET LOCAL` / `COMMIT`
|
|
455
|
+
round-trips once per query and checks a connection out that many times. Two
|
|
456
|
+
changes remove most of that overhead on the health-check path:
|
|
457
|
+
|
|
458
|
+
- **New `withScopedTransaction` helper (`@checkstack/backend-api`).** A reusable
|
|
459
|
+
primitive for running several scoped queries under a SINGLE `SET LOCAL
|
|
460
|
+
search_path` transaction, plus `ScopedTransaction` / `ScopedQueryRunner`
|
|
461
|
+
types so a helper can accept either the scoped db or a transaction handle.
|
|
462
|
+
Use it on any scoped-db hot path that issues 2+ queries in sequence.
|
|
463
|
+
- **`getSystemHealthStatus` is now batched.** It was a `1 + N` read fan-out (one
|
|
464
|
+
associations query, then one run-window query per enabled check) run as `1 +
|
|
465
|
+
N` separate proxy transactions. It now runs as ONE transaction. This is the
|
|
466
|
+
hottest read on the platform - each check tick reads it several times, and the
|
|
467
|
+
dashboard, RPC router, and AI system-signals all call it - so the reduction in
|
|
468
|
+
transaction volume and connection churn is broad. The reads are also now a
|
|
469
|
+
single consistent snapshot.
|
|
470
|
+
- **The executor's run + aggregate writes are batched.** Each persisted run
|
|
471
|
+
previously issued the run `INSERT`, the aggregate `SELECT`, and the aggregate
|
|
472
|
+
`UPSERT` as three separate proxy transactions; they now run in one
|
|
473
|
+
transaction and commit atomically (the run and the aggregate it feeds can no
|
|
474
|
+
longer be persisted apart).
|
|
475
|
+
|
|
476
|
+
Behaviour is unchanged: the derived health status, transition detection, and
|
|
477
|
+
signals are identical; only the number of database transactions per tick drops.
|
|
478
|
+
|
|
479
|
+
Also fixes a dashboard bug where the "Recent activity" feed generated React keys
|
|
480
|
+
from `configurationName` plus a millisecond timestamp, so results from different
|
|
481
|
+
systems sharing a check name that completed in the same millisecond collided on
|
|
482
|
+
one key and React mis-reconciled the list (visually duplicated/omitted entries).
|
|
483
|
+
Keys are now derived from the system, configuration, and environment ids.
|
|
484
|
+
|
|
485
|
+
- d0eddc9: Add opt-in OpenTelemetry metrics with a Prometheus exporter so a performance
|
|
486
|
+
investigation can be grounded in real numbers from a running instance instead of
|
|
487
|
+
guesses.
|
|
488
|
+
|
|
489
|
+
The layer is **off by default and free when off**: the instruments are OTel
|
|
490
|
+
no-ops until a `MeterProvider` is registered, so the hot paths pay nothing until
|
|
491
|
+
you opt in.
|
|
492
|
+
|
|
493
|
+
- **`@checkstack/backend-api` gains an `instrumentation` module** exporting lazy,
|
|
494
|
+
memoized instrument accessors any plugin can record through:
|
|
495
|
+
`dbTransactionsCounter`, `dbQueriesCounter`, `healthcheckExecutionHistogram`,
|
|
496
|
+
`healthcheckPhaseHistogram`, `queueEnqueuedCounter`, `queueProcessedCounter`.
|
|
497
|
+
Each looks up its instrument once and is a no-op until the host registers a
|
|
498
|
+
provider, so callers can record unconditionally.
|
|
499
|
+
- **`@checkstack/backend` owns the SDK bootstrap.** `startMetrics()` registers a
|
|
500
|
+
global `MeterProvider` + Prometheus exporter when `CHECKSTACK_METRICS_ENABLED`
|
|
501
|
+
is set (host `127.0.0.1`, port `9464` by default, both overridable via
|
|
502
|
+
`CHECKSTACK_METRICS_HOST` / `CHECKSTACK_METRICS_PORT`). The exporter runs its
|
|
503
|
+
OWN HTTP server, NOT a route on the app, so it carries no app-auth surface. It
|
|
504
|
+
also registers host-owned observable instruments:
|
|
505
|
+
`checkstack.db.pool.connections` (admin/lock pool active/idle/waiting) and
|
|
506
|
+
`checkstack.runtime.event_loop_delay` (setInterval-drift histogram = JS-thread
|
|
507
|
+
block time).
|
|
508
|
+
- **The scoped-DB proxy records DB transactions/queries per plugin schema**, so
|
|
509
|
+
`db_transactions_total` minus `db_queries_total` per schema is exactly the
|
|
510
|
+
number of batched transactions - a live check that `withScopedTransaction`
|
|
511
|
+
batching is taking effect.
|
|
512
|
+
- **The health-check executor records execution + per-phase histograms**
|
|
513
|
+
(`connect`, `wait`, ...) so a high `connect` p95 with a low `wait` points at
|
|
514
|
+
connection establishment rather than a slow target or a CPU-bound platform.
|
|
515
|
+
- **The in-memory queue records enqueued/processed counters** per queue and
|
|
516
|
+
status.
|
|
517
|
+
|
|
518
|
+
No behaviour changes when disabled. Enable with `CHECKSTACK_METRICS_ENABLED=1`
|
|
519
|
+
and scrape `http://127.0.0.1:9464/metrics`. See the backend observability guide
|
|
520
|
+
for the full metric list and interpretation.
|
|
521
|
+
|
|
522
|
+
- Updated dependencies [8aae4e2]
|
|
523
|
+
- Updated dependencies [f93ee7a]
|
|
524
|
+
- Updated dependencies [f93ee7a]
|
|
525
|
+
- Updated dependencies [8aae4e2]
|
|
526
|
+
- Updated dependencies [d0eddc9]
|
|
527
|
+
- Updated dependencies [d0eddc9]
|
|
528
|
+
- Updated dependencies [f93ee7a]
|
|
529
|
+
- Updated dependencies [f93ee7a]
|
|
530
|
+
- Updated dependencies [d0eddc9]
|
|
531
|
+
- Updated dependencies [d0eddc9]
|
|
532
|
+
- Updated dependencies [8aae4e2]
|
|
533
|
+
- Updated dependencies [d0eddc9]
|
|
534
|
+
- Updated dependencies [f93ee7a]
|
|
535
|
+
- @checkstack/healthcheck-common@1.15.0
|
|
536
|
+
- @checkstack/common@0.22.0
|
|
537
|
+
- @checkstack/catalog-common@2.6.3
|
|
538
|
+
- @checkstack/ai-backend@0.10.9
|
|
539
|
+
- @checkstack/backend-api@0.31.0
|
|
540
|
+
- @checkstack/automation-backend@0.11.0
|
|
541
|
+
- @checkstack/incident-common@1.9.0
|
|
542
|
+
- @checkstack/incident-backend@1.11.0
|
|
543
|
+
- @checkstack/maintenance-common@1.9.0
|
|
544
|
+
- @checkstack/script-packages-backend@0.4.0
|
|
545
|
+
- @checkstack/satellite-backend@0.8.3
|
|
546
|
+
- @checkstack/sdk@0.126.1
|
|
547
|
+
- @checkstack/ai-common@0.6.6
|
|
548
|
+
- @checkstack/cache-api@0.3.19
|
|
549
|
+
- @checkstack/catalog-backend@1.6.9
|
|
550
|
+
- @checkstack/command-backend@0.2.21
|
|
551
|
+
- @checkstack/gitops-backend@0.5.21
|
|
552
|
+
- @checkstack/gitops-common@0.7.3
|
|
553
|
+
- @checkstack/notification-common@1.5.3
|
|
554
|
+
- @checkstack/queue-api@0.3.19
|
|
555
|
+
- @checkstack/secrets-backend@0.3.3
|
|
556
|
+
- @checkstack/secrets-common@0.3.2
|
|
557
|
+
- @checkstack/signal-common@0.2.17
|
|
558
|
+
- @checkstack/status-page-backend@0.4.8
|
|
559
|
+
- @checkstack/status-page-common@0.5.3
|
|
560
|
+
- @checkstack/cache-utils@0.2.24
|
|
561
|
+
|
|
3
562
|
## 1.17.0
|
|
4
563
|
|
|
5
564
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/healthcheck-backend",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.19.0",
|
|
4
4
|
"license": "Elastic-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -14,32 +14,32 @@
|
|
|
14
14
|
"lint:code": "eslint . --max-warnings 0"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@checkstack/ai-backend": "0.10.
|
|
18
|
-
"@checkstack/ai-common": "0.6.
|
|
19
|
-
"@checkstack/automation-backend": "0.
|
|
20
|
-
"@checkstack/backend-api": "0.
|
|
21
|
-
"@checkstack/cache-api": "0.3.
|
|
22
|
-
"@checkstack/cache-utils": "0.2.
|
|
23
|
-
"@checkstack/catalog-backend": "1.
|
|
24
|
-
"@checkstack/catalog-common": "2.
|
|
25
|
-
"@checkstack/command-backend": "0.2.
|
|
26
|
-
"@checkstack/common": "0.
|
|
27
|
-
"@checkstack/gitops-backend": "0.5.
|
|
28
|
-
"@checkstack/gitops-common": "0.7.
|
|
29
|
-
"@checkstack/healthcheck-common": "1.
|
|
30
|
-
"@checkstack/incident-backend": "1.
|
|
31
|
-
"@checkstack/incident-common": "1.
|
|
32
|
-
"@checkstack/maintenance-common": "1.
|
|
33
|
-
"@checkstack/notification-common": "1.
|
|
34
|
-
"@checkstack/queue-api": "0.3.
|
|
35
|
-
"@checkstack/satellite-backend": "0.8.
|
|
36
|
-
"@checkstack/script-packages-backend": "0.
|
|
37
|
-
"@checkstack/sdk": "0.
|
|
38
|
-
"@checkstack/secrets-backend": "0.3.
|
|
39
|
-
"@checkstack/secrets-common": "0.3.
|
|
40
|
-
"@checkstack/signal-common": "0.2.
|
|
41
|
-
"@checkstack/status-page-backend": "0.
|
|
42
|
-
"@checkstack/status-page-common": "0.
|
|
17
|
+
"@checkstack/ai-backend": "0.10.10",
|
|
18
|
+
"@checkstack/ai-common": "0.6.6",
|
|
19
|
+
"@checkstack/automation-backend": "0.11.1",
|
|
20
|
+
"@checkstack/backend-api": "0.31.1",
|
|
21
|
+
"@checkstack/cache-api": "0.3.19",
|
|
22
|
+
"@checkstack/cache-utils": "0.2.24",
|
|
23
|
+
"@checkstack/catalog-backend": "1.7.0",
|
|
24
|
+
"@checkstack/catalog-common": "2.7.0",
|
|
25
|
+
"@checkstack/command-backend": "0.2.22",
|
|
26
|
+
"@checkstack/common": "0.22.0",
|
|
27
|
+
"@checkstack/gitops-backend": "0.5.22",
|
|
28
|
+
"@checkstack/gitops-common": "0.7.3",
|
|
29
|
+
"@checkstack/healthcheck-common": "1.16.0",
|
|
30
|
+
"@checkstack/incident-backend": "1.12.0",
|
|
31
|
+
"@checkstack/incident-common": "1.10.0",
|
|
32
|
+
"@checkstack/maintenance-common": "1.10.0",
|
|
33
|
+
"@checkstack/notification-common": "1.6.0",
|
|
34
|
+
"@checkstack/queue-api": "0.3.19",
|
|
35
|
+
"@checkstack/satellite-backend": "0.8.4",
|
|
36
|
+
"@checkstack/script-packages-backend": "0.4.1",
|
|
37
|
+
"@checkstack/sdk": "0.127.1",
|
|
38
|
+
"@checkstack/secrets-backend": "0.3.4",
|
|
39
|
+
"@checkstack/secrets-common": "0.3.2",
|
|
40
|
+
"@checkstack/signal-common": "0.2.17",
|
|
41
|
+
"@checkstack/status-page-backend": "0.5.0",
|
|
42
|
+
"@checkstack/status-page-common": "0.6.0",
|
|
43
43
|
"@hono/zod-validator": "^0.7.6",
|
|
44
44
|
"@orpc/contract": "^1.14.4",
|
|
45
45
|
"@orpc/server": "^1.14.4",
|
|
@@ -52,13 +52,16 @@
|
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@checkstack/drizzle-helper": "0.0.6",
|
|
55
|
-
"@checkstack/scripts": "0.7.
|
|
56
|
-
"@checkstack/test-utils-backend": "0.1.
|
|
55
|
+
"@checkstack/scripts": "0.7.3",
|
|
56
|
+
"@checkstack/test-utils-backend": "0.1.56",
|
|
57
57
|
"@checkstack/tsconfig": "0.0.7",
|
|
58
58
|
"@types/bun": "^1.0.0",
|
|
59
|
+
"@types/pg": "^8.20.0",
|
|
59
60
|
"@types/tdigest": "^0.1.5",
|
|
61
|
+
"bullmq": "^5.66.4",
|
|
60
62
|
"date-fns": "^4.4.0",
|
|
61
63
|
"drizzle-kit": "^0.31.10",
|
|
64
|
+
"pg": "^8.21.0",
|
|
62
65
|
"typescript": "^5.0.0"
|
|
63
66
|
}
|
|
64
67
|
}
|