Conversation
|
Task linked: DA-392 Create email service |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
danmaku-anywhere-web | 030188e | Commit Preview URL Branch Preview URL |
Mar 16 2026, 01:10 AM |
Summary of ChangesHello @Mr-Quin, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a new email service to the backend proxy, leveraging Resend for transactional email capabilities. This enhancement enables critical authentication features such as password reset and email verification. Concurrently, a new documentation enforcement rule has been added, alongside comprehensive Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a new email service using Resend to handle transactional emails for password resets and email verifications. The implementation includes a service abstraction, which is good practice. The changes correctly use Cloudflare Workers' waitUntil to ensure background tasks like sending emails are completed. My feedback focuses on improving the robustness and security of the new email service by adding validation for required environment variables and preventing potential XSS vulnerabilities. A large portion of this PR also includes adding documentation files across the repository, which is a great addition for maintainability.
| const from = env.EMAIL_FROM.trim() | ||
|
|
||
| emailService = new ResendEmailService(apiKey, from) |
There was a problem hiding this comment.
The EMAIL_FROM environment variable is trimmed but not checked for being empty. If the variable is not set or contains only whitespace, from will be an empty string, which will cause the email sending to fail at runtime. It's better to fail fast with a clear error message if this crucial configuration is missing.
const from = env.EMAIL_FROM.trim()
if (!from) {
throw new Error('EMAIL_FROM environment variable is not configured.')
}
emailService = new ResendEmailService(apiKey, from)| const html = | ||
| params.html ?? | ||
| (params.text | ||
| ? `<p>${params.text.replaceAll('\n', '<br>')}</p>` | ||
| : '<p></p>') |
There was a problem hiding this comment.
When converting a plain text body to HTML, the text content is not escaped. This could lead to a Cross-Site Scripting (XSS) vulnerability if the params.text contains malicious HTML, for example from user-controlled data in the future. While the current usage in better-auth seems safe, it's best practice to always escape content that is injected into HTML.
| const html = | |
| params.html ?? | |
| (params.text | |
| ? `<p>${params.text.replaceAll('\n', '<br>')}</p>` | |
| : '<p></p>') | |
| const escapeHtml = (unsafe: string) => | |
| unsafe | |
| .replace(/&/g, "&") | |
| .replace(/</g, "<") | |
| .replace(/>/g, ">") | |
| .replace(/"/g, """) | |
| .replace(/'/g, "'"); | |
| const html = | |
| params.html ?? | |
| (params.text | |
| ? `<p>${escapeHtml(params.text).replaceAll('\n', '<br>')}</p>` | |
| : '<p></p>') |
There was a problem hiding this comment.
Pull request overview
This PR implements email service functionality for the Danmaku Anywhere backend proxy using Resend as the email provider. The changes enable password reset and email verification features through Better Auth integration. Additionally, this PR includes comprehensive documentation updates (README.md and AGENTS.md files) for multiple packages and apps across the monorepo, following the newly added documentation standards rule.
Changes:
- Integrated Resend email service with abstraction layer for transactional emails
- Configured Better Auth to send password reset and email verification emails
- Added comprehensive README.md and AGENTS.md documentation for all packages and apps
- Updated Cloudflare Workers configuration with email-related environment variables and secrets
Reviewed changes
Copilot reviewed 30 out of 32 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Added resend@6.9.2 and its dependencies (postal-mime, svix, standardwebhooks, uuid@10.0.0) |
| backend/proxy/package.json | Added resend dependency to backend proxy |
| backend/proxy/wrangler.json | Added EMAIL_FROM env var and RESEND_API_KEY secret binding across all environments; also added preview_bucket_name for R2 |
| backend/proxy/worker-configuration.d.ts | Regenerated TypeScript types to include new EMAIL_FROM and RESEND_API_KEY bindings |
| backend/proxy/src/email/types.ts | Defined EmailService interface and SendEmailParams for email abstraction |
| backend/proxy/src/email/resend.ts | Implemented ResendEmailService using Resend SDK |
| backend/proxy/src/email/index.ts | Created getOrCreateEmailService factory with singleton pattern |
| backend/proxy/src/auth/config.ts | Integrated email service for password reset and email verification callbacks; updated getOrCreateAuth signature to accept waitUntil |
| backend/proxy/src/routes/api/auth/router.ts | Updated auth router to pass waitUntil to getOrCreateAuth |
| backend/proxy/src/middleware/authContext.ts | Updated middleware to pass waitUntil to getOrCreateAuth |
| backend/proxy/scripts/setup-secrets-store.ts | Added RESEND_API_KEY_STG to local secrets setup script |
| backend/proxy/.dev.vars.example | Added EMAIL_FROM environment variable example |
| backend/proxy/README.md | Added comprehensive documentation for the backend proxy package |
| backend/proxy/AGENTS.md | Added agent context documentation for the backend proxy |
| packages/*/README.md | Added README documentation for all workspace packages |
| packages/*/AGENTS.md | Added agent context documentation for all workspace packages |
| app/web/README.md | Added README documentation for the web app |
| app/web/AGENTS.md | Added agent context documentation for the web app |
| .cursor/rules/update-docs-after-changes.mdc | Added new documentation maintenance rule |
| .cursor/rules/README.md | Updated rules index to include new documentation rule |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (14)
packages/danmaku-converter/README.md:13
- Typo in the command description: 'tsgo' should likely be 'tsc' (TypeScript compiler) or another valid build tool name.
| `pnpm build` | Compile with tsgo |
packages/web-scraper/README.md:1
- This PR includes documentation updates (README.md and AGENTS.md) for multiple packages and the web app that are unrelated to the email service implementation. While these documentation updates appear to follow the conventions described in
.cursor/rules/update-docs-after-changes.mdc, they should ideally be in a separate PR focused on documentation to keep changes focused and easier to review.
The email service changes are in backend/proxy/src/email/, backend/proxy/src/auth/config.ts, and configuration files, but the documentation changes span across many unrelated packages.
backend/proxy/src/email/resend.ts:42
- The new email service functionality lacks test coverage. The codebase has test infrastructure (vitest with workers pool) and existing test files (e.g.,
src/utils/computeEtag.test.ts), indicating that testing is a practice in this project.
Consider adding tests for:
ResendEmailService.send()- test email formatting, error handling, and API interactiongetOrCreateEmailService()- test singleton behavior and configuration validation- Integration with auth callbacks - verify email sending is triggered correctly for password reset and email verification
import { Resend } from 'resend'
import type { EmailService, SendEmailParams } from './types'
/**
* Resend implementation of the email service abstraction.
* Only this file should import from 'resend' so the rest of the app stays provider-agnostic.
*/
export class ResendEmailService implements EmailService {
private readonly resend: Resend
private readonly from: string
constructor(apiKey: string, from: string) {
this.resend = new Resend(apiKey)
this.from = from
}
async send(params: SendEmailParams): Promise<void> {
const to = Array.isArray(params.to) ? params.to : [params.to]
const html =
params.html ??
(params.text
? `<p>${params.text.replaceAll('\n', '<br>')}</p>`
: '<p></p>')
const text = params.text
const payload: Parameters<Resend['emails']['send']>[0] = {
from: this.from,
to,
subject: params.subject,
html,
}
if (text) payload.text = text
console.log('Sending email to', to)
const { error, data } = await this.resend.emails.send(payload)
console.log('Email sent successfully', data)
if (error) {
throw new Error(`Resend send failed: ${JSON.stringify(error)}`)
}
}
}
backend/proxy/src/auth/config.ts:54
- Email sending operations are wrapped with
waitUntil, but errors thrown fromemailService.send()will not be caught or logged. If an email fails to send (e.g., due to API key issues or network problems), the user won't receive any feedback, and the error might be silently lost.
Consider adding error handling around the email send promise before passing it to waitUntil, or ensure that email send failures are properly logged and monitored.
sendResetPassword: async ({ user, url }) => {
const emailService = await getOrCreateEmailService(env)
const promise = emailService.send({
to: user.email,
subject: 'Reset your password',
text: `Click the link to reset your password: ${url}`,
})
waitUntil(promise)
},
packages/web-scraper/README.md:13
- Typo in the command description: 'tsgo' should likely be 'tsc' (TypeScript compiler) or another valid build tool name. The same typo appears in multiple README files.
packages/bangumi-api/README.md:16 - Typo in the command description: 'tsgo' should likely be 'tsc' (TypeScript compiler) or another valid build tool name.
| `pnpm build` | tsgo + copy schemas |
backend/proxy/src/email/resend.ts:37
- The console.log statement on line 37 executes before checking if there was an error. This means "Email sent successfully" will be logged even when the email send operation fails. The log should only execute when there is no error, or should be moved after the error check.
console.log('Email sent successfully', data)
backend/proxy/src/email/resend.ts:34
- Sensitive information (email addresses) is being logged with console.log. While this might be acceptable for debugging, it could expose user PII in production logs. Consider using a more structured logging approach or redacting sensitive data, especially since the codebase appears to use Sentry for error tracking and observability.
console.log('Sending email to', to)
backend/proxy/src/email/index.ts:14
- The
EMAIL_FROMenvironment variable is only trimmed but not validated. If this value is empty or malformed after trimming, the email service will fail at runtime. Consider adding validation to ensureEMAIL_FROMis a non-empty string with a valid email format, similar to how other critical configuration values are validated.
const from = env.EMAIL_FROM.trim()
backend/proxy/src/auth/config.ts:66
- Email sending operations are wrapped with
waitUntil, but errors thrown fromemailService.send()will not be caught or logged. If an email fails to send (e.g., due to API key issues or network problems), the user won't receive any feedback, and the error might be silently lost.
Consider adding error handling around the email send promise before passing it to waitUntil, or ensure that email send failures are properly logged and monitored.
sendVerificationEmail: async ({ user, url }) => {
const emailService = await getOrCreateEmailService(env)
const promise = emailService.send({
to: user.email,
subject: 'Verify your email address',
text: `Click the link to verify your email: ${url}`,
})
waitUntil(promise)
},
backend/proxy/src/email/resend.ts:23
- The
htmlparameter includes a fallback to<p></p>when bothparams.htmlandparams.textare undefined. However, theSendEmailParamsinterface intypes.tsmarks both as optional but doesn't indicate that at least one must be provided. This could lead to sending emails with empty content.
Consider either: (1) requiring at least one of text or html in the type definition, or (2) adding runtime validation to throw an error if both are missing.
const html =
params.html ??
(params.text
? `<p>${params.text.replaceAll('\n', '<br>')}</p>`
: '<p></p>')
packages/danmaku-engine/README.md:13
- Typo in the command description: 'tsgo' should likely be 'tsc' (TypeScript compiler) or another valid build tool name.
| `pnpm build` | Compile with tsgo |
packages/danmaku-provider/README.md:15
- Typo in the command description: 'tsgo' should likely be 'tsc' (TypeScript compiler) or another valid build tool name.
| `pnpm build` | Compile protobuf + tsgo |
backend/proxy/wrangler.json:136
- The addition of
preview_bucket_namefor the R2 bucket configuration is unrelated to the email service functionality described in the PR title. This change should ideally be in a separate PR or the PR description should mention this infrastructure change.
"bucket_name": "danmaku-anywhere-file-staging",
"preview_bucket_name": "danmaku-anywhere-file-staging-preview"
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
bee9ce1 to
53c69c6
Compare
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Deploying danmaku-anywhere-docs with
|
| Latest commit: |
23d9eb0
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://db7d94b7.danmaku-anywhere.pages.dev |
| Branch Preview URL: | https://da-392-create-email-service.danmaku-anywhere.pages.dev |
23d9eb0 to
030188e
Compare
No description provided.