@checkstack/backend 0.4.9 → 0.4.11
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,45 @@
|
|
|
1
1
|
# @checkstack/backend
|
|
2
2
|
|
|
3
|
+
## 0.4.11
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 48c2080: Migrate aggregation from batch to incremental (`mergeResult`)
|
|
8
|
+
|
|
9
|
+
### Breaking Changes (Internal)
|
|
10
|
+
|
|
11
|
+
- Replaced `aggregateResult(runs[])` with `mergeResult(existing, run)` interface across all HealthCheckStrategy and CollectorStrategy implementations
|
|
12
|
+
|
|
13
|
+
### New Features
|
|
14
|
+
|
|
15
|
+
- Added incremental aggregation utilities in `@checkstack/backend-api`:
|
|
16
|
+
- `mergeCounter()` - track occurrences
|
|
17
|
+
- `mergeAverage()` - track sum/count, compute avg
|
|
18
|
+
- `mergeRate()` - track success/total, compute %
|
|
19
|
+
- `mergeMinMax()` - track min/max values
|
|
20
|
+
- Exported Zod schemas for internal state: `averageStateSchema`, `rateStateSchema`, `minMaxStateSchema`, `counterStateSchema`
|
|
21
|
+
|
|
22
|
+
### Improvements
|
|
23
|
+
|
|
24
|
+
- Enables O(1) storage overhead by maintaining incremental aggregation state
|
|
25
|
+
- Prepares for real-time hourly aggregation without batch accumulation
|
|
26
|
+
|
|
27
|
+
- Updated dependencies [f676e11]
|
|
28
|
+
- Updated dependencies [48c2080]
|
|
29
|
+
- @checkstack/common@0.6.2
|
|
30
|
+
- @checkstack/backend-api@0.6.0
|
|
31
|
+
- @checkstack/api-docs-common@0.1.6
|
|
32
|
+
- @checkstack/auth-common@0.5.5
|
|
33
|
+
- @checkstack/signal-backend@0.1.9
|
|
34
|
+
- @checkstack/signal-common@0.1.6
|
|
35
|
+
- @checkstack/queue-api@0.2.3
|
|
36
|
+
|
|
37
|
+
## 0.4.10
|
|
38
|
+
|
|
39
|
+
### Patch Changes
|
|
40
|
+
|
|
41
|
+
- f8ce585: Improved RPC error logging to include full stack traces for procedure errors. Previously, errors inside RPC handlers (such as database table not found errors) resulted in silent 500 responses. Now these errors are logged with detailed information to the backend console for easier debugging.
|
|
42
|
+
|
|
3
43
|
## 0.4.9
|
|
4
44
|
|
|
5
45
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checkstack/backend",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "bun --env-file=../../.env --watch src/index.ts",
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
"lint:code": "eslint . --max-warnings 0"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@checkstack/api-docs-common": "0.1.
|
|
14
|
-
"@checkstack/auth-common": "0.5.
|
|
15
|
-
"@checkstack/backend-api": "0.5.
|
|
16
|
-
"@checkstack/common": "0.6.
|
|
17
|
-
"@checkstack/drizzle-helper": "0.0.
|
|
18
|
-
"@checkstack/queue-api": "0.2.
|
|
19
|
-
"@checkstack/signal-backend": "0.1.
|
|
20
|
-
"@checkstack/signal-common": "0.1.
|
|
13
|
+
"@checkstack/api-docs-common": "0.1.5",
|
|
14
|
+
"@checkstack/auth-common": "0.5.4",
|
|
15
|
+
"@checkstack/backend-api": "0.5.2",
|
|
16
|
+
"@checkstack/common": "0.6.1",
|
|
17
|
+
"@checkstack/drizzle-helper": "0.0.3",
|
|
18
|
+
"@checkstack/queue-api": "0.2.2",
|
|
19
|
+
"@checkstack/signal-backend": "0.1.8",
|
|
20
|
+
"@checkstack/signal-common": "0.1.5",
|
|
21
21
|
"@hono/zod-validator": "^0.7.6",
|
|
22
22
|
"@orpc/client": "^1.13.2",
|
|
23
23
|
"@orpc/openapi": "^1.13.2",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"drizzle-kit": "^0.31.8",
|
|
36
36
|
"@types/pg": "^8.11.0",
|
|
37
37
|
"@types/bun": "latest",
|
|
38
|
-
"@checkstack/tsconfig": "0.0.
|
|
39
|
-
"@checkstack/scripts": "0.1.
|
|
40
|
-
"@checkstack/test-utils-backend": "0.1.
|
|
38
|
+
"@checkstack/tsconfig": "0.0.3",
|
|
39
|
+
"@checkstack/scripts": "0.1.1",
|
|
40
|
+
"@checkstack/test-utils-backend": "0.1.8"
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -55,7 +55,7 @@ describe("HealthCheck Plugin Integration", () => {
|
|
|
55
55
|
schema: z.record(z.string(), z.unknown()),
|
|
56
56
|
}),
|
|
57
57
|
createClient: mockCreateClient,
|
|
58
|
-
|
|
58
|
+
mergeResult: mock(() => ({})),
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
// 2. Define a mock plugin that registers this strategy
|
|
@@ -56,21 +56,42 @@ export function createApiRouteHandler({
|
|
|
56
56
|
rootRpcRouter[pluginId] = router;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
// Resolve logger first for use in interceptor
|
|
60
|
+
const logger = await getService(coreServices.logger);
|
|
61
|
+
|
|
59
62
|
const rpcHandler = new RPCHandler(
|
|
60
|
-
rootRpcRouter as ConstructorParameters<typeof RPCHandler>[0]
|
|
63
|
+
rootRpcRouter as ConstructorParameters<typeof RPCHandler>[0],
|
|
64
|
+
{
|
|
65
|
+
interceptors: [
|
|
66
|
+
async ({ next, ...rest }) => {
|
|
67
|
+
try {
|
|
68
|
+
return await next(rest);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (logger) {
|
|
71
|
+
(logger as Logger).error(
|
|
72
|
+
`RPC procedure error: ${String(error)}`,
|
|
73
|
+
);
|
|
74
|
+
if (error instanceof Error && error.stack) {
|
|
75
|
+
(logger as Logger).error(`Stack trace: ${error.stack}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
},
|
|
61
83
|
);
|
|
62
84
|
|
|
63
85
|
// Resolve core services for RPC context
|
|
64
86
|
const auth = await getService(coreServices.auth);
|
|
65
|
-
const logger = await getService(coreServices.logger);
|
|
66
87
|
const db = await getService(coreServices.database);
|
|
67
88
|
const fetch = await getService(coreServices.fetch);
|
|
68
89
|
const healthCheckRegistry = await getService(
|
|
69
|
-
coreServices.healthCheckRegistry
|
|
90
|
+
coreServices.healthCheckRegistry,
|
|
70
91
|
);
|
|
71
92
|
const collectorRegistry = await getService(coreServices.collectorRegistry);
|
|
72
93
|
const queuePluginRegistry = await getService(
|
|
73
|
-
coreServices.queuePluginRegistry
|
|
94
|
+
coreServices.queuePluginRegistry,
|
|
74
95
|
);
|
|
75
96
|
const queueManager = await getService(coreServices.queueManager);
|
|
76
97
|
const eventBus = await getService(coreServices.eventBus);
|
|
@@ -119,29 +140,24 @@ export function createApiRouteHandler({
|
|
|
119
140
|
};
|
|
120
141
|
|
|
121
142
|
// 1. Try oRPC first
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
if (matched) {
|
|
129
|
-
return c.newResponse(response.body, response);
|
|
130
|
-
}
|
|
143
|
+
const { matched, response } = await rpcHandler.handle(c.req.raw, {
|
|
144
|
+
prefix: "/api",
|
|
145
|
+
context,
|
|
146
|
+
});
|
|
131
147
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
logger.error(`RPC Handler error: ${String(error)}`);
|
|
148
|
+
if (matched) {
|
|
149
|
+
return c.newResponse(response.body, response);
|
|
135
150
|
}
|
|
136
151
|
|
|
152
|
+
logger.debug(`RPC mismatch for: ${c.req.method} ${pathname}`);
|
|
153
|
+
|
|
137
154
|
// 2. Try native handlers
|
|
138
155
|
// Sort by path length (descending) to ensure more specific paths are tried first
|
|
139
|
-
const sortedHandlers = [...pluginHttpHandlers.entries()].toSorted(
|
|
140
|
-
a,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
});
|
|
156
|
+
const sortedHandlers = [...pluginHttpHandlers.entries()].toSorted(
|
|
157
|
+
function (a, b) {
|
|
158
|
+
return b[0].length - a[0].length;
|
|
159
|
+
},
|
|
160
|
+
);
|
|
145
161
|
|
|
146
162
|
for (const [path, handler] of sortedHandlers) {
|
|
147
163
|
if (pathname.startsWith(path)) {
|
|
@@ -158,7 +174,7 @@ export function createApiRouteHandler({
|
|
|
158
174
|
*/
|
|
159
175
|
export function registerApiRoute(
|
|
160
176
|
rootRouter: Hono,
|
|
161
|
-
handler: ReturnType<typeof createApiRouteHandler
|
|
177
|
+
handler: ReturnType<typeof createApiRouteHandler>,
|
|
162
178
|
) {
|
|
163
179
|
rootRouter.all("/api/:pluginId/*", handler);
|
|
164
180
|
}
|
|
@@ -36,9 +36,9 @@ describe("CoreHealthCheckRegistry", () => {
|
|
|
36
36
|
schema: z.record(z.string(), z.unknown()),
|
|
37
37
|
}),
|
|
38
38
|
createClient: mock(() =>
|
|
39
|
-
Promise.resolve({ client: { exec: async () => ({}) }, close: () => {} })
|
|
39
|
+
Promise.resolve({ client: { exec: async () => ({}) }, close: () => {} }),
|
|
40
40
|
),
|
|
41
|
-
|
|
41
|
+
mergeResult: mock(() => ({})),
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
const mockStrategy2: HealthCheckStrategy = {
|
|
@@ -58,9 +58,9 @@ describe("CoreHealthCheckRegistry", () => {
|
|
|
58
58
|
schema: z.record(z.string(), z.unknown()),
|
|
59
59
|
}),
|
|
60
60
|
createClient: mock(() =>
|
|
61
|
-
Promise.resolve({ client: { exec: async () => ({}) }, close: () => {} })
|
|
61
|
+
Promise.resolve({ client: { exec: async () => ({}) }, close: () => {} }),
|
|
62
62
|
),
|
|
63
|
-
|
|
63
|
+
mergeResult: mock(() => ({})),
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
beforeEach(() => {
|