Merge branch 'develop' into feat/fe/infra-monitor-temp

This commit is contained in:
Alex Holliday
2024-11-26 11:38:45 +08:00
12 changed files with 604 additions and 40 deletions
+156 -21
View File
@@ -13,7 +13,7 @@
"@fontsource/roboto": "^5.0.13",
"@mui/icons-material": "^5.15.17",
"@mui/lab": "^5.0.0-alpha.170",
"@mui/material": "^5.16.7",
"@mui/material": "6.1.8",
"@mui/x-charts": "^7.5.1",
"@mui/x-data-grid": "7.22.3",
"@mui/x-date-pickers": "7.22.3",
@@ -1135,9 +1135,9 @@
}
},
"node_modules/@mui/core-downloads-tracker": {
"version": "5.16.7",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz",
"integrity": "sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==",
"version": "6.1.8",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.8.tgz",
"integrity": "sha512-TGAvzwUg9hybDacwfIGFjI2bXYXrIqky+vMfaeay8rvT56/PNAlvIDUJ54kpT5KRc9AWAihOvtDI7/LJOThOmQ==",
"license": "MIT",
"funding": {
"type": "opencollective",
@@ -1212,26 +1212,26 @@
}
},
"node_modules/@mui/material": {
"version": "5.16.7",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz",
"integrity": "sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg==",
"version": "6.1.8",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.8.tgz",
"integrity": "sha512-QZdQFnXct+7NXIzHgT3qt+sQiO7HYGZU2vymP9Xl9tUMXEOA/S1mZMMb7+WGZrk5TzNlU/kP/85K0da5V1jXoQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.9",
"@mui/core-downloads-tracker": "^5.16.7",
"@mui/system": "^5.16.7",
"@mui/types": "^7.2.15",
"@mui/utils": "^5.16.6",
"@babel/runtime": "^7.26.0",
"@mui/core-downloads-tracker": "^6.1.8",
"@mui/system": "^6.1.8",
"@mui/types": "^7.2.19",
"@mui/utils": "^6.1.8",
"@popperjs/core": "^2.11.8",
"@types/react-transition-group": "^4.4.10",
"clsx": "^2.1.0",
"@types/react-transition-group": "^4.4.11",
"clsx": "^2.1.1",
"csstype": "^3.1.3",
"prop-types": "^15.8.1",
"react-is": "^18.3.1",
"react-transition-group": "^4.4.5"
},
"engines": {
"node": ">=12.0.0"
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
@@ -1240,9 +1240,10 @@
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@types/react": "^17.0.0 || ^18.0.0",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
"@mui/material-pigment-css": "^6.1.8",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
@@ -1251,6 +1252,140 @@
"@emotion/styled": {
"optional": true
},
"@mui/material-pigment-css": {
"optional": true
},
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/material/node_modules/@mui/private-theming": {
"version": "6.1.8",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.8.tgz",
"integrity": "sha512-TuKl7msynCNCVvhX3c0ef1sF0Qb3VHcPs8XOGB/8bdOGBr/ynmIG1yTMjZeiFQXk8yN9fzK/FDEKMFxILNn3wg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.0",
"@mui/utils": "^6.1.8",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/material/node_modules/@mui/styled-engine": {
"version": "6.1.8",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.8.tgz",
"integrity": "sha512-ZvEoT0U2nPLSLI+B4by4cVjaZnPT2f20f4JUPkyHdwLv65ZzuoHiTlwyhqX1Ch63p8bcJzKTHQVGisEoMK6PGA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.0",
"@emotion/cache": "^11.13.1",
"@emotion/serialize": "^1.3.2",
"@emotion/sheet": "^1.4.0",
"csstype": "^3.1.3",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
}
}
},
"node_modules/@mui/material/node_modules/@mui/system": {
"version": "6.1.8",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.8.tgz",
"integrity": "sha512-i1kLfQoWxzFpXTBQIuPoA3xKnAnP3en4I2T8xIolovSolGQX5k8vGjw1JaydQS40td++cFsgCdEU458HDNTGUA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.0",
"@mui/private-theming": "^6.1.8",
"@mui/styled-engine": "^6.1.8",
"@mui/types": "^7.2.19",
"@mui/utils": "^6.1.8",
"clsx": "^2.1.1",
"csstype": "^3.1.3",
"prop-types": "^15.8.1"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
},
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/material/node_modules/@mui/utils": {
"version": "6.1.8",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.8.tgz",
"integrity": "sha512-O2DWb1kz8hiANVcR7Z4gOB3SvPPsSQGUmStpyBDzde6dJIfBzgV9PbEQOBZd3EBsd1pB+Uv1z5LAJAbymmawrA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.0",
"@mui/types": "^7.2.19",
"@types/prop-types": "^15.7.13",
"clsx": "^2.1.1",
"prop-types": "^15.8.1",
"react-is": "^18.3.1"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
@@ -2645,9 +2780,9 @@
}
},
"node_modules/axios": {
"version": "1.7.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"version": "1.7.8",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz",
"integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
+1 -1
View File
@@ -16,7 +16,7 @@
"@fontsource/roboto": "^5.0.13",
"@mui/icons-material": "^5.15.17",
"@mui/lab": "^5.0.0-alpha.170",
"@mui/material": "^5.16.7",
"@mui/material": "6.1.8",
"@mui/x-charts": "^7.5.1",
"@mui/x-data-grid": "7.22.3",
"@mui/x-date-pickers": "7.22.3",
+6
View File
@@ -41,6 +41,7 @@ import { logger } from "./Utils/Logger"; // Import the logger
import { networkService } from "./main";
import { Infrastructure } from "./Pages/Infrastructure";
import InfrastructureDetails from "./Pages/Infrastructure/Details";
import Test from "./Pages/test";
function App() {
const AdminCheckedRegister = withAdminCheck(Register);
const MonitorsWithAdminProp = withAdminProp(Monitors);
@@ -89,6 +90,11 @@ function App() {
path="/"
element={<HomeLayout />}
>
<Route
path="/test"
element={<Test />}
/>
<Route
exact
path="/"
+5 -1
View File
@@ -4,6 +4,10 @@
.field-infrastructure-alert{
max-width: var(--env-var-width-4);
}
.field-infrastructure-alert .MuiInputBase-root:has(input) {
/* height: var(--env-var-height-2); */
min-width: unset;
}
@@ -20,7 +24,7 @@
padding-right: var(--env-var-spacing-1-minus);
}
.field .MuiInputBase-root:has(input) {
height: var(--env-var-height-2);
/* height: var(--env-var-height-2); */
}
.field .MuiInputBase-root:has(.MuiInputAdornment-root) {
padding-right: var(--env-var-spacing-1-minus);
@@ -0,0 +1,60 @@
import { Stack, Typography, InputAdornment, IconButton } from "@mui/material";
import { useTheme } from "@mui/material/styles";
import { useState } from "react";
import PropTypes from "prop-types";
import VisibilityOff from "@mui/icons-material/VisibilityOff";
import Visibility from "@mui/icons-material/Visibility";
export const HttpAdornment = ({ https }) => {
const theme = useTheme();
return (
<Stack
direction="row"
alignItems="center"
height="100%"
sx={{
borderRight: `solid 1px ${theme.palette.border.dark}`,
backgroundColor: theme.palette.background.accent,
pl: theme.spacing(6),
}}
>
<Typography
component="h5"
paddingRight={"var(--env-var-spacing-1-minus)"}
color={theme.palette.text.secondary}
sx={{ lineHeight: 1, opacity: 0.8 }}
>
{https ? "https" : "http"}://
</Typography>
</Stack>
);
};
export const PasswordEndAdornment = ({ fieldType, setFieldType }) => {
const theme = useTheme();
return (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={() => setFieldType(fieldType === "password" ? "text" : "password")}
sx={{
color: theme.palette.border.dark,
padding: theme.spacing(1),
"&:focus-visible": {
outline: `2px solid ${theme.palette.primary.main}`,
outlineOffset: `2px`,
},
"& .MuiTouchRipple-root": {
pointerEvents: "none",
display: "none",
},
}}
>
{fieldType === "password" ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
);
};
HttpAdornment.propTypes = {
https: PropTypes.bool.isRequired,
};
@@ -0,0 +1,130 @@
import { Stack, TextField, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import { forwardRef, useState, cloneElement } from "react";
import PropTypes from "prop-types";
const getSx = (theme, type, maxWidth) => {
const sx = {
maxWidth: maxWidth,
};
if (type === "url") {
return {
...sx,
"& .MuiInputBase-root": { padding: 0 },
"& .MuiStack-root": {
borderTopLeftRadius: theme.shape.borderRadius,
borderBottomLeftRadius: theme.shape.borderRadius,
},
};
}
return sx;
};
const Required = () => {
const theme = useTheme();
return (
<Typography
component="span"
ml={theme.spacing(1)}
color={theme.palette.error.main}
>
*
</Typography>
);
};
const Optional = ({ optionalLabel }) => {
const theme = useTheme();
return (
<Typography
component="span"
fontSize="inherit"
fontWeight={400}
ml={theme.spacing(2)}
sx={{ opacity: 0.6 }}
>
{optionalLabel || "(optional)"}
</Typography>
);
};
Optional.propTypes = {
optionalLabel: PropTypes.string,
};
const TextInput = forwardRef(
(
{
type,
value,
placeholder,
isRequired,
isOptional,
optionalLabel,
onChange,
error = false,
helperText = null,
startAdornment = null,
endAdornment = null,
label = null,
maxWidth = "100%",
},
ref
) => {
const [fieldType, setFieldType] = useState(type);
const theme = useTheme();
return (
<Stack>
<Typography
component="h3"
fontSize={"var(--env-var-font-size-medium)"}
color={theme.palette.text.secondary}
fontWeight={500}
>
{label}
{isRequired && <Required />}
{isOptional && <Optional optionalLabel={optionalLabel} />}
</Typography>
<TextField
type={fieldType}
value={value}
placeholder={placeholder}
onChange={onChange}
error={error}
helperText={helperText}
inputRef={ref}
sx={getSx(theme, type, maxWidth)}
slotProps={{
input: {
startAdornment: startAdornment,
endAdornment: endAdornment
? cloneElement(endAdornment, { fieldType, setFieldType })
: null,
},
}}
/>
</Stack>
);
}
);
TextInput.displayName = "TextInput";
TextInput.propTypes = {
type: PropTypes.string,
value: PropTypes.string,
placeholder: PropTypes.string,
isRequired: PropTypes.bool,
isOptional: PropTypes.bool,
optionalLabel: PropTypes.string,
onChange: PropTypes.func,
error: PropTypes.bool,
helperText: PropTypes.string,
startAdornment: PropTypes.node,
endAdornment: PropTypes.node,
label: PropTypes.string,
maxWidth: PropTypes.string,
};
export default TextInput;
+3 -3
View File
@@ -348,14 +348,14 @@ const Settings = ({ isAdmin }) => {
<Typography component="h1">About</Typography>
</Box>
<Box>
<Typography component="h2">BlueWave Uptime {version}</Typography>
<Typography component="h2">Checkmate {version}</Typography>
<Typography sx={{ mt: theme.spacing(2), mb: theme.spacing(6), opacity: 0.6 }}>
Developed by Bluewave Labs.
</Typography>
<Link
level="secondary"
url="https://github.com/bluewave-labs/bluewave-uptime"
label="https://github.com/bluewave-labs/bluewave-uptime"
url="https://github.com/bluewave-labs/checkmate"
label="https://github.com/bluewave-labs/checkmate"
/>
</Box>
</ConfigBox>
+192
View File
@@ -0,0 +1,192 @@
import { Stack, Typography } from "@mui/material";
import Field from "../Components/Inputs/Field";
import TextInput from "../Components/Inputs/TextInput";
import { useState, useEffect, useRef } from "react";
import { HttpAdornment } from "../Components/Inputs/TextInput/Adornments";
import { PasswordEndAdornment } from "../Components/Inputs/TextInput/Adornments";
const Test = () => {
const [originalValue, setOriginalValue] = useState("");
const [originalError, setOriginalError] = useState("");
const [newValue, setNewValue] = useState("");
const [newError, setNewError] = useState("");
const [thresholdValue, setThresholdValue] = useState(20);
const [thresholdError, setThresholdError] = useState("");
const [thresholdValue2, setThresholdValue2] = useState(20);
const [thresholdError2, setThresholdError2] = useState("");
const inputRef = useRef(null);
useEffect(() => {
if (inputRef.current) {
inputRef.current.focus();
}
}, []);
const checkError = (value) => {
if (value !== "clear") {
return "This is an error";
}
return "";
};
const checkThresholdError = (value) => {
if (value !== 99) {
return "This is a threshold error";
}
return "";
};
const checkThresholdError2 = (value) => {
if (value !== 99) {
return "This is a threshold error 2";
}
return "";
};
const handleOriginalValue = (e) => {
setOriginalError(checkError(e.target.value));
setOriginalValue(e.target.value);
};
const handleNewValue = (e) => {
setNewError(checkError(e.target.value));
setNewValue(e.target.value);
};
const handleThresholdValue = (e) => {
const parsedVal = parseInt(e.target.value);
setThresholdError(checkThresholdError(parsedVal));
setThresholdValue(parsedVal);
};
const handleThresholdValue2 = (e) => {
const parsedVal = parseInt(e.target.value);
setThresholdError2(checkThresholdError2(parsedVal));
setThresholdValue2(parsedVal);
};
return (
<Stack
gap={8}
direction="column"
border="1px dashed blue"
padding="1rem"
>
<Typography>
This is a test page for the TextInput component. It is a rationalized Input
component.
</Typography>
<Typography>Type anything for an error.</Typography>
<Typography>Typing "clear" will clear the error for text based input</Typography>
<Typography>Typing "99" will clear the error for threshold based input</Typography>
<Field
id="original-field"
onChange={handleOriginalValue}
type="text"
value={originalValue}
error={originalError}
/>
<TextInput
value={newValue}
onChange={handleNewValue}
error={newError !== ""}
helperText={newError}
/>
<Field
type={"url"}
id="monitor-url"
label={"URL to monitor"}
https={true}
placeholder={""}
value={originalValue}
onChange={handleOriginalValue}
error={originalError}
/>
<TextInput
type={"url"}
id="monitor-url"
label={"URL to monitor"}
placeholder={""}
value={newValue}
startAdornment={<HttpAdornment https={true} />}
onChange={handleNewValue}
error={newError !== ""}
helperText={newError}
/>
<Field
type="password"
id="login-password-input"
label="Password"
isRequired={true}
placeholder="••••••••••"
autoComplete="current-password"
value={originalValue}
onChange={handleOriginalValue}
error={originalError}
ref={inputRef}
/>
<TextInput
type="password"
id="login-password-input"
label="Password"
isRequired={true}
placeholder="••••••••••"
autoComplete="current-password"
value={newValue}
endAdornment={<PasswordEndAdornment />}
onChange={handleNewValue}
error={newError !== ""}
helperText={newError}
ref={inputRef}
/>
<Field
id="ttl"
label="The days you want to keep monitoring history."
isOptional={true}
optionalLabel="0 for infinite"
value={originalValue}
onChange={handleOriginalValue}
error={originalError}
/>
<TextInput
id="ttl"
label="The days you want to keep monitoring history."
isOptional={true}
optionalLabel="0 for infinite"
value={newValue}
onChange={handleNewValue}
error={newError !== ""}
helperText={newError}
/>
<Typography>Short field for threshold. Easily show/hide error text</Typography>
<TextInput
maxWidth="var(--env-var-width-4)"
id="threshold"
type="number"
value={thresholdValue.toString()}
onChange={handleThresholdValue}
error={thresholdError !== ""}
/>
<TextInput
maxWidth="var(--env-var-width-4)"
id="threshold"
type="number"
value={thresholdValue2.toString()}
onChange={handleThresholdValue2}
error={thresholdError2 !== ""}
/>
<Typography sx={{ color: "red" }}>
{thresholdError} {thresholdError2}
</Typography>
</Stack>
);
};
export default Test;
+37
View File
@@ -209,6 +209,43 @@ const baseTheme = (palette) => ({
}),
},
},
MuiTextField: {
styleOverrides: {
root: ({ theme }) => ({
"& fieldset": {
borderColor: theme.palette.border.dark,
borderRadius: theme.shape.borderRadius,
},
"& .MuiInputBase-input": {
height: "var(--env-var-height-2)",
fontSize: "var(--env-var-font-size-medium)",
fontWeight: 400,
color: palette.text.secondary, // or any color from your palette
},
"& .MuiInputBase-input.MuiOutlinedInput-input": {
padding: "0 var(--env-var-spacing-1-minus) !important",
},
"& .MuiOutlinedInput-root": {
borderRadius: 4,
},
"& .MuiOutlinedInput-notchedOutline": {
borderRadius: 4,
},
"& .MuiFormHelperText-root": {
color: palette.error.main,
opacity: 0.8,
fontSize: "var(--env-var-font-size-medium)",
marginLeft: 0,
},
"& .MuiFormHelperText-root.Mui-error": {
opacity: 0.8,
fontSize: "var(--env-var-font-size-medium)",
color: palette.error.main,
},
}),
},
},
},
shape: {
borderRadius: 2,
+5 -5
View File
@@ -6,18 +6,18 @@
![](https://img.shields.io/github/issues-pr/bluewave-labs/bluewave-uptime)
![](https://img.shields.io/github/issues/bluewave-labs/bluewave-uptime)
<h1 align="center"><a href="https://bluewavelabs.ca" target="_blank">BlueWave Uptime</a></h1>
<h1 align="center"><a href="https://bluewavelabs.ca" target="_blank">Checkmate</a></h1>
<p align="center"><strong>An open source server monitoring application</strong></p>
![Dashboard-dark](https://github.com/user-attachments/assets/db875138-164f-453c-a75e-889f88747578)
(yes, we have a light theme as well, but this looks better on readme.md)
BlueWave Uptime is an open source server monitoring application used to track the operational status and performance of servers and websites. It regularly checks whether a server/website is accessible and performs optimally, providing real-time alerts and reports on the monitored services' availability, downtime, and response time.
Checkmate is an open source server monitoring application used to track the operational status and performance of servers and websites. It regularly checks whether a server/website is accessible and performs optimally, providing real-time alerts and reports on the monitored services' availability, downtime, and response time.
## Demo
See [BlueWave Uptime](https://uptime-demo.bluewavelabs.ca/) in action. The username is uptimedemo@demo.com and the password is Demouser1!
See [Checkmate](https://uptime-demo.bluewavelabs.ca/) in action. The username is uptimedemo@demo.com and the password is Demouser1!
## User's guide
@@ -25,7 +25,7 @@ Usage instructions can be found [here](https://bluewavelabs.gitbook.io/uptime-ma
## Installation
See installation instructions in [Uptime Manager documentation portal](https://bluewavelabs.gitbook.io/uptime-manager/quickstart).
See installation instructions in [Checkmate documentation portal](https://bluewavelabs.gitbook.io/uptime-manager/quickstart).
## Questions & ideas
@@ -44,7 +44,7 @@ We've just launched our [Discussions](https://github.com/bluewave-labs/bluewave-
**Roadmap (short term):**
We are actively developing **infrastructure monitoring** features for Uptime Manager, which will include comprehensive monitoring of memory, disk usage, and CPU performance. Our goal is to build a lightweight agent that runs on Linux servers, continuously collecting and transmitting health metrics to Uptime Manager, where the data will be visualized for real-time insights.
We are actively developing **infrastructure monitoring** features for Checkmate, which will include comprehensive monitoring of memory, disk usage, and CPU performance. Our goal is to build a lightweight agent that runs on Linux servers, continuously collecting and transmitting health metrics to Checkmate, where the data will be visualized for real-time insights.
Additionally, we will introduce **Docker monitoring** to track the performance and health of containerized environments.
+8 -8
View File
@@ -17,7 +17,7 @@
"dotenv": "^16.4.5",
"express": "^4.19.2",
"handlebars": "^4.7.8",
"helmet": "^7.1.0",
"helmet": "^8.0.0",
"joi": "^17.13.1",
"jsonwebtoken": "9.0.2",
"mailersend": "^2.2.0",
@@ -997,9 +997,9 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.7.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
"version": "1.7.8",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz",
"integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
@@ -2808,12 +2808,12 @@
}
},
"node_modules/helmet": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-7.2.0.tgz",
"integrity": "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==",
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-8.0.0.tgz",
"integrity": "sha512-VyusHLEIIO5mjQPUI1wpOAEu+wl6Q0998jzTxqUYGE45xCIcAxy3MsbEK/yyJUJ3ADeMoB6MornPH6GMWAf+Pw==",
"license": "MIT",
"engines": {
"node": ">=16.0.0"
"node": ">=18.0.0"
}
},
"node_modules/html-escaper": {
+1 -1
View File
@@ -20,7 +20,7 @@
"dotenv": "^16.4.5",
"express": "^4.19.2",
"handlebars": "^4.7.8",
"helmet": "^7.1.0",
"helmet": "^8.0.0",
"joi": "^17.13.1",
"jsonwebtoken": "9.0.2",
"mailersend": "^2.2.0",