@checkstack/healthcheck-script-backend 0.0.2

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 ADDED
@@ -0,0 +1,37 @@
1
+ # @checkstack/healthcheck-script-backend
2
+
3
+ ## 0.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - d20d274: Initial release of all @checkstack packages. Rebranded from Checkmate to Checkstack with new npm organization @checkstack and domain checkstack.dev.
8
+ - Updated dependencies [d20d274]
9
+ - @checkstack/backend-api@0.0.2
10
+ - @checkstack/common@0.0.2
11
+ - @checkstack/healthcheck-common@0.0.2
12
+
13
+ ## 0.0.3
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [b4eb432]
18
+ - Updated dependencies [a65e002]
19
+ - @checkstack/backend-api@1.1.0
20
+ - @checkstack/common@0.2.0
21
+ - @checkstack/healthcheck-common@0.1.1
22
+
23
+ ## 0.0.2
24
+
25
+ ### Patch Changes
26
+
27
+ - Updated dependencies [ffc28f6]
28
+ - Updated dependencies [4dd644d]
29
+ - Updated dependencies [71275dd]
30
+ - Updated dependencies [ae19ff6]
31
+ - Updated dependencies [0babb9c]
32
+ - Updated dependencies [b55fae6]
33
+ - Updated dependencies [b354ab3]
34
+ - Updated dependencies [81f3f85]
35
+ - @checkstack/common@0.1.0
36
+ - @checkstack/backend-api@1.0.0
37
+ - @checkstack/healthcheck-common@0.1.0
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@checkstack/healthcheck-script-backend",
3
+ "version": "0.0.2",
4
+ "type": "module",
5
+ "main": "src/index.ts",
6
+ "scripts": {
7
+ "typecheck": "tsc --noEmit",
8
+ "lint": "bun run lint:code",
9
+ "lint:code": "eslint . --max-warnings 0"
10
+ },
11
+ "dependencies": {
12
+ "@checkstack/backend-api": "workspace:*",
13
+ "@checkstack/common": "workspace:*",
14
+ "@checkstack/healthcheck-common": "workspace:*"
15
+ },
16
+ "devDependencies": {
17
+ "@types/bun": "^1.0.0",
18
+ "typescript": "^5.0.0",
19
+ "@checkstack/tsconfig": "workspace:*",
20
+ "@checkstack/scripts": "workspace:*"
21
+ }
22
+ }
package/src/index.ts ADDED
@@ -0,0 +1,23 @@
1
+ import {
2
+ createBackendPlugin,
3
+ coreServices,
4
+ } from "@checkstack/backend-api";
5
+ import { ScriptHealthCheckStrategy } from "./strategy";
6
+ import { pluginMetadata } from "./plugin-metadata";
7
+
8
+ export default createBackendPlugin({
9
+ metadata: pluginMetadata,
10
+ register(env) {
11
+ env.registerInit({
12
+ deps: {
13
+ healthCheckRegistry: coreServices.healthCheckRegistry,
14
+ logger: coreServices.logger,
15
+ },
16
+ init: async ({ healthCheckRegistry, logger }) => {
17
+ logger.debug("🔌 Registering Script Health Check Strategy...");
18
+ const strategy = new ScriptHealthCheckStrategy();
19
+ healthCheckRegistry.register(strategy);
20
+ },
21
+ });
22
+ },
23
+ });
@@ -0,0 +1,8 @@
1
+ import { definePluginMetadata } from "@checkstack/common";
2
+
3
+ /**
4
+ * Plugin metadata for the Script Health Check backend.
5
+ */
6
+ export const pluginMetadata = definePluginMetadata({
7
+ pluginId: "healthcheck-script",
8
+ });
@@ -0,0 +1,255 @@
1
+ import { describe, expect, it, mock } from "bun:test";
2
+ import { ScriptHealthCheckStrategy, ScriptExecutor } from "./strategy";
3
+
4
+ describe("ScriptHealthCheckStrategy", () => {
5
+ // Helper to create mock Script executor
6
+ const createMockExecutor = (
7
+ config: {
8
+ exitCode?: number;
9
+ stdout?: string;
10
+ stderr?: string;
11
+ timedOut?: boolean;
12
+ error?: Error;
13
+ } = {}
14
+ ): ScriptExecutor => ({
15
+ execute: mock(() =>
16
+ config.error
17
+ ? Promise.reject(config.error)
18
+ : Promise.resolve({
19
+ exitCode: config.exitCode ?? 0,
20
+ stdout: config.stdout ?? "",
21
+ stderr: config.stderr ?? "",
22
+ timedOut: config.timedOut ?? false,
23
+ })
24
+ ),
25
+ });
26
+
27
+ describe("execute", () => {
28
+ it("should return healthy for successful script execution", async () => {
29
+ const strategy = new ScriptHealthCheckStrategy(
30
+ createMockExecutor({ exitCode: 0, stdout: "OK" })
31
+ );
32
+
33
+ const result = await strategy.execute({
34
+ command: "/usr/bin/true",
35
+ timeout: 5000,
36
+ });
37
+
38
+ expect(result.status).toBe("healthy");
39
+ expect(result.metadata?.executed).toBe(true);
40
+ expect(result.metadata?.success).toBe(true);
41
+ expect(result.metadata?.exitCode).toBe(0);
42
+ });
43
+
44
+ it("should return unhealthy for non-zero exit code", async () => {
45
+ const strategy = new ScriptHealthCheckStrategy(
46
+ createMockExecutor({ exitCode: 1, stderr: "Error" })
47
+ );
48
+
49
+ const result = await strategy.execute({
50
+ command: "/usr/bin/false",
51
+ timeout: 5000,
52
+ });
53
+
54
+ expect(result.status).toBe("unhealthy");
55
+ expect(result.metadata?.exitCode).toBe(1);
56
+ expect(result.metadata?.success).toBe(false);
57
+ });
58
+
59
+ it("should return unhealthy for timeout", async () => {
60
+ const strategy = new ScriptHealthCheckStrategy(
61
+ createMockExecutor({ timedOut: true, exitCode: -1 })
62
+ );
63
+
64
+ const result = await strategy.execute({
65
+ command: "sleep",
66
+ args: ["60"],
67
+ timeout: 1000,
68
+ });
69
+
70
+ expect(result.status).toBe("unhealthy");
71
+ expect(result.message).toContain("timed out");
72
+ expect(result.metadata?.timedOut).toBe(true);
73
+ });
74
+
75
+ it("should return unhealthy for execution error", async () => {
76
+ const strategy = new ScriptHealthCheckStrategy(
77
+ createMockExecutor({ error: new Error("Command not found") })
78
+ );
79
+
80
+ const result = await strategy.execute({
81
+ command: "nonexistent-command",
82
+ timeout: 5000,
83
+ });
84
+
85
+ expect(result.status).toBe("unhealthy");
86
+ expect(result.message).toContain("Command not found");
87
+ expect(result.metadata?.executed).toBe(false);
88
+ });
89
+
90
+ it("should pass executionTime assertion when below threshold", async () => {
91
+ const strategy = new ScriptHealthCheckStrategy(createMockExecutor());
92
+
93
+ const result = await strategy.execute({
94
+ command: "/usr/bin/true",
95
+ timeout: 5000,
96
+ assertions: [
97
+ { field: "executionTime", operator: "lessThan", value: 5000 },
98
+ ],
99
+ });
100
+
101
+ expect(result.status).toBe("healthy");
102
+ });
103
+
104
+ it("should pass exitCode assertion", async () => {
105
+ const strategy = new ScriptHealthCheckStrategy(
106
+ createMockExecutor({ exitCode: 0 })
107
+ );
108
+
109
+ const result = await strategy.execute({
110
+ command: "/usr/bin/true",
111
+ timeout: 5000,
112
+ assertions: [{ field: "exitCode", operator: "equals", value: 0 }],
113
+ });
114
+
115
+ expect(result.status).toBe("healthy");
116
+ });
117
+
118
+ it("should fail exitCode assertion when non-zero", async () => {
119
+ const strategy = new ScriptHealthCheckStrategy(
120
+ createMockExecutor({ exitCode: 2 })
121
+ );
122
+
123
+ const result = await strategy.execute({
124
+ command: "/usr/bin/false",
125
+ timeout: 5000,
126
+ assertions: [{ field: "exitCode", operator: "equals", value: 0 }],
127
+ });
128
+
129
+ expect(result.status).toBe("unhealthy");
130
+ expect(result.message).toContain("Assertion failed");
131
+ });
132
+
133
+ it("should pass stdout assertion", async () => {
134
+ const strategy = new ScriptHealthCheckStrategy(
135
+ createMockExecutor({ stdout: "Service is running" })
136
+ );
137
+
138
+ const result = await strategy.execute({
139
+ command: "/usr/bin/echo",
140
+ args: ["Service is running"],
141
+ timeout: 5000,
142
+ assertions: [
143
+ { field: "stdout", operator: "contains", value: "running" },
144
+ ],
145
+ });
146
+
147
+ expect(result.status).toBe("healthy");
148
+ });
149
+
150
+ it("should pass with arguments and env vars", async () => {
151
+ const mockExecutor = createMockExecutor({ exitCode: 0 });
152
+ const strategy = new ScriptHealthCheckStrategy(mockExecutor);
153
+
154
+ await strategy.execute({
155
+ command: "./check.sh",
156
+ args: ["--verbose", "--env=prod"],
157
+ cwd: "/opt/scripts",
158
+ env: { API_KEY: "secret" },
159
+ timeout: 5000,
160
+ });
161
+
162
+ expect(mockExecutor.execute).toHaveBeenCalledWith(
163
+ expect.objectContaining({
164
+ command: "./check.sh",
165
+ args: ["--verbose", "--env=prod"],
166
+ cwd: "/opt/scripts",
167
+ env: { API_KEY: "secret" },
168
+ })
169
+ );
170
+ });
171
+ });
172
+
173
+ describe("aggregateResult", () => {
174
+ it("should calculate averages correctly", () => {
175
+ const strategy = new ScriptHealthCheckStrategy();
176
+ const runs = [
177
+ {
178
+ id: "1",
179
+ status: "healthy" as const,
180
+ latencyMs: 100,
181
+ checkId: "c1",
182
+ timestamp: new Date(),
183
+ metadata: {
184
+ executed: true,
185
+ executionTimeMs: 50,
186
+ exitCode: 0,
187
+ success: true,
188
+ timedOut: false,
189
+ },
190
+ },
191
+ {
192
+ id: "2",
193
+ status: "healthy" as const,
194
+ latencyMs: 150,
195
+ checkId: "c1",
196
+ timestamp: new Date(),
197
+ metadata: {
198
+ executed: true,
199
+ executionTimeMs: 100,
200
+ exitCode: 0,
201
+ success: true,
202
+ timedOut: false,
203
+ },
204
+ },
205
+ ];
206
+
207
+ const aggregated = strategy.aggregateResult(runs);
208
+
209
+ expect(aggregated.avgExecutionTime).toBe(75);
210
+ expect(aggregated.successRate).toBe(100);
211
+ expect(aggregated.errorCount).toBe(0);
212
+ expect(aggregated.timeoutCount).toBe(0);
213
+ });
214
+
215
+ it("should count errors and timeouts", () => {
216
+ const strategy = new ScriptHealthCheckStrategy();
217
+ const runs = [
218
+ {
219
+ id: "1",
220
+ status: "unhealthy" as const,
221
+ latencyMs: 100,
222
+ checkId: "c1",
223
+ timestamp: new Date(),
224
+ metadata: {
225
+ executed: false,
226
+ executionTimeMs: 100,
227
+ success: false,
228
+ timedOut: false,
229
+ error: "Command not found",
230
+ },
231
+ },
232
+ {
233
+ id: "2",
234
+ status: "unhealthy" as const,
235
+ latencyMs: 1000,
236
+ checkId: "c1",
237
+ timestamp: new Date(),
238
+ metadata: {
239
+ executed: true,
240
+ executionTimeMs: 1000,
241
+ exitCode: -1,
242
+ success: false,
243
+ timedOut: true,
244
+ },
245
+ },
246
+ ];
247
+
248
+ const aggregated = strategy.aggregateResult(runs);
249
+
250
+ expect(aggregated.errorCount).toBe(1);
251
+ expect(aggregated.timeoutCount).toBe(1);
252
+ expect(aggregated.successRate).toBe(0);
253
+ });
254
+ });
255
+ });
@@ -0,0 +1,365 @@
1
+ import { spawn, type Subprocess } from "bun";
2
+ import {
3
+ HealthCheckStrategy,
4
+ HealthCheckResult,
5
+ HealthCheckRunForAggregation,
6
+ Versioned,
7
+ z,
8
+ timeThresholdField,
9
+ numericField,
10
+ booleanField,
11
+ stringField,
12
+ evaluateAssertions,
13
+ } from "@checkstack/backend-api";
14
+ import {
15
+ healthResultBoolean,
16
+ healthResultNumber,
17
+ healthResultString,
18
+ } from "@checkstack/healthcheck-common";
19
+
20
+ // ============================================================================
21
+ // SCHEMAS
22
+ // ============================================================================
23
+
24
+ /**
25
+ * Assertion schema for Script health checks using shared factories.
26
+ */
27
+ const scriptAssertionSchema = z.discriminatedUnion("field", [
28
+ timeThresholdField("executionTime"),
29
+ numericField("exitCode", { min: 0 }),
30
+ booleanField("success"),
31
+ stringField("stdout"),
32
+ ]);
33
+
34
+ export type ScriptAssertion = z.infer<typeof scriptAssertionSchema>;
35
+
36
+ /**
37
+ * Configuration schema for Script health checks.
38
+ */
39
+ export const scriptConfigSchema = z.object({
40
+ command: z.string().describe("Command or script path to execute"),
41
+ args: z
42
+ .array(z.string())
43
+ .default([])
44
+ .describe("Arguments to pass to the command"),
45
+ cwd: z.string().optional().describe("Working directory for script execution"),
46
+ env: z
47
+ .record(z.string(), z.string())
48
+ .optional()
49
+ .describe("Environment variables to set"),
50
+ timeout: z
51
+ .number()
52
+ .min(100)
53
+ .default(30_000)
54
+ .describe("Execution timeout in milliseconds"),
55
+ assertions: z
56
+ .array(scriptAssertionSchema)
57
+ .optional()
58
+ .describe("Validation conditions"),
59
+ });
60
+
61
+ export type ScriptConfig = z.infer<typeof scriptConfigSchema>;
62
+ export type ScriptConfigInput = z.input<typeof scriptConfigSchema>;
63
+
64
+ /**
65
+ * Per-run result metadata.
66
+ */
67
+ const scriptResultSchema = z.object({
68
+ executed: healthResultBoolean({
69
+ "x-chart-type": "boolean",
70
+ "x-chart-label": "Executed",
71
+ }),
72
+ executionTimeMs: healthResultNumber({
73
+ "x-chart-type": "line",
74
+ "x-chart-label": "Execution Time",
75
+ "x-chart-unit": "ms",
76
+ }),
77
+ exitCode: healthResultNumber({
78
+ "x-chart-type": "counter",
79
+ "x-chart-label": "Exit Code",
80
+ }).optional(),
81
+ stdout: healthResultString({
82
+ "x-chart-type": "text",
83
+ "x-chart-label": "Stdout",
84
+ }).optional(),
85
+ stderr: healthResultString({
86
+ "x-chart-type": "text",
87
+ "x-chart-label": "Stderr",
88
+ }).optional(),
89
+ success: healthResultBoolean({
90
+ "x-chart-type": "boolean",
91
+ "x-chart-label": "Success",
92
+ }),
93
+ timedOut: healthResultBoolean({
94
+ "x-chart-type": "boolean",
95
+ "x-chart-label": "Timed Out",
96
+ }),
97
+ failedAssertion: scriptAssertionSchema.optional(),
98
+ error: healthResultString({
99
+ "x-chart-type": "status",
100
+ "x-chart-label": "Error",
101
+ }).optional(),
102
+ });
103
+
104
+ export type ScriptResult = z.infer<typeof scriptResultSchema>;
105
+
106
+ /**
107
+ * Aggregated metadata for buckets.
108
+ */
109
+ const scriptAggregatedSchema = z.object({
110
+ avgExecutionTime: healthResultNumber({
111
+ "x-chart-type": "line",
112
+ "x-chart-label": "Avg Execution Time",
113
+ "x-chart-unit": "ms",
114
+ }),
115
+ successRate: healthResultNumber({
116
+ "x-chart-type": "gauge",
117
+ "x-chart-label": "Success Rate",
118
+ "x-chart-unit": "%",
119
+ }),
120
+ errorCount: healthResultNumber({
121
+ "x-chart-type": "counter",
122
+ "x-chart-label": "Errors",
123
+ }),
124
+ timeoutCount: healthResultNumber({
125
+ "x-chart-type": "counter",
126
+ "x-chart-label": "Timeouts",
127
+ }),
128
+ });
129
+
130
+ export type ScriptAggregatedResult = z.infer<typeof scriptAggregatedSchema>;
131
+
132
+ // ============================================================================
133
+ // SCRIPT EXECUTOR INTERFACE (for testability)
134
+ // ============================================================================
135
+
136
+ export interface ScriptExecutionResult {
137
+ exitCode: number;
138
+ stdout: string;
139
+ stderr: string;
140
+ timedOut: boolean;
141
+ }
142
+
143
+ export interface ScriptExecutor {
144
+ execute(config: {
145
+ command: string;
146
+ args: string[];
147
+ cwd?: string;
148
+ env?: Record<string, string>;
149
+ timeout: number;
150
+ }): Promise<ScriptExecutionResult>;
151
+ }
152
+
153
+ // Default executor using Bun.spawn
154
+ const defaultScriptExecutor: ScriptExecutor = {
155
+ async execute(config) {
156
+ let proc: Subprocess | undefined;
157
+ let timedOut = false;
158
+
159
+ const timeoutPromise = new Promise<never>((_, reject) => {
160
+ setTimeout(() => {
161
+ timedOut = true;
162
+ proc?.kill();
163
+ reject(new Error("Script execution timed out"));
164
+ }, config.timeout);
165
+ });
166
+
167
+ const execPromise = (async () => {
168
+ proc = spawn({
169
+ cmd: [config.command, ...config.args],
170
+ cwd: config.cwd,
171
+ env: { ...process.env, ...config.env },
172
+ stdout: "pipe",
173
+ stderr: "pipe",
174
+ });
175
+
176
+ const stdoutStream = proc.stdout;
177
+ const stderrStream = proc.stderr;
178
+ const stdout = stdoutStream
179
+ ? await new Response(stdoutStream as unknown as ReadableStream).text()
180
+ : "";
181
+ const stderr = stderrStream
182
+ ? await new Response(stderrStream as unknown as ReadableStream).text()
183
+ : "";
184
+ const exitCode = await proc.exited;
185
+
186
+ return {
187
+ exitCode,
188
+ stdout: stdout.trim(),
189
+ stderr: stderr.trim(),
190
+ timedOut: false,
191
+ };
192
+ })();
193
+
194
+ try {
195
+ return await Promise.race([execPromise, timeoutPromise]);
196
+ } catch (error) {
197
+ if (timedOut) {
198
+ return {
199
+ exitCode: -1,
200
+ stdout: "",
201
+ stderr: "Script execution timed out",
202
+ timedOut: true,
203
+ };
204
+ }
205
+ throw error;
206
+ }
207
+ },
208
+ };
209
+
210
+ // ============================================================================
211
+ // STRATEGY
212
+ // ============================================================================
213
+
214
+ export class ScriptHealthCheckStrategy
215
+ implements
216
+ HealthCheckStrategy<ScriptConfig, ScriptResult, ScriptAggregatedResult>
217
+ {
218
+ id = "script";
219
+ displayName = "Script Health Check";
220
+ description = "Execute local scripts or commands for health checking";
221
+
222
+ private executor: ScriptExecutor;
223
+
224
+ constructor(executor: ScriptExecutor = defaultScriptExecutor) {
225
+ this.executor = executor;
226
+ }
227
+
228
+ config: Versioned<ScriptConfig> = new Versioned({
229
+ version: 1,
230
+ schema: scriptConfigSchema,
231
+ });
232
+
233
+ result: Versioned<ScriptResult> = new Versioned({
234
+ version: 1,
235
+ schema: scriptResultSchema,
236
+ });
237
+
238
+ aggregatedResult: Versioned<ScriptAggregatedResult> = new Versioned({
239
+ version: 1,
240
+ schema: scriptAggregatedSchema,
241
+ });
242
+
243
+ aggregateResult(
244
+ runs: HealthCheckRunForAggregation<ScriptResult>[]
245
+ ): ScriptAggregatedResult {
246
+ let totalExecutionTime = 0;
247
+ let successCount = 0;
248
+ let errorCount = 0;
249
+ let timeoutCount = 0;
250
+ let validRuns = 0;
251
+
252
+ for (const run of runs) {
253
+ if (run.metadata?.error) {
254
+ errorCount++;
255
+ continue;
256
+ }
257
+ if (run.metadata?.timedOut) {
258
+ timeoutCount++;
259
+ }
260
+ if (run.status === "healthy") {
261
+ successCount++;
262
+ }
263
+ if (run.metadata) {
264
+ totalExecutionTime += run.metadata.executionTimeMs;
265
+ validRuns++;
266
+ }
267
+ }
268
+
269
+ return {
270
+ avgExecutionTime: validRuns > 0 ? totalExecutionTime / validRuns : 0,
271
+ successRate: runs.length > 0 ? (successCount / runs.length) * 100 : 0,
272
+ errorCount,
273
+ timeoutCount,
274
+ };
275
+ }
276
+
277
+ async execute(
278
+ config: ScriptConfigInput
279
+ ): Promise<HealthCheckResult<ScriptResult>> {
280
+ const validatedConfig = this.config.validate(config);
281
+ const start = performance.now();
282
+
283
+ try {
284
+ const execResult = await this.executor.execute({
285
+ command: validatedConfig.command,
286
+ args: validatedConfig.args,
287
+ cwd: validatedConfig.cwd,
288
+ env: validatedConfig.env as Record<string, string> | undefined,
289
+ timeout: validatedConfig.timeout,
290
+ });
291
+
292
+ const executionTimeMs = Math.round(performance.now() - start);
293
+ const success = execResult.exitCode === 0 && !execResult.timedOut;
294
+
295
+ const result: Omit<ScriptResult, "failedAssertion" | "error"> = {
296
+ executed: true,
297
+ executionTimeMs,
298
+ exitCode: execResult.exitCode,
299
+ stdout: execResult.stdout,
300
+ stderr: execResult.stderr,
301
+ success,
302
+ timedOut: execResult.timedOut,
303
+ };
304
+
305
+ // Evaluate assertions using shared utility
306
+ const failedAssertion = evaluateAssertions(validatedConfig.assertions, {
307
+ executionTime: executionTimeMs,
308
+ exitCode: execResult.exitCode,
309
+ success,
310
+ stdout: execResult.stdout,
311
+ });
312
+
313
+ if (failedAssertion) {
314
+ return {
315
+ status: "unhealthy",
316
+ latencyMs: executionTimeMs,
317
+ message: `Assertion failed: ${failedAssertion.field} ${
318
+ failedAssertion.operator
319
+ }${"value" in failedAssertion ? ` ${failedAssertion.value}` : ""}`,
320
+ metadata: { ...result, failedAssertion },
321
+ };
322
+ }
323
+
324
+ if (execResult.timedOut) {
325
+ return {
326
+ status: "unhealthy",
327
+ latencyMs: executionTimeMs,
328
+ message: `Script timed out after ${validatedConfig.timeout}ms`,
329
+ metadata: result,
330
+ };
331
+ }
332
+
333
+ if (!success) {
334
+ return {
335
+ status: "unhealthy",
336
+ latencyMs: executionTimeMs,
337
+ message: `Script failed with exit code ${execResult.exitCode}`,
338
+ metadata: result,
339
+ };
340
+ }
341
+
342
+ return {
343
+ status: "healthy",
344
+ latencyMs: executionTimeMs,
345
+ message: `Script executed successfully (exit 0) in ${executionTimeMs}ms`,
346
+ metadata: result,
347
+ };
348
+ } catch (error: unknown) {
349
+ const end = performance.now();
350
+ const isError = error instanceof Error;
351
+ return {
352
+ status: "unhealthy",
353
+ latencyMs: Math.round(end - start),
354
+ message: isError ? error.message : "Script execution failed",
355
+ metadata: {
356
+ executed: false,
357
+ executionTimeMs: Math.round(end - start),
358
+ success: false,
359
+ timedOut: false,
360
+ error: isError ? error.name : "UnknownError",
361
+ },
362
+ };
363
+ }
364
+ }
365
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "@checkstack/tsconfig/backend.json",
3
+ "include": [
4
+ "src"
5
+ ]
6
+ }