@checkstack/common 0.6.4 → 0.7.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 +39 -0
- package/package.json +3 -3
- package/src/chart-types.ts +63 -5
- package/src/error-utils.test.ts +30 -0
- package/src/error-utils.ts +16 -0
- package/src/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# @checkstack/common
|
|
2
2
|
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8d1ef12: Phase 2 of anomaly detection: trend drift detection.
|
|
8
|
+
|
|
9
|
+
The background baseline analyzer now computes a linear regression slope across each field's chronologically-ordered history and runs a `detectDrift` evaluator that catches gradual "creeping degradation" never reaching the 3σ spike threshold. Drifts share the same `anomalies` table as spike anomalies via a new `kind` column (`spike` | `drift`, default `spike`); the existing suspicious → anomaly → recovered lifecycle is reused, ticking at the analyzer's hourly cadence with a default 2-run confirmation window.
|
|
10
|
+
|
|
11
|
+
User-facing additions: a Trend Drift toggle and threshold slider on both the template and assignment anomaly settings panels (with per-field overrides), drift rows in the System Anomaly widget, dashed regression-line overlays on the auto-generated line charts, and a new `ANOMALY_TREND_DETECTED` signal for live UI updates. Plugin authors can disable drift per chartable field via `x-anomaly-drift-enabled: false` or tighten/loosen it via `x-anomaly-drift-threshold`.
|
|
12
|
+
|
|
13
|
+
## 0.6.5
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- d1a2796: Enforce stricter code quality standards and eliminate AI slop anti-patterns.
|
|
18
|
+
|
|
19
|
+
**New utility**
|
|
20
|
+
|
|
21
|
+
- `extractErrorMessage(error, fallback?)` in `@checkstack/common` for consistent error extraction
|
|
22
|
+
|
|
23
|
+
**ESLint rules**
|
|
24
|
+
|
|
25
|
+
- `react-hooks/rules-of-hooks` and `exhaustive-deps` for hook correctness
|
|
26
|
+
- `no-console` in frontend packages — forces `toast` over silent `console.error`
|
|
27
|
+
- `no-restricted-syntax` banning `instanceof Error` — forces `extractErrorMessage`
|
|
28
|
+
- Custom `no-eslint-disable-any` rule preventing `@typescript-eslint/no-explicit-any` circumvention
|
|
29
|
+
|
|
30
|
+
**Refactoring**
|
|
31
|
+
|
|
32
|
+
- Replace 141 `instanceof Error` boilerplate patterns across the codebase
|
|
33
|
+
- Replace swallowed `console.error` with user-visible `toast.error()` feedback
|
|
34
|
+
- Remove 15 redundant `as` type casts in IntegrationsPage and ProviderConnectionsPage
|
|
35
|
+
- Consolidate 3 identical callback handlers into `handleDialogClose`
|
|
36
|
+
- Fix conditional React hook call in `FormField.tsx`
|
|
37
|
+
- Fix unstable useMemo deps in `Dashboard.tsx`
|
|
38
|
+
- Replace `useEffect`→`setState` with derived `useMemo` in `RegisterPage.tsx`
|
|
39
|
+
- Rewrite `keystore.test.ts` with typed `DrizzleMockChain` (eliminating 7 `any` suppressions)
|
|
40
|
+
- Delete obvious comments in `encryption.ts` and Teams `provider.ts`
|
|
41
|
+
|
|
3
42
|
## 0.6.4
|
|
4
43
|
|
|
5
44
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/common",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"typescript": "^5.7.2",
|
|
21
|
-
"@checkstack/tsconfig": "0.0.
|
|
22
|
-
"@checkstack/scripts": "0.1.
|
|
21
|
+
"@checkstack/tsconfig": "0.0.5",
|
|
22
|
+
"@checkstack/scripts": "0.1.2"
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"typecheck": "tsc --noEmit",
|
package/src/chart-types.ts
CHANGED
|
@@ -23,12 +23,9 @@ export type ChartType =
|
|
|
23
23
|
| "status";
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
* Provides autocompletion for chart-related metadata on result fields.
|
|
26
|
+
* Base metadata for all health check result schema fields.
|
|
28
27
|
*/
|
|
29
|
-
export interface
|
|
30
|
-
/** The type of chart to render for this field */
|
|
31
|
-
"x-chart-type"?: ChartType;
|
|
28
|
+
export interface BaseHealthResultMeta {
|
|
32
29
|
/** Human-readable label for the chart (defaults to field name) */
|
|
33
30
|
"x-chart-label"?: string;
|
|
34
31
|
/** Unit suffix for values (e.g., 'ms', '%', 'req/s') */
|
|
@@ -40,4 +37,65 @@ export interface HealthResultMeta {
|
|
|
40
37
|
* Ephemeral fields are stripped before storing results in the database.
|
|
41
38
|
*/
|
|
42
39
|
"x-ephemeral"?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Sensitivity multiplier for this field (default: 1.0).
|
|
42
|
+
* Higher values = fewer alerts (wider threshold).
|
|
43
|
+
* Lower values = more alerts (tighter threshold).
|
|
44
|
+
* Applied as: threshold = μ ± (3σ × sensitivity)
|
|
45
|
+
*/
|
|
46
|
+
"x-anomaly-sensitivity"?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Override the default confirmation window for this field.
|
|
49
|
+
* Number of consecutive anomalous data points required before an alert is raised.
|
|
50
|
+
*/
|
|
51
|
+
"x-anomaly-confirmation-window"?: number;
|
|
52
|
+
/**
|
|
53
|
+
* Enable trend drift detection for this field. Default true (when anomaly
|
|
54
|
+
* detection is enabled). Set false to suppress drift alerts but keep spike
|
|
55
|
+
* detection active.
|
|
56
|
+
*/
|
|
57
|
+
"x-anomaly-drift-enabled"?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Sigma multiplier on the drift trigger band (default 2). Drift fires when
|
|
60
|
+
* |slope × sampleCount| > threshold × σ × sensitivity.
|
|
61
|
+
*/
|
|
62
|
+
"x-anomaly-drift-threshold"?: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Metadata for a field that exposes a chart AND has anomaly detection enabled.
|
|
67
|
+
*/
|
|
68
|
+
export interface ChartMetaAnomalyEnabled extends BaseHealthResultMeta {
|
|
69
|
+
"x-chart-type": ChartType;
|
|
70
|
+
"x-anomaly-enabled": true;
|
|
71
|
+
"x-anomaly-direction": "higher-is-better" | "lower-is-better" | "deviation" | "dominance";
|
|
43
72
|
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Metadata for a field that exposes a chart but explicitly disables anomaly detection.
|
|
76
|
+
*/
|
|
77
|
+
export interface ChartMetaAnomalyDisabled extends BaseHealthResultMeta {
|
|
78
|
+
"x-chart-type": ChartType;
|
|
79
|
+
"x-anomaly-enabled": false;
|
|
80
|
+
"x-anomaly-direction"?: never;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Metadata for a field that does NOT expose a chart.
|
|
85
|
+
*/
|
|
86
|
+
export interface NonChartMeta extends BaseHealthResultMeta {
|
|
87
|
+
"x-chart-type"?: never;
|
|
88
|
+
"x-anomaly-enabled"?: never;
|
|
89
|
+
"x-anomaly-direction"?: never;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Metadata type for health check result schemas.
|
|
94
|
+
* Provides autocompletion and enforces that ANY field exposing a chart
|
|
95
|
+
* MUST explicitly define its anomaly behavior.
|
|
96
|
+
*/
|
|
97
|
+
export type HealthResultMeta =
|
|
98
|
+
| ChartMetaAnomalyEnabled
|
|
99
|
+
| ChartMetaAnomalyDisabled
|
|
100
|
+
| NonChartMeta;
|
|
101
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { describe, it, expect } from "bun:test";
|
|
2
|
+
import { extractErrorMessage } from "./error-utils";
|
|
3
|
+
|
|
4
|
+
describe("extractErrorMessage", () => {
|
|
5
|
+
it("should extract message from Error instances", () => {
|
|
6
|
+
const error = new Error("something went wrong");
|
|
7
|
+
expect(extractErrorMessage(error)).toBe("something went wrong");
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("should extract message from Error subclasses", () => {
|
|
11
|
+
const error = new TypeError("invalid type");
|
|
12
|
+
expect(extractErrorMessage(error)).toBe("invalid type");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("should return string errors directly", () => {
|
|
16
|
+
expect(extractErrorMessage("network failure")).toBe("network failure");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should return the default fallback for non-Error, non-string values", () => {
|
|
20
|
+
expect(extractErrorMessage(42)).toBe("An error occurred");
|
|
21
|
+
expect(extractErrorMessage(undefined)).toBe("An error occurred");
|
|
22
|
+
// eslint-disable-next-line unicorn/no-null
|
|
23
|
+
expect(extractErrorMessage(null)).toBe("An error occurred");
|
|
24
|
+
expect(extractErrorMessage({ code: 500 })).toBe("An error occurred");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should return custom fallback when provided", () => {
|
|
28
|
+
expect(extractErrorMessage(42, "Custom fallback")).toBe("Custom fallback");
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts a human-readable message from an unknown error value.
|
|
3
|
+
*
|
|
4
|
+
* Handles Error instances, plain strings, and arbitrary values.
|
|
5
|
+
* Designed as a single source of truth — use this instead of
|
|
6
|
+
* inline `error instanceof Error ? error.message : fallback` patterns.
|
|
7
|
+
*/
|
|
8
|
+
export function extractErrorMessage(
|
|
9
|
+
error: unknown,
|
|
10
|
+
fallback = "An error occurred",
|
|
11
|
+
): string {
|
|
12
|
+
// eslint-disable-next-line no-restricted-syntax -- This IS the canonical implementation
|
|
13
|
+
if (error instanceof Error) return error.message;
|
|
14
|
+
if (typeof error === "string") return error;
|
|
15
|
+
return fallback;
|
|
16
|
+
}
|
package/src/index.ts
CHANGED