diff --git a/apps/backend/.env.example b/apps/backend/.env.example index 99961029..04b13d42 100644 --- a/apps/backend/.env.example +++ b/apps/backend/.env.example @@ -16,3 +16,4 @@ SMTP_PASSWORD= SMTP_USER_NOTIFY= SMTP_PASSWORD_NOTIFY= SMTP_PORT= +ZOHO_TOKEN= diff --git a/apps/backend/package.json b/apps/backend/package.json index b56be5fd..6ab7e5d1 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -37,6 +37,7 @@ "nodemailer": "^6.9.5", "nodemon": "^3.0.1", "puppeteer": "^20.9.0", + "zeptomail": "^6.0.0", "zod": "^3.21.4" } } diff --git a/apps/backend/src/routes/sendEmail.js b/apps/backend/src/routes/sendEmail.js index 755cdfae..73358a0a 100644 --- a/apps/backend/src/routes/sendEmail.js +++ b/apps/backend/src/routes/sendEmail.js @@ -1,6 +1,6 @@ const express = require('express'); const zod = require('zod'); -const { getTransporter } = require('../utils/getTransporter'); +const { nodemailerTransporter, zohoClient } = require('../utils/email'); const { withEmailTemplate } = require('../utils/withEmailTemplate'); const router = express.Router(); @@ -9,13 +9,70 @@ let personalTransporter; let defaultTransporter; // Initialize transporters -getTransporter(true).then((t) => { +nodemailerTransporter(true).then((t) => { personalTransporter = t; }); -getTransporter(false).then((t) => { +nodemailerTransporter(false).then((t) => { defaultTransporter = t; }); +async function sendWithNodemailer(emailData) { + const { from, to, subject, content, isPersonalEmail, replyTo } = emailData; + + const transporter = isPersonalEmail ? personalTransporter : defaultTransporter; + + if (!transporter) { + return; + } + + return await transporter.sendMail({ + from: from || '"Best from ClassroomIO" ', + to, + subject, + replyTo, + html: withEmailTemplate(content) + }); +} + +// format: "ClassroomIO Developers (via ClassroomIO.com)" +function extractNameAndEmail(str) { + // Use regular expressions to match the name and email + const regex = /"(.*?)"\s+<\s*(.*?)@(.*?)\s*>/; + const match = str.match(regex); + + if (match) { + // Extract the name and email from the match groups + const name = match[1]; + const email = match[2] + '@' + match[3]; + return { name, email }; + } else { + // Return undefined if the format doesn't match + return { name: from, email: from }; + } +} + +async function sendWithZoho(emailData) { + const { from, to, subject, content } = emailData; + + const fromData = extractNameAndEmail(from); + + return zohoClient.sendMail({ + from: { + address: fromData.email, + name: fromData.name + }, + to: [ + { + email_address: { + address: to + } + } + ], + subject, + htmlbody: content + }); +} + router.post('/', async (req, res) => { try { const mySchema = zod.array( @@ -35,26 +92,18 @@ router.post('/', async (req, res) => { Promise.all( emailDataArray.map(async (emailData) => { + let res; + try { - const { from, to, subject, content, isPersonalEmail, replyTo } = emailData; - - const transporter = isPersonalEmail ? personalTransporter : defaultTransporter; - - if (!transporter) { - return; + if (emailData.isPersonalEmail) { + res = await sendWithNodemailer(emailData); + } else { + res = await sendWithZoho(emailData); } - const res = await transporter.sendMail({ - from: from || '"Best from ClassroomIO" ', - to, - subject, - replyTo, - html: withEmailTemplate(content) - }); - console.log('Email status', res); } catch (error) { - console.error('Error sending email', error); + console.error('Error sending email', error, error?.error?.details?.[0]); } }) ); diff --git a/apps/backend/src/utils/email.js b/apps/backend/src/utils/email.js new file mode 100644 index 00000000..266613e3 --- /dev/null +++ b/apps/backend/src/utils/email.js @@ -0,0 +1,49 @@ +const { SendMailClient } = require('zeptomail'); +const nodemailer = require('nodemailer'); + +const { + ZOHO_TOKEN, + SMTP_HOST, + SMTP_PORT, + SMTP_USER, + SMTP_PASSWORD, + SMTP_USER_NOTIFY, + SMTP_PASSWORD_NOTIFY +} = process.env; + +console.log({ ZOHO_TOKEN }); + +const zohoClient = new SendMailClient({ url: 'api.zeptomail.eu/', token: ZOHO_TOKEN }); + +const nodemailerTransporter = async (isPersonal = false) => { + if ( + !SMTP_HOST || + !SMTP_PORT || + !SMTP_USER || + !SMTP_PASSWORD || + !SMTP_USER_NOTIFY || + !SMTP_PASSWORD_NOTIFY + ) { + console.error('SMTP configuration missing'); + return null; + } + + try { + const transporter = nodemailer.createTransport({ + host: SMTP_HOST, + port: parseInt(SMTP_PORT || '465', 10), + secure: true, + auth: { + user: isPersonal ? SMTP_USER : SMTP_USER_NOTIFY, + pass: isPersonal ? SMTP_PASSWORD : SMTP_PASSWORD_NOTIFY + } + }); + await transporter.verify(); + return transporter; + } catch (error) { + console.error('Transporter error:', error); + return null; + } +}; + +module.exports = { nodemailerTransporter, zohoClient }; diff --git a/apps/dashboard/src/routes/api/email/course/exercise_submission_update/+server.js b/apps/dashboard/src/routes/api/email/course/exercise_submission_update/+server.js index e8f10dec..9234c102 100644 --- a/apps/dashboard/src/routes/api/email/course/exercise_submission_update/+server.js +++ b/apps/dashboard/src/routes/api/email/course/exercise_submission_update/+server.js @@ -26,7 +26,7 @@ export async function POST({ request }) { const emailData = [ { - from: `"${orgName} (via ClassroomIO.com)" `, + from: `"${orgName} (via ClassroomIO.com)" `, to, subject: `[Submitted]: ${exerciseTitle}`, content diff --git a/apps/dashboard/src/routes/api/email/course/newsfeed/+server.ts b/apps/dashboard/src/routes/api/email/course/newsfeed/+server.ts index 71a3b316..47e190e8 100644 --- a/apps/dashboard/src/routes/api/email/course/newsfeed/+server.ts +++ b/apps/dashboard/src/routes/api/email/course/newsfeed/+server.ts @@ -14,7 +14,7 @@ const sendEmailNotification = async (feedId: string, authorId: string, comment?: if (comment) { const emailData = [ { - from: `"${feed.org.name} - ClassroomIO" `, + from: `"${feed.org.name} - ClassroomIO" `, to: feed.teacherEmail, subject: `[${feed.courseTitle}] - News feed comment`, content: ` @@ -42,7 +42,7 @@ const sendEmailNotification = async (feedId: string, authorId: string, comment?: // else send to everyone except the author of the post const emailsData = feed.courseMembers.map((member) => ({ - from: `"${feed.org.name} - ClassroomIO" `, + from: `"${feed.org.name} - ClassroomIO" `, to: member.email, replyTo: feed.teacherEmail, subject: `[${feed.courseTitle}] - New post in course`, diff --git a/apps/dashboard/src/routes/api/email/course/student_prove_payment/+server.js b/apps/dashboard/src/routes/api/email/course/student_prove_payment/+server.js index 004f35a7..48ab11d5 100644 --- a/apps/dashboard/src/routes/api/email/course/student_prove_payment/+server.js +++ b/apps/dashboard/src/routes/api/email/course/student_prove_payment/+server.js @@ -34,7 +34,7 @@ export async function POST({ request }) { const emailData = [ { - from: `"${orgName} - ClassroomIO" `, + from: `"${orgName} - ClassroomIO" `, to, replyTo: teacherEmail, subject: `[${courseName}] One more step left`, diff --git a/apps/dashboard/src/routes/api/email/course/student_welcome/+server.js b/apps/dashboard/src/routes/api/email/course/student_welcome/+server.js index 284b8e5a..07897996 100644 --- a/apps/dashboard/src/routes/api/email/course/student_welcome/+server.js +++ b/apps/dashboard/src/routes/api/email/course/student_welcome/+server.js @@ -28,7 +28,7 @@ export async function POST({ request }) { const emailData = [ { - from: `"${orgName} (via ClassroomIO.com)" `, + from: `"${orgName} (via ClassroomIO.com)" `, to, subject: `${orgName} - Welcome to Class 🎉`, content: ` diff --git a/apps/dashboard/src/routes/api/email/course/submission_update/+server.js b/apps/dashboard/src/routes/api/email/course/submission_update/+server.js index c26dc5b7..41ff3cad 100644 --- a/apps/dashboard/src/routes/api/email/course/submission_update/+server.js +++ b/apps/dashboard/src/routes/api/email/course/submission_update/+server.js @@ -26,7 +26,7 @@ export async function POST({ request }) { const emailData = [ { - from: `"${orgName} (via ClassroomIO.com)" `, + from: `"${orgName} (via ClassroomIO.com)" `, to, subject: 'Submission Update', content diff --git a/apps/dashboard/src/routes/api/email/course/teacher_student_buycourse/+server.js b/apps/dashboard/src/routes/api/email/course/teacher_student_buycourse/+server.js index cb7c4e62..60de5dfe 100644 --- a/apps/dashboard/src/routes/api/email/course/teacher_student_buycourse/+server.js +++ b/apps/dashboard/src/routes/api/email/course/teacher_student_buycourse/+server.js @@ -33,7 +33,7 @@ export async function POST({ request }) { const emailData = [ { - from: `ClassroomIO" `, + from: `"ClassroomIO" `, to, subject: `[${courseName}] Request to Join Course!`, content: ` diff --git a/apps/dashboard/src/routes/api/email/course/teacher_student_joined/+server.js b/apps/dashboard/src/routes/api/email/course/teacher_student_joined/+server.js index 36d680bb..6c9235dd 100644 --- a/apps/dashboard/src/routes/api/email/course/teacher_student_joined/+server.js +++ b/apps/dashboard/src/routes/api/email/course/teacher_student_joined/+server.js @@ -27,7 +27,7 @@ export async function POST({ request }) { const emailData = [ { - from: `"ClassroomIO" `, + from: `"ClassroomIO" `, to, subject: `[${courseName}] You've got a new student 🎉!`, content: ` diff --git a/apps/dashboard/src/routes/api/email/course/teacher_welcome/+server.js b/apps/dashboard/src/routes/api/email/course/teacher_welcome/+server.js index ddbff5a7..3939488b 100644 --- a/apps/dashboard/src/routes/api/email/course/teacher_welcome/+server.js +++ b/apps/dashboard/src/routes/api/email/course/teacher_welcome/+server.js @@ -30,7 +30,7 @@ export async function POST({ request }) { const emailData = [ { - from: `"${orgName} (via ClassroomIO.com)" `, + from: `"${orgName} (via ClassroomIO.com)" `, to, subject: `You have been invited to a course in ${orgName}!`, content: ` diff --git a/apps/dashboard/src/routes/api/email/welcome/+server.js b/apps/dashboard/src/routes/api/email/welcome/+server.js index 647313e8..2d15d1ba 100644 --- a/apps/dashboard/src/routes/api/email/welcome/+server.js +++ b/apps/dashboard/src/routes/api/email/welcome/+server.js @@ -51,6 +51,7 @@ export async function POST({ request }) { isPersonalEmail: true } ]; + await sendEmail(emailData); return json({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0551f567..87486f77 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -98,6 +98,9 @@ importers: puppeteer: specifier: ^20.9.0 version: 20.9.0(typescript@5.3.2) + zeptomail: + specifier: ^6.0.0 + version: 6.0.0 zod: specifier: ^3.21.4 version: 3.22.4 @@ -158,7 +161,7 @@ importers: version: 5.1.6 vite: specifier: ^4.4.2 - version: 4.4.8(@types/node@22.2.0)(sass@1.64.2) + version: 4.4.8(@types/node@18.11.10)(sass@1.64.2) apps/dashboard: dependencies: @@ -357,7 +360,7 @@ importers: version: 3.1.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.2.0)(ts-node@10.9.2) + version: 29.7.0(@types/node@18.11.10)(ts-node@10.9.2) postcss: specifier: ^8.4.24 version: 8.4.24 @@ -396,7 +399,7 @@ importers: version: 29.1.1(@babel/core@7.22.9)(babel-jest@29.7.0)(jest@29.7.0)(typescript@5.1.6) ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@22.2.0)(typescript@5.1.6) + version: 10.9.2(@types/node@18.11.10)(typescript@5.1.6) tsconfig: specifier: workspace:* version: link:../../packages/tsconfig @@ -408,7 +411,7 @@ importers: version: 5.1.6 vite: specifier: ^4.4.8 - version: 4.4.8(@types/node@22.2.0)(sass@1.64.2) + version: 4.4.8(@types/node@18.11.10)(sass@1.64.2) apps/docs: dependencies: @@ -1637,7 +1640,7 @@ packages: '@babel/traverse': 7.23.4 '@babel/types': 7.23.4 convert-source-map: 1.9.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -1660,7 +1663,7 @@ packages: '@babel/traverse': 7.23.4 '@babel/types': 7.23.4 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -1683,7 +1686,7 @@ packages: '@babel/traverse': 7.23.9 '@babel/types': 7.23.9 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -1817,7 +1820,7 @@ packages: '@babel/core': 7.22.9 '@babel/helper-compilation-targets': 7.22.15 '@babel/helper-plugin-utils': 7.22.5 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -3137,7 +3140,7 @@ packages: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.23.4 '@babel/types': 7.23.4 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -3155,7 +3158,7 @@ packages: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.23.9 '@babel/types': 7.23.9 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -3514,7 +3517,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) espree: 9.6.1 globals: 13.23.0 ignore: 5.3.0 @@ -3584,7 +3587,7 @@ packages: engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 2.0.1 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -4346,8 +4349,8 @@ packages: typescript: optional: true dependencies: - debug: 4.3.4(supports-color@5.5.0) - extract-zip: 2.0.1 + debug: 4.3.4(supports-color@8.1.1) + extract-zip: 2.0.1(supports-color@8.1.1) progress: 2.0.3 proxy-agent: 6.3.0 tar-fs: 3.0.4 @@ -5819,7 +5822,7 @@ packages: sirv: 2.0.3 svelte: 4.1.2 undici: 5.22.1 - vite: 4.4.8(@types/node@22.2.0)(sass@1.64.2) + vite: 4.4.8(@types/node@18.11.10)(sass@1.64.2) transitivePeerDependencies: - supports-color dev: true @@ -5847,7 +5850,7 @@ packages: svelte: 4.1.2 tiny-glob: 0.2.9 undici: 5.26.5 - vite: 4.4.8(@types/node@22.2.0)(sass@1.64.2) + vite: 4.4.8(@types/node@18.11.10)(sass@1.64.2) transitivePeerDependencies: - supports-color @@ -5860,9 +5863,9 @@ packages: vite: ^4.0.0 dependencies: '@sveltejs/vite-plugin-svelte': 2.5.3(svelte@4.1.2)(vite@4.4.8) - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) svelte: 4.1.2 - vite: 4.4.8(@types/node@22.2.0)(sass@1.64.2) + vite: 4.4.8(@types/node@18.11.10)(sass@1.64.2) transitivePeerDependencies: - supports-color @@ -5874,13 +5877,13 @@ packages: vite: ^4.0.0 dependencies: '@sveltejs/vite-plugin-svelte-inspector': 1.0.4(@sveltejs/vite-plugin-svelte@2.5.3)(svelte@4.1.2)(vite@4.4.8) - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.5 svelte: 4.1.2 svelte-hmr: 0.15.3(svelte@4.1.2) - vite: 4.4.8(@types/node@22.2.0)(sass@1.64.2) + vite: 4.4.8(@types/node@18.11.10)(sass@1.64.2) vitefu: 0.2.5(vite@4.4.8) transitivePeerDependencies: - supports-color @@ -5963,7 +5966,7 @@ packages: chalk: 3.0.0 css.escape: 1.5.1 dom-accessibility-api: 0.5.16 - jest: 29.7.0(@types/node@22.2.0)(ts-node@10.9.2) + jest: 29.7.0(@types/node@18.11.10)(ts-node@10.9.2) lodash: 4.17.21 redent: 3.0.0 dev: true @@ -6176,11 +6179,6 @@ packages: /@types/node@18.11.10: resolution: {integrity: sha512-juG3RWMBOqcOuXC643OAdSA525V44cVgGV6dUDuiFtss+8Fk5x1hI93Rsld43VeJVIeqlP9I7Fn9/qaVqoEAuQ==} - /@types/node@22.2.0: - resolution: {integrity: sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==} - dependencies: - undici-types: 6.13.0 - /@types/nodemailer@6.4.11: resolution: {integrity: sha512-Ld2c0frwpGT4VseuoeboCXQ7UJIkK3X7Lx/4YsZEiUHtHsthWAOCYtf6PAiLhMtfwV0cWJRabLBS3+LD8x6Nrw==} dependencies: @@ -6298,7 +6296,7 @@ packages: '@typescript-eslint/type-utils': 6.12.0(eslint@8.57.0)(typescript@5.3.2) '@typescript-eslint/utils': 6.12.0(eslint@8.57.0)(typescript@5.3.2) '@typescript-eslint/visitor-keys': 6.12.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.0 @@ -6324,7 +6322,7 @@ packages: '@typescript-eslint/types': 6.12.0 '@typescript-eslint/typescript-estree': 6.12.0(typescript@5.3.2) '@typescript-eslint/visitor-keys': 6.12.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 typescript: 5.3.2 transitivePeerDependencies: @@ -6359,7 +6357,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 6.12.0(typescript@5.3.2) '@typescript-eslint/utils': 6.12.0(eslint@8.57.0)(typescript@5.3.2) - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 ts-api-utils: 1.0.3(typescript@5.3.2) typescript: 5.3.2 @@ -6388,7 +6386,7 @@ packages: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 @@ -6409,7 +6407,7 @@ packages: dependencies: '@typescript-eslint/types': 6.12.0 '@typescript-eslint/visitor-keys': 6.12.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 @@ -6684,7 +6682,7 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: false @@ -6693,7 +6691,7 @@ packages: resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} engines: {node: '>= 14'} dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -8219,7 +8217,7 @@ packages: path-type: 4.0.0 dev: false - /create-jest@29.7.0(@types/node@22.2.0)(ts-node@10.9.2): + /create-jest@29.7.0(@types/node@18.11.10)(ts-node@10.9.2): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -8228,7 +8226,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@22.2.0)(ts-node@10.9.2) + jest-config: 29.7.0(@types/node@18.11.10)(ts-node@10.9.2) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -8754,6 +8752,7 @@ packages: dependencies: ms: 2.1.2 supports-color: 5.5.0 + dev: false /debug@4.3.4(supports-color@8.1.1): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} @@ -8766,7 +8765,6 @@ packages: dependencies: ms: 2.1.2 supports-color: 8.1.1 - dev: true /debug@4.3.6: resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} @@ -9440,7 +9438,7 @@ packages: eslint: '*' eslint-plugin-import: '*' dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) enhanced-resolve: 5.15.0 eslint: 8.57.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.12.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) @@ -9637,7 +9635,7 @@ packages: dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@jridgewell/sourcemap-codec': 1.4.15 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 eslint-compat-utils: 0.1.2(eslint@8.57.0) esutils: 2.0.3 @@ -9749,7 +9747,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -10091,20 +10089,6 @@ packages: /extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - /extract-zip@2.0.1: - resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} - engines: {node: '>= 10.17.0'} - hasBin: true - dependencies: - debug: 4.3.4(supports-color@5.5.0) - get-stream: 5.2.0 - yauzl: 2.10.0 - optionalDependencies: - '@types/yauzl': 2.10.3 - transitivePeerDependencies: - - supports-color - dev: false - /extract-zip@2.0.1(supports-color@8.1.1): resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} engines: {node: '>= 10.17.0'} @@ -10117,7 +10101,6 @@ packages: '@types/yauzl': 2.10.3 transitivePeerDependencies: - supports-color - dev: true /extsprintf@1.3.0: resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} @@ -10494,7 +10477,7 @@ packages: dependencies: basic-ftp: 5.0.4 data-uri-to-buffer: 6.0.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) fs-extra: 11.2.0 transitivePeerDependencies: - supports-color @@ -10739,7 +10722,6 @@ packages: /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - dev: true /has-property-descriptors@1.0.1: resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} @@ -11009,7 +10991,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: false @@ -11028,7 +11010,7 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: false @@ -11038,7 +11020,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -11173,7 +11155,7 @@ packages: dependencies: '@ioredis/commands': 1.2.0 cluster-key-slot: 1.1.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -11587,7 +11569,7 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -11664,7 +11646,7 @@ packages: - supports-color dev: true - /jest-cli@29.7.0(@types/node@22.2.0)(ts-node@10.9.2): + /jest-cli@29.7.0(@types/node@18.11.10)(ts-node@10.9.2): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -11678,10 +11660,10 @@ packages: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.2.0)(ts-node@10.9.2) + create-jest: 29.7.0(@types/node@18.11.10)(ts-node@10.9.2) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@22.2.0)(ts-node@10.9.2) + jest-config: 29.7.0(@types/node@18.11.10)(ts-node@10.9.2) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -11727,48 +11709,7 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.2(@types/node@22.2.0)(typescript@5.1.6) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - dev: true - - /jest-config@29.7.0(@types/node@22.2.0)(ts-node@10.9.2): - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true - dependencies: - '@babel/core': 7.23.3 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.2.0 - babel-jest: 29.7.0(@babel/core@7.23.3) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - ts-node: 10.9.2(@types/node@22.2.0)(typescript@5.1.6) + ts-node: 10.9.2(@types/node@18.11.10)(typescript@5.1.6) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -12057,7 +11998,7 @@ packages: supports-color: 8.1.1 dev: true - /jest@29.7.0(@types/node@22.2.0)(ts-node@10.9.2): + /jest@29.7.0(@types/node@18.11.10)(ts-node@10.9.2): resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -12070,7 +12011,7 @@ packages: '@jest/core': 29.7.0(ts-node@10.9.2) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@22.2.0)(ts-node@10.9.2) + jest-cli: 29.7.0(@types/node@18.11.10)(ts-node@10.9.2) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -13253,7 +13194,7 @@ packages: resolution: {integrity: sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==} dependencies: '@types/debug': 4.1.12 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) decode-named-character-reference: 1.0.2 micromark-core-commonmark: 1.1.0 micromark-factory-space: 1.1.0 @@ -14064,7 +14005,7 @@ packages: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) get-uri: 6.0.3 http-proxy-agent: 7.0.1 https-proxy-agent: 7.0.4 @@ -14321,7 +14262,7 @@ packages: dependencies: lilconfig: 2.1.0 postcss: 8.4.24 - ts-node: 10.9.2(@types/node@22.2.0)(typescript@5.1.6) + ts-node: 10.9.2(@types/node@18.11.10)(typescript@5.1.6) yaml: 2.3.4 dev: true @@ -14339,7 +14280,7 @@ packages: dependencies: lilconfig: 2.1.0 postcss: 8.4.32 - ts-node: 10.9.2(@types/node@22.2.0)(typescript@5.1.6) + ts-node: 10.9.2(@types/node@18.11.10)(typescript@5.1.6) yaml: 2.3.4 /postcss-nested@6.0.1(postcss@8.4.32): @@ -14638,7 +14579,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) http-proxy-agent: 7.0.1 https-proxy-agent: 7.0.4 lru-cache: 7.18.3 @@ -14692,7 +14633,7 @@ packages: '@puppeteer/browsers': 1.4.6(typescript@5.3.2) chromium-bidi: 0.4.16(devtools-protocol@0.0.1147663) cross-fetch: 4.0.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) devtools-protocol: 0.0.1147663 typescript: 5.3.2 ws: 8.13.0 @@ -15564,7 +15505,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) socks: 2.7.3 transitivePeerDependencies: - supports-color @@ -16044,7 +15985,6 @@ packages: engines: {node: '>=10'} dependencies: has-flag: 4.0.0 - dev: true /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} @@ -16132,7 +16072,7 @@ packages: jest: '>= 27' svelte: '>= 3' dependencies: - jest: 29.7.0(@types/node@22.2.0)(ts-node@10.9.2) + jest: 29.7.0(@types/node@18.11.10)(ts-node@10.9.2) svelte: 4.1.2 dev: true @@ -16684,7 +16624,7 @@ packages: babel-jest: 29.7.0(@babel/core@7.22.9) bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.2.0)(ts-node@10.9.2) + jest: 29.7.0(@types/node@18.11.10)(ts-node@10.9.2) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -16694,7 +16634,7 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-node@10.9.2(@types/node@22.2.0)(typescript@5.1.6): + /ts-node@10.9.2(@types/node@18.11.10)(typescript@5.1.6): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: @@ -16713,7 +16653,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.2.0 + '@types/node': 18.11.10 acorn: 8.11.2 acorn-walk: 8.3.1 arg: 4.1.3 @@ -16972,9 +16912,6 @@ packages: resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} dev: false - /undici-types@6.13.0: - resolution: {integrity: sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==} - /undici@5.22.1: resolution: {integrity: sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==} engines: {node: '>=14.0'} @@ -17372,7 +17309,7 @@ packages: vfile-message: 4.0.2 dev: false - /vite@4.4.8(@types/node@22.2.0)(sass@1.64.2): + /vite@4.4.8(@types/node@18.11.10)(sass@1.64.2): resolution: {integrity: sha512-LONawOUUjxQridNWGQlNizfKH89qPigK36XhMI7COMGztz8KNY0JHim7/xDd71CZwGT4HtSRgI7Hy+RlhG0Gvg==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -17400,7 +17337,7 @@ packages: terser: optional: true dependencies: - '@types/node': 22.2.0 + '@types/node': 18.11.10 esbuild: 0.18.20 postcss: 8.4.32 rollup: 3.29.4 @@ -17416,7 +17353,7 @@ packages: vite: optional: true dependencies: - vite: 4.4.8(@types/node@22.2.0)(sass@1.64.2) + vite: 4.4.8(@types/node@18.11.10)(sass@1.64.2) /vscode-oniguruma@1.7.0: resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} @@ -17798,6 +17735,14 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + /zeptomail@6.0.0: + resolution: {integrity: sha512-RO7xOBGVGthxMK4IsOVWdkNUAxn1VGFer8Awo+t7KMaO/8xMgQtSGqFcjr48SeYbzDuw6U1FKfpRmeyXt7edOA==} + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + dev: false + /zod@3.21.4: resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} dev: false