From 3f6fe99ea5128ac0162e92dd1e8c889fd5be19e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Fern=C3=A1ndez=20Castillo?= <100673872+JaviFdez7@users.noreply.github.com> Date: Mon, 13 Oct 2025 18:17:49 +0200 Subject: [PATCH 1/6] fix: Remove pull_request trigger from Docker release workflow --- .github/workflows/dockerversion.yaml | 2 -- 1 file changed, 2 deletions(-) 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: From 14645a03f714d67e20ab52c793554cb6b5f6e28d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Fern=C3=A1ndez=20Castillo?= <100673872+JaviFdez7@users.noreply.github.com> Date: Mon, 13 Oct 2025 18:34:31 +0200 Subject: [PATCH 2/6] refactor: Rearrange Dockerfile instructions for improved clarity and structure --- Dockerfile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 From 33976619474d8fc89c970447c0b9c64367a76458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Fern=C3=A1ndez=20Castillo?= <100673872+JaviFdez7@users.noreply.github.com> Date: Mon, 13 Oct 2025 18:58:50 +0200 Subject: [PATCH 3/6] fix: Update PORT configuration to 6200 --- .env.example | 2 +- README.md | 2 +- api/oas-notification.yaml | 2 +- appConfig.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 4afa7b0..93292d0 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,3 @@ SENDGRID_API_KEY=your-sendgrid-api-key FROM_EMAIL=governify.auditor@gmail.com -PORT=6100 +PORT=6200 diff --git a/README.md b/README.md index e74c913..5004bd7 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ The API is documented using the OpenAPI 3.0 specification. The documentation can npm run dev ``` -6. Access the API docs at `http://localhost:6100/api-docs`. +6. Access the API docs at `http://localhost:6200/api-docs`. ## Response Format diff --git a/api/oas-notification.yaml b/api/oas-notification.yaml index 425b6ae..952e4d3 100644 --- a/api/oas-notification.yaml +++ b/api/oas-notification.yaml @@ -4,7 +4,7 @@ info: description: API for sending notifications via email, Slack, and other services. version: 1.0.0 servers: - - url: http://localhost:6100/api/v1 + - url: http://localhost:6200/api/v1 description: Local server - url: https://notificator.bluejay.governify.io/api/v1 description: Production server diff --git a/appConfig.js b/appConfig.js index f641c4f..00e5c0a 100644 --- a/appConfig.js +++ b/appConfig.js @@ -2,7 +2,7 @@ import dotenv from 'dotenv'; dotenv.config(); export default { - port: process.env.PORT || 6100, + port: process.env.PORT || 6200, fromEmail: process.env.FROM_EMAIL, sendgridApiKey: process.env.SENDGRID_API_KEY, } From 2a2132a0c01bdeccb0bd0f198ad2d5614bc5905d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Fern=C3=A1ndez=20Castillo?= <100673872+JaviFdez7@users.noreply.github.com> Date: Mon, 13 Oct 2025 19:21:26 +0200 Subject: [PATCH 4/6] fix: Update PORT configuration from 6200 to 6100 --- .env.example | 2 +- README.md | 2 +- api/oas-notification.yaml | 2 +- appConfig.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 93292d0..4afa7b0 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,3 @@ SENDGRID_API_KEY=your-sendgrid-api-key FROM_EMAIL=governify.auditor@gmail.com -PORT=6200 +PORT=6100 diff --git a/README.md b/README.md index 5004bd7..e74c913 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ The API is documented using the OpenAPI 3.0 specification. The documentation can npm run dev ``` -6. Access the API docs at `http://localhost:6200/api-docs`. +6. Access the API docs at `http://localhost:6100/api-docs`. ## Response Format diff --git a/api/oas-notification.yaml b/api/oas-notification.yaml index 952e4d3..425b6ae 100644 --- a/api/oas-notification.yaml +++ b/api/oas-notification.yaml @@ -4,7 +4,7 @@ info: description: API for sending notifications via email, Slack, and other services. version: 1.0.0 servers: - - url: http://localhost:6200/api/v1 + - url: http://localhost:6100/api/v1 description: Local server - url: https://notificator.bluejay.governify.io/api/v1 description: Production server diff --git a/appConfig.js b/appConfig.js index 00e5c0a..f641c4f 100644 --- a/appConfig.js +++ b/appConfig.js @@ -2,7 +2,7 @@ import dotenv from 'dotenv'; dotenv.config(); export default { - port: process.env.PORT || 6200, + port: process.env.PORT || 6100, fromEmail: process.env.FROM_EMAIL, sendgridApiKey: process.env.SENDGRID_API_KEY, } From bcac7cbc61b101d65103c149ad41488f274126e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Fern=C3=A1ndez=20Castillo?= <100673872+JaviFdez7@users.noreply.github.com> Date: Thu, 16 Oct 2025 00:09:45 +0200 Subject: [PATCH 5/6] fix: Increase JSON payload limit to 50mb --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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"); From 682171a877e009accdf412a9be5dbb4af03c7ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Fern=C3=A1ndez=20Castillo?= <100673872+JaviFdez7@users.noreply.github.com> Date: Fri, 21 Nov 2025 17:58:18 +0100 Subject: [PATCH 6/6] refactor: Replace SendGrid with Resend for email service --- .env.example | 2 +- appConfig.js | 2 +- package-lock.json | 149 +++++++++++++++++++++++++++------------ package.json | 2 +- services/emailService.js | 29 ++++---- 5 files changed, 122 insertions(+), 62 deletions(-) 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/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/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 }); }; + +