feat: move from matrix to email notifs (#2)
Some checks failed
Node.js CI / Lint and Test (push) Successful in 56s
Code Analysis / SonarQube (push) Failing after 1m12s

### Explanation

_No response_

### Issue

_No response_

### Attestations

- [x] I have read and agree to the [Code of Conduct](https://docs.nhcarrigan.com/community/coc/)
- [x] I have read and agree to the [Community Guidelines](https://docs.nhcarrigan.com/community/guide/).
- [x] My contribution complies with the [Contributor Covenant](https://docs.nhcarrigan.com/dev/covenant/).

### Dependencies

- [x] I have pinned the dependencies to a specific patch version.

### Style

- [x] I have run the linter and resolved any errors.
- [x] My pull request uses an appropriate title, matching the conventional commit standards.
- [x] My scope of feat/fix/chore/etc. correctly matches the nature of changes in my pull request.

### Tests

- [ ] My contribution adds new code, and I have added tests to cover it.
- [ ] My contribution modifies existing code, and I have updated the tests to reflect these changes.
- [ ] All new and existing tests pass locally with my changes.
- [ ] Code coverage remains at or above the configured threshold.

### Documentation

_No response_

### Versioning

Minor - My pull request introduces a new non-breaking feature.

Reviewed-on: #2
Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com>
Co-committed-by: Naomi Carrigan <commits@nhcarrigan.com>
This commit is contained in:
Naomi Carrigan 2025-03-11 14:18:35 -07:00 committed by Naomi Carrigan
parent 11a3249bdb
commit 30bc85772f
6 changed files with 71 additions and 235 deletions

View File

@ -1,7 +1,7 @@
{
"name": "alert-server",
"version": "1.0.0",
"description": "A web server that sends alerts to our Matrix room.",
"description": "A web server that sends alerts to our logging inbox.",
"main": "index.js",
"type": "module",
"scripts": {
@ -17,11 +17,12 @@
"@nhcarrigan/eslint-config": "5.1.0",
"@nhcarrigan/typescript-config": "4.0.0",
"@types/node": "22.13.1",
"@types/nodemailer": "6.4.17",
"eslint": "9.20.0",
"typescript": "5.7.3"
},
"dependencies": {
"fastify": "5.2.1",
"matrix-js-sdk": "36.1.0"
"nodemailer": "6.10.0"
}
}

172
pnpm-lock.yaml generated
View File

@ -11,9 +11,9 @@ importers:
fastify:
specifier: 5.2.1
version: 5.2.1
matrix-js-sdk:
specifier: 36.1.0
version: 36.1.0
nodemailer:
specifier: 6.10.0
version: 6.10.0
devDependencies:
'@nhcarrigan/eslint-config':
specifier: 5.1.0
@ -24,6 +24,9 @@ importers:
'@types/node':
specifier: 22.13.1
version: 22.13.1
'@types/nodemailer':
specifier: 6.4.17
version: 6.4.17
eslint:
specifier: 9.20.0
version: 9.20.0
@ -41,10 +44,6 @@ packages:
resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
engines: {node: '>=6.9.0'}
'@babel/runtime@7.26.7':
resolution: {integrity: sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==}
engines: {node: '>=6.9.0'}
'@es-joy/jsdoccomment@0.49.0':
resolution: {integrity: sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==}
engines: {node: '>=16'}
@ -297,13 +296,6 @@ packages:
'@jridgewell/sourcemap-codec@1.5.0':
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
'@matrix-org/matrix-sdk-crypto-wasm@12.1.0':
resolution: {integrity: sha512-NhJFu/8FOGjnW7mDssRUzaMSwXrYOcCqgAjZyAw9KQ9unNADKEi7KoIKe7GtrG2PWtm36y2bUf+hB8vhSY6Wdw==}
engines: {node: '>= 18'}
'@matrix-org/olm@3.2.15':
resolution: {integrity: sha512-S7lOrndAK9/8qOtaTq/WhttJC/o4GAzdfK0MUPpo8ApzsJEC0QjtwrkC3KBXdFP1cD1MXi/mlKR7aaoVMKgs6Q==}
'@nhcarrigan/eslint-config@5.1.0':
resolution: {integrity: sha512-TS6kwPTcm8pFzp34FRq+8PR+0jgVr7FDUDrfilAKtWDArqZSabTMtTt+N1rJyNHQqBHs7de/pUYNWiLpThy2Bw==}
engines: {node: '>=22', pnpm: '>=9'}
@ -443,9 +435,6 @@ packages:
'@types/estree@1.0.6':
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
'@types/events@3.0.3':
resolution: {integrity: sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==}
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@ -455,12 +444,12 @@ packages:
'@types/node@22.13.1':
resolution: {integrity: sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew==}
'@types/nodemailer@6.4.17':
resolution: {integrity: sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==}
'@types/normalize-package-data@2.4.4':
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
'@types/retry@0.12.0':
resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==}
'@typescript-eslint/eslint-plugin@8.19.0':
resolution: {integrity: sha512-NggSaEZCdSrFddbctrVjkVZvFC6KGfKfNK0CU7mNK/iKHGKbzT4Wmgm08dKpcZECBu9f5FypndoMyRHkdqfT1Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -634,9 +623,6 @@ packages:
ajv@8.17.1:
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
another-json@0.2.0:
resolution: {integrity: sha512-/Ndrl68UQLhnCdsAzEXLMFuOR546o2qbYRqCglaNHbjXrwG1ayTcdwr3zkSGOGtGXDyR5X9nCFfnyG2AFJIsqg==}
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
@ -706,9 +692,6 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
base-x@5.0.0:
resolution: {integrity: sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ==}
brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
@ -724,9 +707,6 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
bs58@6.0.0:
resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==}
builtin-modules@3.3.0:
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
engines: {node: '>=6'}
@ -788,10 +768,6 @@ packages:
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
content-type@1.0.5:
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
engines: {node: '>= 0.6'}
cookie@1.0.2:
resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
engines: {node: '>=18'}
@ -1041,10 +1017,6 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
events@3.3.0:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
expect-type@1.1.0:
resolution: {integrity: sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==}
engines: {node: '>=12.0.0'}
@ -1395,10 +1367,6 @@ packages:
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
engines: {node: '>=4.0'}
jwt-decode@4.0.0:
resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==}
engines: {node: '>=18'}
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
@ -1423,10 +1391,6 @@ packages:
lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
loglevel@1.9.2:
resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
engines: {node: '>= 0.6.0'}
loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
@ -1441,16 +1405,6 @@ packages:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
matrix-events-sdk@0.0.1:
resolution: {integrity: sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==}
matrix-js-sdk@36.1.0:
resolution: {integrity: sha512-KNPswMSAGKDxBybJedxRpWadaRes9paxmjTCUsQT8t1Jg3ZENraAt6ynIaxh6PxazAH9D5ly6EYKHaLMLbZ1Dg==}
engines: {node: '>=20.0.0'}
matrix-widget-api@1.13.1:
resolution: {integrity: sha512-mkOHUVzaN018TCbObfGOSaMW2GoUxOfcxNNlTVx5/HeMk3OSQPQM0C9oEME5Liiv/dBUoSrEB64V8wF7e/gb1w==}
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@ -1487,6 +1441,10 @@ packages:
node-releases@2.0.19:
resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
nodemailer@6.10.0:
resolution: {integrity: sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==}
engines: {node: '>=6.0.0'}
normalize-package-data@2.5.0:
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
@ -1522,10 +1480,6 @@ packages:
resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}
engines: {node: '>= 0.4'}
oidc-client-ts@3.1.0:
resolution: {integrity: sha512-IDopEXjiwjkmJLYZo6BTlvwOtnlSniWZkKZoXforC/oLZHC9wkIxd25Kwtmo5yKFMMVcsp3JY6bhcNJqdYk8+g==}
engines: {node: '>=18'}
on-exit-leak-free@2.1.2:
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
engines: {node: '>=14.0.0'}
@ -1554,10 +1508,6 @@ packages:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
p-retry@4.6.2:
resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==}
engines: {node: '>=8'}
p-try@2.2.0:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
@ -1682,9 +1632,6 @@ packages:
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
engines: {node: '>= 0.4'}
regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
regexp-tree@0.1.27:
resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==}
hasBin: true
@ -1722,10 +1669,6 @@ packages:
resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==}
engines: {node: '>=10'}
retry@0.13.1:
resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
engines: {node: '>= 4'}
reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@ -1760,10 +1703,6 @@ packages:
resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
engines: {node: '>=10'}
sdp-transform@2.15.0:
resolution: {integrity: sha512-KrOH82c/W+GYQ0LHqtr3caRpM3ITglq3ljGUIb8LTki7ByacJZ9z+piSGiwZDsRyhQbYBOBJgr2k6X4BZXi3Kw==}
hasBin: true
secure-json-parse@3.0.2:
resolution: {integrity: sha512-H6nS2o8bWfpFEV6U38sOSjS7bTbdgbCGU9wEM6W14P5H0QOsz94KCusifV44GpHDTu2nqZbuDNhTzu+mjDSw1w==}
@ -1995,9 +1934,6 @@ packages:
undici-types@6.20.0:
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
unhomoglyph@1.0.6:
resolution: {integrity: sha512-7uvcWI3hWshSADBu4JpnyYbTVc7YlhF5GDW/oPD5AxIxl34k4wXR3WDkPnzLxkN32LiTCTKMQLtKVZiwki3zGg==}
update-browserslist-db@1.1.2:
resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==}
hasBin: true
@ -2007,10 +1943,6 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
uuid@11.0.5:
resolution: {integrity: sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==}
hasBin: true
validate-npm-package-license@3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
@ -2131,10 +2063,6 @@ snapshots:
'@babel/helper-validator-identifier@7.25.9': {}
'@babel/runtime@7.26.7':
dependencies:
regenerator-runtime: 0.14.1
'@es-joy/jsdoccomment@0.49.0':
dependencies:
comment-parser: 1.4.1
@ -2312,10 +2240,6 @@ snapshots:
'@jridgewell/sourcemap-codec@1.5.0': {}
'@matrix-org/matrix-sdk-crypto-wasm@12.1.0': {}
'@matrix-org/olm@3.2.15': {}
'@nhcarrigan/eslint-config@5.1.0(@typescript-eslint/utils@8.24.0(eslint@9.20.0)(typescript@5.7.3))(eslint@9.20.0)(playwright@1.50.1)(react@19.0.0)(typescript@5.7.3)(vitest@3.0.5(@types/node@22.13.1))':
dependencies:
'@eslint-community/eslint-plugin-eslint-comments': 4.4.1(eslint@9.20.0)
@ -2436,8 +2360,6 @@ snapshots:
'@types/estree@1.0.6': {}
'@types/events@3.0.3': {}
'@types/json-schema@7.0.15': {}
'@types/json5@0.0.29': {}
@ -2446,9 +2368,11 @@ snapshots:
dependencies:
undici-types: 6.20.0
'@types/normalize-package-data@2.4.4': {}
'@types/nodemailer@6.4.17':
dependencies:
'@types/node': 22.13.1
'@types/retry@0.12.0': {}
'@types/normalize-package-data@2.4.4': {}
'@typescript-eslint/eslint-plugin@8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.20.0)(typescript@5.7.3))(eslint@9.20.0)(typescript@5.7.3)':
dependencies:
@ -2682,8 +2606,6 @@ snapshots:
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
another-json@0.2.0: {}
ansi-styles@4.3.0:
dependencies:
color-convert: 2.0.1
@ -2775,8 +2697,6 @@ snapshots:
balanced-match@1.0.2: {}
base-x@5.0.0: {}
brace-expansion@1.1.11:
dependencies:
balanced-match: 1.0.2
@ -2797,10 +2717,6 @@ snapshots:
node-releases: 2.0.19
update-browserslist-db: 1.1.2(browserslist@4.24.4)
bs58@6.0.0:
dependencies:
base-x: 5.0.0
builtin-modules@3.3.0: {}
cac@6.7.14: {}
@ -2857,8 +2773,6 @@ snapshots:
concat-map@0.0.1: {}
content-type@1.0.5: {}
cookie@1.0.2: {}
core-js-compat@3.40.0:
@ -3275,8 +3189,6 @@ snapshots:
esutils@2.0.3: {}
events@3.3.0: {}
expect-type@1.1.0: {}
fast-decode-uri-component@1.0.1: {}
@ -3650,8 +3562,6 @@ snapshots:
object.assign: 4.1.7
object.values: 1.2.1
jwt-decode@4.0.0: {}
keyv@4.5.4:
dependencies:
json-buffer: 3.0.1
@ -3679,8 +3589,6 @@ snapshots:
lodash.merge@4.6.2: {}
loglevel@1.9.2: {}
loose-envify@1.4.0:
dependencies:
js-tokens: 4.0.0
@ -3693,31 +3601,6 @@ snapshots:
math-intrinsics@1.1.0: {}
matrix-events-sdk@0.0.1: {}
matrix-js-sdk@36.1.0:
dependencies:
'@babel/runtime': 7.26.7
'@matrix-org/matrix-sdk-crypto-wasm': 12.1.0
'@matrix-org/olm': 3.2.15
another-json: 0.2.0
bs58: 6.0.0
content-type: 1.0.5
jwt-decode: 4.0.0
loglevel: 1.9.2
matrix-events-sdk: 0.0.1
matrix-widget-api: 1.13.1
oidc-client-ts: 3.1.0
p-retry: 4.6.2
sdp-transform: 2.15.0
unhomoglyph: 1.0.6
uuid: 11.0.5
matrix-widget-api@1.13.1:
dependencies:
'@types/events': 3.0.3
events: 3.3.0
merge2@1.4.1: {}
micromatch@4.0.8:
@ -3745,6 +3628,8 @@ snapshots:
node-releases@2.0.19: {}
nodemailer@6.10.0: {}
normalize-package-data@2.5.0:
dependencies:
hosted-git-info: 2.8.9
@ -3793,10 +3678,6 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.1.1
oidc-client-ts@3.1.0:
dependencies:
jwt-decode: 4.0.0
on-exit-leak-free@2.1.2: {}
optionator@0.9.4:
@ -3830,11 +3711,6 @@ snapshots:
dependencies:
p-limit: 3.1.0
p-retry@4.6.2:
dependencies:
'@types/retry': 0.12.0
retry: 0.13.1
p-try@2.2.0: {}
parent-module@1.0.1:
@ -3955,8 +3831,6 @@ snapshots:
get-proto: 1.0.1
which-builtin-type: 1.2.1
regenerator-runtime@0.14.1: {}
regexp-tree@0.1.27: {}
regexp.prototype.flags@1.5.4:
@ -3992,8 +3866,6 @@ snapshots:
ret@0.5.0: {}
retry@0.13.1: {}
reusify@1.0.4: {}
rfdc@1.4.1: {}
@ -4052,8 +3924,6 @@ snapshots:
safe-stable-stringify@2.5.0: {}
sdp-transform@2.15.0: {}
secure-json-parse@3.0.2: {}
semver@5.7.2: {}
@ -4311,8 +4181,6 @@ snapshots:
undici-types@6.20.0: {}
unhomoglyph@1.0.6: {}
update-browserslist-db@1.1.2(browserslist@4.24.4):
dependencies:
browserslist: 4.24.4
@ -4323,8 +4191,6 @@ snapshots:
dependencies:
punycode: 2.3.1
uuid@11.0.5: {}
validate-npm-package-license@3.0.4:
dependencies:
spdx-correct: 3.2.0

View File

@ -1,3 +1,4 @@
MATRIX_ACCESS_TOKEN="op://Environment Variables - Naomi/Alert Server/matrix_access_token"
MATRIX_ROOM_ID="op://Environment Variables - Naomi/Alert Server/matrix_room_id"
API_AUTH="op://Environment Variables - Naomi/Alert Server/api_auth"
API_AUTH="op://Environment Variables - Naomi/Alert Server/api_auth"
EMAIL_PASSWORD="op://Environment Variables - Naomi/Alert Server/email_pass"

View File

@ -4,37 +4,6 @@
* @author Naomi Carrigan
*/
import { createClient } from "matrix-js-sdk";
import { instantiateServer } from "./server/serve.js";
import type { Logger } from "matrix-js-sdk/lib/logger.js";
const logger: Logger = {
debug: () => {
return null;
},
error: () => {
return null;
},
getChild: () => {
return logger;
},
info: () => {
return null;
},
trace: () => {
return null;
},
warn: () => {
return null;
},
};
const client = createClient({
accessToken: process.env.MATRIX_ACCESS_TOKEN ?? "",
baseUrl: "https://matrix.nhcarrigan.com",
logger: logger,
userId: "@alerts:matrix.nhcarrigan.com",
});
await client.startClient({ initialSyncLimit: 10 });
instantiateServer(client);
instantiateServer();

36
src/modules/sendMail.ts Normal file
View File

@ -0,0 +1,36 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import { createTransport } from "nodemailer";
// eslint-disable-next-line @typescript-eslint/naming-convention -- This is a type import.
import type SMTPTransport from "nodemailer/lib/smtp-transport/index.js";
/**
* Sends an email.
* @param subject - The subject of the email.
* @param body - The text content of the email.
*/
export const sendMail = async(subject: string, body: string): Promise<void> => {
const options: SMTPTransport["options"] = {
auth: {
pass: process.env.EMAIL_PASSWORD ?? "",
type: "login",
user: "noreply@nhcarrigan.com",
},
host: "mail.nhcarrigan.com",
port: 465,
secure: true,
};
const defaults: SMTPTransport["options"] = {
from: "noreply@nhcarrigan.com",
to: "logs@nhcarrigan.com",
};
const transport = createTransport(options, defaults);
await transport.sendMail({
subject: subject,
text: body,
});
};

View File

@ -5,8 +5,8 @@
*/
import fastify from "fastify";
import { MsgType, type MatrixClient } from "matrix-js-sdk";
import { auth } from "../modules/auth.js";
import { sendMail } from "../modules/sendMail.js";
import { errorSchema } from "../schemas/errorSchema.js";
import { logSchema } from "../schemas/logSchema.js";
import { uptimeSchema } from "../schemas/uptimeSchema.js";
@ -20,14 +20,14 @@ const html = `<!DOCTYPE html>
<title>Rosalia Nightsong</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="A basic web server and Matrix bot that allows us to pipe logs and errors from our applications into a Matrix room." />
<meta name="description" content="A basic web server that allows us to pipe logs and errors from our applications into our inbox." />
<script src="https://cdn.nhcarrigan.com/headers/index.js" async defer></script>
</head>
<body>
<main>
<h1>Rosalia Nightsong</h1>
<section>
<p>A basic web server and Matrix bot that allows us to pipe logs and errors from our applications into a Matrix room.</p>
<p>A basic web server that allows us to pipe logs and errors from our applications into our inbox.</p>
</section>
<section>
<h2>Links</h2>
@ -53,10 +53,9 @@ const html = `<!DOCTYPE html>
/**
* Starts up the server to receive events.
* @param client - The authenticated Matrix client.
*/
// eslint-disable-next-line max-lines-per-function -- This function is long because it is setting up a server.
export const instantiateServer = (client: MatrixClient): void => {
export const instantiateServer = (): void => {
try {
const server = fastify({
logger: false,
@ -74,13 +73,7 @@ export const instantiateServer = (client: MatrixClient): void => {
return;
}
const { application, level, message } = request.body;
await client.sendMessage(process.env.MATRIX_ROOM_ID ?? "", {
body: `**${application}** - *${level}*\n${message}`,
format: "org.matrix.custom.html",
// eslint-disable-next-line @typescript-eslint/naming-convention -- Requirement of the SDK.
formatted_body: `<strong>${application}</strong> - <em>${level}</em><br>${message}`,
msgtype: MsgType.Text,
});
await sendMail(`[${level}]: ${application}`, message);
await response.status(200).send({ success: true });
});
@ -94,13 +87,7 @@ export const instantiateServer = (client: MatrixClient): void => {
return;
}
const { application, context, stack, message } = request.body;
await client.sendMessage(process.env.MATRIX_ROOM_ID ?? "", {
body: `**${application}** - *Error in ${context}*\n${message}\n\`\`\`\n${stack}\n\`\`\``,
format: "org.matrix.custom.html",
// eslint-disable-next-line @typescript-eslint/naming-convention -- Requirement of the SDK.
formatted_body: `<strong>${application}</strong> - <em>Error in ${context}</em><br>${message}<br><code>${stack}</code>`,
msgtype: MsgType.Text,
});
await sendMail(`[ERROR]: ${context} - ${application}`, `${message}\n\n${stack}`);
await response.status(200).send({ success: true });
},
);
@ -115,13 +102,7 @@ export const instantiateServer = (client: MatrixClient): void => {
return;
}
const { application, message } = request.body;
await client.sendMessage(process.env.MATRIX_ROOM_ID ?? "", {
body: `${message}\n${application}`,
format: "org.matrix.custom.html",
// eslint-disable-next-line @typescript-eslint/naming-convention -- Requirement of the SDK.
formatted_body: `${message}<br><sub>${application}</sub>`,
msgtype: MsgType.Text,
});
await sendMail(`[UPTIME]: ${application}`, message);
await response.status(200).send({ success: true });
},
);
@ -131,36 +112,18 @@ export const instantiateServer = (client: MatrixClient): void => {
if (error) {
const { message, stack } = error;
const context = "Server Startup";
void client.sendMessage(process.env.MATRIX_ROOM_ID ?? "", {
body: `**${application}** - *Error in ${context}*\n${message}\n\`\`\`\n${stack ?? "No stack trace available."}\n\`\`\``,
format: "org.matrix.custom.html",
// eslint-disable-next-line @typescript-eslint/naming-convention -- Requirement of the SDK.
formatted_body: `<strong>${application}</strong> - <em>Error in ${context}</em><br>${message}<br><code>${stack ?? "No stack trace available."}</code>`,
msgtype: MsgType.Text,
});
void sendMail(`[ERROR]: ${context} - ${application}`, `${message}\n\n${String(stack)}`);
return;
}
const level = "debug";
const message = `Server listening on port 5003.`;
void client.sendMessage(process.env.MATRIX_ROOM_ID ?? "", {
body: `**${application}** - *${level}*\n${message}`,
format: "org.matrix.custom.html",
// eslint-disable-next-line @typescript-eslint/naming-convention -- Requirement of the SDK.
formatted_body: `<strong>${application}</strong> - <em>${level}</em><br>${message}`,
msgtype: MsgType.Text,
});
void sendMail(`[${level}]: ${application}`, message);
});
} catch (error) {
const application = "Alert Server";
const context = "Server Startup";
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Totally being lazy.
const { message, stack } = error as Error;
void client.sendMessage(process.env.MATRIX_ROOM_ID ?? "", {
body: `**${application}** - *Error in ${context}*\n${message}\n\`\`\`\n${stack}\n\`\`\``,
format: "org.matrix.custom.html",
// eslint-disable-next-line @typescript-eslint/naming-convention -- Requirement of the SDK.
formatted_body: `<strong>${application}</strong> - <em>Error in ${context}</em><br>${message}<br><code>${stack}</code>`,
msgtype: MsgType.Text,
});
void sendMail(`[ERROR]: ${context} - ${application}`, `${message}\n\n${stack}`);
}
};