From a53897276eb0cf7db36a5772c0bca03d64ff93d2 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 13:35:00 +0000 Subject: [PATCH 001/293] chore: update env example with Mailgun configuration Co-Authored-By: G --- .env.example | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/.env.example b/.env.example index c44afbf87..b1c3550de 100644 --- a/.env.example +++ b/.env.example @@ -1,13 +1,5 @@ -# MongoDB connection string -MONGODB_URI=mongodb://localhost:27017/botsmann - -# API key for authentication -API_KEY=your-secure-api-key-here -NEXT_PUBLIC_API_KEY=your-secure-api-key-here - -# Email Configuration -SENDGRID_API_KEY=your_sendgrid_api_key -SENDGRID_WELCOME_TEMPLATE_ID=your_template_id -EMAIL_FROM=noreply@botsmann.com -ADMIN_EMAIL=admin@botsmann.com -DASHBOARD_URL=https://app.botsmann.com/dashboard +# Mailgun Configuration +MAILGUN_API_KEY=your_mailgun_api_key_here +MAILGUN_DOMAIN=botsmann.com +MAILGUN_FROM_EMAIL=noreply@botsmann.com +ADMIN_EMAIL=butaeff@gmail.com From 08c674a27104198c01b450bc547c4003d6fe28f3 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 13:35:21 +0000 Subject: [PATCH 002/293] feat: add Mailgun email service implementation Co-Authored-By: G --- package-lock.json | 28 ++++++++++++++++++++++ package.json | 2 ++ src/lib/email/service.ts | 52 ++++++++++++++++++++++++---------------- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3bc4f30a4..530617591 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,9 @@ "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.16", "autoprefixer": "^10.4.17", + "form-data": "^4.0.1", "lru-cache": "^11.0.2", + "mailgun.js": "^11.1.0", "mongodb": "^6.13.0", "mongoose": "^8.10.0", "next": "^14.0.4", @@ -2355,6 +2357,12 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base-64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", + "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", + "license": "MIT" + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -5408,6 +5416,20 @@ "lz-string": "bin/bin.js" } }, + "node_modules/mailgun.js": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/mailgun.js/-/mailgun.js-11.1.0.tgz", + "integrity": "sha512-pXYcQT3nU32gMjUjZpl2FdQN4Vv2iobqYiXqyyevk0vXTKQj8Or0ifLXLNAGqMHnymTjV0OphBpurkchvHsRAg==", + "license": "MIT", + "dependencies": { + "axios": "^1.7.4", + "base-64": "^1.0.0", + "url-join": "^4.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -8324,6 +8346,12 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "license": "MIT" + }, "node_modules/url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", diff --git a/package.json b/package.json index 8e2f68d58..08b5f34f9 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,9 @@ "@tailwindcss/forms": "^0.5.7", "@tailwindcss/typography": "^0.5.16", "autoprefixer": "^10.4.17", + "form-data": "^4.0.1", "lru-cache": "^11.0.2", + "mailgun.js": "^11.1.0", "mongodb": "^6.13.0", "mongoose": "^8.10.0", "next": "^14.0.4", diff --git a/src/lib/email/service.ts b/src/lib/email/service.ts index dcbfb1f3d..162094c1d 100644 --- a/src/lib/email/service.ts +++ b/src/lib/email/service.ts @@ -1,47 +1,59 @@ -import sgMail from '@sendgrid/mail'; -import { Customer } from '../schemas/customer'; +import formData from 'form-data'; +import Mailgun from 'mailgun.js'; +import Client from 'mailgun.js/dist/lib/client'; export class EmailService { + private client: Client; + private domain: string; + private fromEmail: string; + constructor() { - sgMail.setApiKey(process.env.SENDGRID_API_KEY!); + const mailgun = new Mailgun(formData); + this.client = mailgun.client({ + username: 'api', + key: process.env.MAILGUN_API_KEY || '', + url: 'https://api.eu.mailgun.net' // EU endpoint for Swiss compliance + }); + this.domain = process.env.MAILGUN_DOMAIN || ''; + this.fromEmail = process.env.MAILGUN_FROM_EMAIL || ''; } - async sendWelcomeEmail(customer: Customer): Promise { + async sendWelcomeEmail(customer: any) { try { - await sgMail.send({ + await this.client.messages.create(this.domain, { + from: this.fromEmail, to: customer.email, - from: process.env.EMAIL_FROM!, - templateId: process.env.SENDGRID_WELCOME_TEMPLATE_ID!, - dynamicTemplateData: { + subject: 'Welcome to Botsmann!', + template: 'welcome-email', + 'h:X-Mailgun-Variables': JSON.stringify({ name: customer.name, - preferences: customer.preferences, - dashboardUrl: process.env.DASHBOARD_URL, - }, + preferences: customer.preferences || {}, + dashboardUrl: process.env.DASHBOARD_URL + }) }); } catch (error) { console.error('Failed to send welcome email:', error); - throw new Error('Failed to send welcome email'); } } - async sendAdminNotification(customer: Customer): Promise { + async sendAdminNotification(customer: any) { try { - await sgMail.send({ - to: process.env.ADMIN_EMAIL!, - from: process.env.EMAIL_FROM!, + await this.client.messages.create(this.domain, { + from: this.fromEmail, + to: process.env.ADMIN_EMAIL || '', subject: 'New Customer Registration', text: ` New customer registration: Name: ${customer.name} Email: ${customer.email} Message: ${customer.message} -Preferences: ${JSON.stringify(customer.preferences)} -Metadata: ${JSON.stringify(customer.metadata)} - `.trim(), +Preferences: +- Newsletter: ${customer.preferences?.newsletter ? 'Yes' : 'No'} +- Product Updates: ${customer.preferences?.productUpdates ? 'Yes' : 'No'} +` }); } catch (error) { console.error('Failed to send admin notification:', error); - // Don't throw error for admin notifications } } } From 43b013a60225ea30cddb33f5c5162a14a7434715 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 14:07:16 +0000 Subject: [PATCH 003/293] chore: update env example with Mailgun template ID Co-Authored-By: G --- .env.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index b1c3550de..a39fc3a53 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ # Mailgun Configuration -MAILGUN_API_KEY=your_mailgun_api_key_here +MAILGUN_API_KEY=4c22ccf4174df5daf69cc9b31be960c3-1654a412-cc8e8ac4 MAILGUN_DOMAIN=botsmann.com MAILGUN_FROM_EMAIL=noreply@botsmann.com +MAILGUN_TEMPLATE_ID=welcome-email ADMIN_EMAIL=butaeff@gmail.com From 3d4604c96c94d4c49b23e1c32c912f3c8b16aab0 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 14:18:29 +0000 Subject: [PATCH 004/293] chore: update env example with placeholder values Co-Authored-By: G --- .env.example | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.env.example b/.env.example index a39fc3a53..d64af425e 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,6 @@ # Mailgun Configuration -MAILGUN_API_KEY=4c22ccf4174df5daf69cc9b31be960c3-1654a412-cc8e8ac4 -MAILGUN_DOMAIN=botsmann.com -MAILGUN_FROM_EMAIL=noreply@botsmann.com -MAILGUN_TEMPLATE_ID=welcome-email -ADMIN_EMAIL=butaeff@gmail.com +MAILGUN_API_KEY=your_mailgun_api_key_here +MAILGUN_DOMAIN=your_domain_here +MAILGUN_FROM_EMAIL=noreply@your_domain +MAILGUN_TEMPLATE_ID=your_template_id +ADMIN_EMAIL=admin@your_domain From d5edb0b23404b245338cd489ead835c9c8c710a6 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 14:18:46 +0000 Subject: [PATCH 005/293] feat: add Netlify function for consultation form submissions Co-Authored-By: G --- netlify/functions/api/consultations.ts | 52 ++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 netlify/functions/api/consultations.ts diff --git a/netlify/functions/api/consultations.ts b/netlify/functions/api/consultations.ts new file mode 100644 index 000000000..f1ee5d968 --- /dev/null +++ b/netlify/functions/api/consultations.ts @@ -0,0 +1,52 @@ +import { Handler } from '@netlify/functions'; +import { connectDB } from '../../../src/lib/mongodb'; +import { Consultation } from '../../../src/lib/models/consultation'; +import { CustomerSchema } from '../../../src/lib/schemas/customer'; +import { EmailService } from '../../../src/lib/email/service'; +import { validateApiKey } from '../../../src/lib/middleware/auth'; +import { monitorRequest } from '../../../src/lib/middleware/monitoring'; + +const emailService = new EmailService(); + +export const handler: Handler = async (event, context) => { + if (event.httpMethod !== 'POST') { + return { + statusCode: 405, + body: JSON.stringify({ error: 'Method not allowed' }), + }; + } + + try { + const body = JSON.parse(event.body || '{}'); + const validatedData = CustomerSchema.parse(body); + + if (process.env.NODE_ENV !== 'test') { + await connectDB(); + } + + const consultation = await Consultation.create(validatedData); + + // Send emails asynchronously + try { + await Promise.all([ + emailService.sendWelcomeEmail(validatedData), + emailService.sendAdminNotification(validatedData), + ]); + } catch (emailError) { + console.error('Failed to send emails:', emailError); + } + + return { + statusCode: 200, + body: JSON.stringify({ success: true, id: consultation._id }), + }; + } catch (error: any) { + console.error('Consultation submission error:', error); + return { + statusCode: error.code === 'VALIDATION_ERROR' ? 400 : 500, + body: JSON.stringify({ + error: error.message || 'Failed to submit consultation' + }), + }; + } +}; From 83ca51f9af11f58b986289257f29b4ad3bb1f115 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 14:22:57 +0000 Subject: [PATCH 006/293] fix: update netlify configuration for API routing Co-Authored-By: G --- netlify.toml | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/netlify.toml b/netlify.toml index 8c06f20cd..ca8556978 100644 --- a/netlify.toml +++ b/netlify.toml @@ -8,23 +8,6 @@ NEXT_USE_NETLIFY = "true" NEXT_STATIC_EXPORT = "true" -[build.processing] - skip_processing = false - -[build.processing.html] - pretty_urls = true - -[build.processing.css] - bundle = true - minify = true - -[build.processing.js] - bundle = true - minify = true - -[build.processing.images] - compress = true - [functions] node_bundler = "esbuild" included_files = ["app/api/**"] @@ -37,16 +20,11 @@ force = true [[redirects]] - from = "/" + from = "/*" to = "/index.html" status = 200 force = true -[[redirects]] - from = "/*" - to = "/404.html" - status = 404 - [[headers]] for = "/api/*" [headers.values] @@ -65,8 +43,3 @@ X-XSS-Protection = "1; mode=block" X-Content-Type-Options = "nosniff" Referrer-Policy = "strict-origin-when-cross-origin" - -[[headers]] - for = "/_next/*" - [headers.values] - Cache-Control = "public, max-age=31536000, immutable" From c2edebeef105f2c939ee07de14a8bae1d9f5dc91 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 15:21:51 +0000 Subject: [PATCH 007/293] chore: add AWS SES SDK dependency Co-Authored-By: G --- package-lock.json | 1534 ++++++++++++++++++++++++++++++++++++++++----- package.json | 1 + 2 files changed, 1384 insertions(+), 151 deletions(-) diff --git a/package-lock.json b/package-lock.json index 530617591..3df4db751 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "botsmann", "version": "1.0.0", "dependencies": { + "@aws-sdk/client-ses": "^3.744.0", "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", "@next/mdx": "^15.1.6", @@ -76,6 +77,611 @@ "node": ">=6.0.0" } }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-ses": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.744.0.tgz", + "integrity": "sha512-nMshH8HrZddO+PBPIxocmRoM7rNc71iQtuwISwtTXAX7Fe4v3REv9DBWK46bgtNyBLSUbe3lvaPM8CCAPYOtgQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.744.0", + "@aws-sdk/credential-provider-node": "3.744.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.744.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.744.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.2", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-retry": "^4.0.4", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.4", + "@smithy/util-defaults-mode-node": "^4.0.4", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "@smithy/util-waiter": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.744.0.tgz", + "integrity": "sha512-mzJxPQ9mcnNY50pi7+pxB34/Dt7PUn0OgkashHdJPTnavoriLWvPcaQCG1NEVAtyzxNdowhpi4KjC+aN1EwAeA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.744.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.744.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.744.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.2", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-retry": "^4.0.4", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.4", + "@smithy/util-defaults-mode-node": "^4.0.4", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.744.0.tgz", + "integrity": "sha512-R0XLfDDq7MAXYyDf7tPb+m0R7gmzTRRDtPNQ5jvuq8dbkefph5gFMkxZ2zSx7dfTsfYHhBPuTBsQ0c5Xjal3Vg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/core": "^3.1.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/signature-v4": "^5.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", + "@smithy/util-middleware": "^4.0.1", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.744.0.tgz", + "integrity": "sha512-hyjC7xqzAeERorYYjhQG1ivcr1XlxgfBpa+r4pG29toFG60mACyVzaR7+og3kgzjRFAB7D1imMxPQyEvQ1QokA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.744.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.744.0.tgz", + "integrity": "sha512-k+P1Tl5ewBvVByR6hB726qFIzANgQVf2cY87hZ/e09pQYlH4bfBcyY16VJhkqYnKmv6HMdWxKHX7D8nwlc8Obg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.744.0", + "@aws-sdk/types": "3.734.0", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/property-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.744.0.tgz", + "integrity": "sha512-hjEWgkF86tkvg8PIsDiB3KkTj7z8ZFGR0v0OLQYD47o17q1qfoMzZmg9wae3wXp9KzU+lZETo+8oMqX9a+7aVQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.744.0", + "@aws-sdk/credential-provider-env": "3.744.0", + "@aws-sdk/credential-provider-http": "3.744.0", + "@aws-sdk/credential-provider-process": "3.744.0", + "@aws-sdk/credential-provider-sso": "3.744.0", + "@aws-sdk/credential-provider-web-identity": "3.744.0", + "@aws-sdk/nested-clients": "3.744.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.744.0.tgz", + "integrity": "sha512-4oUfRd6pe/VGmKoav17pPoOO0WP0L6YXmHqtJHSDmFUOAa+Vh0ZRljTj/yBdleRgdO6rOfdWqoGLFSFiAZDrsQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.744.0", + "@aws-sdk/credential-provider-http": "3.744.0", + "@aws-sdk/credential-provider-ini": "3.744.0", + "@aws-sdk/credential-provider-process": "3.744.0", + "@aws-sdk/credential-provider-sso": "3.744.0", + "@aws-sdk/credential-provider-web-identity": "3.744.0", + "@aws-sdk/types": "3.734.0", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.744.0.tgz", + "integrity": "sha512-m0d/pDBIaiEAAxWXt/c79RHsKkUkyPOvF2SAMRddVhhOt1GFZI4ml+3f4drmAZfXldIyJmvJTJJqWluVPwTIqQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.744.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.744.0.tgz", + "integrity": "sha512-xdMufTZOvpbDoDPI2XLu0/Rg3qJ/txpS8IJR63NsCGotHJZ/ucLNKwTcGS40hllZB8qSHTlvmlOzElDahTtx/A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.744.0", + "@aws-sdk/core": "3.744.0", + "@aws-sdk/token-providers": "3.744.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.744.0.tgz", + "integrity": "sha512-cNk93GZxORzqEojWfXdrPBF6a7Nu3LpPCWG5mV+lH2tbuGsmw6XhKkwpt7o+OiIP4tKCpHlvqOD8f1nmhe1KDA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.744.0", + "@aws-sdk/nested-clients": "3.744.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.734.0.tgz", + "integrity": "sha512-LW7RRgSOHHBzWZnigNsDIzu3AiwtjeI2X66v+Wn1P1u+eXssy1+up4ZY/h+t2sU4LU36UvEf+jrZti9c6vRnFw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.734.0.tgz", + "integrity": "sha512-mUMFITpJUW3LcKvFok176eI5zXAUomVtahb9IQBwLzkqFYOrMJvWAvoV4yuxrJ8TlQBG8gyEnkb9SnhZvjg67w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.734.0.tgz", + "integrity": "sha512-CUat2d9ITsFc2XsmeiRQO96iWpxSKYFjxvj27Hc7vo87YUHRnfMfnc8jw1EpxEwMcvBD7LsRa6vDNky6AjcrFA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.744.0.tgz", + "integrity": "sha512-ROUbDQHfVWiBHXd4m9E9mKj1Azby8XCs8RC8OCf9GVH339GSE6aMrPJSzMlsV1LmzPdPIypgp5qqh5NfSrKztg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.744.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@smithy/core": "^3.1.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.744.0.tgz", + "integrity": "sha512-Mnrlh4lRY1gZQnKvN2Lh/5WXcGkzC41NM93mtn2uaqOh+DZLCXCttNCfbUesUvYJLOo3lYaOpiDsjTkPVB1yjw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.744.0", + "@aws-sdk/middleware-host-header": "3.734.0", + "@aws-sdk/middleware-logger": "3.734.0", + "@aws-sdk/middleware-recursion-detection": "3.734.0", + "@aws-sdk/middleware-user-agent": "3.744.0", + "@aws-sdk/region-config-resolver": "3.734.0", + "@aws-sdk/types": "3.734.0", + "@aws-sdk/util-endpoints": "3.743.0", + "@aws-sdk/util-user-agent-browser": "3.734.0", + "@aws-sdk/util-user-agent-node": "3.744.0", + "@smithy/config-resolver": "^4.0.1", + "@smithy/core": "^3.1.2", + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/hash-node": "^4.0.1", + "@smithy/invalid-dependency": "^4.0.1", + "@smithy/middleware-content-length": "^4.0.1", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-retry": "^4.0.4", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-body-length-node": "^4.0.0", + "@smithy/util-defaults-mode-browser": "^4.0.4", + "@smithy/util-defaults-mode-node": "^4.0.4", + "@smithy/util-endpoints": "^3.0.1", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.734.0.tgz", + "integrity": "sha512-Lvj1kPRC5IuJBr9DyJ9T9/plkh+EfKLy+12s/mykOy1JaKHDpvj+XGy2YO6YgYVOb8JFtaqloid+5COtje4JTQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.744.0.tgz", + "integrity": "sha512-v/1+lWkDCd60Ei6oyhJqli6mTsPEVepLoSMB50vHUVlJP0fzXu/3FMje90/RzeUoh/VugZQJCEv/NNpuC6wztg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/nested-clients": "3.744.0", + "@aws-sdk/types": "3.734.0", + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.734.0.tgz", + "integrity": "sha512-o11tSPTT70nAkGV1fN9wm/hAIiLPyWX6SuGf+9JyTp7S/rC2cFWhR26MvA69nplcjNaXVzB0f+QFrLXXjOqCrg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.743.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.743.0.tgz", + "integrity": "sha512-sN1l559zrixeh5x+pttrnd0A3+r34r0tmPkJ/eaaMaAzXqsmKU/xYre9K3FNnsSS1J1k4PEfk/nHDTVUgFYjnw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "@smithy/util-endpoints": "^3.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.723.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.723.0.tgz", + "integrity": "sha512-Yf2CS10BqK688DRsrKI/EO6B8ff5J86NXe4C+VCysK7UOgN0l1zOTeTukZ3H8Q9tYYX3oaF1961o8vRkFm7Nmw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.734.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.734.0.tgz", + "integrity": "sha512-xQTCus6Q9LwUuALW+S76OL0jcWtMOVu14q+GoLnWPUM7QeUw963oQcLhF7oq0CtaLLKyl4GOUfcwc773Zmwwng==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.734.0", + "@smithy/types": "^4.1.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.744.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.744.0.tgz", + "integrity": "sha512-BJURjwIXhNa4heXkLC0+GcL+8wVXaU7JoyW6ckdvp93LL+sVHeR1d5FxXZHQW/pMI4E3gNlKyBqjKaT75tObNQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.744.0", + "@aws-sdk/types": "3.734.0", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, "node_modules/@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", @@ -1285,213 +1891,792 @@ "linux" ], "engines": { - "node": ">= 10" + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.4.tgz", + "integrity": "sha512-8QftwPEW37XxXoAwsn+nXlodKWHfpMaSvt81W43Wh8dv0gkheD+30ezWMcFGHLI71KiWmHK5PSQbTQGUiidvLQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.4.tgz", + "integrity": "sha512-/s/Pme3VKfZAfISlYVq2hzFS8AcAIOTnoKupc/j4WlvF6GQ0VouS2Q2KEgPuO1eMBwakWPB1aYFIA4VNVh667A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.4.tgz", + "integrity": "sha512-m8z/6Fyal4L9Bnlxde5g2Mfa1Z7dasMQyhEhskDATpqr+Y0mjOBZcXQ7G5U+vgL22cI4T7MfvgtrM2jdopqWaw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.4.tgz", + "integrity": "sha512-7Wv4PRiWIAWbm5XrGz3D8HUkCVDMMz9igffZG4NB1p4u1KoItwx9qjATHz88kwCEal/HXmbShucaslXCQXUM5w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.4.tgz", + "integrity": "sha512-zLeNEAPULsl0phfGb4kdzF/cAVIfaC7hY+kt0/d+y9mzcZHsMS3hAS829WbJ31DkSlVKQeHEjZHIdhN+Pg7Gyg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.0.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.4.tgz", + "integrity": "sha512-yEh2+R8qDlDCjxVpzOTEpBLQTEFAcP2A8fUFLaWNap9GitYKkKv1//y2S6XY6zsR4rCOPRpU7plYDR+az2n30A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "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/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.0.1.tgz", + "integrity": "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.0.1.tgz", + "integrity": "sha512-Igfg8lKu3dRVkTSEm98QpZUvKEOa71jDX4vKRcvJVyRc3UgN3j7vFMf0s7xLQhYmKa8kyJGQgUJDOV5V3neVlQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-config-provider": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.1.2.tgz", + "integrity": "sha512-htwQXkbdF13uwwDevz9BEzL5ABK+1sJpVQXywwGSH973AVOvisHNfpcB8A8761G6XgHoS2kHPqc9DqHJ2gp+/Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.0.2", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-body-length-browser": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-stream": "^4.0.2", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.0.1.tgz", + "integrity": "sha512-l/qdInaDq1Zpznpmev/+52QomsJNZ3JkTl5yrTl02V6NBgJOQ4LY0SFw/8zsMwj3tLe8vqiIuwF6nxaEwgf6mg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz", + "integrity": "sha512-3aS+fP28urrMW2KTjb6z9iFow6jO8n3MFfineGbndvzGZit3taZhKWtTorf+Gp5RpFDDafeHlhfsGlDCXvUnJA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.0.1.tgz", + "integrity": "sha512-TJ6oZS+3r2Xu4emVse1YPB3Dq3d8RkZDKcPr71Nj/lJsdAP1c7oFzYqEn1IBc915TsgLl2xIJNuxCz+gLbLE0w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.0.1.tgz", + "integrity": "sha512-gdudFPf4QRQ5pzj7HEnu6FhKRi61BfH/Gk5Yf6O0KiSbr1LlVhgjThcvjdu658VE6Nve8vaIWB8/fodmS1rBPQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.0.0.tgz", + "integrity": "sha512-saYhF8ZZNoJDTvJBEWgeBccCg+yvp1CX+ed12yORU3NilJScfc6gfch2oVb4QgxZrGUx3/ZJlb+c/dJbyupxlw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.0.1.tgz", + "integrity": "sha512-OGXo7w5EkB5pPiac7KNzVtfCW2vKBTZNuCctn++TTSOMpe6RZO/n6WEC1AxJINn3+vWLKW49uad3lo/u0WJ9oQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.0.3.tgz", + "integrity": "sha512-YdbmWhQF5kIxZjWqPIgboVfi8i5XgiYMM7GGKFMTvBei4XjNQfNv8sukT50ITvgnWKKKpOtp0C0h7qixLgb77Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-serde": "^4.0.2", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "@smithy/url-parser": "^4.0.1", + "@smithy/util-middleware": "^4.0.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.0.4.tgz", + "integrity": "sha512-wmxyUBGHaYUqul0wZiset4M39SMtDBOtUr2KpDuftKNN74Do9Y36Go6Eqzj9tL0mIPpr31ulB5UUtxcsCeGXsQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/service-error-classification": "^4.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-retry": "^4.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", + "integrity": "sha512-Sdr5lOagCn5tt+zKsaW+U2/iwr6bI9p08wOkCp6/eL6iMbgdtc2R5Ety66rf87PeohR0ExI84Txz9GYv5ou3iQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.0.1.tgz", + "integrity": "sha512-dHwDmrtR/ln8UTHpaIavRSzeIk5+YZTBtLnKwDW3G2t6nAupCiQUvNzNoHBpik63fwUaJPtlnMzXbQrNFWssIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.0.1.tgz", + "integrity": "sha512-8mRTjvCtVET8+rxvmzRNRR0hH2JjV0DFOmwXPrISmTIJEfnCBugpYYGAsCj8t41qd+RB5gbheSQ/6aKZCQvFLQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.0.1", + "@smithy/shared-ini-file-loader": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.0.2.tgz", + "integrity": "sha512-X66H9aah9hisLLSnGuzRYba6vckuFtGE+a5DcHLliI/YlqKrGoxhisD5XbX44KyoeRzoNlGr94eTsMVHFAzPOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/querystring-builder": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.0.1.tgz", + "integrity": "sha512-o+VRiwC2cgmk/WFV0jaETGOtX16VNPp2bSQEzu0whbReqE1BMqsP2ami2Vi3cbGVdKu1kq9gQkDAGKbt0WOHAQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.0.1.tgz", + "integrity": "sha512-TE4cpj49jJNB/oHyh/cRVEgNZaoPaxd4vteJNB0yGidOCVR0jCw/hjPVsT8Q8FRmj8Bd3bFZt8Dh7xGCT+xMBQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.0.1.tgz", + "integrity": "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "@smithy/util-uri-escape": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.0.1.tgz", + "integrity": "sha512-Ma2XC7VS9aV77+clSFylVUnPZRindhB7BbmYiNOdr+CHt/kZNJoPP0cd3QxCnCFyPXC4eybmyE98phEHkqZ5Jw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.0.1.tgz", + "integrity": "sha512-3JNjBfOWpj/mYfjXJHB4Txc/7E4LVq32bwzE7m28GN79+M1f76XHflUaSUkhOriprPDzev9cX/M+dEB80DNDKA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.0.1.tgz", + "integrity": "sha512-hC8F6qTBbuHRI/uqDgqqi6J0R4GtEZcgrZPhFQnMhfJs3MnUTGSnR1NSJCJs5VWlMydu0kJz15M640fJlRsIOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.0.1.tgz", + "integrity": "sha512-nCe6fQ+ppm1bQuw5iKoeJ0MJfz2os7Ic3GBjOkLOPtavbD1ONoyE3ygjBfz2ythFWm4YnRm6OxW+8p/m9uCoIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-middleware": "^4.0.1", + "@smithy/util-uri-escape": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.1.3.tgz", + "integrity": "sha512-A2Hz85pu8BJJaYFdX8yb1yocqigyqBzn+OVaVgm+Kwi/DkN8vhN2kbDVEfADo6jXf5hPKquMLGA3UINA64UZ7A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.1.2", + "@smithy/middleware-endpoint": "^4.0.3", + "@smithy/middleware-stack": "^4.0.1", + "@smithy/protocol-http": "^5.0.1", + "@smithy/types": "^4.1.0", + "@smithy/util-stream": "^4.0.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.1.0.tgz", + "integrity": "sha512-enhjdwp4D7CXmwLtD6zbcDMbo6/T6WtuuKCY49Xxc6OMOmUWlBEBDREsxxgV2LIdeQPW756+f97GzcgAwp3iLw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.4.tgz", - "integrity": "sha512-8QftwPEW37XxXoAwsn+nXlodKWHfpMaSvt81W43Wh8dv0gkheD+30ezWMcFGHLI71KiWmHK5PSQbTQGUiidvLQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@smithy/url-parser": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.0.1.tgz", + "integrity": "sha512-gPXcIEUtw7VlK8f/QcruNXm7q+T5hhvGu9tl63LsJPZ27exB6dtNwvh2HIi0v7JcXJ5emBxB+CJxwaLEdJfA+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">= 10" + "node": ">=18.0.0" } }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.4.tgz", - "integrity": "sha512-/s/Pme3VKfZAfISlYVq2hzFS8AcAIOTnoKupc/j4WlvF6GQ0VouS2Q2KEgPuO1eMBwakWPB1aYFIA4VNVh667A==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@smithy/util-base64": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.0.0.tgz", + "integrity": "sha512-CvHfCmO2mchox9kjrtzoHkWHxjHZzaFojLc8quxXY7WAAMAg43nuxwv95tATVgQFNDwd4M9S1qFzj40Ul41Kmg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">= 10" + "node": ">=18.0.0" } }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.4.tgz", - "integrity": "sha512-m8z/6Fyal4L9Bnlxde5g2Mfa1Z7dasMQyhEhskDATpqr+Y0mjOBZcXQ7G5U+vgL22cI4T7MfvgtrM2jdopqWaw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@smithy/util-body-length-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.0.0.tgz", + "integrity": "sha512-sNi3DL0/k64/LO3A256M+m3CDdG6V7WKWHdAiBBMUN8S3hK3aMPhwnPik2A/a2ONN+9doY9UxaLfgqsIRg69QA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">= 10" + "node": ">=18.0.0" } }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.4.tgz", - "integrity": "sha512-7Wv4PRiWIAWbm5XrGz3D8HUkCVDMMz9igffZG4NB1p4u1KoItwx9qjATHz88kwCEal/HXmbShucaslXCQXUM5w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "node_modules/@smithy/util-body-length-node": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.0.0.tgz", + "integrity": "sha512-q0iDP3VsZzqJyje8xJWEJCNIu3lktUGVoSy1KB0UWym2CL1siV3artm+u1DFYTLejpsrdGyCSWBdGNjJzfDPjg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">= 10" + "node": ">=18.0.0" } }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.4.tgz", - "integrity": "sha512-zLeNEAPULsl0phfGb4kdzF/cAVIfaC7hY+kt0/d+y9mzcZHsMS3hAS829WbJ31DkSlVKQeHEjZHIdhN+Pg7Gyg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "node_modules/@smithy/util-buffer-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.0.0.tgz", + "integrity": "sha512-9TOQ7781sZvddgO8nxueKi3+yGvkY35kotA0Y6BWRajAv8jjmigQ1sBwz0UX47pQMYXJPahSKEKYFgt+rXdcug==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.0.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">= 10" + "node": ">=18.0.0" } }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.0.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.4.tgz", - "integrity": "sha512-yEh2+R8qDlDCjxVpzOTEpBLQTEFAcP2A8fUFLaWNap9GitYKkKv1//y2S6XY6zsR4rCOPRpU7plYDR+az2n30A==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "node_modules/@smithy/util-config-provider": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.0.0.tgz", + "integrity": "sha512-L1RBVzLyfE8OXH+1hsJ8p+acNUSirQnWQ6/EgpchV88G6zGBTDPdXiiExei6Z1wR2RxYvxY/XLw6AMNCCt8H3w==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">= 10" + "node": ">=18.0.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "license": "MIT", + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.0.4.tgz", + "integrity": "sha512-Ej1bV5sbrIfH++KnWxjjzFNq9nyP3RIUq2c9Iqq7SmMO/idUR24sqvKH2LUQFTSPy/K7G4sB2m8n7YYlEAfZaw==", + "license": "Apache-2.0", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@smithy/property-provider": "^4.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">= 8" + "node": ">=18.0.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "license": "MIT", + "node_modules/@smithy/util-defaults-mode-node": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.0.4.tgz", + "integrity": "sha512-HE1I7gxa6yP7ZgXPCFfZSDmVmMtY7SHqzFF55gM/GPegzZKaQWZZ+nYn9C2Cc3JltCMyWe63VPR3tSFDEvuGjw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/config-resolver": "^4.0.1", + "@smithy/credential-provider-imds": "^4.0.1", + "@smithy/node-config-provider": "^4.0.1", + "@smithy/property-provider": "^4.0.1", + "@smithy/smithy-client": "^4.1.3", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">= 8" + "node": ">=18.0.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "license": "MIT", + "node_modules/@smithy/util-endpoints": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.0.1.tgz", + "integrity": "sha512-zVdUENQpdtn9jbpD9SCFK4+aSiavRb9BxEtw9ZGUR1TYo6bBHbIoi7VkrFQ0/RwZlzx0wRBaRmPclj8iAoJCLA==", + "license": "Apache-2.0", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@smithy/node-config-provider": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">= 8" + "node": ">=18.0.0" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", - "optional": true, + "node_modules/@smithy/util-hex-encoding": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz", + "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">=14" + "node": ">=18.0.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", + "node_modules/@smithy/util-middleware": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.0.1.tgz", + "integrity": "sha512-HiLAvlcqhbzhuiOa0Lyct5IIlyIz0PQO5dnMlmQ/ubYM46dPInB+3yQGkfxsk6Q24Y0n3/JmcA1v5iEhmOF5mA==", + "license": "Apache-2.0", "dependencies": { - "@sendgrid/helpers": "^8.0.0", - "axios": "^1.7.4" + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=12.*" + "node": ">=18.0.0" } }, - "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", + "node_modules/@smithy/util-retry": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.0.1.tgz", + "integrity": "sha512-WmRHqNVwn3kI3rKk1LsKcVgPBG6iLTBGC1iYOV3GQegwJ3E8yjzHytPt26VNzOWr1qu0xE03nK0Ug8S7T7oufw==", + "license": "Apache-2.0", "dependencies": { - "deepmerge": "^4.2.2" + "@smithy/service-error-classification": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">= 12.0.0" + "node": ">=18.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", + "node_modules/@smithy/util-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz", + "integrity": "sha512-0eZ4G5fRzIoewtHtwaYyl8g2C+osYOT4KClXgfdNEDAgkbe2TYPqcnw4GAWabqkZCax2ihRGPe9LZnsPdIUIHA==", + "license": "Apache-2.0", "dependencies": { - "@sendgrid/client": "^8.1.4", - "@sendgrid/helpers": "^8.0.0" + "@smithy/fetch-http-handler": "^5.0.1", + "@smithy/node-http-handler": "^4.0.2", + "@smithy/types": "^4.1.0", + "@smithy/util-base64": "^4.0.0", + "@smithy/util-buffer-from": "^4.0.0", + "@smithy/util-hex-encoding": "^4.0.0", + "@smithy/util-utf8": "^4.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=12.*" + "node": ">=18.0.0" } }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" + "node_modules/@smithy/util-uri-escape": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.0.0.tgz", + "integrity": "sha512-77yfbCbQMtgtTylO9itEAdpPXSog3ZxMe09AEhm0dU0NLTalV70ghDZFR+Nfi1C60jnJoh/Re4090/DuZh2Omg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/@smithy/util-utf8": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.0.0.tgz", + "integrity": "sha512-b+zebfKCfRdgNJDknHCob3O7FpeYQN6ZG6YLExMcasDHsCXlsXCEuiPZeLnJLpwa5dvPetGlnGCiMHuLwGvFow==", + "license": "Apache-2.0", "dependencies": { - "type-detect": "4.0.8" + "@smithy/util-buffer-from": "^4.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/@smithy/util-waiter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.0.2.tgz", + "integrity": "sha512-piUTHyp2Axx3p/kc2CIJkYSv0BAaheBQmbACZgQSSfWUumWNW+R1lL+H9PDBxKJkvOeEX+hKYEFiwO8xagL8AQ==", + "license": "Apache-2.0", "dependencies": { - "@sinonjs/commons": "^3.0.0" + "@smithy/abort-controller": "^4.0.1", + "@smithy/types": "^4.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@swc/helpers": { @@ -2375,6 +3560,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "license": "MIT" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3441,6 +4632,28 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-xml-parser": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", + "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fastq": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", @@ -7797,6 +9010,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "license": "MIT" + }, "node_modules/style-to-object": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", @@ -8369,6 +9588,19 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", diff --git a/package.json b/package.json index 08b5f34f9..c35fc9f2c 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "test:watch": "jest --watch" }, "dependencies": { + "@aws-sdk/client-ses": "^3.744.0", "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", "@next/mdx": "^15.1.6", From 8458a55d4e31f703bafe7f86fae482605319448d Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 18:02:15 +0000 Subject: [PATCH 008/293] feat: update email service to use AWS SES Co-Authored-By: G --- src/lib/email/service.ts | 91 +++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/src/lib/email/service.ts b/src/lib/email/service.ts index 162094c1d..e1ca82daa 100644 --- a/src/lib/email/service.ts +++ b/src/lib/email/service.ts @@ -1,59 +1,72 @@ -import formData from 'form-data'; -import Mailgun from 'mailgun.js'; -import Client from 'mailgun.js/dist/lib/client'; +import { SESClient, SendEmailCommand } from '@aws-sdk/client-ses'; +import type { Customer } from '@/src/lib/schemas/customer'; export class EmailService { - private client: Client; - private domain: string; + private ses: SESClient; private fromEmail: string; + private adminEmail: string; constructor() { - const mailgun = new Mailgun(formData); - this.client = mailgun.client({ - username: 'api', - key: process.env.MAILGUN_API_KEY || '', - url: 'https://api.eu.mailgun.net' // EU endpoint for Swiss compliance + this.ses = new SESClient({ + region: 'eu-central-1', // Frankfurt region for Swiss compliance + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID || '', + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || '' + } }); - this.domain = process.env.MAILGUN_DOMAIN || ''; - this.fromEmail = process.env.MAILGUN_FROM_EMAIL || ''; + this.fromEmail = process.env.FROM_EMAIL || 'noreply@botsmann.com'; + this.adminEmail = process.env.ADMIN_EMAIL || 'butaeff@gmail.com'; } - async sendWelcomeEmail(customer: any) { + async sendWelcomeEmail(customer: Customer): Promise { + const params = { + Source: this.fromEmail, + Destination: { + ToAddresses: [customer.email] + }, + Message: { + Subject: { + Data: 'Welcome to Botsmann!' + }, + Body: { + Text: { + Data: `Hello ${customer.name},\n\nThank you for your interest in Botsmann! We've received your message and will get back to you soon.\n\nBest regards,\nThe Botsmann Team` + } + } + } + }; + try { - await this.client.messages.create(this.domain, { - from: this.fromEmail, - to: customer.email, - subject: 'Welcome to Botsmann!', - template: 'welcome-email', - 'h:X-Mailgun-Variables': JSON.stringify({ - name: customer.name, - preferences: customer.preferences || {}, - dashboardUrl: process.env.DASHBOARD_URL - }) - }); + await this.ses.send(new SendEmailCommand(params)); } catch (error) { console.error('Failed to send welcome email:', error); + throw error; } } - async sendAdminNotification(customer: any) { + async sendAdminNotification(customer: Customer): Promise { + const params = { + Source: this.fromEmail, + Destination: { + ToAddresses: [this.adminEmail] + }, + Message: { + Subject: { + Data: 'New Customer Registration' + }, + Body: { + Text: { + Data: `New customer registration:\n\nName: ${customer.name}\nEmail: ${customer.email}\nMessage: ${customer.message}\n\nPreferences:\n- Newsletter: ${customer.preferences.newsletter ? 'Yes' : 'No'}\n- Product Updates: ${customer.preferences.productUpdates ? 'Yes' : 'No'}` + } + } + } + }; + try { - await this.client.messages.create(this.domain, { - from: this.fromEmail, - to: process.env.ADMIN_EMAIL || '', - subject: 'New Customer Registration', - text: ` -New customer registration: -Name: ${customer.name} -Email: ${customer.email} -Message: ${customer.message} -Preferences: -- Newsletter: ${customer.preferences?.newsletter ? 'Yes' : 'No'} -- Product Updates: ${customer.preferences?.productUpdates ? 'Yes' : 'No'} -` - }); + await this.ses.send(new SendEmailCommand(params)); } catch (error) { console.error('Failed to send admin notification:', error); + throw error; } } } From 942e11d2a4abb9ca71a7354cb5ce69742ff82592 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 18:23:33 +0000 Subject: [PATCH 009/293] fix: update AWS SES environment variable names Co-Authored-By: G --- src/lib/email/service.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/email/service.ts b/src/lib/email/service.ts index e1ca82daa..bf1eda9f5 100644 --- a/src/lib/email/service.ts +++ b/src/lib/email/service.ts @@ -8,10 +8,10 @@ export class EmailService { constructor() { this.ses = new SESClient({ - region: 'eu-central-1', // Frankfurt region for Swiss compliance + region: process.env.NEXT_AWS_REGION || 'eu-central-1', // Frankfurt region for Swiss compliance credentials: { - accessKeyId: process.env.AWS_ACCESS_KEY_ID || '', - secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || '' + accessKeyId: process.env.NEXT_AWS_ACCESS_KEY_ID || '', + secretAccessKey: process.env.NEXT_AWS_SECRET_ACCESS_KEY || '' } }); this.fromEmail = process.env.FROM_EMAIL || 'noreply@botsmann.com'; From 1b1d499dc6f96a40c340c6d5a9ec357beaca6470 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2025 18:40:40 +0000 Subject: [PATCH 010/293] chore: update env example with generic placeholders Co-Authored-By: G --- .env.example | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/.env.example b/.env.example index d64af425e..c14a76591 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,15 @@ -# Mailgun Configuration -MAILGUN_API_KEY=your_mailgun_api_key_here -MAILGUN_DOMAIN=your_domain_here -MAILGUN_FROM_EMAIL=noreply@your_domain -MAILGUN_TEMPLATE_ID=your_template_id -ADMIN_EMAIL=admin@your_domain +# MongoDB connection string +MONGODB_URI=mongodb://localhost:27017/botsmann + +# API key for authentication +API_KEY=your-secure-api-key-here +NEXT_PUBLIC_API_KEY=your-secure-api-key-here + +# AWS SES Configuration +NEXT_AWS_ACCESS_KEY_ID=your-aws-access-key-id +NEXT_AWS_SECRET_ACCESS_KEY=your-aws-secret-access-key +NEXT_AWS_REGION=your-aws-region + +# Email Configuration +FROM_EMAIL=your-verified-sender@example.com +ADMIN_EMAIL=your-admin@example.com From 5ffbb527c1408397739e496b0144900f6123c36e Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 08:37:30 +0000 Subject: [PATCH 011/293] fix: update netlify configuration with processing settings Co-Authored-By: G --- netlify.toml | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/netlify.toml b/netlify.toml index ca8556978..19a15257f 100644 --- a/netlify.toml +++ b/netlify.toml @@ -8,6 +8,23 @@ NEXT_USE_NETLIFY = "true" NEXT_STATIC_EXPORT = "true" +[build.processing] + skip_processing = false + +[build.processing.html] + pretty_urls = true + +[build.processing.css] + bundle = true + minify = true + +[build.processing.js] + bundle = true + minify = true + +[build.processing.images] + compress = true + [functions] node_bundler = "esbuild" included_files = ["app/api/**"] @@ -20,11 +37,16 @@ force = true [[redirects]] - from = "/*" + from = "/" to = "/index.html" status = 200 force = true +[[redirects]] + from = "/*" + to = "/404.html" + status = 404 + [[headers]] for = "/api/*" [headers.values] From 315c21b269173368b008fcdb550d327fff0ce9fc Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 08:49:49 +0000 Subject: [PATCH 012/293] chore: remove Vercel configuration Co-Authored-By: G --- vercel.json | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 vercel.json diff --git a/vercel.json b/vercel.json deleted file mode 100644 index 72570550f..000000000 --- a/vercel.json +++ /dev/null @@ -1,12 +0,0 @@ - -{ - "version": 2, - "builds": [ - { "src": "start-server.js", "use": "@vercel/node" }, - { "src": "public/**/*", "use": "@vercel/static" } - ], - "routes": [ - { "src": "/api/(.*)", "dest": "/start-server.js" }, - { "src": "/(.*)", "dest": "/public/$1" } - ] -} From b7c994776e750cee96cc56fe624859079aef80c3 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 08:50:16 +0000 Subject: [PATCH 013/293] chore: update test configuration to use Netlify URL Co-Authored-By: G --- tests/api.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/api.test.js b/tests/api.test.js index 0de0d0a7b..9805ff752 100644 --- a/tests/api.test.js +++ b/tests/api.test.js @@ -1,5 +1,5 @@ const request = require('supertest'); -const baseURL = process.env.VERCEL_URL || 'http://localhost:3000'; +const baseURL = process.env.NETLIFY_URL || 'http://localhost:3000'; describe('API Tests', () => { test('POST /api/consultations with valid data', async () => { @@ -26,4 +26,4 @@ describe('API Tests', () => { expect(response.status).toBe(400); expect(response.body.error).toBeTruthy(); }); -}); \ No newline at end of file +}); From b5cca5590edddc24e96b22f0cca69401aefd0d6c Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 08:53:42 +0000 Subject: [PATCH 014/293] fix: update build script for Netlify functions Co-Authored-By: G --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c35fc9f2c..454b50645 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "dev": "next dev", - "build": "next build", + "build": "next build && mkdir -p netlify/functions/api && cp -r app/api netlify/functions/", "start": "next start", "test": "jest", "test:watch": "jest --watch" From 54cdb138d11bf372420028ad42ef1f8f735710db Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:12:38 +0000 Subject: [PATCH 015/293] fix: simplify netlify configuration for headers and redirects Co-Authored-By: G --- netlify.toml | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/netlify.toml b/netlify.toml index 19a15257f..d665e1db8 100644 --- a/netlify.toml +++ b/netlify.toml @@ -34,21 +34,14 @@ from = "/api/*" to = "/.netlify/functions/api/:splat" status = 200 - force = true [[redirects]] - from = "/" + from = "/*" to = "/index.html" status = 200 - force = true - -[[redirects]] - from = "/*" - to = "/404.html" - status = 404 [[headers]] - for = "/api/*" + for = "/*" [headers.values] X-Frame-Options = "DENY" X-XSS-Protection = "1; mode=block" @@ -57,11 +50,3 @@ Access-Control-Allow-Origin = "*" Access-Control-Allow-Headers = "Origin, X-Requested-With, Content-Type, Accept, x-api-key" Access-Control-Allow-Methods = "GET, POST, OPTIONS" - -[[headers]] - for = "/*" - [headers.values] - X-Frame-Options = "DENY" - X-XSS-Protection = "1; mode=block" - X-Content-Type-Options = "nosniff" - Referrer-Policy = "strict-origin-when-cross-origin" From 27b2ed97f9af718875e6bdad3ed33a3ff14f62e7 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:14:24 +0000 Subject: [PATCH 016/293] fix: remove processing settings from netlify configuration Co-Authored-By: G --- netlify.toml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/netlify.toml b/netlify.toml index d665e1db8..a61e4a30b 100644 --- a/netlify.toml +++ b/netlify.toml @@ -8,23 +8,6 @@ NEXT_USE_NETLIFY = "true" NEXT_STATIC_EXPORT = "true" -[build.processing] - skip_processing = false - -[build.processing.html] - pretty_urls = true - -[build.processing.css] - bundle = true - minify = true - -[build.processing.js] - bundle = true - minify = true - -[build.processing.images] - compress = true - [functions] node_bundler = "esbuild" included_files = ["app/api/**"] From 447ce956d02b0bdc90d5b8ef0c0ff0c3ddbe176e Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:16:22 +0000 Subject: [PATCH 017/293] fix: simplify netlify configuration to basic Next.js static export Co-Authored-By: G --- netlify.toml | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/netlify.toml b/netlify.toml index a61e4a30b..ee2c61876 100644 --- a/netlify.toml +++ b/netlify.toml @@ -12,24 +12,3 @@ node_bundler = "esbuild" included_files = ["app/api/**"] external_node_modules = ["mongodb"] - -[[redirects]] - from = "/api/*" - to = "/.netlify/functions/api/:splat" - status = 200 - -[[redirects]] - from = "/*" - to = "/index.html" - status = 200 - -[[headers]] - for = "/*" - [headers.values] - X-Frame-Options = "DENY" - X-XSS-Protection = "1; mode=block" - X-Content-Type-Options = "nosniff" - Referrer-Policy = "strict-origin-when-cross-origin" - Access-Control-Allow-Origin = "*" - Access-Control-Allow-Headers = "Origin, X-Requested-With, Content-Type, Accept, x-api-key" - Access-Control-Allow-Methods = "GET, POST, OPTIONS" From 73b06288df488da6e9c9a47309488413ab789d59 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:18:29 +0000 Subject: [PATCH 018/293] fix: add basic redirects for Next.js static export Co-Authored-By: G --- netlify.toml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/netlify.toml b/netlify.toml index ee2c61876..fa430d122 100644 --- a/netlify.toml +++ b/netlify.toml @@ -12,3 +12,20 @@ node_bundler = "esbuild" included_files = ["app/api/**"] external_node_modules = ["mongodb"] + +[[redirects]] + from = "/api/*" + to = "/.netlify/functions/api/:splat" + status = 200 + +[[redirects]] + from = "/*" + to = "/404.html" + status = 404 + force = false + +[[redirects]] + from = "/*" + to = "/index.html" + status = 200 + force = false From 40b74616f467ab5bc0fe956e9d6aff26cd56d5fe Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:38:09 +0000 Subject: [PATCH 019/293] fix: simplify Next.js configuration for static export Co-Authored-By: G --- next.config.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/next.config.js b/next.config.js index 3ef5c4f81..824ba0af2 100644 --- a/next.config.js +++ b/next.config.js @@ -1,12 +1,9 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - reactStrictMode: true, - swcMinify: true, output: 'export', images: { unoptimized: true, }, - trailingSlash: true, }; module.exports = nextConfig; From ce9abd65abeed5501cf646197828aa7c9731435a Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:39:56 +0000 Subject: [PATCH 020/293] fix: update build script to handle functions directory Co-Authored-By: G --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 454b50645..235cd0a0d 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "dev": "next dev", - "build": "next build && mkdir -p netlify/functions/api && cp -r app/api netlify/functions/", + "build": "next build && cp -r netlify/functions .", "start": "next start", "test": "jest", "test:watch": "jest --watch" From 8df6b35c8fdfcaecbfe8a82a2cf5a1ef943f582b Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:41:25 +0000 Subject: [PATCH 021/293] fix: use minimal netlify configuration Co-Authored-By: G --- netlify.toml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/netlify.toml b/netlify.toml index fa430d122..808f98698 100644 --- a/netlify.toml +++ b/netlify.toml @@ -5,27 +5,8 @@ [build.environment] NODE_VERSION = "18" - NEXT_USE_NETLIFY = "true" - NEXT_STATIC_EXPORT = "true" [functions] node_bundler = "esbuild" included_files = ["app/api/**"] external_node_modules = ["mongodb"] - -[[redirects]] - from = "/api/*" - to = "/.netlify/functions/api/:splat" - status = 200 - -[[redirects]] - from = "/*" - to = "/404.html" - status = 404 - force = false - -[[redirects]] - from = "/*" - to = "/index.html" - status = 200 - force = false From db414bb7feb8d1786c053609ae0eb5e04adfac98 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:42:39 +0000 Subject: [PATCH 022/293] fix: add Netlify _redirects file for SPA routing Co-Authored-By: G --- public/_redirects | 1 + 1 file changed, 1 insertion(+) create mode 100644 public/_redirects diff --git a/public/_redirects b/public/_redirects new file mode 100644 index 000000000..7797f7c6a --- /dev/null +++ b/public/_redirects @@ -0,0 +1 @@ +/* /index.html 200 From 91e0dc313cc9c12cf50cfa0a00c61fcd8fd5b75f Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:44:06 +0000 Subject: [PATCH 023/293] fix: add API redirects and CORS headers Co-Authored-By: G --- netlify.toml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/netlify.toml b/netlify.toml index 808f98698..1337d1247 100644 --- a/netlify.toml +++ b/netlify.toml @@ -10,3 +10,15 @@ node_bundler = "esbuild" included_files = ["app/api/**"] external_node_modules = ["mongodb"] + +[[redirects]] + from = "/api/*" + to = "/.netlify/functions/api/:splat" + status = 200 + +[[headers]] + for = "/api/*" + [headers.values] + Access-Control-Allow-Origin = "*" + Access-Control-Allow-Headers = "Origin, X-Requested-With, Content-Type, Accept, x-api-key" + Access-Control-Allow-Methods = "GET, POST, OPTIONS" From f63addb2a82c9d2ea6d8bcceb2d8348efa014bc3 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:45:22 +0000 Subject: [PATCH 024/293] fix: update build script to copy redirects file Co-Authored-By: G --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 235cd0a0d..25c05742a 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "dev": "next dev", - "build": "next build && cp -r netlify/functions .", + "build": "next build && cp -r netlify/functions . && cp public/_redirects out/", "start": "next start", "test": "jest", "test:watch": "jest --watch" From b38e2ba09af8f73bfbee4a87d1062e765033fe19 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:53:28 +0000 Subject: [PATCH 025/293] fix: update build script to remove next export Co-Authored-By: G --- package-lock.json | 45 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 46 insertions(+) diff --git a/package-lock.json b/package-lock.json index 3df4db751..d37bf020e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "zod": "^3.24.1" }, "devDependencies": { + "@netlify/functions": "^3.0.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.2.0", "@types/jest": "^29.5.14", @@ -1810,6 +1811,43 @@ "sparse-bitfield": "^3.0.3" } }, + "node_modules/@netlify/functions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@netlify/functions/-/functions-3.0.0.tgz", + "integrity": "sha512-XXf9mNw4+fkxUzukDpJtzc32bl1+YlXZwEhc5ZgMcTbJPLpgRLDs5WWSPJ4eY/Mv1ZFvtxmMwmfgoQYVt68Qog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@netlify/serverless-functions-api": "1.30.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@netlify/node-cookies": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@netlify/node-cookies/-/node-cookies-0.1.0.tgz", + "integrity": "sha512-OAs1xG+FfLX0LoRASpqzVntVV/RpYkgpI0VrUnw2u0Q1qiZUzcPffxRK8HF3gc4GjuhG5ahOEMJ9bswBiZPq0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.16.0 || >=16.0.0" + } + }, + "node_modules/@netlify/serverless-functions-api": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@netlify/serverless-functions-api/-/serverless-functions-api-1.30.1.tgz", + "integrity": "sha512-JkbaWFeydQdeDHz1mAy4rw+E3bl9YtbCgkntfTxq+IlNX/aIMv2/b1kZnQZcil4/sPoZGL831Dq6E374qRpU1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@netlify/node-cookies": "^0.1.0", + "urlpattern-polyfill": "8.0.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@next/env": { "version": "14.0.4", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.4.tgz", @@ -9582,6 +9620,13 @@ "requires-port": "^1.0.0" } }, + "node_modules/urlpattern-polyfill": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-8.0.2.tgz", + "integrity": "sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==", + "dev": true, + "license": "MIT" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 25c05742a..a0b17ea2f 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "zod": "^3.24.1" }, "devDependencies": { + "@netlify/functions": "^3.0.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.2.0", "@types/jest": "^29.5.14", From 96174ff8f245f4dc79b8de33b3f012d9fc1a081a Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:55:45 +0000 Subject: [PATCH 026/293] feat: add Netlify functions directory Co-Authored-By: G --- functions/api/consultations.ts | 52 ++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 functions/api/consultations.ts diff --git a/functions/api/consultations.ts b/functions/api/consultations.ts new file mode 100644 index 000000000..f1ee5d968 --- /dev/null +++ b/functions/api/consultations.ts @@ -0,0 +1,52 @@ +import { Handler } from '@netlify/functions'; +import { connectDB } from '../../../src/lib/mongodb'; +import { Consultation } from '../../../src/lib/models/consultation'; +import { CustomerSchema } from '../../../src/lib/schemas/customer'; +import { EmailService } from '../../../src/lib/email/service'; +import { validateApiKey } from '../../../src/lib/middleware/auth'; +import { monitorRequest } from '../../../src/lib/middleware/monitoring'; + +const emailService = new EmailService(); + +export const handler: Handler = async (event, context) => { + if (event.httpMethod !== 'POST') { + return { + statusCode: 405, + body: JSON.stringify({ error: 'Method not allowed' }), + }; + } + + try { + const body = JSON.parse(event.body || '{}'); + const validatedData = CustomerSchema.parse(body); + + if (process.env.NODE_ENV !== 'test') { + await connectDB(); + } + + const consultation = await Consultation.create(validatedData); + + // Send emails asynchronously + try { + await Promise.all([ + emailService.sendWelcomeEmail(validatedData), + emailService.sendAdminNotification(validatedData), + ]); + } catch (emailError) { + console.error('Failed to send emails:', emailError); + } + + return { + statusCode: 200, + body: JSON.stringify({ success: true, id: consultation._id }), + }; + } catch (error: any) { + console.error('Consultation submission error:', error); + return { + statusCode: error.code === 'VALIDATION_ERROR' ? 400 : 500, + body: JSON.stringify({ + error: error.message || 'Failed to submit consultation' + }), + }; + } +}; From 39f860b759938f0b61a70e507c62c7b88cd1385e Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:57:40 +0000 Subject: [PATCH 027/293] fix: update Netlify configuration with proper headers and redirects Co-Authored-By: G --- netlify.toml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/netlify.toml b/netlify.toml index 1337d1247..3b896fbec 100644 --- a/netlify.toml +++ b/netlify.toml @@ -5,17 +5,32 @@ [build.environment] NODE_VERSION = "18" + NEXT_TELEMETRY_DISABLED = "1" [functions] node_bundler = "esbuild" included_files = ["app/api/**"] external_node_modules = ["mongodb"] +[[redirects]] + from = "/*" + to = "/index.html" + status = 200 + [[redirects]] from = "/api/*" to = "/.netlify/functions/api/:splat" status = 200 +[[headers]] + for = "/*" + [headers.values] + X-Frame-Options = "DENY" + X-XSS-Protection = "1; mode=block" + X-Content-Type-Options = "nosniff" + Referrer-Policy = "strict-origin-when-cross-origin" + Content-Security-Policy = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;" + [[headers]] for = "/api/*" [headers.values] From 576a080569fbbe043556d6209161cdc5052c9380 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:58:50 +0000 Subject: [PATCH 028/293] fix: update _redirects file with API and SPA routes Co-Authored-By: G --- public/_redirects | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/_redirects b/public/_redirects index 7797f7c6a..7bb7c0b7d 100644 --- a/public/_redirects +++ b/public/_redirects @@ -1 +1,2 @@ -/* /index.html 200 +/api/* /.netlify/functions/api/:splat 200 +/* /index.html 200 From ad6a78737e61a8187d793fd121eaf0b46a03d2a5 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 09:59:34 +0000 Subject: [PATCH 029/293] fix: update CSP headers for Netlify deployment Co-Authored-By: G --- netlify.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlify.toml b/netlify.toml index 3b896fbec..14822cf34 100644 --- a/netlify.toml +++ b/netlify.toml @@ -29,7 +29,7 @@ X-XSS-Protection = "1; mode=block" X-Content-Type-Options = "nosniff" Referrer-Policy = "strict-origin-when-cross-origin" - Content-Security-Policy = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;" + Content-Security-Policy = "default-src 'self' *.netlify.app; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' *.netlify.app *.netlify.com;" [[headers]] for = "/api/*" From 18257c8cd66e03717317a2b2a9df498c854ad048 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 10:00:36 +0000 Subject: [PATCH 030/293] fix: simplify Netlify configuration to minimal settings Co-Authored-By: G --- netlify.toml | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/netlify.toml b/netlify.toml index 14822cf34..a6bd635d9 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,39 +1,8 @@ [build] command = "npm run build" publish = "out" - functions = "netlify/functions" - -[build.environment] - NODE_VERSION = "18" - NEXT_TELEMETRY_DISABLED = "1" - -[functions] - node_bundler = "esbuild" - included_files = ["app/api/**"] - external_node_modules = ["mongodb"] [[redirects]] from = "/*" to = "/index.html" status = 200 - -[[redirects]] - from = "/api/*" - to = "/.netlify/functions/api/:splat" - status = 200 - -[[headers]] - for = "/*" - [headers.values] - X-Frame-Options = "DENY" - X-XSS-Protection = "1; mode=block" - X-Content-Type-Options = "nosniff" - Referrer-Policy = "strict-origin-when-cross-origin" - Content-Security-Policy = "default-src 'self' *.netlify.app; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' *.netlify.app *.netlify.com;" - -[[headers]] - for = "/api/*" - [headers.values] - Access-Control-Allow-Origin = "*" - Access-Control-Allow-Headers = "Origin, X-Requested-With, Content-Type, Accept, x-api-key" - Access-Control-Allow-Methods = "GET, POST, OPTIONS" From 85906d7b2a2a0f008459ed9ca7d88e119c021116 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 10:01:25 +0000 Subject: [PATCH 031/293] fix: update Netlify configuration with functions and redirects Co-Authored-By: G --- netlify.toml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/netlify.toml b/netlify.toml index a6bd635d9..c0ffa4cd5 100644 --- a/netlify.toml +++ b/netlify.toml @@ -1,6 +1,19 @@ [build] command = "npm run build" publish = "out" + functions = "netlify/functions" + +[build.environment] + NODE_VERSION = "18" + +[functions] + node_bundler = "esbuild" + external_node_modules = ["mongodb"] + +[[redirects]] + from = "/api/*" + to = "/.netlify/functions/api/:splat" + status = 200 [[redirects]] from = "/*" From 4952773c8d1742baf95c3dedf40a89b74916cb20 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 10:02:26 +0000 Subject: [PATCH 032/293] fix: remove duplicate functions directory Co-Authored-By: G --- functions/api/consultations.ts | 52 ---------------------------------- 1 file changed, 52 deletions(-) delete mode 100644 functions/api/consultations.ts diff --git a/functions/api/consultations.ts b/functions/api/consultations.ts deleted file mode 100644 index f1ee5d968..000000000 --- a/functions/api/consultations.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Handler } from '@netlify/functions'; -import { connectDB } from '../../../src/lib/mongodb'; -import { Consultation } from '../../../src/lib/models/consultation'; -import { CustomerSchema } from '../../../src/lib/schemas/customer'; -import { EmailService } from '../../../src/lib/email/service'; -import { validateApiKey } from '../../../src/lib/middleware/auth'; -import { monitorRequest } from '../../../src/lib/middleware/monitoring'; - -const emailService = new EmailService(); - -export const handler: Handler = async (event, context) => { - if (event.httpMethod !== 'POST') { - return { - statusCode: 405, - body: JSON.stringify({ error: 'Method not allowed' }), - }; - } - - try { - const body = JSON.parse(event.body || '{}'); - const validatedData = CustomerSchema.parse(body); - - if (process.env.NODE_ENV !== 'test') { - await connectDB(); - } - - const consultation = await Consultation.create(validatedData); - - // Send emails asynchronously - try { - await Promise.all([ - emailService.sendWelcomeEmail(validatedData), - emailService.sendAdminNotification(validatedData), - ]); - } catch (emailError) { - console.error('Failed to send emails:', emailError); - } - - return { - statusCode: 200, - body: JSON.stringify({ success: true, id: consultation._id }), - }; - } catch (error: any) { - console.error('Consultation submission error:', error); - return { - statusCode: error.code === 'VALIDATION_ERROR' ? 400 : 500, - body: JSON.stringify({ - error: error.message || 'Failed to submit consultation' - }), - }; - } -}; From 931d6cbea0b03c15001e0edeffb8fa6d319471fa Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 11:14:27 +0000 Subject: [PATCH 033/293] feat: add mobile navigation with hamburger menu Co-Authored-By: G --- components/Header.tsx | 103 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/components/Header.tsx b/components/Header.tsx index b61d1b01e..80532e5cb 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -1,15 +1,51 @@ 'use client'; +import { useState, useEffect } from 'react'; import Link from 'next/link'; export default function Header() { + const [isMenuOpen, setIsMenuOpen] = useState(false); + + const toggleMenu = () => setIsMenuOpen(!isMenuOpen); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + const target = event.target as Element; + if (isMenuOpen && !target.closest('#mobile-menu')) { + setIsMenuOpen(false); + } + }; + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, [isMenuOpen]); + return (
Botsmann -
); From e56d656b04b8680f9d327dcc0fa7aa964ef54b49 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 11:58:28 +0000 Subject: [PATCH 034/293] feat: enhance page-to-page navigation with NextSection component Co-Authored-By: G --- app/about/page.tsx | 7 ++ app/solutions/venture-credit/page.tsx | 107 +++++++++++++++++++++ src/components/bots/BotPage.tsx | 108 ++++++++++++++++++++++ src/components/navigation/NextSection.tsx | 24 +++++ src/types/bot.ts | 19 ++++ 5 files changed, 265 insertions(+) create mode 100644 app/solutions/venture-credit/page.tsx create mode 100644 src/components/bots/BotPage.tsx create mode 100644 src/components/navigation/NextSection.tsx create mode 100644 src/types/bot.ts diff --git a/app/about/page.tsx b/app/about/page.tsx index 3252eac13..781f92ae6 100644 --- a/app/about/page.tsx +++ b/app/about/page.tsx @@ -1,5 +1,6 @@ import React from 'react'; import ConsultationForm from '@/components/ConsultationForm'; +import { NextSection } from '@/src/components/navigation/NextSection'; export default function About() { return ( @@ -16,6 +17,12 @@ export default function About() { + + ); } diff --git a/app/solutions/venture-credit/page.tsx b/app/solutions/venture-credit/page.tsx new file mode 100644 index 000000000..68cf6e9f0 --- /dev/null +++ b/app/solutions/venture-credit/page.tsx @@ -0,0 +1,107 @@ +'use client'; + +import React from 'react'; +import { NextSection } from '../../../src/components/navigation/NextSection'; + +export default function VentureCredit() { + return ( +
+

Venture Credit Workflow Automation

+ +
+

+ Streamline your venture credit operations with our AI-powered workflow automation solution. + Monitor portfolio companies, analyze financial data, and make informed decisions faster. +

+
+ +
+

Key Features

+
+
+

Automated Reporting

+

+ Automatically ingest and process regular reports from portfolio companies, saving time and reducing errors. +

+
+
+

Debt Monitoring

+

+ Track and analyze debt metrics in real-time with automated alerts for key thresholds. +

+
+
+

Financial Analysis

+

+ Comprehensive analysis of financials, KPIs, and qualitative factors including investor information. +

+
+
+
+ +
+

How It Works

+
+
+
+
+ 1 +
+
+
+

Data Integration

+

+ Connect your portfolio companies' reporting systems for automated data ingestion. +

+
+
+
+
+
+ 2 +
+
+
+

AI Analysis

+

+ Our AI processes financial data, identifies trends, and generates insights automatically. +

+
+
+
+
+
+ 3 +
+
+
+

Monitoring Dashboard

+

+ Access real-time insights and alerts through an intuitive dashboard interface. +

+
+
+
+
+ +
+

Ready to Transform Your Workflow?

+

+ Let us help you automate your venture credit operations and make better decisions faster. +

+ + Contact Us + +
+ + +
+ ); +} diff --git a/src/components/bots/BotPage.tsx b/src/components/bots/BotPage.tsx new file mode 100644 index 000000000..dc964f298 --- /dev/null +++ b/src/components/bots/BotPage.tsx @@ -0,0 +1,108 @@ +'use client'; + +import React from 'react'; +import { NextSection } from '../navigation/NextSection'; +import type { BotPageProps, Feature, Step } from '@/src/types/bot'; + +function Overview({ content }: { content: string }) { + return ( +
+

{content}

+
+ ); +} + +function Features({ items }: { items: Feature[] }) { + return ( +
+

Features

+
+ {items.map((feature, index) => ( +
+ {feature.icon && ( +
{feature.icon}
+ )} +

{feature.title}

+

{feature.description}

+
+ ))} +
+
+ ); +} + +function HowItWorks({ steps }: { steps: Step[] }) { + return ( +
+

How It Works

+
+ {steps.map((step, index) => ( +
+
+
+ {index + 1} +
+
+
+

{step.title}

+

{step.description}

+ {step.image && ( + {step.title} + )} +
+
+ ))} +
+
+ ); +} + +function Demo({ children }: { children: React.ReactNode }) { + return ( +
+

Demo

+
+ {children} +
+
+ ); +} + +function CTASection() { + return ( +
+

Ready to Get Started?

+

+ Experience the power of AI automation for your specific needs. +

+ + Contact Us + +
+ ); +} + +export function BotPage({ title, overview, features, howItWorks, demo }: BotPageProps) { + return ( +
+

{title}

+ + + + {demo && {demo}} + + +
+ ); +} diff --git a/src/components/navigation/NextSection.tsx b/src/components/navigation/NextSection.tsx new file mode 100644 index 000000000..a74f75b27 --- /dev/null +++ b/src/components/navigation/NextSection.tsx @@ -0,0 +1,24 @@ +'use client'; + +import React from 'react'; +import Link from 'next/link'; + +interface NextSectionProps { + nextPage: string; + title: string; + description: string; +} + +export function NextSection({ nextPage, title, description }: NextSectionProps) { + return ( +
+

Continue Your Journey

+ +
+

{title}

+

{description}

+
+ +
+ ); +} diff --git a/src/types/bot.ts b/src/types/bot.ts new file mode 100644 index 000000000..289587bf5 --- /dev/null +++ b/src/types/bot.ts @@ -0,0 +1,19 @@ +export interface Feature { + title: string; + description: string; + icon?: string; +} + +export interface Step { + title: string; + description: string; + image?: string; +} + +export interface BotPageProps { + title: string; + overview: string; + features: Feature[]; + howItWorks: Step[]; + demo?: React.ReactNode; +} From 5968a4086eebe2a8ab027b99d017816b66842a70 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 12:00:45 +0000 Subject: [PATCH 035/293] feat: update About section with inspiring automation message Co-Authored-By: G --- app/about/page.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/about/page.tsx b/app/about/page.tsx index 781f92ae6..6f42de1a6 100644 --- a/app/about/page.tsx +++ b/app/about/page.tsx @@ -6,10 +6,16 @@ export default function About() { return (

About Botsmann

+

+ At Botsmann, we are committed to methodically automating redundant, intransparent, and + labor-intensive processes. Our mission is to free people from unpleasant tasks, giving + them back their most precious resource: time and freedom to focus on what truly matters. +

- We specialize in developing cutting-edge AI solutions that help businesses automate tasks, - enhance productivity, and unlock new possibilities. Our suite of specialized bots is designed - to tackle specific challenges across various industries. + Through innovative AI solutions and automation technologies, we transform complex, + time-consuming workflows into efficient, transparent processes. Our commitment extends + beyond mere automation – we strive to create a future where technology serves human + potential, enabling everyone to pursue meaningful endeavors.

Get in Touch

From d537541f41c75c3cfa9ed88dad668fba8c438c1f Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 13:56:11 +0000 Subject: [PATCH 036/293] feat: update project structure with professional names and descriptions Co-Authored-By: G --- app/projects/page.tsx | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/app/projects/page.tsx b/app/projects/page.tsx index 88be5b14a..da6335ffe 100644 --- a/app/projects/page.tsx +++ b/app/projects/page.tsx @@ -6,16 +6,28 @@ import Image from 'next/image'; const projects = [ { - title: 'LiberTech', - description: 'Technologies dedicated to maximizing human liberty and minimizing government power. Featuring innovative solutions like the Venmo-style government spending tracker.', - href: '/projects/libertech', - image: '/libertech.png' + title: 'Governance', + description: 'Technologies dedicated to maximizing transparency and accountability in government spending, featuring innovative solutions like the Venmo-style spending tracker.', + href: '/projects/governance', + image: '/governance.png' }, { - title: 'Roboshop', + title: 'Credit', + description: 'Enterprise-grade automation for venture credit operations. Automatically ingest and analyze portfolio company reports, monitor debt metrics, and make data-driven decisions.', + href: '/projects/credit', + image: '/credit.png' + }, + { + title: 'Shopping', description: 'AI-powered shopping assistant that finds exactly what you need with just one word. Integrating with multiple e-commerce platforms for the best results.', - href: '/projects/roboshop', - image: '/roboshop.png' + href: '/projects/shopping', + image: '/shopping.png' + }, + { + title: 'Project Finance', + description: 'Full transparency project finance and management tool. Start projects, manage funding through donations/credit/investments, track tasks and costs, with complete public visibility.', + href: '/projects/finance', + image: '/finance.png' } ]; @@ -26,7 +38,8 @@ export default function Projects() {

Projects

- Explore our ambitious projects aimed at transforming society through technology. + Explore our transformative projects focused on governance, finance, and automation. + Each project represents our commitment to transparency, efficiency, and technological innovation.

From ab3ab2c28fadf9990dfd57f0ef3a8a8c0ac80bcb Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2025 13:57:13 +0000 Subject: [PATCH 037/293] feat: update navigation to make Bots/Projects links clickable with dropdowns Co-Authored-By: G --- components/Header.tsx | 64 +++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/components/Header.tsx b/components/Header.tsx index 80532e5cb..d1d2c5132 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -47,9 +47,9 @@ export default function Header() {
); From 1b53c59701ca755542a7bcca83ab7ac5894f70f8 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2025 12:39:42 +0000 Subject: [PATCH 172/293] fix: simplify component imports to resolve infinite loop Co-Authored-By: G --- app/layout.tsx | 6 ++---- components/Header.tsx | 6 +----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/app/layout.tsx b/app/layout.tsx index 22fca6ac3..664f0845d 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,10 +1,8 @@ import { Inter } from 'next/font/google'; -import dynamic from 'next/dynamic'; +import Header from '@/components/Header'; +import Footer from '@/components/Footer'; import './globals.css'; -const Header = dynamic(() => import('@/components/Header'), { ssr: true }); -const Footer = dynamic(() => import('@/components/Footer'), { ssr: true }); - const inter = Inter({ subsets: ['latin'] }); export const metadata = { diff --git a/components/Header.tsx b/components/Header.tsx index 156cea3f1..9a0d708ca 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -1,9 +1,5 @@ import Link from 'next/link'; -import dynamic from 'next/dynamic'; - -const MobileMenu = dynamic(() => import('./MobileMenu'), { - ssr: false -}); +import MobileMenu from './MobileMenu'; export default function Header() { From b2734a14b82cd2516d31d55bb9e015a6ee52611a Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2025 12:40:13 +0000 Subject: [PATCH 173/293] fix: split menu button into separate client component Co-Authored-By: G --- components/MenuButton.tsx | 45 +++++++++++++++++++++++++++++++++++++ components/MobileMenu.tsx | 47 +++++++-------------------------------- 2 files changed, 53 insertions(+), 39 deletions(-) create mode 100644 components/MenuButton.tsx diff --git a/components/MenuButton.tsx b/components/MenuButton.tsx new file mode 100644 index 000000000..e7be06f75 --- /dev/null +++ b/components/MenuButton.tsx @@ -0,0 +1,45 @@ +'use client'; + +import React, { useState, useEffect } from 'react'; + +export function MenuButton({ onToggle }: { onToggle: (isOpen: boolean) => void }) { + const [isOpen, setIsOpen] = useState(false); + + const handleClick = () => { + const newState = !isOpen; + setIsOpen(newState); + onToggle(newState); + }; + + useEffect(() => { + const handleClickOutside = (event: Event) => { + const target = event.target as Element; + if (isOpen && !target.closest('#mobile-menu')) { + setIsOpen(false); + onToggle(false); + } + }; + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, [isOpen, onToggle]); + + return ( + + ); +} diff --git a/components/MobileMenu.tsx b/components/MobileMenu.tsx index 994c3b1bf..e075a451a 100644 --- a/components/MobileMenu.tsx +++ b/components/MobileMenu.tsx @@ -1,51 +1,20 @@ -'use client'; - -import React, { useState, useEffect, type MouseEventHandler } from 'react'; import Link from 'next/link'; -import { Fragment } from 'react'; +import { MenuButton } from './MenuButton'; export default function MobileMenu() { - const [isMenuOpen, setIsMenuOpen] = useState(false); + const [isOpen, setIsOpen] = React.useState(false); - const toggleMenu: MouseEventHandler = (e) => { - e.stopPropagation(); - setIsMenuOpen(!isMenuOpen); + const handleToggle = (state: boolean) => { + setIsOpen(state); }; - useEffect(() => { - const handleClickOutside = (event: Event) => { - const target = event.target as Element; - if (isMenuOpen && !target.closest('#mobile-menu')) { - setIsMenuOpen(false); - } - }; - document.addEventListener('mousedown', handleClickOutside); - return () => document.removeEventListener('mousedown', handleClickOutside); - }, [isMenuOpen]); - return ( - - - + <> + +
- + ); } From 357ac5ae7e6c1aca358907fa63eadf53a850d2c5 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2025 12:41:55 +0000 Subject: [PATCH 175/293] fix: make MobileMenu a server component Co-Authored-By: G --- components/MobileMenu.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/components/MobileMenu.tsx b/components/MobileMenu.tsx index d3f43c556..8bc5517f9 100644 --- a/components/MobileMenu.tsx +++ b/components/MobileMenu.tsx @@ -1,14 +1,15 @@ -'use client'; - -import React, { useState } from 'react'; import Link from 'next/link'; -import { MenuButton } from './MenuButton'; +import dynamic from 'next/dynamic'; + +const MenuButton = dynamic(() => import('./MenuButton'), { + ssr: false +}); export default function MobileMenu() { - const [isOpen, setIsOpen] = useState(false); + let isOpen = false; const handleToggle = (state: boolean) => { - setIsOpen(state); + isOpen = state; }; return ( From b1a7c8aa10fdde3f68217ffb7b451f1e791f0bc9 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2025 12:42:12 +0000 Subject: [PATCH 176/293] fix: improve type handling in menu components Co-Authored-By: G --- components/MenuButton.tsx | 6 +++++- components/MobileMenu.tsx | 13 ++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/components/MenuButton.tsx b/components/MenuButton.tsx index e7be06f75..d3f3b880d 100644 --- a/components/MenuButton.tsx +++ b/components/MenuButton.tsx @@ -2,7 +2,11 @@ import React, { useState, useEffect } from 'react'; -export function MenuButton({ onToggle }: { onToggle: (isOpen: boolean) => void }) { +interface MenuButtonProps { + onToggle: (isOpen: boolean) => void; +} + +export function MenuButton({ onToggle }: MenuButtonProps) { const [isOpen, setIsOpen] = useState(false); const handleClick = () => { diff --git a/components/MobileMenu.tsx b/components/MobileMenu.tsx index 8bc5517f9..d3f43c556 100644 --- a/components/MobileMenu.tsx +++ b/components/MobileMenu.tsx @@ -1,15 +1,14 @@ -import Link from 'next/link'; -import dynamic from 'next/dynamic'; +'use client'; -const MenuButton = dynamic(() => import('./MenuButton'), { - ssr: false -}); +import React, { useState } from 'react'; +import Link from 'next/link'; +import { MenuButton } from './MenuButton'; export default function MobileMenu() { - let isOpen = false; + const [isOpen, setIsOpen] = useState(false); const handleToggle = (state: boolean) => { - isOpen = state; + setIsOpen(state); }; return ( From 6590437b2c085236eed6a5fc53964d69c0359625 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 15 Feb 2025 12:43:47 +0000 Subject: [PATCH 177/293] fix: handle menu visibility in client component Co-Authored-By: G --- components/MenuButton.tsx | 9 +++++++++ components/MobileMenu.tsx | 12 +++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/components/MenuButton.tsx b/components/MenuButton.tsx index d3f3b880d..549cd2b7d 100644 --- a/components/MenuButton.tsx +++ b/components/MenuButton.tsx @@ -13,6 +13,15 @@ export function MenuButton({ onToggle }: MenuButtonProps) { const newState = !isOpen; setIsOpen(newState); onToggle(newState); + + // Toggle menu visibility using DOM + const menu = document.querySelector('#mobile-menu-overlay'); + if (menu) { + menu.classList.toggle('translate-y-0'); + menu.classList.toggle('opacity-100'); + menu.classList.toggle('-translate-y-full'); + menu.classList.toggle('opacity-0'); + } }; useEffect(() => { diff --git a/components/MobileMenu.tsx b/components/MobileMenu.tsx index d3f43c556..0d2fbb8ed 100644 --- a/components/MobileMenu.tsx +++ b/components/MobileMenu.tsx @@ -1,14 +1,9 @@ -'use client'; - -import React, { useState } from 'react'; import Link from 'next/link'; import { MenuButton } from './MenuButton'; export default function MobileMenu() { - const [isOpen, setIsOpen] = useState(false); - const handleToggle = (state: boolean) => { - setIsOpen(state); + // State is handled in MenuButton component }; return ( @@ -16,9 +11,8 @@ export default function MobileMenu() {