Repository: hyperjumptech/monika
Pull request #1215 (2023-12-18 08:16:47)

Chore: Clean up ESLint warnings
# Monika Pull Request (PR)

## What feature/issue does this PR add

1. Clean up ESLint warnings down to 67 warnings

## How did you implement / how did you fix it

1. Use Joi library to validate types
2. Apply suggestions from ESLint

## How to test

1. `npm test`
2. `npm pack && npm i -g hyperjumptech-monika-*.tgz`
3. `monika`


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) Report
Attention: `22 lines` in your changes are missing coverage. Please review.
> Comparison is base [(`63ccdf8`)](https://app.codecov.io/gh/hyperjumptech/monika/commit/63ccdf8d6acbf14cbaacae33737ed014dd83c7b6?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) 63.67% compared to head [(`d4a7f30`)](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) 63.70%.

| [Files](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) | Patch % | Lines |
|---|---|---|
| [src/components/config/parse-insomnia.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-c3JjL2NvbXBvbmVudHMvY29uZmlnL3BhcnNlLWluc29tbmlhLnRz) | 73.91% | [3 Missing and 3 partials :warning: ](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) |
| [packages/notification/channel/instatus/database.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-cGFja2FnZXMvbm90aWZpY2F0aW9uL2NoYW5uZWwvaW5zdGF0dXMvZGF0YWJhc2UudHM=) | 20.00% | [4 Missing :warning: ](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) |
| [packages/notification/channel/whatsapp.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-cGFja2FnZXMvbm90aWZpY2F0aW9uL2NoYW5uZWwvd2hhdHNhcHAudHM=) | 0.00% | [4 Missing :warning: ](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) |
| [src/components/config/create-config.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-c3JjL2NvbXBvbmVudHMvY29uZmlnL2NyZWF0ZS1jb25maWcudHM=) | 0.00% | [2 Missing :warning: ](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) |
| [src/components/config/parse-har.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-c3JjL2NvbXBvbmVudHMvY29uZmlnL3BhcnNlLWhhci50cw==) | 84.61% | [1 Missing and 1 partial :warning: ](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) |
| [packages/notification/utils/authorization.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-cGFja2FnZXMvbm90aWZpY2F0aW9uL3V0aWxzL2F1dGhvcml6YXRpb24udHM=) | 75.00% | [0 Missing and 1 partial :warning: ](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) |
| [src/components/config/index.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-c3JjL2NvbXBvbmVudHMvY29uZmlnL2luZGV4LnRz) | 50.00% | [1 Missing :warning: ](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) |
| [src/components/config/parse-postman.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-c3JjL2NvbXBvbmVudHMvY29uZmlnL3BhcnNlLXBvc3RtYW4udHM=) | 94.44% | [1 Missing :warning: ](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) |
| [src/components/logger/history.ts](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech#diff-c3JjL2NvbXBvbmVudHMvbG9nZ2VyL2hpc3RvcnkudHM=) | 75.00% | [1 Missing :warning: ](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #1215      +/-   ##
==========================================
+ Coverage   63.67%   63.70%   +0.02%     
==========================================
  Files         111      111              
  Lines        3207     3237      +30     
  Branches      544      551       +7     
==========================================
+ Hits         2042     2062      +20     
- Misses        990      998       +8     
- Partials      175      177       +2     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/hyperjumptech/monika/pull/1215?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=hyperjumptech).


Patch:
diff --git a/packages/notification/channel/instatus/database.ts b/packages/notification/channel/instatus/database.ts
index f16561f6..60ff4c9c 100644
--- a/packages/notification/channel/instatus/database.ts
+++ b/packages/notification/channel/instatus/database.ts
@@ -1,5 +1,29 @@
+/**********************************************************************************
+ * MIT License                                                                    *
+ *                                                                                *
+ * Copyright (c) 2021 Hyperjump Technology                                        *
+ *                                                                                *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy   *
+ * of this software and associated documentation files (the "Software"), to deal  *
+ * in the Software without restriction, including without limitation the rights   *
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      *
+ * copies of the Software, and to permit persons to whom the Software is          *
+ * furnished to do so, subject to the following conditions:                       *
+ *                                                                                *
+ * The above copyright notice and this permission notice shall be included in all *
+ * copies or substantial portions of the Software.                                *
+ *                                                                                *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE    *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER         *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  *
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  *
+ * SOFTWARE.                                                                      *
+ **********************************************************************************/
+
 import path from 'path'
-import sqlite3 from 'sqlite3'
+import * as sqlite3 from 'sqlite3'
 import { open, type Database } from 'sqlite'
 
 type Incident = {
@@ -37,7 +61,7 @@ export async function insertIncident({
   ) VALUES (?, ?, ?, ?, ?, ?);`
   const sqlParams = [status, url, probeID, incidentID, dateNow, dateNow]
 
-  await (await getDatabase()).run(sqlStatement, sqlParams)
+  await getDatabase().then((db) => db.run(sqlStatement, sqlParams))
 }
 
 export async function updateIncident({
@@ -49,7 +73,7 @@ export async function updateIncident({
    WHERE incident_id = ?`
   const sqlParams = [status, dateNow, incidentID]
 
-  await (await getDatabase()).run(sqlStatement, sqlParams)
+  await getDatabase().then((db) => db.run(sqlStatement, sqlParams))
 }
 
 export async function findIncident({
@@ -60,9 +84,9 @@ export async function findIncident({
   const sqlStatement = `SELECT incident_id FROM instatus_page_incidents 
     WHERE status = ? AND url = ? AND probe_id = ? LIMIT 1`
   const sqlParams = [status, url, probeID]
-  const incident = await (
-    await getDatabase()
-  ).get<FindIncidentResponse>(sqlStatement, sqlParams)
+  const incident = await getDatabase().then((db) =>
+    db.get<FindIncidentResponse>(sqlStatement, sqlParams)
+  )
 
   return incident
 }
@@ -73,6 +97,7 @@ async function getDatabase(): Promise<
   if (!db) {
     db = await open({
       filename: dbPath,
+      // eslint-disable-next-line no-bitwise
       mode: sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE,
       driver: sqlite3.Database,
     })
diff --git a/packages/notification/channel/teams.ts b/packages/notification/channel/teams.ts
index 7ccaeb6b..68bb3a0b 100644
--- a/packages/notification/channel/teams.ts
+++ b/packages/notification/channel/teams.ts
@@ -37,7 +37,7 @@ export type Content = {
     activityTitle?: string
     facts?: {
       name?: string
-      value?: any
+      value?: unknown
     }[]
     activitySubtitle?: string
     markdown?: boolean
diff --git a/packages/notification/channel/whatsapp.ts b/packages/notification/channel/whatsapp.ts
index a72f3656..9f6b5c26 100644
--- a/packages/notification/channel/whatsapp.ts
+++ b/packages/notification/channel/whatsapp.ts
@@ -92,7 +92,7 @@ async function sendTextMessage({
   baseUrl,
 }: SendTextMessageParams): Promise<void> {
   try {
-    const auth = authorize('bearer', token)
+    const auth = authorize({ type: 'bearer', token })
     const url = `${baseUrl}/v1/messages`
 
     await sendHttpRequest({
@@ -100,7 +100,7 @@ async function sendTextMessage({
       url,
       headers: {
         'Content-Type': 'application/json',
-        Authorization: auth,
+        Authorization: auth || '',
       },
       data: {
         to: recipient,
@@ -125,10 +125,7 @@ async function loginUser({
   username,
 }: NotificationData): Promise<string> {
   try {
-    const auth = authorize('basic', {
-      username,
-      password,
-    })
+    const auth = authorize({ type: 'basic', username, password })
 
     const url = `${baseURL}/v1/users/login`
     const resp = await sendHttpRequest({
@@ -136,7 +133,7 @@ async function loginUser({
       url,
       headers: {
         'Content-Type': 'application/json',
-        Authorization: auth,
+        Authorization: auth || '',
       },
     })
     const loginResp: LoginUserSuccessResponse = resp?.data
diff --git a/packages/notification/utils/authorization.ts b/packages/notification/utils/authorization.ts
index e1fe2ce4..288105e5 100644
--- a/packages/notification/utils/authorization.ts
+++ b/packages/notification/utils/authorization.ts
@@ -24,7 +24,13 @@
 
 import { AxiosBasicCredentials } from 'axios'
 
-export const authBasic = (cred: AxiosBasicCredentials): any => {
+type BasicCredentials = AxiosBasicCredentials & {
+  type: 'basic'
+}
+
+type Bearer = { type: 'bearer'; token: string }
+
+export const authBasic = (cred: AxiosBasicCredentials): string => {
   if (!cred.username)
     throw new Error('Username should not be empty or undefined')
   if (!cred.password || cred.password.length < 6)
@@ -39,14 +45,16 @@ export const authBasic = (cred: AxiosBasicCredentials): any => {
 
 export const authBearer = (token: string): string => `Bearer ${token}`
 
-export const authorize = (type: string, args: any): any => {
-  switch (type) {
+export const authorize = (
+  args: BasicCredentials | Bearer
+): string | undefined => {
+  switch (args.type) {
     case 'basic': {
       return authBasic(args)
     }
 
     case 'bearer': {
-      return authBearer(args)
+      return authBearer(args.token)
     }
 
     default: {
diff --git a/src/components/config/create-config.ts b/src/components/config/create-config.ts
index 40ac1abf..b044979c 100644
--- a/src/components/config/create-config.ts
+++ b/src/components/config/create-config.ts
@@ -34,7 +34,7 @@ export const createConfigFile = async (flags: MonikaFlags): Promise<string> => {
     const url =
       'https://raw.githubusercontent.com/hyperjumptech/monika/main/monika.example.yml'
     await sendHttpRequest({ url }).then((resp) => {
-      fs.writeFileSync(filename, resp.data, 'utf-8')
+      fs.writeFileSync(filename, resp.data, 'utf8')
     })
     log.info(
       `${filename} file has been created in this directory. You can change the URL to probe and other configurations in that ${filename} file.`
@@ -52,7 +52,7 @@ export const createConfigFile = async (flags: MonikaFlags): Promise<string> => {
       cron_schedule: '*/1 * * * *'
     `
 
-    fs.writeFileSync(filename, ymlConfig, 'utf-8')
+    fs.writeFileSync(filename, ymlConfig, 'utf8')
   }
 
   return filename
diff --git a/src/components/config/index.ts b/src/components/config/index.ts
index 385f0576..657c7ede 100644
--- a/src/components/config/index.ts
+++ b/src/components/config/index.ts
@@ -22,7 +22,7 @@
  * SOFTWARE.                                                                      *
  **********************************************************************************/
 
-import chokidar from 'chokidar'
+import { watch } from 'chokidar'
 import { ux } from '@oclif/core'
 import { existsSync, writeFileSync } from 'fs'
 import isUrl from 'is-url'
@@ -222,7 +222,7 @@ function scheduleRemoteConfigFetcher({
 function watchConfigFile({ flags, path }: WatchConfigFileParams) {
   const isWatchConfigFile = !(isTestEnvironment || flags.repeat !== 0)
   if (isWatchConfigFile) {
-    const watcher = chokidar.watch(path)
+    const watcher = watch(path)
     watcher.on('change', async () => {
       const config = await getConfigFrom(flags)
 
diff --git a/src/components/config/parse-har.ts b/src/components/config/parse-har.ts
index 29fc6d78..4cdbd7f9 100644
--- a/src/components/config/parse-har.ts
+++ b/src/components/config/parse-har.ts
@@ -22,17 +22,20 @@
  * SOFTWARE.                                                                      *
  **********************************************************************************/
 
+import Joi from 'joi'
 import { Config } from '../../interfaces/config'
 import { RequestConfig } from '../../interfaces/request'
+import { DEFAULT_INTERVAL } from './validation/validator/default-values'
+
+const keyValValidator = Joi.array().items(
+  Joi.object({ key: Joi.string(), value: Joi.string() })
+)
 
 const convertNameValueArraysToObject = (
-  headers: {
-    name: string
-    value: any
-  }[]
+  keyVal: { name: string; value: string }[]
 ) => {
-  const obj: any = {}
-  for (const item of headers) {
+  const obj: Record<string, string> = {}
+  for (const item of keyVal) {
     if (item.name.charAt(0) !== ':') {
       obj[item.name] = item.value
     }
@@ -41,7 +44,15 @@ const convertNameValueArraysToObject = (
   return obj
 }
 
-const parsePostData = (postData: any) => {
+const postDataValidator = Joi.object({
+  mimeType: Joi.string(),
+  text: Joi.string(),
+  params: keyValValidator.optional(),
+})
+
+const parsePostData = (
+  postData: { mimeType: string; text: string } | undefined
+) => {
   if (!postData) {
     return {}
   }
@@ -56,10 +67,37 @@ const parsePostData = (postData: any) => {
 export const parseHarFile = (fileContents: string): Config => {
   // Read file from filepath
   try {
-    const harJson = JSON.parse(fileContents)
+    const entryValidator = Joi.object({
+      entry: Joi.object({
+        request: Joi.object({
+          method: Joi.string(),
+          url: Joi.string(),
+          headers: Joi.array().items(keyValValidator),
+          queryString: Joi.array().items(keyValValidator),
+          postData: postDataValidator,
+        }),
+      }),
+    })
+
+    const { value: harJson, error } = Joi.object({
+      log: Joi.object({
+        entries: Joi.array().items(entryValidator.required()),
+      }),
+    }).validate(JSON.parse(fileContents), { allowUnknown: true })
+
+    if (error)
+      throw new Error(`No HTTP requests in your HAR file. ${error.message}`)
 
     const harRequest: RequestConfig[] = harJson.log.entries.map(
-      (entry: { request: any }) => ({
+      (entry: {
+        request: {
+          method: string
+          url: string
+          headers: { name: string; value: string }[]
+          queryString: { name: string; value: string }[]
+          postData?: { mimeType: string; text: string }
+        }
+      }) => ({
         method: entry.request.method,
         url: entry.request.url,
         headers: convertNameValueArraysToObject(entry.request.headers),
@@ -68,11 +106,14 @@ export const parseHarFile = (fileContents: string): Config => {
       })
     )
 
-    const harConfig: any = {
+    const harConfig: Config = {
       probes: [
         {
           id: harRequest[0].url,
+          name: harRequest[0].url,
+          interval: DEFAULT_INTERVAL,
           requests: harRequest,
+          alerts: [],
         },
       ],
     }
diff --git a/src/components/config/parse-insomnia.ts b/src/components/config/parse-insomnia.ts
index 7896ff87..c17dcc5e 100644
--- a/src/components/config/parse-insomnia.ts
+++ b/src/components/config/parse-insomnia.ts
@@ -25,53 +25,68 @@
 import type { Config } from '../../interfaces/config'
 import yml from 'js-yaml'
 import type { Probe } from '../../interfaces/probe'
-import { compile } from 'handlebars'
+import { compile as compileTemplate } from 'handlebars'
 import type { AxiosRequestHeaders, Method } from 'axios'
+import Joi from 'joi'
 
-interface InsomniaResource {
-  _id: string
-  authentication: any
-  name: string
-  data?: any
-  description?: string
-  url?: string
-  headers?: any
-  method?: string
-  body?: any
-  _type: string
-}
+const envValidator = Joi.object({
+  scheme: Joi.array().items(Joi.string()),
+  host: Joi.string(),
+  // eslint-disable-next-line camelcase
+  base_path: Joi.string(),
+})
+
+const resourceValidator = Joi.object({
+  _id: Joi.string(),
+  authentication: Joi.object({
+    type: Joi.string(),
+    disabled: Joi.boolean(),
+    prefix: Joi.string(),
+  }),
+  name: Joi.string(),
+  data: envValidator,
+  description: Joi.string().allow(''),
+  url: Joi.string(),
+  headers: Joi.array().items(
+    Joi.object({
+      name: Joi.string(),
+      value: Joi.string(),
+      disabled: Joi.boolean(),
+    })
+  ),
+  method: Joi.string(),
+  body: Joi.object({ mimeType: Joi.string(), text: Joi.string() }),
+  _type: Joi.string(),
+})
+
+const insomniaValidator = Joi.object({
+  // eslint-disable-next-line camelcase
+  __export_format: Joi.number(),
+  // eslint-disable-next-line camelcase
+  __export_source: Joi.string(),
+  resources: Joi.array().items(resourceValidator),
+})
 
 let baseUrl = ''
-let environmentVariables: any | undefined
+let environmentVariables: object | undefined
 
 export default function parseInsomnia(
   configString: string,
   format: string
 ): Config {
-  const insomniaData =
+  const parseResult =
     format === 'yaml' || format === 'yml'
-      ? (yml.load(configString, { json: true }) as InsomniaResource[])
+      ? yml.load(configString, { json: true })
       : JSON.parse(configString)
 
-  validateInsomniaExport(insomniaData)
-  const data: InsomniaResource[] = insomniaData.resources
-  const env = data
-    .reverse()
-    .find(
-      (d) =>
-        d._type === 'environment' &&
-        d.data?.scheme &&
-        d.data?.host &&
-        d.data?.base_path
-    )
-
-  environmentVariables = env?.data
-  setBaseUrl(environmentVariables)
+  const { error, value: insomniaData } = insomniaValidator.validate(
+    parseResult,
+    { allowUnknown: true }
+  )
 
-  return mapInsomniaToConfig(data)
-}
+  if (error) throw new Error(error?.message)
 
-function validateInsomniaExport(data: any) {
+  const data = insomniaData.resources
   if (
     data?.__export_format !== 4 &&
     (data?.__export_source as undefined | string)?.includes('insomnia')
@@ -80,30 +95,59 @@ function validateInsomniaExport(data: any) {
       'Failed to parse Insomnia collection, please use export format v4.'
     )
   }
-}
 
-function setBaseUrl(env?: any) {
-  baseUrl = `${env?.scheme?.[0] ?? 'http'}://${env?.host}${env?.base_path}`
+  const env = data
+    .reverse()
+    .find(
+      (res: {
+        _type: string
+        data: { scheme: string; host: string; base_path: string }
+      }) =>
+        res._type === 'environment' &&
+        res.data?.scheme &&
+        res.data?.host &&
+        res.data?.base_path
+    )?.data
+
+  environmentVariables = env
+  baseUrl = env
+    ? `${env?.scheme?.[0] ?? 'http'}://${env?.host}${env?.base_path}`
+    : ''
+
+  return mapInsomniaToConfig(data)
 }
 
-function mapInsomniaToConfig(data: InsomniaResource[]): Config {
-  const insomniaRequests = data.filter(
-    ({ _type, url, body }) =>
+function mapInsomniaToConfig(data: unknown): Config {
+  const res = Joi.array()
+    .items(resourceValidator)
+    .validate(data, { allowUnknown: true }).value
+  const insomniaRequests = res.filter(
+    ({
+      _type,
+      url,
+      body,
+    }: {
+      _type: string
+      url: string
+      body: { mimeType: string }
+    }) =>
       _type === 'request' &&
       url &&
       // skip binary upload requests
       body?.mimeType !== 'application/octet-stream'
   )
-  const probes = insomniaRequests.map<Probe>((probe) =>
+
+  const probes = insomniaRequests.map((probe: unknown) =>
     mapInsomniaRequestToConfig(probe)
   )
 
   return { probes }
 }
 
-function mapInsomniaRequestToConfig(res: InsomniaResource): Probe {
+function mapInsomniaRequestToConfig(req: unknown): Probe {
+  const { value: res } = resourceValidator.validate(req, { allowUnknown: true })
   // eslint-disable-next-line camelcase
-  const url = compile(res.url)({ base_url: baseUrl })
+  const url = compileTemplate(res.url)({ base_url: baseUrl })
   const authorization = getAuthorizationHeader(res)
   let headers: AxiosRequestHeaders | undefined
   if (authorization)
@@ -135,7 +179,10 @@ function mapInsomniaRequestToConfig(res: InsomniaResource): Probe {
   }
 }
 
-function getAuthorizationHeader(res: InsomniaResource): string | undefined {
+function getAuthorizationHeader(data: unknown): string | undefined {
+  const { value: res } = resourceValidator.validate(data, {
+    allowUnknown: true,
+  })
   let authorization: string | undefined
   if (
     res.authentication?.type === 'bearer' &&
@@ -143,9 +190,9 @@ function getAuthorizationHeader(res: InsomniaResource): string | undefined {
   ) {
     let authTemplate = res.authentication?.token as string | undefined
     authTemplate = authTemplate?.replace('_.', '')
-    authorization = `${res.authentication?.prefix ?? 'bearer'} ${compile(
-      authTemplate
-    )(environmentVariables ?? {})}`
+    authorization = `${
+      res.authentication?.prefix ?? 'bearer'
+    } ${compileTemplate(authTemplate)(environmentVariables ?? {})}`
   }
 
   return authorization
diff --git a/src/components/config/parse-postman.ts b/src/components/config/parse-postman.ts
index 96c1425c..e54f7f56 100644
--- a/src/components/config/parse-postman.ts
+++ b/src/components/config/parse-postman.ts
@@ -22,11 +22,14 @@
  * SOFTWARE.                                                                      *
  **********************************************************************************/
 
+import Joi from 'joi'
 import type { Config } from '../../interfaces/config'
 
 type CollectionVersion = 'v2.0' | 'v2.1'
 
-const getCollectionVersion = (config: any) => {
+const getCollectionVersion = (
+  config: { info: { schema: string } } | undefined
+) => {
   if (config?.info?.schema?.includes('v2.0')) {
     return 'v2.0'
   }
@@ -59,20 +62,24 @@ const generateHeaderContentType = (mode: string, rawType?: string) => {
   }
 }
 
-const generateBody = (body: any, mode: string, rawType?: string) => {
+const generateBody = (
+  body: Record<string, string>[] | string,
+  mode: string | undefined,
+  rawType?: string
+) => {
   switch (mode) {
     case 'formdata':
     case 'urlencoded': {
       return {
-        body: body?.reduce(
-          (obj: any, it: any) => Object.assign(obj, { [it.key]: it.value }),
+        body: (body as Record<string, string>[])?.reduce(
+          (obj, it) => Object.assign(obj, { [it.key]: it.value }),
           {}
         ),
       }
     }
 
     case 'raw': {
-      if (rawType === 'json') return { body: JSON.parse(body) }
+      if (rawType === 'json') return { body: JSON.parse(body as string) }
       return { body }
     }
 
@@ -82,31 +89,65 @@ const generateBody = (body: any, mode: string, rawType?: string) => {
   }
 }
 
-const generateEachRequest = (request: any, version: CollectionVersion) => {
+const generateEachRequest = (
+  request:
+    | {
+        header?: Record<string, string>[]
+        body: {
+          mode: 'formdata' | 'raw'
+          formdata: Record<string, string>[] | undefined
+          raw: string | undefined
+          options: { raw: { language: string } }
+        }
+        url: { raw: string }
+        method: string
+      }
+    | undefined,
+  version: CollectionVersion
+) => {
   const mode = request?.body?.mode
-  const body = mode ? request?.body[mode] : {}
+  let body = mode ? request?.body?.[mode] : undefined
   const language = request?.body?.options?.raw?.language
+  body = body ? generateBody(body, mode, language).body : {}
 
   return {
     url: version === 'v2.0' ? request?.url : request?.url.raw,
     method: request?.method,
     headers: {
       ...request?.header?.reduce(
-        (obj: any, it: any) => Object.assign(obj, { [it.key]: it.value }),
+        (obj, it) => Object.assign(obj, { [it.key]: it.value }),
         {}
       ),
-      ...generateHeaderContentType(mode, language),
+      ...generateHeaderContentType(mode || '', language),
     },
     timeout: 10_000,
-    ...generateBody(body, mode, language),
+    body,
   }
 }
 
-const generateRequests = (item: any, version: CollectionVersion) => {
+type ItemExport = {
+  name: string
+  request:
+    | {
+        header?: Record<string, string>[]
+        body: {
+          mode: 'formdata' | 'raw'
+          formdata: Record<string, string>[] | undefined
+          raw: string | undefined
+          options: { raw: { language: string } }
+        }
+        url: { raw: string }
+        method: string
+      }
+    | undefined
+  item: ItemExport[] | undefined
+}
+
+const generateRequests = (item: ItemExport, version: CollectionVersion) => {
   const subitems = item?.item
 
-  if (subitems?.length > 0) {
-    return subitems?.map((subitem: any) =>
+  if ((subitems?.length || 0) > 0) {
+    return subitems?.map((subitem) =>
       generateEachRequest(subitem?.request, version)
     )
   }
@@ -114,8 +155,41 @@ const generateRequests = (item: any, version: CollectionVersion) => {
   return [generateEachRequest(item?.request, version)]
 }
 
-const generateProbesFromConfig = (config: any, version: CollectionVersion) => {
-  const probes = config?.item?.map((item: any) => ({
+const requestValidator = Joi.object({
+  header: Joi.array().items(Joi.object()),
+  body: Joi.object({
+    mode: Joi.string().allow('formdata', 'raw'),
+    formdata: Joi.object(),
+    raw: Joi.string(),
+    options: Joi.object({
+      raw: Joi.object({ language: Joi.string() }),
+    }),
+  }),
+  url: Joi.string(),
+  method: Joi.string(),
+})
+
+const postmanValidator = Joi.object({
+  name: Joi.string(),
+  request: requestValidator,
+  item: Joi.array().items(
+    Joi.object({
+      name: Joi.string(),
+      item: Joi.object({
+        request: requestValidator,
+      }),
+    })
+  ),
+})
+
+const generateProbesFromConfig = (
+  parseResult: unknown,
+  version: CollectionVersion
+) => {
+  const { value: config } = postmanValidator.validate(parseResult, {
+    allowUnknown: true,
+  })
+  const probes = config?.item?.map((item: ItemExport) => ({
     id: item?.name,
     name: item?.name,
     requests: generateRequests(item, version),
diff --git a/src/components/config/parse-sitemap.ts b/src/components/config/parse-sitemap.ts
index c6cbbb9a..6dd4da2f 100644
--- a/src/components/config/parse-sitemap.ts
+++ b/src/components/config/parse-sitemap.ts
@@ -27,41 +27,65 @@ import { XMLParser } from 'fast-xml-parser'
 import { monikaFlagsDefaultValue } from '../../flag'
 import type { MonikaFlags } from '../../flag'
 import type { Probe, ProbeAlert } from '../../interfaces/probe'
+import Joi from 'joi'
+import { RequestConfig } from 'src/interfaces/request'
 
-const generateProbesFromXml = (config: any) => {
-  const probes = config?.urlset?.url?.map((item: any) => {
-    const requests = [
-      {
-        url: item?.loc,
-        method: 'GET',
-        timeout: 10_000,
-      },
-    ]
-    if (item['xhtml:link']) {
-      for (const alt of item['xhtml:link']) {
-        requests.push({
-          url: alt['@_href'],
+const sitemapValidator = Joi.object({
+  config: Joi.object({
+    urlset: Joi.object({
+      url: Joi.array().items(
+        Joi.object({
+          loc: Joi.string(),
+          'xhtml:link': Joi.array().items(
+            Joi.object({ '@_href': Joi.string() })
+          ),
+        })
+      ),
+    }),
+  }),
+})
+
+const generateProbesFromXml = (parseResult: unknown) => {
+  const { value } = sitemapValidator.validate(parseResult, {
+    allowUnknown: true,
+  })
+  const probes = value?.urlset?.url?.map(
+    (item: { loc: string; 'xhtml:link': { '@_href': string }[] }) => {
+      const requests = [
+        {
+          url: item?.loc,
           method: 'GET',
           timeout: 10_000,
-        })
+        },
+      ]
+      if (item['xhtml:link']) {
+        for (const alt of item['xhtml:link']) {
+          requests.push({
+            url: alt['@_href'],
+            method: 'GET',
+            timeout: 10_000,
+          })
+        }
       }
-    }
 
-    return {
-      id: item?.loc,
-      name: item?.loc,
-      requests,
-      alerts: [],
+      return {
+        id: item?.loc,
+        name: item?.loc,
+        requests,
+        alerts: [],
+      }
     }
-  })
+  )
 
   return probes ?? []
 }
 
-const generateProbesFromXmlOneProbe = (config: any) => {
+const generateProbesFromXmlOneProbe = (parseResult: unknown) => {
   let probe: Probe | undefined
-  let requests: any = []
-
+  let requests: RequestConfig[] = []
+  const config = sitemapValidator.validate(parseResult, {
+    allowUnknown: true,
+  }).value
   const resources = config?.urlset?.url
   for (const [, item] of resources.entries()) {
     requests = [
@@ -70,6 +94,7 @@ const generateProbesFromXmlOneProbe = (config: any) => {
         url: item.loc,
         method: 'GET',
         timeout: 10_000,
+        body: '',
       },
     ]
     if (item['xhtml:link']) {
@@ -80,6 +105,7 @@ const generateProbesFromXmlOneProbe = (config: any) => {
             url: alt['@_href'],
             method: 'GET',
             timeout: 10_000,
+            body: '',
           },
         ]
       }
diff --git a/src/components/logger/history.ts b/src/components/logger/history.ts
index 97f5174c..d76b2471 100644
--- a/src/components/logger/history.ts
+++ b/src/components/logger/history.ts
@@ -23,7 +23,7 @@
  **********************************************************************************/
 
 import path from 'path'
-import SQLite3 from 'sqlite3'
+import SQLite3, { verbose as verboseSQLite } from 'sqlite3'
 import { open, Database, ISqlite } from 'sqlite'
 
 import { ProbeRequestResponse } from '../../interfaces/request'
@@ -32,7 +32,8 @@ import type { Notification } from '@hyperjumptech/monika-notification'
 import { log } from '../../utils/pino'
 import { getConfig } from '../config'
 import { getErrorMessage } from '../../utils/catch-error-handler'
-const sqlite3 = SQLite3.verbose()
+import { fileURLToPath } from 'url'
+const sqlite3 = verboseSQLite()
 const dbPath = path.resolve(process.cwd(), 'monika-logs.db')
 
 type RequestsLog = {
@@ -97,7 +98,6 @@ type ProbeRequestDB = {
   response_status: number
   request_url: string
   response_time: number
-  /* eslint-enable camelcase */
 }
 
 type UnreportedProbeRequestDB = {
@@ -108,7 +108,6 @@ type UnreportedProbeRequestDB = {
   response_status: number
   response_time: number
   timestamp: number
-  /* eslint-enable camelcase */
 }
 
 type UnreportedNotificationDB = {
@@ -121,7 +120,6 @@ type UnreportedNotificationDB = {
   type: string
   notification_id: string
   channel: string
-  /* eslint-enable camelcase */
 }
 
 let db: Database<SQLite3.Database, SQLite3.Statement>
@@ -138,7 +136,7 @@ export function setDatabase(
 
 async function migrate() {
   await database().migrate({
-    migrationsPath: path.join(__dirname, '../../../db/migrations'),
+    migrationsPath: path.dirname(fileURLToPath('../../../db/migrations')),
   })
 }
 
@@ -150,6 +148,7 @@ export async function openLogfile(): Promise<void> {
   try {
     const db = await open({
       filename: dbPath,
+      // eslint-disable-next-line no-bitwise
       mode: sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE,
       driver: sqlite3.Database,
     })
@@ -561,7 +560,7 @@ export async function getSummary(): Promise<Summary> {
   const config = getConfig()
 
   return {
-    numberOfProbes: config?.probes?.length ? config.probes.length : 0,
+    numberOfProbes: config?.probes?.length || 0,
     numberOfIncidents,
     numberOfRecoveries,
     numberOfSentNotifications,
diff --git a/src/components/notification/schedule-notification.ts b/src/components/notification/schedule-notification.ts
index 479a8524..63febba6 100644
--- a/src/components/notification/schedule-notification.ts
+++ b/src/components/notification/schedule-notification.ts
@@ -1,4 +1,4 @@
-import cron from 'node-cron'
+import { schedule as scheduleCron } from 'node-cron'
 import type { ScheduledTask } from 'node-cron'
 import type { MonikaFlags } from '../../flag'
 import type { Config } from '../../interfaces/config'
@@ -40,7 +40,7 @@ export function scheduleSummaryNotification({
     config['status-notification'] ||
     DEFAULT_SCHEDULE_CRON_EXPRESSION
 
-  const scheduledStatusUpdateTask = cron.schedule(
+  const scheduledStatusUpdateTask = scheduleCron(
     schedule,
     getSummaryAndSendNotif
   )
diff --git a/src/interfaces/data.ts b/src/interfaces/data.ts
index 024fc281..9e927ed1 100644
--- a/src/interfaces/data.ts
+++ b/src/interfaces/data.ts
@@ -2,5 +2,4 @@ export interface DBLimit {
   max_db_size: number
   deleted_data: number
   cron_schedule: string
-  /* eslint-enable camelcase */
 }


Test patch:
diff --git a/packages/notification/utils/authorization.test.ts b/packages/notification/utils/authorization.test.ts
index dc4b8eab..44f6f230 100644
--- a/packages/notification/utils/authorization.test.ts
+++ b/packages/notification/utils/authorization.test.ts
@@ -28,7 +28,8 @@ import * as auth from './authorization'
 describe('utils authorization tests', () => {
   it('should return basic authorization', async () => {
     chai.spy.on(auth, 'authBasic', () => Promise.resolve('basic token'))
-    const token = auth.authorize('basic', {
+    const token = auth.authorize({
+      type: 'basic',
       username: 'someusername',
       password: 'somepassword',
     })
@@ -39,7 +40,7 @@ describe('utils authorization tests', () => {
 
   it('should return bearer authorization', async () => {
     chai.spy.on(auth, 'authBearer', () => Promise.resolve('bearer token'))
-    const token = auth.authorize('bearer', 'token')
+    const token = auth.authorize({ type: 'bearer', token: 'token' })
 
     expect(auth.authBearer).to.have.been.called()
     expect(token).not.undefined
diff --git a/src/components/config/__tests__/expected.har.yml b/src/components/config/__tests__/expected.har.yml
index 2efb9b15..6b2aa4b6 100644
--- a/src/components/config/__tests__/expected.har.yml
+++ b/src/components/config/__tests__/expected.har.yml
@@ -1,5 +1,7 @@
 probes:
   - id: https://namb.ch/api/admin/login
+    name: https://namb.ch/api/admin/login
+    interval: 10
     requests:
       - method: POST
         url: https://namb.ch/api/admin/login
@@ -29,6 +31,7 @@ probes:
             _gat_gtag_UA_89898_8=1; _ga_AAAAA=GS1.1.1.26.1.1.0; _ga=1.1
         params: {}
         body: email=myemail&password=mypass
+    alerts: []
 notifications:
   - id: default
     type: desktop
diff --git a/src/components/config/__tests__/expected.sitemap-oneprobe.yml b/src/components/config/__tests__/expected.sitemap-oneprobe.yml
index 0f83164b..3cde2b3e 100644
--- a/src/components/config/__tests__/expected.sitemap-oneprobe.yml
+++ b/src/components/config/__tests__/expected.sitemap-oneprobe.yml
@@ -5,18 +5,23 @@ probes:
       - url: https://monika.hyperjump.tech/articles
         method: GET
         timeout: 10000
+        body: ''
       - url: https://de.wiktionary.org/wiki/hyperjump
         method: GET
         timeout: 10000
+        body: ''
       - url: https://id.wiktionary.org/wiki/hyperjump
         method: GET
         timeout: 10000
+        body: ''
       - url: https://en.wiktionary.org/wiki/hyperjump
         method: GET
         timeout: 10000
+        body: ''
       - url: https://monika.hyperjump.tech/index
         method: GET
         timeout: 10000
+        body: ''
     interval: 900
     alerts:
       - assertion: response.status < 200 or response.status > 299
diff --git a/src/components/config/__tests__/mock_files/expected.postman-basic.yml b/src/components/config/__tests__/mock_files/expected.postman-basic.yml
index 49169c28..f9a59de7 100644
--- a/src/components/config/__tests__/mock_files/expected.postman-basic.yml
+++ b/src/components/config/__tests__/mock_files/expected.postman-basic.yml
@@ -6,6 +6,7 @@ probes:
         method: GET
         headers: {}
         timeout: 10000
+        body: {}
     alerts: []
   - id: '[BODY-FORMDATA] Hyperjump GitHub'
     name: '[BODY-FORMDATA] Hyperjump GitHub'
diff --git a/src/components/config/__tests__/mock_files/expected.postman-grouped.yml b/src/components/config/__tests__/mock_files/expected.postman-grouped.yml
index fcec540d..d4102700 100644
--- a/src/components/config/__tests__/mock_files/expected.postman-grouped.yml
+++ b/src/components/config/__tests__/mock_files/expected.postman-grouped.yml
@@ -6,6 +6,7 @@ probes:
         method: GET
         headers: {}
         timeout: 10000
+        body: {}
       - url: https://api.github.com/users/hyperjumptech
         method: GET
         headers:
@@ -41,6 +42,7 @@ probes:
         method: GET
         headers: {}
         timeout: 10000
+        body: {}
       - url: https://api.github.com/users/hyperjumptech
         method: GET
         headers:
diff --git a/src/components/config/__tests__/parse-postman.test.ts b/src/components/config/__tests__/parse-postman.test.ts
index 4a267f50..1ff6f8cf 100644
--- a/src/components/config/__tests__/parse-postman.test.ts
+++ b/src/components/config/__tests__/parse-postman.test.ts
@@ -116,7 +116,7 @@ describe('parseConfigFromPostman', () => {
 
       expect(config.probes.length).to.equals(5)
 
-      for (const [index, item] of (basicCollectionV21 as any).item.entries()) {
+      for (const [index, item] of basicCollectionV21.item.entries()) {
         expect(item.name).to.equals(config.probes[index].name)
 
         for (const req of config.probes[index].requests || []) {
@@ -227,9 +227,7 @@ describe('parseConfigFromPostman', () => {
 
       expect(config.probes.length).to.equals(2)
 
-      for (const [index, item] of (
-        groupedCollectionV21 as any
-      ).item.entries()) {
+      for (const [index, item] of groupedCollectionV21.item.entries()) {
         expect(item.name).to.equals(config.probes[index].name)
 
         for (const [rIndex, req] of (