diff --git a/.env.template b/.env.template index 2de8b1afb..ab9818278 100644 --- a/.env.template +++ b/.env.template @@ -27,3 +27,5 @@ AWS_SECRET_ACCESS_KEY=_ GOOGLE_CLIENT_ID=_ GOOGLE_CLIENT_SECRET=_ SESSION_SECRET=_ + +SENDGRID_API_KEY=_ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7a8da287a..c8c7f8b3c 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ generated-types/ # others *.cert *.key + +prod-backup.gz diff --git a/apps/backend/package.json b/apps/backend/package.json index c3c6f47bc..914a6c7e1 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -41,6 +41,8 @@ "@repo/common": "*", "@repo/shared": "*", "@repo/sis-api": "*", + "@types/node-cron": "^3.0.11", + "@types/nodemailer": "^7.0.2", "compression": "^1.8.1", "connect-redis": "^9.0.0", "cors": "^2.8.5", @@ -55,7 +57,9 @@ "keyv": "^5.5.3", "lodash": "^4.17.21", "mongodb": "^6.20.0", - "mongoose": "^8.19.1", + "mongoose": "^8.17.0", + "node-cron": "^4.2.1", + "nodemailer": "^7.0.7", "papaparse": "^5.5.3", "passport": "^0.7.0", "passport-google-oauth20": "^2.0.0", diff --git a/apps/backend/src/modules/user/controller.ts b/apps/backend/src/modules/user/controller.ts index 6475bb56b..e29b29bee 100644 --- a/apps/backend/src/modules/user/controller.ts +++ b/apps/backend/src/modules/user/controller.ts @@ -79,3 +79,39 @@ export const getBookmarkedClasses = async ( return classes.map(formatClass); }; + +export const getMonitoredClasses = async ( + monitoredClasses: + | UserModule.MonitoredClassInput[] + | UserModule.MonitoredClass[] +) => { + const filters = monitoredClasses.map((mc) => { + const c = mc.class; + return { + year: c.year, + semester: c.semester, + sessionId: c.sessionId ?? "1", + subject: c.subject, + courseNumber: c.courseNumber, + number: c.number, + }; + }); + + const docs = await ClassModel.find({ $or: filters }).lean(); + const classKey = (c: any) => + `${c.year}-${c.semester}-${c.sessionId ?? "1"}-${c.subject}-${c.courseNumber}-${c.number}`; + const docsByKey = new Map(docs.map((d) => [classKey(d), d])); + + return monitoredClasses + .map((mc) => { + const key = classKey(mc.class); + const doc = docsByKey.get(key); + if (!doc) return null; + + return { + class: formatClass(doc), + thresholds: mc.thresholds, + }; + }) + .filter(Boolean); +}; diff --git a/apps/backend/src/modules/user/formatter.ts b/apps/backend/src/modules/user/formatter.ts index 97c01cef0..11fdbaf96 100644 --- a/apps/backend/src/modules/user/formatter.ts +++ b/apps/backend/src/modules/user/formatter.ts @@ -5,6 +5,7 @@ import { UserModule } from "./generated-types/module-types"; interface UserRelationships { bookmarkedCourses: UserModule.BookmarkedCourseInput[]; bookmarkedClasses: UserModule.BookmarkedClassInput[]; + monitoredClasses: UserModule.MonitoredClassInput[]; } export type IntermediateUser = Omit & @@ -21,5 +22,7 @@ export const formatUser = (user: UserType) => { bookmarkedClasses: user.bookmarkedClasses, majors: user.majors ? user.majors : [], minors: user.minors ? user.minors : [], + monitoredClasses: user.monitoredClasses, + notificationsOn: user.notificationsOn, } as IntermediateUser; }; diff --git a/apps/backend/src/modules/user/resolver.ts b/apps/backend/src/modules/user/resolver.ts index f19b82208..f27714c81 100644 --- a/apps/backend/src/modules/user/resolver.ts +++ b/apps/backend/src/modules/user/resolver.ts @@ -1,6 +1,7 @@ import { getBookmarkedClasses, getBookmarkedCourses, + getMonitoredClasses, getUser, updateUser, } from "./controller"; @@ -40,6 +41,21 @@ const resolvers: UserModule.Resolvers = { return courses as unknown as UserModule.Course[]; }, + + monitoredClasses: async (parent: UserModule.User | IntermediateUser) => { + if ( + parent.monitoredClasses[0] && + (parent.monitoredClasses[0] as UserModule.MonitoredClass).class + ) { + return parent.monitoredClasses as UserModule.MonitoredClass[]; + } + + const monitoredClasses = await getMonitoredClasses( + parent.monitoredClasses + ); + + return monitoredClasses as unknown as UserModule.MonitoredClass[]; + }, }, Mutation: { diff --git a/apps/backend/src/modules/user/typedefs/user.ts b/apps/backend/src/modules/user/typedefs/user.ts index ef579a2a3..b9f6f956e 100644 --- a/apps/backend/src/modules/user/typedefs/user.ts +++ b/apps/backend/src/modules/user/typedefs/user.ts @@ -1,6 +1,11 @@ import { gql } from "graphql-tag"; const typedef = gql` + type MonitoredClass { + class: Class! + thresholds: [Float]! + } + type User @cacheControl(scope: PRIVATE) { _id: ID! email: String! @@ -11,6 +16,8 @@ const typedef = gql` bookmarkedClasses: [Class!]! majors: [String!]! minors: [String!]! + monitoredClasses: [MonitoredClass!]! + notificationsOn: Boolean! } type Query { @@ -31,11 +38,41 @@ const typedef = gql` number: ClassNumber! } + input MonitoredClassRefInput { + year: Int! + semester: Semester! + sessionId: SessionIdentifier + subject: String! + courseNumber: CourseNumber! + number: ClassNumber! + } + + input MonitoredClassInput { + class: MonitoredClassRefInput! + thresholds: [Float!]! + } + + input MonitoredClassRefInput { + year: Int! + semester: Semester! + sessionId: SessionIdentifier + subject: String! + courseNumber: CourseNumber! + number: ClassNumber! + } + + input MonitoredClassInput { + class: MonitoredClassRefInput! + thresholds: [Float!]! + } + input UpdateUserInput { bookmarkedClasses: [BookmarkedClassInput!] bookmarkedCourses: [BookmarkedCourseInput!] majors: [String!] minors: [String!] + monitoredClasses: [MonitoredClassInput!] + notificationsOn: Boolean! } type Mutation { diff --git a/apps/datapuller/package.json b/apps/datapuller/package.json index e6fd0b074..80463842d 100644 --- a/apps/datapuller/package.json +++ b/apps/datapuller/package.json @@ -19,6 +19,7 @@ "@repo/sis-api": "*", "dotenv": "^17.2.3", "luxon": "^3.7.2", + "@sendgrid/mail": "^8.1.4", "papaparse": "^5.5.3", "tslog": "^4.10.2" } diff --git a/apps/datapuller/src/pullers/enrollment.ts b/apps/datapuller/src/pullers/enrollment.ts index 47e265e94..6590a845a 100644 --- a/apps/datapuller/src/pullers/enrollment.ts +++ b/apps/datapuller/src/pullers/enrollment.ts @@ -1,19 +1,56 @@ +import sgMail from "@sendgrid/mail"; import { DateTime } from "luxon"; +import { readFileSync } from "fs"; +import { join, dirname } from "path"; +import { fileURLToPath } from "url"; import { IEnrollmentSingularItem, NewEnrollmentHistoryModel, TermModel, + UserModel, } from "@repo/common"; import { GRANULARITY, getEnrollmentSingulars } from "../lib/enrollment"; import { Config } from "../shared/config"; +import { getActiveTerms } from "../shared/term-selectors"; // duration of time in seconds that can pass before being considered a data gap const DATAGAP_THRESHOLD = 4 * GRANULARITY; const TERMS_PER_API_BATCH = 4; +interface EnrollmentThreshold { + percentage: number; + name: string; +} + +const ENROLLMENT_THRESHOLDS: EnrollmentThreshold[] = [ + { percentage: 50, name: "half_full" }, + { percentage: 75, name: "three_quarters_full" }, + { percentage: 90, name: "nearly_full" }, + { percentage: 100, name: "completely_full" }, +]; + +interface EnrollmentAlert { + termId: string; + sessionId: string; + sectionId: string; + subject: string; + courseNumber: string; + sectionNumber: string; + year: number; + semester: string; + threshold: string; + percentage: number; + enrolledCount: number; + maxEnroll: number; + waitlistedCount: number; + maxWaitlist: number; + timestamp: string; + previousPercentage?: number; +} + // enrollmentSingulars are equivalent if their data points are all equal const enrollmentSingularsEqual = ( a: IEnrollmentSingularItem["data"], @@ -63,11 +100,12 @@ const enrollmentSingularsEqual = ( return true; }; -const updateEnrollmentHistories = async ({ - log, - sis: { CLASS_APP_ID, CLASS_APP_KEY }, - backend: { url: BACKEND_URL }, -}: Config) => { +const updateEnrollmentHistories = async (config: Config) => { + const { + log, + sis: { CLASS_APP_ID, CLASS_APP_KEY }, + backend: { url: BACKEND_URL }, + } = config; log.trace(`Fetching terms...`); const now = DateTime.now(); @@ -290,6 +328,320 @@ const updateEnrollmentHistories = async ({ } } log.info("Completed catalog cache warming."); + + // Check enrollment thresholds and send notifications + await checkEnrollmentThresholds(config); +}; + +const generateEnrollmentAlertEmail = ( + userEmail: string, + userName: string, + alerts: EnrollmentAlert[] +): { to: string; from: string; subject: string; html: string } => { + const alertsList = alerts + .map( + (alert) => ` +
+

+ ${alert.subject} ${alert.courseNumber} - Section ${alert.sectionNumber} +

+

+ Enrollment Status: ${alert.threshold.replace(/_/g, " ").toUpperCase()} +

+

+ Current Enrollment: ${alert.enrolledCount}/${alert.maxEnroll} (${alert.percentage}%) +

+ ${ + alert.waitlistedCount > 0 + ? `

+ Waitlist: ${alert.waitlistedCount}/${alert.maxWaitlist} +

` + : "" + } +

+ Term: ${alert.semester} ${alert.year} +

+
+ ` + ) + .join(""); + + // Read the email template + const __filename = fileURLToPath(import.meta.url); + const __dirname = dirname(__filename); + const templatePath = join(__dirname, "../templates/enrollment-alert-email.html"); + const template = readFileSync(templatePath, "utf-8"); + + // Replace placeholders in the template + const html = template + .replace("{{userName}}", userName) + .replace("{{alertsList}}", alertsList); + + return { + to: userEmail, + from: process.env.SENDGRID_FROM_EMAIL || "octo.berkeleytime@asuc.org", + subject: `BerkeleTime Alert: ${alerts.length} class${alerts.length > 1 ? "es" : ""} reached enrollment threshold`, + html, + }; +}; + +const checkEnrollmentThresholds = async ({ log }: Config) => { + log.trace(`Starting enrollment threshold checks...`); + + const allTerms = await getActiveTerms(); + const terms = allTerms.filter((term) => { + if (term.academicCareerCode !== "UGRD") { + return false; + } + + if (!term.sessions) return true; + return term.sessions.some((session) => { + if (!session.enrollBeginDate || !session.enrollEndDate) return false; + + const now = Date.now(); + const enrollBeginDate = new Date(session.enrollBeginDate).getTime(); + const enrollEndDate = new Date(session.enrollEndDate).getTime(); + + return now >= enrollBeginDate && now <= enrollEndDate; + }); + }); + + if (terms.length === 0) { + log.warn("No active terms found for enrollment checking"); + return; + } + + const termIds = terms.map((term) => term.id); + log.info( + `Checking enrollment thresholds for ${terms.length} active terms: ${terms.map((term) => term.name).join(", ")}` + ); + + const enrollmentHistories = await NewEnrollmentHistoryModel.find({ + termId: { $in: termIds }, + }).lean(); + + log.info(`Found ${enrollmentHistories.length} enrollment histories to check`); + + const alerts: EnrollmentAlert[] = []; + let totalChecks = 0; + + for (const history of enrollmentHistories) { + if (!history.history || history.history.length < 2) { + continue; + } + + const latestData = history.history[history.history.length - 1]; + const previousData = history.history[history.history.length - 2]; + + if (!latestData.enrolledCount || !latestData.maxEnroll) { + continue; + } + + totalChecks++; + + const currentPercentage = Math.round( + (latestData.enrolledCount / latestData.maxEnroll) * 100 + ); + + const previousPercentage = + previousData.enrolledCount && previousData.maxEnroll + ? Math.round( + (previousData.enrolledCount / previousData.maxEnroll) * 100 + ) + : undefined; + + // Check each threshold + for (const threshold of ENROLLMENT_THRESHOLDS) { + const crossedThreshold = + currentPercentage >= threshold.percentage && + (!previousPercentage || previousPercentage < threshold.percentage); + + if (crossedThreshold) { + alerts.push({ + termId: history.termId, + sessionId: history.sessionId, + sectionId: history.sectionId, + subject: history.subject, + courseNumber: history.courseNumber, + sectionNumber: history.sectionNumber, + year: history.year, + semester: history.semester, + threshold: threshold.name, + percentage: currentPercentage, + enrolledCount: latestData.enrolledCount, + maxEnroll: latestData.maxEnroll, + waitlistedCount: latestData.waitlistedCount || 0, + maxWaitlist: latestData.maxWaitlist || 0, + timestamp: latestData.endTime.toString(), + previousPercentage, + }); + } + } + } + + log.info(`Completed ${totalChecks} enrollment checks`); + + if (alerts.length > 0) { + log.info(`Found ${alerts.length} enrollment threshold alerts:`); + + const alertsByThreshold = alerts.reduce( + (acc, alert) => { + if (!acc[alert.threshold]) { + acc[alert.threshold] = []; + } + acc[alert.threshold].push(alert); + return acc; + }, + {} as Record + ); + + for (const [threshold, thresholdAlerts] of Object.entries( + alertsByThreshold + )) { + log.info(` ${threshold}: ${thresholdAlerts.length} sections`); + + thresholdAlerts.slice(0, 3).forEach((alert) => { + log.info( + ` ${alert.subject} ${alert.courseNumber} ${alert.sectionNumber} - ${alert.percentage}% (${alert.enrolledCount}/${alert.maxEnroll})` + ); + }); + + if (thresholdAlerts.length > 3) { + log.info(` ... and ${thresholdAlerts.length - 3} more`); + } + } + + const usersToNotify = new Map>(); + + for (const alert of alerts) { + const thresholdPercentage = ENROLLMENT_THRESHOLDS.find( + (t) => t.name === alert.threshold + )?.percentage; + + if (!thresholdPercentage) { + continue; + } + + const matchingUsers = await UserModel.find({ + notificationsOn: true, + monitoredClasses: { + $elemMatch: { + "class.year": alert.year, + "class.semester": alert.semester, + "class.subject": alert.subject, + "class.courseNumber": alert.courseNumber, + "class.number": alert.sectionNumber, + }, + }, + }).lean(); + + for (const user of matchingUsers) { + const monitoredClass = user.monitoredClasses?.find( + (mc) => + mc.class && + mc.class.year === alert.year && + mc.class.semester === alert.semester && + mc.class.subject === alert.subject && + mc.class.courseNumber === alert.courseNumber && + mc.class.number === alert.sectionNumber + ); + + if ( + monitoredClass && + monitoredClass.thresholds.includes(thresholdPercentage) + ) { + const userId = user._id.toString(); + if (!usersToNotify.has(userId)) { + usersToNotify.set(userId, new Set()); + } + usersToNotify.get(userId)!.add(alert); + } + } + } + + log.info(`Found ${usersToNotify.size} users to notify`); + + // Initialize SendGrid + const sendgridApiKey = process.env.SENDGRID_API_KEY; + if (!sendgridApiKey) { + log.warn("SENDGRID_API_KEY not set - skipping email notifications"); + } else { + sgMail.setApiKey(sendgridApiKey); + } + + let emailsSent = 0; + let emailsFailed = 0; + let emailsThrottled = 0; + + for (const [userId, userAlerts] of usersToNotify.entries()) { + log.info(` User ${userId}: ${userAlerts.size} alert(s)`); + + // Get user email for notifications + const user = await UserModel.findById(userId).lean(); + if (!user) { + log.warn(` User ${userId} not found, skipping`); + continue; + } + + // Only send email notifications + if (!user.notificationsOn) { + log.info(`User has notifications off, skipping email`); + continue; + } + + // Check if user was notified less than 2 hours ago + if (user.lastNotified) { + const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000); + if (new Date(user.lastNotified) > twoHoursAgo) { + emailsThrottled++; + log.info( + ` User was notified less than 2 hours ago, skipping email` + ); + continue; + } + } + + for (const alert of userAlerts) { + log.info( + ` - ${alert.subject} ${alert.courseNumber} ${alert.sectionNumber}: ${alert.threshold} (${alert.percentage}%)` + ); + } + + // Send email if SendGrid is configured + if (sendgridApiKey && user.email) { + try { + const emailData = generateEnrollmentAlertEmail( + user.email, + user.name, + Array.from(userAlerts) + ); + + await sgMail.send(emailData); + + // Update lastNotified after successfully sending email + await UserModel.findByIdAndUpdate(userId, { + lastNotified: new Date(), + }); + + emailsSent++; + log.info(` ✓ Email sent to ${user.email}`); + } catch (error) { + emailsFailed++; + log.error(` ✗ Failed to send email to ${user.email}:`, error); + } + } + } + + if (sendgridApiKey) { + log.info( + `Email notifications: ${emailsSent} sent, ${emailsFailed} failed, ${emailsThrottled} throttled` + ); + } else { + log.info("Email sending skipped - SENDGRID_API_KEY not configured"); + } + } else { + log.info("No enrollment threshold alerts detected"); + } }; export default { updateEnrollmentHistories }; diff --git a/apps/datapuller/src/templates/enrollment-alert-email.html b/apps/datapuller/src/templates/enrollment-alert-email.html new file mode 100644 index 000000000..1f3a57063 --- /dev/null +++ b/apps/datapuller/src/templates/enrollment-alert-email.html @@ -0,0 +1,26 @@ + + + + + + + +
+

BerkeleTime Enrollment Alert

+

Your monitored classes have reached enrollment thresholds

+
+ +
+

Hello {{userName}},

+

The following classes you're monitoring have crossed their enrollment thresholds:

+
+ + {{alertsList}} + +
+

You're receiving this email because you've set up enrollment notifications on BerkeleTime.

+

To manage your notification settings, please visit your profile page.

+
+ + + diff --git a/package-lock.json b/package-lock.json index a244a7999..e64103c54 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,6 +67,8 @@ "@repo/common": "*", "@repo/shared": "*", "@repo/sis-api": "*", + "@types/node-cron": "^3.0.11", + "@types/nodemailer": "^7.0.2", "compression": "^1.8.1", "connect-redis": "^9.0.0", "cors": "^2.8.5", @@ -81,7 +83,9 @@ "keyv": "^5.5.3", "lodash": "^4.17.21", "mongodb": "^6.20.0", - "mongoose": "^8.19.1", + "mongoose": "^8.17.0", + "node-cron": "^4.2.1", + "nodemailer": "^7.0.7", "papaparse": "^5.5.3", "passport": "^0.7.0", "passport-google-oauth20": "^2.0.0", @@ -114,6 +118,7 @@ "@aws-sdk/client-s3": "^3.901.0", "@repo/common": "*", "@repo/sis-api": "*", + "@sendgrid/mail": "^8.1.4", "dotenv": "^17.2.3", "luxon": "^3.7.2", "papaparse": "^5.5.3", @@ -727,59 +732,602 @@ "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.901.0", - "@aws-sdk/credential-provider-node": "3.901.0", - "@aws-sdk/middleware-bucket-endpoint": "3.901.0", - "@aws-sdk/middleware-expect-continue": "3.901.0", - "@aws-sdk/middleware-flexible-checksums": "3.901.0", - "@aws-sdk/middleware-host-header": "3.901.0", - "@aws-sdk/middleware-location-constraint": "3.901.0", - "@aws-sdk/middleware-logger": "3.901.0", - "@aws-sdk/middleware-recursion-detection": "3.901.0", - "@aws-sdk/middleware-sdk-s3": "3.901.0", - "@aws-sdk/middleware-ssec": "3.901.0", - "@aws-sdk/middleware-user-agent": "3.901.0", - "@aws-sdk/region-config-resolver": "3.901.0", - "@aws-sdk/signature-v4-multi-region": "3.901.0", - "@aws-sdk/types": "3.901.0", - "@aws-sdk/util-endpoints": "3.901.0", - "@aws-sdk/util-user-agent-browser": "3.901.0", - "@aws-sdk/util-user-agent-node": "3.901.0", - "@aws-sdk/xml-builder": "3.901.0", - "@smithy/config-resolver": "^4.3.0", - "@smithy/core": "^3.14.0", - "@smithy/eventstream-serde-browser": "^4.2.0", - "@smithy/eventstream-serde-config-resolver": "^4.3.0", - "@smithy/eventstream-serde-node": "^4.2.0", - "@smithy/fetch-http-handler": "^5.3.0", - "@smithy/hash-blob-browser": "^4.2.0", - "@smithy/hash-node": "^4.2.0", - "@smithy/hash-stream-node": "^4.2.0", - "@smithy/invalid-dependency": "^4.2.0", - "@smithy/md5-js": "^4.2.0", - "@smithy/middleware-content-length": "^4.2.0", - "@smithy/middleware-endpoint": "^4.3.0", - "@smithy/middleware-retry": "^4.4.0", - "@smithy/middleware-serde": "^4.2.0", - "@smithy/middleware-stack": "^4.2.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/node-http-handler": "^4.3.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/smithy-client": "^4.7.0", - "@smithy/types": "^4.6.0", - "@smithy/url-parser": "^4.2.0", - "@smithy/util-base64": "^4.2.0", + "@aws-sdk/core": "3.857.0", + "@aws-sdk/credential-provider-node": "3.857.0", + "@aws-sdk/middleware-bucket-endpoint": "3.840.0", + "@aws-sdk/middleware-expect-continue": "3.840.0", + "@aws-sdk/middleware-flexible-checksums": "3.857.0", + "@aws-sdk/middleware-host-header": "3.840.0", + "@aws-sdk/middleware-location-constraint": "3.840.0", + "@aws-sdk/middleware-logger": "3.840.0", + "@aws-sdk/middleware-recursion-detection": "3.840.0", + "@aws-sdk/middleware-sdk-s3": "3.857.0", + "@aws-sdk/middleware-ssec": "3.840.0", + "@aws-sdk/middleware-user-agent": "3.857.0", + "@aws-sdk/region-config-resolver": "3.840.0", + "@aws-sdk/signature-v4-multi-region": "3.857.0", + "@aws-sdk/types": "3.840.0", + "@aws-sdk/util-endpoints": "3.848.0", + "@aws-sdk/util-user-agent-browser": "3.840.0", + "@aws-sdk/util-user-agent-node": "3.857.0", + "@aws-sdk/xml-builder": "3.821.0", + "@smithy/config-resolver": "^4.1.4", + "@smithy/core": "^3.7.2", + "@smithy/eventstream-serde-browser": "^4.0.4", + "@smithy/eventstream-serde-config-resolver": "^4.1.2", + "@smithy/eventstream-serde-node": "^4.0.4", + "@smithy/fetch-http-handler": "^5.1.0", + "@smithy/hash-blob-browser": "^4.0.4", + "@smithy/hash-node": "^4.0.4", + "@smithy/hash-stream-node": "^4.0.4", + "@smithy/invalid-dependency": "^4.0.4", + "@smithy/md5-js": "^4.0.4", + "@smithy/middleware-content-length": "^4.0.4", + "@smithy/middleware-endpoint": "^4.1.17", + "@smithy/middleware-retry": "^4.1.18", + "@smithy/middleware-serde": "^4.0.8", + "@smithy/middleware-stack": "^4.0.4", + "@smithy/node-config-provider": "^4.1.3", + "@smithy/node-http-handler": "^4.1.0", + "@smithy/protocol-http": "^5.1.2", + "@smithy/smithy-client": "^4.4.9", + "@smithy/types": "^4.3.1", + "@smithy/url-parser": "^4.0.4", + "@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.25", + "@smithy/util-defaults-mode-node": "^4.0.25", + "@smithy/util-endpoints": "^3.0.6", + "@smithy/util-middleware": "^4.0.4", + "@smithy/util-retry": "^4.0.6", + "@smithy/util-stream": "^4.2.3", + "@smithy/util-utf8": "^4.0.0", + "@smithy/util-waiter": "^4.0.6", + "@types/uuid": "^9.0.1", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2": { + "version": "3.913.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sesv2/-/client-sesv2-3.913.0.tgz", + "integrity": "sha512-xurdihi/HH3em6XgvI+AlolCjqu74CxyOAEEWAJBk1Xp+yqNUaYR5d1m26iI7UuTy8gAZ+48UNvQBVhUXe5ZwA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.911.0", + "@aws-sdk/credential-provider-node": "3.913.0", + "@aws-sdk/middleware-host-header": "3.910.0", + "@aws-sdk/middleware-logger": "3.910.0", + "@aws-sdk/middleware-recursion-detection": "3.910.0", + "@aws-sdk/middleware-user-agent": "3.911.0", + "@aws-sdk/region-config-resolver": "3.910.0", + "@aws-sdk/signature-v4-multi-region": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@aws-sdk/util-endpoints": "3.910.0", + "@aws-sdk/util-user-agent-browser": "3.910.0", + "@aws-sdk/util-user-agent-node": "3.911.0", + "@smithy/config-resolver": "^4.3.2", + "@smithy/core": "^3.16.1", + "@smithy/fetch-http-handler": "^5.3.3", + "@smithy/hash-node": "^4.2.2", + "@smithy/invalid-dependency": "^4.2.2", + "@smithy/middleware-content-length": "^4.2.2", + "@smithy/middleware-endpoint": "^4.3.3", + "@smithy/middleware-retry": "^4.4.3", + "@smithy/middleware-serde": "^4.2.2", + "@smithy/middleware-stack": "^4.2.2", + "@smithy/node-config-provider": "^4.3.2", + "@smithy/node-http-handler": "^4.4.1", + "@smithy/protocol-http": "^5.3.2", + "@smithy/smithy-client": "^4.8.1", + "@smithy/types": "^4.7.1", + "@smithy/url-parser": "^4.2.2", + "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.0", - "@smithy/util-defaults-mode-browser": "^4.2.0", - "@smithy/util-defaults-mode-node": "^4.2.0", - "@smithy/util-endpoints": "^3.2.0", - "@smithy/util-middleware": "^4.2.0", - "@smithy/util-retry": "^4.2.0", - "@smithy/util-stream": "^4.4.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.2", + "@smithy/util-defaults-mode-node": "^4.2.3", + "@smithy/util-endpoints": "^3.2.2", + "@smithy/util-middleware": "^4.2.2", + "@smithy/util-retry": "^4.2.2", "@smithy/util-utf8": "^4.2.0", - "@smithy/util-waiter": "^4.2.0", - "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/client-sso": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.911.0.tgz", + "integrity": "sha512-N9QAeMvN3D1ZyKXkQp4aUgC4wUMuA5E1HuVCkajc0bq1pnH4PIke36YlrDGGREqPlyLFrXCkws2gbL5p23vtlg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.911.0", + "@aws-sdk/middleware-host-header": "3.910.0", + "@aws-sdk/middleware-logger": "3.910.0", + "@aws-sdk/middleware-recursion-detection": "3.910.0", + "@aws-sdk/middleware-user-agent": "3.911.0", + "@aws-sdk/region-config-resolver": "3.910.0", + "@aws-sdk/types": "3.910.0", + "@aws-sdk/util-endpoints": "3.910.0", + "@aws-sdk/util-user-agent-browser": "3.910.0", + "@aws-sdk/util-user-agent-node": "3.911.0", + "@smithy/config-resolver": "^4.3.2", + "@smithy/core": "^3.16.1", + "@smithy/fetch-http-handler": "^5.3.3", + "@smithy/hash-node": "^4.2.2", + "@smithy/invalid-dependency": "^4.2.2", + "@smithy/middleware-content-length": "^4.2.2", + "@smithy/middleware-endpoint": "^4.3.3", + "@smithy/middleware-retry": "^4.4.3", + "@smithy/middleware-serde": "^4.2.2", + "@smithy/middleware-stack": "^4.2.2", + "@smithy/node-config-provider": "^4.3.2", + "@smithy/node-http-handler": "^4.4.1", + "@smithy/protocol-http": "^5.3.2", + "@smithy/smithy-client": "^4.8.1", + "@smithy/types": "^4.7.1", + "@smithy/url-parser": "^4.2.2", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.2", + "@smithy/util-defaults-mode-node": "^4.2.3", + "@smithy/util-endpoints": "^3.2.2", + "@smithy/util-middleware": "^4.2.2", + "@smithy/util-retry": "^4.2.2", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/core": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.911.0.tgz", + "integrity": "sha512-k4QG9A+UCq/qlDJFmjozo6R0eXXfe++/KnCDMmajehIE9kh+b/5DqlGvAmbl9w4e92LOtrY6/DN3mIX1xs4sXw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.910.0", + "@aws-sdk/xml-builder": "3.911.0", + "@smithy/core": "^3.16.1", + "@smithy/node-config-provider": "^4.3.2", + "@smithy/property-provider": "^4.2.2", + "@smithy/protocol-http": "^5.3.2", + "@smithy/signature-v4": "^5.3.2", + "@smithy/smithy-client": "^4.8.1", + "@smithy/types": "^4.7.1", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.2", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.911.0.tgz", + "integrity": "sha512-6FWRwWn3LUZzLhqBXB+TPMW2ijCWUqGICSw8bVakEdODrvbiv1RT/MVUayzFwz/ek6e6NKZn6DbSWzx07N9Hjw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@smithy/property-provider": "^4.2.2", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.911.0.tgz", + "integrity": "sha512-xUlwKmIUW2fWP/eM3nF5u4CyLtOtyohlhGJ5jdsJokr3MrQ7w0tDITO43C9IhCn+28D5UbaiWnKw5ntkw7aVfA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@smithy/fetch-http-handler": "^5.3.3", + "@smithy/node-http-handler": "^4.4.1", + "@smithy/property-provider": "^4.2.2", + "@smithy/protocol-http": "^5.3.2", + "@smithy/smithy-client": "^4.8.1", + "@smithy/types": "^4.7.1", + "@smithy/util-stream": "^4.5.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.913.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.913.0.tgz", + "integrity": "sha512-iR4c4NQ1OSRKQi0SxzpwD+wP1fCy+QNKtEyCajuVlD0pvmoIHdrm5THK9e+2/7/SsQDRhOXHJfLGxHapD74WJw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.911.0", + "@aws-sdk/credential-provider-env": "3.911.0", + "@aws-sdk/credential-provider-http": "3.911.0", + "@aws-sdk/credential-provider-process": "3.911.0", + "@aws-sdk/credential-provider-sso": "3.911.0", + "@aws-sdk/credential-provider-web-identity": "3.911.0", + "@aws-sdk/nested-clients": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@smithy/credential-provider-imds": "^4.2.2", + "@smithy/property-provider": "^4.2.2", + "@smithy/shared-ini-file-loader": "^4.3.2", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.913.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.913.0.tgz", + "integrity": "sha512-HQPLkKDxS83Q/nZKqg9bq4igWzYQeOMqhpx5LYs4u1GwsKeCsYrrfz12Iu4IHNWPp9EnGLcmdfbfYuqZGrsaSQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.911.0", + "@aws-sdk/credential-provider-http": "3.911.0", + "@aws-sdk/credential-provider-ini": "3.913.0", + "@aws-sdk/credential-provider-process": "3.911.0", + "@aws-sdk/credential-provider-sso": "3.911.0", + "@aws-sdk/credential-provider-web-identity": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@smithy/credential-provider-imds": "^4.2.2", + "@smithy/property-provider": "^4.2.2", + "@smithy/shared-ini-file-loader": "^4.3.2", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.911.0.tgz", + "integrity": "sha512-mKshhV5jRQffZjbK9x7bs+uC2IsYKfpzYaBamFsEov3xtARCpOiKaIlM8gYKFEbHT2M+1R3rYYlhhl9ndVWS2g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@smithy/property-provider": "^4.2.2", + "@smithy/shared-ini-file-loader": "^4.3.2", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.911.0.tgz", + "integrity": "sha512-JAxd4uWe0Zc9tk6+N0cVxe9XtJVcOx6Ms0k933ZU9QbuRMH6xti/wnZxp/IvGIWIDzf5fhqiGyw5MSyDeI5b1w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.911.0", + "@aws-sdk/core": "3.911.0", + "@aws-sdk/token-providers": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@smithy/property-provider": "^4.2.2", + "@smithy/shared-ini-file-loader": "^4.3.2", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.911.0.tgz", + "integrity": "sha512-urIbXWWG+cm54RwwTFQuRwPH0WPsMFSDF2/H9qO2J2fKoHRURuyblFCyYG3aVKZGvFBhOizJYexf5+5w3CJKBw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.911.0", + "@aws-sdk/nested-clients": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@smithy/property-provider": "^4.2.2", + "@smithy/shared-ini-file-loader": "^4.3.2", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.910.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.910.0.tgz", + "integrity": "sha512-F9Lqeu80/aTM6S/izZ8RtwSmjfhWjIuxX61LX+/9mxJyEkgaECRxv0chsLQsLHJumkGnXRy/eIyMLBhcTPF5vg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.910.0", + "@smithy/protocol-http": "^5.3.2", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/middleware-logger": { + "version": "3.910.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.910.0.tgz", + "integrity": "sha512-3LJyyfs1USvRuRDla1pGlzGRtXJBXD1zC9F+eE9Iz/V5nkmhyv52A017CvKWmYoR0DM9dzjLyPOI0BSSppEaTw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.910.0", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.910.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.910.0.tgz", + "integrity": "sha512-m/oLz0EoCy+WoIVBnXRXJ4AtGpdl0kPE7U+VH9TsuUzHgxY1Re/176Q1HWLBRVlz4gr++lNsgsMWEC+VnAwMpw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.910.0", + "@aws/lambda-invoke-store": "^0.0.1", + "@smithy/protocol-http": "^5.3.2", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.911.0.tgz", + "integrity": "sha512-P0mIIW/QkAGNvFu15Jqa5NSmHeQvZkkQY8nbQpCT3tGObZe4wRsq5u1mOS+CJp4DIBbRZuHeX7ohbX5kPMi4dg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@aws-sdk/util-arn-parser": "3.893.0", + "@smithy/core": "^3.16.1", + "@smithy/node-config-provider": "^4.3.2", + "@smithy/protocol-http": "^5.3.2", + "@smithy/signature-v4": "^5.3.2", + "@smithy/smithy-client": "^4.8.1", + "@smithy/types": "^4.7.1", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.2", + "@smithy/util-stream": "^4.5.2", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.911.0.tgz", + "integrity": "sha512-rY3LvGvgY/UI0nmt5f4DRzjEh8135A2TeHcva1bgOmVfOI4vkkGfA20sNRqerOkSO6hPbkxJapO50UJHFzmmyA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@aws-sdk/util-endpoints": "3.910.0", + "@smithy/core": "^3.16.1", + "@smithy/protocol-http": "^5.3.2", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/nested-clients": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.911.0.tgz", + "integrity": "sha512-lp/sXbdX/S0EYaMYPVKga0omjIUbNNdFi9IJITgKZkLC6CzspihIoHd5GIdl4esMJevtTQQfkVncXTFkf/a4YA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.911.0", + "@aws-sdk/middleware-host-header": "3.910.0", + "@aws-sdk/middleware-logger": "3.910.0", + "@aws-sdk/middleware-recursion-detection": "3.910.0", + "@aws-sdk/middleware-user-agent": "3.911.0", + "@aws-sdk/region-config-resolver": "3.910.0", + "@aws-sdk/types": "3.910.0", + "@aws-sdk/util-endpoints": "3.910.0", + "@aws-sdk/util-user-agent-browser": "3.910.0", + "@aws-sdk/util-user-agent-node": "3.911.0", + "@smithy/config-resolver": "^4.3.2", + "@smithy/core": "^3.16.1", + "@smithy/fetch-http-handler": "^5.3.3", + "@smithy/hash-node": "^4.2.2", + "@smithy/invalid-dependency": "^4.2.2", + "@smithy/middleware-content-length": "^4.2.2", + "@smithy/middleware-endpoint": "^4.3.3", + "@smithy/middleware-retry": "^4.4.3", + "@smithy/middleware-serde": "^4.2.2", + "@smithy/middleware-stack": "^4.2.2", + "@smithy/node-config-provider": "^4.3.2", + "@smithy/node-http-handler": "^4.4.1", + "@smithy/protocol-http": "^5.3.2", + "@smithy/smithy-client": "^4.8.1", + "@smithy/types": "^4.7.1", + "@smithy/url-parser": "^4.2.2", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.2", + "@smithy/util-defaults-mode-node": "^4.2.3", + "@smithy/util-endpoints": "^3.2.2", + "@smithy/util-middleware": "^4.2.2", + "@smithy/util-retry": "^4.2.2", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.910.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.910.0.tgz", + "integrity": "sha512-gzQAkuHI3xyG6toYnH/pju+kc190XmvnB7X84vtN57GjgdQJICt9So/BD0U6h+eSfk9VBnafkVrAzBzWMEFZVw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.910.0", + "@smithy/node-config-provider": "^4.3.2", + "@smithy/types": "^4.7.1", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.911.0.tgz", + "integrity": "sha512-SJ4dUcY9+HPDIMCHiskT8F7JrRVZF2Y1NUN0Yiy6VUHSULgq2MDlIzSQpNICnmXhk1F1E1B2jJG9XtPYrvtqUg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@smithy/protocol-http": "^5.3.2", + "@smithy/signature-v4": "^5.3.2", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/token-providers": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.911.0.tgz", + "integrity": "sha512-O1c5F1pbEImgEe3Vr8j1gpWu69UXWj3nN3vvLGh77hcrG5dZ8I27tSP5RN4Labm8Dnji/6ia+vqSYpN8w6KN5A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.911.0", + "@aws-sdk/nested-clients": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@smithy/property-provider": "^4.2.2", + "@smithy/shared-ini-file-loader": "^4.3.2", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/types": { + "version": "3.910.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.910.0.tgz", + "integrity": "sha512-o67gL3vjf4nhfmuSUNNkit0d62QJEwwHLxucwVJkR/rw9mfUtAWsgBs8Tp16cdUbMgsyQtCQilL8RAJDoGtadQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/util-arn-parser": { + "version": "3.893.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.893.0.tgz", + "integrity": "sha512-u8H4f2Zsi19DGnwj5FSZzDMhytYF/bCh37vAtBsn3cNDL3YG578X5oc+wSX54pM3tOxS+NY7tvOAo52SW7koUA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/util-endpoints": { + "version": "3.910.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.910.0.tgz", + "integrity": "sha512-6XgdNe42ibP8zCQgNGDWoOF53RfEKzpU/S7Z29FTTJ7hcZv0SytC0ZNQQZSx4rfBl036YWYwJRoJMlT4AA7q9A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.910.0", + "@smithy/types": "^4.7.1", + "@smithy/url-parser": "^4.2.2", + "@smithy/util-endpoints": "^3.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.910.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.910.0.tgz", + "integrity": "sha512-iOdrRdLZHrlINk9pezNZ82P/VxO/UmtmpaOAObUN+xplCUJu31WNM2EE/HccC8PQw6XlAudpdA6HDTGiW6yVGg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.910.0", + "@smithy/types": "^4.7.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.911.0.tgz", + "integrity": "sha512-3l+f6ooLF6Z6Lz0zGi7vSKSUYn/EePPizv88eZQpEAFunBHv+CSVNPtxhxHfkm7X9tTsV4QGZRIqo3taMLolmA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.911.0", + "@aws-sdk/types": "3.910.0", + "@smithy/node-config-provider": "^4.3.2", + "@smithy/types": "^4.7.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-sesv2/node_modules/@aws-sdk/xml-builder": { + "version": "3.911.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.911.0.tgz", + "integrity": "sha512-/yh3oe26bZfCVGrIMRM9Z4hvvGJD+qx5tOLlydOkuBkm72aXON7D9+MucjJXTAcI8tF2Yq+JHa0478eHQOhnLg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.7.1", + "fast-xml-parser": "5.2.5", "tslib": "^2.6.2" }, "engines": { @@ -1316,6 +1864,8 @@ }, "node_modules/@aws/lambda-invoke-store": { "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.0.1.tgz", + "integrity": "sha512-ORHRQ2tmvnBXc8t/X9Z8IcSbBA4xTLKuN873FopzklHMeqBst7YG0d+AX97inkvDX+NChYtSr+qGfcqGFaI8Zw==", "license": "Apache-2.0", "engines": { "node": ">=18.0.0" @@ -6541,15 +7091,94 @@ "linux" ] }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz", + "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz", + "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz", + "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sendgrid/client": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-8.1.6.tgz", + "integrity": "sha512-/BHu0hqwXNHr2aLhcXU7RmmlVqrdfrbY9KpaNj00KZHlVOVoRxRVrpOCabIB+91ISXJ6+mLM9vpaVUhK6TwBWA==", + "license": "MIT", + "dependencies": { + "@sendgrid/helpers": "^8.0.0", + "axios": "^1.12.0" + }, + "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.6", + "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-8.1.6.tgz", + "integrity": "sha512-/ZqxUvKeEztU9drOoPC/8opEPOk+jLlB2q4+xpx6HVLq6aFu3pMpalkTpAQz8XfRfpLp8O25bh6pGPcHDCYpqg==", + "license": "MIT", + "dependencies": { + "@sendgrid/client": "^8.1.5", + "@sendgrid/helpers": "^8.0.0" + }, + "engines": { + "node": ">=12.*" + } + }, "node_modules/@shopify/draggable": { "version": "1.1.4", "license": "MIT" }, "node_modules/@smithy/abort-controller": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.3.tgz", + "integrity": "sha512-xWL9Mf8b7tIFuAlpjKtRPnHrR8XVrwTj5NPYO/QwZPtc0SDLsPxb56V5tzi5yspSMytISHybifez+4jlrx0vkQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.6.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -6578,13 +7207,15 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "4.3.0", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.3.3.tgz", + "integrity": "sha512-xSql8A1Bl41O9JvGU/CtgiLBlwkvpHTSKRlvz9zOBvBCPjXghZ6ZkcVzmV2f7FLAA+80+aqKmIOmy8pEDrtCaw==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.0", - "@smithy/types": "^4.6.0", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/types": "^4.8.0", "@smithy/util-config-provider": "^4.2.0", - "@smithy/util-middleware": "^4.2.0", + "@smithy/util-middleware": "^4.2.3", "tslib": "^2.6.2" }, "engines": { @@ -6592,16 +7223,18 @@ } }, "node_modules/@smithy/core": { - "version": "3.14.0", + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.17.0.tgz", + "integrity": "sha512-Tir3DbfoTO97fEGUZjzGeoXgcQAUBRDTmuH9A8lxuP8ATrgezrAJ6cLuRvwdKN4ZbYNlHgKlBX69Hyu3THYhtg==", "license": "Apache-2.0", "dependencies": { - "@smithy/middleware-serde": "^4.2.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "@smithy/util-base64": "^4.2.0", + "@smithy/middleware-serde": "^4.2.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", + "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-middleware": "^4.2.0", - "@smithy/util-stream": "^4.4.0", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-stream": "^4.5.3", "@smithy/util-utf8": "^4.2.0", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" @@ -6611,13 +7244,15 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.3.tgz", + "integrity": "sha512-hA1MQ/WAHly4SYltJKitEsIDVsNmXcQfYBRv2e+q04fnqtAX5qXaybxy/fhUeAMCnQIdAjaGDb04fMHQefWRhw==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/types": "^4.6.0", - "@smithy/url-parser": "^4.2.0", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/property-provider": "^4.2.3", + "@smithy/types": "^4.8.0", + "@smithy/url-parser": "^4.2.3", "tslib": "^2.6.2" }, "engines": { @@ -6685,13 +7320,15 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "5.3.0", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.4.tgz", + "integrity": "sha512-bwigPylvivpRLCm+YK9I5wRIYjFESSVwl8JQ1vVx/XhCw0PtCi558NwTnT2DaVCl5pYlImGuQTSwMsZ+pIavRw==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.0", - "@smithy/querystring-builder": "^4.2.0", - "@smithy/types": "^4.6.0", - "@smithy/util-base64": "^4.2.0", + "@smithy/protocol-http": "^5.3.3", + "@smithy/querystring-builder": "^4.2.3", + "@smithy/types": "^4.8.0", + "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" }, "engines": { @@ -6712,10 +7349,12 @@ } }, "node_modules/@smithy/hash-node": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.3.tgz", + "integrity": "sha512-6+NOdZDbfuU6s1ISp3UOk5Rg953RJ2aBLNLLBEcamLjHAg1Po9Ha7QIB5ZWhdRUVuOUrT8BVFR+O2KIPmw027g==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.6.0", + "@smithy/types": "^4.8.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" @@ -6737,10 +7376,12 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.3.tgz", + "integrity": "sha512-Cc9W5DwDuebXEDMpOpl4iERo8I0KFjTnomK2RMdhhR87GwrSmUmwMxS4P5JdRf+LsjOdIqumcerwRgYMr/tZ9Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.6.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -6749,6 +7390,8 @@ }, "node_modules/@smithy/is-array-buffer": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.0.tgz", + "integrity": "sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -6770,11 +7413,13 @@ } }, "node_modules/@smithy/middleware-content-length": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.3.tgz", + "integrity": "sha512-/atXLsT88GwKtfp5Jr0Ks1CSa4+lB+IgRnkNrrYP0h1wL4swHNb0YONEvTceNKNdZGJsye+W2HH8W7olbcPUeA==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -6782,16 +7427,18 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.3.0", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.3.4.tgz", + "integrity": "sha512-/RJhpYkMOaUZoJEkddamGPPIYeKICKXOu/ojhn85dKDM0n5iDIhjvYAQLP3K5FPhgB203O3GpWzoK2OehEoIUw==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.14.0", - "@smithy/middleware-serde": "^4.2.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/shared-ini-file-loader": "^4.3.0", - "@smithy/types": "^4.6.0", - "@smithy/url-parser": "^4.2.0", - "@smithy/util-middleware": "^4.2.0", + "@smithy/core": "^3.17.0", + "@smithy/middleware-serde": "^4.2.3", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/shared-ini-file-loader": "^4.3.3", + "@smithy/types": "^4.8.0", + "@smithy/url-parser": "^4.2.3", + "@smithy/util-middleware": "^4.2.3", "tslib": "^2.6.2" }, "engines": { @@ -6799,16 +7446,18 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.4.0", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.4.tgz", + "integrity": "sha512-vSgABQAkuUHRO03AhR2rWxVQ1un284lkBn+NFawzdahmzksAoOeVMnXXsuPViL4GlhRHXqFaMlc8Mj04OfQk1w==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/service-error-classification": "^4.2.0", - "@smithy/smithy-client": "^4.7.0", - "@smithy/types": "^4.6.0", - "@smithy/util-middleware": "^4.2.0", - "@smithy/util-retry": "^4.2.0", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/service-error-classification": "^4.2.3", + "@smithy/smithy-client": "^4.9.0", + "@smithy/types": "^4.8.0", + "@smithy/util-middleware": "^4.2.3", + "@smithy/util-retry": "^4.2.3", "@smithy/uuid": "^1.1.0", "tslib": "^2.6.2" }, @@ -6817,11 +7466,13 @@ } }, "node_modules/@smithy/middleware-serde": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.3.tgz", + "integrity": "sha512-8g4NuUINpYccxiCXM5s1/V+uLtts8NcX4+sPEbvYQDZk4XoJfDpq5y2FQxfmUL89syoldpzNzA0R9nhzdtdKnQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -6829,10 +7480,12 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.3.tgz", + "integrity": "sha512-iGuOJkH71faPNgOj/gWuEGS6xvQashpLwWB1HjHq1lNNiVfbiJLpZVbhddPuDbx9l4Cgl0vPLq5ltRfSaHfspA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.6.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -6840,12 +7493,14 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "4.3.0", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.3.tgz", + "integrity": "sha512-NzI1eBpBSViOav8NVy1fqOlSfkLgkUjUTlohUSgAEhHaFWA3XJiLditvavIP7OpvTjDp5u2LhtlBhkBlEisMwA==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.2.0", - "@smithy/shared-ini-file-loader": "^4.3.0", - "@smithy/types": "^4.6.0", + "@smithy/property-provider": "^4.2.3", + "@smithy/shared-ini-file-loader": "^4.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -6853,13 +7508,15 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "4.3.0", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.2.tgz", + "integrity": "sha512-MHFvTjts24cjGo1byXqhXrbqm7uznFD/ESFx8npHMWTFQVdBZjrT1hKottmp69LBTRm/JQzP/sn1vPt0/r6AYQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^4.2.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/querystring-builder": "^4.2.0", - "@smithy/types": "^4.6.0", + "@smithy/abort-controller": "^4.2.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/querystring-builder": "^4.2.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -6867,10 +7524,12 @@ } }, "node_modules/@smithy/property-provider": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.3.tgz", + "integrity": "sha512-+1EZ+Y+njiefCohjlhyOcy1UNYjT+1PwGFHCxA/gYctjg3DQWAU19WigOXAco/Ql8hZokNehpzLd0/+3uCreqQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.6.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -6878,10 +7537,12 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "5.3.0", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.3.tgz", + "integrity": "sha512-Mn7f/1aN2/jecywDcRDvWWWJF4uwg/A0XjFMJtj72DsgHTByfjRltSqcT9NyE9RTdBSN6X1RSXrhn/YWQl8xlw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.6.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -6889,10 +7550,12 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.3.tgz", + "integrity": "sha512-LOVCGCmwMahYUM/P0YnU/AlDQFjcu+gWbFJooC417QRB/lDJlWSn8qmPSDp+s4YVAHOgtgbNG4sR+SxF/VOcJQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.6.0", + "@smithy/types": "^4.8.0", "@smithy/util-uri-escape": "^4.2.0", "tslib": "^2.6.2" }, @@ -6901,10 +7564,12 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.3.tgz", + "integrity": "sha512-cYlSNHcTAX/wc1rpblli3aUlLMGgKZ/Oqn8hhjFASXMCXjIqeuQBei0cnq2JR8t4RtU9FpG6uyl6PxyArTiwKA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.6.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -6912,20 +7577,24 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.3.tgz", + "integrity": "sha512-NkxsAxFWwsPsQiwFG2MzJ/T7uIR6AQNh1SzcxSUnmmIqIQMlLRQDKhc17M7IYjiuBXhrQRjQTo3CxX+DobS93g==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.6.0" + "@smithy/types": "^4.8.0" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.3.0", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.3.3.tgz", + "integrity": "sha512-9f9Ixej0hFhroOK2TxZfUUDR13WVa8tQzhSzPDgXe5jGL3KmaM9s8XN7RQwqtEypI82q9KHnKS71CJ+q/1xLtQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.6.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -6933,14 +7602,16 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.3.0", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.3.tgz", + "integrity": "sha512-CmSlUy+eEYbIEYN5N3vvQTRfqt0lJlQkaQUIf+oizu7BbDut0pozfDjBGecfcfWf7c62Yis4JIEgqQ/TCfodaA==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.2.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", "@smithy/util-hex-encoding": "^4.2.0", - "@smithy/util-middleware": "^4.2.0", + "@smithy/util-middleware": "^4.2.3", "@smithy/util-uri-escape": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" @@ -6950,15 +7621,17 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.7.0", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.9.0.tgz", + "integrity": "sha512-qz7RTd15GGdwJ3ZCeBKLDQuUQ88m+skh2hJwcpPm1VqLeKzgZvXf6SrNbxvx7uOqvvkjCMXqx3YB5PDJyk00ww==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.14.0", - "@smithy/middleware-endpoint": "^4.3.0", - "@smithy/middleware-stack": "^4.2.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "@smithy/util-stream": "^4.4.0", + "@smithy/core": "^3.17.0", + "@smithy/middleware-endpoint": "^4.3.4", + "@smithy/middleware-stack": "^4.2.3", + "@smithy/protocol-http": "^5.3.3", + "@smithy/types": "^4.8.0", + "@smithy/util-stream": "^4.5.3", "tslib": "^2.6.2" }, "engines": { @@ -6966,7 +7639,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.6.0", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.8.0.tgz", + "integrity": "sha512-QpELEHLO8SsQVtqP+MkEgCYTFW0pleGozfs3cZ183ZBj9z3VC1CX1/wtFMK64p+5bhtZo41SeLK1rBRtd25nHQ==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -6976,11 +7651,13 @@ } }, "node_modules/@smithy/url-parser": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.3.tgz", + "integrity": "sha512-I066AigYvY3d9VlU3zG9XzZg1yT10aNqvCaBTw9EPgu5GrsEl1aUkcMvhkIXascYH1A8W0LQo3B1Kr1cJNcQEw==", "license": "Apache-2.0", "dependencies": { - "@smithy/querystring-parser": "^4.2.0", - "@smithy/types": "^4.6.0", + "@smithy/querystring-parser": "^4.2.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -6988,7 +7665,9 @@ } }, "node_modules/@smithy/util-base64": { - "version": "4.2.0", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.0.tgz", + "integrity": "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==", "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^4.2.0", @@ -7001,6 +7680,8 @@ }, "node_modules/@smithy/util-body-length-browser": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.0.tgz", + "integrity": "sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -7010,7 +7691,9 @@ } }, "node_modules/@smithy/util-body-length-node": { - "version": "4.2.0", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.1.tgz", + "integrity": "sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -7021,6 +7704,8 @@ }, "node_modules/@smithy/util-buffer-from": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.0.tgz", + "integrity": "sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.2.0", @@ -7032,6 +7717,8 @@ }, "node_modules/@smithy/util-config-provider": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.0.tgz", + "integrity": "sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -7041,13 +7728,14 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.2.0", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.3.tgz", + "integrity": "sha512-vqHoybAuZXbFXZqgzquiUXtdY+UT/aU33sxa4GBPkiYklmR20LlCn+d3Wc3yA5ZM13gQ92SZe/D8xh6hkjx+IQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/property-provider": "^4.2.0", - "@smithy/smithy-client": "^4.7.0", - "@smithy/types": "^4.6.0", - "bowser": "^2.11.0", + "@smithy/property-provider": "^4.2.3", + "@smithy/smithy-client": "^4.9.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -7055,15 +7743,17 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.2.0", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.4.tgz", + "integrity": "sha512-X5/xrPHedifo7hJUUWKlpxVb2oDOiqPUXlvsZv1EZSjILoutLiJyWva3coBpn00e/gPSpH8Rn2eIbgdwHQdW7Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/config-resolver": "^4.3.0", - "@smithy/credential-provider-imds": "^4.2.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/smithy-client": "^4.7.0", - "@smithy/types": "^4.6.0", + "@smithy/config-resolver": "^4.3.3", + "@smithy/credential-provider-imds": "^4.2.3", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/property-provider": "^4.2.3", + "@smithy/smithy-client": "^4.9.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -7071,11 +7761,13 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "3.2.0", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.3.tgz", + "integrity": "sha512-aCfxUOVv0CzBIkU10TubdgKSx5uRvzH064kaiPEWfNIvKOtNpu642P4FP1hgOFkjQIkDObrfIDnKMKkeyrejvQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/node-config-provider": "^4.3.0", - "@smithy/types": "^4.6.0", + "@smithy/node-config-provider": "^4.3.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -7084,6 +7776,8 @@ }, "node_modules/@smithy/util-hex-encoding": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.0.tgz", + "integrity": "sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -7093,10 +7787,12 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.3.tgz", + "integrity": "sha512-v5ObKlSe8PWUHCqEiX2fy1gNv6goiw6E5I/PN2aXg3Fb/hse0xeaAnSpXDiWl7x6LamVKq7senB+m5LOYHUAHw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.6.0", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -7104,11 +7800,13 @@ } }, "node_modules/@smithy/util-retry": { - "version": "4.2.0", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.3.tgz", + "integrity": "sha512-lLPWnakjC0q9z+OtiXk+9RPQiYPNAovt2IXD3CP4LkOnd9NpUsxOjMx1SnoUVB7Orb7fZp67cQMtTBKMFDvOGg==", "license": "Apache-2.0", "dependencies": { - "@smithy/service-error-classification": "^4.2.0", - "@smithy/types": "^4.6.0", + "@smithy/service-error-classification": "^4.2.3", + "@smithy/types": "^4.8.0", "tslib": "^2.6.2" }, "engines": { @@ -7116,13 +7814,15 @@ } }, "node_modules/@smithy/util-stream": { - "version": "4.4.0", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.3.tgz", + "integrity": "sha512-oZvn8a5bwwQBNYHT2eNo0EU8Kkby3jeIg1P2Lu9EQtqDxki1LIjGRJM6dJ5CZUig8QmLxWxqOKWvg3mVoOBs5A==", "license": "Apache-2.0", "dependencies": { - "@smithy/fetch-http-handler": "^5.3.0", - "@smithy/node-http-handler": "^4.3.0", - "@smithy/types": "^4.6.0", - "@smithy/util-base64": "^4.2.0", + "@smithy/fetch-http-handler": "^5.3.4", + "@smithy/node-http-handler": "^4.4.2", + "@smithy/types": "^4.8.0", + "@smithy/util-base64": "^4.3.0", "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-hex-encoding": "^4.2.0", "@smithy/util-utf8": "^4.2.0", @@ -7134,6 +7834,8 @@ }, "node_modules/@smithy/util-uri-escape": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.0.tgz", + "integrity": "sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -7144,6 +7846,8 @@ }, "node_modules/@smithy/util-utf8": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.0.tgz", + "integrity": "sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==", "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^4.2.0", @@ -7157,8 +7861,8 @@ "version": "4.2.0", "license": "Apache-2.0", "dependencies": { - "@smithy/abort-controller": "^4.2.0", - "@smithy/types": "^4.6.0", + "@smithy/abort-controller": "^4.0.4", + "@smithy/types": "^4.3.1", "tslib": "^2.6.2" }, "engines": { @@ -7167,6 +7871,8 @@ }, "node_modules/@smithy/uuid": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.0.tgz", + "integrity": "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -7726,10 +8432,28 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.7.0", + "version": "24.9.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.2.tgz", + "integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==", "license": "MIT", "dependencies": { - "undici-types": "~7.14.0" + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/node-cron": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/node-cron/-/node-cron-3.0.11.tgz", + "integrity": "sha512-0ikrnug3/IyneSHqCBeslAhlK2aBfYek1fGo4bP4QnZPmiqSGRK+Oy7ZMisLWkesffJvQ1cqAcBnJC+8+nxIAg==", + "license": "MIT" + }, + "node_modules/@types/nodemailer": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-7.0.2.tgz", + "integrity": "sha512-Zo6uOA9157WRgBk/ZhMpTQ/iCWLMk7OIs/Q9jvHarMvrzUUP/MDdPHL2U1zpf57HrrWGv4nYQn5uIxna0xY3xw==", + "license": "MIT", + "dependencies": { + "@aws-sdk/client-sesv2": "^3.839.0", + "@types/node": "*" } }, "node_modules/@types/normalize-package-data": { @@ -8615,6 +9339,12 @@ "retry": "0.13.1" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/auto-bind": { "version": "4.0.0", "dev": true, @@ -8639,11 +9369,15 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/axe-core": { - "version": "4.10.3", - "license": "MPL-2.0", - "engines": { - "node": ">=4" + "node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" } }, "node_modules/babel-plugin-macros": { @@ -9432,6 +10166,18 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/common-tags": { "version": "1.8.2", "dev": true, @@ -9637,6 +10383,7 @@ }, "node_modules/cross-spawn": { "version": "7.0.6", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -9863,6 +10610,15 @@ "dev": true, "license": "MIT" }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "license": "MIT", @@ -9890,6 +10646,15 @@ "dev": true, "license": "MIT" }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "license": "MIT", @@ -10105,6 +10870,21 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-toolkit": { "version": "1.39.10", "license": "MIT", @@ -10804,6 +11584,26 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.5", "license": "MIT", @@ -10817,28 +11617,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/foreground-child": { - "version": "3.3.1", - "license": "ISC", + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "license": "ISC", "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 6" } }, "node_modules/formdata-polyfill": { @@ -11772,6 +12564,7 @@ }, "node_modules/isexe": { "version": "2.0.0", + "dev": true, "license": "ISC" }, "node_modules/isomorphic-ws": { @@ -12577,7 +13370,9 @@ } }, "node_modules/mime-types": { - "version": "3.0.1", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" @@ -12586,9 +13381,10 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "dev": true, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { "node": ">=6" @@ -12835,6 +13631,15 @@ "license": "MIT", "optional": true }, + "node_modules/node-cron": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-4.2.1.tgz", + "integrity": "sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg==", + "license": "ISC", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/node-domexception": { "version": "1.0.0", "dev": true, @@ -12924,6 +13729,15 @@ "version": "2.0.23", "license": "MIT" }, + "node_modules/nodemailer": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.9.tgz", + "integrity": "sha512-9/Qm0qXIByEP8lEV2qOqcAW7bRpL8CR9jcTwk3NBnHJNmP9fIJ86g2fgmIXqHY+nj55ZEMwWqYAT2QTDpRUYiQ==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/normalize-package-data": { "version": "3.0.3", "license": "BSD-2-Clause", @@ -13436,6 +14250,7 @@ }, "node_modules/path-key": { "version": "3.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13824,6 +14639,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/prr": { "version": "1.0.1", "dev": true, @@ -15067,6 +15888,7 @@ }, "node_modules/shebang-command": { "version": "2.0.0", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -15077,6 +15899,7 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -16018,6 +16841,20 @@ "turbo-windows-arm64": "2.5.8" } }, + "node_modules/turbo-darwin-64": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-2.5.8.tgz", + "integrity": "sha512-Dh5bCACiHO8rUXZLpKw+m3FiHtAp2CkanSyJre+SInEvEr5kIxjGvCK/8MFX8SFRjQuhjtvpIvYYZJB4AGCxNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, "node_modules/turbo-darwin-arm64": { "version": "2.5.8", "cpu": [ @@ -16030,6 +16867,62 @@ "darwin" ] }, + "node_modules/turbo-linux-64": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-2.5.8.tgz", + "integrity": "sha512-hMyvc7w7yadBlZBGl/bnR6O+dJTx3XkTeyTTH4zEjERO6ChEs0SrN8jTFj1lueNXKIHh1SnALmy6VctKMGnWfw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/turbo-linux-arm64": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-2.5.8.tgz", + "integrity": "sha512-LQELGa7bAqV2f+3rTMRPnj5G/OHAe2U+0N9BwsZvfMvHSUbsQ3bBMWdSQaYNicok7wOZcHjz2TkESn1hYK6xIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/turbo-windows-64": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-2.5.8.tgz", + "integrity": "sha512-3YdcaW34TrN1AWwqgYL9gUqmZsMT4T7g8Y5Azz+uwwEJW+4sgcJkIi9pYFyU4ZBSjBvkfuPZkGgfStir5BBDJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/turbo-windows-arm64": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-2.5.8.tgz", + "integrity": "sha512-eFC5XzLmgXJfnAK3UMTmVECCwuBcORrWdewoiXBnUm934DY6QN8YowC/srhNnROMpaKaqNeRpoB5FxCww3eteQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/turf-extent": { "version": "1.0.4", "license": "MIT", @@ -16197,7 +17090,9 @@ } }, "node_modules/undici-types": { - "version": "7.14.0", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -16700,6 +17595,7 @@ }, "node_modules/which": { "version": "2.0.2", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" diff --git a/packages/common/src/lib/common.ts b/packages/common/src/lib/common.ts index 2deb0c7d0..2783de2d8 100644 --- a/packages/common/src/lib/common.ts +++ b/packages/common/src/lib/common.ts @@ -5,3 +5,5 @@ export const schemaOptions = { updatedAt: "_updatedAt", }, }; + +export const SEMESTER_ENUM = ["Spring", "Summer", "Fall", "Winter"] as const; diff --git a/packages/common/src/models/schedule.ts b/packages/common/src/models/schedule.ts index 3c8dd8ebc..55b5634e2 100644 --- a/packages/common/src/models/schedule.ts +++ b/packages/common/src/models/schedule.ts @@ -1,4 +1,5 @@ import mongoose, { Document, InferSchemaType, Schema } from "mongoose"; +import { SEMESTER_ENUM } from "../lib/common"; export const customEventSchema = new Schema({ startTime: { @@ -88,7 +89,7 @@ export const scheduleSchema = new Schema( }, semester: { type: String, - enum: ["Spring", "Summer", "Fall", "Winter"], + enum: SEMESTER_ENUM, required: true, }, sessionId: { diff --git a/packages/common/src/models/user.ts b/packages/common/src/models/user.ts index 3be797bc3..105fff4ee 100644 --- a/packages/common/src/models/user.ts +++ b/packages/common/src/models/user.ts @@ -1,4 +1,5 @@ import mongoose, { Document, InferSchemaType, Schema } from "mongoose"; +import { SEMESTER_ENUM } from "../lib/common"; export const userSchema = new Schema( { @@ -41,7 +42,7 @@ export const userSchema = new Schema( }, semester: { type: String, - enum: ["Spring", "Summer", "Fall", "Winter"], + enum: SEMESTER_ENUM, required: true, }, subject: { @@ -75,6 +76,51 @@ export const userSchema = new Schema( }, ], }, + monitoredClasses: { + required: false, + default: [], + type: [ + { + class: { + year: { + type: Number, + required: true, + }, + semester: { + type: String, + enum: ["Spring", "Summer", "Fall", "Winter"], + required: true, + }, + subject: { + type: String, + required: true, + }, + courseNumber: { + type: String, + required: true, + }, + number: { + type: String, + required: true, + }, + }, + thresholds: [Number], + }, + ], + }, + notificationsOn: { + type: Boolean, + required: true, + default: false, + }, + lastNotified: { + type: Date, + required: false, + }, + refresh_token: { + type: String, + required: false, + }, minors: { type: [String], trim: true,