refactor service

This commit is contained in:
Alex Holliday committed 2026-01-02 22:16:00 +00:00
1 parent 82cb59ae9e
commit 56aa7b3e1a
21 files changed
+301 -162

No files matched your search

+1 -1
View File
@@ -70,7 +70,7 @@ const DockerMonitorsPage = () => {
const monitorLimitReached = useLimitReached("monitorsMax", count);
const handleConfirm = async () => {
await deleteFn(`/monitors/${selectedMonitor?._id}`);
await deleteFn(`/monitors/${selectedMonitor?.id}`);
setSelectedMonitor(null);
refetch();
};
@@ -58,17 +58,17 @@ export const DockerMonitorsTable = ({
{
id: 2,
label: t("monitors.common.actions.details"),
action: () => navigate(`/docker/${monitor._id}`),
action: () => navigate(`/docker/${monitor.id}`),
},
{
id: 3,
label: t("monitors.common.actions.incidents"),
action: () => navigate(`/incidents?monitorId=${monitor._id}`),
action: () => navigate(`/incidents?monitorId=${monitor.id}`),
},
{
id: 4,
label: t("monitors.common.actions.configure"),
action: () => navigate(`/docker/${monitor._id}/configure`),
action: () => navigate(`/docker/${monitor.id}/configure`),
},
{
id: 6,
@@ -77,7 +77,7 @@ export const DockerMonitorsTable = ({
? t("common.buttons.resume")
: t("common.buttons.pause"),
action: async () => {
await patch(`/monitors/${monitor._id}/active`);
await patch(`/monitors/${monitor.id}/active`);
refetch();
},
closeMenu: true,
@@ -124,7 +124,7 @@ export const DockerMonitorsTable = ({
),
render: (row) => {
const containerCount = (
checksMap[row._id]?.[0]?.dockerContainers || []
checksMap[row.id]?.[0]?.dockerContainers || []
).filter((c: any) => c?.running).length;
return containerCount;
},
@@ -145,7 +145,7 @@ export const DockerMonitorsTable = ({
<Table
headers={headers}
data={monitors}
onRowClick={(row) => navigate(`/docker/${row._id}`)}
onRowClick={(row) => navigate(`/docker/${row.id}`)}
/>
<Pagination
component="div"
@@ -70,7 +70,7 @@ const InfraMonitorsPage = () => {
const monitorLimitReached = useLimitReached("monitorsMax", count);
const handleConfirm = async () => {
await deleteFn(`/monitors/${selectedMonitor?._id}`);
await deleteFn(`/monitors/${selectedMonitor?.id}`);
setSelectedMonitor(null);
refetch();
};
@@ -97,21 +97,21 @@ export const InfraMonitorsTable = ({
id: 2,
label: t("monitors.common.actions.details"),
action: () => {
navigate(`${monitor._id}`);
navigate(`${monitor.id}`);
},
},
{
id: 3,
label: t("monitors.common.actions.incidents"),
action: () => {
navigate(`/incidents?monitorId=${monitor._id}`);
navigate(`/incidents?monitorId=${monitor.id}`);
},
},
{
id: 4,
label: t("monitors.common.actions.configure"),
action: () => {
navigate(`/infrastructure/${monitor._id}/configure`);
navigate(`/infrastructure/${monitor.id}/configure`);
},
},
// {
@@ -128,7 +128,7 @@ export const InfraMonitorsTable = ({
? t("common.buttons.resume")
: t("common.buttons.pause"),
action: async () => {
await patch(`/monitors/${monitor._id}/active`);
await patch(`/monitors/${monitor.id}/active`);
refetch();
},
closeMenu: true,
@@ -208,7 +208,7 @@ export const InfraMonitorsTable = ({
content: t("monitors.infrastructure.table.headers.cpu"),
render: (row) => {
const cpuUsage =
(checksMap[row._id]?.[0]?.system?.cpu?.usage_percent || 0) * 100;
(checksMap[row.id]?.[0]?.system?.cpu?.usage_percent || 0) * 100;
return <Gauge progress={cpuUsage} />;
},
},
@@ -217,7 +217,7 @@ export const InfraMonitorsTable = ({
content: t("monitors.infrastructure.table.headers.memory"),
render: (row) => {
const memoryUsage =
(checksMap[row._id]?.[0]?.system?.memory?.usage_percent || 0) * 100;
(checksMap[row.id]?.[0]?.system?.memory?.usage_percent || 0) * 100;
return <Gauge progress={memoryUsage} />;
},
},
@@ -225,11 +225,11 @@ export const InfraMonitorsTable = ({
id: "disk",
content: t("monitors.infrastructure.table.headers.disk"),
render: (row) => {
const totalDiskUsage = checksMap[row._id]?.[0]?.system?.disk?.reduce(
const totalDiskUsage = checksMap[row.id]?.[0]?.system?.disk?.reduce(
(acc, disk) => acc + disk.usage_percent,
0
);
const diskCount = checksMap[row._id]?.[0]?.system?.disk?.length || 1;
const diskCount = checksMap[row.id]?.[0]?.system?.disk?.length || 1;
const diskUsage = ((totalDiskUsage || 0) / diskCount) * 100;
return <Gauge progress={diskUsage} />;
},
@@ -257,7 +257,7 @@ export const InfraMonitorsTable = ({
headers={headers}
data={monitors}
onRowClick={(row) => {
navigate(`/infrastructure/${row._id}`);
navigate(`/infrastructure/${row.id}`);
}}
/>
<Pagination
@@ -98,21 +98,21 @@ export const PageSpeedMonitorTable = ({
id: 2,
label: t("monitors.common.actions.details"),
action: () => {
navigate(`${monitor._id}`);
navigate(`${monitor.id}`);
},
},
{
id: 3,
label: t("monitors.common.actions.incidents"),
action: () => {
navigate(`/incidents?monitorId=${monitor._id}`);
navigate(`/incidents?monitorId=${monitor.id}`);
},
},
{
id: 4,
label: t("monitors.common.actions.configure"),
action: () => {
navigate(`/pagespeed/${monitor._id}/configure`);
navigate(`/pagespeed/${monitor.id}/configure`);
},
},
// {
@@ -129,7 +129,7 @@ export const PageSpeedMonitorTable = ({
? t("common.buttons.resume")
: t("common.buttons.pause"),
action: async () => {
await patch(`/monitors/${monitor._id}/active`);
await patch(`/monitors/${monitor.id}/active`);
refetch();
},
closeMenu: true,
@@ -207,7 +207,7 @@ export const PageSpeedMonitorTable = ({
return (
<Stack alignItems={"center"}>
<HistogramPageSpeed
checks={checksMap[row._id] ?? []}
checks={checksMap[row.id] ?? []}
status={row.status}
/>
</Stack>
@@ -237,7 +237,7 @@ export const PageSpeedMonitorTable = ({
headers={headers}
data={monitors}
onRowClick={(row) => {
navigate(`/pagespeed/${row._id}`);
navigate(`/pagespeed/${row.id}`);
}}
/>
<Pagination
@@ -71,7 +71,7 @@ const PageSpeedMonitorsPage = () => {
const monitorLimitReached = useLimitReached("monitorsMax", count);
const handleConfirm = async () => {
await deleteFn(`/monitors/${selectedMonitor?._id}`);
await deleteFn(`/monitors/${selectedMonitor?.id}`);
setSelectedMonitor(null);
refetch();
};
+1 -1
View File
@@ -155,7 +155,7 @@ const UptimeDetailsPage = () => {
<ChartAvgResponse avg={avgResponseTime} max={maxResponseTime} />
</Stack>
<ChartResponseTime checks={checksAll} range={range} />
<CheckTable monitorId={monitor?._id} />
<CheckTable monitorId={monitor?.id} />
</BasePage>
);
};
+1 -1
View File
@@ -97,7 +97,7 @@ const UptimeMonitors = () => {
const monitorLimitReached = useLimitReached("monitorsMax", count);
const handleConfirm = async () => {
await deleteFn(`/monitors/${selectedMonitor?._id}`);
await deleteFn(`/monitors/${selectedMonitor?.id}`);
setSelectedMonitor(null);
refetch();
};
@@ -102,21 +102,21 @@ export const MonitorTable = ({
id: 2,
label: t("monitors.common.actions.details"),
action: () => {
navigate(`${monitor._id}`);
navigate(`${monitor.id}`);
},
},
{
id: 3,
label: t("monitors.common.actions.incidents"),
action: () => {
navigate(`/incidents?monitorId=${monitor._id}`);
navigate(`/incidents?monitorId=${monitor.id}`);
},
},
{
id: 4,
label: t("monitors.common.actions.configure"),
action: () => {
navigate(`/uptime/${monitor._id}/configure`);
navigate(`/uptime/${monitor.id}/configure`);
},
},
// {
@@ -133,7 +133,7 @@ export const MonitorTable = ({
? t("common.buttons.resume")
: t("common.buttons.pause"),
action: async () => {
await patch(`/monitors/${monitor._id}/active`);
await patch(`/monitors/${monitor.id}/active`);
refetch();
},
closeMenu: true,
@@ -209,9 +209,9 @@ export const MonitorTable = ({
content: t("monitors.uptime.table.headers.responseTime"),
render: (row) => {
if (chartType === "histogram") {
return <HistogramResponseTime checks={checksMap[row._id] ?? []} />;
return <HistogramResponseTime checks={checksMap[row.id] ?? []} />;
} else {
return <HeatmapResponseTime checks={checksMap[row._id] ?? []} />;
return <HeatmapResponseTime checks={checksMap[row.id] ?? []} />;
}
},
},
@@ -253,7 +253,7 @@ export const MonitorTable = ({
headers={headers}
data={monitors}
onRowClick={(row) => {
navigate(`/uptime/${row._id}`);
navigate(`/uptime/${row.id}`);
}}
/>
<Pagination
+2 -1
View File
@@ -19,11 +19,13 @@ export const MonitorStatuses = [
"down",
"paused",
"initializing",
"resuming",
] as const;
export type MonitorStatus = (typeof MonitorStatuses)[number];
export interface IMonitor {
id: string;
checks: ICheck[];
createdAt: string;
createdBy: string;
@@ -47,7 +49,6 @@ export interface IMonitor {
temperature: number;
};
__v: number;
_id: string;
}
export interface IMonitorWithStats {
+2
View File
@@ -21,6 +21,7 @@ export const getStatusPalette = (status: MonitorStatus): PaletteKey => {
down: "error",
paused: "warning",
initializing: "warning",
resuming: "warning",
};
return paletteMap[status];
};
@@ -40,6 +41,7 @@ export const getStatusColor = (status: MonitorStatus, theme: any): string => {
down: theme.palette.error.light,
paused: theme.palette.warning.light,
initializing: theme.palette.warning.light,
resuming: theme.palette.warning.light,
};
return statusColors[status];
};
+3 -1
View File
@@ -33,6 +33,7 @@ import {
} from "@/services/index.js";
import { EntitlementsFactory } from "@/services/system/EntitlementsService.js";
import { MeService } from "@/services/index.js";
import { MongoMonitorRepository } from "@/repositories/index.js";
export const initServices = async () => {
const checkService = new CheckService();
@@ -71,7 +72,8 @@ export const initServices = async () => {
const entitlementsProvider = EntitlementsFactory.create();
const authService = new AuthService(jobQueue, entitlementsProvider);
const meService = new MeService(entitlementsProvider);
const monitorService = new MonitorService(jobQueue);
const monitorRepository = new MongoMonitorRepository();
const monitorService = new MonitorService(jobQueue, monitorRepository);
const queueService = new QueueService(jobQueue);
const teamService = new TeamService(jobQueue);
const roleService = new RoleService();
Whitespace-only changes.
@@ -1,58 +0,0 @@
import { Check } from "@/db/models/index.js";
import type { ICheck } from "@/db/models/index.js";
import type { IChecksRepository } from "@/repositories/checks/IChecksRepository.js";
import { CheckEntity } from "@/types/domain/check.js";
import mongoose from "mongoose";
export class MongoChecksRepository implements IChecksRepository {
private toEntity = (check: ICheck): CheckEntity => {
return {
id: check._id.toString(),
metadata: {
monitorId: check.metadata.monitorId.toString(),
teamId: check.metadata.teamId.toString(),
type: check.metadata.type,
},
status: check.status,
httpStatusCode: check.httpStatusCode,
message: check.message,
timings: check.timings,
errorMessage: check.errorMessage,
ackAt: check.ackAt,
ackBy: check.ackBy?.toString(),
system: check.system,
capture: check.capture,
lighthouse: check.lighthouse,
dockerContainers: check.dockerContainers,
createdAt: check.createdAt,
updatedAt: check.updatedAt,
expiry: check.expiry,
};
};
findLatestByMonitorIds = async (monitorIds: string[]) => {
const checks = await Check.aggregate([
{
$match: {
"metadata.monitorId": {
$in: monitorIds.map((id) => new mongoose.Types.ObjectId(id)),
},
},
},
{ $sort: { createdAt: -1 } },
{
$group: {
_id: "$metadata.monitorId",
latestChecks: { $push: "$$ROOT" },
},
},
{
$project: {
latestChecks: { $slice: [{ $ifNull: ["$latestChecks", []] }, 25] },
},
},
]);
console.log(checks);
return checks;
};
}
+5
View File
@@ -0,0 +1,5 @@
export type {
IMonitorRepository,
TeamQueryConfig,
} from "@/repositories/monitors/IMonitorRepoistory.js";
export { default as MongoMonitorRepository } from "@/repositories/monitors/MongoMonitorRepository.js";
@@ -0,0 +1,41 @@
import type {
Monitor,
MonitorType,
MonitorStatus,
} from "@/types/domain/monitor.js";
export interface TeamQueryConfig {
search: string;
sortField: string;
sortOrder: string;
page: number;
rowsPerPage: number;
type: MonitorType[];
status: MonitorStatus[];
}
export interface IMonitorRepository {
// Single fetch
findById(monitorId: string, teamId: string): Promise<Monitor | null>;
// Collection fetches
findByTeamId(teamId: string): Promise<Monitor[]>;
findByTeamIdWithConfig(
teamId: string,
config: TeamQueryConfig
): Promise<Monitor[]>;
findMonitorCountsByTeamId(teamId: string): Promise<{
total: number;
upCount: number;
downCount: number;
pausedCount: number;
}>;
findByOrgId(orgId: string): Promise<Monitor[]>;
// Deletions
deleteById(id: string): Promise<boolean>;
deleteByOrgId(orgId: string): Promise<number>;
}
export default IMonitorRepository;
@@ -0,0 +1,126 @@
import { Monitor, IMonitor } from "@/db/models/index.js";
import { IMonitorRepository, TeamQueryConfig } from "@/repositories/index.js";
import type { Monitor as MonitorEntity } from "@/types/domain/monitor.js";
import mongoose from "mongoose";
class MongoMonitorRepository implements IMonitorRepository {
private toEntity = (monitor: IMonitor): MonitorEntity => {
return {
id: monitor._id.toString(),
orgId: monitor.orgId.toString(),
teamId: monitor.teamId.toString(),
name: monitor.name,
url: monitor.url,
port: monitor.port,
secret: monitor.secret,
type: monitor.type,
interval: monitor.interval,
rejectUnauthorized: monitor.rejectUnauthorized,
status: monitor.status,
n: monitor.n,
thresholds: monitor.thresholds,
lastCheckedAt: monitor.lastCheckedAt,
latestStatuses: monitor.latestStatuses,
notificationChannels: monitor.notificationChannels?.map((id) =>
id.toString()
),
createdBy: monitor.createdBy.toString(),
updatedBy: monitor.updatedBy.toString(),
createdAt: monitor.createdAt,
updatedAt: monitor.updatedAt,
};
};
// Single fetch
findById = async (monitorId: string, teamId: string) => {
const monitor = await Monitor.findOne({ _id: monitorId, teamId });
if (!monitor) return null;
return this.toEntity(monitor);
};
// Collection fetches
findByTeamId = async (teamId: string) => {
const monitors = await Monitor.find({ teamId });
return monitors.map(this.toEntity);
};
findByTeamIdWithConfig = async (teamId: string, config: TeamQueryConfig) => {
if (!config) {
const monitors = await Monitor.find({ teamId });
return monitors.map(this.toEntity);
}
const { search, sortField, sortOrder, page, rowsPerPage, type, status } =
config;
const match: Record<string, unknown> = {
teamId: new mongoose.Types.ObjectId(teamId),
};
if (search && search.trim() !== "") {
const term = search.trim();
(match as any).$or = [
{ name: { $regex: term, $options: "i" } },
{ url: { $regex: term, $options: "i" } },
];
}
if (Array.isArray(type) && type.length > 0) {
match.type = { $in: type };
}
if (Array.isArray(status) && status.length > 0) {
match.status = { $in: status };
}
const skip = page * rowsPerPage;
const monitors = await Monitor.find(match)
.sort({ [sortField]: sortOrder === "asc" ? 1 : -1 })
.skip(skip)
.limit(rowsPerPage);
return monitors.map(this.toEntity);
};
findByOrgId = async (orgId: string) => {
return [];
};
findMonitorCountsByTeamId = async (teamId: string) => {
const countResult = await Monitor.aggregate([
{
$match: { teamId: new mongoose.Types.ObjectId(teamId) },
},
{
$group: {
_id: null,
total: { $sum: 1 },
upCount: { $sum: { $cond: [{ $eq: ["$status", "up"] }, 1, 0] } },
downCount: { $sum: { $cond: [{ $eq: ["$status", "down"] }, 1, 0] } },
pausedCount: {
$sum: {
$cond: [{ $in: ["$status", ["paused", "resuming"]] }, 1, 0],
},
},
},
},
]);
const counts = countResult[0] || {
total: 0,
upCount: 0,
downCount: 0,
pausedCount: 0,
};
return counts;
};
// Deletions
deleteById = async (id: string) => {
return false;
};
deleteByOrgId = async (orgId: string) => {
return 0;
};
}
export default MongoMonitorRepository;
+36 -66
View File
@@ -8,6 +8,8 @@ import { MonitorWithChecksResponse } from "@/types/index.js";
import { MonitorStatus, MonitorType } from "@/db/models/monitors/Monitor.js";
import { Entitlements } from "@/types/entitlements.js";
import { getStartDate } from "@/utils/TimeUtils.js";
import { IMonitorRepository } from "@/repositories/index.js";
import type { Monitor as MonitorEntity } from "@/types/domain/index.js";
export interface IImportedMonitor {
name: string;
@@ -44,7 +46,7 @@ export interface IMonitorService {
currentTeamId: string,
monitorData: IMonitor
) => Promise<IMonitor>;
getAll: (teamId: string) => Promise<IMonitor[]>;
getAll: (teamId: string) => Promise<MonitorEntity[]>;
getAllEmbedChecks: (
teamId: string,
search: string,
@@ -61,7 +63,7 @@ export interface IMonitorService {
pausedCount: number;
monitors: any[];
}>;
get: (teamId: string, monitorId: string) => Promise<IMonitor>;
get: (teamId: string, monitorId: string) => Promise<MonitorEntity>;
getEmbedChecks: (
teamId: string,
monitorId: string,
@@ -93,9 +95,11 @@ export interface IMonitorService {
class MonitorService implements IMonitorService {
public SERVICE_NAME: string;
private jobQueue: IJobQueue;
constructor(jobQueue: IJobQueue) {
private monitorRepository: IMonitorRepository;
constructor(jobQueue: IJobQueue, monitorRepository: IMonitorRepository) {
this.SERVICE_NAME = SERVICE_NAME;
this.jobQueue = jobQueue;
this.monitorRepository = monitorRepository;
}
create = async (
@@ -122,7 +126,7 @@ class MonitorService implements IMonitorService {
};
getAll = async (teamId: string) => {
return Monitor.find({ teamId });
return await this.monitorRepository.findByTeamId(teamId);
};
getAllEmbedChecks = async (
@@ -135,61 +139,24 @@ class MonitorService implements IMonitorService {
type: MonitorType[] = [],
status: MonitorStatus[] = []
) => {
const teamObjectId = new mongoose.Types.ObjectId(teamId);
const counts = await this.monitorRepository.findMonitorCountsByTeamId(
teamId
);
const matchConditions: Record<string, unknown> = {
teamId: teamObjectId,
};
if (search && search.trim() !== "") {
const term = search.trim();
(matchConditions as any).$or = [
{ name: { $regex: term, $options: "i" } },
{ url: { $regex: term, $options: "i" } },
];
}
if (Array.isArray(type) && type.length > 0) {
matchConditions.type = { $in: type };
}
if (Array.isArray(status) && status.length > 0) {
matchConditions.status = { $in: status };
}
const countResult = await Monitor.aggregate([
const monitors = await this.monitorRepository.findByTeamIdWithConfig(
teamId,
{
$match: { teamId: teamObjectId },
},
{
$group: {
_id: null,
total: { $sum: 1 },
upCount: { $sum: { $cond: [{ $eq: ["$status", "up"] }, 1, 0] } },
downCount: { $sum: { $cond: [{ $eq: ["$status", "down"] }, 1, 0] } },
pausedCount: {
$sum: { $cond: [{ $eq: ["$status", "paused"] }, 1, 0] },
},
},
},
]);
search,
sortField,
sortOrder,
page,
rowsPerPage,
type,
status,
}
);
const counts = countResult[0] || {
total: 0,
upCount: 0,
downCount: 0,
pausedCount: 0,
};
const skip = page * rowsPerPage;
const monitors = await Monitor.find(matchConditions)
.lean()
.sort({ [sortField]: sortOrder === "asc" ? 1 : -1 })
.skip(skip)
.limit(rowsPerPage);
const monitorIds = monitors.map((m) => m._id);
const monitorIds = monitors.map((m) => new mongoose.Types.ObjectId(m.id));
const checks = await Check.aggregate([
{
@@ -226,7 +193,7 @@ class MonitorService implements IMonitorService {
};
get = async (teamId: string, monitorId: string) => {
const monitor = await Monitor.findOne({ _id: monitorId, teamId });
const monitor = await this.monitorRepository.findById(monitorId, teamId);
if (!monitor) {
throw new ApiError("Monitor not found", 404);
}
@@ -555,13 +522,16 @@ class MonitorService implements IMonitorService {
return {};
};
private getEmbedChecksRecent = async (monitor: IMonitor, startDate: Date) => {
private getEmbedChecksRecent = async (
monitor: MonitorEntity,
startDate: Date
) => {
const endDate = new Date();
const matchStage: {
"metadata.monitorId": mongoose.Types.ObjectId;
createdAt: { $gte: Date; $lt: Date };
} = {
"metadata.monitorId": monitor._id,
"metadata.monitorId": new mongoose.Types.ObjectId(monitor.id),
createdAt: { $gte: startDate, $lt: endDate },
};
@@ -652,7 +622,7 @@ class MonitorService implements IMonitorService {
// Get monitor stats
const monitorStats = await MonitorStats.findOne({
monitorId: monitor._id,
monitorId: monitor.id,
});
if (!monitorStats) {
@@ -660,19 +630,19 @@ class MonitorService implements IMonitorService {
}
return {
monitor: monitor.toObject(),
monitor: monitor,
checks,
stats: monitorStats,
};
};
private getEmbedChecksOtherRanges = async (
monitor: IMonitor,
monitor: MonitorEntity,
range: string,
startDate: Date
) => {
const monitorStats = await MonitorStats.findOne({
monitorId: monitor._id,
monitorId: monitor.id,
});
if (!monitorStats) {
throw new ApiError("Monitor stats not found", 404);
@@ -683,7 +653,7 @@ class MonitorService implements IMonitorService {
const endDate = new Date();
const docs = await Model.find({
monitorId: monitor._id,
monitorId: monitor.id,
windowStart: { $gte: startDate, $lt: endDate },
})
.sort({ windowStart: -1 })
@@ -739,7 +709,7 @@ class MonitorService implements IMonitorService {
});
return {
monitor: monitor.toObject(),
monitor: monitor,
checks,
stats: monitorStats,
};
@@ -750,7 +720,7 @@ class MonitorService implements IMonitorService {
monitorId: string,
range: string
): Promise<MonitorWithChecksResponse> => {
const monitor = await Monitor.findOne({ _id: monitorId, teamId });
const monitor = await this.monitorRepository.findById(monitorId, teamId);
if (!monitor) {
throw new ApiError("Monitor not found", 404);
}
+1
View File
@@ -0,0 +1 @@
export type { Monitor } from "@/types/domain/monitor.js";
+49
View File
@@ -0,0 +1,49 @@
export const MonitorTypes = [
"http",
"https",
"port",
"ping",
"infrastructure",
"pagespeed",
"docker",
] as const;
export type MonitorType = (typeof MonitorTypes)[number];
export const MonitorStatuses = [
"up",
"down",
"paused",
"initializing",
"resuming",
] as const;
export type MonitorStatus = (typeof MonitorStatuses)[number];
export interface MonitorThresholds {
cpu?: number;
memory?: number;
disk?: number;
temperature?: number;
}
export interface Monitor {
id: string;
orgId: string;
teamId: string;
name: string;
url: string;
port?: number;
secret?: string;
type: MonitorType;
interval: number; // in ms
rejectUnauthorized: boolean;
status: MonitorStatus;
n: number; // Number of consecutive successes required to change status
thresholds?: MonitorThresholds;
lastCheckedAt?: Date;
latestStatuses?: MonitorStatus[];
notificationChannels?: string[];
createdBy: string;
updatedBy: string;
createdAt: Date;
updatedAt: Date;
}
@@ -1,7 +1,7 @@
import { IMonitor, IMonitorStats } from "@/db/models/index.js";
import { IMonitorStats } from "@/db/models/index.js";
import type { Monitor } from "@/types/domain/index.js";
export interface MonitorWithChecksResponse {
monitor: IMonitor;
monitor: Monitor;
checks: Array<{
_id: string;
count: number;