refactor: remove GmailOAuthClient and googleapis dependency#64
Conversation
Replaces the custom GmailOAuthClient wrapper (which used googleapis to fetch access tokens) with a plain TransportOath2SchemaType object passed directly to Nodemailer. Nodemailer handles OAuth2 token refresh natively via its refreshToken field, making the extra abstraction unnecessary. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR removes the Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/src/lib/email/send.ts (1)
12-24:⚠️ Potential issue | 🟠 MajorValidate the email payload before creating the OAuth transport.
send()still initializescreateTransport3LO()before any payload validation. With the newsend(payload)usage inapp/src/__tests__/sendFormat.test.ts, malformed email input now also requires validGOOGLE_*config and can fail with transport/auth errors instead of the expectedEmailSchemaMessages.*. Please short-circuit invalidparamsbefore transport setup.Based on learnings,
EmailSenderclass must extendEmailTransport, exposesendEmail()method, validate email params with Zod schema, and support singlerecipientstring orrecipients[]array (max 20 total).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/lib/email/send.ts` around lines 12 - 24, The send function currently calls handler.createTransport3LO(oauth2) before validating the incoming params; move validation to the top of send (validate EmailType with the module's Zod schema and emit the proper EmailSchemaMessages.* on failure) so malformed payloads short-circuit before any transport/auth is initialized. Ensure validation accepts either a single recipient string or recipients[] and enforces a combined maximum of 20 addresses. Update EmailSender to extend EmailTransport and expose a sendEmail(params) method that assumes params are validated (or re-validates internally) and uses the already-created transport; in send(), validate first, then instantiate EmailSender, call createTransport3LO(oauth2), and finally call EmailSender.sendEmail(validatedParams).
🧹 Nitpick comments (1)
app/src/types/transport.interface.ts (1)
17-17: Drop the semicolons here to keep the TS style consistent.These changed members are in a TS file, and the repo style is semicolon-free.
As per coding guidelines, "No semicolons in code".
Also applies to: 30-30
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/src/types/transport.interface.ts` at line 17, Remove trailing semicolons from the TypeScript interface method declarations to match the repo's semicolon-free style: update the createTransport3LO method signature in transport.interface.ts (and the other changed member at the same file mentioned in the review) by removing the terminating semicolon so the declaration ends without a semicolon; ensure all interface members in this file follow the same no-semicolon convention.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@app/src/lib/email/send.ts`:
- Around line 12-24: The send function currently calls
handler.createTransport3LO(oauth2) before validating the incoming params; move
validation to the top of send (validate EmailType with the module's Zod schema
and emit the proper EmailSchemaMessages.* on failure) so malformed payloads
short-circuit before any transport/auth is initialized. Ensure validation
accepts either a single recipient string or recipients[] and enforces a combined
maximum of 20 addresses. Update EmailSender to extend EmailTransport and expose
a sendEmail(params) method that assumes params are validated (or re-validates
internally) and uses the already-created transport; in send(), validate first,
then instantiate EmailSender, call createTransport3LO(oauth2), and finally call
EmailSender.sendEmail(validatedParams).
---
Nitpick comments:
In `@app/src/types/transport.interface.ts`:
- Line 17: Remove trailing semicolons from the TypeScript interface method
declarations to match the repo's semicolon-free style: update the
createTransport3LO method signature in transport.interface.ts (and the other
changed member at the same file mentioned in the review) by removing the
terminating semicolon so the declaration ends without a semicolon; ensure all
interface members in this file follow the same no-semicolon convention.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a2e7e033-e3ce-4409-a6e8-9c40c0b4c5e2
⛔ Files ignored due to path filters (1)
app/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (20)
.github/workflows/release.yml.github/workflows/test.ymlCLAUDE.mdREADME.mdapp/.env.exampleapp/package.jsonapp/src/__tests__/oauth2client.test.tsapp/src/__tests__/send.test.tsapp/src/__tests__/sendFormat.test.tsapp/src/index.tsapp/src/lib/email/send.tsapp/src/lib/email/transport.tsapp/src/lib/google/oauth2client.tsapp/src/lib/index.tsapp/src/types/oauth2client.interface.tsapp/src/types/oauth2client.schema.tsapp/src/types/oauth2client.types.tsapp/src/types/transport.interface.tsapp/src/types/transport.schema.tsdocs/README_NPM.md
💤 Files with no reviewable changes (12)
- docs/README_NPM.md
- app/.env.example
- README.md
- .github/workflows/release.yml
- .github/workflows/test.yml
- app/src/index.ts
- app/src/tests/oauth2client.test.ts
- app/src/lib/index.ts
- app/src/types/oauth2client.types.ts
- app/src/types/oauth2client.interface.ts
- app/src/types/oauth2client.schema.ts
- app/src/lib/google/oauth2client.ts
Summary
GmailOAuthClientclass (lib/google/oauth2client.ts) and all supporting files (oauth2client.interface.ts,oauth2client.schema.ts,oauth2client.types.ts,oauth2client.test.ts)googleapisnpm package dependency entirelyGmailOAuthClientparameter onsend()andcreateTransport3LO()with a plainTransportOath2SchemaTypeobject (newtypes/transport.schema.ts)GmailOAuthClientno longer appears in the public API exportsRelated Issue
Why googleapis was removed
Previously,
GmailOAuthClientwrappedgoogle.auth.OAuth2from thegoogleapispackage solely to callgetAccessToken()— exchanging the refresh token for a short-lived access token — before passing that token to Nodemailer.This was unnecessary: Nodemailer's built-in OAuth2 transport support handles token refresh natively when a
refreshTokenis supplied in the transport auth config (see Nodemailer OAuth2 docs). Nodemailer calls the Google token endpoint internally on each send, so there is no need to pre-fetch an access token or maintain a separategoogle.auth.OAuth2client instance. Removing this layer eliminates ~1,000 lines of wrapper code and drops thegoogleapispackage — a large dependency that pulls in the entire Google API Node.js client library and was used for nothing other than onegetAccessToken()call.Before / After
Before — callers had to instantiate
GmailOAuthClient, optionally pre-generate an access token, and pass it intosend():After — pass a plain credentials object (or nothing, falling back to
GOOGLE_*env vars):Breaking changes
GmailOAuthClientis no longer exported from the package public API.GOOGLE_REDIRECT_URIenv var is no longer required or used.accessTokenpre-generation pattern (generateAccessToken()) no longer exists — Nodemailer handles token refresh internally on every send.Test plan
npm run lintpassesnpm run transpile:noemitpasses (type-check)npm testpasses (with validGOOGLE_*env vars in.env)npm run sendemail:dev -- text --recipients <email> --subject "Test" --content "Hello"npm run sendemail:dev -- html --recipients <email> --subject "Test" --content "Paragraph 1"🤖 Generated with Claude Code
Summary by CodeRabbit
Breaking Changes
GmailOAuthClienthas been removed from the public API and is no longer available for importsend()function now accepts optional OAuth2 credentials as a parameter instead of a client instanceGOOGLE_REDIRECT_URIenvironment variable is no longer required for configurationDependencies
googleapisfrom package dependencies