Skip to content

Conversation

@abhinav-anshul
Copy link

@abhinav-anshul abhinav-anshul commented Nov 15, 2025

Changes

  • Validates DODO_PAYMENTS_API_KEY, STRIPE_API_KEY, and webhook secrets at startup
  • Throws clear error messages when required variables are missing or empty
  • Updates .env.example files with proper documentation

Templates Updated

  • Express
  • Fastify
  • Hono
  • Next.js (API Routes)

Benefits

  • Prevents runtime errors from missing credentials
  • Provides immediate feedback during development
  • Improves developer experience with clear error messages

Summary by CodeRabbit

  • Refactor

    • Enhanced environment validation across all templates with fast-fail schema checks and replaced ad-hoc env reads with validated configuration objects.
    • Exposed validated configuration objects for reuse by webhook handlers and payment integrations.
    • Added conservative public type exports for payment-related entities where applicable.
  • Chores

    • Updated example environment files with clearer, standardized payment provider configuration sections.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Nov 15, 2025

@abhinav-anshul is attempting to deploy a commit to the Dodo Payments Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 15, 2025

Walkthrough

Adds module-load Zod validation for Stripe and DodoPayments environment variables across Express, Fastify, Hono, and Next.js templates, exporting typed validatedEnv objects and replacing direct process.env reads in client initialization and webhook handlers.

Changes

Cohort / File(s) Change Summary
Environment examples
packages/templates/express/.env.example, packages/templates/hono/.env.example, packages/templates/nextjs/.env.example
Standardized and updated .env.example blocks for DodoPayments and Stripe (new keys, removed legacy placeholders, restructured headings).
DodoPayments libraries
packages/templates/express/src/lib/dodopayments.ts, packages/templates/fastify/src/lib/dodopayments.ts, packages/templates/hono/src/lib/dodopayments.ts, packages/templates/nextjs/lib/dodopayments.ts
Add Zod schemas and module-load validation; export validatedEnv; refactor getDodoPaymentsClient() to use validated values instead of direct process.env.
Stripe libraries
packages/templates/express/src/lib/stripe.ts, packages/templates/hono/src/lib/stripe.ts, packages/templates/nextjs/lib/stripe.ts
Add Zod schemas and module-load validation; export validatedEnv; refactor getStripe() to use validated values; add exported Stripe-related type aliases.
DodoPayments webhook routes
packages/templates/express/src/routes/dodopayments/webhook.ts, packages/templates/fastify/src/routes/dodopayments/webhook.ts, packages/templates/hono/src/routes/dodopayments/webhook.ts, packages/templates/nextjs/api-routes/(dodopayments)/webhook/route.ts
Replace process.env.DODO_PAYMENTS_WEBHOOK_KEY with validatedEnv.DODO_PAYMENTS_WEBHOOK_KEY imported from the DodoPayments library.
Stripe webhook routes
packages/templates/express/src/routes/stripe/webhook.ts, packages/templates/hono/src/routes/stripe/webhook.ts, packages/templates/nextjs/api-routes/(stripe)/webhook/route.ts
Replace process.env.STRIPE_WEBHOOK_SECRET with validatedEnv.STRIPE_WEBHOOK_SECRET imported from the Stripe library.

Sequence Diagram(s)

sequenceDiagram
    participant Loader as Module Load
    participant Zod as Zod Validator
    participant Env as validatedEnv (export)
    participant Library as Library (getStripe/getDodoPayments)
    participant Webhook as Webhook Route

    rect rgb(220,235,255)
    note over Loader,Zod: New fast-fail validation at module load
    Loader->>Zod: parse(process.env)
    alt valid
        Zod->>Env: return validated values
        Env->>Library: exported validatedEnv used to init clients
        Library->>Webhook: Webhook imports validatedEnv for secret
    else invalid
        Zod->>Loader: throw descriptive error (fail-fast)
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Focus areas:
    • Zod schema correctness (prefixes, allowed enum values)
    • Ensure validatedEnv exports/types match consuming imports across templates
    • Verify no remaining direct process.env usages for the validated keys

Possibly related PRs

Suggested reviewers

  • tsahil01
  • thepushkaraj

Poem

🐇
I checked the env with Zod so keen,
No hidden keys or values unseen,
validatedEnv snug in its nest,
Webhooks read only what’s best,
Hop, skip, deploy — the rabbit’s serene.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The description includes a Changes section and Templates Updated section, but lacks Screenshots/Recordings, How to Test steps, and a Checklist as specified in the template. Add the missing template sections: How to Test (with npm ci, npm run typecheck, npm run build steps) and the verification Checklist to fully comply with the template.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding runtime validation for environment variables to prevent startup failures.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
packages/templates/express/.env.example (1)

10-12: Minor: Address linter conventions (optional).

Two low-priority items flagged by dotenv-linter:

  1. Missing blank line at EOF (line 12): Add a newline at the end of the file.
  2. Key ordering (lines 11–12): Conventionally, NODE_ENV should precede PORT for consistency in environment file organization.

These are style refinements and can be addressed if the project enforces dotenv-linter rules.

If addressing these conventions, apply this diff:

 # Server Configuration
-PORT=3000
 NODE_ENV=development
+PORT=3000
+
packages/templates/nextjs/.env.example (1)

1-8: Add a trailing newline for .env file convention.

The file is missing a blank line at the end. While this doesn't affect functionality, it's a standard convention for .env files.

Apply this diff:

 # Stripe Configuration
 STRIPE_SECRET_KEY=sk_test_your_stripe_secret_key_here
-STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret_here
+STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret_here

Based on static analysis.

packages/templates/hono/.env.example (1)

1-12: Add a trailing newline for .env file convention.

The file is missing a blank line at the end. While this doesn't affect functionality, it's a standard convention for .env files.

Apply this diff:

 # Server Configuration
 PORT=3000
-BUN_ENV=development
+BUN_ENV=development

Based on static analysis.

packages/templates/hono/src/lib/dodopayments.ts (1)

13-35: Minor: Error message formatting differs from other templates.

Line 18-19 starts the error message with a newline and space (\n DodoPayments...), while the Fastify version (line 18 in packages/templates/fastify/src/lib/dodopayments.ts) starts directly with the text. Consider aligning the formatting for consistency across templates.

Apply this diff to match the Fastify template:

-    throw new Error(`
- DodoPayments environment validation failed: ${errors}
+    throw new Error(`DodoPayments environment validation failed: ${errors}
packages/templates/hono/src/lib/stripe.ts (1)

14-34: Minor: Consistent error message formatting.

Line 19 has a leading space in the error message (" Stripe environment validation failed"). While this doesn't affect functionality, consider removing it for consistency with error message formatting in other templates.

Apply this diff:

-    throw new Error(` Stripe environment validation failed: ${errors}
+    throw new Error(`Stripe environment validation failed: ${errors}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bfc7ce6 and 01c2e91.

📒 Files selected for processing (17)
  • packages/templates/express/.env.example (1 hunks)
  • packages/templates/express/src/lib/dodopayments.ts (1 hunks)
  • packages/templates/express/src/lib/stripe.ts (1 hunks)
  • packages/templates/express/src/routes/dodopayments/webhook.ts (1 hunks)
  • packages/templates/express/src/routes/stripe/webhook.ts (2 hunks)
  • packages/templates/fastify/src/lib/dodopayments.ts (1 hunks)
  • packages/templates/fastify/src/routes/dodopayments/webhook.ts (1 hunks)
  • packages/templates/hono/.env.example (1 hunks)
  • packages/templates/hono/src/lib/dodopayments.ts (1 hunks)
  • packages/templates/hono/src/lib/stripe.ts (1 hunks)
  • packages/templates/hono/src/routes/dodopayments/webhook.ts (1 hunks)
  • packages/templates/hono/src/routes/stripe/webhook.ts (2 hunks)
  • packages/templates/nextjs/.env.example (1 hunks)
  • packages/templates/nextjs/api-routes/(dodopayments)/webhook/route.ts (1 hunks)
  • packages/templates/nextjs/api-routes/(stripe)/webhook/route.ts (2 hunks)
  • packages/templates/nextjs/lib/dodopayments.ts (1 hunks)
  • packages/templates/nextjs/lib/stripe.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (13)
packages/templates/nextjs/lib/dodopayments.ts (3)
packages/templates/express/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/fastify/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/hono/src/lib/dodopayments.ts (2)
  • validatedEnv (41-41)
  • getDodoPaymentsClient (45-54)
packages/templates/hono/src/lib/stripe.ts (6)
packages/templates/express/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/express/src/lib/stripe.ts (2)
  • validatedEnv (40-40)
  • getStripe (43-50)
packages/templates/fastify/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/hono/src/lib/dodopayments.ts (1)
  • validatedEnv (41-41)
packages/templates/nextjs/lib/dodopayments.ts (1)
  • validatedEnv (42-42)
packages/templates/nextjs/lib/stripe.ts (2)
  • validatedEnv (40-40)
  • getStripe (43-50)
packages/templates/nextjs/api-routes/(dodopayments)/webhook/route.ts (1)
packages/templates/nextjs/lib/dodopayments.ts (1)
  • validatedEnv (42-42)
packages/templates/nextjs/api-routes/(stripe)/webhook/route.ts (1)
packages/templates/nextjs/lib/stripe.ts (1)
  • validatedEnv (40-40)
packages/templates/hono/src/routes/dodopayments/webhook.ts (1)
packages/templates/hono/src/lib/dodopayments.ts (1)
  • validatedEnv (41-41)
packages/templates/fastify/src/lib/dodopayments.ts (6)
packages/templates/express/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/express/src/lib/stripe.ts (1)
  • validatedEnv (40-40)
packages/templates/hono/src/lib/dodopayments.ts (2)
  • validatedEnv (41-41)
  • getDodoPaymentsClient (45-54)
packages/templates/hono/src/lib/stripe.ts (1)
  • validatedEnv (40-40)
packages/templates/nextjs/lib/dodopayments.ts (2)
  • validatedEnv (42-42)
  • getDodoPaymentsClient (46-55)
packages/templates/nextjs/lib/stripe.ts (1)
  • validatedEnv (40-40)
packages/templates/express/src/routes/dodopayments/webhook.ts (1)
packages/templates/express/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/hono/src/lib/dodopayments.ts (3)
packages/templates/express/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/fastify/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/nextjs/lib/dodopayments.ts (2)
  • validatedEnv (42-42)
  • getDodoPaymentsClient (46-55)
packages/templates/hono/src/routes/stripe/webhook.ts (1)
packages/templates/hono/src/lib/stripe.ts (1)
  • validatedEnv (40-40)
packages/templates/express/src/lib/stripe.ts (6)
packages/templates/express/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/fastify/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/hono/src/lib/dodopayments.ts (1)
  • validatedEnv (41-41)
packages/templates/hono/src/lib/stripe.ts (2)
  • validatedEnv (40-40)
  • getStripe (43-50)
packages/templates/nextjs/lib/dodopayments.ts (1)
  • validatedEnv (42-42)
packages/templates/nextjs/lib/stripe.ts (2)
  • validatedEnv (40-40)
  • getStripe (43-50)
packages/templates/nextjs/lib/stripe.ts (6)
packages/templates/express/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/express/src/lib/stripe.ts (2)
  • validatedEnv (40-40)
  • getStripe (43-50)
packages/templates/fastify/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/hono/src/lib/dodopayments.ts (1)
  • validatedEnv (41-41)
packages/templates/hono/src/lib/stripe.ts (2)
  • validatedEnv (40-40)
  • getStripe (43-50)
packages/templates/nextjs/lib/dodopayments.ts (1)
  • validatedEnv (42-42)
packages/templates/fastify/src/routes/dodopayments/webhook.ts (1)
packages/templates/fastify/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/express/src/lib/dodopayments.ts (6)
packages/templates/express/src/lib/stripe.ts (1)
  • validatedEnv (40-40)
packages/templates/fastify/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/hono/src/lib/dodopayments.ts (2)
  • validatedEnv (41-41)
  • getDodoPaymentsClient (45-54)
packages/templates/hono/src/lib/stripe.ts (1)
  • validatedEnv (40-40)
packages/templates/nextjs/lib/dodopayments.ts (2)
  • validatedEnv (42-42)
  • getDodoPaymentsClient (46-55)
packages/templates/nextjs/lib/stripe.ts (1)
  • validatedEnv (40-40)
🪛 dotenv-linter (4.0.0)
packages/templates/express/.env.example

[warning] 12-12: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 12-12: [UnorderedKey] The NODE_ENV key should go before the PORT key

(UnorderedKey)

packages/templates/hono/.env.example

[warning] 12-12: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 12-12: [UnorderedKey] The BUN_ENV key should go before the PORT key

(UnorderedKey)

packages/templates/nextjs/.env.example

[warning] 8-8: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

🔇 Additional comments (26)
packages/templates/express/.env.example (1)

6-8: ✓ Stripe configuration properly documented.

The addition of STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET with appropriate placeholder values aligns with the PR objectives and follows the existing documentation pattern. These entries match the environment variables expected by the validation schema used in Stripe initialization across the templates.

packages/templates/fastify/src/lib/dodopayments.ts (4)

4-10: LGTM! Schema validates required fields correctly.

The Zod schema properly validates:

  • Required environment variables with non-empty string checks
  • Environment enum with clear error message
  • All three essential DodoPayments configuration values

13-34: Excellent error messaging for developer experience.

The validation function provides:

  • Clear, actionable error messages with formatting
  • Helpful troubleshooting checklist
  • Documentation of all required variables
  • Good use of safeParse for controlled error handling

This will significantly improve the developer experience when environment variables are misconfigured.


44-53: LGTM! Clean client initialization with validated config.

The function correctly:

  • Uses pre-validated environment variables from validatedEnv
  • Maintains lazy initialization pattern
  • Eliminates redundant runtime checks (validation happens at module load)

36-40: Review comment is not applicable to this codebase.

This is template/boilerplate code in packages/templates/ with no automated tests. The module-load validation is an intentional fail-fast pattern used consistently across all template frameworks (Stripe, Hono, etc.), and validatedEnv is properly exported for use in webhook handlers. No test setup verification is needed.

Likely an incorrect or invalid review comment.

packages/templates/fastify/src/routes/dodopayments/webhook.ts (1)

5-8: LGTM! Webhook now uses validated environment.

The webhook correctly sources its secret from validatedEnv, ensuring the key is validated at application startup rather than at runtime.

packages/templates/hono/src/lib/dodopayments.ts (3)

4-10: LGTM! Schema is consistent across templates.

Identical validation schema to other templates, ensuring consistent environment validation across all frameworks.


45-54: LGTM! Consistent implementation across templates.

Client initialization correctly uses validated environment variables.


37-41: No test compatibility issues detected; verification complete.

The hono template contains no test files, so there are no tests to break with module-level validation. The validatedEnv is properly exported and designed for use in handlers. This fail-fast validation pattern at startup is intentional and appropriate for a template.

packages/templates/nextjs/api-routes/(stripe)/webhook/route.ts (1)

2-15: LGTM! Stripe webhook uses validated configuration.

The webhook correctly sources the Stripe webhook secret from validatedEnv, ensuring validation at startup. This aligns with the same pattern used for DodoPayments webhooks.

packages/templates/nextjs/api-routes/(dodopayments)/webhook/route.ts (1)

3-5: LGTM! DodoPayments webhook uses validated configuration.

Correctly uses validatedEnv for the webhook key, ensuring validation occurs at startup.

packages/templates/hono/src/lib/stripe.ts (3)

4-11: Excellent format validation for Stripe keys!

The schema correctly validates:

  • STRIPE_SECRET_KEY must start with sk_ (standard Stripe prefix)
  • STRIPE_WEBHOOK_SECRET must start with whsec_ (webhook secret prefix)

This catches common copy-paste errors and provides better validation than simple non-empty checks.


43-50: LGTM! Clean Stripe client initialization.

The function correctly uses validated environment variables and maintains the lazy initialization pattern.


36-40: Module-level validation doesn't affect this template; guidance should be documented.

No tests exist in this template package, so module-level validation isn't an immediate concern. However, the routes (webhook.ts, subscriptions.ts, products.ts, payments.ts, checkout.ts, customer.ts) import lib/stripe at the module level, which means validation runs at app startup rather than test time. This is the expected behavior for a deployed application. If tests are added in the future, they'll need environment variables configured before importing these routes.

packages/templates/express/src/routes/stripe/webhook.ts (1)

3-3: LGTM! Clean refactor to validated environment.

The webhook secret now sources from validatedEnv, ensuring the value was validated at module load time. This eliminates runtime errors from missing or malformed secrets.

Also applies to: 15-15

packages/templates/hono/src/routes/dodopayments/webhook.ts (1)

3-3: LGTM! Consistent with the validation pattern.

The webhook key now uses the pre-validated environment value, preventing initialization with missing credentials.

Also applies to: 7-7

packages/templates/hono/src/routes/stripe/webhook.ts (1)

3-3: LGTM! Validated environment used correctly.

Also applies to: 16-16

packages/templates/nextjs/lib/stripe.ts (2)

45-45: LGTM! Stripe client now uses validated configuration.


4-40: Excellent validation implementation with clear error messaging.

The Zod schema correctly validates Stripe key formats and provides comprehensive error messages. The fail-fast approach at module load ensures configuration issues are caught immediately during development. Verified that zod is available in the project's root dependencies (version ^3.25.76), so the validation code will function as intended.

packages/templates/express/src/routes/dodopayments/webhook.ts (1)

3-3: LGTM! Webhook initialization now uses validated credentials.

Also applies to: 7-7

packages/templates/nextjs/lib/dodopayments.ts (2)

6-42: Well-structured validation with enum constraints.

The schema correctly validates the DodoPayments environment as an enum with a helpful custom error message. The validation pattern is consistent with the Stripe implementation.


49-50: LGTM! Client initialization uses validated configuration.

packages/templates/express/src/lib/dodopayments.ts (2)

4-40: LGTM! Framework-appropriate validation for Express.

The validation correctly references .env file instead of .env.local, which is appropriate for Express applications. The implementation is consistent with other templates.


47-48: LGTM! Client configuration uses validated environment.

packages/templates/express/src/lib/stripe.ts (2)

4-40: LGTM! Robust validation with Stripe-specific prefix checks.

The schema enforces correct Stripe key formats with the sk_ and whsec_ prefix validations. Error messaging is clear and framework-appropriate for Express.


45-45: LGTM! Stripe client initialization uses validated key.

@aagarwal1012
Copy link
Member

@abhinav-anshul you need to rebase your PR.

@abhinav-anshul abhinav-anshul force-pushed the feat/environment-variable-validation branch from 01c2e91 to d8fb89d Compare November 20, 2025 14:23
@abhinav-anshul
Copy link
Author

@aagarwal1012 done!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
packages/templates/nextjs/lib/stripe.ts (1)

2-40: Next.js Stripe env helper is consistent; apply same schema tweak as Hono/Express

This mirrors the Hono/Express helpers nicely: module-load validation, a reusable validatedEnv, and getStripe now sourcing from it. The added Stripe type exports are also useful for API route typing.

The same minor Zod nuance applies here: a missing env var yields a generic Required message, while your custom "… is required" text only covers the “empty string” case. If you adopt the required_error + .min(1, { message: … }) pattern from my Hono comment, I’d mirror it here so all templates emit equally explicit messages.

Also applies to: 45-53

packages/templates/express/src/lib/stripe.ts (1)

2-40: Express Stripe env validation is solid; consider aligning schema and other templates

The Express helper cleanly centralizes Stripe configuration: validation at module load, validatedEnv exported for webhooks, and getStripe now using validatedEnv.STRIPE_SECRET_KEY. That’s a nice DX improvement over ad‑hoc process.env checks.

Two small follow‑ups you might consider:

  • Apply the same required_error + .min(1, { message: … }) refinement as suggested on the Hono helper so missing vs empty variables get clearer, non‑generic messages.
  • For cross‑template consistency, ensure the Fastify Stripe helper also uses this shared stripeEnvSchema/validatedEnv pattern rather than a bespoke process.env check, so developers get identical behavior regardless of framework.

Also applies to: 45-52

🧹 Nitpick comments (6)
packages/templates/express/.env.example (1)

6-8: Stripe env examples look good; consider minor dotenv-linter cleanups

The added Stripe keys and example values line up with the rest of the templates and the validation logic implied by the PR description, so the semantics look correct.

If you care about keeping dotenv-linter fully green, you can also:

  • Move NODE_ENV above PORT, and
  • Add a trailing blank line at EOF.

Example:

-# Server Configuration
-PORT=3000
-NODE_ENV=development
+# Server Configuration
+NODE_ENV=development
+PORT=3000
+

Also applies to: 10-12

packages/templates/express/src/lib/dodopayments.ts (1)

2-40: Server-side env validation and client construction look correct

For the Express template, the zod schema + validateDodoPaymentsEnv give you a clean fail-fast path on misconfigured DODO_PAYMENTS_* variables, and using validatedEnv inside getDodoPaymentsClient removes the scattered process.env reads and inline checks. This matches the stated PR objective nicely.

There is some repetition of the same schema/validation logic across Express/Fastify/Hono; that’s reasonable for templates, but if these ever start drifting it might be worth centralizing into a small shared helper in the monorepo.

Also applies to: 47-48

packages/templates/hono/.env.example (1)

1-12: Env example keys align with code; minor optional dotenv-linter tweaks

The updated DodoPayments block and the new Stripe Configuration section (with STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRET) look consistent with the runtime validation behavior described for the Hono template.

If you want to satisfy dotenv-linter fully, you can also:

  • Put BUN_ENV before PORT, and
  • Add a blank line at EOF.

Example:

-# Server Configuration
-PORT=3000
-BUN_ENV=development
+# Server Configuration
+BUN_ENV=development
+PORT=3000
+
packages/templates/fastify/src/lib/dodopayments.ts (1)

2-40: Fastify env validation matches Express/Hono patterns and looks correct

The Fastify DodoPayments lib follows the same schema + module-load validation pattern as the other templates and correctly wires getDodoPaymentsClient through validatedEnv, eliminating ad-hoc process.env reads and runtime checks.

Given the near-identical logic across frameworks, you might later extract a small shared helper for the schema + validateDodoPaymentsEnv to avoid divergence, but that’s optional for template code.

Also applies to: 47-48

packages/templates/nextjs/.env.example (1)

1-8: Env example matches validation; optional trailing newline for tooling

The placeholders and prefixes line up with the Stripe validators you added elsewhere (sk_ / whsec_), and the DodoPayments block is clear. To satisfy dotenv-linter’s EndingBlankLine warning, you can add a final blank line at EOF; it’s non-functional but keeps tools quiet.

packages/templates/hono/src/lib/stripe.ts (1)

2-40: Centralized Stripe env validation looks good; consider sharpening Zod error messages

The stripeEnvSchema + validateStripeEnv + validatedEnv pattern is solid and aligns well with the “fail fast with clear messaging” goal. One small DX improvement: when a variable is missing vs just empty, Zod currently reports a generic Required message; your custom "… is required" text only applies to the .min(1, …) check.

If you want fully explicit messages for both cases, you could tweak the schema like this:

-const stripeEnvSchema = z.object({
-  STRIPE_SECRET_KEY: z.string().min(1, 'STRIPE_SECRET_KEY is required').startsWith('sk_', {
-    message: 'STRIPE_SECRET_KEY must start with "sk_"'
-  }),
-  STRIPE_WEBHOOK_SECRET: z.string().min(1, 'STRIPE_WEBHOOK_SECRET is required').startsWith('whsec_', {
-    message: 'STRIPE_WEBHOOK_SECRET must start with "whsec_"'
-  }),
-});
+const stripeEnvSchema = z.object({
+  STRIPE_SECRET_KEY: z
+    .string({ required_error: 'STRIPE_SECRET_KEY is required' })
+    .min(1, { message: 'STRIPE_SECRET_KEY cannot be empty' })
+    .startsWith('sk_', { message: 'STRIPE_SECRET_KEY must start with "sk_"' }),
+  STRIPE_WEBHOOK_SECRET: z
+    .string({ required_error: 'STRIPE_WEBHOOK_SECRET is required' })
+    .min(1, { message: 'STRIPE_WEBHOOK_SECRET cannot be empty' })
+    .startsWith('whsec_', { message: 'STRIPE_WEBHOOK_SECRET must start with "whsec_"' }),
+});

That keeps the behavior the same while making the thrown error text even more explicit for missing vs empty values.

Also applies to: 45-45

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 01c2e91 and d8fb89d.

📒 Files selected for processing (17)
  • packages/templates/express/.env.example (1 hunks)
  • packages/templates/express/src/lib/dodopayments.ts (1 hunks)
  • packages/templates/express/src/lib/stripe.ts (1 hunks)
  • packages/templates/express/src/routes/dodopayments/webhook.ts (1 hunks)
  • packages/templates/express/src/routes/stripe/webhook.ts (2 hunks)
  • packages/templates/fastify/src/lib/dodopayments.ts (1 hunks)
  • packages/templates/fastify/src/routes/dodopayments/webhook.ts (1 hunks)
  • packages/templates/hono/.env.example (1 hunks)
  • packages/templates/hono/src/lib/dodopayments.ts (1 hunks)
  • packages/templates/hono/src/lib/stripe.ts (1 hunks)
  • packages/templates/hono/src/routes/dodopayments/webhook.ts (1 hunks)
  • packages/templates/hono/src/routes/stripe/webhook.ts (2 hunks)
  • packages/templates/nextjs/.env.example (1 hunks)
  • packages/templates/nextjs/api-routes/(dodopayments)/webhook/route.ts (1 hunks)
  • packages/templates/nextjs/api-routes/(stripe)/webhook/route.ts (2 hunks)
  • packages/templates/nextjs/lib/dodopayments.ts (1 hunks)
  • packages/templates/nextjs/lib/stripe.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • packages/templates/nextjs/api-routes/(dodopayments)/webhook/route.ts
  • packages/templates/hono/src/routes/stripe/webhook.ts
  • packages/templates/hono/src/lib/dodopayments.ts
  • packages/templates/hono/src/routes/dodopayments/webhook.ts
  • packages/templates/fastify/src/routes/dodopayments/webhook.ts
  • packages/templates/nextjs/api-routes/(stripe)/webhook/route.ts
  • packages/templates/express/src/routes/stripe/webhook.ts
  • packages/templates/express/src/routes/dodopayments/webhook.ts
🧰 Additional context used
🧬 Code graph analysis (6)
packages/templates/fastify/src/lib/dodopayments.ts (3)
packages/templates/express/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/hono/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/nextjs/lib/dodopayments.ts (2)
  • validatedEnv (42-42)
  • getDodoPaymentsClient (46-55)
packages/templates/nextjs/lib/stripe.ts (3)
packages/templates/express/src/lib/stripe.ts (6)
  • validatedEnv (40-40)
  • getStripe (43-48)
  • Product (49-49)
  • Customer (50-50)
  • Subscription (51-51)
  • PaymentIntent (52-52)
packages/templates/hono/src/lib/stripe.ts (6)
  • validatedEnv (40-40)
  • getStripe (43-48)
  • Product (50-50)
  • Customer (51-51)
  • Subscription (52-52)
  • PaymentIntent (53-53)
packages/templates/fastify/src/lib/stripe.ts (5)
  • getStripe (5-23)
  • Product (25-25)
  • Customer (26-26)
  • Subscription (27-27)
  • PaymentIntent (28-28)
packages/templates/hono/src/lib/stripe.ts (7)
packages/templates/express/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/express/src/lib/stripe.ts (2)
  • validatedEnv (40-40)
  • getStripe (43-48)
packages/templates/fastify/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/hono/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/nextjs/lib/dodopayments.ts (1)
  • validatedEnv (42-42)
packages/templates/nextjs/lib/stripe.ts (2)
  • validatedEnv (40-40)
  • getStripe (43-48)
packages/templates/fastify/src/lib/stripe.ts (1)
  • getStripe (5-23)
packages/templates/nextjs/lib/dodopayments.ts (3)
packages/templates/express/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/fastify/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/hono/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/express/src/lib/dodopayments.ts (4)
packages/templates/express/src/lib/stripe.ts (1)
  • validatedEnv (40-40)
packages/templates/fastify/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/hono/src/lib/dodopayments.ts (2)
  • validatedEnv (40-40)
  • getDodoPaymentsClient (44-53)
packages/templates/nextjs/lib/dodopayments.ts (2)
  • validatedEnv (42-42)
  • getDodoPaymentsClient (46-55)
packages/templates/express/src/lib/stripe.ts (7)
packages/templates/express/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/fastify/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/hono/src/lib/dodopayments.ts (1)
  • validatedEnv (40-40)
packages/templates/hono/src/lib/stripe.ts (2)
  • validatedEnv (40-40)
  • getStripe (43-48)
packages/templates/nextjs/lib/dodopayments.ts (1)
  • validatedEnv (42-42)
packages/templates/nextjs/lib/stripe.ts (2)
  • validatedEnv (40-40)
  • getStripe (43-48)
packages/templates/fastify/src/lib/stripe.ts (1)
  • getStripe (5-23)
🪛 dotenv-linter (4.0.0)
packages/templates/hono/.env.example

[warning] 12-12: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 12-12: [UnorderedKey] The BUN_ENV key should go before the PORT key

(UnorderedKey)

packages/templates/express/.env.example

[warning] 12-12: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 12-12: [UnorderedKey] The NODE_ENV key should go before the PORT key

(UnorderedKey)

packages/templates/nextjs/.env.example

[warning] 8-8: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

Comment on lines +2 to +42
import { z } from 'zod'

type Product = DodoPayments.Product;

const dodoPaymentsEnvSchema = z.object({
DODO_PAYMENTS_API_KEY: z.string().min(1, 'DODO_PAYMENTS_API_KEY is required'),
DODO_PAYMENTS_ENVIRONMENT: z.enum(['live_mode', 'test_mode'], {
errorMap: () => ({ message: 'DODO_PAYMENTS_ENVIRONMENT must be either "live_mode" or "test_mode"' })
}),
DODO_PAYMENTS_WEBHOOK_KEY: z.string().min(1, 'DODO_PAYMENTS_WEBHOOK_KEY is required'),
})

// Validate environment variables at module load time (fails fast!)
function validateDodoPaymentsEnv() {
const result = dodoPaymentsEnvSchema.safeParse(process.env)

if (!result.success) {
const errors = result.error.errors.map(err => ` - ${err.path.join('.')}: ${err.message}`).join('\n')
throw new Error(`DodoPayments environment validation failed: ${errors}
Please check:
1. Your .env.local file exists in the project root
2. All required variables are set correctly
3. You've restarted your development server
4. No extra quotes or spaces in the .env.local file
Required variables:
- DODO_PAYMENTS_API_KEY: Your DodoPayments API key
- DODO_PAYMENTS_ENVIRONMENT: Either "live_mode" or "test_mode"
- DODO_PAYMENTS_WEBHOOK_KEY: Your DodoPayments webhook secret key
`)
}

return result.data
}

// Validate once at module load
const validatedEnv = validateDodoPaymentsEnv()

// Export for use in webhook handlers
export { validatedEnv }
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Env validation is solid; verify this module stays server-only in Next.js

The zod schema + safeParse(process.env) + detailed error message give clear, early feedback when DodoPayments env is misconfigured, and wiring getDodoPaymentsClient through validatedEnv is consistent with the rest of the PR.

One thing to double‑check: this file also exports purely client-safe helpers (getProducts, getCustomer, etc.). If any client component imports them from "@/lib/dodopayments", the module-level validation will run in the browser build, where process.env.DODO_PAYMENTS_* are typically unavailable, and you’ll throw before rendering.

If those helpers are (or might be) used from client components, consider either:

  • Moving the env validation + getDodoPaymentsClient into a server-only module (e.g. lib/server/dodopayments), and re-exporting only fetch helpers from the client-facing module, or
  • Lazily validating only when getDodoPaymentsClient is actually called, in a server-only path.

To verify current usage, you can run:

Also applies to: 49-50


🏁 Script executed:

#!/bin/bash
# Find client components (or any files) importing the Next.js DodoPayments lib
rg -n "from ['\"]@/lib/dodopayments['\"]" packages/templates/nextjs -C3 || true

Length of output: 3880



---

🏁 Script executed:

```shell
#!/bin/bash
# Check what useBilling.ts imports from dodopayments
sed -n '11,14p' packages/templates/nextjs/hooks/dodopayments/useBilling.ts

# Also check full exports from dodopayments.ts to see what's available
rg -n "^export" packages/templates/nextjs/lib/dodopayments.ts

Length of output: 503


Module-level validation throws in browser; move server code to separate module

Verification confirms the issue: packages/templates/nextjs/hooks/dodopayments/useBilling.ts (a client hook) imports createCustomer, updateCustomer, and checkout from @/lib/dodopayments. When this module loads in the browser bundle, the module-level validation at line 37 (const validatedEnv = validateDodoPaymentsEnv()) executes immediately and throws because process.env.DODO_PAYMENTS_* are not available in the browser.

Split the module:

  • lib/server/dodopayments.ts: Move validateDodoPaymentsEnv(), validatedEnv, and getDodoPaymentsClient().
  • lib/dodopayments.ts: Re-export only the client-safe fetch helpers (getProducts, getCustomer, createCustomer, updateCustomer, checkout, etc.).

This prevents the validation from executing in client bundles while keeping API routes able to import everything from the server module.

@aagarwal1012
Copy link
Member

@thepushkaraj can you review this?

Copy link
Contributor

@thepushkaraj thepushkaraj left a comment

Choose a reason for hiding this comment

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

Hey @abhinav-anshul - Thanks for the PR!

I found a few issues that need to be addressed:

1. In Zod v4, enum parameters don't support errorMap, it only accept the error field
image

2. Property errors doesn't exist on zod error type, should be issues
image

3. The NestJS integration hasn’t been updated with this new validation change. Could you please update that as well to keep consistency across all frameworks?

Let me know if you need any help!

@abhinav-anshul
Copy link
Author

@thepushkaraj I had a review of this, there seems to be an underlying issue with the Zod type here. The installed version of Zod is as

    "zod": "^4.1.12"

however this package is pulling Zod ts type from @ai-sdk/openai-compatible and @ai-sdk/react that used zodv3.

A better solution for this would be to upgrade the helper packges with zodv4 or downgrade the zod to v3 here. Let me know your thoughts

cc - @aagarwal1012

@thepushkaraj
Copy link
Contributor

@abhinav-anshul I found that only one dependency zod-to-json-schema which is internally used by ai-sdk doesn't support zod v4 and that library is no longer maintained. We can keep using zod v4, npm will deduplicate and consistently use v4 across all dependencies.

image

@sandipkumardey
Copy link
Contributor

Hey @abhinav-anshul, thanks again for digging into this, really appreciate the effort on tightening env validation across the templates.

Given the follow‑up findings:

  • Zod v4 enums don’t accept errorMap at the schema definition and only expose the error field.
  • The error object exposes issues rather than errors.
  • The Next.js template still needs to be updated to use the new validation pattern so all frameworks stay consistent.

It’s probably cleaner to tackle these in a fresh PR instead of layering more changes on this one. Lemme know if you need any help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants