Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
faedb5ba4b |
No files matched your search
Generated
+24
-16
@@ -46,6 +46,7 @@
|
||||
"zod": "^4.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@asteasolutions/zod-to-openapi": "^8.5.0",
|
||||
"@eslint/js": "^9.17.0",
|
||||
"@types/compression": "1.8.1",
|
||||
"@types/cookie-parser": "1.4.10",
|
||||
@@ -126,6 +127,19 @@
|
||||
"integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@asteasolutions/zod-to-openapi": {
|
||||
"version": "8.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@asteasolutions/zod-to-openapi/-/zod-to-openapi-8.5.0.tgz",
|
||||
"integrity": "sha512-SABbKiObg5dLRiTFnqiW1WWwGcg1BJfmHtT2asIBnBHg6Smy/Ms2KHc650+JI4Hw7lSkdiNebEGXpwoxfben8Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"openapi3-ts": "^4.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"zod": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@aws-crypto/sha256-browser": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz",
|
||||
@@ -851,7 +865,6 @@
|
||||
"integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.28.6",
|
||||
"@babel/generator": "^7.28.6",
|
||||
@@ -1471,7 +1484,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
@@ -1516,7 +1528,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -4230,7 +4241,6 @@
|
||||
"integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/body-parser": "*",
|
||||
"@types/express-serve-static-core": "^5.0.0",
|
||||
@@ -4391,7 +4401,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz",
|
||||
"integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
@@ -4629,7 +4638,6 @@
|
||||
"integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.56.1",
|
||||
"@typescript-eslint/types": "8.56.1",
|
||||
@@ -5243,7 +5251,6 @@
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -5822,7 +5829,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.19",
|
||||
"caniuse-lite": "^1.0.30001751",
|
||||
@@ -6716,7 +6722,6 @@
|
||||
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.1.tgz",
|
||||
"integrity": "sha512-fm4D8ti0dQmFPeF8DXSAA//btEmqCOgAc/9Oa3C1LW94h5usNrJEfrON7b4FkPZgnDEn6OUs5NdxiJZmAtGOpQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cssnano-preset-default": "^7.0.9",
|
||||
"lilconfig": "^3.1.3"
|
||||
@@ -7481,7 +7486,6 @@
|
||||
"integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
@@ -7843,7 +7847,6 @@
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
|
||||
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
@@ -9512,7 +9515,6 @@
|
||||
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jest/core": "30.2.0",
|
||||
"@jest/types": "30.2.0",
|
||||
@@ -11956,6 +11958,16 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/openapi3-ts": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-4.5.0.tgz",
|
||||
"integrity": "sha512-jaL+HgTq2Gj5jRcfdutgRGLosCy/hT8sQf6VOy+P+g36cZOjI1iukdPnijC+4CmeRzg/jEllJUboEic2FhxhtQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"yaml": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/optionator": {
|
||||
"version": "0.9.4",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||
@@ -12347,7 +12359,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
@@ -14370,7 +14381,6 @@
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -14539,7 +14549,6 @@
|
||||
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@cspotcode/source-map-support": "^0.8.0",
|
||||
"@tsconfig/node10": "^1.0.7",
|
||||
@@ -14703,7 +14712,6 @@
|
||||
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"zod": "^4.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@asteasolutions/zod-to-openapi": "^8.5.0",
|
||||
"@eslint/js": "^9.17.0",
|
||||
"@types/compression": "1.8.1",
|
||||
"@types/cookie-parser": "1.4.10",
|
||||
|
||||
+2
-2
@@ -3,9 +3,9 @@ import { initializeControllers } from "./config/controllers.js";
|
||||
import { createApp } from "./app.js";
|
||||
import { initShutdownListener } from "@/shutdown.js";
|
||||
import { validateEnv } from "@/validation/envValidation.js";
|
||||
import { getOpenApiSpec } from "@/openapi/index.js";
|
||||
import { fileURLToPath } from "url";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
|
||||
import Logger, { ILogger } from "@/utils/logger.js";
|
||||
import { SettingsService } from "@/service/index.js";
|
||||
@@ -20,7 +20,7 @@ const startApp = async () => {
|
||||
// FE path
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const openApiSpec = JSON.parse(fs.readFileSync(path.join(__dirname, "../openapi.json"), "utf8"));
|
||||
const openApiSpec = getOpenApiSpec();
|
||||
const frontendPath = path.join(__dirname, "..", "public");
|
||||
|
||||
// Create settings service (env only — DB repository injected after connect)
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import "./registry.js";
|
||||
import "./routes/monitor.js";
|
||||
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { OpenApiGeneratorV3 } from "@asteasolutions/zod-to-openapi";
|
||||
import type { JsonObject } from "swagger-ui-express";
|
||||
import { registry } from "./registry.js";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
let cached: JsonObject | null = null;
|
||||
|
||||
export function getOpenApiSpec(): JsonObject {
|
||||
if (cached) return cached;
|
||||
|
||||
const staticSpec = JSON.parse(fs.readFileSync(path.join(__dirname, "../../openapi.json"), "utf8")) as Record<string, unknown>;
|
||||
|
||||
const generator = new OpenApiGeneratorV3(registry.definitions);
|
||||
const generated = generator.generateDocument({
|
||||
openapi: "3.0.0",
|
||||
info: { title: "generated", version: "0.0.0" },
|
||||
});
|
||||
|
||||
const generatedPaths = (generated.paths ?? {}) as Record<string, unknown>;
|
||||
const generatedSchemas = (generated.components?.schemas ?? {}) as Record<string, unknown>;
|
||||
const generatedSecuritySchemes = (generated.components?.securitySchemes ?? {}) as Record<string, unknown>;
|
||||
|
||||
const staticPaths = (staticSpec.paths ?? {}) as Record<string, unknown>;
|
||||
const staticComponents = (staticSpec.components ?? {}) as Record<string, unknown>;
|
||||
const staticSchemas = (staticComponents.schemas ?? {}) as Record<string, unknown>;
|
||||
const staticSecuritySchemes = (staticComponents.securitySchemes ?? {}) as Record<string, unknown>;
|
||||
|
||||
// Drop static paths that the registry now owns, plus stale entries
|
||||
// for routes that no longer exist in the codebase.
|
||||
const owned = new Set(Object.keys(generatedPaths));
|
||||
const stale = new Set(["/monitors/bulk", "/monitors/test-email"]);
|
||||
const filteredStaticPaths = Object.fromEntries(Object.entries(staticPaths).filter(([key]) => !owned.has(key) && !stale.has(key)));
|
||||
|
||||
cached = {
|
||||
...staticSpec,
|
||||
paths: { ...filteredStaticPaths, ...generatedPaths },
|
||||
components: {
|
||||
...staticComponents,
|
||||
schemas: { ...staticSchemas, ...generatedSchemas },
|
||||
securitySchemes: { ...staticSecuritySchemes, ...generatedSecuritySchemes },
|
||||
},
|
||||
};
|
||||
|
||||
return cached;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { OpenAPIRegistry, OpenApiGeneratorV3, extendZodWithOpenApi } from "@asteasolutions/zod-to-openapi";
|
||||
import { z } from "zod";
|
||||
|
||||
extendZodWithOpenApi(z);
|
||||
|
||||
export const registry = new OpenAPIRegistry();
|
||||
|
||||
registry.registerComponent("securitySchemes", "bearerAuth", {
|
||||
type: "http",
|
||||
scheme: "bearer",
|
||||
bearerFormat: "JWT",
|
||||
});
|
||||
|
||||
export function generateMonitorPaths() {
|
||||
const generator = new OpenApiGeneratorV3(registry.definitions);
|
||||
return generator.generateDocument({
|
||||
openapi: "3.0.0",
|
||||
info: { title: "Checkmate generated paths", version: "0.0.0" },
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
import "../registry.js";
|
||||
import { z } from "zod";
|
||||
import { registry } from "../registry.js";
|
||||
import { successEnvelope, successEnvelopeNoData, errorEnvelope } from "../schemas/common.js";
|
||||
import {
|
||||
MonitorSchema,
|
||||
MonitorWithChecksListSchema,
|
||||
CertificateInfoSchema,
|
||||
NotificationsUpdateResultSchema,
|
||||
ImportResultSchema,
|
||||
} from "../schemas/monitor.js";
|
||||
import {
|
||||
getMonitorByIdParamValidation,
|
||||
getMonitorByIdQueryValidation,
|
||||
getMonitorsByTeamIdQueryValidation,
|
||||
getMonitorsWithChecksQueryValidation,
|
||||
getCertificateParamValidation,
|
||||
createMonitorBodyValidation,
|
||||
editMonitorBodyValidation,
|
||||
pauseMonitorParamValidation,
|
||||
getUptimeDetailsByIdParamValidation,
|
||||
getUptimeDetailsByIdQueryValidation,
|
||||
importMonitorsBodyValidation,
|
||||
getHardwareDetailsByIdParamValidation,
|
||||
getHardwareDetailsByIdQueryValidation,
|
||||
} from "@/validation/monitorValidation.js";
|
||||
import { updateNotificationsValidation } from "@/validation/notificationValidation.js";
|
||||
|
||||
const bearer = [{ bearerAuth: [] }];
|
||||
const tags = ["monitors"];
|
||||
|
||||
const json = <T extends z.ZodTypeAny>(schema: T) => ({
|
||||
"application/json": { schema },
|
||||
});
|
||||
|
||||
const standardErrors = {
|
||||
"401": { description: "Unauthorized", content: json(errorEnvelope) },
|
||||
"403": { description: "Forbidden", content: json(errorEnvelope) },
|
||||
"500": { description: "Internal server error", content: json(errorEnvelope) },
|
||||
};
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/monitors/team",
|
||||
tags,
|
||||
summary: "List monitors for the caller's team",
|
||||
security: bearer,
|
||||
request: { query: getMonitorsByTeamIdQueryValidation },
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(z.array(MonitorSchema))) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/monitors/team/with-checks",
|
||||
tags,
|
||||
summary: "List team monitors with their most recent checks (paginated)",
|
||||
security: bearer,
|
||||
request: { query: getMonitorsWithChecksQueryValidation },
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(MonitorWithChecksListSchema)) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/monitors/team/groups",
|
||||
tags,
|
||||
summary: "List monitor groups for the caller's team",
|
||||
security: bearer,
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(z.array(z.string()))) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/monitors/uptime/details/{monitorId}",
|
||||
tags,
|
||||
summary: "Get uptime details for a monitor",
|
||||
security: bearer,
|
||||
request: {
|
||||
params: getUptimeDetailsByIdParamValidation,
|
||||
query: getUptimeDetailsByIdQueryValidation,
|
||||
},
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(z.unknown())) },
|
||||
"400": { description: "Validation error", content: json(errorEnvelope) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/monitors/hardware/details/{monitorId}",
|
||||
tags,
|
||||
summary: "Get hardware metrics detail for a monitor",
|
||||
security: bearer,
|
||||
request: {
|
||||
params: getHardwareDetailsByIdParamValidation,
|
||||
query: getHardwareDetailsByIdQueryValidation,
|
||||
},
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(z.unknown())) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/monitors/pagespeed/details/{monitorId}",
|
||||
tags,
|
||||
summary: "Get PageSpeed detail for a monitor",
|
||||
security: bearer,
|
||||
request: {
|
||||
params: getHardwareDetailsByIdParamValidation,
|
||||
query: getHardwareDetailsByIdQueryValidation,
|
||||
},
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelopeNoData) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/monitors/{monitorId}/geo-checks",
|
||||
tags,
|
||||
summary: "Get geo check results for a monitor",
|
||||
security: bearer,
|
||||
request: {
|
||||
params: getMonitorByIdParamValidation,
|
||||
query: getMonitorByIdQueryValidation,
|
||||
},
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelopeNoData) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "post",
|
||||
path: "/monitors/pause/{monitorId}",
|
||||
tags,
|
||||
summary: "Toggle pause state for a monitor",
|
||||
security: bearer,
|
||||
request: { params: pauseMonitorParamValidation },
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(MonitorSchema)) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/monitors/certificate/{monitorId}",
|
||||
tags,
|
||||
summary: "Get SSL certificate info for a monitor",
|
||||
security: bearer,
|
||||
request: { params: getCertificateParamValidation },
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(CertificateInfoSchema)) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "patch",
|
||||
path: "/monitors/notifications",
|
||||
tags,
|
||||
summary: "Bulk update notifications across monitors",
|
||||
security: bearer,
|
||||
request: { body: { content: json(updateNotificationsValidation) } },
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(NotificationsUpdateResultSchema)) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "post",
|
||||
path: "/monitors",
|
||||
tags,
|
||||
summary: "Create a new monitor",
|
||||
security: bearer,
|
||||
request: { body: { content: json(createMonitorBodyValidation) } },
|
||||
responses: {
|
||||
"200": { description: "Monitor created", content: json(successEnvelope(MonitorSchema)) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "delete",
|
||||
path: "/monitors",
|
||||
tags,
|
||||
summary: "Delete every monitor (superadmin only)",
|
||||
security: bearer,
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelopeNoData) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "post",
|
||||
path: "/monitors/demo",
|
||||
tags,
|
||||
summary: "Insert preconfigured demo monitors",
|
||||
security: bearer,
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(z.number())) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/monitors/export/json",
|
||||
tags,
|
||||
summary: "Export all team monitors as JSON",
|
||||
security: bearer,
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(z.unknown())) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "post",
|
||||
path: "/monitors/import/json",
|
||||
tags,
|
||||
summary: "Import monitors from JSON",
|
||||
security: bearer,
|
||||
request: { body: { content: json(importMonitorsBodyValidation) } },
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(ImportResultSchema)) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/monitors/games",
|
||||
tags,
|
||||
summary: "List supported game-server types",
|
||||
security: bearer,
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(z.array(z.string()))) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/monitors/{monitorId}",
|
||||
tags,
|
||||
summary: "Get a monitor by id",
|
||||
security: bearer,
|
||||
request: { params: getMonitorByIdParamValidation },
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(MonitorSchema)) },
|
||||
"404": { description: "Monitor not found", content: json(errorEnvelope) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "patch",
|
||||
path: "/monitors/{monitorId}",
|
||||
tags,
|
||||
summary: "Edit a monitor",
|
||||
security: bearer,
|
||||
request: {
|
||||
params: getMonitorByIdParamValidation,
|
||||
body: { content: json(editMonitorBodyValidation) },
|
||||
},
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(MonitorSchema)) },
|
||||
"404": { description: "Monitor not found", content: json(errorEnvelope) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "delete",
|
||||
path: "/monitors/{monitorId}",
|
||||
tags,
|
||||
summary: "Delete a monitor",
|
||||
security: bearer,
|
||||
request: { params: getMonitorByIdParamValidation },
|
||||
responses: {
|
||||
"200": { description: "OK", content: json(successEnvelope(MonitorSchema)) },
|
||||
"404": { description: "Monitor not found", content: json(errorEnvelope) },
|
||||
...standardErrors,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const successEnvelope = <T extends z.ZodTypeAny>(data: T) =>
|
||||
z.object({
|
||||
success: z.literal(true),
|
||||
msg: z.string(),
|
||||
data,
|
||||
});
|
||||
|
||||
export const successEnvelopeNoData = z.object({
|
||||
success: z.literal(true),
|
||||
msg: z.string(),
|
||||
});
|
||||
|
||||
export const errorEnvelope = z.object({
|
||||
success: z.literal(false),
|
||||
msg: z.string(),
|
||||
data: z.unknown().optional(),
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
import "../registry.js";
|
||||
import { z } from "zod";
|
||||
import { GeoContinents } from "@/types/geoCheck.js";
|
||||
import { MonitorMatchMethods, MonitorTypes } from "@/types/monitor.js";
|
||||
|
||||
export const MonitorSchema = z
|
||||
.object({
|
||||
_id: z.string().openapi({ example: "65f1c2a4d8b9e0123456789a" }),
|
||||
name: z.string(),
|
||||
description: z.string().optional(),
|
||||
type: z.enum(MonitorTypes),
|
||||
url: z.string(),
|
||||
port: z.number().optional(),
|
||||
isActive: z.boolean(),
|
||||
interval: z.number(),
|
||||
status: z.enum(["up", "down", "paused", "initializing", "maintenance", "breached"]),
|
||||
statusWindowSize: z.number(),
|
||||
statusWindowThreshold: z.number(),
|
||||
ignoreTlsErrors: z.boolean(),
|
||||
useAdvancedMatching: z.boolean(),
|
||||
jsonPath: z.string().optional(),
|
||||
expectedValue: z.string().optional(),
|
||||
matchMethod: z.enum(MonitorMatchMethods).optional(),
|
||||
notifications: z.array(z.string()),
|
||||
secret: z.string().optional(),
|
||||
cpuAlertThreshold: z.number(),
|
||||
memoryAlertThreshold: z.number(),
|
||||
diskAlertThreshold: z.number(),
|
||||
tempAlertThreshold: z.number(),
|
||||
selectedDisks: z.array(z.string()),
|
||||
gameId: z.string().optional(),
|
||||
grpcServiceName: z.string().optional(),
|
||||
group: z.string().nullable().optional(),
|
||||
geoCheckEnabled: z.boolean(),
|
||||
geoCheckLocations: z.array(z.enum(GeoContinents)),
|
||||
geoCheckInterval: z.number(),
|
||||
teamId: z.string(),
|
||||
userId: z.string(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
})
|
||||
.passthrough()
|
||||
.openapi("Monitor");
|
||||
|
||||
export const MonitorWithChecksListSchema = z
|
||||
.object({
|
||||
monitors: z.array(MonitorSchema),
|
||||
monitorCount: z.number(),
|
||||
filteredCount: z.number(),
|
||||
})
|
||||
.passthrough()
|
||||
.openapi("MonitorWithChecksList");
|
||||
|
||||
export const CertificateInfoSchema = z
|
||||
.object({
|
||||
certificateDate: z.string(),
|
||||
})
|
||||
.openapi("CertificateInfo");
|
||||
|
||||
export const NotificationsUpdateResultSchema = z
|
||||
.object({
|
||||
modifiedCount: z.number(),
|
||||
})
|
||||
.openapi("NotificationsUpdateResult");
|
||||
|
||||
export const ImportResultSchema = z
|
||||
.object({
|
||||
imported: z.number(),
|
||||
})
|
||||
.passthrough()
|
||||
.openapi("ImportResult");
|
||||
Reference in new issue
Block a user