Openstatus
www.openstatus.dev
1import type { Monitor, Notification } from "@openstatus/db/src/schema";
2
3import type { Region } from "@openstatus/db/src/schema/constants";
4import { transformHeaders } from "@openstatus/utils";
5import { PayloadSchema, WebhookSchema } from "./schema";
6
7export const sendAlert = async ({
8 monitor,
9 notification,
10 cronTimestamp,
11 statusCode,
12 latency,
13 message,
14 // biome-ignore lint/correctness/noUnusedVariables: <explanation>
15 incidentId,
16}: {
17 monitor: Monitor;
18 notification: Notification;
19 statusCode?: number;
20 message?: string;
21 incidentId?: string;
22 cronTimestamp: number;
23 latency?: number;
24 region?: Region;
25}) => {
26 const notificationData = WebhookSchema.parse(JSON.parse(notification.data));
27
28 const body = PayloadSchema.parse({
29 monitor: monitor,
30 cronTimestamp,
31 status: "error",
32 statusCode,
33 latency,
34 errorMessage: message,
35 });
36
37 const res = await fetch(notificationData.webhook.endpoint, {
38 method: "post",
39 body: JSON.stringify(body),
40 headers: notificationData.webhook.headers
41 ? transformHeaders(notificationData.webhook.headers)
42 : {
43 "Content-Type": "application/json",
44 },
45 });
46 if (!res.ok) {
47 throw new Error(`Failed to send webhook notification: ${res.statusText}`);
48 }
49};
50
51export const sendRecovery = async ({
52 monitor,
53 notification,
54 cronTimestamp,
55 latency,
56 statusCode,
57 message,
58 // biome-ignore lint/correctness/noUnusedVariables: <explanation>
59 incidentId,
60}: {
61 monitor: Monitor;
62 notification: Notification;
63 statusCode?: number;
64 message?: string;
65 incidentId?: string;
66 cronTimestamp: number;
67 latency?: number;
68 region?: Region;
69}) => {
70 const notificationData = WebhookSchema.parse(JSON.parse(notification.data));
71
72 const body = PayloadSchema.parse({
73 monitor: monitor,
74 cronTimestamp,
75 status: "recovered",
76 statusCode,
77 latency,
78 errorMessage: message,
79 });
80 const url = notificationData.webhook.endpoint;
81 const res = await fetch(url, {
82 method: "post",
83 body: JSON.stringify(body),
84 headers: notificationData.webhook.headers
85 ? transformHeaders(notificationData.webhook.headers)
86 : {
87 "Content-Type": "application/json",
88 },
89 });
90 if (!res.ok) {
91 throw new Error(`Failed to send SMS: ${res.statusText}`);
92 }
93};
94
95export const sendDegraded = async ({
96 monitor,
97 notification,
98 cronTimestamp,
99 latency,
100 statusCode,
101 message,
102}: {
103 monitor: Monitor;
104 notification: Notification;
105 statusCode?: number;
106 message?: string;
107 incidentId?: string;
108 cronTimestamp: number;
109 latency?: number;
110 region?: Region;
111}) => {
112 const notificationData = WebhookSchema.parse(JSON.parse(notification.data));
113
114 const body = PayloadSchema.parse({
115 monitor: monitor,
116 cronTimestamp,
117 status: "degraded",
118 statusCode,
119 latency,
120 errorMessage: message,
121 });
122
123 const res = await fetch(notificationData.webhook.endpoint, {
124 method: "post",
125 body: JSON.stringify(body),
126 headers: notificationData.webhook.headers
127 ? transformHeaders(notificationData.webhook.headers)
128 : {
129 "Content-Type": "application/json",
130 },
131 });
132 if (!res.ok) {
133 throw new Error(`Failed to send SMS: ${res.statusText}`);
134 }
135};
136
137export const sendTest = async ({
138 url,
139 headers,
140}: {
141 url: string;
142 headers?: { key: string; value: string }[];
143}) => {
144 const body = PayloadSchema.parse({
145 monitor: {
146 id: 1,
147 name: "test",
148 url: "http://openstat.us",
149 },
150 cronTimestamp: Date.now(),
151 status: "recovered",
152 statusCode: 200,
153 latency: 1337,
154 });
155 try {
156 const response = await fetch(url, {
157 method: "post",
158 body: JSON.stringify(body),
159 headers: headers
160 ? transformHeaders(headers)
161 : {
162 "Content-Type": "application/json",
163 },
164 });
165 if (!response.ok) {
166 throw new Error("Failed to send test");
167 }
168 return true;
169 } catch (err) {
170 console.log(err);
171 throw new Error("Failed to send test");
172 }
173};