@oneuptime/common 10.0.6 → 10.0.8
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/Server/Middleware/UserAuthorization.ts +36 -0
- package/Server/Services/MonitorService.ts +9 -0
- package/Server/Services/UserNotificationRuleService.ts +83 -0
- package/Server/Types/Markdown.ts +17 -4
- package/Server/Utils/Browser.ts +3 -3
- package/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.ts +158 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +15 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +32 -0
- package/Server/Utils/VM/VMRunner.ts +273 -52
- package/Server/Views/Partials/Head.ejs +3 -1
- package/Tests/Server/Middleware/UserAuthorization.test.ts +1 -0
- package/Types/Monitor/CriteriaFilter.ts +12 -2
- package/Types/Monitor/ExternalStatusPageMonitor/ExternalStatusPageMonitorResponse.ts +16 -0
- package/Types/Monitor/ExternalStatusPageProviderType.ts +8 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +67 -0
- package/Types/Monitor/MonitorStep.ts +34 -0
- package/Types/Monitor/MonitorStepExternalStatusPageMonitor.ts +48 -0
- package/Types/Monitor/MonitorType.ts +16 -2
- package/Types/Probe/ProbeMonitorResponse.ts +2 -0
- package/Utils/Monitor/MonitorMetricType.ts +3 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +30 -1
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +7 -1
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +58 -5
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +16 -4
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/Browser.js +3 -3
- package/build/dist/Server/Utils/Browser.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.js +119 -0
- package/build/dist/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +10 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +22 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMRunner.js +243 -49
- package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
- package/build/dist/Tests/Server/Middleware/UserAuthorization.test.js +1 -0
- package/build/dist/Tests/Server/Middleware/UserAuthorization.test.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +11 -2
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/ExternalStatusPageMonitor/ExternalStatusPageMonitorResponse.js +2 -0
- package/build/dist/Types/Monitor/ExternalStatusPageMonitor/ExternalStatusPageMonitorResponse.js.map +1 -0
- package/build/dist/Types/Monitor/ExternalStatusPageProviderType.js +9 -0
- package/build/dist/Types/Monitor/ExternalStatusPageProviderType.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +62 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +22 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepExternalStatusPageMonitor.js +32 -0
- package/build/dist/Types/Monitor/MonitorStepExternalStatusPageMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorType.js +14 -2
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +3 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/package.json +1 -1
|
@@ -77,22 +77,46 @@ export default class VMRunner {
|
|
|
77
77
|
};
|
|
78
78
|
`);
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
/*
|
|
81
|
+
* axios (get, head, options, post, put, patch, delete, request)
|
|
82
|
+
* bridged via applySyncPromise.
|
|
83
|
+
*
|
|
84
|
+
* For GET/HEAD/OPTIONS/DELETE: args = [method, url, configJson?]
|
|
85
|
+
* For POST/PUT/PATCH: args = [method, url, bodyJson?, configJson?]
|
|
86
|
+
* For REQUEST: args = ['request', '', configJson]
|
|
87
|
+
*/
|
|
81
88
|
const axiosRef: ivm.Reference<
|
|
82
|
-
(
|
|
89
|
+
(
|
|
90
|
+
method: string,
|
|
91
|
+
url: string,
|
|
92
|
+
arg1?: string,
|
|
93
|
+
arg2?: string,
|
|
94
|
+
) => Promise<string>
|
|
83
95
|
> = new ivm.Reference(
|
|
84
96
|
async (
|
|
85
97
|
method: string,
|
|
86
98
|
url: string,
|
|
87
|
-
|
|
99
|
+
arg1?: string,
|
|
100
|
+
arg2?: string,
|
|
88
101
|
): Promise<string> => {
|
|
89
|
-
const
|
|
90
|
-
|
|
102
|
+
const methodsWithBody: string[] = ["post", "put", "patch"];
|
|
103
|
+
const hasBody: boolean = methodsWithBody.includes(method);
|
|
104
|
+
|
|
105
|
+
/*
|
|
106
|
+
* For POST/PUT/PATCH: arg1=body, arg2=config
|
|
107
|
+
* For GET/HEAD/OPTIONS/DELETE/REQUEST: arg1=config
|
|
108
|
+
*/
|
|
109
|
+
const body: JSONObject | undefined =
|
|
110
|
+
hasBody && arg1 ? (JSON.parse(arg1) as JSONObject) : undefined;
|
|
111
|
+
|
|
112
|
+
const configStr: string | undefined = hasBody ? arg2 : arg1;
|
|
113
|
+
const config: JSONObject | undefined = configStr
|
|
114
|
+
? (JSON.parse(configStr) as JSONObject)
|
|
91
115
|
: undefined;
|
|
92
116
|
|
|
93
117
|
// Reconstruct real http/https Agents from serialized markers
|
|
94
|
-
if (
|
|
95
|
-
const httpsAgentConfig: JSONObject | undefined =
|
|
118
|
+
if (config) {
|
|
119
|
+
const httpsAgentConfig: JSONObject | undefined = config[
|
|
96
120
|
"httpsAgent"
|
|
97
121
|
] as JSONObject | undefined;
|
|
98
122
|
|
|
@@ -100,12 +124,12 @@ export default class VMRunner {
|
|
|
100
124
|
httpsAgentConfig &&
|
|
101
125
|
httpsAgentConfig["__agentType"] === "__https_agent__"
|
|
102
126
|
) {
|
|
103
|
-
|
|
127
|
+
config["httpsAgent"] = new https.Agent(
|
|
104
128
|
httpsAgentConfig["options"] as https.AgentOptions,
|
|
105
129
|
) as unknown as JSONObject;
|
|
106
130
|
}
|
|
107
131
|
|
|
108
|
-
const httpAgentConfig: JSONObject | undefined =
|
|
132
|
+
const httpAgentConfig: JSONObject | undefined = config[
|
|
109
133
|
"httpAgent"
|
|
110
134
|
] as JSONObject | undefined;
|
|
111
135
|
|
|
@@ -113,63 +137,246 @@ export default class VMRunner {
|
|
|
113
137
|
httpAgentConfig &&
|
|
114
138
|
httpAgentConfig["__agentType"] === "__http_agent__"
|
|
115
139
|
) {
|
|
116
|
-
|
|
140
|
+
config["httpAgent"] = new http.Agent(
|
|
117
141
|
httpAgentConfig["options"] as http.AgentOptions,
|
|
118
142
|
) as unknown as JSONObject;
|
|
119
143
|
}
|
|
120
144
|
}
|
|
121
145
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Helper: convert AxiosHeaders (or any header-like object) to a
|
|
148
|
+
* plain record so it can be safely JSON-serialised.
|
|
149
|
+
*/
|
|
150
|
+
const toPlainHeaders: (
|
|
151
|
+
headers: unknown,
|
|
152
|
+
) => Record<string, unknown> = (
|
|
153
|
+
headers: unknown,
|
|
154
|
+
): Record<string, unknown> => {
|
|
155
|
+
const plain: Record<string, unknown> = {};
|
|
156
|
+
if (headers) {
|
|
157
|
+
for (const hKey of Object.keys(
|
|
158
|
+
headers as Record<string, unknown>,
|
|
159
|
+
)) {
|
|
160
|
+
plain[hKey] = (headers as Record<string, unknown>)[hKey];
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return plain;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
let response: AxiosResponse;
|
|
168
|
+
|
|
169
|
+
switch (method) {
|
|
170
|
+
case "get":
|
|
171
|
+
response = await axios.get(url, config);
|
|
172
|
+
break;
|
|
173
|
+
case "head":
|
|
174
|
+
response = await axios.head(url, config);
|
|
175
|
+
break;
|
|
176
|
+
case "options":
|
|
177
|
+
response = await axios.options(url, config);
|
|
178
|
+
break;
|
|
179
|
+
case "post":
|
|
180
|
+
response = await axios.post(url, body, config);
|
|
181
|
+
break;
|
|
182
|
+
case "put":
|
|
183
|
+
response = await axios.put(url, body, config);
|
|
184
|
+
break;
|
|
185
|
+
case "patch":
|
|
186
|
+
response = await axios.patch(url, body, config);
|
|
187
|
+
break;
|
|
188
|
+
case "delete":
|
|
189
|
+
response = await axios.delete(url, config);
|
|
190
|
+
break;
|
|
191
|
+
case "request":
|
|
192
|
+
response = await axios.request(
|
|
193
|
+
config as Parameters<typeof axios.request>[0],
|
|
194
|
+
);
|
|
195
|
+
break;
|
|
196
|
+
default:
|
|
197
|
+
throw new Error(`Unsupported HTTP method: ${method}`);
|
|
198
|
+
}
|
|
140
199
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
200
|
+
/*
|
|
201
|
+
* Convert AxiosHeaders to a plain object before serializing.
|
|
202
|
+
* JSON.stringify calls AxiosHeaders.toJSON(key) with a truthy key,
|
|
203
|
+
* which makes it join array headers (like set-cookie) with commas.
|
|
204
|
+
* This produces invalid Cookie headers when user code forwards them.
|
|
205
|
+
*/
|
|
206
|
+
return JSON.stringify({
|
|
207
|
+
status: response.status,
|
|
208
|
+
headers: toPlainHeaders(response.headers),
|
|
209
|
+
data: response.data,
|
|
210
|
+
});
|
|
211
|
+
} catch (err: unknown) {
|
|
212
|
+
/*
|
|
213
|
+
* If this is an axios error with a response (4xx, 5xx, etc.),
|
|
214
|
+
* return the error details as JSON so the sandbox-side axios
|
|
215
|
+
* wrapper can reconstruct error.response for user code.
|
|
216
|
+
*/
|
|
217
|
+
const axiosErr: {
|
|
218
|
+
isAxiosError?: boolean;
|
|
219
|
+
response?: AxiosResponse<any, any, Record<string, unknown>>;
|
|
220
|
+
message?: string;
|
|
221
|
+
} = err as {
|
|
222
|
+
isAxiosError?: boolean;
|
|
223
|
+
response?: AxiosResponse;
|
|
224
|
+
message?: string;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
if (axiosErr.isAxiosError && axiosErr.response) {
|
|
228
|
+
return JSON.stringify({
|
|
229
|
+
__isAxiosError: true,
|
|
230
|
+
message: axiosErr.message || "Request failed",
|
|
231
|
+
status: axiosErr.response.status,
|
|
232
|
+
statusText: axiosErr.response.statusText,
|
|
233
|
+
headers: toPlainHeaders(axiosErr.response.headers),
|
|
234
|
+
data: axiosErr.response.data,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
throw err;
|
|
239
|
+
}
|
|
146
240
|
},
|
|
147
241
|
);
|
|
148
242
|
|
|
149
243
|
await jail.set("_axiosRef", axiosRef);
|
|
150
244
|
|
|
151
245
|
await context.eval(`
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
return
|
|
168
|
-
}
|
|
169
|
-
|
|
246
|
+
function _assertNoFunctions(obj, path) {
|
|
247
|
+
if (!obj || typeof obj !== 'object') return;
|
|
248
|
+
if (Array.isArray(obj)) {
|
|
249
|
+
for (let i = 0; i < obj.length; i++) {
|
|
250
|
+
const fullPath = path + '[' + i + ']';
|
|
251
|
+
if (typeof obj[i] === 'function') {
|
|
252
|
+
throw new Error(
|
|
253
|
+
'Functions are not supported in axios config because of security. ' +
|
|
254
|
+
'Found a function at "' + fullPath + '". Please remove it or replace it with a plain value.'
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
if (obj[i] && typeof obj[i] === 'object') {
|
|
258
|
+
_assertNoFunctions(obj[i], fullPath);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
for (const key of Object.keys(obj)) {
|
|
264
|
+
const fullPath = path ? path + '.' + key : key;
|
|
265
|
+
if (typeof obj[key] === 'function') {
|
|
266
|
+
throw new Error(
|
|
267
|
+
'Functions are not supported in axios config because of security. ' +
|
|
268
|
+
'Found a function at "' + fullPath + '". Please remove it or replace it with a plain value.'
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
if (obj[key] && typeof obj[key] === 'object') {
|
|
272
|
+
_assertNoFunctions(obj[key], fullPath);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function _parseAxiosResult(r) {
|
|
278
|
+
const parsed = JSON.parse(r);
|
|
279
|
+
if (parsed && parsed.__isAxiosError) {
|
|
280
|
+
const err = new Error(parsed.message);
|
|
281
|
+
err.response = {
|
|
282
|
+
status: parsed.status,
|
|
283
|
+
statusText: parsed.statusText,
|
|
284
|
+
headers: parsed.headers,
|
|
285
|
+
data: parsed.data,
|
|
286
|
+
};
|
|
287
|
+
err.isAxiosError = true;
|
|
288
|
+
err.status = parsed.status;
|
|
289
|
+
throw err;
|
|
290
|
+
}
|
|
291
|
+
return parsed;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function _makeAxiosInstance(defaults) {
|
|
295
|
+
function mergeConfig(overrides) {
|
|
296
|
+
if (!defaults && !overrides) return undefined;
|
|
297
|
+
if (!defaults) return overrides;
|
|
298
|
+
if (!overrides) return Object.assign({}, defaults);
|
|
299
|
+
const merged = Object.assign({}, defaults, overrides);
|
|
300
|
+
if (defaults.headers && overrides.headers) {
|
|
301
|
+
merged.headers = Object.assign({}, defaults.headers, overrides.headers);
|
|
302
|
+
}
|
|
303
|
+
return merged;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async function _request(config) {
|
|
307
|
+
const merged = mergeConfig(config);
|
|
308
|
+
if (merged) _assertNoFunctions(merged, 'config');
|
|
309
|
+
const r = await _axiosRef.applySyncPromise(undefined, ['request', '', merged ? JSON.stringify(merged) : undefined]);
|
|
310
|
+
return _parseAxiosResult(r);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Make instance callable: axios(config) or axios(url, config)
|
|
314
|
+
const instance = async function(urlOrConfig, config) {
|
|
315
|
+
if (typeof urlOrConfig === 'object') {
|
|
316
|
+
return _request(urlOrConfig);
|
|
317
|
+
}
|
|
318
|
+
return _request(Object.assign({}, config || {}, { url: urlOrConfig }));
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
instance.request = _request;
|
|
322
|
+
instance.get = async (url, config) => {
|
|
323
|
+
const merged = mergeConfig(config);
|
|
324
|
+
if (merged) _assertNoFunctions(merged, 'config');
|
|
325
|
+
const r = await _axiosRef.applySyncPromise(undefined, ['get', url, merged ? JSON.stringify(merged) : undefined]);
|
|
326
|
+
return _parseAxiosResult(r);
|
|
327
|
+
};
|
|
328
|
+
instance.head = async (url, config) => {
|
|
329
|
+
const merged = mergeConfig(config);
|
|
330
|
+
if (merged) _assertNoFunctions(merged, 'config');
|
|
331
|
+
const r = await _axiosRef.applySyncPromise(undefined, ['head', url, merged ? JSON.stringify(merged) : undefined]);
|
|
332
|
+
return _parseAxiosResult(r);
|
|
333
|
+
};
|
|
334
|
+
instance.options = async (url, config) => {
|
|
335
|
+
const merged = mergeConfig(config);
|
|
336
|
+
if (merged) _assertNoFunctions(merged, 'config');
|
|
337
|
+
const r = await _axiosRef.applySyncPromise(undefined, ['options', url, merged ? JSON.stringify(merged) : undefined]);
|
|
338
|
+
return _parseAxiosResult(r);
|
|
339
|
+
};
|
|
340
|
+
instance.post = async (url, data, config) => {
|
|
341
|
+
const merged = mergeConfig(config);
|
|
342
|
+
if (data) _assertNoFunctions(data, 'data');
|
|
343
|
+
if (merged) _assertNoFunctions(merged, 'config');
|
|
344
|
+
const r = await _axiosRef.applySyncPromise(undefined, ['post', url, data ? JSON.stringify(data) : undefined, merged ? JSON.stringify(merged) : undefined]);
|
|
345
|
+
return _parseAxiosResult(r);
|
|
346
|
+
};
|
|
347
|
+
instance.put = async (url, data, config) => {
|
|
348
|
+
const merged = mergeConfig(config);
|
|
349
|
+
if (data) _assertNoFunctions(data, 'data');
|
|
350
|
+
if (merged) _assertNoFunctions(merged, 'config');
|
|
351
|
+
const r = await _axiosRef.applySyncPromise(undefined, ['put', url, data ? JSON.stringify(data) : undefined, merged ? JSON.stringify(merged) : undefined]);
|
|
352
|
+
return _parseAxiosResult(r);
|
|
353
|
+
};
|
|
354
|
+
instance.patch = async (url, data, config) => {
|
|
355
|
+
const merged = mergeConfig(config);
|
|
356
|
+
if (data) _assertNoFunctions(data, 'data');
|
|
357
|
+
if (merged) _assertNoFunctions(merged, 'config');
|
|
358
|
+
const r = await _axiosRef.applySyncPromise(undefined, ['patch', url, data ? JSON.stringify(data) : undefined, merged ? JSON.stringify(merged) : undefined]);
|
|
359
|
+
return _parseAxiosResult(r);
|
|
360
|
+
};
|
|
361
|
+
instance.delete = async (url, config) => {
|
|
362
|
+
const merged = mergeConfig(config);
|
|
363
|
+
if (merged) _assertNoFunctions(merged, 'config');
|
|
364
|
+
const r = await _axiosRef.applySyncPromise(undefined, ['delete', url, merged ? JSON.stringify(merged) : undefined]);
|
|
365
|
+
return _parseAxiosResult(r);
|
|
366
|
+
};
|
|
367
|
+
instance.create = (instanceDefaults) => {
|
|
368
|
+
if (instanceDefaults) _assertNoFunctions(instanceDefaults, 'defaults');
|
|
369
|
+
const combinedDefaults = mergeConfig(instanceDefaults);
|
|
370
|
+
return _makeAxiosInstance(combinedDefaults);
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
return instance;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const axios = _makeAxiosInstance(null);
|
|
170
377
|
`);
|
|
171
378
|
|
|
172
|
-
// crypto (createHash, createHmac, randomBytes) - bridged via applySync
|
|
379
|
+
// crypto (createHash, createHmac, randomBytes, randomUUID, randomInt) - bridged via applySync
|
|
173
380
|
const cryptoRef: ivm.Reference<
|
|
174
381
|
(op: string, ...args: string[]) => string
|
|
175
382
|
> = new ivm.Reference((op: string, ...args: string[]): string => {
|
|
@@ -192,6 +399,13 @@ export default class VMRunner {
|
|
|
192
399
|
const [size] = args;
|
|
193
400
|
return crypto.randomBytes(parseInt(size!)).toString("hex");
|
|
194
401
|
}
|
|
402
|
+
case "randomUUID": {
|
|
403
|
+
return crypto.randomUUID();
|
|
404
|
+
}
|
|
405
|
+
case "randomInt": {
|
|
406
|
+
const [min, max] = args;
|
|
407
|
+
return String(crypto.randomInt(parseInt(min!), parseInt(max!)));
|
|
408
|
+
}
|
|
195
409
|
default:
|
|
196
410
|
throw new Error(`Unsupported crypto operation: ${op}`);
|
|
197
411
|
}
|
|
@@ -214,6 +428,13 @@ export default class VMRunner {
|
|
|
214
428
|
randomBytes: (size) => ({
|
|
215
429
|
toString(enc) { return _cryptoRef.applySync(undefined, ['randomBytes', String(size)]); }
|
|
216
430
|
}),
|
|
431
|
+
randomUUID: () => {
|
|
432
|
+
return _cryptoRef.applySync(undefined, ['randomUUID']);
|
|
433
|
+
},
|
|
434
|
+
randomInt: (minOrMax, max) => {
|
|
435
|
+
if (max === undefined) { max = minOrMax; minOrMax = 0; }
|
|
436
|
+
return Number(_cryptoRef.applySync(undefined, ['randomInt', String(minOrMax), String(max)]));
|
|
437
|
+
},
|
|
217
438
|
};
|
|
218
439
|
`);
|
|
219
440
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
2
2
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
3
|
+
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap" as="style">
|
|
3
4
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap"
|
|
4
5
|
rel="stylesheet">
|
|
5
6
|
<style>
|
|
6
7
|
* {
|
|
7
|
-
font-family: Inter;
|
|
8
|
+
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
|
|
@@ -34,6 +35,7 @@
|
|
|
34
35
|
width: auto;
|
|
35
36
|
}
|
|
36
37
|
</style>
|
|
38
|
+
<link rel="preload" href="https://cdn.tailwindcss.com" as="script">
|
|
37
39
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
38
40
|
|
|
39
41
|
<!-- Google Tag Manager -->
|
|
@@ -74,6 +74,13 @@ export enum CheckOn {
|
|
|
74
74
|
DomainNameServer = "Domain Name Server",
|
|
75
75
|
DomainStatusCode = "Domain Status Code",
|
|
76
76
|
DomainIsExpired = "Domain Is Expired",
|
|
77
|
+
|
|
78
|
+
// External Status Page monitors.
|
|
79
|
+
ExternalStatusPageIsOnline = "External Status Page Is Online",
|
|
80
|
+
ExternalStatusPageOverallStatus = "External Status Page Overall Status",
|
|
81
|
+
ExternalStatusPageComponentStatus = "External Status Page Component Status",
|
|
82
|
+
ExternalStatusPageActiveIncidents = "External Status Page Active Incidents",
|
|
83
|
+
ExternalStatusPageResponseTime = "External Status Page Response Time (in ms)",
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
export interface ServerMonitorOptions {
|
|
@@ -159,7 +166,8 @@ export class CriteriaFilterUtil {
|
|
|
159
166
|
checkOn === CheckOn.IsOnline ||
|
|
160
167
|
checkOn === CheckOn.SnmpIsOnline ||
|
|
161
168
|
checkOn === CheckOn.DnsIsOnline ||
|
|
162
|
-
checkOn === CheckOn.DomainIsExpired
|
|
169
|
+
checkOn === CheckOn.DomainIsExpired ||
|
|
170
|
+
checkOn === CheckOn.ExternalStatusPageIsOnline
|
|
163
171
|
) {
|
|
164
172
|
return false;
|
|
165
173
|
}
|
|
@@ -229,7 +237,9 @@ export class CriteriaFilterUtil {
|
|
|
229
237
|
checkOn === CheckOn.SnmpResponseTime ||
|
|
230
238
|
checkOn === CheckOn.SnmpIsOnline ||
|
|
231
239
|
checkOn === CheckOn.DnsResponseTime ||
|
|
232
|
-
checkOn === CheckOn.DnsIsOnline
|
|
240
|
+
checkOn === CheckOn.DnsIsOnline ||
|
|
241
|
+
checkOn === CheckOn.ExternalStatusPageResponseTime ||
|
|
242
|
+
checkOn === CheckOn.ExternalStatusPageIsOnline
|
|
233
243
|
);
|
|
234
244
|
}
|
|
235
245
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ExternalStatusPageComponentStatus {
|
|
2
|
+
name: string;
|
|
3
|
+
status: string;
|
|
4
|
+
description?: string | undefined;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export default interface ExternalStatusPageMonitorResponse {
|
|
8
|
+
isOnline: boolean;
|
|
9
|
+
overallStatus: string;
|
|
10
|
+
componentStatuses: Array<ExternalStatusPageComponentStatus>;
|
|
11
|
+
activeIncidentCount: number;
|
|
12
|
+
responseTimeInMs: number;
|
|
13
|
+
failureCause: string;
|
|
14
|
+
rawBody?: string | undefined;
|
|
15
|
+
isTimeout?: boolean | undefined;
|
|
16
|
+
}
|
|
@@ -448,6 +448,33 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
|
|
448
448
|
return monitorCriteriaInstance;
|
|
449
449
|
}
|
|
450
450
|
|
|
451
|
+
if (arg.monitorType === MonitorType.ExternalStatusPage) {
|
|
452
|
+
const monitorCriteriaInstance: MonitorCriteriaInstance =
|
|
453
|
+
new MonitorCriteriaInstance();
|
|
454
|
+
|
|
455
|
+
monitorCriteriaInstance.data = {
|
|
456
|
+
id: ObjectID.generate().toString(),
|
|
457
|
+
monitorStatusId: arg.monitorStatusId,
|
|
458
|
+
filterCondition: FilterCondition.All,
|
|
459
|
+
filters: [
|
|
460
|
+
{
|
|
461
|
+
checkOn: CheckOn.ExternalStatusPageIsOnline,
|
|
462
|
+
filterType: FilterType.True,
|
|
463
|
+
value: undefined,
|
|
464
|
+
},
|
|
465
|
+
],
|
|
466
|
+
incidents: [],
|
|
467
|
+
alerts: [],
|
|
468
|
+
createAlerts: false,
|
|
469
|
+
changeMonitorStatus: true,
|
|
470
|
+
createIncidents: false,
|
|
471
|
+
name: `Check if ${arg.monitorName} is online`,
|
|
472
|
+
description: `This criteria checks if the ${arg.monitorName} external status page is reachable`,
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
return monitorCriteriaInstance;
|
|
476
|
+
}
|
|
477
|
+
|
|
451
478
|
return null;
|
|
452
479
|
}
|
|
453
480
|
|
|
@@ -629,6 +656,46 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
|
|
|
629
656
|
};
|
|
630
657
|
}
|
|
631
658
|
|
|
659
|
+
if (arg.monitorType === MonitorType.ExternalStatusPage) {
|
|
660
|
+
monitorCriteriaInstance.data = {
|
|
661
|
+
id: ObjectID.generate().toString(),
|
|
662
|
+
monitorStatusId: arg.monitorStatusId,
|
|
663
|
+
filterCondition: FilterCondition.Any,
|
|
664
|
+
filters: [
|
|
665
|
+
{
|
|
666
|
+
checkOn: CheckOn.ExternalStatusPageIsOnline,
|
|
667
|
+
filterType: FilterType.False,
|
|
668
|
+
value: undefined,
|
|
669
|
+
},
|
|
670
|
+
],
|
|
671
|
+
incidents: [
|
|
672
|
+
{
|
|
673
|
+
title: `${arg.monitorName} is offline`,
|
|
674
|
+
description: `${arg.monitorName} external status page is currently unreachable.`,
|
|
675
|
+
incidentSeverityId: arg.incidentSeverityId,
|
|
676
|
+
autoResolveIncident: true,
|
|
677
|
+
id: ObjectID.generate().toString(),
|
|
678
|
+
onCallPolicyIds: [],
|
|
679
|
+
},
|
|
680
|
+
],
|
|
681
|
+
changeMonitorStatus: true,
|
|
682
|
+
createIncidents: true,
|
|
683
|
+
createAlerts: false,
|
|
684
|
+
alerts: [
|
|
685
|
+
{
|
|
686
|
+
title: `${arg.monitorName} is offline`,
|
|
687
|
+
description: `${arg.monitorName} external status page is currently unreachable.`,
|
|
688
|
+
alertSeverityId: arg.alertSeverityId,
|
|
689
|
+
autoResolveAlert: true,
|
|
690
|
+
id: ObjectID.generate().toString(),
|
|
691
|
+
onCallPolicyIds: [],
|
|
692
|
+
},
|
|
693
|
+
],
|
|
694
|
+
name: `Check if ${arg.monitorName} is offline`,
|
|
695
|
+
description: `This criteria checks if the ${arg.monitorName} external status page is unreachable`,
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
|
|
632
699
|
if (
|
|
633
700
|
arg.monitorType === MonitorType.API ||
|
|
634
701
|
arg.monitorType === MonitorType.Website
|
|
@@ -35,6 +35,9 @@ import MonitorStepDnsMonitor, {
|
|
|
35
35
|
import MonitorStepDomainMonitor, {
|
|
36
36
|
MonitorStepDomainMonitorUtil,
|
|
37
37
|
} from "./MonitorStepDomainMonitor";
|
|
38
|
+
import MonitorStepExternalStatusPageMonitor, {
|
|
39
|
+
MonitorStepExternalStatusPageMonitorUtil,
|
|
40
|
+
} from "./MonitorStepExternalStatusPageMonitor";
|
|
38
41
|
import Zod, { ZodSchema } from "../../Utils/Schema/Zod";
|
|
39
42
|
|
|
40
43
|
export interface MonitorStepType {
|
|
@@ -84,6 +87,9 @@ export interface MonitorStepType {
|
|
|
84
87
|
|
|
85
88
|
// Domain monitor
|
|
86
89
|
domainMonitor?: MonitorStepDomainMonitor | undefined;
|
|
90
|
+
|
|
91
|
+
// External Status Page monitor
|
|
92
|
+
externalStatusPageMonitor?: MonitorStepExternalStatusPageMonitor | undefined;
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
export default class MonitorStep extends DatabaseProperty {
|
|
@@ -112,6 +118,7 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
112
118
|
snmpMonitor: undefined,
|
|
113
119
|
dnsMonitor: undefined,
|
|
114
120
|
domainMonitor: undefined,
|
|
121
|
+
externalStatusPageMonitor: undefined,
|
|
115
122
|
};
|
|
116
123
|
}
|
|
117
124
|
|
|
@@ -145,6 +152,7 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
145
152
|
snmpMonitor: undefined,
|
|
146
153
|
dnsMonitor: undefined,
|
|
147
154
|
domainMonitor: undefined,
|
|
155
|
+
externalStatusPageMonitor: undefined,
|
|
148
156
|
};
|
|
149
157
|
|
|
150
158
|
return monitorStep;
|
|
@@ -252,6 +260,13 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
252
260
|
return this;
|
|
253
261
|
}
|
|
254
262
|
|
|
263
|
+
public setExternalStatusPageMonitor(
|
|
264
|
+
externalStatusPageMonitor: MonitorStepExternalStatusPageMonitor,
|
|
265
|
+
): MonitorStep {
|
|
266
|
+
this.data!.externalStatusPageMonitor = externalStatusPageMonitor;
|
|
267
|
+
return this;
|
|
268
|
+
}
|
|
269
|
+
|
|
255
270
|
public setCustomCode(customCode: string): MonitorStep {
|
|
256
271
|
this.data!.customCode = customCode;
|
|
257
272
|
return this;
|
|
@@ -380,6 +395,16 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
380
395
|
}
|
|
381
396
|
}
|
|
382
397
|
|
|
398
|
+
if (monitorType === MonitorType.ExternalStatusPage) {
|
|
399
|
+
if (!value.data.externalStatusPageMonitor) {
|
|
400
|
+
return "External status page configuration is required";
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (!value.data.externalStatusPageMonitor.statusPageUrl) {
|
|
404
|
+
return "Status page URL is required";
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
383
408
|
return null;
|
|
384
409
|
}
|
|
385
410
|
|
|
@@ -431,6 +456,11 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
431
456
|
domainMonitor: this.data.domainMonitor
|
|
432
457
|
? MonitorStepDomainMonitorUtil.toJSON(this.data.domainMonitor)
|
|
433
458
|
: undefined,
|
|
459
|
+
externalStatusPageMonitor: this.data.externalStatusPageMonitor
|
|
460
|
+
? MonitorStepExternalStatusPageMonitorUtil.toJSON(
|
|
461
|
+
this.data.externalStatusPageMonitor,
|
|
462
|
+
)
|
|
463
|
+
: undefined,
|
|
434
464
|
},
|
|
435
465
|
});
|
|
436
466
|
}
|
|
@@ -542,6 +572,9 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
542
572
|
domainMonitor: json["domainMonitor"]
|
|
543
573
|
? (json["domainMonitor"] as JSONObject)
|
|
544
574
|
: undefined,
|
|
575
|
+
externalStatusPageMonitor: json["externalStatusPageMonitor"]
|
|
576
|
+
? (json["externalStatusPageMonitor"] as JSONObject)
|
|
577
|
+
: undefined,
|
|
545
578
|
}) as any;
|
|
546
579
|
|
|
547
580
|
return monitorStep;
|
|
@@ -569,6 +602,7 @@ export default class MonitorStep extends DatabaseProperty {
|
|
|
569
602
|
snmpMonitor: Zod.any().optional(),
|
|
570
603
|
dnsMonitor: Zod.any().optional(),
|
|
571
604
|
domainMonitor: Zod.any().optional(),
|
|
605
|
+
externalStatusPageMonitor: Zod.any().optional(),
|
|
572
606
|
}).openapi({
|
|
573
607
|
type: "object",
|
|
574
608
|
example: {
|