diff --git a/package-lock.json b/package-lock.json index a118566b8..ebca1057e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -95,6 +95,7 @@ "@types/node": "^8.10.61", "@types/supertest": "^6.0.2", "babel-jest": "^29.7.0", + "baseline-browser-mapping": "^2.10.29", "eslint": "^8.47.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-base": "^15.0.0", @@ -1577,6 +1578,7 @@ "node_modules/@babel/core": { "version": "7.28.5", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -4548,6 +4550,7 @@ "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz", "integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==", "license": "MIT", + "peer": true, "dependencies": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", @@ -5700,6 +5703,7 @@ "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.13.tgz", "integrity": "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==", "license": "MIT", + "peer": true, "dependencies": { "@types/node": "*", "form-data": "^4.0.4" @@ -5871,6 +5875,7 @@ "version": "8.15.0", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5900,6 +5905,7 @@ "node_modules/ajv": { "version": "6.12.6", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -6887,10 +6893,15 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.8.25", + "version": "2.10.29", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.29.tgz", + "integrity": "sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==", "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/basic-ftp": { @@ -7128,6 +7139,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", @@ -8168,6 +8180,7 @@ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.21.0" }, @@ -8368,7 +8381,8 @@ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1581282.tgz", "integrity": "sha512-nv7iKtNZQshSW2hKzYNr46nM/Cfh5SEvE2oV0/SEGgc9XupIY5ggf84Cz8eJIkBce7S3bmTAauFD6aysMpnqsQ==", "dev": true, - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/dezalgo": { "version": "1.0.4", @@ -9031,6 +9045,7 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -9208,6 +9223,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -9265,6 +9281,7 @@ "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", @@ -9295,6 +9312,7 @@ "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", @@ -9328,6 +9346,7 @@ "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -19792,6 +19811,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "license": "MIT", + "peer": true, "engines": { "node": ">=10.0.0" }, diff --git a/package.json b/package.json index c488c5e5d..991e548ab 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@types/node": "^8.10.61", "@types/supertest": "^6.0.2", "babel-jest": "^29.7.0", + "baseline-browser-mapping": "^2.10.29", "eslint": "^8.47.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb-base": "^15.0.0", diff --git a/src/controllers/userProfileController.js b/src/controllers/userProfileController.js index eef1dd74f..6472be314 100644 --- a/src/controllers/userProfileController.js +++ b/src/controllers/userProfileController.js @@ -2089,6 +2089,8 @@ const createControllerMethods = function (UserProfile, Project, cache) { if (userIdx !== -1) { const userData = allUserData[userIdx]; userData.isActive = user.isActive; + userData.reactivationDate = null; + userData.endDate = null; allUserData.splice(userIdx, 1, userData); cache.setCache('allusers', JSON.stringify(allUserData)); } diff --git a/src/helpers/userHelper.js b/src/helpers/userHelper.js index 8146116f1..d76d554bb 100644 --- a/src/helpers/userHelper.js +++ b/src/helpers/userHelper.js @@ -39,6 +39,7 @@ const Timer = require('../models/timer'); const DEFAULT_CC_EMAILS = ['onecommunityglobal@gmail.com', 'jae@onecommunityglobal.org']; const DEFAULT_BCC_EMAILS = ['onecommunityhospitality@gmail.com']; const DEFAULT_REPLY_TO = ['jae@onecommunityglobal.org']; +const { COMPANY_TZ } = require('../constants/company'); const delay = (ms) => new Promise((resolve) => { @@ -2260,7 +2261,7 @@ const userHelper = function () { const lastDay = moment(person.endDate).format('YYYY-MM-DD'); logger.logInfo(`User with id: ${user._id}'s final Day is set at ${moment().format()}.`); person.teams.map(async (teamId) => { - const managementEmails = await userHelper.getTeamManagementEmail(teamId); + const managementEmails = await getTeamManagementEmail(teamId); if (Array.isArray(managementEmails) && managementEmails.length > 0) { managementEmails.forEach((management) => { recipients.push(management.email); @@ -2297,7 +2298,7 @@ const userHelper = function () { const lastDay = moment(person.endDate).format('YYYY-MM-DD'); logger.logInfo(`User with id: ${user._id} was de-activated at ${moment().format()}.`); person.teams.map(async (teamId) => { - const managementEmails = await userHelper.getTeamManagementEmail(teamId); + const managementEmails = await getTeamManagementEmail(teamId); if (Array.isArray(managementEmails) && managementEmails.length > 0) { managementEmails.forEach((management) => { recipients.push(management.email); @@ -2628,12 +2629,316 @@ const userHelper = function () { } }; + const sendUserPausedEmail = ({ firstName, lastName, email, reactivationDate, recipients }) => { + const returnDate = moment(reactivationDate) + .tz(COMPANY_TZ) + .add(1, 'day') // adding a day to make it clear they return on the day of reactivation + .format('M-D-YYYY'); + const subject = `IMPORTANT: ${firstName} ${lastName} has been PAUSED in the Highest Good Network`; + + const emailBody = ` +

Management,

+

+ Please note that ${firstName} ${lastName} has been PAUSED in the Highest Good Network. +

+

+ Please confirm all work has been wrapped up until they return on + ${returnDate}. +

+

With Gratitude,
One Community

+ `; + + emailSender(recipients, subject, emailBody, null, email); + }; + + const sendUserSeparatedEmail = ({ firstName, lastName, email, recipients, endDate }) => { + const formattedFinalDay = moment(endDate).tz(COMPANY_TZ).format('M-D-YYYY'); + const subject = `IMPORTANT: ${firstName} ${lastName} has been deactivated in the Highest Good Network`; + + const emailBody = ` +

Management,

+

+ Please note that ${firstName} ${lastName} has been DEACTIVATED and made inactive in the Highest Good Network from ${formattedFinalDay} onwards. +

+

+ Please confirm all work has been wrapped up and nothing further is required. +

+

With Gratitude,
One Community

+ `; + + emailSender(recipients, subject, emailBody, null, email); + }; + + const sendUserActivatedEmail = ({ firstName, lastName, email, recipients }) => { + const subject = `IMPORTANT: ${firstName} ${lastName} has been activated in the Highest Good Network`; + + const emailBody = ` +

Management,

+

+ ${firstName} ${lastName} has been activated in the Highest Good Network. +

+

Email: ${email}

+

With Gratitude,
One Community

+ `; + + emailSender(recipients, subject, emailBody, null, email); + }; + + const sendUserScheduledSeparationEmail = ({ + firstName, + lastName, + email, + endDate, + recipients, + }) => { + const formattedFinalDay = endDate ? moment(endDate).tz(COMPANY_TZ).format('M-D-YYYY') : 'N/A'; + const subject = `IMPORTANT: ${firstName} ${lastName} has a FINAL DAY scheduled in the Highest Good Network`; + + const emailBody = ` +

Management,

+

+ Please note that ${firstName} ${lastName} has a FINAL DAY scheduled in the Highest Good Network. +

+

+ The final day is set for ${formattedFinalDay}, and they have until the end of this day to continue logging hours. +

+

+ Please begin wrapping up any remaining work as they will be deactivated the following day. +

+

With Gratitude,
One Community

+ `; + + emailSender(recipients, subject, emailBody, null, email); + }; + + const sendUserResumedEmail = ({ firstName, lastName, email, recipients, pausedOn }) => { + const formattedPausedOn = pausedOn + ? moment(pausedOn).tz(COMPANY_TZ).format('M-D-YYYY') + : 'an earlier date'; + const subject = `IMPORTANT: ${firstName} ${lastName} has been RESUMED in the Highest Good Network`; + + const emailBody = ` +

Management,

+

+ Please note that ${firstName} ${lastName}, who was previously PAUSED in the Highest Good Network on + ${formattedPausedOn}, has now been RESUMED and is active again. +

+

+ ${firstName} ${lastName} will remain active until they are deactivated, paused again, + or a final day is scheduled. +

+

With Gratitude,
One Community

+ `; + + emailSender(recipients, subject, emailBody, null, email); + }; + + const sendUserReactivatedAfterSeparation = ({ + firstName, + lastName, + email, + recipients, + previousEndDate, + }) => { + const formattedPreviousEndDate = moment(previousEndDate).tz(COMPANY_TZ).format('M-D-YYYY'); + const subject = `IMPORTANT: ${firstName} ${lastName} has been REACTIVATED in the Highest Good Network`; + + const emailBody = ` +

Management,

+

+ Please note that ${firstName} ${lastName}, who was previously DEACTIVATED from the Highest Good Network on + ${formattedPreviousEndDate}, has now been REACTIVATED. +

+

+ ${firstName} ${lastName} is currently active and will remain so until they are deactivated, + paused, or a final day is scheduled. +

+

With Gratitude,
One Community

+ `; + + emailSender(recipients, subject, emailBody, null, email); + }; + + const sendUserCancelledSeparationEmail = ({ + firstName, + lastName, + email, + recipients, + previousEndDate, + }) => { + const formattedPreviousEndDate = moment(previousEndDate).tz(COMPANY_TZ).format('M-D-YYYY'); + const subject = `IMPORTANT: Final Day has been CANCELLED for ${firstName} ${lastName}`; + + const emailBody = ` +

Management,

+

+ Please note that the previously scheduled FINAL DAY for ${firstName} ${lastName} + in the Highest Good Network as ${formattedPreviousEndDate} has now been REMOVED. +

+

+ ${firstName} ${lastName} is currently active and will remain so until they are + deactivated, paused, or a new final day is scheduled. +

+

With Gratitude,
One Community

+ `; + + emailSender(recipients, subject, emailBody, null, email); + }; + + async function finalizeUserEndDates() { + const now = moment.tz(COMPANY_TZ); + + // 1) Only users who are scheduled for separation (still active) + const users = await userProfile.find({ + isActive: true, + endDate: { $ne: null }, + inactiveReason: InactiveReason.SCHEDULED_SEPARATION, + // Safety: should not be a paused user + reactivationDate: { $in: [null, undefined] }, + }); + + console.log('Found', users.length, 'scheduled-separation users to process.'); + + for (const user of users) { + const scheduledEndMoment = moment(user.endDate).tz(COMPANY_TZ).endOf('day'); + const recipients = await getEmailRecipientsForStatusChange(user._id); + + // 2) 3-week email logic (trigger window starts at start of day, 3 weeks before endDate) + if ( + !user.finalEmailThreeWeeksSent && + now.isSameOrAfter( + moment(scheduledEndMoment) + .subtract(WEEKS_BEFORE_END_DATE_FOR_EMAIL, 'weeks') + .startOf('day'), + ) && + now.isBefore(scheduledEndMoment) // only while still pending + ) { + await sendThreeWeekFinalDayEmail({ + email: user.email, + firstName: user.firstName, + lastName: user.lastName, + endDate: user.endDate, // IMPORTANT: email references scheduled endDate + recipients, + }); + + user.finalEmailThreeWeeksSent = true; + await user.save(); + } + + // 3) If endDate hasn't passed yet, skip finalization + if (now.isBefore(scheduledEndMoment)) continue; + + // 4) Finalize separation + if (user.deactivatedAt) continue; // safety check + + user.deactivatedAt = now.toDate(); + user.isActive = false; + user.inactiveReason = InactiveReason.SEPARATED; + user.endDate = resolveEffectiveEndDate(user).toDate(); + sendUserSeparatedEmail({ + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + recipients, + endDate: user.endDate, + }); + await user.save(); + } + } + + function resolveEffectiveEndDate(user) { + // 1) endDate + lastActivityAt → earlier of the two + if (user?.endDate && user?.lastActivityAt) { + return moment.min( + moment(user.endDate).tz(COMPANY_TZ), + moment(user.lastActivityAt).tz(COMPANY_TZ), + ); + } + + // 2) no lastActivityAt → use createdDate (normalized to COMPANY_TZ) + if (!user?.lastActivityAt && user?.createdDate) { + return moment.tz(user.createdDate, 'YYYY-MM-DD', COMPANY_TZ).startOf('day'); + } + + // 3) only endDate present + if (user?.endDate) { + return moment(user.endDate).tz(COMPANY_TZ); + } + + // 4) only lastActivityAt present + if (user?.lastActivityAt) { + return moment(user.lastActivityAt).tz(COMPANY_TZ); + } + + // 5) fallback → now + return moment().tz(COMPANY_TZ); + } + + const sendThreeWeekFinalDayEmail = async ({ + email, + firstName, + lastName, + endDate, + recipients, + }) => { + const subject = `IMPORTANT: Upcoming final day for ${firstName} ${lastName} in the Highest Good Network`; + + const formattedEndDate = moment(endDate).tz(COMPANY_TZ).format('M-D-YYYY'); + + const emailBody = ` +

Management,

+ +

+ Please note that the final day for ${firstName} ${lastName} + in the Highest Good Network is set for ${formattedEndDate}. +

+ +

+ This is a reminder sent approximately three weeks in advance. + Please begin wrapping up any remaining work and transitions with this individual. +

+ +

+ Please note that they will be actively able to log hours until the end of their final day. +

+ +

With gratitude,
One Community

+ `; + try { + await emailSender(recipients, subject, emailBody, null, email, email); + } catch (err) { + logger.logException(err, 'Failed to send 3-week final day email'); + } + }; + + const getEmailRecipientsForStatusChange = async (userId) => { + const emailReceivers = await userProfile.find( + { isActive: true, role: { $in: ['Owner'] } }, + '_id isActive role email', + ); + const recipients = emailReceivers.map((receiver) => receiver.email); + + try { + const findUser = await userProfile.findById(userId, 'teams'); + findUser.teams.map(async (teamId) => { + const managementEmails = await getTeamManagementEmail(teamId); + if (Array.isArray(managementEmails) && managementEmails.length > 0) { + managementEmails.forEach((management) => { + recipients.push(management.email); + }); + } + }); + } catch (err) { + logger.logException(err, 'Unexpected error in finding menagement team'); + } + return recipients; + }; + return { changeBadgeCount, getUserName, getTeamMembers, checkTeamCodeMismatch, - getTeamManagementEmail, validateProfilePic, assignBlueSquareForTimeNotMet, applyMissedHourForCoreTeam, @@ -2650,6 +2955,16 @@ const userHelper = function () { deleteExpiredTokens, deleteOldTimeOffRequests, getProfileImagesFromWebsite, + sendUserPausedEmail, + sendUserSeparatedEmail, + sendUserActivatedEmail, + sendUserScheduledSeparationEmail, + sendUserResumedEmail, + sendUserReactivatedAfterSeparation, + sendUserCancelledSeparationEmail, + finalizeUserEndDates, + getEmailRecipientsForStatusChange, + getTeamManagementEmail, }; }; diff --git a/yarn.lock b/yarn.lock index 38883a2df..52cd4dc14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1770,6 +1770,13 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@emnapi/runtime@^1.7.0": + version "1.8.1" + resolved "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz" + integrity sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg== + dependencies: + tslib "^2.4.0" + "@eslint-community/eslint-utils@^4.2.0": version "4.9.0" dependencies: @@ -1856,6 +1863,143 @@ "@img/colour@^1.0.0": version "1.0.0" +"@img/sharp-darwin-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz" + integrity sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.2.4" + +"@img/sharp-darwin-x64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz" + integrity sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.2.4" + +"@img/sharp-libvips-darwin-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz" + integrity sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g== + +"@img/sharp-libvips-darwin-x64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz" + integrity sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg== + +"@img/sharp-libvips-linux-arm@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz" + integrity sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A== + +"@img/sharp-libvips-linux-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz" + integrity sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw== + +"@img/sharp-libvips-linux-ppc64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz" + integrity sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA== + +"@img/sharp-libvips-linux-riscv64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz" + integrity sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA== + +"@img/sharp-libvips-linux-s390x@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz" + integrity sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ== + +"@img/sharp-libvips-linux-x64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz" + integrity sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw== + +"@img/sharp-libvips-linuxmusl-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz" + integrity sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw== + +"@img/sharp-libvips-linuxmusl-x64@1.2.4": + version "1.2.4" + resolved "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz" + integrity sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg== + +"@img/sharp-linux-arm@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz" + integrity sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.2.4" + +"@img/sharp-linux-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz" + integrity sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.2.4" + +"@img/sharp-linux-ppc64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz" + integrity sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA== + optionalDependencies: + "@img/sharp-libvips-linux-ppc64" "1.2.4" + +"@img/sharp-linux-riscv64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz" + integrity sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw== + optionalDependencies: + "@img/sharp-libvips-linux-riscv64" "1.2.4" + +"@img/sharp-linux-s390x@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz" + integrity sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.2.4" + +"@img/sharp-linux-x64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz" + integrity sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.2.4" + +"@img/sharp-linuxmusl-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz" + integrity sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.2.4" + +"@img/sharp-linuxmusl-x64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz" + integrity sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.2.4" + +"@img/sharp-wasm32@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz" + integrity sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw== + dependencies: + "@emnapi/runtime" "^1.7.0" + +"@img/sharp-win32-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz" + integrity sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g== + +"@img/sharp-win32-ia32@0.34.5": + version "0.34.5" + resolved "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz" + integrity sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg== + "@img/sharp-win32-x64@0.34.5": version "0.34.5" resolved "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz" @@ -3705,8 +3849,10 @@ base64id@~2.0.0, base64id@2.0.0: resolved "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz" integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== -baseline-browser-mapping@^2.8.19: - version "2.8.25" +baseline-browser-mapping@^2.10.29, baseline-browser-mapping@^2.8.19: + version "2.10.29" + resolved "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.29.tgz" + integrity sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ== basic-ftp@^5.0.2: version "5.2.2" @@ -5832,6 +5978,16 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +fsevents@2.3.2: + version "2.3.2" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" @@ -10217,7 +10373,7 @@ teex@^1.0.1: dependencies: streamx "^2.12.5" -telesignsdk@^3.0.3: +telesignsdk@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/telesignsdk/-/telesignsdk-3.0.4.tgz" integrity sha512-aBcC7BqRSjGTs4EZkYOcIMSJhLOxHYDfX/Qi5NVW6McAmbJim9V6baw9VHXd2Br+2POCJB6Ww0sV7zwchDTbYA== @@ -10350,7 +10506,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== -twilio@^5.5.2: +twilio@^5.10.2: version "5.10.4" dependencies: axios "^1.12.0"