diff --git a/.env.example b/.env.example index 4afa7b0..cce6a76 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,3 @@ -SENDGRID_API_KEY=your-sendgrid-api-key +RESEND_API_KEY=your-resend-api-key FROM_EMAIL=governify.auditor@gmail.com PORT=6100 diff --git a/.github/workflows/dockerversion.yaml b/.github/workflows/dockerversion.yaml index 16a9ea5..ada6324 100644 --- a/.github/workflows/dockerversion.yaml +++ b/.github/workflows/dockerversion.yaml @@ -3,8 +3,6 @@ name: Create Release and Push to DockerHub on: push: branches: [ main, develop ] - pull_request: - branches: [ main, develop ] jobs: test: diff --git a/Dockerfile b/Dockerfile index ffe15bf..0cdad49 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,12 @@ FROM node:21-alpine - -COPY . . + +WORKDIR /app + +COPY package*.json ./ RUN npm install +COPY . . + ARG PORT=80 ENV PORT $PORT EXPOSE $PORT diff --git a/appConfig.js b/appConfig.js index f641c4f..1f086fb 100644 --- a/appConfig.js +++ b/appConfig.js @@ -4,5 +4,5 @@ dotenv.config(); export default { port: process.env.PORT || 6100, fromEmail: process.env.FROM_EMAIL, - sendgridApiKey: process.env.SENDGRID_API_KEY, + resendApiKey: process.env.RESEND_API_KEY, } diff --git a/index.js b/index.js index d8e2934..058f1d8 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,7 @@ import appConfig from "./appConfig.js"; dotenv.config(); const app = express(); -app.use(express.json()); +app.use(express.json({ limit: '50mb' })); // Load OpenAPI Specification const swaggerDocument = yaml.load("./api/oas-notification.yaml"); diff --git a/package-lock.json b/package-lock.json index 23b42c5..49ea9ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,13 +9,13 @@ "version": "0.1.0", "license": "ISC", "dependencies": { - "@sendgrid/mail": "^8.1.4", "axios": "^1.4.0", "dotenv": "^16.4.7", "express": "^4.18.2", "express-validator": "^7.2.1", "marked": "^4.3.0", "nodemon": "^3.1.9", + "resend": "^6.5.2", "slackify-markdown": "^4.4.0", "swagger-ui-express": "^5.0.1", "yamljs": "^0.3.0" @@ -28,43 +28,11 @@ "hasInstallScript": true, "license": "Apache-2.0" }, - "node_modules/@sendgrid/client": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-8.1.4.tgz", - "integrity": "sha512-VxZoQ82MpxmjSXLR3ZAE2OWxvQIW2k2G24UeRPr/SYX8HqWLV/8UBN15T2WmjjnEb5XSmFImTJOKDzzSeKr9YQ==", - "license": "MIT", - "dependencies": { - "@sendgrid/helpers": "^8.0.0", - "axios": "^1.7.4" - }, - "engines": { - "node": ">=12.*" - } - }, - "node_modules/@sendgrid/helpers": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-8.0.0.tgz", - "integrity": "sha512-Ze7WuW2Xzy5GT5WRx+yEv89fsg/pgy3T1E3FS0QEx0/VvRmigMZ5qyVGhJz4SxomegDkzXv/i0aFPpHKN8qdAA==", - "license": "MIT", - "dependencies": { - "deepmerge": "^4.2.2" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/@sendgrid/mail": { - "version": "8.1.4", - "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-8.1.4.tgz", - "integrity": "sha512-MUpIZykD9ARie8LElYCqbcBhGGMaA/E6I7fEcG7Hc2An26QJyLtwOaKQ3taGp8xO8BICPJrSKuYV4bDeAJKFGQ==", - "license": "MIT", - "dependencies": { - "@sendgrid/client": "^8.1.4", - "@sendgrid/helpers": "^8.0.0" - }, - "engines": { - "node": ">=12.*" - } + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" }, "node_modules/@types/mdast": { "version": "3.0.15", @@ -75,6 +43,15 @@ "@types/unist": "^2" } }, + "node_modules/@types/node": { + "version": "22.19.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.1.tgz", + "integrity": "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, "node_modules/@types/unist": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", @@ -378,15 +355,6 @@ "ms": "2.0.0" } }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -501,6 +469,12 @@ "node": ">= 0.4" } }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -593,6 +567,12 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -1592,6 +1572,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -1677,6 +1663,32 @@ "node": ">=0.10" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/resend": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/resend/-/resend-6.5.2.tgz", + "integrity": "sha512-Yl83UvS8sYsjgmF8dVbNPzlfpmb3DkLUk3VwsAbkaEFo9UMswpNuPGryHBXGk+Ta4uYMv5HmjVk3j9jmNkcEDg==", + "license": "MIT", + "dependencies": { + "svix": "1.76.1" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@react-email/render": "*" + }, + "peerDependenciesMeta": { + "@react-email/render": { + "optional": true + } + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1901,6 +1913,20 @@ "node": ">=4" } }, + "node_modules/svix": { + "version": "1.76.1", + "resolved": "https://registry.npmjs.org/svix/-/svix-1.76.1.tgz", + "integrity": "sha512-CRuDWBTgYfDnBLRaZdKp9VuoPcNUq9An14c/k+4YJ15Qc5Grvf66vp0jvTltd4t7OIRj+8lM1DAgvSgvf7hdLw==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "@types/node": "^22.7.5", + "es6-promise": "^4.2.8", + "fast-sha256": "^1.3.0", + "url-parse": "^1.5.10", + "uuid": "^10.0.0" + } + }, "node_modules/swagger-ui-dist": { "version": "5.20.1", "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.20.1.tgz", @@ -1984,6 +2010,12 @@ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "license": "MIT" }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, "node_modules/unified": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz", @@ -2076,6 +2108,16 @@ "node": ">= 0.8" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -2085,6 +2127,19 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/validator": { "version": "13.12.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", diff --git a/package.json b/package.json index 0e22cb5..17300ea 100644 --- a/package.json +++ b/package.json @@ -26,13 +26,13 @@ }, "homepage": "https://github.com/governify/notificator#readme", "dependencies": { - "@sendgrid/mail": "^8.1.4", "axios": "^1.4.0", "dotenv": "^16.4.7", "express": "^4.18.2", "express-validator": "^7.2.1", "marked": "^4.3.0", "nodemon": "^3.1.9", + "resend": "^6.5.2", "slackify-markdown": "^4.4.0", "swagger-ui-express": "^5.0.1", "yamljs": "^0.3.0" diff --git a/services/emailService.js b/services/emailService.js index ecfbba9..b0f1249 100644 --- a/services/emailService.js +++ b/services/emailService.js @@ -1,18 +1,23 @@ -import sgMail from "@sendgrid/mail"; +import { Resend } from 'resend'; import appConfig from "../appConfig.js"; -const SENDGRID_API_KEY = appConfig.sendgridApiKey; +const RESEND_API_KEY = appConfig.resendApiKey; const FROM = appConfig.fromEmail; -sgMail.setApiKey(SENDGRID_API_KEY); +const resend = new Resend(RESEND_API_KEY); export const sendEmail = async (to, subject, text, html) => { - const msg = { - to, - from: FROM, - subject, - text, - html, - }; - - await sgMail.send(msg); + const message = { + to: to, + from: FROM, + subject, + text, + html, + } + const { data, error } = await resend.emails.send(message); + if (error) { + return console.error({ error }); + } + console.log({ data }); }; + +