From 66fbcc68065cd1cc8a4ec22fb74cb8568b66d879 Mon Sep 17 00:00:00 2001
From: Scott Wilson
Date: Thu, 1 May 2025 14:57:24 -0700
Subject: [PATCH] improvemet(email-templates): migrate email templates to react
email
---
backend/.eslintrc.js | 9 +
backend/package-lock.json | 2493 ++++++++++++++++-
backend/package.json | 8 +-
.../secret-rotation-v2-fns.ts | 2 +-
.../ssh/ssh-certificate-authority-service.ts | 4 +-
.../src/services/auth/auth-login-service.ts | 6 +-
backend/src/services/org/org-service.ts | 12 +-
.../services/secret-sync/secret-sync-fns.ts | 2 +-
.../services/secret-sync/secret-sync-queue.ts | 2 +-
.../secret-v2-bridge/secret-v2-bridge-dal.ts | 2 +-
backend/src/services/secret/secret-queue.ts | 2 +-
.../emails/AccessApprovalRequestTemplate.tsx | 95 +
.../services/smtp/emails/BaseEmailWrapper.tsx | 45 +
.../services/smtp/emails/EmailMfaTemplate.tsx | 50 +
.../smtp/emails/EmailVerificationTemplate.tsx | 53 +
.../emails/ExternalImportFailedTemplate.tsx | 43 +
.../emails/ExternalImportStartedTemplate.tsx | 30 +
.../ExternalImportSucceededTemplate.tsx | 31 +
.../emails/IntegrationSyncFailedTemplate.tsx | 65 +
.../smtp/emails/NewDeviceLoginTemplate.tsx | 68 +
.../OrgAdminBreakglassAccessTemplate.tsx | 57 +
.../OrgAdminProjectGrantAccessTemplate.tsx | 40 +
.../emails/OrganizationInvitationTemplate.tsx | 75 +
.../smtp/emails/PasswordResetTemplate.tsx | 58 +
.../smtp/emails/PasswordSetupTemplate.tsx | 57 +
.../emails/PkiExpirationAlertTemplate.tsx | 68 +
.../emails/ProjectAccessRequestTemplate.tsx | 68 +
.../smtp/emails/ProjectInvitationTemplate.tsx | 50 +
.../emails/ScimUserProvisionedTemplate.tsx | 56 +
.../SecretApprovalRequestBypassedTemplate.tsx | 72 +
...cretApprovalRequestNeedsReviewTemplate.tsx | 57 +
.../emails/SecretLeakIncidentTemplate.tsx | 82 +
.../smtp/emails/SecretReminderTemplate.tsx | 45 +
.../emails/SecretRequestCompletedTemplate.tsx | 53 +
.../emails/SecretRotationFailedTemplate.tsx | 68 +
.../smtp/emails/SecretSyncFailedTemplate.tsx | 80 +
.../ServiceTokenExpiryNoticeTemplate.tsx | 53 +
.../SignupEmailVerificationTemplate.tsx | 53 +
.../smtp/emails/UnlockAccountTemplate.tsx | 46 +
backend/src/services/smtp/emails/index.ts | 28 +
backend/src/services/smtp/smtp-service.ts | 112 -
backend/src/services/smtp/smtp-service.tsx | 179 ++
.../accessApprovalRequest.handlebars | 55 -
.../accessSecretRequestBypassed.handlebars | 33 -
.../smtp/templates/emailMfa.handlebars | 20 -
.../templates/emailVerification.handlebars | 17 -
.../historicalSecretLeakIncident.handlebars | 21 -
.../integrationSyncFailed.handlebars | 33 -
.../smtp/templates/newDevice.handlebars | 22 -
.../orgAdminBreakglassAccess.handlebars | 20 -
.../orgAdminProjectGrantAccess.handlebars | 16 -
.../organizationInvitation.handlebars | 18 -
.../smtp/templates/passwordReset.handlebars | 16 -
.../smtp/templates/passwordSetup.handlebars | 17 -
.../templates/pkiExpirationAlert.handlebars | 33 -
.../smtp/templates/projectAccess.handlebars | 26 -
.../templates/scimUserProvisioned.handlebars | 18 -
...ecretApprovalRequestNeedsReview.handlebars | 24 -
.../templates/secretLeakIncident.handlebars | 27 -
.../smtp/templates/secretReminder.handlebars | 20 -
.../secretRequestCompleted.handlebars | 33 -
.../templates/secretRotationFailed.handlebars | 31 -
.../templates/secretSyncFailed.handlebars | 39 -
.../templates/serviceTokenExpired.handlebars | 19 -
.../signupEmailVerification.handlebars | 19 -
.../smtp/templates/unlockAccount.handlebars | 18 -
.../templates/workspaceInvitation.handlebars | 17 -
.../super-admin/super-admin-service.ts | 4 +-
backend/tsconfig.json | 3 +-
69 files changed, 4224 insertions(+), 874 deletions(-)
create mode 100644 backend/src/services/smtp/emails/AccessApprovalRequestTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/BaseEmailWrapper.tsx
create mode 100644 backend/src/services/smtp/emails/EmailMfaTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/EmailVerificationTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/ExternalImportFailedTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/ExternalImportStartedTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/ExternalImportSucceededTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/IntegrationSyncFailedTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/NewDeviceLoginTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/OrgAdminBreakglassAccessTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/OrgAdminProjectGrantAccessTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/OrganizationInvitationTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/PasswordResetTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/PasswordSetupTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/PkiExpirationAlertTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/ProjectAccessRequestTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/ProjectInvitationTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/ScimUserProvisionedTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/SecretApprovalRequestBypassedTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/SecretApprovalRequestNeedsReviewTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/SecretLeakIncidentTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/SecretReminderTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/SecretRequestCompletedTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/SecretRotationFailedTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/SecretSyncFailedTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/ServiceTokenExpiryNoticeTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/SignupEmailVerificationTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/UnlockAccountTemplate.tsx
create mode 100644 backend/src/services/smtp/emails/index.ts
delete mode 100644 backend/src/services/smtp/smtp-service.ts
create mode 100644 backend/src/services/smtp/smtp-service.tsx
delete mode 100644 backend/src/services/smtp/templates/accessApprovalRequest.handlebars
delete mode 100644 backend/src/services/smtp/templates/accessSecretRequestBypassed.handlebars
delete mode 100644 backend/src/services/smtp/templates/emailMfa.handlebars
delete mode 100644 backend/src/services/smtp/templates/emailVerification.handlebars
delete mode 100644 backend/src/services/smtp/templates/historicalSecretLeakIncident.handlebars
delete mode 100644 backend/src/services/smtp/templates/integrationSyncFailed.handlebars
delete mode 100644 backend/src/services/smtp/templates/newDevice.handlebars
delete mode 100644 backend/src/services/smtp/templates/orgAdminBreakglassAccess.handlebars
delete mode 100644 backend/src/services/smtp/templates/orgAdminProjectGrantAccess.handlebars
delete mode 100644 backend/src/services/smtp/templates/organizationInvitation.handlebars
delete mode 100644 backend/src/services/smtp/templates/passwordReset.handlebars
delete mode 100644 backend/src/services/smtp/templates/passwordSetup.handlebars
delete mode 100644 backend/src/services/smtp/templates/pkiExpirationAlert.handlebars
delete mode 100644 backend/src/services/smtp/templates/projectAccess.handlebars
delete mode 100644 backend/src/services/smtp/templates/scimUserProvisioned.handlebars
delete mode 100644 backend/src/services/smtp/templates/secretApprovalRequestNeedsReview.handlebars
delete mode 100644 backend/src/services/smtp/templates/secretLeakIncident.handlebars
delete mode 100644 backend/src/services/smtp/templates/secretReminder.handlebars
delete mode 100644 backend/src/services/smtp/templates/secretRequestCompleted.handlebars
delete mode 100644 backend/src/services/smtp/templates/secretRotationFailed.handlebars
delete mode 100644 backend/src/services/smtp/templates/secretSyncFailed.handlebars
delete mode 100644 backend/src/services/smtp/templates/serviceTokenExpired.handlebars
delete mode 100644 backend/src/services/smtp/templates/signupEmailVerification.handlebars
delete mode 100644 backend/src/services/smtp/templates/unlockAccount.handlebars
delete mode 100644 backend/src/services/smtp/templates/workspaceInvitation.handlebars
diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js
index b23cf05ae3..f901f0df9d 100644
--- a/backend/.eslintrc.js
+++ b/backend/.eslintrc.js
@@ -69,6 +69,15 @@ module.exports = {
["^\\."]
]
}
+ ],
+ "import/extensions": [
+ "error",
+ "ignorePackages",
+ {
+ "": "never", // this is required to get the .tsx to work...
+ ts: "never",
+ tsx: "never"
+ }
]
}
};
diff --git a/backend/package-lock.json b/backend/package-lock.json
index 19e10942ee..93c28c9e29 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -48,6 +48,7 @@
"@opentelemetry/semantic-conventions": "^1.27.0",
"@peculiar/asn1-schema": "^2.3.8",
"@peculiar/x509": "^1.12.1",
+ "@react-email/components": "0.0.36",
"@serdnam/pino-cloudwatch-transport": "^1.0.4",
"@sindresorhus/slugify": "1.1.0",
"@slack/oauth": "^3.0.2",
@@ -107,6 +108,8 @@
"posthog-node": "^3.6.2",
"probot": "^13.3.8",
"re2": "^1.21.4",
+ "react": "19.1.0",
+ "react-dom": "19.1.0",
"safe-regex": "^2.1.1",
"scim-patch": "^0.8.3",
"scim2-parse-filter": "^0.2.10",
@@ -142,6 +145,7 @@
"@types/picomatch": "^2.3.3",
"@types/pkcs11js": "^1.0.4",
"@types/prompt-sync": "^4.2.3",
+ "@types/react": "^19.1.2",
"@types/resolve": "^1.20.6",
"@types/safe-regex": "^1.1.6",
"@types/sjcl": "^1.0.34",
@@ -161,6 +165,7 @@
"nodemon": "^3.0.2",
"pino-pretty": "^10.2.3",
"prompt-sync": "^4.2.0",
+ "react-email": "4.0.7",
"rimraf": "^5.0.5",
"ts-node": "^10.9.2",
"tsc-alias": "^1.8.8",
@@ -2902,13 +2907,15 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
- "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+ "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@babel/highlight": "^7.24.7",
- "picocolors": "^1.0.0"
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
},
"engines": {
"node": ">=6.9.0"
@@ -2986,15 +2993,17 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz",
- "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.1.tgz",
+ "integrity": "sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@babel/types": "^7.24.7",
+ "@babel/parser": "^7.27.1",
+ "@babel/types": "^7.27.1",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
- "jsesc": "^2.5.1"
+ "jsesc": "^3.0.2"
},
"engines": {
"node": ">=6.9.0"
@@ -3010,6 +3019,19 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@babel/generator/node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/@babel/helper-annotate-as-pure": {
"version": "7.24.7",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz",
@@ -3348,19 +3370,21 @@
}
},
"node_modules/@babel/helper-string-parser": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz",
- "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
- "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
+ "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
@@ -3402,76 +3426,15 @@
"node": ">=6.9.0"
}
},
- "node_modules/@babel/highlight": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
- "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
- "dev": true,
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.24.7",
- "chalk": "^2.4.2",
- "js-tokens": "^4.0.0",
- "picocolors": "^1.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/highlight/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/highlight/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/highlight/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/@babel/highlight/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
- },
- "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
"node_modules/@babel/parser": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz",
- "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.1.tgz",
+ "integrity": "sha512-I0dZ3ZpCrJ1c04OqlNsQcKiZlsrXf/kkE4FXzID9rIOYICsAbA8mMDzhW/luRNAHdCNt7os/u8wenklZDlUVUQ==",
"dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.27.1"
+ },
"bin": {
"parser": "bin/babel-parser.js"
},
@@ -4807,33 +4770,32 @@
}
},
"node_modules/@babel/template": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
- "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.1.tgz",
+ "integrity": "sha512-Fyo3ghWMqkHHpHQCoBs2VnYjR4iWFFjguTDEqA5WgZDOrFesVjMhMM2FSqTKSoUSDO1VQtavj8NFpdRBEvJTtg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@babel/code-frame": "^7.24.7",
- "@babel/parser": "^7.24.7",
- "@babel/types": "^7.24.7"
+ "@babel/code-frame": "^7.27.1",
+ "@babel/parser": "^7.27.1",
+ "@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz",
- "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==",
+ "version": "7.25.6",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz",
+ "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.24.7",
- "@babel/generator": "^7.24.7",
- "@babel/helper-environment-visitor": "^7.24.7",
- "@babel/helper-function-name": "^7.24.7",
- "@babel/helper-hoist-variables": "^7.24.7",
- "@babel/helper-split-export-declaration": "^7.24.7",
- "@babel/parser": "^7.24.7",
- "@babel/types": "^7.24.7",
+ "@babel/generator": "^7.25.6",
+ "@babel/parser": "^7.25.6",
+ "@babel/template": "^7.25.0",
+ "@babel/types": "^7.25.6",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
@@ -4874,14 +4836,14 @@
"dev": true
},
"node_modules/@babel/types": {
- "version": "7.24.7",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz",
- "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==",
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz",
+ "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@babel/helper-string-parser": "^7.24.7",
- "@babel/helper-validator-identifier": "^7.24.7",
- "to-fast-properties": "^2.0.0"
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
@@ -5192,6 +5154,17 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"license": "MIT"
},
+ "node_modules/@emnapi/runtime": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz",
+ "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@@ -5465,6 +5438,23 @@
"node": ">=12"
}
},
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
+ "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@esbuild/netbsd-x64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
@@ -5481,6 +5471,23 @@
"node": ">=12"
}
},
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
+ "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@esbuild/openbsd-x64": {
"version": "0.18.20",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
@@ -6222,6 +6229,386 @@
"integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
"dev": true
},
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
+ "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
+ "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
+ "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
+ "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
+ "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
+ "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
+ "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
+ "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
+ "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
+ "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
+ "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.0.5"
+ }
+ },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
+ "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
+ "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
+ "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
+ "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
+ "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4"
+ }
+ },
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
+ "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/runtime": "^1.2.0"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
+ "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
+ "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
"node_modules/@infisical/quic": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@infisical/quic/-/quic-1.0.8.tgz",
@@ -6759,6 +7146,149 @@
"win32"
]
},
+ "node_modules/@next/env": {
+ "version": "15.2.4",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-15.2.4.tgz",
+ "integrity": "sha512-+SFtMgoiYP3WoSswuNmxJOCwi06TdWE733D+WPjpXIe4LXGULwEaofiiAy6kbS0+XjM5xF5n3lKuBwN2SnqD9g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@next/swc-darwin-arm64": {
+ "version": "15.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.2.4.tgz",
+ "integrity": "sha512-1AnMfs655ipJEDC/FHkSr0r3lXBgpqKo4K1kiwfUf3iE68rDFXZ1TtHdMvf7D0hMItgDZ7Vuq3JgNMbt/+3bYw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-darwin-x64": {
+ "version": "15.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.2.4.tgz",
+ "integrity": "sha512-3qK2zb5EwCwxnO2HeO+TRqCubeI/NgCe+kL5dTJlPldV/uwCnUgC7VbEzgmxbfrkbjehL4H9BPztWOEtsoMwew==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-gnu": {
+ "version": "15.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.2.4.tgz",
+ "integrity": "sha512-HFN6GKUcrTWvem8AZN7tT95zPb0GUGv9v0d0iyuTb303vbXkkbHDp/DxufB04jNVD+IN9yHy7y/6Mqq0h0YVaQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-arm64-musl": {
+ "version": "15.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.2.4.tgz",
+ "integrity": "sha512-Oioa0SORWLwi35/kVB8aCk5Uq+5/ZIumMK1kJV+jSdazFm2NzPDztsefzdmzzpx5oGCJ6FkUC7vkaUseNTStNA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-gnu": {
+ "version": "15.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.2.4.tgz",
+ "integrity": "sha512-yb5WTRaHdkgOqFOZiu6rHV1fAEK0flVpaIN2HB6kxHVSy/dIajWbThS7qON3W9/SNOH2JWkVCyulgGYekMePuw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-linux-x64-musl": {
+ "version": "15.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.2.4.tgz",
+ "integrity": "sha512-Dcdv/ix6srhkM25fgXiyOieFUkz+fOYkHlydWCtB0xMST6X9XYI3yPDKBZt1xuhOytONsIFJFB08xXYsxUwJLw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-arm64-msvc": {
+ "version": "15.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.2.4.tgz",
+ "integrity": "sha512-dW0i7eukvDxtIhCYkMrZNQfNicPDExt2jPb9AZPpL7cfyUo7QSNl1DjsHjmmKp6qNAqUESyT8YFl/Aw91cNJJg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@next/swc-win32-x64-msvc": {
+ "version": "15.2.4",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.2.4.tgz",
+ "integrity": "sha512-SbnWkJmkS7Xl3kre8SdMF6F/XDh1DTFEhp0jRTj/uB8iPKoU2bb2NDfcu+iifv1+mxQEd1g2vvSxcZbXSKyWiQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/@nicolo-ribaudo/chokidar-2": {
"version": "2.1.8-no-fsevents.3",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz",
@@ -8519,6 +9049,286 @@
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
},
+ "node_modules/@react-email/body": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/@react-email/body/-/body-0.0.11.tgz",
+ "integrity": "sha512-ZSD2SxVSgUjHGrB0Wi+4tu3MEpB4fYSbezsFNEJk2xCWDBkFiOeEsjTmR5dvi+CxTK691hQTQlHv0XWuP7ENTg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/button": {
+ "version": "0.0.19",
+ "resolved": "https://registry.npmjs.org/@react-email/button/-/button-0.0.19.tgz",
+ "integrity": "sha512-HYHrhyVGt7rdM/ls6FuuD6XE7fa7bjZTJqB2byn6/oGsfiEZaogY77OtoLL/mrQHjHjZiJadtAMSik9XLcm7+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/code-block": {
+ "version": "0.0.12",
+ "resolved": "https://registry.npmjs.org/@react-email/code-block/-/code-block-0.0.12.tgz",
+ "integrity": "sha512-Faw3Ij9+/Qwq6moWaeHnV8Hn7ekc/EqyAzPi6yUar21dhcqYugCC4Da1x4d9nA9zC0H9KU3lYVJczh8D3cA+Eg==",
+ "license": "MIT",
+ "dependencies": {
+ "prismjs": "1.30.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/code-inline": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/@react-email/code-inline/-/code-inline-0.0.5.tgz",
+ "integrity": "sha512-MmAsOzdJpzsnY2cZoPHFPk6uDO/Ncpb4Kh1hAt9UZc1xOW3fIzpe1Pi9y9p6wwUmpaeeDalJxAxH6/fnTquinA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/column": {
+ "version": "0.0.13",
+ "resolved": "https://registry.npmjs.org/@react-email/column/-/column-0.0.13.tgz",
+ "integrity": "sha512-Lqq17l7ShzJG/d3b1w/+lVO+gp2FM05ZUo/nW0rjxB8xBICXOVv6PqjDnn3FXKssvhO5qAV20lHM6S+spRhEwQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/components": {
+ "version": "0.0.36",
+ "resolved": "https://registry.npmjs.org/@react-email/components/-/components-0.0.36.tgz",
+ "integrity": "sha512-VMh+OQplAnG8JMLlJjdnjt+ThJZ+JVkp0q2YMS2NEz+T88N22bLD2p7DZO0QgtNaKgumOhJI/0a2Q7VzCrwu5g==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-email/body": "0.0.11",
+ "@react-email/button": "0.0.19",
+ "@react-email/code-block": "0.0.12",
+ "@react-email/code-inline": "0.0.5",
+ "@react-email/column": "0.0.13",
+ "@react-email/container": "0.0.15",
+ "@react-email/font": "0.0.9",
+ "@react-email/head": "0.0.12",
+ "@react-email/heading": "0.0.15",
+ "@react-email/hr": "0.0.11",
+ "@react-email/html": "0.0.11",
+ "@react-email/img": "0.0.11",
+ "@react-email/link": "0.0.12",
+ "@react-email/markdown": "0.0.14",
+ "@react-email/preview": "0.0.12",
+ "@react-email/render": "1.0.6",
+ "@react-email/row": "0.0.12",
+ "@react-email/section": "0.0.16",
+ "@react-email/tailwind": "1.0.4",
+ "@react-email/text": "0.1.1"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/container": {
+ "version": "0.0.15",
+ "resolved": "https://registry.npmjs.org/@react-email/container/-/container-0.0.15.tgz",
+ "integrity": "sha512-Qo2IQo0ru2kZq47REmHW3iXjAQaKu4tpeq/M8m1zHIVwKduL2vYOBQWbC2oDnMtWPmkBjej6XxgtZByxM6cCFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/font": {
+ "version": "0.0.9",
+ "resolved": "https://registry.npmjs.org/@react-email/font/-/font-0.0.9.tgz",
+ "integrity": "sha512-4zjq23oT9APXkerqeslPH3OZWuh5X4crHK6nx82mVHV2SrLba8+8dPEnWbaACWTNjOCbcLIzaC9unk7Wq2MIXw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/head": {
+ "version": "0.0.12",
+ "resolved": "https://registry.npmjs.org/@react-email/head/-/head-0.0.12.tgz",
+ "integrity": "sha512-X2Ii6dDFMF+D4niNwMAHbTkeCjlYYnMsd7edXOsi0JByxt9wNyZ9EnhFiBoQdqkE+SMDcu8TlNNttMrf5sJeMA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/heading": {
+ "version": "0.0.15",
+ "resolved": "https://registry.npmjs.org/@react-email/heading/-/heading-0.0.15.tgz",
+ "integrity": "sha512-xF2GqsvBrp/HbRHWEfOgSfRFX+Q8I5KBEIG5+Lv3Vb2R/NYr0s8A5JhHHGf2pWBMJdbP4B2WHgj/VUrhy8dkIg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/hr": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/@react-email/hr/-/hr-0.0.11.tgz",
+ "integrity": "sha512-S1gZHVhwOsd1Iad5IFhpfICwNPMGPJidG/Uysy1AwmspyoAP5a4Iw3OWEpINFdgh9MHladbxcLKO2AJO+cA9Lw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/html": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/@react-email/html/-/html-0.0.11.tgz",
+ "integrity": "sha512-qJhbOQy5VW5qzU74AimjAR9FRFQfrMa7dn4gkEXKMB/S9xZN8e1yC1uA9C15jkXI/PzmJ0muDIWmFwatm5/+VA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/img": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/@react-email/img/-/img-0.0.11.tgz",
+ "integrity": "sha512-aGc8Y6U5C3igoMaqAJKsCpkbm1XjguQ09Acd+YcTKwjnC2+0w3yGUJkjWB2vTx4tN8dCqQCXO8FmdJpMfOA9EQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/link": {
+ "version": "0.0.12",
+ "resolved": "https://registry.npmjs.org/@react-email/link/-/link-0.0.12.tgz",
+ "integrity": "sha512-vF+xxQk2fGS1CN7UPQDbzvcBGfffr+GjTPNiWM38fhBfsLv6A/YUfaqxWlmL7zLzVmo0K2cvvV9wxlSyNba1aQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/markdown": {
+ "version": "0.0.14",
+ "resolved": "https://registry.npmjs.org/@react-email/markdown/-/markdown-0.0.14.tgz",
+ "integrity": "sha512-5IsobCyPkb4XwnQO8uFfGcNOxnsg3311GRXhJ3uKv51P7Jxme4ycC/MITnwIZ10w2zx7HIyTiqVzTj4XbuIHbg==",
+ "license": "MIT",
+ "dependencies": {
+ "md-to-react-email": "5.0.5"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/preview": {
+ "version": "0.0.12",
+ "resolved": "https://registry.npmjs.org/@react-email/preview/-/preview-0.0.12.tgz",
+ "integrity": "sha512-g/H5fa9PQPDK6WUEG7iTlC19sAktI23qyoiJtMLqQiXFCfWeQMhqjLGKeLSKkfzszqmfJCjZtpSiKtBoOdxp3Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/render": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@react-email/render/-/render-1.0.6.tgz",
+ "integrity": "sha512-zNueW5Wn/4jNC1c5LFgXzbUdv5Lhms+FWjOvWAhal7gx5YVf0q6dPJ0dnR70+ifo59gcMLwCZEaTS9EEuUhKvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "html-to-text": "9.0.5",
+ "prettier": "3.5.3",
+ "react-promise-suspense": "0.3.4"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/row": {
+ "version": "0.0.12",
+ "resolved": "https://registry.npmjs.org/@react-email/row/-/row-0.0.12.tgz",
+ "integrity": "sha512-HkCdnEjvK3o+n0y0tZKXYhIXUNPDx+2vq1dJTmqappVHXS5tXS6W5JOPZr5j+eoZ8gY3PShI2LWj5rWF7ZEtIQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/section": {
+ "version": "0.0.16",
+ "resolved": "https://registry.npmjs.org/@react-email/section/-/section-0.0.16.tgz",
+ "integrity": "sha512-FjqF9xQ8FoeUZYKSdt8sMIKvoT9XF8BrzhT3xiFKdEMwYNbsDflcjfErJe3jb7Wj/es/lKTbV5QR1dnLzGpL3w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/tailwind": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@react-email/tailwind/-/tailwind-1.0.4.tgz",
+ "integrity": "sha512-tJdcusncdqgvTUYZIuhNC6LYTfL9vNTSQpwWdTCQhQ1lsrNCEE4OKCSdzSV3S9F32pi0i0xQ+YPJHKIzGjdTSA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
+ "node_modules/@react-email/text": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@react-email/text/-/text-0.1.1.tgz",
+ "integrity": "sha512-Zo9tSEzkO3fODLVH1yVhzVCiwETfeEL5wU93jXKWo2DHoMuiZ9Iabaso3T0D0UjhrCB1PBMeq2YiejqeToTyIQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0 || ^19.0.0-rc"
+ }
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
@@ -8743,6 +9553,19 @@
"win32"
]
},
+ "node_modules/@selderee/plugin-htmlparser2": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
+ "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==",
+ "license": "MIT",
+ "dependencies": {
+ "domhandler": "^5.0.3",
+ "selderee": "^0.11.0"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
"node_modules/@sentry-internal/tracing": {
"version": "7.119.2",
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.119.2.tgz",
@@ -9659,6 +10482,13 @@
"node": ">=16.0.0"
}
},
+ "node_modules/@socket.io/component-emitter": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
+ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@swc/core": {
"version": "1.3.107",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.107.tgz",
@@ -9870,22 +10700,20 @@
}
},
"node_modules/@swc/counter": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz",
- "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==",
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
+ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
"dev": true,
- "optional": true,
- "peer": true
+ "license": "Apache-2.0"
},
"node_modules/@swc/helpers": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.3.tgz",
- "integrity": "sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==",
+ "version": "0.5.15",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
+ "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
"dev": true,
- "optional": true,
- "peer": true,
+ "license": "Apache-2.0",
"dependencies": {
- "tslib": "^2.4.0"
+ "tslib": "^2.8.0"
}
},
"node_modules/@swc/types": {
@@ -9979,6 +10807,16 @@
"@types/node": "*"
}
},
+ "node_modules/@types/cors": {
+ "version": "2.8.17",
+ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
+ "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/debug": {
"version": "4.1.12",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
@@ -10287,6 +11125,16 @@
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ=="
},
+ "node_modules/@types/react": {
+ "version": "19.1.2",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz",
+ "integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.0.2"
+ }
+ },
"node_modules/@types/readable-stream": {
"version": "4.0.14",
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.14.tgz",
@@ -11914,6 +12762,16 @@
}
]
},
+ "node_modules/base64id": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
+ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^4.5.0 || >= 5.9"
+ }
+ },
"node_modules/base64url": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz",
@@ -12454,6 +13312,18 @@
"esbuild": ">=0.17"
}
},
+ "node_modules/busboy": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
+ "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
+ "dev": true,
+ "dependencies": {
+ "streamsearch": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=10.16.0"
+ }
+ },
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -12794,6 +13664,13 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/client-only": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
+ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -12863,6 +13740,16 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
+ "node_modules/clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
@@ -13053,6 +13940,20 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
},
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/create-hash": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
@@ -13130,6 +14031,13 @@
"node": ">=18"
}
},
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/data-urls": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
@@ -13262,6 +14170,19 @@
"node": ">= 8"
}
},
+ "node_modules/debounce": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/debounce/-/debounce-2.0.0.tgz",
+ "integrity": "sha512-xRetU6gL1VJbs85Mc4FoEGSjQxzpdxRyFhe3lmWFyy2EzydIcD4xzUvRJMD+NPDfMwKNhxa3PvsIOU32luIWeA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
@@ -13354,6 +14275,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/defaults": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
+ "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "clone": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
@@ -13465,9 +14399,10 @@
}
},
"node_modules/detect-libc": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz",
- "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
+ "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
+ "license": "Apache-2.0",
"engines": {
"node": ">=8"
}
@@ -13697,6 +14632,77 @@
"once": "^1.4.0"
}
},
+ "node_modules/engine.io": {
+ "version": "6.6.4",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz",
+ "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/cors": "^2.8.12",
+ "@types/node": ">=10.0.0",
+ "accepts": "~1.3.4",
+ "base64id": "2.0.0",
+ "cookie": "~0.7.2",
+ "cors": "~2.8.5",
+ "debug": "~4.3.1",
+ "engine.io-parser": "~5.2.1",
+ "ws": "~8.17.1"
+ },
+ "engines": {
+ "node": ">=10.2.0"
+ }
+ },
+ "node_modules/engine.io-parser": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
+ "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/engine.io/node_modules/debug": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/engine.io/node_modules/ws": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+ "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
"node_modules/enhanced-resolve": {
"version": "5.15.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz",
@@ -16116,6 +17122,41 @@
],
"license": "MIT"
},
+ "node_modules/html-to-text": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz",
+ "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==",
+ "license": "MIT",
+ "dependencies": {
+ "@selderee/plugin-htmlparser2": "^0.11.0",
+ "deepmerge": "^4.3.1",
+ "dom-serializer": "^2.0.0",
+ "htmlparser2": "^8.0.2",
+ "selderee": "^0.11.0"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/html-to-text/node_modules/htmlparser2": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
+ "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1",
+ "entities": "^4.4.0"
+ }
+ },
"node_modules/htmlparser2": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
@@ -16975,7 +18016,8 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/js-yaml": {
"version": "4.1.0",
@@ -17487,6 +18529,15 @@
"integrity": "sha512-8s46m/r2lSFO2+DqMxqWiJ10iiL4tuR5LC/KndV+E5//OAOzOx5s3HS5O34PJ5+kyaCA+K2oCaEPaDRfXUnQow==",
"license": "MIT"
},
+ "node_modules/leac": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
+ "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
"node_modules/leven": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz",
@@ -17872,6 +18923,18 @@
"node": ">=16 || 14 >=14.17"
}
},
+ "node_modules/marked": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-7.0.4.tgz",
+ "integrity": "sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ==",
+ "license": "MIT",
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 16"
+ }
+ },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -17880,6 +18943,18 @@
"node": ">= 0.4"
}
},
+ "node_modules/md-to-react-email": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/md-to-react-email/-/md-to-react-email-5.0.5.tgz",
+ "integrity": "sha512-OvAXqwq57uOk+WZqFFNCMZz8yDp8BD3WazW1wAKHUrPbbdr89K9DWS6JXY09vd9xNdPNeurI8DU/X4flcfaD8A==",
+ "license": "MIT",
+ "dependencies": {
+ "marked": "7.0.4"
+ },
+ "peerDependencies": {
+ "react": "^18.0 || ^19.0"
+ }
+ },
"node_modules/md5.js": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@@ -18540,6 +19615,90 @@
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
+ "node_modules/next": {
+ "version": "15.2.4",
+ "resolved": "https://registry.npmjs.org/next/-/next-15.2.4.tgz",
+ "integrity": "sha512-VwL+LAaPSxEkd3lU2xWbgEOtrM8oedmyhBqaVNmgKB+GvZlCy9rgaEc+y2on0wv+l0oSFqLtYD6dcC1eAedUaQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@next/env": "15.2.4",
+ "@swc/counter": "0.1.3",
+ "@swc/helpers": "0.5.15",
+ "busboy": "1.6.0",
+ "caniuse-lite": "^1.0.30001579",
+ "postcss": "8.4.31",
+ "styled-jsx": "5.1.6"
+ },
+ "bin": {
+ "next": "dist/bin/next"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
+ },
+ "optionalDependencies": {
+ "@next/swc-darwin-arm64": "15.2.4",
+ "@next/swc-darwin-x64": "15.2.4",
+ "@next/swc-linux-arm64-gnu": "15.2.4",
+ "@next/swc-linux-arm64-musl": "15.2.4",
+ "@next/swc-linux-x64-gnu": "15.2.4",
+ "@next/swc-linux-x64-musl": "15.2.4",
+ "@next/swc-win32-arm64-msvc": "15.2.4",
+ "@next/swc-win32-x64-msvc": "15.2.4",
+ "sharp": "^0.33.5"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "^1.1.0",
+ "@playwright/test": "^1.41.2",
+ "babel-plugin-react-compiler": "*",
+ "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+ "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+ "sass": "^1.3.0"
+ },
+ "peerDependenciesMeta": {
+ "@opentelemetry/api": {
+ "optional": true
+ },
+ "@playwright/test": {
+ "optional": true
+ },
+ "babel-plugin-react-compiler": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/next/node_modules/postcss": {
+ "version": "8.4.31",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
+ "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
"node_modules/node-abi": {
"version": "3.65.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz",
@@ -19557,6 +20716,19 @@
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
+ "node_modules/parseley": {
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz",
+ "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==",
+ "license": "MIT",
+ "dependencies": {
+ "leac": "^0.6.0",
+ "peberminta": "^0.9.0"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -19732,6 +20904,15 @@
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
},
+ "node_modules/peberminta": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
+ "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
"node_modules/pg": {
"version": "8.13.1",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.13.1.tgz",
@@ -20320,11 +21501,10 @@
}
},
"node_modules/prettier": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz",
- "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==",
- "dev": true,
- "peer": true,
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
+ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
+ "license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -20373,6 +21553,15 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/prismjs": {
+ "version": "1.30.0",
+ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
+ "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/probot": {
"version": "13.3.8",
"resolved": "https://registry.npmjs.org/probot/-/probot-13.3.8.tgz",
@@ -20928,12 +22117,817 @@
"node-gyp": "^10.2.0"
}
},
+ "node_modules/react": {
+ "version": "19.1.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
+ "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.1.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
+ "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.26.0"
+ },
+ "peerDependencies": {
+ "react": "^19.1.0"
+ }
+ },
+ "node_modules/react-email": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/react-email/-/react-email-4.0.7.tgz",
+ "integrity": "sha512-XCXlfZLKv9gHd/ZwUEhCpRGc/FJLZGYczeuG1kVR/be2PlkwEB4gjX9ARBbRFv86ncbtpOu/wI6jD6kadRyAKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "7.24.5",
+ "@babel/traverse": "7.25.6",
+ "chalk": "4.1.2",
+ "chokidar": "4.0.3",
+ "commander": "11.1.0",
+ "debounce": "2.0.0",
+ "esbuild": "0.25.0",
+ "glob": "10.3.4",
+ "log-symbols": "4.1.0",
+ "mime-types": "2.1.35",
+ "next": "15.2.4",
+ "normalize-path": "3.0.0",
+ "ora": "5.4.1",
+ "socket.io": "4.8.1"
+ },
+ "bin": {
+ "email": "dist/cli/index.js"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/react-email/node_modules/@babel/parser": {
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz",
+ "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
+ "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/android-arm": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
+ "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/android-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
+ "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/android-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
+ "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
+ "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
+ "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
+ "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
+ "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/linux-arm": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
+ "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
+ "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
+ "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
+ "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
+ "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
+ "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
+ "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
+ "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/linux-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
+ "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
+ "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
+ "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
+ "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
+ "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
+ "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/@esbuild/win32-x64": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
+ "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/react-email/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/react-email/node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/react-email/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/react-email/node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/react-email/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/react-email/node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/react-email/node_modules/cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "restore-cursor": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/react-email/node_modules/commander": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
+ "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/react-email/node_modules/esbuild": {
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
+ "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.0",
+ "@esbuild/android-arm": "0.25.0",
+ "@esbuild/android-arm64": "0.25.0",
+ "@esbuild/android-x64": "0.25.0",
+ "@esbuild/darwin-arm64": "0.25.0",
+ "@esbuild/darwin-x64": "0.25.0",
+ "@esbuild/freebsd-arm64": "0.25.0",
+ "@esbuild/freebsd-x64": "0.25.0",
+ "@esbuild/linux-arm": "0.25.0",
+ "@esbuild/linux-arm64": "0.25.0",
+ "@esbuild/linux-ia32": "0.25.0",
+ "@esbuild/linux-loong64": "0.25.0",
+ "@esbuild/linux-mips64el": "0.25.0",
+ "@esbuild/linux-ppc64": "0.25.0",
+ "@esbuild/linux-riscv64": "0.25.0",
+ "@esbuild/linux-s390x": "0.25.0",
+ "@esbuild/linux-x64": "0.25.0",
+ "@esbuild/netbsd-arm64": "0.25.0",
+ "@esbuild/netbsd-x64": "0.25.0",
+ "@esbuild/openbsd-arm64": "0.25.0",
+ "@esbuild/openbsd-x64": "0.25.0",
+ "@esbuild/sunos-x64": "0.25.0",
+ "@esbuild/win32-arm64": "0.25.0",
+ "@esbuild/win32-ia32": "0.25.0",
+ "@esbuild/win32-x64": "0.25.0"
+ }
+ },
+ "node_modules/react-email/node_modules/glob": {
+ "version": "10.3.4",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.4.tgz",
+ "integrity": "sha512-6LFElP3A+i/Q8XQKEvZjkEWEOTgAIALR9AO2rwT8bgPhDd1anmqDJDZ6lLddI4ehxxxR1S5RIqKe1uapMQfYaQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^2.0.3",
+ "minimatch": "^9.0.1",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
+ "path-scurry": "^1.10.1"
+ },
+ "bin": {
+ "glob": "dist/cjs/src/bin.js"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/react-email/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/react-email/node_modules/is-interactive": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+ "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/react-email/node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/react-email/node_modules/log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/react-email/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/react-email/node_modules/ora": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
+ "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bl": "^4.1.0",
+ "chalk": "^4.1.0",
+ "cli-cursor": "^3.1.0",
+ "cli-spinners": "^2.5.0",
+ "is-interactive": "^1.0.0",
+ "is-unicode-supported": "^0.1.0",
+ "log-symbols": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "wcwidth": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/react-email/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/react-email/node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/react-email/node_modules/restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/react-email/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/react-email/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
"dev": true
},
+ "node_modules/react-promise-suspense": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/react-promise-suspense/-/react-promise-suspense-0.3.4.tgz",
+ "integrity": "sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^2.0.1"
+ }
+ },
+ "node_modules/react-promise-suspense/node_modules/fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==",
+ "license": "MIT"
+ },
"node_modules/readable-stream": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
@@ -21509,6 +23503,12 @@
"node": ">=v12.22.7"
}
},
+ "node_modules/scheduler": {
+ "version": "0.26.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
+ "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
+ "license": "MIT"
+ },
"node_modules/scim-patch": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/scim-patch/-/scim-patch-0.8.3.tgz",
@@ -21537,18 +23537,28 @@
"resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
"integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="
},
+ "node_modules/selderee": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz",
+ "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==",
+ "license": "MIT",
+ "dependencies": {
+ "parseley": "^0.12.0"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/killymxi"
+ }
+ },
"node_modules/semifies": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/semifies/-/semifies-1.0.0.tgz",
"integrity": "sha512-xXR3KGeoxTNWPD4aBvL5NUpMTT7WMANr3EWnaS190QVkY52lqqcVRD7Q05UVbBhiWDGWMlJEUam9m7uFFGVScw=="
},
"node_modules/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+ "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -21708,6 +23718,62 @@
"sha.js": "bin.js"
}
},
+ "node_modules/sharp": {
+ "version": "0.33.5",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
+ "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "color": "^4.2.3",
+ "detect-libc": "^2.0.3",
+ "semver": "^7.6.3"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.33.5",
+ "@img/sharp-darwin-x64": "0.33.5",
+ "@img/sharp-libvips-darwin-arm64": "1.0.4",
+ "@img/sharp-libvips-darwin-x64": "1.0.4",
+ "@img/sharp-libvips-linux-arm": "1.0.5",
+ "@img/sharp-libvips-linux-arm64": "1.0.4",
+ "@img/sharp-libvips-linux-s390x": "1.0.4",
+ "@img/sharp-libvips-linux-x64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.0.4",
+ "@img/sharp-libvips-linuxmusl-x64": "1.0.4",
+ "@img/sharp-linux-arm": "0.33.5",
+ "@img/sharp-linux-arm64": "0.33.5",
+ "@img/sharp-linux-s390x": "0.33.5",
+ "@img/sharp-linux-x64": "0.33.5",
+ "@img/sharp-linuxmusl-arm64": "0.33.5",
+ "@img/sharp-linuxmusl-x64": "0.33.5",
+ "@img/sharp-wasm32": "0.33.5",
+ "@img/sharp-win32-ia32": "0.33.5",
+ "@img/sharp-win32-x64": "0.33.5"
+ }
+ },
+ "node_modules/sharp/node_modules/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -22080,6 +24146,126 @@
"uuid": "dist/bin/uuid"
}
},
+ "node_modules/socket.io": {
+ "version": "4.8.1",
+ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
+ "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "~1.3.4",
+ "base64id": "~2.0.0",
+ "cors": "~2.8.5",
+ "debug": "~4.3.2",
+ "engine.io": "~6.6.0",
+ "socket.io-adapter": "~2.5.2",
+ "socket.io-parser": "~4.2.4"
+ },
+ "engines": {
+ "node": ">=10.2.0"
+ }
+ },
+ "node_modules/socket.io-adapter": {
+ "version": "2.5.5",
+ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
+ "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "~4.3.4",
+ "ws": "~8.17.1"
+ }
+ },
+ "node_modules/socket.io-adapter/node_modules/debug": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/socket.io-adapter/node_modules/ws": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+ "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/socket.io-parser": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
+ "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@socket.io/component-emitter": "~3.1.0",
+ "debug": "~4.3.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/socket.io-parser/node_modules/debug": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/socket.io/node_modules/debug": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
"node_modules/socks": {
"version": "2.8.4",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz",
@@ -22326,6 +24512,15 @@
"node": ">=4.0.0"
}
},
+ "node_modules/streamsearch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
+ "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -22521,6 +24716,30 @@
"integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==",
"license": "MIT"
},
+ "node_modules/styled-jsx": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
+ "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "client-only": "0.0.1"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ },
+ "babel-plugin-macros": {
+ "optional": true
+ }
+ }
+ },
"node_modules/sucrase": {
"version": "3.34.0",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz",
@@ -24923,6 +27142,16 @@
"node": ">=18"
}
},
+ "node_modules/wcwidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+ "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "defaults": "^1.0.3"
+ }
+ },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
diff --git a/backend/package.json b/backend/package.json
index 58bc6a32d6..c19d304418 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -72,7 +72,8 @@
"seed:new": "tsx ./scripts/create-seed-file.ts",
"seed": "knex --knexfile ./dist/db/knexfile.ts --client pg seed:run",
"seed-dev": "knex --knexfile ./src/db/knexfile.ts --client pg seed:run",
- "db:reset": "npm run migration:rollback -- --all && npm run migration:latest"
+ "db:reset": "npm run migration:rollback -- --all && npm run migration:latest",
+ "email:dev": "email dev --dir src/services/smtp/emails"
},
"keywords": [],
"author": "",
@@ -96,6 +97,7 @@
"@types/picomatch": "^2.3.3",
"@types/pkcs11js": "^1.0.4",
"@types/prompt-sync": "^4.2.3",
+ "@types/react": "^19.1.2",
"@types/resolve": "^1.20.6",
"@types/safe-regex": "^1.1.6",
"@types/sjcl": "^1.0.34",
@@ -115,6 +117,7 @@
"nodemon": "^3.0.2",
"pino-pretty": "^10.2.3",
"prompt-sync": "^4.2.0",
+ "react-email": "4.0.7",
"rimraf": "^5.0.5",
"ts-node": "^10.9.2",
"tsc-alias": "^1.8.8",
@@ -164,6 +167,7 @@
"@opentelemetry/semantic-conventions": "^1.27.0",
"@peculiar/asn1-schema": "^2.3.8",
"@peculiar/x509": "^1.12.1",
+ "@react-email/components": "0.0.36",
"@serdnam/pino-cloudwatch-transport": "^1.0.4",
"@sindresorhus/slugify": "1.1.0",
"@slack/oauth": "^3.0.2",
@@ -223,6 +227,8 @@
"posthog-node": "^3.6.2",
"probot": "^13.3.8",
"re2": "^1.21.4",
+ "react": "19.1.0",
+ "react-dom": "19.1.0",
"safe-regex": "^2.1.1",
"scim-patch": "^0.8.3",
"scim2-parse-filter": "^0.2.10",
diff --git a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-fns.ts b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-fns.ts
index 5c0d97ee88..a25482c8cc 100644
--- a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-fns.ts
+++ b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-fns.ts
@@ -219,7 +219,7 @@ export const parseRotationErrorMessage = (err: unknown): string => {
if (err instanceof AxiosError) {
errorMessage += err?.response?.data
? JSON.stringify(err?.response?.data)
- : err?.message ?? "An unknown error occurred.";
+ : (err?.message ?? "An unknown error occurred.");
} else {
errorMessage += (err as Error)?.message || "An unknown error occurred.";
}
diff --git a/backend/src/ee/services/ssh/ssh-certificate-authority-service.ts b/backend/src/ee/services/ssh/ssh-certificate-authority-service.ts
index 312b7966b7..d58644d905 100644
--- a/backend/src/ee/services/ssh/ssh-certificate-authority-service.ts
+++ b/backend/src/ee/services/ssh/ssh-certificate-authority-service.ts
@@ -282,7 +282,7 @@ export const sshCertificateAuthorityServiceFactory = ({
// set [keyId] depending on if [allowCustomKeyIds] is true or false
const keyId = sshCertificateTemplate.allowCustomKeyIds
- ? requestedKeyId ?? `${actor}-${actorId}`
+ ? (requestedKeyId ?? `${actor}-${actorId}`)
: `${actor}-${actorId}`;
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: sshCertificateTemplate.sshCaId });
@@ -404,7 +404,7 @@ export const sshCertificateAuthorityServiceFactory = ({
// set [keyId] depending on if [allowCustomKeyIds] is true or false
const keyId = sshCertificateTemplate.allowCustomKeyIds
- ? requestedKeyId ?? `${actor}-${actorId}`
+ ? (requestedKeyId ?? `${actor}-${actorId}`)
: `${actor}-${actorId}`;
const sshCaSecret = await sshCertificateAuthoritySecretDAL.findOne({ sshCaId: sshCertificateTemplate.sshCaId });
diff --git a/backend/src/services/auth/auth-login-service.ts b/backend/src/services/auth/auth-login-service.ts
index d1b0a550de..5e2b450bb5 100644
--- a/backend/src/services/auth/auth-login-service.ts
+++ b/backend/src/services/auth/auth-login-service.ts
@@ -397,8 +397,8 @@ export const authLoginServiceFactory = ({
}
const shouldCheckMfa = selectedOrg.enforceMfa || user.isMfaEnabled;
- const orgMfaMethod = selectedOrg.enforceMfa ? selectedOrg.selectedMfaMethod ?? MfaMethod.EMAIL : undefined;
- const userMfaMethod = user.isMfaEnabled ? user.selectedMfaMethod ?? MfaMethod.EMAIL : undefined;
+ const orgMfaMethod = selectedOrg.enforceMfa ? (selectedOrg.selectedMfaMethod ?? MfaMethod.EMAIL) : undefined;
+ const userMfaMethod = user.isMfaEnabled ? (user.selectedMfaMethod ?? MfaMethod.EMAIL) : undefined;
const mfaMethod = orgMfaMethod ?? userMfaMethod;
if (shouldCheckMfa && (!decodedToken.isMfaVerified || decodedToken.mfaMethod !== mfaMethod)) {
@@ -569,9 +569,9 @@ export const authLoginServiceFactory = ({
}: TVerifyMfaTokenDTO) => {
const appCfg = getConfig();
const user = await userDAL.findById(userId);
- enforceUserLockStatus(Boolean(user.isLocked), user.temporaryLockDateEnd);
try {
+ enforceUserLockStatus(Boolean(user.isLocked), user.temporaryLockDateEnd);
if (mfaMethod === MfaMethod.EMAIL) {
await tokenService.validateTokenForUser({
type: TokenType.TOKEN_EMAIL_MFA,
diff --git a/backend/src/services/org/org-service.ts b/backend/src/services/org/org-service.ts
index 060a016342..d794391c16 100644
--- a/backend/src/services/org/org-service.ts
+++ b/backend/src/services/org/org-service.ts
@@ -698,6 +698,8 @@ export const orgServiceFactory = ({
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Member);
+ const invitingUser = await userDAL.findOne({ id: actorId });
+
const org = await orgDAL.findOrgById(orgId);
const [inviteeOrgMembership] = await orgDAL.findMembership({
@@ -731,8 +733,8 @@ export const orgServiceFactory = ({
subjectLine: "Infisical organization invitation",
recipients: [inviteeOrgMembership.email as string],
substitutions: {
- inviterFirstName: inviteeOrgMembership.firstName,
- inviterUsername: inviteeOrgMembership.email,
+ inviterFirstName: invitingUser.firstName,
+ inviterUsername: invitingUser.email,
organizationName: org?.name,
email: inviteeOrgMembership.email,
organizationId: org?.id.toString(),
@@ -761,6 +763,8 @@ export const orgServiceFactory = ({
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
+ const invitingUser = await userDAL.findOne({ id: actorId });
+
const org = await orgDAL.findOrgById(orgId);
const isEmailInvalid = await isDisposableEmail(inviteeEmails);
@@ -1179,8 +1183,8 @@ export const orgServiceFactory = ({
subjectLine: "Infisical organization invitation",
recipients: [el.email],
substitutions: {
- inviterFirstName: el.firstName,
- inviterUsername: el.email,
+ inviterFirstName: invitingUser.firstName,
+ inviterUsername: invitingUser.email,
organizationName: org?.name,
email: el.email,
organizationId: org?.id.toString(),
diff --git a/backend/src/services/secret-sync/secret-sync-fns.ts b/backend/src/services/secret-sync/secret-sync-fns.ts
index 143fa46227..1d3e8888c3 100644
--- a/backend/src/services/secret-sync/secret-sync-fns.ts
+++ b/backend/src/services/secret-sync/secret-sync-fns.ts
@@ -282,7 +282,7 @@ export const parseSyncErrorMessage = (err: unknown): string => {
} else if (err instanceof AxiosError) {
errorMessage = err?.response?.data
? JSON.stringify(err?.response?.data)
- : err?.message ?? "An unknown error occurred.";
+ : (err?.message ?? "An unknown error occurred.");
} else {
errorMessage = (err as Error)?.message || "An unknown error occurred.";
}
diff --git a/backend/src/services/secret-sync/secret-sync-queue.ts b/backend/src/services/secret-sync/secret-sync-queue.ts
index 34ac84947d..62b4ba3cc4 100644
--- a/backend/src/services/secret-sync/secret-sync-queue.ts
+++ b/backend/src/services/secret-sync/secret-sync-queue.ts
@@ -834,7 +834,7 @@ export const secretSyncQueueFactory = ({
secretPath: folder?.path,
environment: environment?.name,
projectName: project.name,
- syncUrl: `${appCfg.SITE_URL}/integrations/secret-syncs/${destination}/${secretSync.id}`
+ syncUrl: `${appCfg.SITE_URL}/secret-manager/${projectId}/integrations/secret-syncs/${destination}/${secretSync.id}`
}
});
};
diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts
index 6ab3485203..cd27731720 100644
--- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts
+++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts
@@ -7,6 +7,7 @@ import { ProjectType, SecretsV2Schema, SecretType, TableName, TSecretsV2, TSecre
import { TKeyStoreFactory } from "@app/keystore/keystore";
import { getConfig } from "@app/lib/config/env";
import { generateCacheKeyFromData } from "@app/lib/crypto/cache";
+import { applyJitter } from "@app/lib/dates";
import { BadRequestError, DatabaseError, NotFoundError } from "@app/lib/errors";
import {
buildFindFilter,
@@ -22,7 +23,6 @@ import type {
TFindSecretsByFolderIdsFilter,
TGetSecretsDTO
} from "@app/services/secret-v2-bridge/secret-v2-bridge-types";
-import { applyJitter } from "@app/lib/dates";
export const SecretServiceCacheKeys = {
get productKey() {
diff --git a/backend/src/services/secret/secret-queue.ts b/backend/src/services/secret/secret-queue.ts
index 6a0868741e..714df0d3f8 100644
--- a/backend/src/services/secret/secret-queue.ts
+++ b/backend/src/services/secret/secret-queue.ts
@@ -740,7 +740,7 @@ export const secretQueueFactory = ({
environment: jobPayload.environmentName,
count: jobPayload.count,
projectName: project.name,
- integrationUrl: `${appCfg.SITE_URL}/integrations/${project.id}`
+ integrationUrl: `${appCfg.SITE_URL}/secret-manager/${project.id}/integrations?selectedTab=native-integrations`
}
});
}
diff --git a/backend/src/services/smtp/emails/AccessApprovalRequestTemplate.tsx b/backend/src/services/smtp/emails/AccessApprovalRequestTemplate.tsx
new file mode 100644
index 0000000000..fef072546a
--- /dev/null
+++ b/backend/src/services/smtp/emails/AccessApprovalRequestTemplate.tsx
@@ -0,0 +1,95 @@
+import { Button, Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface AccessApprovalRequestTemplateProps extends Omit {
+ projectName: string;
+ requesterFullName: string;
+ requesterEmail: string;
+ isTemporary: boolean;
+ secretPath: string;
+ environment: string;
+ expiresIn: string;
+ permissions: string[];
+ note?: string;
+ approvalUrl: string;
+}
+
+export const AccessApprovalRequestTemplate = ({
+ projectName,
+ siteUrl,
+ requesterFullName,
+ requesterEmail,
+ isTemporary,
+ secretPath,
+ environment,
+ expiresIn,
+ permissions,
+ note,
+ approvalUrl
+}: AccessApprovalRequestTemplateProps) => {
+ return (
+
+
+ You have a new access approval request pending review for the project {projectName}
+
+
+
+ {requesterFullName} (
+
+ {requesterEmail}
+
+ ) has requested {isTemporary ? "temporary" : "permanent"} access to {secretPath} in the{" "}
+ {environment} environment.
+
+
+ {isTemporary && (
+
+ This access will expire {expiresIn} after approval.
+
+ )}
+
+ The following permissions are requested:
+
+ {permissions.map((permission) => (
+
+ - {permission}
+
+ ))}
+ {note && (
+
+ User Note: "{note}"
+
+ )}
+
+
+
+ );
+};
+
+export default AccessApprovalRequestTemplate;
+
+AccessApprovalRequestTemplate.PreviewProps = {
+ requesterFullName: "Abigail Williams",
+ requesterEmail: "abigail@infisical.com",
+ isTemporary: true,
+ secretPath: "/api/secrets",
+ environment: "Production",
+ siteUrl: "https://infisical.com",
+ projectName: "Example Project",
+ expiresIn: "1 day",
+ permissions: ["Read Secret", "Delete Project", "Create Dynamic Secret"],
+ note: "I need access to these permissions for the new initiative for HR."
+} as AccessApprovalRequestTemplateProps;
diff --git a/backend/src/services/smtp/emails/BaseEmailWrapper.tsx b/backend/src/services/smtp/emails/BaseEmailWrapper.tsx
new file mode 100644
index 0000000000..3d02fc793d
--- /dev/null
+++ b/backend/src/services/smtp/emails/BaseEmailWrapper.tsx
@@ -0,0 +1,45 @@
+import { Body, Container, Head, Hr, Html, Img, Link, Preview, Section, Tailwind, Text } from "@react-email/components";
+import React, { ReactNode } from "react";
+
+export interface BaseEmailWrapperProps {
+ title: string;
+ preview: string;
+ siteUrl: string;
+ children?: ReactNode;
+}
+
+export const BaseEmailWrapper = ({ title, preview, children, siteUrl }: BaseEmailWrapperProps) => {
+ return (
+
+
+
+
+ {preview}
+
+
+
+
+
+
+
+
+
+
+
+ Email sent via{" "}
+
+ Infisical
+
+
+
+
+
+
+
+ );
+};
diff --git a/backend/src/services/smtp/emails/EmailMfaTemplate.tsx b/backend/src/services/smtp/emails/EmailMfaTemplate.tsx
new file mode 100644
index 0000000000..8a35b011d1
--- /dev/null
+++ b/backend/src/services/smtp/emails/EmailMfaTemplate.tsx
@@ -0,0 +1,50 @@
+import { Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface EmailMfaTemplateProps extends Omit {
+ code: string;
+ isCloud: boolean;
+}
+
+export const EmailMfaTemplate = ({ code, siteUrl, isCloud }: EmailMfaTemplateProps) => {
+ return (
+
+
+ MFA required
+
+
+ Enter the MFA code below in the browser where you started sign-in.
+
+ {code}
+
+
+
+
+ Not you? {" "}
+ {isCloud ? (
+ <>
+ Contact us at{" "}
+
+ support@infisical.com
+ {" "}
+ immediately
+ >
+ ) : (
+ "Contact your administrator immediately"
+ )}
+ .
+
+
+
+ );
+};
+
+export default EmailMfaTemplate;
+
+EmailMfaTemplate.PreviewProps = {
+ code: "124356",
+ isCloud: true,
+ siteUrl: "https://infisical.com"
+} as EmailMfaTemplateProps;
diff --git a/backend/src/services/smtp/emails/EmailVerificationTemplate.tsx b/backend/src/services/smtp/emails/EmailVerificationTemplate.tsx
new file mode 100644
index 0000000000..6c0f410b1c
--- /dev/null
+++ b/backend/src/services/smtp/emails/EmailVerificationTemplate.tsx
@@ -0,0 +1,53 @@
+import { Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface EmailVerificationTemplateProps extends Omit {
+ code: string;
+ isCloud: boolean;
+}
+
+export const EmailVerificationTemplate = ({ code, siteUrl, isCloud }: EmailVerificationTemplateProps) => {
+ return (
+
+
+ Confirm your email address
+
+
+ Enter the confirmation code below in the browser window requiring confirmation.
+
+ {code}
+
+
+
+
+ Questions about Infisical? {" "}
+ {isCloud ? (
+ <>
+ Email us at{" "}
+
+ support@infisical.com
+
+ >
+ ) : (
+ "Contact your administrator"
+ )}
+ .
+
+
+
+ );
+};
+
+export default EmailVerificationTemplate;
+
+EmailVerificationTemplate.PreviewProps = {
+ code: "124356",
+ isCloud: true,
+ siteUrl: "https://infisical.com"
+} as EmailVerificationTemplateProps;
diff --git a/backend/src/services/smtp/emails/ExternalImportFailedTemplate.tsx b/backend/src/services/smtp/emails/ExternalImportFailedTemplate.tsx
new file mode 100644
index 0000000000..c283fdad93
--- /dev/null
+++ b/backend/src/services/smtp/emails/ExternalImportFailedTemplate.tsx
@@ -0,0 +1,43 @@
+import { Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface ExternalImportFailedTemplateProps extends Omit {
+ error: string;
+ provider: string;
+}
+
+export const ExternalImportFailedTemplate = ({ error, siteUrl, provider }: ExternalImportFailedTemplateProps) => {
+ return (
+
+
+ An import from {provider} to Infisical has failed
+
+
+
+ An import from {provider} to Infisical has failed due to unforeseen circumstances. Please
+ re-try your import.
+
+
+ If your issue persists, you can contact the Infisical team at{" "}
+
+ support@infisical.com
+
+ .
+
+
+ Error: "{error}"
+
+
+
+ );
+};
+
+export default ExternalImportFailedTemplate;
+
+ExternalImportFailedTemplate.PreviewProps = {
+ provider: "EnvKey",
+ error: "Something went wrong. Please try again.",
+ siteUrl: "https://infisical.com"
+} as ExternalImportFailedTemplateProps;
diff --git a/backend/src/services/smtp/emails/ExternalImportStartedTemplate.tsx b/backend/src/services/smtp/emails/ExternalImportStartedTemplate.tsx
new file mode 100644
index 0000000000..fc24536b45
--- /dev/null
+++ b/backend/src/services/smtp/emails/ExternalImportStartedTemplate.tsx
@@ -0,0 +1,30 @@
+import { Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface ExternalImportStartedTemplateProps extends Omit {
+ provider: string;
+}
+
+export const ExternalImportStartedTemplate = ({ siteUrl, provider }: ExternalImportStartedTemplateProps) => {
+ return (
+
+
+ An import from {provider} to Infisical has been started
+
+
+
+ An import from {provider} to Infisical is in progress. The import process may take up to 30
+ minutes. You will receive an email once the import has completed.
+
+
+
+ );
+};
+
+export default ExternalImportStartedTemplate;
+
+ExternalImportStartedTemplate.PreviewProps = {
+ provider: "EnvKey"
+} as ExternalImportStartedTemplateProps;
diff --git a/backend/src/services/smtp/emails/ExternalImportSucceededTemplate.tsx b/backend/src/services/smtp/emails/ExternalImportSucceededTemplate.tsx
new file mode 100644
index 0000000000..390d50fbca
--- /dev/null
+++ b/backend/src/services/smtp/emails/ExternalImportSucceededTemplate.tsx
@@ -0,0 +1,31 @@
+import { Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface ExternalImportSucceededTemplateProps extends Omit {
+ provider: string;
+}
+
+export const ExternalImportSucceededTemplate = ({ siteUrl, provider }: ExternalImportSucceededTemplateProps) => {
+ return (
+
+
+ An import from {provider} to Infisical has completed
+
+
+
+ An import from {provider} to Infisical was successful. Your data is now available in
+ Infisical.
+
+
+
+ );
+};
+
+export default ExternalImportSucceededTemplate;
+
+ExternalImportSucceededTemplate.PreviewProps = {
+ provider: "EnvKey",
+ siteUrl: "https://infisical.com"
+} as ExternalImportSucceededTemplateProps;
diff --git a/backend/src/services/smtp/emails/IntegrationSyncFailedTemplate.tsx b/backend/src/services/smtp/emails/IntegrationSyncFailedTemplate.tsx
new file mode 100644
index 0000000000..9eeeb4c3f3
--- /dev/null
+++ b/backend/src/services/smtp/emails/IntegrationSyncFailedTemplate.tsx
@@ -0,0 +1,65 @@
+import { Button, Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface IntegrationSyncFailedTemplateProps extends Omit {
+ count: number;
+ projectName: string;
+ secretPath: string;
+ environment: string;
+ syncMessage: string;
+ integrationUrl: string;
+}
+
+export const IntegrationSyncFailedTemplate = ({
+ count,
+ siteUrl,
+ projectName,
+ secretPath,
+ environment,
+ syncMessage,
+ integrationUrl
+}: IntegrationSyncFailedTemplateProps) => {
+ return (
+
+
+ {count} integration(s) failed to sync
+
+
+ Project
+ {projectName}
+ Environment
+ {environment}
+ Secret Path
+ {secretPath}
+ Failure Reason:
+ "{syncMessage}"
+
+
+
+ View Integrations
+
+
+
+ );
+};
+
+export default IntegrationSyncFailedTemplate;
+
+IntegrationSyncFailedTemplate.PreviewProps = {
+ projectName: "Example Project",
+ secretPath: "/api/secrets",
+ environment: "Production",
+ siteUrl: "https://infisical.com",
+ integrationUrl: "https://infisical.com",
+ count: 2,
+ syncMessage: "Secret key cannot contain a colon (:)"
+} as IntegrationSyncFailedTemplateProps;
diff --git a/backend/src/services/smtp/emails/NewDeviceLoginTemplate.tsx b/backend/src/services/smtp/emails/NewDeviceLoginTemplate.tsx
new file mode 100644
index 0000000000..3d301c0abb
--- /dev/null
+++ b/backend/src/services/smtp/emails/NewDeviceLoginTemplate.tsx
@@ -0,0 +1,68 @@
+import { Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface NewDeviceLoginTemplateProps extends Omit {
+ email: string;
+ timestamp: string;
+ ip: string;
+ userAgent: string;
+ isCloud: boolean;
+}
+
+export const NewDeviceLoginTemplate = ({
+ email,
+ timestamp,
+ ip,
+ userAgent,
+ siteUrl,
+ isCloud
+}: NewDeviceLoginTemplateProps) => {
+ return (
+
+
+ We're verifying a recent login for
+
+ {email}
+
+
+ Timestamp
+ {timestamp}
+ IP Address
+ {ip}
+ User Agent
+ {userAgent}
+
+
+
+ If you believe that this login is suspicious, please contact{" "}
+ {isCloud ? (
+
+ support@infisical.com
+
+ ) : (
+ "your administrator"
+ )}{" "}
+ or reset your password immediately.
+
+
+
+ );
+};
+
+export default NewDeviceLoginTemplate;
+
+NewDeviceLoginTemplate.PreviewProps = {
+ email: "john@infisical.com",
+ ip: "127.0.0.1",
+ userAgent:
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3.1 Safari/605.1.15",
+ timestamp: "Tue Apr 29 2025 23:03:27 GMT+0000 (Coordinated Universal Time)",
+ isCloud: true,
+ siteUrl: "https://infisical.com"
+} as NewDeviceLoginTemplateProps;
diff --git a/backend/src/services/smtp/emails/OrgAdminBreakglassAccessTemplate.tsx b/backend/src/services/smtp/emails/OrgAdminBreakglassAccessTemplate.tsx
new file mode 100644
index 0000000000..f3d0d01d77
--- /dev/null
+++ b/backend/src/services/smtp/emails/OrgAdminBreakglassAccessTemplate.tsx
@@ -0,0 +1,57 @@
+import { Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface OrgAdminBreakglassAccessTemplateProps extends Omit {
+ email: string;
+ timestamp: string;
+ ip: string;
+ userAgent: string;
+}
+
+export const OrgAdminBreakglassAccessTemplate = ({
+ email,
+ siteUrl,
+ timestamp,
+ ip,
+ userAgent
+}: OrgAdminBreakglassAccessTemplateProps) => {
+ return (
+
+
+ The organization admin {email} has bypassed enforced SSO login.
+
+
+ Timestamp
+ {timestamp}
+ IP Address
+ {ip}
+ User Agent
+ {userAgent}
+
+ If you'd like to disable Admin SSO Bypass, please visit{" "}
+
+ Organization Security Settings
+
+ .
+
+
+
+ );
+};
+
+export default OrgAdminBreakglassAccessTemplate;
+
+OrgAdminBreakglassAccessTemplate.PreviewProps = {
+ ip: "127.0.0.1",
+ userAgent:
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3.1 Safari/605.1.15",
+ timestamp: "Tue Apr 29 2025 23:03:27 GMT+0000 (Coordinated Universal Time)",
+ siteUrl: "https://infisical.com",
+ email: "august@infiscal.com"
+} as OrgAdminBreakglassAccessTemplateProps;
diff --git a/backend/src/services/smtp/emails/OrgAdminProjectGrantAccessTemplate.tsx b/backend/src/services/smtp/emails/OrgAdminProjectGrantAccessTemplate.tsx
new file mode 100644
index 0000000000..4a9eeae3e6
--- /dev/null
+++ b/backend/src/services/smtp/emails/OrgAdminProjectGrantAccessTemplate.tsx
@@ -0,0 +1,40 @@
+import { Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface OrgAdminProjectGrantAccessTemplateProps extends Omit {
+ email: string;
+ projectName: string;
+}
+
+export const OrgAdminProjectGrantAccessTemplate = ({
+ email,
+ siteUrl,
+ projectName
+}: OrgAdminProjectGrantAccessTemplateProps) => {
+ return (
+
+
+ An organization admin has joined the project {projectName}
+
+
+
+ The organization admin {email} has self-issued direct access to the project{" "}
+ {projectName} .
+
+
+
+ );
+};
+
+export default OrgAdminProjectGrantAccessTemplate;
+
+OrgAdminProjectGrantAccessTemplate.PreviewProps = {
+ email: "kevin@infisical.com",
+ projectName: "Example Project"
+} as OrgAdminProjectGrantAccessTemplateProps;
diff --git a/backend/src/services/smtp/emails/OrganizationInvitationTemplate.tsx b/backend/src/services/smtp/emails/OrganizationInvitationTemplate.tsx
new file mode 100644
index 0000000000..6e27d1e9bb
--- /dev/null
+++ b/backend/src/services/smtp/emails/OrganizationInvitationTemplate.tsx
@@ -0,0 +1,75 @@
+import { Button, Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface OrganizationInvitationTemplateProps extends Omit {
+ metadata?: string;
+ inviterFirstName: string;
+ inviterUsername: string;
+ organizationName: string;
+ email: string;
+ organizationId: string;
+ token: string;
+ callback_url: string;
+}
+
+export const OrganizationInvitationTemplate = ({
+ organizationName,
+ inviterFirstName,
+ inviterUsername,
+ token,
+ callback_url,
+ metadata,
+ email,
+ organizationId,
+ siteUrl
+}: OrganizationInvitationTemplateProps) => {
+ return (
+
+
+ You've been invited to join
+
+ {organizationName} on Infisical
+
+
+
+ {inviterFirstName} (
+
+ {inviterUsername}
+
+ ) has invited you to collaborate on {organizationName} .
+
+
+
+
+
+ About Infisical: Infisical is an all-in-one platform to securely manage application secrets,
+ certificates, SSH keys, and configurations across your team and infrastructure.
+
+
+
+ );
+};
+
+export default OrganizationInvitationTemplate;
+
+OrganizationInvitationTemplate.PreviewProps = {
+ organizationName: "Example Organization",
+ inviterFirstName: "Jane",
+ inviterUsername: "jane@infisical.com",
+ email: "john@infisical.com",
+ siteUrl: "https://infisical.com",
+ callback_url: "https://app.infisical.com"
+} as OrganizationInvitationTemplateProps;
diff --git a/backend/src/services/smtp/emails/PasswordResetTemplate.tsx b/backend/src/services/smtp/emails/PasswordResetTemplate.tsx
new file mode 100644
index 0000000000..b4ac0d5a73
--- /dev/null
+++ b/backend/src/services/smtp/emails/PasswordResetTemplate.tsx
@@ -0,0 +1,58 @@
+import { Button, Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface PasswordResetTemplateProps extends Omit {
+ email: string;
+ callback_url: string;
+ token: string;
+ isCloud: boolean;
+}
+
+export const PasswordResetTemplate = ({ email, isCloud, siteUrl, callback_url, token }: PasswordResetTemplateProps) => {
+ return (
+
+
+ Account Recovery
+
+
+ A password reset was requested for your Infisical account.
+
+ If you did not initiate this request, please contact{" "}
+ {isCloud ? (
+ <>
+ us immediately at{" "}
+
+ support@infisical.com
+
+ >
+ ) : (
+ "your administrator immediately"
+ )}
+ .
+
+
+
+
+ );
+};
+
+export default PasswordResetTemplate;
+
+PasswordResetTemplate.PreviewProps = {
+ email: "kevin@infisical.com",
+ callback_url: "https://app.infisical.com",
+ isCloud: true
+} as PasswordResetTemplateProps;
diff --git a/backend/src/services/smtp/emails/PasswordSetupTemplate.tsx b/backend/src/services/smtp/emails/PasswordSetupTemplate.tsx
new file mode 100644
index 0000000000..a03724a39d
--- /dev/null
+++ b/backend/src/services/smtp/emails/PasswordSetupTemplate.tsx
@@ -0,0 +1,57 @@
+import { Button, Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface PasswordSetupTemplateProps extends Omit {
+ email: string;
+ callback_url: string;
+ token: string;
+ isCloud: boolean;
+}
+
+export const PasswordSetupTemplate = ({ email, isCloud, siteUrl, callback_url, token }: PasswordSetupTemplateProps) => {
+ return (
+
+
+ Password Setup
+
+
+ Someone requested to set up a password for your Infisical account.
+
+ Make sure you are already logged in to Infisical in the current browser before clicking the link below.
+
+
+ If you did not initiate this request, please contact{" "}
+ {isCloud ? (
+ <>
+ us immediately at{" "}
+
+ support@infisical.com
+
+ >
+ ) : (
+ "your administrator immediately"
+ )}
+ .
+
+
+
+
+ );
+};
+
+export default PasswordSetupTemplate;
+
+PasswordSetupTemplate.PreviewProps = {
+ email: "casey@infisical.com",
+ callback_url: "https://app.infisical.com",
+ isCloud: true
+} as PasswordSetupTemplateProps;
diff --git a/backend/src/services/smtp/emails/PkiExpirationAlertTemplate.tsx b/backend/src/services/smtp/emails/PkiExpirationAlertTemplate.tsx
new file mode 100644
index 0000000000..db3b4816e5
--- /dev/null
+++ b/backend/src/services/smtp/emails/PkiExpirationAlertTemplate.tsx
@@ -0,0 +1,68 @@
+import { Heading, Hr, Section, Text } from "@react-email/components";
+import React, { Fragment } from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface PkiExpirationAlertTemplateProps extends Omit {
+ alertName: string;
+ alertBeforeDays: number;
+ items: { type: string; friendlyName: string; serialNumber: string; expiryDate: string }[];
+}
+
+export const PkiExpirationAlertTemplate = ({
+ alertName,
+ siteUrl,
+ alertBeforeDays,
+ items
+}: PkiExpirationAlertTemplateProps) => {
+ return (
+
+
+ CA/Certificate Expiration Notice
+
+
+ Hello,
+
+ This is an automated alert for {alertName} triggered for CAs/Certificates expiring in{" "}
+ {alertBeforeDays} days.
+
+
+ Expiring Items:
+
+ {items.map((item) => (
+
+
+ {item.type}:
+ {item.friendlyName}
+ Serial Number:
+ {item.serialNumber}
+ Expires On:
+ {item.expiryDate}
+
+ ))}
+
+
+ Please take the necessary actions to renew these items before they expire.
+
+
+ For more details, please log in to your Infisical account and check your PKI management section.
+
+
+
+ );
+};
+
+export default PkiExpirationAlertTemplate;
+
+PkiExpirationAlertTemplate.PreviewProps = {
+ alertBeforeDays: 5,
+ items: [
+ { type: "CA", friendlyName: "Example CA", serialNumber: "1234567890", expiryDate: "2022-01-01" },
+ { type: "Certificate", friendlyName: "Example Certificate", serialNumber: "1234567890", expiryDate: "2022-01-01" }
+ ],
+ alertName: "My PKI Alert"
+} as PkiExpirationAlertTemplateProps;
diff --git a/backend/src/services/smtp/emails/ProjectAccessRequestTemplate.tsx b/backend/src/services/smtp/emails/ProjectAccessRequestTemplate.tsx
new file mode 100644
index 0000000000..28933b538a
--- /dev/null
+++ b/backend/src/services/smtp/emails/ProjectAccessRequestTemplate.tsx
@@ -0,0 +1,68 @@
+import { Button, Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface ProjectAccessRequestTemplateProps extends Omit {
+ projectName: string;
+ requesterName: string;
+ requesterEmail: string;
+ orgName: string;
+ environment: string;
+ note: string;
+ callback_url: string;
+}
+
+export const ProjectAccessRequestTemplate = ({
+ projectName,
+ siteUrl,
+ requesterName,
+ requesterEmail,
+ orgName,
+ note,
+ callback_url
+}: ProjectAccessRequestTemplateProps) => {
+ return (
+
+
+ A user has requested access to the project {projectName}
+
+
+
+ {requesterName} (
+
+ {requesterEmail}
+
+ ) has requested access to the project {projectName} in the organization{" "}
+ {orgName} .
+
+
+ User note: "{note}"
+
+
+
+
+ );
+};
+
+export default ProjectAccessRequestTemplate;
+
+ProjectAccessRequestTemplate.PreviewProps = {
+ requesterName: "Abigail Williams",
+ requesterEmail: "abigail@infisical.com",
+ orgName: "Example Org",
+ siteUrl: "https://infisical.com",
+ projectName: "Example Project",
+ note: "I need access to the project for the new initiative for HR."
+} as ProjectAccessRequestTemplateProps;
diff --git a/backend/src/services/smtp/emails/ProjectInvitationTemplate.tsx b/backend/src/services/smtp/emails/ProjectInvitationTemplate.tsx
new file mode 100644
index 0000000000..452b098a58
--- /dev/null
+++ b/backend/src/services/smtp/emails/ProjectInvitationTemplate.tsx
@@ -0,0 +1,50 @@
+import { Button, Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface ProjectInvitationTemplateProps extends Omit {
+ callback_url: string;
+ workspaceName: string;
+}
+
+export const ProjectInvitationTemplate = ({ callback_url, workspaceName, siteUrl }: ProjectInvitationTemplateProps) => {
+ return (
+
+
+ You've been invited to join a new project on Infisical
+
+
+
+ You've been invited to join the project {workspaceName} .
+
+
+
+
+
+ About Infisical: Infisical is an all-in-one platform to securely manage application secrets,
+ certificates, SSH keys, and configurations across your team and infrastructure.
+
+
+
+ );
+};
+
+export default ProjectInvitationTemplate;
+
+ProjectInvitationTemplate.PreviewProps = {
+ workspaceName: "Example Project",
+ siteUrl: "https://infisical.com",
+ callback_url: "https://app.infisical.com"
+} as ProjectInvitationTemplateProps;
diff --git a/backend/src/services/smtp/emails/ScimUserProvisionedTemplate.tsx b/backend/src/services/smtp/emails/ScimUserProvisionedTemplate.tsx
new file mode 100644
index 0000000000..7228948354
--- /dev/null
+++ b/backend/src/services/smtp/emails/ScimUserProvisionedTemplate.tsx
@@ -0,0 +1,56 @@
+import { Button, Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface ScimUserProvisionedTemplateProps extends Omit {
+ organizationName: string;
+ callback_url: string;
+}
+
+export const ScimUserProvisionedTemplate = ({
+ organizationName,
+ callback_url,
+ siteUrl
+}: ScimUserProvisionedTemplateProps) => {
+ return (
+
+
+ You've been invited to join
+
+ {organizationName} on Infisical
+
+
+
+ You've been invited you to collaborate on {organizationName} .
+
+
+
+
+
+ About Infisical: Infisical is an all-in-one platform to securely manage application secrets,
+ certificates, SSH keys, and configurations across your team and infrastructure.
+
+
+
+ );
+};
+
+export default ScimUserProvisionedTemplate;
+
+ScimUserProvisionedTemplate.PreviewProps = {
+ organizationName: "Example Organization",
+ callback_url: "https://app.infisical.com",
+ siteUrl: "https://app.infisical.com"
+} as ScimUserProvisionedTemplateProps;
diff --git a/backend/src/services/smtp/emails/SecretApprovalRequestBypassedTemplate.tsx b/backend/src/services/smtp/emails/SecretApprovalRequestBypassedTemplate.tsx
new file mode 100644
index 0000000000..bad823bd34
--- /dev/null
+++ b/backend/src/services/smtp/emails/SecretApprovalRequestBypassedTemplate.tsx
@@ -0,0 +1,72 @@
+import { Button, Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface SecretApprovalRequestBypassedTemplateProps
+ extends Omit {
+ projectName: string;
+ requesterFullName: string;
+ requesterEmail: string;
+ secretPath: string;
+ environment: string;
+ bypassReason: string;
+ approvalUrl: string;
+}
+
+export const SecretApprovalRequestBypassedTemplate = ({
+ projectName,
+ siteUrl,
+ requesterFullName,
+ requesterEmail,
+ secretPath,
+ environment,
+ bypassReason,
+ approvalUrl
+}: SecretApprovalRequestBypassedTemplateProps) => {
+ return (
+
+
+ A secret approval request has been bypassed in the project {projectName}
+
+
+
+ {requesterFullName} (
+
+ {requesterEmail}
+
+ ) has merged a secret to {secretPath} in the {environment} environment
+ without obtaining the required approval.
+
+
+ The following reason was provided for bypassing the policy: "
+ {bypassReason}"
+
+
+
+
+ );
+};
+
+export default SecretApprovalRequestBypassedTemplate;
+
+SecretApprovalRequestBypassedTemplate.PreviewProps = {
+ requesterFullName: "Abigail Williams",
+ requesterEmail: "abigail@infisical.com",
+ secretPath: "/api/secrets",
+ environment: "Production",
+ siteUrl: "https://infisical.com",
+ projectName: "Example Project",
+ bypassReason: "I needed urgent access for a production misconfiguration."
+} as SecretApprovalRequestBypassedTemplateProps;
diff --git a/backend/src/services/smtp/emails/SecretApprovalRequestNeedsReviewTemplate.tsx b/backend/src/services/smtp/emails/SecretApprovalRequestNeedsReviewTemplate.tsx
new file mode 100644
index 0000000000..faff34b582
--- /dev/null
+++ b/backend/src/services/smtp/emails/SecretApprovalRequestNeedsReviewTemplate.tsx
@@ -0,0 +1,57 @@
+import { Button, Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface SecretApprovalRequestNeedsReviewTemplateProps
+ extends Omit {
+ projectName: string;
+ firstName: string;
+ organizationName: string;
+ approvalUrl: string;
+}
+
+export const SecretApprovalRequestNeedsReviewTemplate = ({
+ projectName,
+ siteUrl,
+ firstName,
+ organizationName,
+ approvalUrl
+}: SecretApprovalRequestNeedsReviewTemplateProps) => {
+ return (
+
+
+ A secret approval request for the project {projectName} requires review.
+
+
+ Hello {firstName},
+
+ You have a new secret change request pending your review for the project {projectName} in the
+ organization {organizationName} .
+
+
+
+
+ );
+};
+
+export default SecretApprovalRequestNeedsReviewTemplate;
+
+SecretApprovalRequestNeedsReviewTemplate.PreviewProps = {
+ firstName: "Gordon",
+ organizationName: "Example Org",
+ siteUrl: "https://infisical.com",
+ approvalUrl: "https://infisical.com",
+ projectName: "Example Project"
+} as SecretApprovalRequestNeedsReviewTemplateProps;
diff --git a/backend/src/services/smtp/emails/SecretLeakIncidentTemplate.tsx b/backend/src/services/smtp/emails/SecretLeakIncidentTemplate.tsx
new file mode 100644
index 0000000000..3ef10eb4e2
--- /dev/null
+++ b/backend/src/services/smtp/emails/SecretLeakIncidentTemplate.tsx
@@ -0,0 +1,82 @@
+import { Button, Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface SecretLeakIncidentTemplateProps extends Omit {
+ numberOfSecrets: number;
+ pusher_email: string;
+ pusher_name: string;
+}
+
+export const SecretLeakIncidentTemplate = ({
+ numberOfSecrets,
+ siteUrl,
+ pusher_name,
+ pusher_email
+}: SecretLeakIncidentTemplateProps) => {
+ return (
+
+
+ Infisical has uncovered {numberOfSecrets} secret(s) from a recent commit
+
+
+
+ You are receiving this notification because one or more leaked secrets have been detected in a recent commit
+ {(pusher_email || pusher_name) && (
+ <>
+ {" "}
+ pushed by {pusher_name ?? "Unknown Pusher"} {" "}
+ {pusher_email && (
+ <>
+ (
+
+ {pusher_email}
+
+ )
+ >
+ )}
+ >
+ )}
+ .
+
+
+ If these are test secrets, please add `infisical-scan:ignore` at the end of the line containing the secret as
+ a comment in the given programming language. This will prevent future notifications from being sent out for
+ these secrets.
+
+
+ If these are production secrets, please rotate them immediately.
+
+
+ Once you have taken action, be sure to update the status of the risk in the{" "}
+
+ Infisical Dashboard
+
+ .
+
+
+
+
+ View Leaked Secrets
+
+
+
+ );
+};
+
+export default SecretLeakIncidentTemplate;
+
+SecretLeakIncidentTemplate.PreviewProps = {
+ pusher_name: "Jim",
+ pusher_email: "jim@infisical.com",
+ numberOfSecrets: 3,
+ siteUrl: "https://infisical.com"
+} as SecretLeakIncidentTemplateProps;
diff --git a/backend/src/services/smtp/emails/SecretReminderTemplate.tsx b/backend/src/services/smtp/emails/SecretReminderTemplate.tsx
new file mode 100644
index 0000000000..753246db56
--- /dev/null
+++ b/backend/src/services/smtp/emails/SecretReminderTemplate.tsx
@@ -0,0 +1,45 @@
+import { Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface SecretReminderTemplateProps extends Omit {
+ projectName: string;
+ organizationName: string;
+ reminderNote?: string;
+}
+
+export const SecretReminderTemplate = ({
+ siteUrl,
+ reminderNote,
+ projectName,
+ organizationName
+}: SecretReminderTemplateProps) => {
+ return (
+
+
+ Secret Reminder
+
+
+
+ You have a new secret reminder from the project {projectName} in the{" "}
+ {organizationName} organization.
+
+ {reminderNote && (
+
+ Reminder Note: "{reminderNote}"
+
+ )}
+
+
+ );
+};
+
+export default SecretReminderTemplate;
+
+SecretReminderTemplate.PreviewProps = {
+ reminderNote: "Remember to rotate secret.",
+ projectName: "Example Project",
+ organizationName: "Example Organization",
+ siteUrl: "https://infisical.com"
+} as SecretReminderTemplateProps;
diff --git a/backend/src/services/smtp/emails/SecretRequestCompletedTemplate.tsx b/backend/src/services/smtp/emails/SecretRequestCompletedTemplate.tsx
new file mode 100644
index 0000000000..75e2d1ba59
--- /dev/null
+++ b/backend/src/services/smtp/emails/SecretRequestCompletedTemplate.tsx
@@ -0,0 +1,53 @@
+import { Button, Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface ShareSecretTemplateProps extends Omit {
+ name?: string;
+ respondentUsername: string;
+ secretRequestUrl: string;
+}
+
+export const SecretRequestCompletedTemplate = ({
+ name,
+ siteUrl,
+ respondentUsername,
+ secretRequestUrl
+}: ShareSecretTemplateProps) => {
+ return (
+
+
+ A secret has been shared with you
+
+
+
+ {respondentUsername ? {respondentUsername} : "Someone"} shared a secret{" "}
+ {name && (
+ <>
+ {name} {" "}
+ >
+ )}{" "}
+ with you.
+
+
+
+
+ );
+};
+
+export default SecretRequestCompletedTemplate;
+
+SecretRequestCompletedTemplate.PreviewProps = {
+ respondentUsername: "Gracie",
+ siteUrl: "https://infisical.com",
+ secretRequestUrl: "https://infisical.com",
+ name: "API_TOKEN"
+} as ShareSecretTemplateProps;
diff --git a/backend/src/services/smtp/emails/SecretRotationFailedTemplate.tsx b/backend/src/services/smtp/emails/SecretRotationFailedTemplate.tsx
new file mode 100644
index 0000000000..6b149dcf38
--- /dev/null
+++ b/backend/src/services/smtp/emails/SecretRotationFailedTemplate.tsx
@@ -0,0 +1,68 @@
+import { Button, Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface SecretRotationFailedTemplateProps extends Omit {
+ rotationType: string;
+ rotationName: string;
+ rotationUrl: string;
+ projectName: string;
+ environment: string;
+ secretPath: string;
+ content: string;
+}
+
+export const SecretRotationFailedTemplate = ({
+ rotationType,
+ rotationName,
+ rotationUrl,
+ projectName,
+ siteUrl,
+ environment,
+ secretPath,
+ content
+}: SecretRotationFailedTemplateProps) => {
+ return (
+
+
+ Your {rotationType} Rotation {rotationName} failed to rotate
+
+
+ Name
+ {rotationName}
+ Type
+ {rotationType}
+ Project
+ {projectName}
+ Environment
+ {environment}
+ Secret Path
+ {secretPath}
+ Reason:
+ {content}
+
+
+
+ );
+};
+
+export default SecretRotationFailedTemplate;
+
+SecretRotationFailedTemplate.PreviewProps = {
+ rotationType: "Auth0 Client Secret",
+ rotationUrl: "https://infisical.com",
+ content: "See Rotation status for details",
+ projectName: "Example Project",
+ secretPath: "/api/secrets",
+ environment: "Production",
+ rotationName: "my-auth0-rotation",
+ siteUrl: "https://infisical.com"
+} as SecretRotationFailedTemplateProps;
diff --git a/backend/src/services/smtp/emails/SecretSyncFailedTemplate.tsx b/backend/src/services/smtp/emails/SecretSyncFailedTemplate.tsx
new file mode 100644
index 0000000000..9cad012506
--- /dev/null
+++ b/backend/src/services/smtp/emails/SecretSyncFailedTemplate.tsx
@@ -0,0 +1,80 @@
+import { Button, Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface SecretSyncFailedTemplateProps extends Omit {
+ syncDestination: string;
+ syncName: string;
+ syncUrl: string;
+ projectName: string;
+ environment: string;
+ secretPath: string;
+ failureMessage: string;
+}
+
+export const SecretSyncFailedTemplate = ({
+ syncDestination,
+ syncName,
+ syncUrl,
+ projectName,
+ siteUrl,
+ environment,
+ secretPath,
+ failureMessage
+}: SecretSyncFailedTemplateProps) => {
+ return (
+
+
+ Your {syncDestination} Sync {syncName} failed to sync
+
+
+ Name
+ {syncName}
+ Destination
+ {syncDestination}
+ Project
+ {projectName}
+ {environment && (
+ <>
+ Environment
+ {environment}
+ >
+ )}
+ {secretPath && (
+ <>
+ Secret Path
+ {secretPath}
+ >
+ )}
+ {failureMessage && (
+ <>
+ Reason:
+ {failureMessage}
+ >
+ )}
+
+
+
+ );
+};
+
+export default SecretSyncFailedTemplate;
+
+SecretSyncFailedTemplate.PreviewProps = {
+ syncDestination: "AWS Parameter Store",
+ syncUrl: "https://infisical.com",
+ failureMessage: "Key name cannot contain a colon (:) or a forward slash (/).",
+ projectName: "Example Project",
+ secretPath: "/api/secrets",
+ environment: "Production",
+ syncName: "my-aws-sync",
+ siteUrl: "https://infisical.com"
+} as SecretSyncFailedTemplateProps;
diff --git a/backend/src/services/smtp/emails/ServiceTokenExpiryNoticeTemplate.tsx b/backend/src/services/smtp/emails/ServiceTokenExpiryNoticeTemplate.tsx
new file mode 100644
index 0000000000..a45b83d7de
--- /dev/null
+++ b/backend/src/services/smtp/emails/ServiceTokenExpiryNoticeTemplate.tsx
@@ -0,0 +1,53 @@
+import { Button, Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface ServiceTokenExpiryNoticeTemplateProps extends Omit {
+ tokenName: string;
+ projectName: string;
+ url: string;
+}
+
+export const ServiceTokenExpiryNoticeTemplate = ({
+ tokenName,
+ siteUrl,
+ projectName,
+ url
+}: ServiceTokenExpiryNoticeTemplateProps) => {
+ return (
+
+
+ Service token expiry notice
+
+
+
+ Your service token {tokenName} for the project {projectName} will expire
+ within 24 hours.
+
+ If this token is still needed for your workflow, please create a new one before it expires.
+
+
+
+ );
+};
+
+export default ServiceTokenExpiryNoticeTemplate;
+
+ServiceTokenExpiryNoticeTemplate.PreviewProps = {
+ projectName: "Example Project",
+ siteUrl: "https://infisical.com",
+ url: "https://infisical.com",
+ tokenName: "Example Token"
+} as ServiceTokenExpiryNoticeTemplateProps;
diff --git a/backend/src/services/smtp/emails/SignupEmailVerificationTemplate.tsx b/backend/src/services/smtp/emails/SignupEmailVerificationTemplate.tsx
new file mode 100644
index 0000000000..66bb8e6338
--- /dev/null
+++ b/backend/src/services/smtp/emails/SignupEmailVerificationTemplate.tsx
@@ -0,0 +1,53 @@
+import { Heading, Link, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface SignupEmailVerificationTemplateProps extends Omit {
+ code: string;
+ isCloud: boolean;
+}
+
+export const SignupEmailVerificationTemplate = ({ code, siteUrl, isCloud }: SignupEmailVerificationTemplateProps) => {
+ return (
+
+
+ Confirm your email address
+
+
+ Enter the confirmation code below in the browser where you started sign-up.
+
+ {code}
+
+
+
+
+ Questions about setting up Infisical? {" "}
+ {isCloud ? (
+ <>
+ Email us at{" "}
+
+ support@infisical.com
+
+ >
+ ) : (
+ "Contact your administrator"
+ )}
+ .
+
+
+
+ );
+};
+
+export default SignupEmailVerificationTemplate;
+
+SignupEmailVerificationTemplate.PreviewProps = {
+ code: "124356",
+ isCloud: true,
+ siteUrl: "https://infisical.com"
+} as SignupEmailVerificationTemplateProps;
diff --git a/backend/src/services/smtp/emails/UnlockAccountTemplate.tsx b/backend/src/services/smtp/emails/UnlockAccountTemplate.tsx
new file mode 100644
index 0000000000..daeabf4fdc
--- /dev/null
+++ b/backend/src/services/smtp/emails/UnlockAccountTemplate.tsx
@@ -0,0 +1,46 @@
+import { Button, Heading, Section, Text } from "@react-email/components";
+import React from "react";
+
+import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
+
+interface UnlockAccountTemplateProps extends Omit {
+ token: string;
+ callback_url: string;
+}
+
+export const UnlockAccountTemplate = ({ token, siteUrl, callback_url }: UnlockAccountTemplateProps) => {
+ return (
+
+
+ Unlock your Infisical account
+
+
+
+ Your account has been temporarily locked due to multiple failed login attempts.
+
+ If these attempts were not made by you, reset your password immediately.
+
+
+
+ );
+};
+
+export default UnlockAccountTemplate;
+
+UnlockAccountTemplate.PreviewProps = {
+ callback_url: "Example Project",
+ siteUrl: "https://infisical.com",
+ url: "https://infisical.com",
+ token: "Example Token"
+} as UnlockAccountTemplateProps;
diff --git a/backend/src/services/smtp/emails/index.ts b/backend/src/services/smtp/emails/index.ts
new file mode 100644
index 0000000000..324f7063e4
--- /dev/null
+++ b/backend/src/services/smtp/emails/index.ts
@@ -0,0 +1,28 @@
+export * from "./AccessApprovalRequestTemplate";
+export * from "./EmailMfaTemplate";
+export * from "./EmailVerificationTemplate";
+export * from "./ExternalImportFailedTemplate";
+export * from "./ExternalImportStartedTemplate";
+export * from "./ExternalImportSucceededTemplate";
+export * from "./IntegrationSyncFailedTemplate";
+export * from "./NewDeviceLoginTemplate";
+export * from "./OrgAdminBreakglassAccessTemplate";
+export * from "./OrgAdminProjectGrantAccessTemplate";
+export * from "./OrganizationInvitationTemplate";
+export * from "./OrganizationInvitationTemplate";
+export * from "./PasswordResetTemplate";
+export * from "./PasswordSetupTemplate";
+export * from "./PkiExpirationAlertTemplate";
+export * from "./ProjectAccessRequestTemplate";
+export * from "./ProjectInvitationTemplate";
+export * from "./ScimUserProvisionedTemplate";
+export * from "./SecretApprovalRequestBypassedTemplate";
+export * from "./SecretApprovalRequestNeedsReviewTemplate";
+export * from "./SecretLeakIncidentTemplate";
+export * from "./SecretReminderTemplate";
+export * from "./SecretRequestCompletedTemplate";
+export * from "./SecretRotationFailedTemplate";
+export * from "./SecretSyncFailedTemplate";
+export * from "./ServiceTokenExpiryNoticeTemplate";
+export * from "./SignupEmailVerificationTemplate";
+export * from "./UnlockAccountTemplate";
diff --git a/backend/src/services/smtp/smtp-service.ts b/backend/src/services/smtp/smtp-service.ts
deleted file mode 100644
index 550e1bb076..0000000000
--- a/backend/src/services/smtp/smtp-service.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-import fs from "node:fs/promises";
-import path from "node:path";
-
-import handlebars from "handlebars";
-import { createTransport } from "nodemailer";
-import SMTPTransport from "nodemailer/lib/smtp-transport";
-
-import { getConfig } from "@app/lib/config/env";
-import { logger } from "@app/lib/logger";
-
-export type TSmtpConfig = SMTPTransport.Options;
-export type TSmtpSendMail = {
- template: SmtpTemplates;
- subjectLine: string;
- recipients: string[];
- substitutions: object;
-};
-export type TSmtpService = ReturnType;
-
-export enum SmtpTemplates {
- SignupEmailVerification = "signupEmailVerification.handlebars",
- EmailVerification = "emailVerification.handlebars",
- SecretReminder = "secretReminder.handlebars",
- EmailMfa = "emailMfa.handlebars",
- UnlockAccount = "unlockAccount.handlebars",
- AccessApprovalRequest = "accessApprovalRequest.handlebars",
- AccessSecretRequestBypassed = "accessSecretRequestBypassed.handlebars",
- SecretApprovalRequestNeedsReview = "secretApprovalRequestNeedsReview.handlebars",
- HistoricalSecretList = "historicalSecretLeakIncident.handlebars",
- NewDeviceJoin = "newDevice.handlebars",
- OrgInvite = "organizationInvitation.handlebars",
- ResetPassword = "passwordReset.handlebars",
- SetupPassword = "passwordSetup.handlebars",
- SecretLeakIncident = "secretLeakIncident.handlebars",
- WorkspaceInvite = "workspaceInvitation.handlebars",
- ScimUserProvisioned = "scimUserProvisioned.handlebars",
- PkiExpirationAlert = "pkiExpirationAlert.handlebars",
- IntegrationSyncFailed = "integrationSyncFailed.handlebars",
- SecretSyncFailed = "secretSyncFailed.handlebars",
- ExternalImportSuccessful = "externalImportSuccessful.handlebars",
- ExternalImportFailed = "externalImportFailed.handlebars",
- ExternalImportStarted = "externalImportStarted.handlebars",
- SecretRequestCompleted = "secretRequestCompleted.handlebars",
- SecretRotationFailed = "secretRotationFailed.handlebars",
- ProjectAccessRequest = "projectAccess.handlebars",
- OrgAdminProjectDirectAccess = "orgAdminProjectGrantAccess.handlebars",
- OrgAdminBreakglassAccess = "orgAdminBreakglassAccess.handlebars",
- ServiceTokenExpired = "serviceTokenExpired.handlebars"
-}
-
-export enum SmtpHost {
- Sendgrid = "smtp.sendgrid.net",
- Mailgun = "smtp.mailgun.org",
- SocketLabs = "smtp.sockerlabs.com",
- Zohomail = "smtp.zoho.com",
- Gmail = "smtp.gmail.com",
- Office365 = "smtp.office365.com"
-}
-
-export const smtpServiceFactory = (cfg: TSmtpConfig) => {
- const smtp = createTransport(cfg);
- const isSmtpOn = Boolean(cfg.host);
-
- handlebars.registerHelper("emailFooter", () => {
- const { SITE_URL } = getConfig();
- return new handlebars.SafeString(
- `Email sent via Infisical at ${SITE_URL}
`
- );
- });
-
- const sendMail = async ({ substitutions, recipients, template, subjectLine }: TSmtpSendMail) => {
- const appCfg = getConfig();
- const html = await fs.readFile(path.resolve(__dirname, "./templates/", template), "utf8");
- const temp = handlebars.compile(html);
- const htmlToSend = temp({ isCloud: appCfg.isCloud, siteUrl: appCfg.SITE_URL, ...substitutions });
-
- if (isSmtpOn) {
- await smtp.sendMail({
- from: cfg.from,
- to: recipients.join(", "),
- subject: subjectLine,
- html: htmlToSend
- });
- } else {
- logger.info("SMTP is not configured. Outputting it in terminal");
- logger.info({
- from: cfg.from,
- to: recipients.join(", "),
- subject: subjectLine,
- html: htmlToSend
- });
- }
- };
-
- const verify = async () => {
- const isConnected = smtp
- .verify()
- .then(async () => {
- logger.info("SMTP connected");
- return true;
- })
- .catch((err: Error) => {
- logger.error("SMTP error");
- logger.error(err);
- return false;
- });
-
- return isConnected;
- };
-
- return { sendMail, verify };
-};
diff --git a/backend/src/services/smtp/smtp-service.tsx b/backend/src/services/smtp/smtp-service.tsx
new file mode 100644
index 0000000000..dd1755aafd
--- /dev/null
+++ b/backend/src/services/smtp/smtp-service.tsx
@@ -0,0 +1,179 @@
+import { render } from "@react-email/components";
+import handlebars from "handlebars";
+import { createTransport } from "nodemailer";
+import SMTPTransport from "nodemailer/lib/smtp-transport";
+import React from "react";
+import {
+ AccessApprovalRequestTemplate,
+ EmailMfaTemplate,
+ EmailVerificationTemplate,
+ ExternalImportFailedTemplate,
+ ExternalImportStartedTemplate,
+ ExternalImportSucceededTemplate,
+ IntegrationSyncFailedTemplate,
+ NewDeviceLoginTemplate,
+ OrgAdminBreakglassAccessTemplate,
+ OrganizationInvitationTemplate,
+ PasswordResetTemplate,
+ PasswordSetupTemplate,
+ PkiExpirationAlertTemplate,
+ ProjectAccessRequestTemplate,
+ ProjectInvitationTemplate,
+ ScimUserProvisionedTemplate,
+ SecretApprovalRequestBypassedTemplate,
+ SecretApprovalRequestNeedsReviewTemplate,
+ SecretLeakIncidentTemplate,
+ SecretReminderTemplate,
+ SecretRequestCompletedTemplate,
+ SecretRotationFailedTemplate,
+ SecretSyncFailedTemplate,
+ ServiceTokenExpiryNoticeTemplate,
+ SignupEmailVerificationTemplate,
+ UnlockAccountTemplate
+} from "src/services/smtp/emails";
+
+import { getConfig } from "@app/lib/config/env";
+import { logger } from "@app/lib/logger";
+
+import OrgAdminProjectGrantAccessTemplate from "./emails/OrgAdminProjectGrantAccessTemplate";
+
+export type TSmtpConfig = SMTPTransport.Options;
+export type TSmtpSendMail = {
+ template: SmtpTemplates;
+ subjectLine: string;
+ recipients: string[];
+ substitutions: object;
+};
+export type TSmtpService = ReturnType;
+
+export enum SmtpTemplates {
+ SignupEmailVerification = "signupEmailVerification",
+ EmailVerification = "emailVerification",
+ SecretReminder = "secretReminder",
+ EmailMfa = "emailMfa",
+ UnlockAccount = "unlockAccount",
+ AccessApprovalRequest = "accessApprovalRequest",
+ AccessSecretRequestBypassed = "accessSecretRequestBypassed",
+ SecretApprovalRequestNeedsReview = "secretApprovalRequestNeedsReview",
+ // HistoricalSecretList = "historicalSecretLeakIncident", not used anymore?
+ NewDeviceJoin = "newDevice",
+ OrgInvite = "organizationInvitation",
+ ResetPassword = "passwordReset",
+ SetupPassword = "passwordSetup",
+ SecretLeakIncident = "secretLeakIncident",
+ WorkspaceInvite = "workspaceInvitation",
+ ScimUserProvisioned = "scimUserProvisioned",
+ PkiExpirationAlert = "pkiExpirationAlert",
+ IntegrationSyncFailed = "integrationSyncFailed",
+ SecretSyncFailed = "secretSyncFailed",
+ ExternalImportSuccessful = "externalImportSuccessful",
+ ExternalImportFailed = "externalImportFailed",
+ ExternalImportStarted = "externalImportStarted",
+ SecretRequestCompleted = "secretRequestCompleted",
+ SecretRotationFailed = "secretRotationFailed",
+ ProjectAccessRequest = "projectAccess",
+ OrgAdminProjectDirectAccess = "orgAdminProjectGrantAccess",
+ OrgAdminBreakglassAccess = "orgAdminBreakglassAccess",
+ ServiceTokenExpired = "serviceTokenExpired"
+}
+
+export enum SmtpHost {
+ Sendgrid = "smtp.sendgrid.net",
+ Mailgun = "smtp.mailgun.org",
+ SocketLabs = "smtp.sockerlabs.com",
+ Zohomail = "smtp.zoho.com",
+ Gmail = "smtp.gmail.com",
+ Office365 = "smtp.office365.com"
+}
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+const EmailTemplateMap: Record> = {
+ [SmtpTemplates.OrgInvite]: OrganizationInvitationTemplate,
+ [SmtpTemplates.NewDeviceJoin]: NewDeviceLoginTemplate,
+ [SmtpTemplates.SignupEmailVerification]: SignupEmailVerificationTemplate,
+ [SmtpTemplates.EmailMfa]: EmailMfaTemplate,
+ [SmtpTemplates.AccessApprovalRequest]: AccessApprovalRequestTemplate,
+ [SmtpTemplates.EmailVerification]: EmailVerificationTemplate,
+ [SmtpTemplates.ExternalImportFailed]: ExternalImportFailedTemplate,
+ [SmtpTemplates.ExternalImportStarted]: ExternalImportStartedTemplate,
+ [SmtpTemplates.ExternalImportSuccessful]: ExternalImportSucceededTemplate,
+ [SmtpTemplates.AccessSecretRequestBypassed]: SecretApprovalRequestBypassedTemplate,
+ [SmtpTemplates.IntegrationSyncFailed]: IntegrationSyncFailedTemplate,
+ [SmtpTemplates.OrgAdminBreakglassAccess]: OrgAdminBreakglassAccessTemplate,
+ [SmtpTemplates.SecretLeakIncident]: SecretLeakIncidentTemplate,
+ [SmtpTemplates.WorkspaceInvite]: ProjectInvitationTemplate,
+ [SmtpTemplates.ScimUserProvisioned]: ScimUserProvisionedTemplate,
+ [SmtpTemplates.SecretRequestCompleted]: SecretRequestCompletedTemplate,
+ [SmtpTemplates.UnlockAccount]: UnlockAccountTemplate,
+ [SmtpTemplates.ServiceTokenExpired]: ServiceTokenExpiryNoticeTemplate,
+ [SmtpTemplates.SecretReminder]: SecretReminderTemplate,
+ [SmtpTemplates.SecretRotationFailed]: SecretRotationFailedTemplate,
+ [SmtpTemplates.SecretSyncFailed]: SecretSyncFailedTemplate,
+ [SmtpTemplates.OrgAdminProjectDirectAccess]: OrgAdminProjectGrantAccessTemplate,
+ [SmtpTemplates.ProjectAccessRequest]: ProjectAccessRequestTemplate,
+ [SmtpTemplates.SecretApprovalRequestNeedsReview]: SecretApprovalRequestNeedsReviewTemplate,
+ [SmtpTemplates.ResetPassword]: PasswordResetTemplate,
+ [SmtpTemplates.SetupPassword]: PasswordSetupTemplate,
+ [SmtpTemplates.PkiExpirationAlert]: PkiExpirationAlertTemplate
+};
+
+export const smtpServiceFactory = (cfg: TSmtpConfig) => {
+ const smtp = createTransport(cfg);
+ const isSmtpOn = Boolean(cfg.host);
+
+ handlebars.registerHelper("emailFooter", () => {
+ const { SITE_URL } = getConfig();
+ return new handlebars.SafeString(
+ `Email sent via Infisical at ${SITE_URL}
`
+ );
+ });
+
+ const sendMail = async ({ substitutions, recipients, template, subjectLine }: TSmtpSendMail) => {
+ const appCfg = getConfig();
+
+ const EmailTemplate = EmailTemplateMap[template];
+
+ if (!EmailTemplate) {
+ throw new Error(`Email template ${template} not found`);
+ }
+
+ const htmlToSend = await render(
+
+ );
+
+ if (isSmtpOn) {
+ await smtp.sendMail({
+ from: cfg.from,
+ to: recipients.join(", "),
+ subject: subjectLine,
+ html: htmlToSend
+ });
+ } else {
+ logger.info("SMTP is not configured. Outputting it in terminal");
+ logger.info({
+ from: cfg.from,
+ to: recipients.join(", "),
+ subject: subjectLine,
+ html: htmlToSend
+ });
+ }
+ };
+
+ const verify = async () => {
+ const isConnected = smtp
+ .verify()
+ .then(async () => {
+ logger.info("SMTP connected");
+ return true;
+ })
+ .catch((err: Error) => {
+ logger.error("SMTP error");
+ logger.error(err);
+ return false;
+ });
+
+ return isConnected;
+ };
+
+ return { sendMail, verify };
+};
diff --git a/backend/src/services/smtp/templates/accessApprovalRequest.handlebars b/backend/src/services/smtp/templates/accessApprovalRequest.handlebars
deleted file mode 100644
index 6813c12005..0000000000
--- a/backend/src/services/smtp/templates/accessApprovalRequest.handlebars
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
- Access Approval Request
-
-
-
- Infisical
- New access approval request pending your review
- You have a new access approval request pending review in project "{{projectName}}".
-
-
- {{requesterFullName}}
- ({{requesterEmail}}) has requested
- {{#if isTemporary}}
- temporary
- {{else}}
- permanent
- {{/if}}
- access to
- {{secretPath}}
- in the
- {{environment}}
- environment.
-
- {{#if isTemporary}}
-
- This access will expire
- {{expiresIn}}
- after it has been approved.
- {{/if}}
-
-
- The following permissions are requested:
-
- {{#each permissions}}
- {{this}}
- {{/each}}
-
-
- {{#if note}}
- User Note: "{{note}}"
- {{/if}}
-
-
- View the request and approve or deny it
- here .
-
-
- {{emailFooter}}
-
-
-
diff --git a/backend/src/services/smtp/templates/accessSecretRequestBypassed.handlebars b/backend/src/services/smtp/templates/accessSecretRequestBypassed.handlebars
deleted file mode 100644
index 8c82df289c..0000000000
--- a/backend/src/services/smtp/templates/accessSecretRequestBypassed.handlebars
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
- Secret Approval Request Policy Bypassed
-
-
-
- Infisical
- Secret Approval Request Bypassed
- A secret approval request has been bypassed in the project "{{projectName}}".
-
-
- {{requesterFullName}}
- ({{requesterEmail}}) has merged a secret to environment
- {{environment}}
- at secret path
- {{secretPath}}
- without obtaining the required approvals.
-
-
- The following reason was provided for bypassing the policy:
- {{bypassReason}}
-
-
-
- To review this action, please visit the request panel
- here .
-
-
- {{emailFooter}}
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/emailMfa.handlebars b/backend/src/services/smtp/templates/emailMfa.handlebars
deleted file mode 100644
index 4c948b08c0..0000000000
--- a/backend/src/services/smtp/templates/emailMfa.handlebars
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
- MFA Code
-
-
-
- Infisical
- Sign in attempt requires further verification
- Your MFA code is below — enter it where you started signing in to Infisical.
- {{code}}
- The MFA code will be valid for 2 minutes.
- Not you? Contact {{#if isCloud}}Infisical{{else}}your administrator{{/if}} immediately.
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/emailVerification.handlebars b/backend/src/services/smtp/templates/emailVerification.handlebars
deleted file mode 100644
index 4a989626e4..0000000000
--- a/backend/src/services/smtp/templates/emailVerification.handlebars
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
- Code
-
-
-
- Confirm your email address
- Your confirmation code is below — enter it in the browser window where you've started confirming your email.
- {{code}}
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/historicalSecretLeakIncident.handlebars b/backend/src/services/smtp/templates/historicalSecretLeakIncident.handlebars
deleted file mode 100644
index 4a918ee0d6..0000000000
--- a/backend/src/services/smtp/templates/historicalSecretLeakIncident.handlebars
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
- Incident alert: secrets potentially leaked
-
-
-
- Infisical has uncovered {{numberOfSecrets}} secret(s) from historical commits to your repo
- View leaked secrets
-
- If these are production secrets, please rotate them immediately.
-
- Once you have taken action, be sure to update the status of the risk in your
- Infisical dashboard .
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/integrationSyncFailed.handlebars b/backend/src/services/smtp/templates/integrationSyncFailed.handlebars
deleted file mode 100644
index 2aff820fad..0000000000
--- a/backend/src/services/smtp/templates/integrationSyncFailed.handlebars
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
- Integration Sync Failed
-
-
-
- Infisical
-
-
-
-
-
-
Project : {{projectName}}
-
Environment : {{environment}}
-
Secret Path : {{secretPath}}
-
-
- {{#if syncMessage}}
- Reason: {{syncMessage}}
- {{/if}}
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/newDevice.handlebars b/backend/src/services/smtp/templates/newDevice.handlebars
deleted file mode 100644
index 197e0b7a7c..0000000000
--- a/backend/src/services/smtp/templates/newDevice.handlebars
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- Successful login for {{email}} from new device
-
-
-
- Infisical
- We're verifying a recent login for {{email}}:
- Timestamp : {{timestamp}}
- IP address : {{ip}}
- User agent : {{userAgent}}
- If you believe that this login is suspicious, please contact
- {{#if isCloud}}Infisical{{else}}your administrator{{/if}}
- or reset your password immediately.
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/orgAdminBreakglassAccess.handlebars b/backend/src/services/smtp/templates/orgAdminBreakglassAccess.handlebars
deleted file mode 100644
index cc97ff2019..0000000000
--- a/backend/src/services/smtp/templates/orgAdminBreakglassAccess.handlebars
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
- Organization admin has bypassed SSO
-
-
-
- Infisical
- The organization admin {{email}} has bypassed enforced SSO login.
- Timestamp : {{timestamp}}
- IP address : {{ip}}
- User agent : {{userAgent}}
- If you'd like to disable Admin SSO Bypass, please visit Organization Settings > Security.
-
- {{emailFooter}}
-
-
-
diff --git a/backend/src/services/smtp/templates/orgAdminProjectGrantAccess.handlebars b/backend/src/services/smtp/templates/orgAdminProjectGrantAccess.handlebars
deleted file mode 100644
index ef8c6e6b42..0000000000
--- a/backend/src/services/smtp/templates/orgAdminProjectGrantAccess.handlebars
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
- Organization admin issued direct access to project
-
-
-
- Infisical
- The organization admin {{email}} has granted direct access to the project "{{projectName}}".
-
- {{emailFooter}}
-
-
-
diff --git a/backend/src/services/smtp/templates/organizationInvitation.handlebars b/backend/src/services/smtp/templates/organizationInvitation.handlebars
deleted file mode 100644
index da429477be..0000000000
--- a/backend/src/services/smtp/templates/organizationInvitation.handlebars
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
- Organization Invitation
-
-
- Join your organization on Infisical
- {{inviterFirstName}} ({{inviterUsername}}) has invited you to their Infisical organization named {{organizationName}}
- Click to join
- What is Infisical?
- Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets and configs.
-
- {{emailFooter}}
-
-
diff --git a/backend/src/services/smtp/templates/passwordReset.handlebars b/backend/src/services/smtp/templates/passwordReset.handlebars
deleted file mode 100644
index 1cb2ae8ce1..0000000000
--- a/backend/src/services/smtp/templates/passwordReset.handlebars
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
- Account Recovery
-
-
- Reset your password
- Someone requested a password reset.
- Reset password
- If you didn't initiate this request, please contact
- {{#if isCloud}}us immediately at team@infisical.com.{{else}}your administrator immediately.{{/if}}
-
- {{emailFooter}}
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/passwordSetup.handlebars b/backend/src/services/smtp/templates/passwordSetup.handlebars
deleted file mode 100644
index 1059a74460..0000000000
--- a/backend/src/services/smtp/templates/passwordSetup.handlebars
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
- Password Setup
-
-
- Setup your password
- Someone requested to set up a password for your account.
- Make sure you are already logged in to Infisical in the current browser before clicking the link below.
- Setup password
- If you didn't initiate this request, please contact
- {{#if isCloud}}us immediately at team@infisical.com.{{else}}your administrator immediately.{{/if}}
-
- {{emailFooter}}
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/pkiExpirationAlert.handlebars b/backend/src/services/smtp/templates/pkiExpirationAlert.handlebars
deleted file mode 100644
index f9013e24db..0000000000
--- a/backend/src/services/smtp/templates/pkiExpirationAlert.handlebars
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
- Infisical CA/Certificate expiration notice
-
-
- Hello,
- This is an automated alert for "{{alertName}}" triggered for CAs/Certificates expiring in
- {{alertBeforeDays}}
- days.
-
- Expiring Items:
-
- {{#each items}}
-
- {{type}}:
- {{friendlyName}}
- Serial Number:
- {{serialNumber}}
- Expires On:
- {{expiryDate}}
-
- {{/each}}
-
-
- Please take necessary actions to renew these items before they expire.
-
- For more details, please log in to your Infisical account and check your PKI management section.
-
- {{emailFooter}}
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/projectAccess.handlebars b/backend/src/services/smtp/templates/projectAccess.handlebars
deleted file mode 100644
index 5ff1ca7ec4..0000000000
--- a/backend/src/services/smtp/templates/projectAccess.handlebars
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
- Project Access Request
-
-
-
- Infisical
- You have a new project access request!
-
- Requester Name: "{{requesterName}}"
- Requester Email: "{{requesterEmail}}"
- Project Name: "{{projectName}}"
- Organization Name: "{{orgName}}"
- User Note: "{{note}}"
-
-
- Please click on the link below to grant access
-
- Grant Access
- {{emailFooter}}
-
-
-
diff --git a/backend/src/services/smtp/templates/scimUserProvisioned.handlebars b/backend/src/services/smtp/templates/scimUserProvisioned.handlebars
deleted file mode 100644
index ba04d72011..0000000000
--- a/backend/src/services/smtp/templates/scimUserProvisioned.handlebars
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
- Organization Invitation
-
-
- Join your organization on Infisical
- You've been invited to join the Infisical organization — {{organizationName}}
- Join now
- What is Infisical?
- Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets
- and configs.
-
- {{emailFooter}}
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/secretApprovalRequestNeedsReview.handlebars b/backend/src/services/smtp/templates/secretApprovalRequestNeedsReview.handlebars
deleted file mode 100644
index c12c084607..0000000000
--- a/backend/src/services/smtp/templates/secretApprovalRequestNeedsReview.handlebars
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
- Secret Change Approval Request
-
-
-
- Hi {{firstName}},
- New secret change requests are pending review.
-
- You have a secret change request pending your review in project "{{projectName}}", in the "{{organizationName}}"
- organization.
-
-
- View the request and approve or deny it
- here .
-
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/secretLeakIncident.handlebars b/backend/src/services/smtp/templates/secretLeakIncident.handlebars
deleted file mode 100644
index d0d9a617ce..0000000000
--- a/backend/src/services/smtp/templates/secretLeakIncident.handlebars
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
- Incident alert: secret leaked
-
-
-
- Infisical has uncovered {{numberOfSecrets}} secret(s) from your recent push
- View leaked secrets
- You are receiving this notification because one or more secret leaks have been detected in a recent commit pushed
- by
- {{pusher_name}}
- ({{pusher_email}}). If these are test secrets, please add `infisical-scan:ignore` at the end of the line
- containing the secret as comment in the given programming. This will prevent future notifications from being sent
- out for those secret(s).
-
- If these are production secrets, please rotate them immediately.
-
- Once you have taken action, be sure to update the status of the risk in your
- Infisical dashboard .
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/secretReminder.handlebars b/backend/src/services/smtp/templates/secretReminder.handlebars
deleted file mode 100644
index d64c4bf42f..0000000000
--- a/backend/src/services/smtp/templates/secretReminder.handlebars
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
- Secret Reminder
-
-
-
- Infisical
- You have a new secret reminder!
- You have a new secret reminder from project "{{projectName}}", in {{organizationName}}
- {{#if reminderNote}}
- Here's the note included with the reminder: {{reminderNote}}
- {{/if}}
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/secretRequestCompleted.handlebars b/backend/src/services/smtp/templates/secretRequestCompleted.handlebars
deleted file mode 100644
index d2cefdd546..0000000000
--- a/backend/src/services/smtp/templates/secretRequestCompleted.handlebars
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
- Secret Request Completed
-
-
-
- Infisical
- A secret has been shared with you
-
- {{#if name}}
- Secret request name: {{name}}
- {{/if}}
- {{#if respondentUsername}}
- Shared by: {{respondentUsername}}
- {{/if}}
-
-
-
-
-
- You can access the secret by clicking the link below.
-
-
- Access Secret
-
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/secretRotationFailed.handlebars b/backend/src/services/smtp/templates/secretRotationFailed.handlebars
deleted file mode 100644
index 728798ce85..0000000000
--- a/backend/src/services/smtp/templates/secretRotationFailed.handlebars
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
- Your {{rotationType}} Rotation "{{rotationName}}" Failed to Rotate
-
-
-
- Infisical
-
-
-
-
-
-
Name : {{rotationName}}
-
Type : {{rotationType}}
-
Project : {{projectName}}
-
Environment : {{environment}}
-
Secret Path : {{secretPath}}
-
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/secretSyncFailed.handlebars b/backend/src/services/smtp/templates/secretSyncFailed.handlebars
deleted file mode 100644
index 3e7ad7831d..0000000000
--- a/backend/src/services/smtp/templates/secretSyncFailed.handlebars
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
- {{syncDestination}} Sync "{{syncName}}" Failed
-
-
-
- Infisical
-
-
-
-
-
-
Name : {{syncName}}
-
Destination : {{syncDestination}}
-
Project : {{projectName}}
- {{#if environment}}
-
Environment : {{environment}}
- {{/if}}
- {{#if secretPath}}
-
Secret Path : {{secretPath}}
- {{/if}}
-
-
- {{#if failureMessage}}
- Reason: {{failureMessage}}
- {{/if}}
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/serviceTokenExpired.handlebars b/backend/src/services/smtp/templates/serviceTokenExpired.handlebars
deleted file mode 100644
index 199150c051..0000000000
--- a/backend/src/services/smtp/templates/serviceTokenExpired.handlebars
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
- Service Token Expiring Soon
-
-
-
- Service Token Expiry Notice
- Your service token "{{tokenName}}" will expire within 24 hours.
-
- This token is currently being used on project "{{projectName}}". If this token is still needed for your workflow, please create a new one before it expires.
-
- Create New Token
-
- {{emailFooter}}
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/signupEmailVerification.handlebars b/backend/src/services/smtp/templates/signupEmailVerification.handlebars
deleted file mode 100644
index 39f47ae48b..0000000000
--- a/backend/src/services/smtp/templates/signupEmailVerification.handlebars
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
- Code
-
-
-
- Confirm your email address
- Your confirmation code is below — enter it in the browser window where you've started signing up for Infisical.
- {{code}}
- Questions about setting up Infisical?
- {{#if isCloud}}Email us at support@infisical.com{{else}}Contact your administrator{{/if}}.
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/unlockAccount.handlebars b/backend/src/services/smtp/templates/unlockAccount.handlebars
deleted file mode 100644
index b65cb56259..0000000000
--- a/backend/src/services/smtp/templates/unlockAccount.handlebars
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
- Your Infisical account has been locked
-
-
-
- Unlock your Infisical account
- Your account has been temporarily locked due to multiple failed login attempts.
- To unlock your account, follow the link here
-
If these attempts were not made by you, reset your password immediately.
-
- {{emailFooter}}
-
-
-
\ No newline at end of file
diff --git a/backend/src/services/smtp/templates/workspaceInvitation.handlebars b/backend/src/services/smtp/templates/workspaceInvitation.handlebars
deleted file mode 100644
index fde75a6d65..0000000000
--- a/backend/src/services/smtp/templates/workspaceInvitation.handlebars
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
- Project Invitation
-
-
- Join your team on Infisical
- You have been invited to a new Infisical project named {{workspaceName}}
- Click to join
- What is Infisical?
- Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets
- and configs.
-
- {{emailFooter}}
-
-
diff --git a/backend/src/services/super-admin/super-admin-service.ts b/backend/src/services/super-admin/super-admin-service.ts
index 8c23a00c68..8687826c8d 100644
--- a/backend/src/services/super-admin/super-admin-service.ts
+++ b/backend/src/services/super-admin/super-admin-service.ts
@@ -172,8 +172,8 @@ export const superAdminServiceFactory = ({
const canServerAdminAccessAfterApply =
data.enabledLoginMethods.some((loginMethod) =>
- loginMethodToAuthMethod[loginMethod as LoginMethod].some(
- (authMethod) => superAdminUser.authMethods?.includes(authMethod)
+ loginMethodToAuthMethod[loginMethod as LoginMethod].some((authMethod) =>
+ superAdminUser.authMethods?.includes(authMethod)
)
) ||
isUserSamlAccessEnabled ||
diff --git a/backend/tsconfig.json b/backend/tsconfig.json
index 90165acbe2..3d78132577 100644
--- a/backend/tsconfig.json
+++ b/backend/tsconfig.json
@@ -25,7 +25,8 @@
"baseUrl": ".",
"paths": {
"@app/*": ["./src/*"]
- }
+ },
+ "jsx": "react"
},
"include": ["src/**/*", "scripts/**/*", "e2e-test/**/*", "./.eslintrc.js", "./tsup.config.js"],
"exclude": ["node_modules"]