Conversation
…er/types.ts' in import statements
…iver/types.ts' file
…new environment variable for Perplexity API key
…h tool and refining system prompt instructions
…and refine web search implementation
chore: remove unused Twilio configuration and add ZeroAgent and ZeroMCP to migrations
chore: add versioning for migrations with new_classes and new_sqlite_classes for v2
chore: remove duplicate entries for ZeroAgent and ZeroMCP in wrangler.jsonc
feat: enhance ZeroMCP with new tools and improved thread information handling
Feature/pdf print
…on-886 feat(mail/spam): add 'Delete All Spam' button (#886)
fix: phone number verification
feat: move db from packages into server
WalkthroughThis update introduces significant refactoring and feature additions across the mail and server applications. Major changes include a new bulk spam deletion feature, label color mapping, phone number verification with Twilio integration, infinite scrolling in the mail list, centralized user settings schemas, and the migration of ESLint and TypeScript configurations to shared packages. Several files and modules related to cookie consent and feature flags are removed, and new durable objects and MCP (Model Context Protocol) support are added on the server. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant MailUI
participant ServerAPI
participant MailDriver
participant Twilio
Note over User,MailUI: Bulk Spam Deletion Feature
User->>MailUI: Click "Delete All Spam"
MailUI->>ServerAPI: Call deleteAllSpam mutation
ServerAPI->>MailDriver: driver.deleteAllSpam()
MailDriver->>MailDriver: List spam threads (batch)
loop For each batch
MailDriver->>MailDriver: Move threads to trash
end
MailDriver-->>ServerAPI: Return count of deleted threads
ServerAPI-->>MailUI: Return success/failure message
MailUI-->>User: Show toast with result
Note over User,MailUI: Phone Number Verification (Twilio OTP)
User->>MailUI: Enter phone number, submit
MailUI->>ServerAPI: Update profile, request sendOtp
ServerAPI->>Twilio: Send SMS with OTP
Twilio-->>ServerAPI: SMS sent confirmation
ServerAPI-->>MailUI: Prompt for OTP input
User->>MailUI: Enter OTP, submit
MailUI->>ServerAPI: Verify OTP
ServerAPI-->>MailUI: Verification result
MailUI-->>User: Show verification status
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
zero-server-staging | 7f9a1c3 | May 26 2025, 06:53 PM |
There was a problem hiding this comment.
Actionable comments posted: 27
🔭 Outside diff range comments (1)
apps/server/src/routes/agent/utils.ts (1)
38-88: 🛠️ Refactor suggestionGood refactoring, but avoid using 'any' type.
The separation of
executeFunctionsfromtoolsimproves the function interface. However, the use ofanytype on lines 52 and 72 reduces type safety.Consider using a generic type parameter or unknown instead:
- ) => Promise<any>; + ) => Promise<unknown>;- let result: any; + let result: unknown;
♻️ Duplicate comments (1)
apps/server/src/main.ts (1)
85-98: Duplicate authorization logic (same as above)This mount point has the same authorization pattern as
/sse. The refactoring suggestion above applies here as well.
🧹 Nitpick comments (26)
apps/server/src/lib/party.ts (1)
12-15: Consider adding error handling around session retrieval
Right now,getSessionwill bubble up any errors fromthis.auth.api.getSession. You may want to wrap this call in atry/catchand handle network or auth errors gracefully (e.g. logging, returningnull, etc.).apps/mail/components/ui/sidebar.tsx (1)
263-263: Verify Tailwind scrollbar utilities and accessibility
You’ve addedscrollbar-noneandscrollbar-w-0to hide the scrollbar. Make sure the Tailwind CSS scrollbar plugin (or equivalent) is enabled so these classes are recognized, and double-check that hiding the scrollbar doesn’t impair keyboard or screen-reader navigation..devcontainer/Dockerfile (1)
31-33: Good addition of pnpm support, but consider adding PATH configuration.The pnpm installation using the official script is correct and aligns well with the existing Bun setup.
Consider adding pnpm to the PATH in both bashrc and zshrc for consistency with the Bun setup:
# Register Bun in bashrc and zshrc RUN echo 'export PATH="$HOME/.bun/bin:$PATH"' >> ~/.bashrc RUN echo 'export PATH="$HOME/.bun/bin:$PATH"' >> ~/.zshrc + +# Register pnpm in bashrc and zshrc +RUN echo 'export PNPM_HOME="$HOME/.local/share/pnpm"' >> ~/.bashrc +RUN echo 'export PATH="$PNPM_HOME:$PATH"' >> ~/.bashrc +RUN echo 'export PNPM_HOME="$HOME/.local/share/pnpm"' >> ~/.zshrc +RUN echo 'export PATH="$PNPM_HOME:$PATH"' >> ~/.zshrc.env.example (1)
32-32: Consider adding a comment for clarity.The purpose of
AUTUMN_SECRET_KEYis not immediately clear from the context.Consider adding a comment to clarify its purpose:
+# Autumn encryption/secret key (specify purpose) AUTUMN_SECRET_KEY=apps/mail/components/party.tsx (1)
14-16: Remove commented code for cleaner codebase.The commented-out refetch function destructuring suggests a successful transition to the query invalidation approach with debouncers. Since the new implementation using
queryClient.invalidateQueries()is more performant and follows React Query best practices, the old code should be removed entirely.-// const { refetch: refetchLabels } = useLabels(); -// const [{ refetch: refetchThreads }] = useThreads();Also consider removing the related commented callback functions (lines 19-25) if they're no longer needed.
README.md (2)
116-116: Fix grammar: "setup" should be "set up" when used as a verb.- - Run `pnpm nizzy env` to setup your environment variables + - Run `pnpm nizzy env` to set up your environment variables🧰 Tools
🪛 LanguageTool
[grammar] ~116-~116: The word “setup” is a noun. The verb is spelled with a white space.
Context: ...ronment** - Runpnpm nizzy envto setup your environment variables - Run `pn...(NOUN_VERB_CONFUSION)
107-107: Add language specification to the code block.- ``` + ```bash pnpm install🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
107-107: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
apps/server/src/lib/services.ts (1)
26-47: Consider input validation and alternative encoding methods.The SMS sending implementation could be enhanced with:
- Phone number validation: Add basic E.164 format validation
- Message length validation: Twilio has SMS length limits
- Alternative to btoa: Consider using TextEncoder for better compatibility
const send = async (to: string, body: string) => { + // Validate phone number format (basic E.164) + if (!/^\+[1-9]\d{1,14}$/.test(to)) { + throw new Error('Invalid phone number format. Use E.164 format (+1234567890)'); + } + + // Validate message length (160 chars for single SMS) + if (body.length > 160) { + console.warn('Message exceeds 160 characters and may be split into multiple SMS'); + } + const response = await fetch( `https://api.twilio.com/2010-04-01/Accounts/${env.TWILIO_ACCOUNT_SID}/Messages.json`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', - Authorization: `Basic ${btoa(`${env.TWILIO_ACCOUNT_SID}:${env.TWILIO_AUTH_TOKEN}`)}`, + Authorization: `Basic ${Buffer.from(`${env.TWILIO_ACCOUNT_SID}:${env.TWILIO_AUTH_TOKEN}`).toString('base64')}`, },apps/server/src/lib/utils.ts (1)
3-7: Consider renaming the function for clarity and add input validation.The function name
parseHeadersis misleading since it's creating headers rather than parsing them. Consider renaming tocreateAuthHeadersorbuildCookieHeadersfor better clarity.Additionally, consider adding basic input validation for the token parameter.
-export const parseHeaders = (token: string) => { +export const createAuthHeaders = (token: string) => { + if (!token || typeof token !== 'string') { + throw new Error('Token must be a non-empty string'); + } const headers = new Headers(); headers.set('Cookie', token); return headers; };apps/server/src/trpc/routes/mail.ts (1)
258-258: Remove extra blank line.Extra blank line should be removed for consistency.
-apps/mail/vite.config.ts (1)
33-35: Consider more specific warmup patterns.The warmup patterns
./app/**/*and./components/**/*might be too broad and could include unnecessary files like test files, stories, or other non-runtime files.Consider more specific patterns:
warmup: { - ssrFiles: ['./app/**/*', './components/**/*'], + ssrFiles: ['./app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}'], },apps/mail/components/mail/render-labels.tsx (1)
48-48: Remove commented code.The commented
borderColorline should either be implemented or removed.color: label.color?.backgroundColor, - // borderColor: label.color?.backgroundColor,apps/server/package.json (1)
24-76: Consider version pinning consistency.The package uses different versioning strategies: exact versions for some packages (e.g.,
"@ai-sdk/perplexity": "1.1.9"), ranges for others (e.g.,"eslint": "^9.27.0"), and catalog references for workspace packages.Consider establishing a consistent versioning strategy:
- Use exact versions for critical dependencies
- Use ranges for development tools
- Document the rationale in a comment or README
apps/server/src/lib/schemas.ts (1)
48-57: Consider adding validation constraints and defaultsThe schema could benefit from more specific validation rules and consistent default handling.
Consider these improvements:
export const userSettingsSchema = z.object({ - language: z.string(), - timezone: z.string(), + language: z.string().min(2).max(5).default('en'), + timezone: z.string().min(1).default('UTC'), dynamicContent: z.boolean().optional(), externalImages: z.boolean(), - customPrompt: z.string(), + customPrompt: z.string().max(1000).default(''), isOnboarded: z.boolean().optional(), trustedSenders: z.string().array().optional(), colorTheme: z.enum(['light', 'dark', 'system']).default('system'), });This adds length constraints for language codes, ensures timezone is not empty, limits custom prompt length, and adds appropriate defaults.
apps/mail/components/create/extensions.ts (1)
146-164: Consider documenting the removed extensionsWhile the removals of
CodeBlockLowlight,Youtube, andMathematicsextensions streamline the editor, consider adding a comment explaining the rationale to help future maintainers understand why these were removed.Add a comment above the defaultExtensions array:
+// Note: CodeBlockLowlight, Youtube, and Mathematics extensions were removed +// to simplify the editor and reduce bundle size for email composition use case export const defaultExtensions = [MCP.md (2)
3-3: Fix typo in heading."Capabilties" should be "Capabilities".
Apply this fix:
-## Capabilties +## Capabilities
42-42: Fix typo in connection instructions."connecto" should be "connect to".
Apply this fix:
-You can connecto ZeroMCP using two methods: +You can connect to ZeroMCP using two methods:apps/mail/components/ui/recursive-folder.tsx (1)
90-90: Consider improving type safety for childLabel.While the parent label type has been improved,
childLabelis still typed asany.Consider updating the type:
- {label.labels?.map((childLabel: any) => ( + {label.labels?.map((childLabel: Label & { originalLabel?: Label }) => (apps/mail/components/ui/ai-sidebar.tsx (1)
377-380: Consider adding validation for the backend URL.The agent configuration relies on an environment variable that might be undefined.
Add validation to ensure the backend URL is defined:
const agent = useAgent({ agent: 'ZeroAgent', - host: `${import.meta.env.VITE_PUBLIC_BACKEND_URL}`, + host: import.meta.env.VITE_PUBLIC_BACKEND_URL || (() => { + throw new Error('VITE_PUBLIC_BACKEND_URL environment variable is not defined'); + })(), });apps/mail/lib/label-colors.ts (1)
1-35: Well-structured label color palette!The color palette is comprehensive and well-organized by categories (grayscale, warm, cool, purple, pastels). The use of
as constensures type safety and prevents accidental modifications.Consider adding a comment or documentation about WCAG color contrast compliance, especially for the combinations with
#000000text on lighter backgrounds.apps/server/src/routes/agent/tools.ts (1)
530-552: Enhance error handling with more context.While the implementation correctly uses the new AI SDK, the error handling could provide more specific information about failures.
Improve error handling to include the query for debugging:
} catch (error) { console.error('Error searching the web:', error); - throw new Error('Failed to search the web'); + throw new Error(`Failed to search the web for query: "${query}". ${error instanceof Error ? error.message : 'Unknown error'}`); }apps/server/src/lib/prompts.ts (1)
188-188: Consider consolidating redundant em dash instructions.The instruction to avoid em dashes appears in both the style adaptation section (line 188) and strict guidelines (line 228). While redundancy can reinforce important rules, consider whether both mentions are necessary.
Also applies to: 228-228
apps/server/src/lib/driver/google-label-color-map.ts (2)
7-9: Track the TODO comment for custom color mappings.The TODO comment should be tracked in an issue to ensure it's addressed in the future.
Would you like me to create an issue to track the implementation of custom color mappings?
74-77: Consider adding validation for the split operation.While the current implementation handles missing parts with empty strings, consider validating that the split produces exactly 2 parts for more robust error handling.
const parts = googleKey.split('|'); +if (parts.length !== 2) { + continue; +} const backgroundColor = parts[0] || ''; const textColor = parts[1] || '';apps/server/src/routes/chat.ts (2)
71-78: Remove commented code.The commented code should be removed to maintain code cleanliness, unless it's temporarily needed for reference.
- // async onRequest(request: Request): Promise<Response> { - // const token = request.headers.get('cookie'); - // if (!token) { - // return new Response('Unauthorized', { status: 401 }); - // } - // await this.setupAuth(token); - // return this.getDataStreamResponse(() => {}); - // }
186-200: Optimize thread loading in listThreads tool.The current implementation loads full thread details for each thread in the list, which could be performance-intensive for large result sets. Consider implementing pagination or limiting the detail level.
- const content = await Promise.all( - result.threads.map(async (thread) => { - const loadedThread = await driver.get(thread.id); - return [ - { - type: 'text' as const, - text: loadedThread.latest?.subject ?? '', - }, - { - type: 'text' as const, - text: `ThreadId: ${thread.id}`, - }, - ]; - }), - ); + const content = await Promise.all( + result.threads.slice(0, Math.min(result.threads.length, 5)).map(async (thread) => { + try { + const loadedThread = await driver.get(thread.id); + return [ + { + type: 'text' as const, + text: loadedThread.latest?.subject ?? 'No subject', + }, + { + type: 'text' as const, + text: `ThreadId: ${thread.id}`, + }, + ]; + } catch (error) { + return [ + { + type: 'text' as const, + text: `Error loading thread ${thread.id}: ${error}`, + }, + ]; + } + }), + );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (107)
.devcontainer/Dockerfile(1 hunks).env.example(1 hunks).gitignore(1 hunks)MCP.md(1 hunks)README.md(1 hunks)apps/mail/app/(full-width)/contributors.tsx(1 hunks)apps/mail/app/(routes)/settings/general/page.tsx(2 hunks)apps/mail/app/(routes)/settings/labels/page.tsx(3 hunks)apps/mail/app/(routes)/settings/privacy/page.tsx(1 hunks)apps/mail/app/root.tsx(1 hunks)apps/mail/components/context/thread-context.tsx(2 hunks)apps/mail/components/cookies/cookie-dialog.tsx(0 hunks)apps/mail/components/create/extensions.ts(1 hunks)apps/mail/components/home/HomeContent.tsx(2 hunks)apps/mail/components/labels/label-dialog.tsx(1 hunks)apps/mail/components/magicui/file-tree.tsx(5 hunks)apps/mail/components/mail/mail-display.tsx(6 hunks)apps/mail/components/mail/mail-iframe.tsx(1 hunks)apps/mail/components/mail/mail-list.tsx(10 hunks)apps/mail/components/mail/render-labels.tsx(2 hunks)apps/mail/components/motion-primitives/text-effect.tsx(0 hunks)apps/mail/components/party.tsx(1 hunks)apps/mail/components/ui/ai-sidebar.tsx(2 hunks)apps/mail/components/ui/app-sidebar.tsx(4 hunks)apps/mail/components/ui/input-otp.tsx(3 hunks)apps/mail/components/ui/input.tsx(1 hunks)apps/mail/components/ui/nav-main.tsx(5 hunks)apps/mail/components/ui/recursive-folder.tsx(3 hunks)apps/mail/components/ui/sidebar-labels.tsx(1 hunks)apps/mail/components/ui/sidebar.tsx(1 hunks)apps/mail/components/ui/switch.tsx(0 hunks)apps/mail/eslint.config.mjs(0 hunks)apps/mail/eslint.config.ts(1 hunks)apps/mail/hooks/use-previous.ts(1 hunks)apps/mail/hooks/use-threads.ts(2 hunks)apps/mail/lib/auth-client.ts(2 hunks)apps/mail/lib/auth-proxy.ts(2 hunks)apps/mail/lib/cookie-utils.ts(0 hunks)apps/mail/lib/cookies.ts(0 hunks)apps/mail/lib/email-utils.client.tsx(2 hunks)apps/mail/lib/flags.ts(0 hunks)apps/mail/lib/label-colors.ts(1 hunks)apps/mail/lib/sanitize-tip-tap-html.tsx(1 hunks)apps/mail/lib/utils.ts(0 hunks)apps/mail/locales/en.json(1 hunks)apps/mail/package.json(3 hunks)apps/mail/providers/cookie-provider.tsx(0 hunks)apps/mail/tsconfig.json(1 hunks)apps/mail/types/index.ts(3 hunks)apps/mail/vite.config.ts(1 hunks)apps/server/drizzle.config.ts(1 hunks)apps/server/eslint.config.ts(1 hunks)apps/server/package.json(2 hunks)apps/server/src/ctx.ts(1 hunks)apps/server/src/db/migrations/0027_vengeful_golden_guardian.sql(1 hunks)apps/server/src/db/migrations/meta/0027_snapshot.json(1 hunks)apps/server/src/db/migrations/meta/_journal.json(1 hunks)apps/server/src/db/schema.ts(2 hunks)apps/server/src/lib/auth.ts(2 hunks)apps/server/src/lib/driver/google-label-color-map.ts(1 hunks)apps/server/src/lib/driver/google.ts(8 hunks)apps/server/src/lib/driver/microsoft.ts(2 hunks)apps/server/src/lib/driver/types.ts(4 hunks)apps/server/src/lib/driver/utils.ts(1 hunks)apps/server/src/lib/notes-manager.ts(1 hunks)apps/server/src/lib/party.ts(1 hunks)apps/server/src/lib/prompts.ts(1 hunks)apps/server/src/lib/schemas.ts(1 hunks)apps/server/src/lib/server-utils.ts(1 hunks)apps/server/src/lib/services.ts(1 hunks)apps/server/src/lib/utils.ts(1 hunks)apps/server/src/main.ts(3 hunks)apps/server/src/overrides.d.ts(1 hunks)apps/server/src/routes/agent/tools.ts(2 hunks)apps/server/src/routes/agent/utils.ts(4 hunks)apps/server/src/routes/chat.ts(1 hunks)apps/server/src/services/writing-style-service.ts(1 hunks)apps/server/src/trpc/routes/ai/compose.ts(2 hunks)apps/server/src/trpc/routes/connections.ts(1 hunks)apps/server/src/trpc/routes/mail.ts(3 hunks)apps/server/src/trpc/routes/settings.ts(1 hunks)apps/server/src/trpc/routes/shortcut.ts(1 hunks)apps/server/src/trpc/trpc.ts(1 hunks)apps/server/src/types.ts(1 hunks)apps/server/tsconfig.json(1 hunks)apps/server/wrangler.jsonc(6 hunks)package.json(1 hunks)packages/cli/package.json(1 hunks)packages/cli/tsconfig.json(1 hunks)packages/db/.npmrc(0 hunks)packages/db/drizzle.config.ts(0 hunks)packages/db/package.json(0 hunks)packages/db/src/user_settings_default.ts(0 hunks)packages/db/tsconfig.json(0 hunks)packages/eslint-config/config.ts(1 hunks)packages/eslint-config/eslint.config.mjs(0 hunks)packages/eslint-config/index.js(0 hunks)packages/eslint-config/package.json(1 hunks)packages/eslint-config/tsconfig.json(1 hunks)packages/tailwind-config/tsconfig.json(1 hunks)packages/tsconfig/base.json(1 hunks)packages/tsconfig/nextjs.json(0 hunks)packages/tsconfig/package.json(1 hunks)packages/tsconfig/react-library.json(0 hunks)pnpm-workspace.yaml(1 hunks)scripts/seed-style/seeder.ts(1 hunks)tsconfig.json(1 hunks)
⛔ Files not processed due to max files limit (1)
- turbo.json
💤 Files with no reviewable changes (18)
- apps/mail/components/ui/switch.tsx
- packages/tsconfig/react-library.json
- packages/db/.npmrc
- apps/mail/components/motion-primitives/text-effect.tsx
- packages/db/tsconfig.json
- packages/db/drizzle.config.ts
- packages/tsconfig/nextjs.json
- apps/mail/eslint.config.mjs
- packages/db/package.json
- apps/mail/lib/flags.ts
- apps/mail/lib/utils.ts
- packages/db/src/user_settings_default.ts
- apps/mail/components/cookies/cookie-dialog.tsx
- apps/mail/providers/cookie-provider.tsx
- apps/mail/lib/cookie-utils.ts
- packages/eslint-config/eslint.config.mjs
- apps/mail/lib/cookies.ts
- packages/eslint-config/index.js
🧰 Additional context used
🧬 Code Graph Analysis (14)
apps/mail/app/(routes)/settings/general/page.tsx (1)
apps/mail/components/ui/select.tsx (1)
SelectTrigger(142-142)
apps/mail/lib/auth-proxy.ts (1)
apps/server/src/db/schema.ts (1)
session(29-40)
apps/mail/types/index.ts (1)
apps/server/src/types.ts (1)
Label(3-13)
apps/server/src/lib/auth.ts (1)
apps/server/src/lib/services.ts (1)
twilio(12-54)
apps/server/src/lib/driver/types.ts (1)
apps/server/src/types.ts (1)
DeleteAllSpamResponse(140-145)
apps/mail/components/ui/input-otp.tsx (1)
apps/mail/lib/utils.ts (1)
cn(51-51)
apps/mail/components/ui/input.tsx (1)
apps/mail/lib/utils.ts (1)
cn(51-51)
apps/server/src/trpc/routes/mail.ts (2)
apps/server/src/trpc/trpc.ts (1)
activeDriverProcedure(44-78)apps/server/src/types.ts (1)
DeleteAllSpamResponse(140-145)
apps/server/src/main.ts (1)
apps/server/src/routes/chat.ts (1)
ZeroMCP(120-453)
apps/server/src/routes/agent/tools.ts (1)
apps/server/src/lib/driver/types.ts (1)
MailManager(39-93)
apps/server/src/routes/agent/utils.ts (2)
apps/server/src/routes/agent/shared.ts (1)
APPROVAL(1-4)apps/server/src/routes/agent/tools.ts (1)
tools(554-572)
apps/server/src/lib/driver/google.ts (1)
apps/server/src/lib/driver/google-label-color-map.ts (2)
mapGoogleLabelColor(49-60)mapToGoogleLabelColor(62-82)
apps/server/src/routes/chat.ts (9)
apps/server/src/lib/auth.ts (2)
SimpleAuth(271-271)createSimpleAuth(266-268)apps/server/src/lib/driver/types.ts (1)
MailManager(39-93)apps/server/src/routes/agent/tools.ts (1)
tools(554-572)apps/server/src/routes/agent/utils.ts (1)
processToolCalls(33-117)apps/server/src/lib/prompts.ts (3)
AiChatPrompt(267-586)GmailSearchAssistantSystemPrompt(233-265)getCurrentDateContext(112-112)apps/server/src/db/schema.ts (1)
connection(87-106)apps/server/src/lib/utils.ts (2)
parseHeaders(3-7)FOLDERS(9-16)apps/server/src/db/index.ts (1)
createDb(5-9)apps/server/src/lib/server-utils.ts (1)
connectionToDriver(37-50)
apps/mail/components/mail/mail-list.tsx (2)
apps/mail/hooks/use-threads.ts (1)
useThread(62-99)apps/mail/components/mail/render-labels.tsx (1)
RenderLabels(8-85)
🪛 LanguageTool
README.md
[grammar] ~116-~116: The word “setup” is a noun. The verb is spelled with a white space.
Context: ...ronment** - Run pnpm nizzy env to setup your environment variables - Run `pn...
(NOUN_VERB_CONFUSION)
🪛 markdownlint-cli2 (0.17.2)
README.md
107-107: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
🪛 Biome (1.9.4)
apps/mail/components/mail/mail-display.tsx
[error] 694-694: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 701-701: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
apps/server/src/routes/chat.ts
[error] 39-39: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
[error] 112-112: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
[error] 120-120: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
apps/mail/components/mail/mail-list.tsx
[error] 820-820: Avoid passing children using a prop
The canonical way to pass children in React is to use JSX elements
(lint/correctness/noChildrenProp)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Workers Builds: zero-staging
- GitHub Check: Workers Builds: zero-server-staging
🔇 Additional comments (130)
packages/cli/package.json (1)
9-9: LGTM! Good addition for TypeScript configuration centralization.The addition of
@zero/tsconfigas a development dependency aligns with the broader TypeScript configuration refactoring effort across the repository. Using theworkspace:*protocol ensures the local workspace version is used, which follows monorepo best practices.tsconfig.json (1)
2-2:Details
❓ Verification inconclusive
Verify TypeScript configuration resolution works without .json extension.
The removal of the
.jsonextension from the extends path aligns with the standardization effort across the repository. However, ensure that TypeScript can properly resolve the configuration without the explicit file extension in all environments and build tools.
🏁 Script executed:
#!/bin/bash # Description: Verify that TypeScript can resolve the @zero/tsconfig/base configuration without .json extension # Expected: TypeScript should successfully compile and resolve the extended configuration # Check if the tsconfig resolves correctly npx tsc --showConfig --project tsconfig.jsonLength of output: 901
🏁 Script executed:
#!/bin/bash # Install TypeScript locally to ensure the tsc command is available npm install typescript@latest --no-save # Verify that TypeScript can resolve the @zero/tsconfig/base configuration without the .json extension npx tsc --showConfig --project tsconfig.jsonLength of output: 1298
Manual Verification Required: Ensure TS Config Extends Resolves Without “.json”
The removal of the
.jsonextension from"extends": "@zero/tsconfig/base"relies on TypeScript’s built-in ability to resolve JSON config files without an explicit extension. Since installing and running
tscin the sandbox failed due to workspace protocols, please verify in your local or CI environment that:
- Running
npx tsc --showConfig --project tsconfig.jsoncompletes successfully without errors.- All downstream build tools and editors correctly pick up the extended config.
apps/mail/lib/sanitize-tip-tap-html.tsx (2)
1-1: Good switch to React's built-in server-side rendering.Switching from
@react-email/rendertoreact-dom/servereliminates an external dependency and uses React's core utilities, which is a good architectural decision.
5-13:Details
✅ Verification successful
Remove unnecessary async keyword since renderToString is synchronous.
The function is marked as
asyncbutrenderToStringis a synchronous function, unlike the previousrenderfunction which was likely asynchronous. This creates misleading function signature.-export const sanitizeTipTapHtml = async (html: string) => { +export const sanitizeTipTapHtml = (html: string) => { const clean = sanitizeHtml(html); return renderToString( <Html> <div dangerouslySetInnerHTML={{ __html: clean }} /> </Html>, ); };
🏁 Script executed:
#!/bin/bash # Description: Check for any callers of sanitizeTipTapHtml that expect it to return a Promise # Expected: Find all usages and verify they don't await this function # Search for all usages of sanitizeTipTapHtml rg -A 3 -B 1 "sanitizeTipTapHtml" --type tsx --type tsLength of output: 82
Let’s broaden the search and explicitly include both
.tsand.tsxfiles:
🏁 Script executed:
#!/bin/bash # Search for all occurrences of sanitizeTipTapHtml and check for any awaited calls rg -n "sanitizeTipTapHtml" -g "*.ts" -g "*.tsx" rg -n "await sanitizeTipTapHtml" -g "*.ts" -g "*.tsx"Length of output: 1345
To ensure there are no callsites chaining
.thenon this function, let’s search for any direct.thenusage:
🏁 Script executed:
#!/bin/bash # Check for any usages chaining sanitizeTipTapHtml with .then rg -n "sanitizeTipTapHtml(.*)\\.then" -g "*.ts" -g "*.tsx"Length of output: 59
Remove unnecessary
asyncfromsanitizeTipTapHtmlin the Mail appSince
renderToStringis synchronous and there are no callsites inapps/mailawaiting this function, you can safely drop theasynckeyword to avoid misleading consumers about its return type.• Affected file:
apps/mail/lib/sanitize-tip-tap-html.tsxSuggested diff:
-export const sanitizeTipTapHtml = async (html: string) => { +export const sanitizeTipTapHtml = (html: string) => { const clean = sanitizeHtml(html); return renderToString( <Html> <div dangerouslySetInnerHTML={{ __html: clean }} /> </Html>, ); };🧰 Tools
🪛 Biome (1.9.4)
[error] 10-10: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
apps/mail/components/home/HomeContent.tsx (2)
1543-1546: LGTM! Clean visual spacing improvements.The added horizontal padding (
pr-12andpr-14) creates better visual separation between text spans, improving readability and layout consistency.
1563-1575: LGTM! Image positioning adjustments look good.The repositioning of the snooze and star images enhances the visual layout without affecting functionality.
apps/mail/components/ui/input.tsx (2)
11-11: Good accessibility improvements with focus-visible styles.The updated focus styles using
focus-visible:ring-2andfocus-visible:ring-offset-2follow modern accessibility patterns and provide better keyboard navigation feedback.
5-6:Details
✅ Verification successful
Verify removal of error prop doesn't break existing usage.
The component has been simplified by removing the custom
InputPropsinterface anderrorprop in favor of standard React input props. This is a cleaner approach, but could be a breaking change.
🏁 Script executed:
#!/bin/bash # Description: Check for any usage of the error prop on Input components # Expected: Should find no usage of error prop, or identify components that need updating # Search for Input components with error prop rg -A 5 -B 2 '<Input[^>]*error' --type tsx --type ts # Search for Input imports to understand usage patterns rg -A 3 "import.*Input.*from" --type tsx --type tsLength of output: 163
🏁 Script executed:
#!/bin/bash # Re-run search without relying on ripgrep's tsx type # Search for Input components with an error prop in .ts and .tsx files find . -type f \( -name '*.ts' -o -name '*.tsx' \) -print0 \ | xargs -0 rg -n '<Input[^>]*error' # Search for all imports of the Input component in .ts and .tsx files find . -type f \( -name '*.ts' -o -name '*.tsx' \) -print0 \ | xargs -0 rg -n 'import .*Input.* from'Length of output: 1839
No breaking changes detected:
errorprop removal is safeI searched all
.ts/.tsxfiles importing and using theInputcomponent and found zero occurrences of anerrorprop on<Input>. All existing usages will continue to work without modification.
- Styling improvements (new focus-visible ring and offset) align with modern accessibility standards.
This simplification is safe to merge.
apps/server/src/ctx.ts (1)
4-4: LGTM! Consistent import path update.The change from
@zero/dbto./dbis consistent with the broader refactoring to use local modules instead of the external package. Since this is a type-only import, there's no runtime impact.apps/mail/components/mail/mail-iframe.tsx (1)
2-2: Approve import update fordefaultUserSettings.
Switching the source to@zero/server/schemascorrectly reflects the migration of user settings defaults into the server module.Please verify that the exported
defaultUserSettingsstill contains all expected properties (e.g.,externalImages,trustedSenders, etc.) so thatexistingSettingsis fully populated.apps/mail/app/(routes)/settings/privacy/page.tsx (1)
11-11: Approve updated import foruserSettingsSchema.
This aligns with the consolidated server‐side schema location and keeps the form validation consistent across the application.Confirm that the shape of
userSettingsSchemamatches the hard‐codeddefaultValues(externalImagesandtrustedSenders) to avoid any mismatches during form reset.apps/server/src/trpc/routes/shortcut.ts (1)
3-3: Approve relative import foruserHotkeys.
Replacing the absolute@zero/db/schemaimport with the local../../db/schemacorrectly follows the PR’s refactoring and does not introduce functional changes.apps/server/src/services/writing-style-service.ts (1)
3-3: Approve relative import forwritingStyleMatrix.
The update from the removed@zero/db/schemato the local../db/schemais correct and preserves existing behavior.apps/server/src/trpc/routes/connections.ts (1)
3-3: Approve updated schema imports.
Importingconnectionanduserfrom the local../../db/schemamatches the removal of@zero/dband keeps the route logic unchanged.apps/server/src/db/migrations/meta/_journal.json (1)
194-200: LGTM! Standard migration metadata entry.The new migration entry follows the correct format and structure consistent with existing entries. The migration appears to be for phone number verification features as indicated in the summary.
apps/server/src/lib/server-utils.ts (1)
2-2: LGTM! Consistent import path refactoring.The change from absolute package import to relative path is part of the broader refactoring to remove the
@zero/dbpackage and use local schema definitions. The relative path is correct for this file location.apps/server/src/lib/notes-manager.ts (1)
2-3: LGTM! Consistent import path refactoring.The import paths have been correctly updated from absolute package imports to relative imports, consistent with the broader refactoring to remove the
@zero/dbpackage. Both the schema and type imports are properly aligned with the new local structure.apps/server/src/trpc/trpc.ts (1)
6-6: LGTM! Consistent import path refactoring.The import path update aligns with the broader refactoring to use local relative imports instead of the removed
@zero/dbpackage. The relative path is correct for this file location.apps/mail/app/(routes)/settings/general/page.tsx (2)
21-21: LGTM! Schema import migration.The import has been correctly updated from the removed
@zero/db/user_settings_defaultpackage to the new server schema module@zero/server/schemas, consistent with the broader refactoring effort.
198-198: LGTM! UI alignment improvement.Adding
justify-startto the SelectTrigger className improves the alignment of the language selector content by aligning it to the left, providing better visual consistency with the icon and text layout.apps/server/src/lib/party.ts (1)
3-3: Use centralizedparseHeadersutility
This import replaces the previous local implementation. Confirm thatapps/server/src/lib/utils.tsexportsparseHeaderswith the same header-building behavior (e.g. setting theCookieheader and any defaults) to avoid regressions.apps/server/eslint.config.ts (1)
1-3: Centralized ESLint config import
This file correctly re-exports the shared config from@zero/eslint-config. Ensure the legacyeslint.config.mjs(if still present) is removed fromapps/serverto prevent conflicting configurations.apps/mail/eslint.config.ts (1)
1-3: Centralized ESLint config re-export
This new file cleanly delegates to the shared@zero/eslint-config. Verify that the oldeslint.config.mjshas been removed fromapps/mailto avoid overlapping configurations..gitignore (1)
56-60: LGTM! Proper devcontainer artifact exclusion.The additions correctly ignore devcontainer-related files:
.pnpm-storefor pnpm cache directorytsx-0/for tsx temporary files- Well-organized with descriptive comment section
These changes align with the devcontainer setup mentioned in the broader PR changes.
apps/mail/lib/auth-client.ts (2)
10-10: Plugin instantiation updated correctly.The change to use
phoneNumberClient()in the plugins array is consistent with the import change and maintains the same function call pattern.
1-1:Details
✅ Verification successful
LGTM! Verify server-side authentication consistency.
The import change from
customSessionClienttophoneNumberClientaligns with the phone number verification feature addition.Please verify that the server-side authentication configuration has been updated to use the corresponding
phoneNumberplugin:
🏁 Script executed:
#!/bin/bash # Description: Verify server-side auth plugin consistency # Expected: Server should use phoneNumber plugin from better-auth/plugins rg -A 5 -B 5 "phoneNumber.*plugin|better-auth/plugins" apps/server/Length of output: 883
Server-side authentication plugin updated
The server now imports
phoneNumberfrombetter-auth/pluginsinapps/server/src/lib/auth.ts, matching the client-side change. No further action required.packages/tailwind-config/tsconfig.json (1)
2-2:Details
✅ Verification successful
LGTM! Verify base config exists and consistency across configs.
The removal of
.jsonextension follows modern TypeScript conventions and standardizes the extends path format.Please verify that the base config exists and all TypeScript configs were updated consistently:
🏁 Script executed:
#!/bin/bash # Description: Verify TypeScript config consistency across the monorepo # Expected: All configs should use the same extends format and base config should exist echo "=== Checking if base config exists ===" fd "base.json" packages/tsconfig/ --type f echo "=== Checking extends patterns in all tsconfig.json files ===" fd "tsconfig.json" --type f -x cat {} \; -x echo "File: {}" \; | rg -A 1 -B 1 "extends.*@zero/tsconfig"Length of output: 808
All TypeScript configs uniformly extend “@zero/tsconfig/base”
- packages/tsconfig/base.json is present and accessible
- Every tsconfig.json in the repo now uses the extension-free
"@zero/tsconfig/base"formatNo further action required—this change is consistent and ready to merge.
package.json (1)
21-23:Details
✅ Verification successful
LGTM! Modern Docker CLI syntax adoption.
The update from
docker-composetodocker composefollows current Docker best practices as the compose functionality is now integrated into the Docker CLI.The commands maintain the same functionality:
docker:db:up: Starts database container in detached modedocker:db:down: Stops and removes containersdocker:db:clean: Stops containers and removes volumesPlease verify that the team's Docker installations support the new syntax (Docker CLI v20.10+ required):
🌐 Web query:
What is the minimum Docker version required for "docker compose" command?💡 Result:
The "docker compose" command (Compose V2) requires Docker Engine version 19.03 or higher as a minimum requirement. This version was introduced when Compose V2 was first released in 2020[8].
Docker Compose V2 is now integrated directly into the Docker CLI platform, replacing the older hyphenated "docker-compose" command (Compose V1)[8]. This newer version offers several advantages including improved CLI experience, better build performance with BuildKit, and ongoing feature development[8].
For those using Docker Desktop, Compose V2 is bundled with all currently supported versions, making it the easiest way to access the "docker compose" functionality[8][10]. Docker Desktop users can check which version of Compose they have by selecting "About Docker Desktop" from the Docker menu[10].
It's worth noting that Compose V1 (the "docker-compose" command) stopped receiving updates as of July 2023 and is no longer available in new releases of Docker Desktop[8]. The main syntactic difference between the two versions is that Compose V2 uses a space instead of a hyphen, so scripts should be updated to use "docker compose" rather than "docker-compose"[8].
For Linux users who already have Docker Engine and Docker CLI installed, the Docker Compose plugin can be installed separately from the command line[10]. The standalone version of Docker Compose is still available but is only supported for backward compatibility and is not recommended for new installations[10].
Citations:
- 1: https://docs.docker.com/reference/compose-file/
- 2: https://docs.docker.com/compose/releases/release-notes/
- 3: https://community.baserow.io/t/confused-about-docker-version-requirements/1437
- 4: wardenenv/warden#165
- 5: https://mailu.io/master/compose/requirements.html
- 6: https://oneuptime.com/docs/installation/docker-compose
- 7: getsentry/self-hosted#1550
- 8: https://docs.docker.com/compose/releases/migrate/
- 9: https://forums.docker.com/t/docker-compose-vs-docker-compose/137884
- 10: https://docs.docker.com/compose/install/
Ensure Docker Engine ≥19.03 for “docker compose” Commands
The change to use the modern
docker composesyntax aligns with Docker Compose V2 (integrated into the Docker CLI) and requires Docker Engine version 19.03 or higher. The behavior and flags remain identical:
docker:db:up→docker compose -f docker-compose.db.yaml up -ddocker:db:down→docker compose -f docker-compose.db.yaml downdocker:db:clean→docker compose -f docker-compose.db.yaml down -vPlease confirm your team’s Docker installations meet the 19.03+ requirement (or are using Docker Desktop, which bundles Compose V2).
packages/eslint-config/tsconfig.json (2)
2-2: LGTM! Configuration centralization looks good.The change from
"@zero/tsconfig/base.json"to"@zero/tsconfig/base"follows Node.js module resolution conventions and aligns with the monorepo-wide TypeScript configuration centralization.
8-9:Details
✅ Verification successful
Verify the broadened include pattern and simplified exclude.
The include pattern was changed from specific files to
"**/*.ts"and exclude was simplified to only"node_modules". While this simplification is good for maintainability, ensure that:
- The glob pattern
"**/*.ts"captures all necessary TypeScript files in this package- Removing
"dist"from exclude doesn't cause issues if build artifacts contain TypeScript files
🏁 Script executed:
#!/bin/bash # Description: Verify TypeScript files in eslint-config package and check for dist directory usage # Find all TypeScript files in the eslint-config package echo "=== TypeScript files in eslint-config package ===" fd -e ts . packages/eslint-config # Check if dist directory exists and contains TypeScript files echo "=== Checking for dist directory and TypeScript files in it ===" if [ -d "packages/eslint-config/dist" ]; then echo "dist directory exists" fd -e ts . packages/eslint-config/dist else echo "dist directory does not exist" fi # Check the base config file being extended echo "=== Checking base config file ===" if [ -f "packages/tsconfig/base.json" ]; then echo "Found packages/tsconfig/base.json" cat packages/tsconfig/base.json elif [ -f "packages/tsconfig/base/index.json" ]; then echo "Found packages/tsconfig/base/index.json" cat packages/tsconfig/base/index.json else echo "Base config not found in expected locations" fiLength of output: 1221
Include/Exclude Patterns Verified
- The only
.tsfile inpackages/eslint-configisconfig.ts, which is correctly picked up by"**/*.ts".- There is no
dist/directory in this package, so omitting it fromexcludehas no effect.No changes required here.
apps/mail/lib/auth-proxy.ts (2)
18-18: Excellent improvement to error logging.Adding the full
sessionobject to the error log provides much better debugging information for authentication issues. This will help track down session-related problems more effectively.
8-8:Details
❓ Verification inconclusive
Verify that the empty plugins array is intentional.
The
pluginsarray is now empty, which aligns with the authentication strategy migration mentioned in the summary. However, ensure that the phone number authentication functionality is properly configured elsewhere in the application.
🏁 Script executed:
#!/bin/bash # Description: Verify phone number authentication configuration # Search for phone number client configuration echo "=== Searching for phoneNumberClient usage ===" rg -A 5 -B 5 "phoneNumberClient" apps/mail # Search for auth client configuration in other files echo "=== Searching for authClient configuration ===" rg -A 10 -B 5 "createAuthClient" apps/mail # Check for phone number verification components echo "=== Searching for phone verification components ===" rg -A 5 "phone.*verify|verify.*phone|CallInboxDialog" apps/mailLength of output: 5001
We’ve confirmed that the React client (
apps/mail/lib/auth-client.ts) is correctly usingphoneNumberClient(), while the server-side proxy (apps/mail/lib/auth-proxy.ts) deliberately omits all plugins—including the phone-number plugin. Verify that this is intentional, since any server-side endpoint usingauthProxywill not have phone number methods available unless the plugin is added.Please check:
- Any API routes or server handlers importing
authProxyexpect to call phone-number methods (e.g..api.phoneNumber.verify).- If so, add
phoneNumberClient()to thepluginsarray inauth-proxy.ts.- Otherwise, leave it empty to restrict the proxy to session methods only.
packages/cli/tsconfig.json (1)
2-2:Details
✅ Verification successful
Verify that the base configuration is suitable for CLI package requirements.
The complete delegation to the base configuration promotes consistency and reduces maintenance overhead. However, CLI packages sometimes have specific requirements (like different target environments or module systems).
🏁 Script executed:
#!/bin/bash # Description: Verify base configuration suitability for CLI package # Check the base configuration echo "=== Base TypeScript Configuration ===" cat packages/tsconfig/base.json 2>/dev/null || cat packages/tsconfig/base/index.json 2>/dev/null || echo "Base config not found" # Check CLI package structure for specific requirements echo "=== CLI Package Structure ===" fd -t f . packages/cli | head -20 # Look for CLI-specific build scripts or requirements echo "=== CLI Package.json ===" if [ -f "packages/cli/package.json" ]; then cat packages/cli/package.json | jq -r '.scripts, .bin, .main, .types' fi # Check for any executable files that might need specific compilation echo "=== Executable files in CLI package ===" fd -t f -x test -x {} + packages/cli | grep -E "#!/.*node" || echo "No shebang files found"Length of output: 20207
Approve centralization: base config is suitable for CLI usage
The shared
@zero/tsconfig/basealready includes all necessary settings for a Node-based CLI (ESNext target, ESNext modules with bundler resolution, JSON modules, Node types, strict checks, etc.). The CLI package has no custom build scripts, shebang files, or overrides in itspackage.json, so no configuration was lost.apps/server/src/trpc/routes/settings.ts (2)
4-4:Details
✅ Verification successful
LGTM! Import path updated to use local database schema.
The import statement correctly points to the local database schema file, maintaining consistency with the package refactoring.
Let me verify that the schema file exists and exports the required
userSettings:
🏁 Script executed:
#!/bin/bash # Description: Verify that the local schema file exists and exports userSettings # Expected: File exists and contains userSettings export # Check if the target schema file exists fd -t f "schema.ts" apps/server/src/db/ # Verify userSettings is exported from the schema file ast-grep --pattern $'export const userSettings = $_'Length of output: 799
Verified: local database schema export present
Confirmed that
apps/server/src/db/schema.tsexists and exportsuserSettingsas expected. The import statement:import { userSettings } from '../../db/schema';is correct.
1-1:Details
✅ Verification successful
LGTM! Import path refactored to use local schemas.
The import statement correctly points to the new local schemas location, aligning with the migration away from the external
@zero/dbpackage.Let me verify that the new import path resolves correctly:
🏁 Script executed:
#!/bin/bash # Description: Verify that the local schemas file exists and exports the expected items # Expected: File exists and contains the required exports # Check if the target file exists fd -t f "schemas.ts" apps/server/src/lib/ # Verify the exports are available in the schemas file ast-grep --pattern $'export { $_ } from $_' ast-grep --pattern $'export const defaultUserSettings = $_' ast-grep --pattern $'export const userSettingsSchema = $_' ast-grep --pattern $'export type UserSettings = $_'Length of output: 1660
🏁 Script executed:
#!/bin/bash # 1. List all import statements in the settings route echo "Imports in apps/server/src/trpc/routes/settings.ts:" rg '^import' -n apps/server/src/trpc/routes/settings.ts # 2. Verify that apps/server/src/db/schema.ts exists echo echo "Checking for apps/server/src/db/schema.ts:" fd -t f "schema.ts" apps/server/src/dbLength of output: 658
🏁 Script executed:
#!/bin/bash # Verify that apps/server/src/db/schema.ts exports `userSettings` rg -n "export .*userSettings" apps/server/src/db/schema.tsLength of output: 123
Import paths verified and approved
- Confirmed
apps/server/src/lib/schemas.tsexists and exportsdefaultUserSettings,userSettingsSchema, andUserSettings.- Confirmed
apps/server/src/db/schema.tsexists and exportsuserSettings.LGTM! 🎉
.env.example (2)
25-25: LGTM! Added Perplexity API key for AI integration.The environment variable addition supports the new Perplexity AI web search functionality mentioned in the AI summary.
34-36: LGTM! Added Twilio configuration for phone verification.The Twilio environment variables correctly support the new phone number verification feature with proper naming conventions.
packages/tsconfig/package.json (1)
4-6: LGTM! Added explicit exports for better module resolution.The exports field with explicit mapping to
"./base.json"follows modern Node.js package standards and supports the centralized TypeScript configuration approach.apps/server/src/db/schema.ts (3)
9-9: LGTM! Improved import organization.Moving the
uniqueimport to be grouped with other imports from the same module improves code organization and readability.
11-11: LGTM! Import path refactored to use local schemas.The import statement correctly points to the new local schemas location, maintaining consistency with the migration away from the external
@zero/dbpackage.
25-26:Details
✅ Verification successful
LGTM! Well-designed phone verification schema additions.
The new fields support phone number verification functionality with appropriate constraints:
phoneNumberwith unique constraint prevents duplicate registrationsphoneNumberVerifiedtracks verification statusLet me verify that the corresponding database migration exists:
🏁 Script executed:
#!/bin/bash # Description: Verify that database migration exists for the new phone number fields # Expected: Migration file exists with ALTER TABLE statements for phone_number fields # Find recent migration files that might contain phone number changes fd -t f -e sql . apps/server/src/db/migrations/ | head -10 # Look for migration files containing phone_number references rg -l "phone_number" apps/server/src/db/migrations/Length of output: 797
Migration Verified: SQL Migration Exists for Phone Number Fields
✔️ Found migration file
apps/server/src/db/migrations/0027_vengeful_golden_guardian.sqlcontainingphone_numberandphone_number_verifiedalterations.Everything looks good—approved!
apps/server/src/types.ts (1)
140-145: LGTM! Well-designed interface for bulk spam deletion response.The interface properly defines required and optional fields with clear semantics:
- Required
successandmessagefor essential response data- Optional
countanderrorfor additional context- Follows consistent naming conventions
apps/mail/app/root.tsx (2)
49-49: Good defensive programming with locale fallback.Ensuring a fallback to
'en'prevents potential runtime issues with undefined/null locale values. This pairs well with the corresponding default in the Layout component.
56-56: Consistent locale handling with proper fallback.The destructuring default complements the loader fallback, ensuring the Layout component always receives a valid locale value. This defensive approach prevents potential runtime issues.
apps/server/tsconfig.json (1)
2-3: LGTM! Good monorepo standardization.The migration to a shared TypeScript base configuration is excellent for maintaining consistency across the project. The inclusion of
"src/overrides.d.ts"and"drizzle.config.ts"aligns well with the other infrastructure changes in this PR.pnpm-workspace.yaml (2)
18-24: LGTM! Proper use of onlyBuiltDependencies.The
onlyBuiltDependenciesconfiguration is correctly used for packages that require native compilation (esbuild,sharp,workerd, etc.). This will help ensure consistent builds across different environments.
15-17:Details
✅ Verification successful
Verify the package versions are compatible.
The new Drizzle packages (
drizzle-orm: 0.43.1,drizzle-kit: 0.31.1) and Node types (@types/node: 22.15.21) should be verified for compatibility with your current setup.
🏁 Script executed:
#!/bin/bash # Description: Check if the specified package versions exist and are compatible # Expected: All versions should be available on npm registry echo "Checking drizzle-orm@0.43.1..." npm view drizzle-orm@0.43.1 version echo "Checking drizzle-kit@0.31.1..." npm view drizzle-kit@0.31.1 version echo "Checking @types/node@22.15.21..." npm view @types/node@22.15.21 versionLength of output: 355
Package version verification passed
All specified versions (drizzle-orm@0.43.1, drizzle-kit@0.31.1, @types/node@22.15.21) exist on the npm registry. Approving the workspace configuration updates.
apps/server/drizzle.config.ts (1)
10-10: LGTM! Appropriate table filtering.The
tablesFilter: ['mail0_*']is a good practice to scope migrations to specific tables, preventing accidental operations on unrelated database objects.apps/mail/types/index.ts (1)
109-109: LGTM! historyId addition aligns with mail driver updates.The optional
historyIdproperty inThreadProps.messagecorrectly supports the enhanced thread synchronization mentioned in the summary. The nullable type (string | null) appropriately handles cases where historyId might not be available.apps/mail/tsconfig.json (1)
2-2:Details
✅ Verification successful
Verify that the base TypeScript configuration exists and is properly maintained.
This refactoring to extend from a centralized base configuration is a good practice for reducing duplication and improving maintainability across the monorepo.
Please run the following script to verify the base configuration exists and contains the expected compiler options:
🏁 Script executed:
#!/bin/bash # Description: Verify the base TypeScript configuration exists and contains expected options # Check if the base config file exists fd "tsconfig" packages/tsconfig/ --type f # If found, display its contents to verify it contains the removed options if [ -f "packages/tsconfig/base.json" ]; then echo "=== Base TypeScript Configuration ===" cat packages/tsconfig/base.json else echo "Base configuration not found at expected location" # Search for alternative locations fd "base" --type f --extension json | head -10 fiLength of output: 771
Base TypeScript configuration verified
The shared config at packages/tsconfig/base.json exists and defines all of the removed compilerOptions (target, lib, strict, module, moduleResolution, etc.). The app-specific tsconfig retains only its own
paths,rootDirs,include/excludeand overrides. This centralization is correct—no further changes needed.apps/mail/lib/email-utils.client.tsx (2)
4-4: Verify import change aligns with usage.The import changed from
@react-email/rendertoreact-dom/server, which suggests a shift from React Email's optimized rendering to standard React SSR.
265-267:Details
❓ Verification inconclusive
Verify email rendering functionality after switching from React Email to React SSR.
This change switches from React Email's
renderfunction to React'srenderToString. While both produce HTML, they may have different optimizations and output formats specifically designed for email clients.Please run the following script to verify the email rendering still works correctly:
Consider testing email output in various email clients to ensure the switch from React Email's optimized rendering doesn't introduce compatibility issues.
🏁 Script executed:
#!/bin/bash # Description: Search for tests or usage of the template function to ensure compatibility # Search for tests related to email template rendering rg -A 10 -B 5 "template.*function|renderToString" --type ts --type tsx # Look for any existing email rendering tests fd "test" --type f | xargs rg -l "email.*template|template.*email" 2>/dev/null || echo "No email template tests found" # Check if there are any other imports of @react-email/render that might need updating rg "@react-email/render" --type ts --type tsxLength of output: 283
Verify EmailTemplate Rendering After SSR Migration
We’ve replaced React Email’s
renderwith React’srenderToStringin
apps/mail/lib/email-utils.client.tsx(around lines 265–267). No automated tests currently cover this change, so please:
- Add unit/snapshot tests for the updated
EmailTemplateoutput.- Remove any leftover
@react-email/renderimports.- Manually send sample emails (or render the HTML) in your target clients to confirm rendering hasn’t regressed.
README.md (1)
92-126: Excellent comprehensive devcontainer setup documentation.The devcontainer setup instructions are well-structured and provide clear step-by-step guidance that mirrors the standard setup approach. This will help developers get started quickly with a consistent development environment.
🧰 Tools
🪛 LanguageTool
[grammar] ~116-~116: The word “setup” is a noun. The verb is spelled with a white space.
Context: ...ronment** - Runpnpm nizzy envto setup your environment variables - Run `pn...(NOUN_VERB_CONFUSION)
🪛 markdownlint-cli2 (0.17.2)
107-107: Fenced code blocks should have a language specified
null(MD040, fenced-code-language)
apps/server/src/lib/driver/microsoft.ts (3)
308-308: Good implementation of historyId for API consistency.Using
lastModifiedDateTimeas thehistoryIdsource makes sense for tracking message changes. The nullish coalescing operator properly handles cases where this property might not be available.
623-623: Appropriate historyId handling for drafts.Setting
historyIdtonullfor drafts is appropriate since draft messages typically don't have the same history tracking as regular messages.
306-313:Details
✅ Verification successful
Verify historyId property usage across the codebase.
The addition of
historyIdto thread objects aligns with the broader effort to standardize mail provider APIs. Ensure that consuming code properly handles this new property.Also applies to: 621-626
🏁 Script executed:
#!/bin/bash # Description: Verify historyId usage and type definitions across the codebase # Check if historyId is defined in types rg -A 5 -B 5 "historyId" apps/server/src/lib/driver/types.ts # Look for usage of historyId in hooks or components rg "historyId" apps/mail/hooks/ apps/mail/components/ --type ts --type tsx # Check Google driver for similar implementation rg -A 3 -B 3 "historyId" apps/server/src/lib/driver/google.tsLength of output: 1518
HistoryId Property Usage Verified
All instances of the new
historyIdfield are consistently defined and handled:• In
apps/server/src/lib/driver/types.ts, bothlistandlistDraftsthreads includehistoryId: string | null.
• The Google driver (apps/server/src/lib/driver/google.ts) mapshistoryIdin both message and draft threads exactly as in Microsoft.
• No existing mail hooks or components referencehistoryId, so no downstream breakages are expected.No further changes are required.
packages/eslint-config/config.ts (1)
1-1:⚠️ Potential issueFix the ESLint import statement.
The import from 'eslint/config' is incorrect for modern ESLint flat config. The
defineConfigandglobalIgnoresare not exported from this path.Apply this fix:
-import { defineConfig, globalIgnores } from 'eslint/config'; +// Remove defineConfig import as it's not needed for flat config +// globalIgnores can be used directly as an arrayAnd update the export:
-export default defineConfig([ - globalIgnores([ +export default [ + { + ignores: [ '**/node_modules/**', '**/dist/**', '**/build/**', '**/.react-router/**', '**/.well-known/**', - ]), + ] + },Likely an incorrect or invalid review comment.
apps/mail/locales/en.json (1)
52-59: Well-structured localization for bulk spam deletion feature.The new localization strings comprehensively cover the bulk spam deletion feature with:
- Clear action labels and status messages
- Proper plural formatting for count display
- Confirmation dialogs for destructive actions
- Consistent error handling messages
The implementation follows existing naming conventions and provides good user experience.
apps/server/src/overrides.d.ts (1)
1-8: Proper TypeScript declarations for Cloudflare Durable Object bindings.The type declarations correctly define the environment interface for Cloudflare Workers with:
- Proper namespace structure
- Correct extension of the Fetcher type for Durable Object bindings
- Well-typed async methods for subscription management
- Clear parameter and return type definitions
This aligns with the new Durable Object functionality mentioned in the PR summary.
apps/server/src/lib/services.ts (1)
12-54: Well-implemented Twilio SMS service with good development experience.The implementation provides excellent features:
- Mock mode for development with clear logging
- Comprehensive environment variable validation
- Proper error handling with meaningful messages
- Clean API interface matching Twilio's structure
apps/mail/components/ui/input-otp.tsx (4)
1-1: Good addition of 'use client' directive.Properly marks this as a client component for Next.js, which is necessary for interactive OTP input functionality.
4-4: Appropriate icon change for OTP separator.The change from
MinustoDoticon better represents the visual separator between OTP input groups.
44-45: Enhanced styling improves user experience.The size increase from
h-9 w-9toh-10 w-10, removal of shadow, and improved ring styling for active slots provide better visual feedback and touch targets.
66-66: Consistent icon usage in separator.Using the
Doticon here maintains consistency with the import change and provides a cleaner visual separator.apps/server/src/lib/auth.ts (3)
8-8: Good refactoring to relative imports.The migration from absolute to relative import paths improves maintainability and aligns with best practices for modular code organization.
Also applies to: 10-10, 14-14, 17-17, 23-23
82-82: Proper Twilio client initialization.Creating the Twilio client instance using the service factory function follows the established pattern and supports both development and production environments.
85-98: Well-implemented phone number verification with proper error handling.The
phoneNumberplugin integration is correctly configured with:
- Proper async OTP sending via Twilio
- Comprehensive error handling with logging
- Appropriate APIError responses for client feedback
- Security-conscious message format
The implementation aligns well with the Twilio service from the relevant code snippets.
Consider adding rate limiting for OTP requests to prevent abuse:
phoneNumber({ + rateLimit: { + window: 60, // 1 minute + max: 3, // max 3 OTP requests per minute + }, sendOTP: async ({ code, phoneNumber }) => {apps/mail/hooks/use-threads.ts (3)
2-2: Appropriate imports for enhanced functionality.Adding
useQueryClientandusePrevioushook imports supports the new history tracking functionality without introducing unnecessary dependencies.Also applies to: 7-8
62-62: Good API extension for history tracking.Adding the optional
historyIdparameter maintains backward compatibility while enabling message history change detection for cache invalidation.
68-74: Excellent cache invalidation strategy.The implementation correctly:
- Uses
usePreviousto detecthistoryIdchanges- Only invalidates when there's an actual change (not on initial render)
- Targets the specific thread query for efficient cache management
- Properly handles null/undefined values
This ensures the UI stays synchronized with message history updates while avoiding unnecessary refetches.
apps/mail/vite.config.ts (1)
42-46:Details
✅ Verification successful
Verify SSR optimization dependencies exist.
The SSR optimization explicitly includes
noveland@tiptap/extension-placeholder. Ensure these dependencies are actually used in SSR context and require optimization.
🏁 Script executed:
#!/bin/bash # Description: Verify that the specified SSR optimization dependencies exist and are used # Expected: Find imports/usage of these packages in the codebase echo "Checking for 'novel' package usage:" rg -r --type ts --type tsx "import.*novel" || echo "No novel imports found" echo -e "\nChecking for '@tiptap/extension-placeholder' package usage:" rg -r --type ts --type tsx "import.*@tiptap/extension-placeholder" || echo "No @tiptap/extension-placeholder imports found" echo -e "\nChecking package.json dependencies:" if [ -f "package.json" ]; then jq -r '.dependencies | keys[] | select(test("novel|@tiptap"))' package.json || echo "Dependencies not found in package.json" fiLength of output: 889
Let’s broaden the search to catch any import or require patterns and also look in devDependencies:
🏁 Script executed:
#!/bin/bash echo "🔍 Searching for 'novel' import or require:" rg "import .* from ['\"]novel['\"]" || rg "require\(['\"]novel['\"]\)" || echo "No 'novel' usage found" echo -e "\n🔍 Searching for '@tiptap/extension-placeholder' import or require:" rg "import .* from ['\"]@tiptap/extension-placeholder['\"]" || rg "require\(['\"]@tiptap/extension-placeholder['\"]\)" || echo "No '@tiptap/extension-placeholder' usage found" echo -e "\n📦 Checking package.json for these deps in dependencies and devDependencies:" jq -r '.dependencies, .devDependencies | select(type == "object") | keys[] | select(test("novel|@tiptap/extension-placeholder"))' package.json \ || echo "No matching entries in package.json"Length of output: 2147
Let’s verify whether the
apps/mailfolder has its ownpackage.jsonand declares these dependencies:
🏁 Script executed:
#!/bin/bash echo "🔍 Searching for package.json under apps/mail:" find apps/mail -maxdepth 2 -type f -name package.json || echo "No package.json found in apps/mail" if [ -f apps/mail/package.json ]; then echo -e "\n📦 Checking apps/mail/package.json for ‘novel’ and ‘@tiptap/extension-placeholder’:" jq -r ' .dependencies, .devDependencies | select(type == "object") | keys[] | select(test("^(novel|@tiptap/extension-placeholder)$")) ' apps/mail/package.json \ || echo "No matching entries in apps/mail/package.json" fiLength of output: 615
SSR optimizeDeps verification ✅
Bothnoveland@tiptap/extension-placeholderare indeed used in the SSR code underapps/mailand declared inapps/mail/package.json, so thessr.optimizeDeps.includelist is correct.apps/server/package.json (2)
9-13: Database management scripts look good.The new drizzle-kit scripts provide comprehensive database management capabilities including migrations, schema pushing, and studio access.
18-19:Details
✅ Verification successful
Verify new exports are used by consumers.
The new exports, especially
"./schemas", will affect packages that import from this server package.
🏁 Script executed:
#!/bin/bash # Description: Check if the new exports are used by other packages # Expected: Find imports of these new exports echo "Checking for imports of server schemas:" rg -r --type ts --type tsx "from ['\"]@zero/server/schemas['\"]" || echo "No schema imports found" echo -e "\nChecking for imports of auth-providers:" rg -r --type ts --type tsx "from ['\"]@zero/server/auth-providers['\"]" || echo "No auth-providers imports found"Length of output: 518
I noticed the initial
rgcalls failed due to an unrecognizedtsxtype. Let’s broaden the search across TS/TSX/JS/JSX files:
🏁 Script executed:
#!/bin/bash # Search for any references to the new exports in all TS/TSX/JS/JSX files echo "Searching for @zero/server/schemas usage..." rg "@zero/server/schemas" -g '*.ts' -g '*.tsx' -g '*.js' -g '*.jsx' || echo "No schema imports found" echo -e "\nSearching for @zero/server/auth-providers usage..." rg "@zero/server/auth-providers" -g '*.ts' -g '*.tsx' -g '*.js' -g '*.jsx' || echo "No auth-providers imports found"Length of output: 914
Verified new exports are consumed
File:apps/server/package.jsonLines: 18–19I searched for imports of
@zero/server/schemasand@zero/server/auth-providersand confirmed they’re used in:
- apps/mail/components/mail/mail-iframe.tsx
- apps/mail/app/(routes)/settings/general/page.tsx
- apps/mail/app/(routes)/settings/privacy/page.tsx
- apps/mail/app/(auth)/login/page.tsx
- apps/mail/app/(auth)/login/login-client.tsx
No further action required.
apps/mail/components/magicui/file-tree.tsx (2)
272-272: Good addition of max-width constraint.The
max-w-[124px]class helps prevent folder labels from overflowing, improving the UI layout consistency.
291-299: Improved JSX structure for count badge.The refactored count badge rendering with explicit JSX structure is cleaner and more readable than the previous inline approach.
apps/server/wrangler.jsonc (1)
24-31: Well-structured Durable Objects configuration.The addition of
ZERO_AGENTandZERO_MCPDurable Objects is correctly implemented:
- Consistent bindings across all environments (local, staging, production)
- Proper migration versioning with
v2tag- Appropriate use of
new_sqlite_classesfor SQLite-backed Durable ObjectsThe configuration follows Cloudflare Workers best practices.
Also applies to: 43-46, 108-115, 127-130, 199-206, 218-221
apps/server/src/trpc/routes/ai/compose.ts (3)
53-79: Improved message construction clarity.The refactored message construction is much clearer and more maintainable than the previous conditional spreading approach. The explicit conversation flow with assistant acknowledgments provides better context for the AI model.
82-82: Verify model downgrade impact on email quality.The change from
gpt-4otogpt-4o-minimay impact email composition quality. Ensure this change aligns with performance requirements and acceptable quality standards.Consider testing both models to compare output quality for your email composition use case, especially for complex or professional emails.
94-95: Enhanced AI capabilities with appropriate limits.Good additions:
maxSteps: 10provides reasonable limit for tool usage- Increased
maxTokens: 2000allows for more comprehensive email generationwebSearchtool integration enables more informed email compositionAlso applies to: 100-102
apps/mail/components/context/thread-context.tsx (2)
81-92: Excellent UX improvement with toast.promise pattern.The refactoring from direct async/await to
toast.promiseprovides better user feedback:
- Automatic loading states
- Consistent error handling
- Proper cleanup in
finallycallback- Better user experience during label modifications
217-225: Consistent toast.promise implementation for favorites.The favorites handling follows the same improved pattern:
- Consistent error messaging based on current state
- Proper cleanup of bulk selection state
- Reliable data refetching after operations
This maintains consistency with the label modification pattern.
apps/server/src/main.ts (5)
3-3: LGTM on the new importsThe import of
ZeroAgentandZeroMCPfrom./routes/chatis correctly structured and aligns with the new MCP functionality being introduced.
6-6: LGTM on the middleware importThe
agentsMiddlewareimport fromhono-agentsis properly added to support the new agent functionality.
14-14: LGTM on the local DB importThe change from
@zero/dbto the local./dbmodule is consistent with the removal of the external package mentioned in the AI summary.
152-152: LGTM on the updated exportsThe addition of
ZeroAgentandZeroMCPto the exports is correct and necessary for external usage of these classes.
100-111:Details
❓ Verification inconclusive
Validate the middleware placement and error handling
The global
agentsMiddlewareis applied after the mount points, which means it won't affect the/sseand/mcproutes. This might be intentional, but consider if the cookie validation should be consistent across all agent-related endpoints.Let me verify how this middleware interacts with the existing routes:
🏁 Script executed:
#!/bin/bash # Description: Check for other agent-related routes and middleware usage patterns # Expected: Find other routes that might need consistent authentication # Search for agent-related route patterns rg -A 3 -B 3 "agent|Agent" --type ts # Look for other middleware usage patterns rg -A 5 -B 2 "middleware|Middleware" --type tsLength of output: 23753
🏁 Script executed:
#!/bin/bash # Dump the first 200 lines of main.ts to inspect route and middleware order sed -n '1,200p' apps/server/src/main.tsLength of output: 4740
Confirm cookie validation coverage for all agent endpoints
The
agentsMiddlewareis registered after the/sseand/mcpmounts, so those routes currently bypass its cookie-based check (they use theAuthorizationheader instead). Please verify whether you want to:
- Enforce the same cookie validation on
/sseand/mcp
• Move the.use('*', agentsMiddleware(...))call above the.mount('/sse')and.mount('/mcp')lines
• Or explicitly wrap those mounts withagentsMiddleware- Or keep the separation (bearer-token auth for SSE/MCP vs. cookie check for other agent routes) and add a comment to clarify the intended behavior
[src/apps/server/src/main.ts lines ~30–60]
apps/server/src/lib/schemas.ts (1)
37-46:⚠️ Potential issueFix circular reference in default settings definition
The
defaultUserSettingsobject usessatisfies UserSettingsbutUserSettingsis defined after this object, creating a forward reference issue. Additionally, some default values don't align with the schema's optional fields.Move the type definition before the default object and fix the alignment:
+export const userSettingsSchema = z.object({ + language: z.string(), + timezone: z.string(), + dynamicContent: z.boolean().optional(), + externalImages: z.boolean(), + customPrompt: z.string(), + isOnboarded: z.boolean().optional(), + trustedSenders: z.string().array().optional(), + colorTheme: z.enum(['light', 'dark', 'system']).default('system'), +}); + +export type UserSettings = z.infer<typeof userSettingsSchema>; export const defaultUserSettings = { language: 'en', timezone: 'UTC', dynamicContent: false, externalImages: true, customPrompt: '', trustedSenders: [], isOnboarded: false, colorTheme: 'system', } satisfies UserSettings; -export const userSettingsSchema = z.object({ - language: z.string(), - timezone: z.string(), - dynamicContent: z.boolean().optional(), - externalImages: z.boolean(), - customPrompt: z.string(), - isOnboarded: z.boolean().optional(), - trustedSenders: z.string().array().optional(), - colorTheme: z.enum(['light', 'dark', 'system']).default('system'), -}); - -export type UserSettings = z.infer<typeof userSettingsSchema>;Likely an incorrect or invalid review comment.
apps/server/src/lib/driver/types.ts (3)
1-3: LGTM on the updated importsThe imports correctly include the new
DeleteAllSpamResponsetype and updated schema path. The type imports are properly structured.
92-92: LGTM on the deleteAllSpam method additionThe new
deleteAllSpam()method is properly typed with theDeleteAllSpamResponseinterface. This enhances the mail management capabilities by providing bulk spam deletion functionality.
49-49:Details
✅ Verification successful
Verify historyId implementation across all mail drivers
The addition of
historyId: string | nullto thread objects is a good enhancement for tracking changes, but we should ensure all implementing drivers properly handle this field.Let me check if all mail drivers implement the historyId field correctly:
Also applies to: 60-62
🏁 Script executed:
#!/bin/bash # Description: Verify historyId implementation in mail drivers # Expected: Find implementations in google.ts and microsoft.ts that properly set historyId # Search for historyId usage in driver implementations rg -A 5 -B 2 "historyId" apps/server/src/lib/driver/ # Check list and listDrafts method implementations ast-grep --pattern $'list($$$) { $$$ }' ast-grep --pattern $'listDrafts($$$) { $$$ }'Length of output: 3499
Verified historyId handling in all mail drivers
Both Google and Microsoft drivers assign the
historyIdfield in accordance with the new type:
google.ts
- In
list: usesthread.historyId ?? null- In
listDrafts: usesdraft.threadId ?? nullmicrosoft.ts
- In
list: usesmsg.lastModifiedDateTime ?? null- In
listDrafts: deliberately setshistoryId: null(no draft history tracking)No further changes are needed.
apps/mail/components/create/extensions.ts (2)
18-18: LGTM on UploadImagesPlugin import retentionGood decision to keep the
UploadImagesPluginfrom thenovelpackage as image uploading is essential functionality for an email composer.
31-49: LGTM on the custom ExitLinkOnSpace extensionThe custom extension implementation is well-structured and addresses a common UX issue where users want to exit link editing mode by pressing space. The logic correctly inserts a space and then unsets the link mark.
packages/tsconfig/base.json (1)
4-5:Details
❓ Verification inconclusive
Verify compatibility with deployment environments and tooling.
The configuration uses modern TypeScript features that may have compatibility requirements:
ESNexttarget may not be supported in all runtime environmentsmoduleResolution: "Bundler"requires TypeScript 5.0+allowImportingTsExtensionsis a newer featurePlease ensure all deployment targets and build tools support these settings.
Run the following script to check TypeScript version compatibility:
Also applies to: 12-13, 19-20
🏁 Script executed:
#!/bin/bash # Description: Verify TypeScript version across the monorepo # Check TypeScript version in package.json files echo "Checking TypeScript versions in package.json files:" fd package.json --exec jq -r 'select(.devDependencies.typescript or .dependencies.typescript) | "\(.name): typescript@\(.devDependencies.typescript // .dependencies.typescript)"' 2>/dev/null || echo "No TypeScript dependencies found" # Check for TypeScript version in root package.json if [ -f package.json ]; then echo -e "\nRoot package.json TypeScript version:" jq -r '.devDependencies.typescript // .dependencies.typescript // "Not found"' package.json fiLength of output: 605
🏁 Script executed:
#!/bin/bash # Search for lockfiles and inspect TypeScript version entries lockfiles=(pnpm-lock.yaml package-lock.json yarn.lock) for file in "${lockfiles[@]}"; do if [ -f "$file" ]; then echo "---- $file ----" # Look for the version line or package key for typescript grep -R -n "typescript@" "$file" || echo "No TypeScript entry found in $file" echo fi doneLength of output: 7444
ESNext & Bundler Resolution Compatibility Confirmed
- Monorepo is using TypeScript 5.8.3 (from pnpm-lock.yaml), so
moduleResolution: "Bundler"(introduced in TS 5.0) is supported.allowImportingTsExtensionsremains valid andnoEmit: trueis already set.Remaining action:
• Please confirm that your deployment targets or your build pipeline will correctly handletarget: "ESNext"(either by down-level transpiling or by running on environments that natively support the latest ECMAScript features).apps/mail/components/ui/recursive-folder.tsx (1)
11-19: Great type safety improvements!The change from
anytoLabel & { originalLabel?: Label }improves type safety and makes the component's expectations clearer.apps/mail/components/ui/ai-sidebar.tsx (1)
382-451: Clean migration to agent-based chat architecture!The refactoring successfully migrates from the previous
useChathook to the new agent-based system while preserving all existing functionality including error handling, response processing, and tool calls.packages/eslint-config/package.json (2)
9-14: Clean dependency consolidation with typescript-eslintGood job consolidating to
typescript-eslintv8.32.1! This is the recommended approach as it bundles both the parser and plugin. The removal of separate@typescript-eslint/eslint-pluginand@typescript-eslint/parserpackages aligns with the latest best practices.
5-7:Details
✅ Verification successful
Good modernization with the exports field!
The migration from
"main"to"exports"is a good practice for modern Node.js packages. However, ensure that all consumers of this package can handle TypeScript files directly, as you're exportingconfig.tsinstead of a compiled JavaScript file.Run the following script to verify that all consumers are properly configured to handle TypeScript imports:
🏁 Script executed:
#!/bin/bash # Description: Check if consumers of @zero/eslint-config have TypeScript configured # Find all package.json files that depend on @zero/eslint-config fd package.json --exec grep -l "@zero/eslint-config" {} \; | while read -r file; do dir=$(dirname "$file") echo "Checking $dir for TypeScript configuration..." # Check if tsconfig.json exists if [ -f "$dir/tsconfig.json" ]; then echo "✓ TypeScript configured in $dir" else echo "⚠ No tsconfig.json found in $dir" fi # Check if the ESLint config file exists and can import TypeScript if fd -e ts -e js "eslint.config" . "$dir" --max-depth 1 | grep -q .; then echo "✓ ESLint config file found" else echo "⚠ No ESLint config file found" fi doneLength of output: 1534
All consumers support TypeScript imports—no further action needed
I’ve verified that both
apps/serverandapps/mailinclude atsconfig.jsonand have ESLint config files capable of importing TypeScript. Since all consumers of@zero/eslint-configcan handle.tsexports, keeping"./config.ts"under theexportsfield is safe.apps/mail/lib/label-colors.ts (1)
39-45: Type-safe color validation implementationThe validation function correctly checks both backgroundColor and textColor properties. Good use of Array.some() for efficient searching.
apps/mail/components/mail/mail-display.tsx (1)
965-987: Clean print button UI implementationGood placement of the print button next to the email date, with proper keyboard shortcut indicator and responsive design.
apps/mail/components/ui/nav-main.tsx (3)
194-199: Improved user feedback with toast notificationsGood improvement to the user experience with more descriptive toast messages for label creation states.
243-255: Excellent refactoring with LabelDialog component!Great job extracting the inline label creation form into a reusable
LabelDialogcomponent. This improves:
- Code maintainability
- Separation of concerns
- Reusability across the application
259-263: Clean delegation to SidebarLabels componentGood modularization by delegating label rendering to the dedicated
SidebarLabelscomponent. This makes the nav component more focused and easier to maintain.apps/mail/components/labels/label-dialog.tsx (1)
129-149: LGTM!The color selection implementation is well-structured with proper visual feedback for hover and selected states. Good use of conditional styling and form value updates.
apps/mail/package.json (1)
121-125: LGTM!The ESLint configuration changes properly support the centralization effort. The addition of
jitienables TypeScript config files for ESLint.apps/server/src/routes/agent/tools.ts (1)
554-572: LGTM!The explicit return statement improves readability for the multi-line object. All tools are properly mapped including the new
webSearchtool.apps/server/src/lib/prompts.ts (2)
155-173: LGTM!The tool usage section provides clear, actionable instructions for the webSearch tool. The rules ensure natural integration of search results without exposing the underlying mechanics to users.
208-230: LGTM!The output format and strict guidelines are comprehensive and well-structured. Excellent security considerations preventing exposure of internal metrics and tool invocations.
apps/server/src/lib/driver/google-label-color-map.ts (1)
49-60: LGTM!The color mapping function correctly validates input and handles edge cases appropriately.
apps/mail/app/(routes)/settings/labels/page.tsx (2)
52-63: LGTM!The unified submit handler correctly handles both create and update operations with appropriate user feedback.
87-102: Well-structured dialog implementation!The LabelDialog integration properly manages state, resets the editing label on close, and provides all necessary callbacks. Good separation of concerns.
apps/mail/components/ui/sidebar-labels.tsx (3)
28-36: LGTM!The memoized callback correctly handles label count retrieval with appropriate case-insensitive matching.
62-74: LGTM!The label categorization logic correctly groups labels using appropriate regex patterns.
127-127: LGTM!The bracket removal correctly strips both opening and closing brackets from label names.
apps/mail/components/ui/app-sidebar.tsx (3)
54-59: LGTM!The phone number validation correctly enforces E.164 format with a helpful error message.
66-77: Robust phone number masking implementation!The function properly handles edge cases and includes error handling to prevent crashes.
280-280: Verify if the phone verification dialog should be enabled.The conditional rendering of
CallInboxDialogis commented out. Please confirm if this is intentional for this release or if it should be enabled.Is the phone verification feature ready for production, or is this commented out for a phased rollout?
apps/server/src/lib/driver/google.ts (4)
11-11: LGTM! Good centralization of color mapping logic.Moving label color handling to dedicated mapping functions improves maintainability and consistency.
197-204: Correct implementation of historyId tracking.The addition of
historyIdto thread objects with proper null fallback enables history-based synchronization as intended.
586-637: Consistent and correct bidirectional color mapping implementation.The color mapping is properly applied:
mapGoogleLabelColorfor data coming from Google API (getUserLabels, getLabel)mapToGoogleLabelColorfor data going to Google API (createLabel, updateLabel)This ensures consistent color representation across the application.
661-703:Details
✅ Verification successful
Well-implemented bulk spam deletion with proper pagination.
The method correctly handles large volumes of spam emails. However, I notice it removes both 'SPAM' and 'INBOX' labels on line 684.
Spam emails typically shouldn't have the INBOX label. Let's verify if this is necessary:
🏁 Script executed:
#!/bin/bash # Check if there are other places where SPAM and INBOX labels coexist rg -B 3 -A 3 "SPAM.*INBOX|INBOX.*SPAM" --type ts # Look for Gmail API documentation or comments about spam label behavior rg -i "spam.*label|label.*spam" --type ts -g "*.ts" -g "*.md"Length of output: 3094
No changes needed for INBOX label removal
The removal of ‘INBOX’ alongside ‘SPAM’ is simply a harmless, defensive step to ensure threads are fully moved into Trash. Spam threads rarely retain the ‘INBOX’ label, so the removeLabels call is a no-op when it’s absent and has no unintended side effects.
apps/server/src/routes/agent/utils.ts (2)
10-14: LGTM! Appropriate relocation of the APPROVAL constant.Moving the constant to where it's primarily used improves code organization.
119-129: Correctly identifies tools requiring user confirmation.The function properly filters tools that lack automatic execution capabilities, which aligns with the confirmation workflow.
apps/mail/components/mail/mail-list.tsx (2)
87-91: Correct integration with historyId tracking.The
useThreadhook now properly accepts thehistoryIdparameter, enabling cache invalidation when thread history changes.
447-452: Improved label rendering with proper conditionals.The replacement of
MailLabelswithRenderLabelsand the conditional rendering logic improve the UI consistency.apps/server/src/routes/chat.ts (1)
455-471: LGTM! Well-structured tool implementation.The
buildGmailSearchQuerytool is well-implemented usinggenerateObjectfor structured output and proper schema validation. The integration with the AI model and prompt system is clean.apps/server/src/db/migrations/meta/0027_snapshot.json (5)
568-598: Well-designed phone verification schema.The addition of
phone_numberandphone_number_verifiedfields with proper unique constraints supports the new phone verification feature. The unique constraint on phone_number ensures data integrity.
355-357: Appropriate use of cascade delete for notes.The
onDelete: "cascade"for the note-to-user foreign key relationship is correctly configured, ensuring that user notes are automatically cleaned up when a user is deleted.
812-814: Appropriate use of cascade delete for writing style matrix.The cascade delete for writing style matrix ensures data consistency when connections are removed, which is the correct behavior for this derived data.
206-214: Well-designed unique constraint for connections.The unique constraint on
user_idand
671-677:Details
✅ Verification successful
Validate default settings JSON structure.
The default JSONB value for user settings contains a comprehensive configuration. Ensure this aligns with the application's
userSettingsSchema.
🏁 Script executed:
#!/bin/bash # Description: Check if the default settings JSON matches the application schema rg -A 10 -B 5 "userSettingsSchema|defaultUserSettings" --type tsLength of output: 21897
Default settings JSON aligns with application schema
The JSONB default in
apps/server/src/db/migrations/meta/0027_snapshot.jsonexactly matches thedefaultUserSettingsobject and satisfies theuserSettingsSchemainapps/server/src/lib/schemas.ts. No changes required.
| // import { | ||
| // command, | ||
| // string as stringType, | ||
| // number as numberType, | ||
| // flag, | ||
| // oneOf, | ||
| // option, | ||
| // boolean, | ||
| // subcommands, | ||
| // optional, | ||
| // } from 'cmd-ts'; | ||
| // import { input, select, confirm, number as numberPrompt } from '@inquirer/prompts'; | ||
| // import { updateWritingStyleMatrix } from '../services/writing-style-service'; | ||
| // import professionalEmails from './styles/professional_emails.json'; | ||
| // import persuasiveEmails from './styles/persuasive_emails.json'; | ||
| // import friendlyEmails from './styles/friendly_emails.json'; | ||
| // import conciseEmails from './styles/concise_emails.json'; | ||
| // import { writingStyleMatrix } from '@zero/db/schema'; | ||
| // import genZEmails from './styles/genz_emails.json'; | ||
| // import { keys, take } from 'remeda'; | ||
| // import { eq } from 'drizzle-orm'; | ||
| // import { db } from '@zero/db'; | ||
| // import pRetry from 'p-retry'; | ||
| // import pAll from 'p-all'; | ||
|
|
||
| // const mapping = { | ||
| // professional: professionalEmails, | ||
| // persuasive: persuasiveEmails, | ||
| // genz: genZEmails, | ||
| // concise: conciseEmails, | ||
| // friendly: friendlyEmails, | ||
| // } as const; | ||
|
|
||
| // const runSeeder = async (connectionId: string, style: keyof typeof mapping, size: number) => { | ||
| // console.warn( | ||
| // 'Seeding style matrix for connection', | ||
| // connectionId, | ||
| // 'based on', | ||
| // size, | ||
| // 'mock emails.', | ||
| // ); | ||
|
|
||
| // const testDataSet = take(mapping[style], size); | ||
|
|
||
| // await pAll( | ||
| // testDataSet.map((email, index) => async () => { | ||
| // console.warn('Seeding email', index); | ||
| // await pRetry( | ||
| // async () => { | ||
| // try { | ||
| // await updateWritingStyleMatrix(connectionId, email.body); | ||
| // } catch (error) { | ||
| // console.error(error); | ||
|
|
||
| // throw error; | ||
| // } | ||
| // }, | ||
| // { | ||
| // retries: 5, | ||
| // maxTimeout: 60_000, | ||
| // minTimeout: 1_000, | ||
| // }, | ||
| // ); | ||
| // }), | ||
| // { concurrency: 1 }, | ||
| // ); | ||
|
|
||
| // console.warn('Seeded style matrix for connection', connectionId); | ||
| // }; | ||
|
|
||
| // const runResetStyleMatrix = async (connectionId: string) => { | ||
| // await db.delete(writingStyleMatrix).where(eq(writingStyleMatrix.connectionId, connectionId)); | ||
| // }; | ||
|
|
||
| // const seed = command({ | ||
| // name: 'seed-style-matrix', | ||
| // args: { | ||
| // connectionId: option({ | ||
| // type: optional(stringType), | ||
| // long: 'connection-id', | ||
| // short: 'c', | ||
| // description: 'Connection ID to seed the generated style matrix for', | ||
| // }), | ||
| // style: option({ | ||
| // type: optional(oneOf(keys(mapping))), | ||
| // description: 'Style to seed the generated style matrix for', | ||
| // long: 'style', | ||
| // short: 's', | ||
| // }), | ||
| // size: option({ | ||
| // type: optional(numberType), | ||
| // description: 'Number of emails to seed', | ||
| // long: 'size', | ||
| // short: 'n', | ||
| // defaultValue: () => { | ||
| // return 10; | ||
| // }, | ||
| // }), | ||
| // resetStyleMatrix: flag({ | ||
| // type: optional(boolean), | ||
| // description: 'Reset the style matrix before seeding', | ||
| // long: 'reset', | ||
| // short: 'r', | ||
| // defaultValue: () => { | ||
| // return false; | ||
| // }, | ||
| // }), | ||
| // }, | ||
| // handler: async (inputs) => { | ||
| // const connectionId = inputs.connectionId ?? (await getConnectionId()); | ||
| // const style = inputs.style ?? (await getStyle()); | ||
| // const resetStyleMatrix = inputs.resetStyleMatrix ?? (await getResetStyleMatrix(connectionId)); | ||
| // const size = inputs.size ?? (await getNumberOfEmails(mapping[style].length)); | ||
|
|
||
| // if (resetStyleMatrix) { | ||
| // await runResetStyleMatrix(connectionId); | ||
| // } | ||
|
|
||
| // await runSeeder(connectionId, style, size); | ||
| // }, | ||
| // }); | ||
|
|
||
| // const reset = command({ | ||
| // name: 'reset', | ||
| // args: { | ||
| // connectionId: option({ | ||
| // type: optional(stringType), | ||
| // long: 'connection-id', | ||
| // short: 'c', | ||
| // description: 'Connection ID to seed the generated style matrix for', | ||
| // }), | ||
| // }, | ||
| // handler: async (inputs) => { | ||
| // const connectionId = inputs.connectionId ?? (await getConnectionId()); | ||
|
|
||
| // const confirmed = await confirm({ | ||
| // message: `Reset the style matrix for Connection ID (${connectionId})?`, | ||
| // }); | ||
|
|
||
| // if (confirmed) { | ||
| // console.warn('Resetting style matrix for connection', connectionId); | ||
| // await runResetStyleMatrix(connectionId); | ||
| // console.warn('Reset style matrix for connection', connectionId); | ||
| // } else { | ||
| // console.warn('Aborted reset'); | ||
| // } | ||
| // }, | ||
| // }); | ||
|
|
||
| // const getConnectionId = async () => { | ||
| // return input({ | ||
| // message: 'Connection ID to seed:', | ||
| // required: true, | ||
| // validate: async (value) => { | ||
| // const connection = await db.query.connection.findFirst({ | ||
| // where: (table, ops) => { | ||
| // return ops.eq(table.id, value); | ||
| // }, | ||
| // columns: { | ||
| // id: true, | ||
| // }, | ||
| // }); | ||
|
|
||
| // return connection ? true : 'Invalid Connection ID'; | ||
| // }, | ||
| // }); | ||
| // }; | ||
|
|
||
| // const getStyle = async () => { | ||
| // return select<keyof typeof mapping>({ | ||
| // message: 'Style to seed the generated style matrix for', | ||
| // choices: keys(mapping), | ||
| // }); | ||
| // }; | ||
|
|
||
| // const getResetStyleMatrix = async (connectionId: string) => { | ||
| // return confirm({ | ||
| // message: `Reset the style matrix for Connection ID (${connectionId}) before seeding?`, | ||
| // default: true, | ||
| // }); | ||
| // }; | ||
|
|
||
| // const getNumberOfEmails = async (maxSize: number) => { | ||
| // return numberPrompt({ | ||
| // message: 'Number of emails to seed', | ||
| // default: 10, | ||
| // max: maxSize, | ||
| // min: 0, | ||
| // required: true, | ||
| // }); | ||
| // }; | ||
|
|
||
| // export const seedStyleCommand = subcommands({ | ||
| // name: 'seed-style', | ||
| // description: 'Seed style matrix for a given Connection ID', | ||
| // cmds: { | ||
| // seed, | ||
| // reset, | ||
| // }, | ||
| // }); |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Consider deleting the file instead of commenting out all content.
Commenting out the entire file creates dead code and removes the exported seedStyleCommand, which could break imports elsewhere in the codebase. If this functionality is being deprecated, consider either:
- Deleting the file entirely
- Adding a clear deprecation notice explaining why it's commented out
- Providing migration guidance if replacement functionality exists
🏁 Script executed:
#!/bin/bash
# Description: Check for any imports of seedStyleCommand or this seeder module
# Expected: Find all references to verify nothing breaks when this export is removed
# Search for imports of seedStyleCommand
rg -g "!scripts/seed-style/seeder.ts" "seedStyleCommand"
# Search for imports from this file
rg -g "!scripts/seed-style/seeder.ts" "from.*scripts/seed-style/seeder"
# Search for require statements
rg -g "!scripts/seed-style/seeder.ts" "require.*scripts/seed-style/seeder"Length of output: 565
Update or Remove Deprecated Seeder Imports
Commenting out scripts/seed-style/seeder.ts breaks all references to seedStyleCommand. You’ll need to either fully delete the module and clean up its imports or restore it (with a deprecation notice) if you still intend to support it.
Files to update:
- scripts/run.ts
- import { seedStyleCommand } from './seed-style/seeder';
- 'seed-style': seedStyleCommand,
- scripts/README.md
- import { seedStyleCommand } from '@zero/mail/scripts/seed-style/seeder';
- 'seed-style': seedStyleCommand,
Recommended actions:
- If deprecating:
- Delete scripts/seed-style/seeder.ts.
- Remove or replace the above imports.
- Update documentation to note removal of the
seed-stylecommand.
- If keeping (but deprecated):
- Un-comment the file.
- Add a clear deprecation warning at top of seeder.ts.
- Update README to mark the command as deprecated.
- Ensure tests or any CI steps aren’t relying on the removed command.
🤖 Prompt for AI Agents
In scripts/seed-style/seeder.ts lines 1 to 200, the entire file is commented out
which breaks the export of seedStyleCommand and any imports relying on it. To
fix this, either fully delete this file and remove all imports of
seedStyleCommand in scripts/run.ts and scripts/README.md, updating documentation
accordingly, or restore the file by uncommenting it and adding a clear
deprecation notice at the top, then mark the command as deprecated in the
README. Also verify no tests or CI steps depend on this command.
| import { getContext } from 'hono/context-storage'; | ||
| import type { gmail_v1 } from '@googleapis/gmail'; | ||
| import { connection } from '@zero/db/schema'; | ||
| import { connection } from '../../db/schema'; |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
LGTM! Import path update looks correct.
The change from absolute import @zero/db/schema to relative import ../../db/schema aligns with the broader refactoring to remove the @zero/db package. The relative path appears correct based on the file structure.
🏁 Script executed:
#!/bin/bash
# Description: Verify all @zero/db imports have been updated consistently
# Expected: Should find no remaining @zero/db imports
# Search for any remaining @zero/db imports
rg "@zero/db" --type ts --type tsx
# Verify the target schema file exists at the expected location
fd "schema" apps/server/src/db/Length of output: 123
🏁 Script executed:
#!/bin/bash
# Search for any remaining @zero/db imports across TS and TSX files
rg "@zero/db" -g "*.ts" -g "*.tsx" || echo "No matches found"
# Confirm schema.ts still exists
ls apps/server/src/db/schema.tsLength of output: 246
Action Required: Clean up leftover @zero/db references
The import update in apps/server/src/lib/driver/utils.ts is correct, and apps/server/src/db/schema.ts exists at the expected location. However, there are still references to the old @zero/db package in your scripts:
• scripts/seed-style/seeder.ts (commented imports):
// import { writingStyleMatrix } from '@zero/db/schema';
// import { db } from '@zero/db';Please remove or update these references to complete the refactoring.
🤖 Prompt for AI Agents
In apps/server/src/lib/driver/utils.ts at line 4, the import path has been
correctly updated from '@zero/db/schema' to a relative path. However, to
complete the refactoring, locate the commented out imports referencing
'@zero/db' in scripts/seed-style/seeder.ts and remove or update them to use the
new relative import paths consistent with the rest of the codebase.
| ALTER TABLE "mail0_user" ADD COLUMN "phone_number" text;--> statement-breakpoint | ||
| ALTER TABLE "mail0_user" ADD COLUMN "phone_number_verified" boolean;--> statement-breakpoint | ||
| ALTER TABLE "mail0_user" ADD CONSTRAINT "mail0_user_phone_number_unique" UNIQUE("phone_number"); No newline at end of file |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Enforce default and non-null for verification flag
Currently, phone_number_verified will default to NULL for existing rows, leading to tri-state logic. It’s safer to make it NOT NULL DEFAULT false. For example:
ALTER TABLE "mail0_user" ADD COLUMN "phone_number" text;
-ALTER TABLE "mail0_user" ADD COLUMN "phone_number_verified" boolean;
+ALTER TABLE "mail0_user" ADD COLUMN "phone_number_verified" boolean NOT NULL DEFAULT false;
ALTER TABLE "mail0_user" ADD CONSTRAINT "mail0_user_phone_number_unique" UNIQUE("phone_number");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ALTER TABLE "mail0_user" ADD COLUMN "phone_number" text;--> statement-breakpoint | |
| ALTER TABLE "mail0_user" ADD COLUMN "phone_number_verified" boolean;--> statement-breakpoint | |
| ALTER TABLE "mail0_user" ADD CONSTRAINT "mail0_user_phone_number_unique" UNIQUE("phone_number"); | |
| ALTER TABLE "mail0_user" ADD COLUMN "phone_number" text; | |
| ALTER TABLE "mail0_user" ADD COLUMN "phone_number_verified" boolean NOT NULL DEFAULT false; | |
| ALTER TABLE "mail0_user" ADD CONSTRAINT "mail0_user_phone_number_unique" UNIQUE("phone_number"); |
🤖 Prompt for AI Agents
In apps/server/src/db/migrations/0027_vengeful_golden_guardian.sql at lines 1 to
3, the column phone_number_verified is added without a default value or NOT NULL
constraint, allowing NULLs. Modify the ALTER TABLE statement to add
phone_number_verified as NOT NULL with a DEFAULT false to avoid tri-state logic
and ensure existing rows have a defined value.
| queryFn: () => | ||
| fetch(`https://api.github.com/repos/${REPOSITORY}`).then((res) => res.json() as any), |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Consider using proper TypeScript interfaces instead of as any.
While the explicit type casting improves type safety awareness, using as any bypasses TypeScript's type checking entirely. Consider creating proper interfaces for the GitHub API responses to maintain type safety.
+// Add interfaces for GitHub API responses
+interface GitHubRepository {
+ stargazers_count: number;
+ forks_count: number;
+ subscribers_count: number;
+ open_issues_count: number;
+}
+
+interface GitHubCommit {
+ commit: {
+ author: {
+ date: string;
+ };
+ };
+}
+
+interface GitHubPullRequest {
+ // Add relevant PR fields
+}
const { data: repoData, error: repoError } = useQuery({
queryFn: () =>
- fetch(`https://api.github.com/repos/${REPOSITORY}`).then((res) => res.json() as any),
+ fetch(`https://api.github.com/repos/${REPOSITORY}`).then((res) => res.json() as Promise<GitHubRepository>),
queryKey: ['repo-data', REPOSITORY],
});
const { data: commitsData, error: commitsError } = useQuery({
queryFn: () =>
fetch(`https://api.github.com/repos/${REPOSITORY}/commits?per_page=100`).then(
- (res) => res.json() as any,
+ (res) => res.json() as Promise<GitHubCommit[]>,
),
queryKey: ['commits-data', REPOSITORY],
});
const { data: prsData, error: prsError } = useQuery({
queryFn: () =>
fetch(`https://api.github.com/repos/${REPOSITORY}/pulls?state=open`).then(
- (res) => res.json() as any,
+ (res) => res.json() as Promise<GitHubPullRequest[]>,
),
queryKey: ['prs-data', REPOSITORY],
});Also applies to: 176-177, 184-185
🤖 Prompt for AI Agents
In apps/mail/app/(full-width)/contributors.tsx around lines 169-170, 176-177,
and 184-185, the code uses 'as any' to cast the JSON response from the GitHub
API, which disables TypeScript's type checking. To fix this, define appropriate
TypeScript interfaces representing the expected structure of the GitHub API
responses and replace 'as any' with these interfaces in the fetch calls to
ensure proper type safety.
| if (value !== current) { | ||
| setPrevious(current); | ||
| setCurrent(value); | ||
| } |
There was a problem hiding this comment.
Critical: Avoid setState during render - causes unpredictable behavior.
Calling setState during render (lines 7-10) violates React's rules and can lead to infinite re-renders, performance issues, or unpredictable behavior. This pattern is explicitly discouraged in React documentation.
Use useRef and useEffect instead for tracking previous values:
-import { useState } from 'react';
+import { useRef, useEffect } from 'react';
-export function usePrevious<T>(value: T) {
- const [current, setCurrent] = useState(value);
- const [previous, setPrevious] = useState<T | null>(null);
-
- if (value !== current) {
- setPrevious(current);
- setCurrent(value);
- }
-
- return previous;
-}
+export function usePrevious<T>(value: T) {
+ const ref = useRef<T>();
+
+ useEffect(() => {
+ ref.current = value;
+ });
+
+ return ref.current;
+}🤖 Prompt for AI Agents
In apps/mail/hooks/use-previous.ts at lines 7 to 10, avoid calling setState
during render as it causes unpredictable behavior and violates React rules.
Refactor the code to use useRef to hold the previous value and update it inside
a useEffect hook that runs after render. This prevents state updates during
render and ensures the previous value is tracked correctly without triggering
re-renders.
| const connectionId = (await this.ctx.storage.get('connectionId')) as string; | ||
| if (!connectionId || !this.driver) { | ||
| throw new Error('Unauthorized'); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add proper error handling for missing connectionId.
The current error handling throws a generic error without providing context about the authentication failure. This could make debugging difficult.
- if (!connectionId || !this.driver) {
- throw new Error('Unauthorized');
- }
+ if (!connectionId) {
+ throw new Error('No connection ID found. User may not be properly authenticated.');
+ }
+ if (!this.driver) {
+ throw new Error('Mail driver not initialized. Check authentication and connection setup.');
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const connectionId = (await this.ctx.storage.get('connectionId')) as string; | |
| if (!connectionId || !this.driver) { | |
| throw new Error('Unauthorized'); | |
| } | |
| const connectionId = (await this.ctx.storage.get('connectionId')) as string; | |
| if (!connectionId) { | |
| throw new Error('No connection ID found. User may not be properly authenticated.'); | |
| } | |
| if (!this.driver) { | |
| throw new Error('Mail driver not initialized. Check authentication and connection setup.'); | |
| } |
🤖 Prompt for AI Agents
In apps/server/src/routes/chat.ts around lines 42 to 45, the code throws a
generic error when connectionId is missing, which lacks context. Update the
error handling to throw a more descriptive error message that clearly indicates
the authentication failure due to missing connectionId. This will improve
debugging and clarity of the issue.
| const _conn = await getActiveConnection().catch((err) => { | ||
| console.error('Error in getActiveConnection:', err); | ||
| throw c.json({ error: 'Failed to get active connection' }, 500); | ||
| export class ZeroMCP extends McpAgent<typeof env, {}, { cookie: string }> { |
There was a problem hiding this comment.
Fix the banned {} type in ZeroMCP class declaration.
The generic parameter uses the banned {} type. Consider using a more specific type.
-export class ZeroMCP extends McpAgent<typeof env, {}, { cookie: string }> {
+export class ZeroMCP extends McpAgent<typeof env, Record<string, unknown>, { cookie: string }> {🧰 Tools
🪛 Biome (1.9.4)
[error] 120-120: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
🤖 Prompt for AI Agents
In apps/server/src/routes/chat.ts at line 120, the ZeroMCP class declaration
uses the banned empty object type `{}` as a generic parameter. Replace this `{}`
with a more specific type that accurately represents the expected shape or
interface for that generic parameter to improve type safety and clarity.
| } else if (canSendMessages.data.balance <= 0) { | ||
| console.log('Balance is 0 or less'); | ||
| return c.json({ error: 'Insufficient plan balance' }, 403); | ||
| async onChatMessage(onFinish: StreamTextOnFinishCallback<{}>) { |
There was a problem hiding this comment.
Fix the banned {} type.
Same issue as line 39 - replace the {} type with a more specific type.
- async onChatMessage(onFinish: StreamTextOnFinishCallback<{}>) {
+ async onChatMessage(onFinish: StreamTextOnFinishCallback<Record<string, unknown>>) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async onChatMessage(onFinish: StreamTextOnFinishCallback<{}>) { | |
| async onChatMessage(onFinish: StreamTextOnFinishCallback<Record<string, unknown>>) { |
🧰 Tools
🪛 Biome (1.9.4)
[error] 112-112: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
🤖 Prompt for AI Agents
In apps/server/src/routes/chat.ts at line 112, the use of the banned `{}` type
in the generic parameter of StreamTextOnFinishCallback should be replaced with a
more specific type that accurately represents the expected data structure.
Review the context or similar usages (like line 39) to determine the appropriate
type and update the generic accordingly to ensure type safety and clarity.
| } catch (e) { | ||
| return { | ||
| content: [ | ||
| { | ||
| type: 'text', | ||
| text: 'Failed to create label', | ||
| }, | ||
| ], | ||
| }; | ||
| } | ||
| }, |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Improve error handling in createLabel tool.
The error handling is too generic. Consider providing more specific error information or at least logging the error for debugging.
- } catch (e) {
- return {
- content: [
- {
- type: 'text',
- text: 'Failed to create label',
- },
- ],
- };
- }
+ } catch (e) {
+ console.error('Failed to create label:', e);
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `Failed to create label: ${e instanceof Error ? e.message : 'Unknown error'}`,
+ },
+ ],
+ };
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| } catch (e) { | |
| return { | |
| content: [ | |
| { | |
| type: 'text', | |
| text: 'Failed to create label', | |
| }, | |
| ], | |
| }; | |
| } | |
| }, | |
| } catch (e) { | |
| console.error('Failed to create label:', e); | |
| return { | |
| content: [ | |
| { | |
| type: 'text', | |
| text: `Failed to create label: ${e instanceof Error ? e.message : 'Unknown error'}`, | |
| }, | |
| ], | |
| }; | |
| } | |
| }, |
🤖 Prompt for AI Agents
In apps/server/src/routes/chat.ts between lines 376 and 386, the catch block for
the createLabel tool currently returns a generic error message without logging
or providing specific error details. Modify the catch block to log the caught
error for debugging purposes and, if appropriate, include more specific error
information in the returned response to improve error handling and
troubleshooting.
| if (token) { | ||
| const session = await this.getSession(token); | ||
| if (session) { | ||
| const db = createDb(env.HYPERDRIVE.connectionString); |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify environment variable access in class context.
The env variable is imported from 'cloudflare:workers' but accessed inside the class. Ensure this is accessible in the durable object context.
🏁 Script executed:
#!/bin/bash
# Description: Check how env is used across the codebase to ensure proper access patterns
rg -A 3 -B 3 "env\.HYPERDRIVE"Length of output: 1809
🏁 Script executed:
#!/bin/bash
# Show the top of chat.ts to inspect imports and class definitions
sed -n '1,50p' apps/server/src/routes/chat.tsLength of output: 1882
🏁 Script executed:
#!/bin/bash
# List top-level directories
find . -maxdepth 2 -type d | sed 's/\.\///g'Length of output: 376
Use the Durable Object’s env in ZeroAgent
Inside apps/server/src/routes/chat.ts, the env you imported from 'cloudflare:workers' is only a type stub. In your ZeroAgent class you should use the environment passed into the constructor (this.env), not the top-level import.
Please update both occurrences of:
const db = createDb(env.HYPERDRIVE.connectionString);to:
const db = createDb(this.env.HYPERDRIVE.connectionString);— apps/server/src/routes/chat.ts (around line 89 and the subsequent block)
🤖 Prompt for AI Agents
In apps/server/src/routes/chat.ts around line 89, replace the usage of the
imported top-level env variable with the Durable Object's environment instance
by changing all occurrences of "env.HYPERDRIVE.connectionString" to
"this.env.HYPERDRIVE.connectionString" inside the ZeroAgent class. This ensures
the correct environment context is used within the class methods.
Summary by CodeRabbit
New Features
Enhancements
Bug Fixes
Chores
Removals