Skip to content

Add template support and enhanced error handling to email sending API#813

Merged
BilalG1 merged 7 commits intodevfrom
email-sending-and-unsubscribes
Aug 2, 2025
Merged

Add template support and enhanced error handling to email sending API#813
BilalG1 merged 7 commits intodevfrom
email-sending-and-unsubscribes

Conversation

@BilalG1
Copy link
Contributor

@BilalG1 BilalG1 commented Jul 29, 2025


Important

Enhances email sending API with template support, improved error handling, and new interfaces, while adding comprehensive tests and updating rendering logic.

  • Behavior:
    • Adds support for sending emails using templates with variables and optional theming in send-email/route.tsx.
    • Introduces per-user notification category checks before sending emails.
    • Adds optional unsubscribe link in email themes.
  • Error Handling:
    • Refines error handling in send-email/route.tsx for missing content, non-existent user IDs, and shared email server configurations.
    • Uses KnownErrors for specific error cases.
  • API Changes:
    • Adds new interfaces and methods for email sending in server-interface.ts and admin-interface.ts.
    • Removes deprecated email sending methods from admin interfaces.
  • Testing:
    • Adds e2e tests in email.test.ts for various email sending scenarios, including HTML content, templates, and error cases.
  • Misc:
    • Updates email rendering logic in email-rendering.tsx to handle new template and theme options.
    • Simplifies import statements and cleans up code structure across multiple files.

This description was created by Ellipsis for 1d5a056. You can customize this summary. It will automatically update as commits are pushed.


Summary by CodeRabbit

  • New Features

    • Enhanced email sending to support both raw HTML and template-based emails with variables and optional theming.
    • Added per-user notification category checks before sending emails.
    • Email themes now support an optional unsubscribe link in the footer.
  • Improvements

    • Updated email rendering to pass the unsubscribe link as a prop to themes.
    • Refined error handling for email sending.
    • Improved flexibility of email sending options and result reporting.
  • API Changes

    • Introduced new interfaces and methods for sending emails on the server side, including detailed result reporting.
    • Removed deprecated admin-side email sending methods and interfaces.
    • Added new types for email sending options and results.
  • Bug Fixes

    • Fixed navigation and property naming inconsistencies in dashboard email template editing and sending flows.
  • Chores

    • Simplified import statements and cleaned up internal code structure.
    • Updated Docker environment for freestyle mock service to use Bun runtime and adjusted port mappings.
  • Tests

    • Added comprehensive tests covering email sending scenarios, including error handling and multi-user support.
    • Updated existing tests to reflect refined email subjects, template rendering, and unsubscribe link features.

@vercel
Copy link

vercel bot commented Jul 29, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
stack-backend ✅ Ready (Inspect) Visit Preview 💬 Add feedback Aug 2, 2025 1:28am
stack-dashboard ✅ Ready (Inspect) Visit Preview 💬 Add feedback Aug 2, 2025 1:28am
stack-demo ✅ Ready (Inspect) Visit Preview 💬 Add feedback Aug 2, 2025 1:28am
stack-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Aug 2, 2025 1:28am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 29, 2025

Walkthrough

This change refactors and extends the email sending system to support template- and theme-based emails with dynamic variables and unsubscribe link handling. It updates backend APIs, type declarations, and client interfaces, removes deprecated admin-only methods, and introduces new server-side email-sending interfaces and result types to enable more flexible and granular email delivery.

Changes

Cohort / File(s) Change Summary
Backend Email Send Route Enhancements
apps/backend/src/app/api/latest/emails/send-email/route.tsx
Expanded the email send handler to support template-based emails, dynamic themes, variable injection, and per-user notification category checks. Improved error handling and updated request schema.
Backend Email Render Route Cleanup
apps/backend/src/app/api/latest/emails/render-email/route.tsx
Consolidated import statements by merging templateThemeIdSchema imports; no logic changes.
Email Rendering Logic Refactor
apps/backend/src/lib/email-rendering.tsx
Refactored template creation and rendering to pass unsubscribe links as props to themes, updated function signatures, and cleaned up unsubscribe link handling.
Dashboard Email Send Dialog Update
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx
Changed the property name from content to html when sending email content to the backend.
Dashboard Email Template Edit Path Fix
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/email-templates/page-client.tsx
Updated the template edit navigation path for consistency.
Dashboard Editor ThemeProps Typing
apps/dashboard/src/components/vibe-coding/code-editor.tsx
Added a ThemeProps type declaration for email themes in the module.
Shared Email Theme/Template Source Update
packages/stack-shared/src/helpers/emails.ts
Modified theme and template source code to support optional unsubscribe links, updated theme function signatures, and added static preview props.
Shared Admin Interface Cleanup
packages/stack-shared/src/interface/admin-interface.ts
Removed the deprecated sendEmail method from the admin interface.
Shared Server Interface Expansion
packages/stack-shared/src/interface/server-interface.ts
Added a new sendEmail method supporting template, theme, and variable options, returning per-user results and handling known errors.
Template Admin App Implementation Cleanup
packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts
Removed the deprecated sendEmail method from the admin app implementation.
Template Server App Implementation Expansion
packages/template/src/lib/stack-app/apps/implementations/server-app-impl.ts
Added a new sendEmail method delegating to the updated interface, supporting the expanded options and result types.
Template Admin App Interface Cleanup
packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts
Removed the deprecated sendEmail method from the admin app interface.
Template Server App Interface Expansion
packages/template/src/lib/stack-app/apps/interfaces/server-app.ts
Added a new sendEmail method to the server app interface with expanded options and result/error typing.
Template Email Types Addition
packages/template/src/lib/stack-app/email/index.ts
Added new type SendEmailOptions enforcing either raw HTML or template usage with variables for email sending.
End-to-End Email Tests Addition
apps/e2e/tests/js/email.test.ts
Added comprehensive tests covering email sending with HTML, templates, themes, multiple users, notification categories, and error cases including missing server, invalid users, and schema violations.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ServerAPI
    participant EmailRenderer
    participant ThemeSelector
    participant TemplateStore
    participant User

    Client->>ServerAPI: POST /emails/send-email (userIds, templateId, variables, themeId, etc.)
    ServerAPI->>ThemeSelector: Get theme by themeId (if provided)
    ServerAPI->>TemplateStore: Get template by templateId or use raw HTML
    loop For each user
        ServerAPI->>EmailRenderer: Render email (template, theme, variables, unsubscribeLink)
        EmailRenderer-->>ServerAPI: Rendered email, notificationCategory
        ServerAPI->>User: Check notificationCategory enabled
        alt Notifications enabled
            ServerAPI->>User: Send email
        else Notifications disabled
            ServerAPI-->>User: Skip email
        end
    end
    ServerAPI-->>Client: Per-user result array (userId, email)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • sending new templates #794: Also modifies email template rendering and theme selection logic in overlapping backend and rendering files, indicating close relation to this PR's changes.

Suggested reviewers

  • N2D4

Poem

🐇✨
With templates and themes, our emails now gleam,
Unsubscribe links hop in, as part of the dream.
Old admin code burrowed away,
New server flows brighten the day.
Per-user checks, variables galore—
This bunny’s email magic is hard to ignore!
✉️🌱

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch email-sending-and-unsubscribes

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@recurseml
Copy link

recurseml bot commented Jul 29, 2025

✨ No issues found! Your code is sparkling clean! ✨

🗒️ View all ignored comments in this repo
  • The constraint 'TokenStoreType extends string' is too restrictive. It should likely be 'TokenStoreType extends string | object' to match the condition check in line 113 where TokenStoreType is checked against {}
  • Return type mismatch - the interface declares useUsers() returning ServerUser[] but the Team interface that this extends declares useUsers() returning TeamUser[]
  • There is a syntax error in the super constructor call due to the ellipsis operator used incorrectly. Objects aren't being merged correctly. This syntax usage can lead to runtime errors when trying to pass the merged object to 'super()'. Verify that the intended alterations to the object occur before or outside of the super() call if needed.
  • Throwing an error when no active span is found is too aggressive. The log function should gracefully fallback to console.log or another logging mechanism when there's no active span, since not all execution contexts will have an active span. This makes the code less resilient and could break functionality in non-traced environments.

📚 Relevant Docs

  • Function sets backendContext with a new configuration but doesn't pass 'defaultProjectKeys'. Since defaultProjectKeys is required in the type definition and cannot be updated (throws error if tried to set), this will cause a type error.
  • The schema is using array syntax for pick() which is incorrect for Yup schemas. The pick() method in Yup expects individual arguments, not an array. Should be changed to: emailConfigSchema.pick('type', 'host', 'port', 'username', 'sender_name', 'sender_email')

📚 Relevant Docs

  • Creating a refresh token with current timestamp as expiration means it expires immediately. Should set a future date for token expiration.
  • The 'tools' object is initialized as an empty object, even though 'tools' is presumably expected to contain tool definitions. This could cause the server capabilities to lack necessary tool configurations, thus potentially impacting functionalities that depend on certain tool setups.

📚 Relevant Docs

  • 'STACK_SECRET_SERVER_KEY' is potentially being included in every request header without checking its existence again here. Although it's checked during initialization, this could lead to security issues as it's exposed in all communications where the header is logged or captured.

📚 Relevant Docs

  • When adding 'use client' directive at the beginning, it doesn't check if file.text already contains the 'use client' directive. This could lead to duplicate 'use client' directives if the file already has one.

📚 Relevant Docs

⚠️ Only 5 files were analyzed due to processing limits.

Need help? Join our Discord for support!
https://discord.gg/qEjHQk64Z9

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Summary

This PR significantly enhances Stack Auth's email sending system by adding template support and improving error handling across the entire email infrastructure. The changes represent a major architectural shift from a simple HTML-based email system to a comprehensive template-based approach.

Key Changes:

  1. New Email Sending API: Replaces the old sendEmail method in StackAdminApp with a more robust implementation in StackServerApp. The new API supports both HTML content and template-based emails with variables, themes, and proper error handling.

  2. Template System Enhancements: Updates email rendering to support unsubscribe links at the theme level rather than hardcoded in templates. This provides better customization and styling control for developers.

  3. Type Safety Improvements: Adds comprehensive TypeScript definitions including SendEmailOptions, SendEmailResult, and ThemeProps types to support the new functionality with proper IntelliSense.

  4. Enhanced Error Handling: Implements Result types with specific known errors (RequiresCustomEmailServer, SchemaError) to provide better error reporting and handling.

  5. Bulk Email Support: The new API can send emails to multiple users simultaneously and returns per-user results, making it suitable for batch operations.

  6. Unsubscribe Compliance: Adds standardized unsubscribe link functionality to both Light and Dark email themes, supporting regulatory compliance requirements.

The changes maintain backward compatibility while providing a foundation for more sophisticated email campaigns and better developer experience through improved type safety and error reporting.

PR Description Notes:

  • The PR body is empty and could benefit from a detailed description of the changes and their impact

Confidence score: 3/5

  • This PR introduces significant architectural changes that should work well but has some performance and complexity concerns
  • The dual rendering approach for template emails could impact performance, and there are edge cases in error handling that need attention
  • Files that need more attention: apps/backend/src/app/api/latest/emails/send-email/route.tsx for performance optimization and error handling improvements

14 files reviewed, 4 comments

Edit Code Review Bot Settings | Greptile

@patched-codes
Copy link

patched-codes bot commented Jul 29, 2025

Documentation Changes Required

docs/templates/sdk/objects/stack-app.mdx

  1. Add documentation for the new sendEmail method in the StackServerApp interface:

    • Insert a new collapsible method section for sendEmail after the existing createUser method and before the "Team Management" section.
    • Include the following information:
      • Method description: Sends emails from the server
      • Parameters: options (SendEmailOptions)
      • Return value: Promise<Result<SendEmailResult[], KnownErrors["RequiresCustomEmailServer"] | KnownErrors["SchemaError"]>>
      • Example usage

    Example addition:

    <CollapsibleMethodSection method="sendEmail" signature="options" appType="StackServerApp" defaultOpen={false}>
    <MethodLayout>
      <MethodContent>
    
    Sends emails from the server.
    
    **Parameters:**
    - `options` (SendEmailOptions) - Configuration for the email(s) to send
    
    **Returns:** `Promise<Result<SendEmailResult[], Error>>`
    
    The result can be either successful with an array of SendEmailResult objects or an error of type "RequiresCustomEmailServer" or "SchemaError".
    
      </MethodContent>
      <MethodAside>
    
    <AsideSection title="Signature">
    
    ```typescript
    declare function sendEmail(options: SendEmailOptions): Promise<Result<SendEmailResult[], KnownErrors["RequiresCustomEmailServer"] | KnownErrors["SchemaError"]>>;
    const result = await stackServerApp.sendEmail({
      to: ["user@example.com"],
      subject: "Welcome to our platform",
      text: "Thank you for signing up!",
      html: "<p>Thank you for signing up!</p>"
    });
    
    if (result.ok) {
      console.log("Email sent successfully:", result.value);
    } else {
      console.error("Failed to send email:", result.error);
    }
    ```

Note on Other Files

No changes are required for other documentation files, as the new types SendEmailOptions and SendEmailResult are internal and not exposed in the public API.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (5)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/email-templates/page-client.tsx (1)

64-64: Path correction improves consistency.

The updated path email-templates/${sharedSmtpWarningDialogOpen} now aligns with the routing pattern used elsewhere in the component (line 47), providing better consistency.

However, as noted in a previous review, consider using tagged template literals for URL construction to ensure proper encoding:

-            router.push(`email-templates/${sharedSmtpWarningDialogOpen}`);
+            router.push(urlString`email-templates/${sharedSmtpWarningDialogOpen}`);
packages/template/src/lib/stack-app/email/index.ts (1)

17-17: Use Record<string, unknown> for better type safety.

Using Record<string, any> for variables could lead to runtime type errors. Consider using Record<string, unknown> for better type safety.

-  variables?: Record<string, any>,
+  variables?: Record<string, unknown>,
packages/stack-shared/src/interface/server-interface.ts (1)

832-837: Define proper interface for API response structure.

Using any type for result mapping loses type safety. Consider defining a proper interface for the API response structure instead of casting to any.

-    const results = data.results.map((result: any) => ({
+    interface ApiEmailResult {
+      user_id: string;
+      user_email?: string;
+      success: boolean;
+      error?: string;
+    }
+    const results = data.results.map((result: ApiEmailResult) => ({
packages/stack-shared/src/helpers/emails.ts (1)

101-101: Remove trailing space.

Extra trailing space after ThemeProps.

-} satisfies Partial<ThemeProps>  
+} satisfies Partial<ThemeProps>
apps/backend/src/lib/email-rendering.tsx (1)

101-101: Clarify JSX interpolation syntax.

The nested template literal and JSX expression syntax is unclear and hard to read. Consider refactoring for better clarity.

-          {${previewMode ? "EmailTheme.PreviewProps?.children ?? " : ""} EmailTemplateWithProps}
+          {previewMode ? (EmailTheme.PreviewProps?.children ?? EmailTemplateWithProps) : EmailTemplateWithProps}
🧹 Nitpick comments (3)
apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx (1)

348-348: LGTM! Property name updated to match new API.

The change from content to html correctly aligns with the updated backend email sending API that now supports HTML content and template-based emails.

Consider updating the form field name from content to html for consistency:

-const handleSend = async (formData: { subject?: string, content?: string, notificationCategoryName?: string }) => {
+const handleSend = async (formData: { subject?: string, html?: string, notificationCategoryName?: string }) => {
  if (!formData.subject || !formData.content || !formData.notificationCategoryName) {

And update the corresponding form field name in the render function (line 505).

apps/backend/src/app/api/latest/emails/send-email/route.tsx (2)

100-122: Consider optimizing the double-rendering pattern.

The current implementation renders template-based emails twice - once to extract the notification category and again for the final email. This could impact performance when sending bulk emails.

Consider refactoring to render once and extract all necessary data, or implement a lighter-weight method to determine the notification category from templates without full rendering.


166-172: Consider preserving error details for debugging.

The subject fallback logic is good. However, the catch block discards valuable error information that could help with debugging email delivery issues.

Consider logging the actual error or including more specific error messages:

-      } catch {
+      } catch (error) {
+        console.error(`Failed to send email to user ${userId}:`, error);
         userSendErrors.set(userId, "Failed to send email");
       }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7a0a26d and bf29943.

📒 Files selected for processing (14)
  • apps/backend/src/app/api/latest/emails/render-email/route.tsx (1 hunks)
  • apps/backend/src/app/api/latest/emails/send-email/route.tsx (6 hunks)
  • apps/backend/src/lib/email-rendering.tsx (3 hunks)
  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/email-templates/page-client.tsx (1 hunks)
  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx (1 hunks)
  • apps/dashboard/src/components/vibe-coding/code-editor.tsx (1 hunks)
  • packages/stack-shared/src/helpers/emails.ts (4 hunks)
  • packages/stack-shared/src/interface/admin-interface.ts (0 hunks)
  • packages/stack-shared/src/interface/server-interface.ts (1 hunks)
  • packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts (0 hunks)
  • packages/template/src/lib/stack-app/apps/implementations/server-app-impl.ts (2 hunks)
  • packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts (0 hunks)
  • packages/template/src/lib/stack-app/apps/interfaces/server-app.ts (2 hunks)
  • packages/template/src/lib/stack-app/email/index.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • packages/template/src/lib/stack-app/apps/interfaces/admin-app.ts
  • packages/stack-shared/src/interface/admin-interface.ts
  • packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: TypeScript with strict types, prefer type over interface
Avoid casting to any; Prefer making changes to the API so that any casts are unnecessary to access a property or method

Files:

  • apps/backend/src/app/api/latest/emails/render-email/route.tsx
  • apps/dashboard/src/components/vibe-coding/code-editor.tsx
  • packages/template/src/lib/stack-app/email/index.ts
  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/email-templates/page-client.tsx
  • packages/template/src/lib/stack-app/apps/interfaces/server-app.ts
  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx
  • packages/template/src/lib/stack-app/apps/implementations/server-app-impl.ts
  • packages/stack-shared/src/interface/server-interface.ts
  • apps/backend/src/lib/email-rendering.tsx
  • packages/stack-shared/src/helpers/emails.ts
  • apps/backend/src/app/api/latest/emails/send-email/route.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{js,jsx,ts,tsx}: 2-space indentation, spaces in braces, semicolons required
Return promises with return await, no floating promises
Proper error handling for async code with try/catch
Use helper functions: yupXyz() for validation, getPublicEnvVar() for env
Switch cases must use blocks

Files:

  • apps/backend/src/app/api/latest/emails/render-email/route.tsx
  • apps/dashboard/src/components/vibe-coding/code-editor.tsx
  • packages/template/src/lib/stack-app/email/index.ts
  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/email-templates/page-client.tsx
  • packages/template/src/lib/stack-app/apps/interfaces/server-app.ts
  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx
  • packages/template/src/lib/stack-app/apps/implementations/server-app-impl.ts
  • packages/stack-shared/src/interface/server-interface.ts
  • apps/backend/src/lib/email-rendering.tsx
  • packages/stack-shared/src/helpers/emails.ts
  • apps/backend/src/app/api/latest/emails/send-email/route.tsx
**/*.{jsx,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{jsx,tsx}: React Server Components preferred where applicable
No direct 'use' imports from React (use React.use instead)

Files:

  • apps/backend/src/app/api/latest/emails/render-email/route.tsx
  • apps/dashboard/src/components/vibe-coding/code-editor.tsx
  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/email-templates/page-client.tsx
  • apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/emails/page-client.tsx
  • apps/backend/src/lib/email-rendering.tsx
  • apps/backend/src/app/api/latest/emails/send-email/route.tsx
🧠 Learnings (8)
apps/backend/src/app/api/latest/emails/render-email/route.tsx (4)

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{ts,tsx} : Avoid casting to any; Prefer making changes to the API so that any casts are unnecessary to access a property or method

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to apps/e2e/**/*.test.{ts,tsx} : Import test utilities from /apps/e2e/test/helpers.ts

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{jsx,tsx} : No direct 'use' imports from React (use React.use instead)

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Proper error handling for async code with try/catch

apps/dashboard/src/components/vibe-coding/code-editor.tsx (3)

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{ts,tsx} : Avoid casting to any; Prefer making changes to the API so that any casts are unnecessary to access a property or method

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{ts,tsx} : TypeScript with strict types, prefer type over interface

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{jsx,tsx} : No direct 'use' imports from React (use React.use instead)

packages/template/src/lib/stack-app/email/index.ts (2)

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{ts,tsx} : Avoid casting to any; Prefer making changes to the API so that any casts are unnecessary to access a property or method

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{ts,tsx} : TypeScript with strict types, prefer type over interface

packages/template/src/lib/stack-app/apps/implementations/server-app-impl.ts (1)

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{jsx,tsx} : React Server Components preferred where applicable

packages/stack-shared/src/interface/server-interface.ts (2)

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{ts,tsx} : Avoid casting to any; Prefer making changes to the API so that any casts are unnecessary to access a property or method

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{ts,tsx} : TypeScript with strict types, prefer type over interface

apps/backend/src/lib/email-rendering.tsx (3)

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{jsx,tsx} : React Server Components preferred where applicable

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{jsx,tsx} : No direct 'use' imports from React (use React.use instead)

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use helper functions: yupXyz() for validation, getPublicEnvVar() for env

packages/stack-shared/src/helpers/emails.ts (3)

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : 2-space indentation, spaces in braces, semicolons required

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{jsx,tsx} : No direct 'use' imports from React (use React.use instead)

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{jsx,tsx} : React Server Components preferred where applicable

apps/backend/src/app/api/latest/emails/send-email/route.tsx (1)

Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use helper functions: yupXyz() for validation, getPublicEnvVar() for env

🧬 Code Graph Analysis (3)
packages/template/src/lib/stack-app/apps/implementations/server-app-impl.ts (2)
packages/template/src/lib/stack-app/email/index.ts (2)
  • SendEmailOptions (10-18)
  • SendEmailResult (20-25)
packages/stack-shared/src/known-errors.tsx (2)
  • KnownErrors (1418-1420)
  • KnownErrors (1422-1532)
packages/stack-shared/src/interface/server-interface.ts (1)
packages/stack-shared/src/known-errors.tsx (2)
  • KnownErrors (1418-1420)
  • KnownErrors (1422-1532)
apps/backend/src/lib/email-rendering.tsx (2)
packages/stack-shared/src/utils/html.tsx (1)
  • html (30-32)
packages/stack-shared/src/utils/strings.tsx (1)
  • deindent (235-238)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: all-good
  • GitHub Check: docker
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: setup-tests
  • GitHub Check: restart-dev-and-test
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: Security Check
🔇 Additional comments (18)
apps/backend/src/app/api/latest/emails/render-email/route.tsx (1)

5-5: LGTM! Clean removal of unused imports.

The unused StackAssertionError and captureError imports were properly removed, leaving only the actively used StatusError import.

apps/dashboard/src/components/vibe-coding/code-editor.tsx (1)

93-96: LGTM! Well-structured type definition for email themes.

The ThemeProps type properly defines the interface for email theme components, with required children and optional unsubscribeLink properties. This supports the enhanced email theming system with unsubscribe functionality.

packages/template/src/lib/stack-app/apps/implementations/server-app-impl.ts (2)

31-31: Proper import for email functionality.

The import statement correctly brings in the required types for the new email sending capability.


945-947: Well-implemented email sending method.

The sendEmail method follows established patterns in the codebase:

  • Proper async/await with Result type for error handling
  • Clean delegation to the interface layer
  • Type-safe with SendEmailOptions and SendEmailResult[]
  • Includes appropriate error types (RequiresCustomEmailServer, SchemaError)

This implementation supports the enhanced email system with template and theme capabilities while maintaining consistency with the existing server app architecture.

packages/template/src/lib/stack-app/apps/interfaces/server-app.ts (1)

1-1: LGTM! Well-structured interface additions.

The new imports and sendEmail method are properly typed with explicit error handling using the Result pattern. The method signature clearly defines the expected input/output types and specific error cases.

Also applies to: 7-8, 52-52

packages/template/src/lib/stack-app/email/index.ts (1)

20-25: LGTM! Well-structured result type.

The SendEmailResult type appropriately captures the result of email sending operations with proper optional fields and clear property types.

packages/stack-shared/src/helpers/emails.ts (2)

4-4: LGTM! Proper unsubscribe link implementation.

The changes correctly add unsubscribe link support to the light email theme with proper conditional rendering and preview props for development.

Also applies to: 45-46, 48-48, 57-62, 69-71


75-76: LGTM! Consistent dark theme implementation.

The dark theme changes properly mirror the light theme implementation with correct unsubscribe link support.

Also applies to: 78-78, 87-92, 99-100

apps/backend/src/lib/email-rendering.tsx (3)

34-43: LGTM! Good separation of concerns.

Simplifying createTemplateComponentFromHtml by removing the unsubscribeLink parameter and moving that responsibility to the theme component level is a clean refactor.


52-52: LGTM! Proper parameter addition.

Adding unsubscribeLink to the options parameter correctly supports the new theme-based unsubscribe link handling.


98-100: LGTM! Correct prop-based implementation.

The logic correctly passes unsubscribeLink as a prop to EmailTheme and handles both preview and normal modes appropriately.

Also applies to: 102-102

apps/backend/src/app/api/latest/emails/send-email/route.tsx (7)

1-1: LGTM! Import changes align with new template functionality.

The new imports properly support the template-based email sending feature.

Also applies to: 6-6, 9-9, 11-11


22-23: Clear and accurate API documentation.

The updated description properly documents both HTML and template-based email options.


32-37: Well-structured schema for dual email modes.

The schema properly supports both HTML and template-based emails with appropriate optional fields.


58-58: Improved error handling with standardized error types.

Good use of KnownErrors for consistent error responses. The validation for either html or template_id is properly placed.

Regarding the past review comment about line 64: The use of throwErr here is appropriate since this is for the default notification category (not per-user), and a missing category represents a configuration error that should fail fast.

Also applies to: 60-62, 64-64


63-69: Clean template and theme resolution logic.

The code properly handles both template-based and HTML-based emails with appropriate error handling for missing templates.


124-145: Proper notification preferences and unsubscribe handling.

The code correctly checks user notification preferences and generates unsubscribe links only when the category allows disabling.


147-160: Well-structured email rendering with proper context.

The email rendering includes all necessary data and handles rendering errors appropriately.

@BilalG1 BilalG1 assigned N2D4 and unassigned BilalG1 Jul 30, 2025
Copy link
Contributor

@N2D4 N2D4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add some E2E tests for the new behavior (both JS library and the API)? otherwise looks great

@N2D4 N2D4 assigned BilalG1 and unassigned N2D4 Aug 1, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/e2e/tests/js/email.test.ts (1)

202-202: Remove trailing empty line.

There appears to be an extra line at the end of the file that should be cleaned up for better code formatting.

-
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf29943 and 8ba69bd.

📒 Files selected for processing (10)
  • apps/backend/src/app/api/latest/emails/render-email/route.tsx (1 hunks)
  • apps/backend/src/app/api/latest/emails/send-email/route.tsx (6 hunks)
  • apps/backend/src/lib/email-rendering.tsx (3 hunks)
  • apps/e2e/tests/js/email.test.ts (1 hunks)
  • packages/stack-shared/src/interface/admin-interface.ts (0 hunks)
  • packages/stack-shared/src/interface/server-interface.ts (1 hunks)
  • packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts (0 hunks)
  • packages/template/src/lib/stack-app/apps/implementations/server-app-impl.ts (2 hunks)
  • packages/template/src/lib/stack-app/apps/interfaces/server-app.ts (2 hunks)
  • packages/template/src/lib/stack-app/email/index.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • packages/stack-shared/src/interface/admin-interface.ts
  • packages/template/src/lib/stack-app/apps/implementations/admin-app-impl.ts
✅ Files skipped from review due to trivial changes (1)
  • apps/backend/src/app/api/latest/emails/render-email/route.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/template/src/lib/stack-app/email/index.ts
  • packages/template/src/lib/stack-app/apps/interfaces/server-app.ts
  • packages/stack-shared/src/interface/server-interface.ts
  • apps/backend/src/app/api/latest/emails/send-email/route.tsx
  • apps/backend/src/lib/email-rendering.tsx
  • packages/template/src/lib/stack-app/apps/implementations/server-app-impl.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{ts,tsx}: TypeScript with strict types, prefer type over interface
Avoid casting to any; Prefer making changes to the API so that any casts are unnecessary to access a property or method

Files:

  • apps/e2e/tests/js/email.test.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.{js,jsx,ts,tsx}: 2-space indentation, spaces in braces, semicolons required
Return promises with return await, no floating promises
Proper error handling for async code with try/catch
Use helper functions: yupXyz() for validation, getPublicEnvVar() for env
Switch cases must use blocks

Files:

  • apps/e2e/tests/js/email.test.ts
apps/e2e/**/*.test.{ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Import test utilities from /apps/e2e/test/helpers.ts

Files:

  • apps/e2e/tests/js/email.test.ts
**/*.test.{js,jsx,ts,tsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Prefer inline snapshot testing with expect(response).toMatchInlineSnapshot(...)

Files:

  • apps/e2e/tests/js/email.test.ts
🧠 Learnings (1)
📚 Learning: applies to apps/e2e/**/*.test.{ts,tsx} : import test utilities from `/apps/e2e/test/helpers.ts`...
Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T23:25:51.701Z
Learning: Applies to apps/e2e/**/*.test.{ts,tsx} : Import test utilities from `/apps/e2e/test/helpers.ts`

Applied to files:

  • apps/e2e/tests/js/email.test.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: docker
  • GitHub Check: docker
  • GitHub Check: restart-dev-and-test
  • GitHub Check: all-good
  • GitHub Check: setup-tests
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: Security Check
🔇 Additional comments (9)
apps/e2e/tests/js/email.test.ts (9)

23-39: LGTM! Well-structured test for HTML email sending.

The test properly sets up the environment, creates a user with verified email, sends an email with HTML content, and verifies the successful result. Good use of async/await and clear test structure.


41-57: LGTM! Good test coverage for template-based emails.

The test effectively verifies the template-based email functionality using predefined template IDs. Follows the same solid test structure as the HTML test.


59-80: LGTM! Comprehensive test for bulk email functionality.

The test properly validates sending emails to multiple users by creating two users and including both in the userIds array. Good coverage of the bulk email sending feature.


82-99: LGTM! Good test for email theme customization.

The test effectively validates the theme functionality by using the DEFAULT_EMAIL_THEME_ID. Maintains consistent test structure and focuses on a specific feature.


101-118: LGTM! Good test for notification category functionality.

The test properly validates the notification category feature by including the notificationCategoryName parameter. Consistent with other test structures and focuses on a specific feature.


120-138: LGTM! Excellent error handling test for missing email server configuration.

The test properly validates the RequiresCustomEmailServer error case by skipping the email server setup. Good use of type narrowing to check the specific error instance.


141-157: LGTM! Thorough error handling test for non-existent users.

The test effectively validates the UserIdDoesNotExist error case using a properly formatted UUID. Good use of inline snapshot testing as recommended in the coding guidelines, and proper type narrowing for error handling.


159-178: LGTM! Good schema validation error test.

The test properly validates the SchemaError case when required email content is missing. The use of as any is acceptable here since it's intentionally testing invalid input that would be caught at compile time. Good use of inline snapshot testing and proper error type checking.


180-201: LGTM! Good test for mutually exclusive parameters validation.

The test effectively validates the SchemaError case when both html and templateId are provided simultaneously, which should be mutually exclusive. Proper error type checking and inline snapshot testing usage.

<!--

Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md

-->

<!-- ELLIPSIS_HIDDEN -->


----

> [!IMPORTANT]
> Enhance email functionality by updating mock server setup, email
templates, and tests, and switching Freestyle mock to Bun.
> 
>   - **Behavior**:
> - Removed mock API key handling in `renderEmailWithTemplate()` in
`email-rendering.tsx`.
> - Updated `Freestyle` class in `freestyle.tsx` to set `baseUrl` for
mock environments.
> - Changed port for Freestyle mock from 8119 to 8122 in
`docker.compose.yaml` and `index.html`.
>   - **Docker**:
>     - Updated `freestyle-mock/Dockerfile` to use Bun instead of Deno.
> - Updated `docker.compose.yaml` to reflect new Freestyle mock setup.
>   - **Tests**:
> - Updated email-related tests in `send-email.test.ts`,
`render-email.test.ts`, and others to reflect changes in email handling.
> - Added tests for handling invalid user IDs and missing email content.
>   - **Misc**:
>     - Updated `esbuild.tsx` to use a new URL for `esbuild.wasm`.
>     - Minor updates to `server-app-impl.ts` for email sending logic.
> 
> <sup>This description was created by </sup>[<img alt="Ellipsis"
src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=stack-auth%2Fstack-auth&utm_source=github&utm_medium=referral)<sup>
for 4137933. You can
[customize](https://app.ellipsis.dev/stack-auth/settings/summaries) this
summary. It will automatically update as commits are pushed.</sup>


<!-- ELLIPSIS_HIDDEN -->

---------

Co-authored-by: Konsti Wohlwend <n2d4xc@gmail.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (2)
apps/e2e/tests/backend/endpoints/api/v1/send-email.test.ts (2)

52-87: Test name doesn't match the test behavior

The test is named "should return 200 with user not found error in results" but it actually creates a valid user and successfully sends an email. The response shows a successful email delivery, not a user not found error.

Consider renaming this test to reflect what it actually tests, such as "should return 200 and successfully send email to user with Marketing category".


162-219: Test name doesn't reflect actual behavior

The test is named "should return 200 with disabled notifications error in results" but the response shows a successful result without any error indication. If the system is supposed to skip sending emails to users who have disabled notifications, the response structure should indicate this somehow (e.g., with an error field or status).

Either:

  1. The test name should be updated to reflect that emails are sent regardless of notification preferences
  2. Or the implementation should be updated to properly handle disabled notifications
🧹 Nitpick comments (5)
docker/dependencies/docker.compose.yaml (1)

163-163: Update the comment to reflect the new port mapping.

The port mapping was changed from 8119 to 8122, but the comment still references the old port.

-      - "8122:8080"       # POST http://localhost:8119/execute/v1/script
+      - "8122:8080"       # POST http://localhost:8122/execute/v1/script
apps/e2e/tests/backend/endpoints/api/v1/send-email.test.ts (1)

221-255: Consider adding explicit error indication in response

The test name mentions "no primary email error" but the response only shows user_id without an explicit error field. For better API clarity, consider adding an error field to indicate why the email wasn't sent (e.g., "error": "no_primary_email").

apps/e2e/tests/backend/endpoints/api/v1/internal/email-templates.test.ts (3)

18-28: LGTM! Realistic TSX source improves test quality.

The replacement of the placeholder with a full TSX source string significantly improves the test by using a realistic email template component structure with proper imports and React patterns.

Consider enhancing the variablesSchema function for more comprehensive testing:

-        export const variablesSchema = (v) => v;
+        export const variablesSchema = (v) => ({
+          ...v,
+          // Add test-specific variable validations if needed
+        });

69-79: Consider extracting the duplicated TSX source to reduce maintenance burden.

The TSX source is identical between both test cases, which creates duplication that could lead to maintenance issues if the template structure needs to change.

Extract the TSX source to a constant:

+const MOCK_TSX_SOURCE = `
+  import { Subject, NotificationCategory } from '@stackframe/emails';
+  export const variablesSchema = (v) => v;
+  export function EmailTemplate() {
+    return <>
+      <Subject value="Test Subject" />
+      <NotificationCategory value="Transactional" />
+      <div>Mock email template</div>
+    </>;
+  }
+`;

 it("should not allow updating email templates when using shared email config", async ({ expect }) => {
   // ... existing code ...
   body: {
-    tsx_source: `
-      import { Subject, NotificationCategory } from '@stackframe/emails';
-      export const variablesSchema = (v) => v;
-      export function EmailTemplate() {
-        return <>
-          <Subject value="Test Subject" />
-          <NotificationCategory value="Transactional" />
-          <div>Mock email template</div>
-        </>;
-      }
-    `,
+    tsx_source: MOCK_TSX_SOURCE,
   },
 });

 // Apply similar change to the second test case

86-86: Snapshot updated correctly but consider brittleness.

The rendered HTML snapshot correctly reflects the new template structure and includes the unsubscribe link as expected from the email rendering changes.

The inline snapshot is quite lengthy and may be brittle to minor HTML formatting changes. Consider using a separate snapshot file or extracting key assertions:

-expect(updateResponse).toMatchInlineSnapshot(`...very long HTML...`);
+expect(updateResponse.status).toBe(200);
+expect(updateResponse.body.rendered_html).toContain('Mock email template');
+expect(updateResponse.body.rendered_html).toContain('unsubscribe');
+expect(updateResponse.body.rendered_html).toContain('DOCTYPE html');
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ba69bd and 5fd9ab2.

📒 Files selected for processing (24)
  • apps/backend/src/app/api/latest/emails/send-email/route.tsx (6 hunks)
  • apps/backend/src/lib/email-rendering.tsx (4 hunks)
  • apps/backend/src/lib/freestyle.tsx (1 hunks)
  • apps/dev-launchpad/public/index.html (1 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/auth/otp/send-sign-in-code.test.ts (2 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/auth/otp/sign-in.test.ts (2 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/auth/password/reset.test.ts (1 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/auth/password/send-reset-code.test.ts (1 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/auth/password/sign-up.test.ts (1 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/contact-channels/legacy-send-verification-code.test.ts (1 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/contact-channels/send-verification-code.test.ts (1 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/contact-channels/verify.test.ts (1 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/email-themes.test.ts (2 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/internal/email-templates.test.ts (2 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/internal/email.test.ts (3 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/render-email.test.ts (5 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/send-email.test.ts (9 hunks)
  • apps/e2e/tests/backend/endpoints/api/v1/unsubscribe-link.test.ts (1 hunks)
  • apps/e2e/tests/js/email.test.ts (1 hunks)
  • docker/dependencies/docker.compose.yaml (1 hunks)
  • docker/dependencies/freestyle-mock/Dockerfile (1 hunks)
  • packages/stack-shared/src/helpers/emails.ts (4 hunks)
  • packages/stack-shared/src/utils/esbuild.tsx (1 hunks)
  • packages/template/src/lib/stack-app/apps/implementations/server-app-impl.ts (2 hunks)
✅ Files skipped from review due to trivial changes (8)
  • apps/dev-launchpad/public/index.html
  • apps/e2e/tests/backend/endpoints/api/v1/auth/password/sign-up.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/contact-channels/legacy-send-verification-code.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/auth/password/send-reset-code.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/contact-channels/verify.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/contact-channels/send-verification-code.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/internal/email.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/auth/otp/sign-in.test.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/template/src/lib/stack-app/apps/implementations/server-app-impl.ts
  • apps/e2e/tests/js/email.test.ts
  • apps/backend/src/app/api/latest/emails/send-email/route.tsx
  • apps/backend/src/lib/email-rendering.tsx
  • packages/stack-shared/src/helpers/emails.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{test,spec}.{ts,js,tsx,jsx}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Testing is done using Vitest

Files:

  • apps/e2e/tests/backend/endpoints/api/v1/auth/password/reset.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/unsubscribe-link.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/auth/otp/send-sign-in-code.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/render-email.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/internal/email-templates.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/send-email.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/email-themes.test.ts
🧠 Learnings (2)
📚 Learning: applies to **/*.{test,spec}.{ts,js,tsx,jsx} : testing is done using vitest...
Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-02T01:22:10.098Z
Learning: Applies to **/*.{test,spec}.{ts,js,tsx,jsx} : Testing is done using Vitest

Applied to files:

  • apps/e2e/tests/backend/endpoints/api/v1/unsubscribe-link.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/render-email.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/internal/email-templates.test.ts
📚 Learning: styling is done using tailwind css...
Learnt from: CR
PR: stack-auth/stack-auth#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-02T01:22:10.098Z
Learning: Styling is done using Tailwind CSS

Applied to files:

  • apps/e2e/tests/backend/endpoints/api/v1/render-email.test.ts
  • apps/e2e/tests/backend/endpoints/api/v1/email-themes.test.ts
🧬 Code Graph Analysis (2)
packages/stack-shared/src/utils/esbuild.tsx (2)
packages/stack-shared/src/utils/telemetry.tsx (1)
  • withTraceSpan (7-11)
packages/stack-shared/src/utils/env.tsx (1)
  • isBrowserLike (4-6)
apps/backend/src/lib/freestyle.tsx (1)
packages/stack-shared/src/utils/env.tsx (1)
  • getNodeEnvironment (65-67)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: build (22.x)
  • GitHub Check: restart-dev-and-test
  • GitHub Check: docker
  • GitHub Check: docker
  • GitHub Check: all-good
  • GitHub Check: build (22.x)
  • GitHub Check: setup-tests
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: Security Check
🔇 Additional comments (22)
apps/backend/src/lib/freestyle.tsx (2)

1-2: LGTM! Clean import organization.

The import changes improve code organization by using local telemetry utilities and adding the necessary environment detection.


10-17: Excellent conditional configuration for mock environment.

The implementation correctly handles the mock freestyle service configuration by:

  • Only setting baseUrl in development/test environments
  • Properly checking for the mock API key
  • Using the updated port 8122 that aligns with the Docker compose changes
  • Keeping baseUrl undefined for production scenarios
docker/dependencies/freestyle-mock/Dockerfile (4)

1-1: LGTM! Runtime migration from Deno to Bun.

The base image change from denoland/deno:1.46.1 to oven/bun:1 aligns with the server implementation rewrite and provides better compatibility with the Node.js ecosystem.


6-19: Well-structured global dependency management.

The package.json creation and global dependency installation is properly implemented. The choice of global dependencies (arktype, react, @react-email/components) aligns well with the PR's email functionality enhancements.


30-170: Excellent Bun server implementation with comprehensive script execution.

The server implementation demonstrates several strong qualities:

  • Proper isolation: Each script execution uses a unique temp directory
  • Dependency management: Installs user-specified nodeModules via bun install
  • Log capture: Proxies console methods to collect execution logs
  • Error handling: Comprehensive try-catch with proper JSON error responses
  • Resource cleanup: Ensures temp directories are removed in finally block
  • Security: Uses crypto.randomUUID() for temp directory names

The migration from Deno's serve API to Bun's serve API is correctly implemented with the proper { port, async fetch(req) } structure.


177-177: LGTM! Updated command for Bun runtime.

The CMD properly uses bun run server.ts to execute the server with the new Bun runtime.

packages/stack-shared/src/utils/esbuild.tsx (4)

8-9: Good refactoring: centralized WASM URL configuration.

Extracting the esbuild WASM URL into a constant eliminates duplication and improves maintainability. Using esbuild.version in the template literal ensures version consistency.


18-18: LGTM: consistent usage of the centralized constant.

Both references now use the esbuildWasmUrl constant, eliminating the previous duplication and maintaining consistency.

Also applies to: 21-21


29-30: LGTM: correctly returns the initialization promise.

The function now returns the esbuildInitializePromise directly, which is consistent with the non-async function signature. This maintains the singleton initialization pattern while allowing callers more flexibility in handling the promise.


14-14: No external references to initializeEsbuild – change is transparent

I searched the entire codebase for calls to initializeEsbuild( and only found the internal invocation within packages/stack-shared/src/utils/esbuild.tsx. Switching from an async function to one that directly returns Promise<void> is transparent to callers and does not break any existing usage.

• Only usage found:
– packages/stack-shared/src/utils/esbuild.tsx: internal await initializeEsbuild()

No further action required.

apps/e2e/tests/backend/endpoints/api/v1/auth/password/reset.test.ts (2)

25-32: LGTM: Improved email message identification

The change from relying on the last message to matching by subject string is more robust and reliable. The concrete subject "Reset your password at Stack Dashboard" provides better test stability than template-based matching.


33-33: Consistent email matching logic

Good use of the same subject matching pattern for extracting the reset code URL. This maintains consistency with the assertion above.

apps/e2e/tests/backend/endpoints/api/v1/unsubscribe-link.test.ts (1)

146-146: LGTM: Updated snapshot reflects actual email rendering

The snapshot update correctly shows the fully rendered HTML email output instead of JSX-like component code. This aligns with the email rendering system changes and provides better test coverage of the actual email content sent to users.

apps/e2e/tests/backend/endpoints/api/v1/auth/otp/send-sign-in-code.test.ts (2)

11-11: LGTM: Standardized email subject format

The concrete subject string "Sign in to Stack Dashboard: Your code is " provides better test reliability than template-based matching.


103-103: LGTM: Updated OTP extraction for HTML content

The regex pattern correctly matches the 6-character OTP code within HTML paragraph tags, which aligns with the actual email rendering format.

apps/e2e/tests/backend/endpoints/api/v1/render-email.test.ts (3)

11-11: LGTM: Updated template structure with arktype integration

The template TSX source now correctly includes arktype import and variablesSchema export, which aligns with the new email template system requirements.

Also applies to: 63-63


30-30: LGTM: Consistent named export pattern for themes

Using named exports for EmailTheme functions provides better consistency and aligns with the updated email system architecture.

Also applies to: 82-82


75-112: LGTM: Comprehensive test for successful email rendering

The new test case properly validates the happy path for email rendering with both valid theme and template TSX sources. The snapshot correctly shows the fully rendered HTML output.

apps/e2e/tests/backend/endpoints/api/v1/email-themes.test.ts (4)

94-95: LGTM: Added necessary imports for unsubscribe functionality

The Link component and ThemeProps type imports are correctly added to support the new unsubscribe link feature in email themes.


97-97: LGTM: Updated function signature for unsubscribe support

The EmailTheme function now correctly accepts ThemeProps which includes the optional unsubscribeLink parameter, enabling dynamic unsubscribe link rendering.


106-112: LGTM: Proper conditional rendering of unsubscribe link

The unsubscribe footer is correctly rendered only when unsubscribeLink is provided, with appropriate styling and link text. This provides a good user experience for email recipients.


118-121: LGTM: Preview props for theme testing

The EmailTheme.PreviewProps provides a sensible default unsubscribe link for theme preview purposes, which is helpful for testing and development workflows.

@BilalG1 BilalG1 merged commit 4899632 into dev Aug 2, 2025
18 checks passed
@BilalG1 BilalG1 deleted the email-sending-and-unsubscribes branch August 2, 2025 01:40
This was referenced Aug 18, 2025
@coderabbitai coderabbitai bot mentioned this pull request Sep 2, 2025
This was referenced Sep 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants