-
-
Notifications
You must be signed in to change notification settings - Fork 203
feat(cli): add polar as better-auth plugin #578
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Caution Review failedThe pull request is closed. Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a payments option (polar/none) across CLI, web builder, templates, and validation; wires Polar integration into templates and dependency pins; moves and extends addon compatibility logic to auth- and payments-aware rules; adds prompts, env vars, scaffolding, and post-install instructions for Polar. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant CLI as CLI
participant Prompts as Prompts
participant Rules as CompatibilityRules
participant Creator as ProjectCreator
participant Templates as TemplateManager
participant Payments as PaymentsSetup
participant Env as EnvSetup
participant Post as PostInstall
U->>CLI: run init
CLI->>Prompts: gather (auth, backend, frontend, payments)
Prompts->>Rules: validate addons/payments (auth-aware)
Rules-->>Prompts: validation result
Prompts-->>CLI: config (with payments)
CLI->>Creator: createProject(config)
Creator->>Templates: setupAuthTemplate
alt payments == "polar"
Creator->>Templates: setupPaymentsTemplate
end
Creator->>Payments: setupPayments (install deps if polar)
Creator->>Env: write env (.env, .env.example)
Env-->>Creator: includes POLAR_* when polar
Creator->>Post: finalize
Post-->>U: show Polar post-install instructions (if applicable)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (5)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/cli/src/utils/bts-config.ts (1)
21-46
: payments is never persisted to bts.jsonc (missing in baseContent).Detected config will not include payments after write; downstream reads (detect-project-config) will see undefined.
Apply this diff to serialize payments:
auth: btsConfig.auth, + payments: btsConfig.payments, packageManager: btsConfig.packageManager,
♻️ Duplicate comments (2)
apps/cli/templates/auth/better-auth/server/base/src/lib/auth.ts.hbs (2)
105-129
: Same successUrl/portal concerns as prisma block.Apply the same guard/fallback and confirm portal redundancy.
237-259
: Repeat of successUrl/portal notes.Same recommendations as above.
🧹 Nitpick comments (40)
apps/cli/test/deployment.test.ts (1)
459-468
: Auto-generate the deploy matrix from WEB_DEPLOYS × SERVER_DEPLOYS to avoid drift.This list is the full 3×3 cross product; derive it from the imported constants so future additions don’t require manual edits. If test order matters, keep a custom sorter; otherwise this is simpler.
- }> = [ - { webDeploy: "wrangler", serverDeploy: "wrangler" }, - { webDeploy: "wrangler", serverDeploy: "alchemy" }, - { webDeploy: "alchemy", serverDeploy: "wrangler" }, - { webDeploy: "alchemy", serverDeploy: "alchemy" }, - { webDeploy: "wrangler", serverDeploy: "none" }, - { webDeploy: "alchemy", serverDeploy: "none" }, - { webDeploy: "none", serverDeploy: "wrangler" }, - { webDeploy: "none", serverDeploy: "alchemy" }, - { webDeploy: "none", serverDeploy: "none" }, - ]; + }> = + WEB_DEPLOYS.flatMap((w) => + SERVER_DEPLOYS.map((s) => ({ webDeploy: w, serverDeploy: s })), + ) satisfies ReadonlyArray<{ + webDeploy: TestConfig["webDeploy"]; + serverDeploy: TestConfig["serverDeploy"]; + }>;Follow-up: since the PR introduces “payments”, consider a parallel table-driven suite that sweeps payments options with this matrix (don’t expand this list here to keep scope focused).
apps/cli/templates/backend/server/server-base/package.json.hbs (1)
20-21
: [email protected] — TS compatibility OK; Node >=20.19.0 required; pin or document
- Verified: [email protected] peerDependencies include "typescript": "^5.0.0" — compatible with typescript ^5.8.2.
- Verified: [email protected] engines.node = ">=20.19.0" — ensure generated projects target Node 20.19+ or document/adjust the template runtime.
- Action: for reproducible scaffolds, pin to 0.15.1 or ~0.15.1 in apps/cli/templates/backend/server/server-base/package.json.hbs (lines 20–21), or keep "^0.15.1" but add packageManager/engines guidance in the template.
apps/web/src/app/(home)/new/_components/utils.ts (1)
1597-1612
: Consistent copy: use “Better-Auth” spelling in disabled reason.Keeps terminology consistent with other messages.
if (category === "payments" && optionId === "polar") { - if (finalStack.auth !== "better-auth") { - return "Polar payments requires Better Auth. Select Better Auth first."; + if (finalStack.auth !== "better-auth") { + return "Polar payments requires Better-Auth. Select Better-Auth first."; }apps/cli/test/test-utils.ts (2)
101-113
: Add payments default to avoid prompt paths in testsWhen
willUseYesFlag
is false, tests may hit the payments prompt unless a default is supplied. Includepayments: "none"
incoreStackDefaults
.Apply this diff inside the shown block:
: { frontend: ["tanstack-router"] as Frontend[], backend: "hono" as Backend, runtime: "bun" as Runtime, api: "trpc" as API, database: "sqlite" as Database, orm: "drizzle" as ORM, auth: "none" as Auth, + payments: "none" as Payments, addons: ["none"] as Addons[], examples: ["none"] as Examples[], dbSetup: "none" as DatabaseSetup, webDeploy: "none" as WebDeploy, serverDeploy: "none" as ServerDeploy, };
Additionally add the missing type import/alias elsewhere (see follow‑up snippet).
74-87
: Consider treating payments as a core flag for --yes conflict detectionIf the CLI treats
--payments
like other core selectors, include it incoreStackFlags
sowillUseYesFlag
behaves consistently.Follow‑up (outside the changed hunk):
// add to imports list at top: import { /* ... */, PaymentsSchema } from "../src/types"; // add type alias near other inferred types: export type Payments = (typeof PaymentsSchema)["options"][number];apps/cli/templates/payments/polar/server/base/src/lib/payments.ts.hbs (1)
1-6
: Rename SDK client to avoid confusion with better-auth plugin and allow env-based serverAvoid naming collision with the plugin named
polarClient()
and make server target configurable.Apply:
-import { Polar } from "@polar-sh/sdk"; - -export const polarClient = new Polar({ - accessToken: process.env.POLAR_ACCESS_TOKEN, - server: "sandbox", -}); +import { Polar } from "@polar-sh/sdk"; + +// SDK instance used on the server +export const polarSdk = new Polar({ + accessToken: process.env.POLAR_ACCESS_TOKEN, + server: process.env.POLAR_SERVER === "production" ? "production" : "sandbox", +});Ensure server templates that reference this use
polarSdk
.apps/cli/src/helpers/core/post-installation.ts (1)
455-457
: Expand Polar guidance with required envs and environment selectionCall out
POLAR_SUCCESS_URL
and optionalPOLAR_SERVER
so users don’t miss them.Apply:
-function getPolarInstructions() { - return `${pc.bold("Polar Payments Setup:")}\n${pc.cyan("•")} Get access token & product ID from ${pc.underline("https://sandbox.polar.sh/")}\n${pc.cyan("•")} Set POLAR_ACCESS_TOKEN in apps/server/.env`; -} +function getPolarInstructions() { + return `${pc.bold("Polar Payments Setup:")} +${pc.cyan("•")} Get access token & product/plan from ${pc.underline("https://sandbox.polar.sh/")} +${pc.cyan("•")} Set POLAR_ACCESS_TOKEN in apps/server/.env +${pc.cyan("•")} Optionally set POLAR_SERVER=sandbox|production (defaults to sandbox) +${pc.cyan("•")} Set POLAR_SUCCESS_URL in apps/server/.env (checkout redirect)`; +}apps/cli/templates/auth/better-auth/web/react/base/src/lib/auth-client.ts.hbs (2)
2-4
: Optional: alias the plugin import to disambiguate from server SDKPurely to reduce mental overhead alongside
polarSdk
on the server.-{{#if (eq payments "polar")}} -import { polarClient } from "@polar-sh/better-auth"; -{{/if}} +{{#if (eq payments "polar")}} +import { polarClient as polarPlugin } from "@polar-sh/better-auth"; +{{/if}}
13-15
: Align usage with alias (if applied)No behavior change.
-{{#if (eq payments "polar")}} - plugins: [polarClient()] -{{/if}} +{{#if (eq payments "polar")}} + plugins: [polarPlugin()] +{{/if}}apps/cli/src/constants.ts (1)
160-161
: Ensure Polar deps are only installed when payments = polarAvoid bloating projects not using payments. Verify the package.json generation path gates these dependencies on
config.payments === "polar"
.If not already gated, I can provide a small patch to conditionally include these deps in the template manager.
apps/cli/templates/payments/polar/web/react/tanstack-router/src/routes/success.tsx.hbs (1)
5-8
: Avoid unsafe type assertion for search params; makecheckout_id
optional.This prevents runtime issues when
checkout_id
is missing and aligns types with reality.Apply this diff:
export const Route = createFileRoute("/success")({ component: SuccessPage, - validateSearch: (search) => ({ - checkout_id: search.checkout_id as string, - }), + validateSearch(search) { + return { + checkout_id: + typeof search.checkout_id === "string" ? search.checkout_id : undefined, + }; + }, });apps/cli/templates/auth/better-auth/web/nuxt/app/plugins/auth-client.ts.hbs (1)
10-15
: Nuxt plugin initialization is sound; consider minor hardening and cleanup.
- baseURL relies on
config.public.serverURL
; if unset, client init may fail. Consider a small fallback or an explicit warning.- Use object property shorthand for
provide
.Apply this diff:
const authClient = createAuthClient({ baseURL: serverUrl, {{#if (eq payments "polar")}} plugins: [polarClient()], {{/if}} }); @@ return { provide: { - authClient: authClient, + authClient, }, };Optionally add a warning before init:
+ if (!serverUrl) { + console.warn("[auth] Missing runtimeConfig.public.serverURL"); + }apps/cli/src/helpers/core/payments-setup.ts (1)
29-40
: Hoist and reuse the web frontends list (minor perf/readability).Avoid recreating the array each call; a Set also makes intent clearer.
Apply this diff:
import { addPackageDependency } from "../../utils/add-package-deps"; +const WEB_FRONTENDS = new Set([ + "react-router", + "tanstack-router", + "tanstack-start", + "next", + "nuxt", + "svelte", + "solid", +]); + export async function setupPayments(config: ProjectConfig) { @@ - const hasWebFrontend = frontend.some((f) => - [ - "react-router", - "tanstack-router", - "tanstack-start", - "next", - "nuxt", - "svelte", - "solid", - ].includes(f), - ); + const hasWebFrontend = frontend.some((f) => WEB_FRONTENDS.has(f));apps/cli/templates/auth/better-auth/web/react/next/src/app/dashboard/page.tsx.hbs (1)
7-11
: Remove unnecessaryawait
onheaders()
; consider disabling fetch caching.
headers()
is synchronous in Next; also, considercache: "no-store"
to avoid caching session requests.Apply this diff:
const session = await authClient.getSession({ fetchOptions: { - headers: await headers() + headers: headers(), + // cache: "no-store", } }); @@ {{#if (eq payments "polar")}} const { data: customerState, error } = await authClient.customer.state({ fetchOptions: { - headers: await headers() + headers: headers(), + // cache: "no-store", } }); {{/if}}Also applies to: 18-22
apps/cli/templates/auth/better-auth/server/base/src/lib/auth.ts.hbs (1)
37-59
: Harden successUrl and dedupe portal config.
- successUrl may be undefined at runtime; add a guard or fallback.
- You set enableCustomerPortal: true and also use portal(); verify both are required per the current @polar-sh/better-auth API.
Example tweak (Node/Bun variants):
- successUrl: process.env.POLAR_SUCCESS_URL, + successUrl: + process.env.POLAR_SUCCESS_URL ?? + (process.env.BETTER_AUTH_URL + ? new URL("/billing/success", process.env.BETTER_AUTH_URL).toString() + : undefined),apps/web/src/app/(home)/new/_components/tech-icon.tsx (1)
33-35
: Light-variant handling for Polar—LGTM; consider stricter match.Using icon.includes("polar") can false-match unrelated filenames. Consider matching basename or a known CDN path segment to reduce accidental rewrites. Also ensure -light.svg assets exist for Polar.
apps/cli/src/utils/bts-config.ts (1)
93-98
: Allow updating payments via updateBtsConfig.You’ll likely want to patch payments in-place like other top-level fields.
Apply this diff:
- updates: Partial< - Pick<BetterTStackConfig, "addons" | "webDeploy" | "serverDeploy"> - >, + updates: Partial< + Pick<BetterTStackConfig, "addons" | "payments" | "webDeploy" | "serverDeploy"> + >,apps/cli/templates/payments/polar/web/react/tanstack-start/src/routes/success.tsx.hbs (1)
5-8
: Guard the search param type in validateSearch.Avoid asserting to string; make checkout_id optional if absent/malformed.
Apply this diff:
export const Route = createFileRoute("/success")({ component: SuccessPage, - validateSearch: (search) => ({ - checkout_id: search.checkout_id as string, - }), + validateSearch: (search) => ({ + checkout_id: + typeof search.checkout_id === "string" ? search.checkout_id : undefined, + }), });Also applies to: 10-17
apps/cli/src/helpers/core/env-setup.ts (1)
283-292
: Add TanStack Router/Start to CORS-origin 5173 checkInclude hasTanStackRouter and hasTanStackStart in the existing conditional; POLAR_SUCCESS_URL (
${corsOrigin}/success?checkout_id={CHECKOUT_ID}
) matches templates that readcheckout_id
.Location: apps/cli/src/helpers/core/env-setup.ts (near CORS origin conditional)
- if (hasReactRouter || hasSvelte) { + if (hasReactRouter || hasTanStackRouter || hasTanStackStart || hasSvelte) { corsOrigin = "http://localhost:5173"; }apps/web/src/lib/stack-utils.ts (1)
92-92
: CLI flag wiring for --payments added — OK.Flag shape matches CLI schema. Optional: consider omitting the flag when value is "none" to reduce noise (follow existing conventions if any).
apps/cli/src/helpers/core/command-handlers.ts (1)
272-277
: Updated getAddonsToAdd signature usage — pass auth defensively.If detectedConfig.auth can be undefined, pass "none" to avoid runtime surprises.
- const addonsPrompt = await getAddonsToAdd( - detectedConfig.frontend || [], - detectedConfig.addons || [], - detectedConfig.auth, - ); + const addonsPrompt = await getAddonsToAdd( + detectedConfig.frontend || [], + detectedConfig.addons || [], + detectedConfig.auth ?? "none", + );apps/cli/src/helpers/core/add-addons.ts (1)
6-6
: Move validateAddonCompatibility import to compatibility-rules — OK.If ../../utils/addon-compatibility is now unused elsewhere, clean it up.
apps/cli/src/helpers/core/template-manager.ts (1)
610-704
: Payments templating mirrors auth templating — avoid overwrites and extract shared frontend-detection
- processAndCopyFiles (apps/cli/src/helpers/core/template-manager.ts) supports an overwrite flag (defaults to true). setupPaymentsTemplate currently calls it without the flag and will overwrite existing files; use overwrite=false for payments web/server copies to avoid clobbering generic pages/routes (e.g., success/cancel/index). Examples already use overwrite=false in setupExamplesTemplate — make payments consistent.
- Frontend-detection (hasReactWeb, hasNuxtWeb, hasSvelteWeb, hasSolidWeb + reactFramework lookup) is duplicated across setupAuthTemplate, setupPaymentsTemplate, setupFrontendTemplates, setupExamplesTemplate — extract a small helper to compute these flags and the reactFramework to reduce drift.
Recommended quick change (apply where payments web copy is invoked):
+// Example: guard against overwriting if a file already exists - await processAndCopyFiles("**/*", paymentsWebSrc, webAppDir, context); + await processAndCopyFiles("**/*", paymentsWebSrc, webAppDir, context, /*overwrite*/ false);apps/cli/src/utils/config-validation.ts (1)
445-451
: Fail fast on payments compatibility — nice. Minor hardening suggestion.To future‑proof against signature changes, you could defensively pass an empty array when
config.frontend
is undefined (function defaults handle it today, but being explicit avoids footguns).validatePaymentsCompatibility( config.payments, config.auth, config.backend, - config.frontend, + config.frontend ?? [], );apps/cli/src/prompts/payments.ts (1)
15-22
: Align “compatibility” predicate with validation (treat undefined frontends as allowed).If
frontends
is undefined (rare in current prompt order, but possible programmatically), Polar is hidden even thoughvalidatePaymentsCompatibility
allows “no frontend”. Consider:- const isPolarCompatible = - auth === "better-auth" && - backend !== "convex" && - (frontends?.length === 0 || splitFrontends(frontends).web.length > 0); + const isPolarCompatible = + auth === "better-auth" && + backend !== "convex" && + ((frontends == null || frontends.length === 0) || + splitFrontends(frontends).web.length > 0);apps/web/src/lib/constant.ts (1)
743-776
: Tighten StackState typing for payments to the concrete union.Keeps UI and CLI in sync and improves DX.
-import type { TechCategory } from "./types"; +import type { TechCategory, Payments } from "./types"; ... export type StackState = { ... - payments: string; + payments: Payments; ... };apps/cli/templates/auth/better-auth/web/react/tanstack-router/src/routes/dashboard.tsx.hbs (4)
7-13
: Remove unused imports.
queryClient
,useSuspenseQuery
,useEffect
, anduseState
aren’t used in the rendered branches.-{{#if (eq api "trpc")}} -import { queryClient, trpc } from "@/utils/trpc"; -{{/if}} +{{#if (eq api "trpc")}} +import { trpc } from "@/utils/trpc"; +{{/if}} {{#if ( or (eq api "orpc") (eq api "trpc"))}} -import { useQuery, useSuspenseQuery } from "@tanstack/react-query"; +import { useQuery } from "@tanstack/react-query"; {{/if}} -import { createFileRoute, redirect } from "@tanstack/react-router"; -import { useEffect, useState } from "react"; +import { createFileRoute, redirect } from "@tanstack/react-router";
45-47
: Avoid non-null assertion in boolean check.Safer and clearer:
-const hasProSubscription = customerState?.activeSubscriptions?.length! > 0 +const hasProSubscription = !!customerState?.activeSubscriptions?.length
56-67
: Optional UX: disable button while awaiting and handle errors.Prevents double submits and surfaces failures.
-<Button onClick={async () => await authClient.customer.portal()}> +<Button + onClick={async (e) => { + (e.currentTarget as HTMLButtonElement).disabled = true + try { await authClient.customer.portal() } finally { + (e.currentTarget as HTMLButtonElement).disabled = false + } + }}> Manage Subscription </Button> ... -<Button onClick={async () => await authClient.checkout({ slug: "pro" })}> +<Button + onClick={async (e) => { + (e.currentTarget as HTMLButtonElement).disabled = true + try { await authClient.checkout({ slug: "pro" }) } finally { + (e.currentTarget as HTMLButtonElement).disabled = false + } + }}> Upgrade to Pro </Button>
46-47
: Remove console.log from template.Avoids shipping debug logs to users.
- console.log("Active subscriptions:", customerState?.activeSubscriptions)
apps/cli/templates/auth/better-auth/web/react/next/src/app/dashboard/dashboard.tsx.hbs (2)
31-34
: Avoid non-null assertion and drop console.log in template output.Safer boolean with default to 0; remove debug log from scaffolds.
{{#if (eq payments "polar")}} -const hasProSubscription = customerState?.activeSubscriptions?.length! > 0; -console.log("Active subscriptions:", customerState?.activeSubscriptions); +const hasProSubscription = (customerState?.activeSubscriptions?.length ?? 0) > 0; {{/if}}
38-43
: DRY the duplicated API message block.Use the
or
helper once (as done in the TanStack Start template) to reduce duplication.- {{#if (eq api "orpc")}} - <p>API: {privateData.data?.message}</p> - {{/if}} - {{#if (eq api "trpc")}} - <p>API: {privateData.data?.message}</p> - {{/if}} + {{#if (or (eq api "orpc") (eq api "trpc"))}} + <p>API: {privateData.data?.message}</p> + {{/if}}apps/cli/src/utils/compatibility-rules.ts (2)
196-218
: Addon compatibility helper reads clean; minor nit on type cast.
as readonly string[]
is unnecessary ifADDON_COMPATIBILITY
isas const
. Optional to drop.- const hasCompatibleFrontend = frontend.some((f) => - (compatibleFrontends as readonly string[]).includes(f), - ); + const hasCompatibleFrontend = frontend.some((f) => + compatibleFrontends.includes(f), + );
254-283
: Tighten the auth check and clarify web-frontend requirement wording.Functional as-is; simplify the predicate and improve message.
if (payments === "polar") { - if (!auth || auth === "none" || auth !== "better-auth") { + if (auth !== "better-auth") { exitWithError( "Polar payments requires Better Auth. Please use '--auth better-auth' or choose a different payments provider.", ); } @@ - if (web.length === 0 && frontends.length > 0) { + if (frontends.length > 0 && web.length === 0) { exitWithError( - "Polar payments requires a web frontend or no frontend. Please select a web frontend or choose a different payments provider.", + "Polar payments requires at least one web frontend (or no frontend at all). Please select a web frontend or choose a different payments provider.", ); } }I can add unit tests covering: (1) polar+non-better-auth, (2) polar+convex, (3) polar+native-only frontends, (4) none/undefined payments paths.
apps/cli/templates/auth/better-auth/web/react/tanstack-start/src/routes/dashboard.tsx.hbs (6)
5-5
: Remove unused importuseSuspenseQuery
.-import { useQuery, useSuspenseQuery } from "@tanstack/react-query"; +import { useQuery } from "@tanstack/react-query";
9-9
: Remove unused importuseSuspenseQuery
.-import { useQuery, useSuspenseQuery } from "@tanstack/react-query"; +import { useQuery } from "@tanstack/react-query";
12-12
: Drop unused React imports.
useEffect
anduseState
aren’t used.-import { useEffect, useState } from "react";
45-47
: Avoid non-null assertion and remove console.log in scaffold.-const hasProSubscription = customerState?.activeSubscriptions?.length! > 0 - console.log("Active subscriptions:", customerState?.activeSubscriptions) +const hasProSubscription = (customerState?.activeSubscriptions?.length ?? 0) > 0
59-66
: Remove redundant async/await in onClick handlers.- <Button onClick={async () => await authClient.customer.portal()}> + <Button onClick={() => authClient.customer.portal()}> Manage Subscription </Button> ) : ( - <Button onClick={async () => await authClient.checkout({ slug: "pro" })}> + <Button onClick={() => authClient.checkout({ slug: "pro" })}> Upgrade to Pro </Button> )}
24-29
: Prefer explicit Handlebars conditions over a generic else for forward-compat.If more payment providers are added later, the else-branch may become incorrect.
- {{else}} + {{else if (eq payments "none")}} return { session }; + {{else}} + return { session };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (51)
apps/cli/src/constants.ts
(3 hunks)apps/cli/src/helpers/core/add-addons.ts
(2 hunks)apps/cli/src/helpers/core/add-deployment.ts
(1 hunks)apps/cli/src/helpers/core/command-handlers.ts
(2 hunks)apps/cli/src/helpers/core/create-project.ts
(4 hunks)apps/cli/src/helpers/core/detect-project-config.ts
(1 hunks)apps/cli/src/helpers/core/env-setup.ts
(1 hunks)apps/cli/src/helpers/core/payments-setup.ts
(1 hunks)apps/cli/src/helpers/core/post-installation.ts
(3 hunks)apps/cli/src/helpers/core/template-manager.ts
(1 hunks)apps/cli/src/index.ts
(2 hunks)apps/cli/src/prompts/addons.ts
(5 hunks)apps/cli/src/prompts/config-prompts.ts
(5 hunks)apps/cli/src/prompts/payments.ts
(1 hunks)apps/cli/src/types.ts
(4 hunks)apps/cli/src/utils/addon-compatibility.ts
(0 hunks)apps/cli/src/utils/bts-config.ts
(1 hunks)apps/cli/src/utils/compatibility-rules.ts
(2 hunks)apps/cli/src/utils/config-processing.ts
(2 hunks)apps/cli/src/utils/config-validation.ts
(3 hunks)apps/cli/src/utils/display-config.ts
(1 hunks)apps/cli/src/utils/generate-reproducible-command.ts
(1 hunks)apps/cli/templates/auth/better-auth/server/base/src/lib/auth.ts.hbs
(10 hunks)apps/cli/templates/auth/better-auth/web/nuxt/app/plugins/auth-client.ts
(0 hunks)apps/cli/templates/auth/better-auth/web/nuxt/app/plugins/auth-client.ts.hbs
(1 hunks)apps/cli/templates/auth/better-auth/web/react/base/src/lib/auth-client.ts.hbs
(2 hunks)apps/cli/templates/auth/better-auth/web/react/next/src/app/dashboard/dashboard.tsx.hbs
(1 hunks)apps/cli/templates/auth/better-auth/web/react/next/src/app/dashboard/page.tsx.hbs
(1 hunks)apps/cli/templates/auth/better-auth/web/react/tanstack-router/src/routes/dashboard.tsx.hbs
(1 hunks)apps/cli/templates/auth/better-auth/web/react/tanstack-start/src/routes/dashboard.tsx.hbs
(1 hunks)apps/cli/templates/auth/better-auth/web/solid/src/lib/auth-client.ts
(0 hunks)apps/cli/templates/auth/better-auth/web/solid/src/lib/auth-client.ts.hbs
(1 hunks)apps/cli/templates/auth/better-auth/web/svelte/src/lib/auth-client.ts.hbs
(1 hunks)apps/cli/templates/backend/server/server-base/package.json.hbs
(1 hunks)apps/cli/templates/extras/bunfig.toml.hbs
(1 hunks)apps/cli/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs
(1 hunks)apps/cli/templates/payments/polar/server/base/src/lib/payments.ts.hbs
(1 hunks)apps/cli/templates/payments/polar/web/react/next/src/app/success/page.tsx.hbs
(1 hunks)apps/cli/templates/payments/polar/web/react/tanstack-router/src/routes/success.tsx.hbs
(1 hunks)apps/cli/templates/payments/polar/web/react/tanstack-start/src/routes/success.tsx.hbs
(1 hunks)apps/cli/test/database-orm.test.ts
(1 hunks)apps/cli/test/deployment.test.ts
(1 hunks)apps/cli/test/test-utils.ts
(1 hunks)apps/web/src/app/(home)/new/_components/tech-icon.tsx
(1 hunks)apps/web/src/app/(home)/new/_components/utils.ts
(2 hunks)apps/web/src/lib/constant.ts
(8 hunks)apps/web/src/lib/stack-url-keys.ts
(1 hunks)apps/web/src/lib/stack-url-state.client.ts
(1 hunks)apps/web/src/lib/stack-url-state.ts
(1 hunks)apps/web/src/lib/stack-utils.ts
(2 hunks)apps/web/src/lib/types.ts
(1 hunks)
💤 Files with no reviewable changes (3)
- apps/cli/src/utils/addon-compatibility.ts
- apps/cli/templates/auth/better-auth/web/nuxt/app/plugins/auth-client.ts
- apps/cli/templates/auth/better-auth/web/solid/src/lib/auth-client.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/convex_rules.mdc)
**/*.{ts,tsx}
: Use Id from './_generated/dataModel' to type document ids (e.g., Id<'users'>)
Ensure Record key/value types align with validators (e.g., v.record(v.id('users'), v.string()) => Record<Id<'users'>, string>)
Be strict with types for document ids; prefer Id<'table'> over string
Use 'as const' for string literals in discriminated unions
When using Array and Record types, declare with explicit generic types (e.g., const arr: Array = ...)
**/*.{ts,tsx}
: Use TypeScript type aliases instead of interface declarations.
Do not use explicit return types in TypeScript.
Files:
apps/web/src/lib/types.ts
apps/cli/src/types.ts
apps/cli/src/helpers/core/detect-project-config.ts
apps/cli/src/helpers/core/env-setup.ts
apps/cli/src/utils/display-config.ts
apps/cli/src/utils/generate-reproducible-command.ts
apps/cli/src/helpers/core/payments-setup.ts
apps/cli/test/test-utils.ts
apps/web/src/app/(home)/new/_components/tech-icon.tsx
apps/web/src/lib/stack-url-keys.ts
apps/cli/src/helpers/core/post-installation.ts
apps/cli/test/database-orm.test.ts
apps/web/src/app/(home)/new/_components/utils.ts
apps/cli/src/utils/config-processing.ts
apps/cli/src/utils/bts-config.ts
apps/cli/test/deployment.test.ts
apps/cli/src/prompts/addons.ts
apps/web/src/lib/stack-url-state.client.ts
apps/cli/src/prompts/payments.ts
apps/web/src/lib/stack-utils.ts
apps/cli/src/helpers/core/add-addons.ts
apps/cli/src/constants.ts
apps/cli/src/helpers/core/add-deployment.ts
apps/cli/src/index.ts
apps/cli/src/helpers/core/create-project.ts
apps/cli/src/helpers/core/template-manager.ts
apps/web/src/lib/constant.ts
apps/web/src/lib/stack-url-state.ts
apps/cli/src/helpers/core/command-handlers.ts
apps/cli/src/utils/compatibility-rules.ts
apps/cli/src/utils/config-validation.ts
apps/cli/src/prompts/config-prompts.ts
**/*.{js,jsx,ts,tsx,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{js,jsx,ts,tsx,mjs,cjs}
: Do not use dotenv; Bun auto-loads .env
UseBun.serve()
for HTTP/WebSockets; do not useexpress
Usebun:sqlite
for SQLite; do not usebetter-sqlite3
UseBun.redis
for Redis; do not useioredis
UseBun.sql
for Postgres; do not usepg
orpostgres.js
Use built-inWebSocket
; do not usews
PreferBun.file
overnode:fs
readFile/writeFile
UseBun.$
instead ofexeca
for shelling out
Files:
apps/web/src/lib/types.ts
apps/cli/src/types.ts
apps/cli/src/helpers/core/detect-project-config.ts
apps/cli/src/helpers/core/env-setup.ts
apps/cli/src/utils/display-config.ts
apps/cli/src/utils/generate-reproducible-command.ts
apps/cli/src/helpers/core/payments-setup.ts
apps/cli/test/test-utils.ts
apps/web/src/app/(home)/new/_components/tech-icon.tsx
apps/web/src/lib/stack-url-keys.ts
apps/cli/src/helpers/core/post-installation.ts
apps/cli/test/database-orm.test.ts
apps/web/src/app/(home)/new/_components/utils.ts
apps/cli/src/utils/config-processing.ts
apps/cli/src/utils/bts-config.ts
apps/cli/test/deployment.test.ts
apps/cli/src/prompts/addons.ts
apps/web/src/lib/stack-url-state.client.ts
apps/cli/src/prompts/payments.ts
apps/web/src/lib/stack-utils.ts
apps/cli/src/helpers/core/add-addons.ts
apps/cli/src/constants.ts
apps/cli/src/helpers/core/add-deployment.ts
apps/cli/src/index.ts
apps/cli/src/helpers/core/create-project.ts
apps/cli/src/helpers/core/template-manager.ts
apps/web/src/lib/constant.ts
apps/web/src/lib/stack-url-state.ts
apps/cli/src/helpers/core/command-handlers.ts
apps/cli/src/utils/compatibility-rules.ts
apps/cli/src/utils/config-validation.ts
apps/cli/src/prompts/config-prompts.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Define functions using the standard function declaration syntax, not arrow functions.
Files:
apps/web/src/lib/types.ts
apps/cli/src/types.ts
apps/cli/src/helpers/core/detect-project-config.ts
apps/cli/src/helpers/core/env-setup.ts
apps/cli/src/utils/display-config.ts
apps/cli/src/utils/generate-reproducible-command.ts
apps/cli/src/helpers/core/payments-setup.ts
apps/cli/test/test-utils.ts
apps/web/src/app/(home)/new/_components/tech-icon.tsx
apps/web/src/lib/stack-url-keys.ts
apps/cli/src/helpers/core/post-installation.ts
apps/cli/test/database-orm.test.ts
apps/web/src/app/(home)/new/_components/utils.ts
apps/cli/src/utils/config-processing.ts
apps/cli/src/utils/bts-config.ts
apps/cli/test/deployment.test.ts
apps/cli/src/prompts/addons.ts
apps/web/src/lib/stack-url-state.client.ts
apps/cli/src/prompts/payments.ts
apps/web/src/lib/stack-utils.ts
apps/cli/src/helpers/core/add-addons.ts
apps/cli/src/constants.ts
apps/cli/src/helpers/core/add-deployment.ts
apps/cli/src/index.ts
apps/cli/src/helpers/core/create-project.ts
apps/cli/src/helpers/core/template-manager.ts
apps/web/src/lib/constant.ts
apps/web/src/lib/stack-url-state.ts
apps/cli/src/helpers/core/command-handlers.ts
apps/cli/src/utils/compatibility-rules.ts
apps/cli/src/utils/config-validation.ts
apps/cli/src/prompts/config-prompts.ts
**/*.{hbs,handlebars}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
In Handlebars templates, avoid generic if/else blocks; write explicit conditions (e.g., if (eq orm "prisma") and else if (eq orm "drizzle")).
Files:
apps/cli/templates/payments/polar/web/react/next/src/app/success/page.tsx.hbs
apps/cli/templates/extras/bunfig.toml.hbs
apps/cli/templates/backend/server/server-base/package.json.hbs
apps/cli/templates/payments/polar/server/base/src/lib/payments.ts.hbs
apps/cli/templates/auth/better-auth/web/svelte/src/lib/auth-client.ts.hbs
apps/cli/templates/auth/better-auth/web/solid/src/lib/auth-client.ts.hbs
apps/cli/templates/payments/polar/web/react/tanstack-router/src/routes/success.tsx.hbs
apps/cli/templates/auth/better-auth/web/react/base/src/lib/auth-client.ts.hbs
apps/cli/templates/auth/better-auth/server/base/src/lib/auth.ts.hbs
apps/cli/templates/payments/polar/web/react/tanstack-start/src/routes/success.tsx.hbs
apps/cli/templates/auth/better-auth/web/react/tanstack-start/src/routes/dashboard.tsx.hbs
apps/cli/templates/auth/better-auth/web/nuxt/app/plugins/auth-client.ts.hbs
apps/cli/templates/auth/better-auth/web/react/next/src/app/dashboard/page.tsx.hbs
apps/cli/templates/auth/better-auth/web/react/tanstack-router/src/routes/dashboard.tsx.hbs
apps/cli/templates/auth/better-auth/web/react/next/src/app/dashboard/dashboard.tsx.hbs
apps/cli/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs
🧠 Learnings (2)
📚 Learning: 2025-08-24T18:00:39.152Z
Learnt from: CR
PR: AmanVarshney01/create-better-t-stack#0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-08-24T18:00:39.152Z
Learning: Applies to convex/**/*.ts : Respect file-based routing: api.<path>.<name> for public and internal.<path>.<name> for private functions based on file location/name
Applied to files:
apps/cli/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs
📚 Learning: 2025-08-24T18:00:39.152Z
Learnt from: CR
PR: AmanVarshney01/create-better-t-stack#0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-08-24T18:00:39.152Z
Learning: Applies to convex/**/*.ts : Use query/mutation/action for public API; use internalQuery/internalMutation/internalAction for private functions; do not register via api/internal objects
Applied to files:
apps/cli/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs
🧬 Code graph analysis (14)
apps/cli/src/helpers/core/payments-setup.ts (2)
apps/cli/src/types.ts (1)
ProjectConfig
(172-192)apps/cli/src/utils/add-package-deps.ts (1)
addPackageDependency
(6-43)
apps/cli/test/test-utils.ts (1)
apps/cli/src/types.ts (12)
Frontend
(37-37)Backend
(16-16)Runtime
(21-21)API
(82-82)Database
(6-6)ORM
(11-11)Auth
(87-87)Addons
(54-54)Examples
(59-59)DatabaseSetup
(79-79)WebDeploy
(120-120)ServerDeploy
(125-125)
apps/cli/test/database-orm.test.ts (2)
apps/cli/src/types.ts (2)
Database
(6-6)ORM
(11-11)apps/cli/test/test-utils.ts (2)
Database
(197-197)ORM
(198-198)
apps/cli/src/utils/config-processing.ts (1)
apps/cli/src/types.ts (1)
Payments
(92-92)
apps/cli/src/prompts/addons.ts (2)
apps/cli/src/types.ts (1)
Auth
(87-87)apps/cli/src/utils/compatibility-rules.ts (1)
validateAddonCompatibility
(196-218)
apps/web/src/lib/stack-url-state.client.ts (1)
apps/web/src/lib/constant.ts (2)
StackState
(743-763)DEFAULT_STACK
(765-785)
apps/cli/src/prompts/payments.ts (4)
apps/cli/src/types.ts (4)
Payments
(92-92)Auth
(87-87)Backend
(16-16)Frontend
(37-37)apps/cli/src/utils/compatibility-rules.ts (1)
splitFrontends
(21-30)apps/cli/src/constants.ts (1)
DEFAULT_CONFIG
(40-40)apps/cli/src/utils/errors.ts (1)
exitCancelled
(17-23)
apps/cli/src/index.ts (1)
apps/cli/src/types.ts (1)
PaymentsSchema
(89-91)
apps/cli/src/helpers/core/create-project.ts (2)
apps/cli/src/helpers/core/template-manager.ts (1)
setupPaymentsTemplate
(610-704)apps/cli/src/helpers/core/payments-setup.ts (1)
setupPayments
(6-50)
apps/cli/src/helpers/core/template-manager.ts (2)
apps/cli/src/types.ts (1)
ProjectConfig
(172-192)apps/cli/src/constants.ts (1)
PKG_ROOT
(7-7)
apps/web/src/lib/stack-url-state.ts (1)
apps/web/src/lib/constant.ts (2)
StackState
(743-763)DEFAULT_STACK
(765-785)
apps/cli/src/utils/compatibility-rules.ts (3)
apps/cli/src/types.ts (5)
Addons
(54-54)Frontend
(37-37)Auth
(87-87)Payments
(92-92)Backend
(16-16)apps/cli/src/constants.ts (1)
ADDON_COMPATIBILITY
(166-178)apps/cli/src/utils/errors.ts (1)
exitWithError
(9-15)
apps/cli/src/utils/config-validation.ts (1)
apps/cli/src/utils/compatibility-rules.ts (2)
validateAddonsAgainstFrontends
(236-252)validatePaymentsCompatibility
(254-282)
apps/cli/src/prompts/config-prompts.ts (3)
apps/cli/src/types.ts (1)
Payments
(92-92)apps/cli/src/prompts/payments.ts (1)
getPaymentsChoice
(7-46)apps/cli/src/prompts/addons.ts (1)
getAddonsChoice
(75-134)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cursor Bugbot
🔇 Additional comments (51)
apps/cli/templates/extras/bunfig.toml.hbs (1)
2-6
: Resolved — Nuxt-aware linker conditional is correcthandlebars.registerHelper("includes", ...) is defined in apps/cli/src/utils/template-processor.ts and ProjectConfig.frontend is typed/used as Frontend[] (apps/cli/src/types.ts and many call sites/tests), so keep the current template conditional as-is.
apps/web/src/app/(home)/new/_components/utils.ts (1)
821-877
: Guard Polar payments checks to avoid duplicate disables
- Ensure later checks only run if payments is still "polar" (e.g. add
nextStack.payments === "polar"
to the backend check and/or wrap the web-frontend check inif (nextStack.payments === "polar") { ... }
). Location: apps/web/src/app/(home)/new/_components/utils.ts (≈ lines 821–877).- Do not change the user-facing message to "Better-Auth" — the repo uses "Better Auth" in messages and "better-auth" as the internal id; keep messaging consistent or normalize across the repo.
- Verified: CATEGORY_ORDER includes "payments"; StackState and TECH_OPTIONS include payments; notes.payments is initialized from CATEGORY_ORDER (no extra existence guard needed).
Likely an incorrect or invalid review comment.
apps/cli/src/utils/generate-reproducible-command.ts (1)
18-18
: LGTM: add --payments flag to reproducible commandUnconditional emission matches other core flags and aligns with default "none". No issues.
apps/cli/test/database-orm.test.ts (1)
63-110
: LGTM: formatting-only restructure of invalid combinationsData unchanged; readability improved.
apps/cli/src/helpers/core/post-installation.ts (2)
75-78
: Condition for Polar instructions looks correctShown only when payments = polar and auth = better-auth. Good gate.
195-195
: Include Polar steps in final outputIntegration point is correct; ordering matches other sections.
apps/cli/src/types.ts (4)
89-93
: LGTM: Payments schema surfaceEnum and description look good.
140-140
: LGTM: add payments to CreateInput (optional)Keeps CLI inputs backward‑compatible.
184-184
: LGTM: add payments to ProjectConfigRequired in resolved config is appropriate.
205-205
: LGTM: add payments to BetterTStackConfigEnsures persisted config includes payments.
apps/cli/src/constants.ts (1)
16-16
: LGTM: default payments noneSensible default; aligns with reproducible command behavior.
apps/cli/templates/auth/better-auth/web/svelte/src/lib/auth-client.ts.hbs (1)
3-5
: Conditional Polar plugin wiring looks good.Import is gated correctly and the plugin is injected only when payments = "polar".
Ensure PUBLIC_SERVER_URL is always defined in generated projects; otherwise client init may fail at runtime. Do you want a defensive fallback added in the template?
Also applies to: 9-11
apps/cli/templates/auth/better-auth/web/solid/src/lib/auth-client.ts.hbs (1)
6-11
: Solid auth client template looks correct.Polar plugin gating and baseURL usage are consistent with other frameworks.
Verify VITE_SERVER_URL is populated in generated env files; otherwise consider a small fallback or a build-time check.
apps/cli/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs (1)
20-23
: Conditional type-only import looks right; verify QueryClient provider and aliases.
- Good call scoping the QueryClient import to trpc/orpc.
- Please confirm a QueryClient Provider is mounted upstream for non-convex trpc/orpc templates; ReactQueryDevtools will require it.
- Verify path aliases and exports resolve: AppRouter at "../../../server/src/routers" and named
orpc
at "@/utils/orpc".apps/cli/templates/auth/better-auth/server/base/src/lib/auth.ts.hbs (3)
7-10
: Polar imports are correctly gated; ensure dependency wiring.Confirm the CLI adds @polar-sh/better-auth and the generated server template pins compatible versions. Also ensure "./payments" exists in every variant (prisma/drizzle/mongoose/none/workers) that includes polar.
176-197
: Workers: ensure env binding exists and is documented.Confirm POLAR_SUCCESS_URL is bound in Cloudflare env bindings (and referenced in the generated README). If not present, checkout will misroute.
36-36
: Minor: keep advanced.defaultCookieAttributes consistent across variants.Looks consistent; good defaults for SameSite=None + Secure + HttpOnly.
Also applies to: 104-104, 176-176, 235-235, 296-296
apps/web/src/lib/stack-url-keys.ts (1)
15-15
: URL key for payments added—LGTM.Please verify stack-url-state parsers and defaults include "payments" and that "pay" doesn’t collide with existing keys.
apps/web/src/lib/types.ts (1)
13-13
: Adding "payments" to TechCategory—LGTM.Ensure CATEGORY_ORDER and any UI sections respect the new category.
apps/cli/src/helpers/core/detect-project-config.ts (1)
20-21
: LGTM; payments plumbed through detectProjectConfig.This relies on bts.jsonc actually containing payments; ensure write path persists it (see bts-config note).
apps/cli/src/helpers/core/add-deployment.ts (1)
72-73
: LGTM; sane defaulting of payments.Passing detectedConfig.payments || "none" keeps templates/env-setup consistent.
apps/cli/src/utils/display-config.ts (1)
46-48
: LGTM; Payments displayed consistently after Auth.No issues.
apps/web/src/lib/stack-url-state.client.ts (1)
46-49
: LGTM — payments added and URL key mapping present.
apps/web/src/lib/stack-url-keys.ts maps payments -> "pay".apps/cli/src/utils/config-processing.ts (1)
60-62
: Approve — payments wiring is correct. CLIInput (CreateInput) exposes payments?: Payments and PaymentsSchema/Payments type exist; no changes required.apps/cli/src/helpers/core/command-handlers.ts (1)
106-107
: Extend error-path ProjectConfig with payments — OK.Keeps fallback shape aligned with updated ProjectConfig.
apps/cli/src/helpers/core/add-addons.ts (1)
48-49
: Propagate payments into ProjectConfig — OK.Keeps downstream setup flows informed.
apps/cli/src/index.ts (2)
35-35
: Expose PaymentsSchema — OK.Public surface aligned with types.
84-85
: Wire payments option into init input — update docs/examples to include --payments
Add the --payments flag to README/CLI examples (including the reproducible init command) and confirm the CLI help output lists the flag.apps/cli/src/helpers/core/create-project.ts (3)
20-20
: Import payments setup hooks — OK.Aligns with new payments flow.
Also applies to: 35-35
84-86
: Runtime setup for payments — good placement after setupAuth.Ensures the plugin has its host auth installed first.
55-57
: Template step for payments — gate verified.Compatibility rule at apps/cli/src/utils/compatibility-rules.ts (lines 262–274) enforces payments === "polar" only when auth === "better-auth" and also rejects backend === "convex". Optional: simplify the conditional (!auth || auth === "none" || auth !== "better-auth") to (auth !== "better-auth").
apps/web/src/lib/stack-url-state.ts (1)
47-49
: Add payments parser — OK.
Matches DEFAULT_STACK and TECH_OPTIONS; stackUrlKeys includes payments -> "pay" (apps/web/src/lib/stack-url-keys.ts:15), so the URL will round-trip.apps/web/src/lib/stack-utils.ts (1)
21-21
: Add payments to CATEGORY_ORDER — looks good. Confirmed TECH_OPTIONS defines a "payments" category and stackUrlKeys maps it to "pay" (apps/web/src/lib/constant.ts:430–444; apps/web/src/lib/stack-url-keys.ts:15). CATEGORY_ORDER already contains "payments" so URL and summary behavior remain consistent.apps/cli/src/utils/config-validation.ts (3)
14-18
: Good addition: payments validation is now part of the rules import.Brings programmatic validation in line with CLI flows.
420-423
: Auth-aware addon validation hookup looks correct.Passing
config.auth
intovalidateAddonsAgainstFrontends
matches the new signature and preserves the de-dupe that follows.
453-457
: Programmatic addons check: auth pipe-through confirmed.Consistent with full-config validation.
apps/cli/src/prompts/payments.ts (1)
37-45
: Prompt wiring and cancellation handling look solid.Initial value from
DEFAULT_CONFIG.payments
; clean cancel path toexitCancelled
.apps/web/src/lib/constant.ts (1)
610-741
: Presets/defaults include payments — good coverage.Defaults/presets align with validation rules (Convex presets use
"none"
, full-featured uses"polar"
).Also applies to: 765-785
apps/cli/src/prompts/addons.ts (3)
3-8
: Import + API shift to compatibility-rules is correct.Auth is typed and plumbed through.
75-97
: Auth-aware compatibility in selection loop looks good.Skips incompatible addons early; grouping logic preserved.
136-155
: getAddonsToAdd: passes auth through to filtering — nice.Keeps “add more” flow consistent with initial selection.
apps/cli/src/prompts/config-prompts.ts (4)
13-18
: Type surface extended with Payments — OK.
32-36
: Payments prompt import is correct.
93-100
: Prompt order puts payments after auth/backend/frontend — perfect.Ensures compatibility context is available.
151-152
: Result wiring includes payments — good.apps/cli/templates/auth/better-auth/web/react/tanstack-router/src/routes/dashboard.tsx.hbs (1)
17-31
: No change required — redirect usage in beforeLoad is correct. The existing redirect({ to: "/login", throw: true }) is supported in TanStack Router v1; throwing redirect({ to: "/login" }) is an equivalent, commonly shown pattern.apps/cli/templates/auth/better-auth/web/react/next/src/app/dashboard/dashboard.tsx.hbs (1)
47-54
: Remove redundant async/await in onClick handlers.Returning a Promise is fine; no need for
async
/await
wrappers.
[ suggest_nitpick_refactor ]- <Button onClick={async () => await authClient.customer.portal()}> + <Button onClick={() => authClient.customer.portal()}> Manage Subscription </Button> ) : ( - <Button onClick={async () => await authClient.checkout({ slug: "pro" })}> + <Button onClick={() => authClient.checkout({ slug: "pro" })}> Upgrade to Pro </Button> )}apps/cli/src/utils/compatibility-rules.ts (3)
1-1
: Import of ADDON_COMPATIBILITY looks good.
220-235
: Filtering logic for compatible addons is correct.
236-252
: Validation wiring passes auth through correctly.apps/cli/templates/auth/better-auth/web/react/tanstack-start/src/routes/dashboard.tsx.hbs (1)
16-23
: No change required — both redirect styles are valid in TanStack Router v1.
The redirect helper returns a Redirect you can either throw yourself (throw redirect({ to: '/login' })) or call redirect({ to: '/login', throw: true }) to have it thrown for you; both will abort loaders/beforeLoad.
apps/cli/templates/auth/better-auth/web/react/next/src/app/dashboard/dashboard.tsx.hbs
Show resolved
Hide resolved
apps/cli/templates/payments/polar/web/react/next/src/app/success/page.tsx.hbs
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (10)
apps/cli/templates/payments/polar/web/svelte/src/routes/success/+page.svelte.hbs (1)
1-5
: Makecheckout_id
reactive to$page
changesUse a reactive statement (and
let
) so the value updates on client-side navigations and aligns with Svelte store usage.<script lang="ts"> import { page } from '$app/stores'; - - const checkout_id = $page.url.searchParams.get('checkout_id'); + let checkout_id: string | null = null; + $: checkout_id = $page.url.searchParams.get('checkout_id'); </script>apps/cli/templates/auth/better-auth/web/svelte/src/routes/dashboard/+page.svelte.hbs (2)
24-30
: Harden Polar state fetch: add error handling and unmount safety.Prevent setting state after unmount and surface errors minimally.
- if (session) { - authClient.customer.state().then(({ data }) => { - customerState = data; - }); - } + if (session) { + let cancelled = false; + authClient.customer.state() + .then(({ data }) => { if (!cancelled) customerState = data; }) + .catch((e) => console.error('customer.state failed', e)); + return () => { cancelled = true; }; + }
9-11
: Type refinement: avoidany
forcustomerState
.Use a minimal shape to aid DX.
- let customerState: any = null; + type CustomerState = { activeSubscriptions?: unknown[] } | null; + let customerState: CustomerState = null;apps/cli/templates/auth/better-auth/web/react/react-router/src/routes/dashboard.tsx.hbs (5)
18-21
: Prefer a typed customer state overany
.- const [customerState, setCustomerState] = useState<any>(null); + type CustomerState = { activeSubscriptions?: unknown[] } | null; + const [customerState, setCustomerState] = useState<CustomerState>(null);
29-34
: Good: addednavigate
to deps. Consider replacing history on redirect.- navigate("/login"); + navigate("/login", { replace: true });
36-45
: Add cleanup and error handling in Polar state effect.Avoid setState after unmount and log failures.
- useEffect(() => { - async function fetchCustomerState() { - if (session) { - const { data } = await authClient.customer.state(); - setCustomerState(data); - } - } - - fetchCustomerState(); - }, [session]); + useEffect(() => { + let cancelled = false; + async function fetchCustomerState() { + if (!session) return; + try { + const { data } = await authClient.customer.state(); + if (!cancelled) setCustomerState(data); + } catch (e) { + console.error("customer.state failed", e); + } + } + fetchCustomerState(); + return () => { cancelled = true; }; + }, [session]);
52-56
: Tidy: remove non-null assertion and console log.
!
after optional chain is redundant; convert to boolean. Drop debug log in template.- const hasProSubscription = customerState?.activeSubscriptions?.length! > 0; - console.log("Active subscriptions:", customerState?.activeSubscriptions); + const hasProSubscription = Boolean(customerState?.activeSubscriptions?.length);
67-73
: Optional: handle action errors for better UX.Wrap portal/checkout calls to catch and surface failures.
- <Button onClick={async () => await authClient.customer.portal()}> + <Button onClick={async () => { try { await authClient.customer.portal(); } catch (e) { console.error(e); } }}> Manage Subscription </Button> @@ - <Button onClick={async () => await authClient.checkout({ slug: "pro" })}> + <Button onClick={async () => { try { await authClient.checkout({ slug: "pro" }); } catch (e) { console.error(e); } }}> Upgrade to Pro </Button>apps/cli/templates/auth/better-auth/web/solid/src/routes/dashboard.tsx.hbs (2)
48-50
: Tidy: remove non-null assertion and coerce to boolean.- const hasProSubscription = () => - customerState?.activeSubscriptions?.length! > 0; + const hasProSubscription = () => + Boolean(customerState?.activeSubscriptions?.length);
62-70
: Optional: wrap actions in try/catch.Improves resilience of customer portal/checkout UI actions.
- <button onClick={async () => await authClient.customer.portal()}> + <button onClick={async () => { try { await authClient.customer.portal(); } catch (e) { console.error(e); } }}> Manage Subscription </button> @@ - <button - onClick={async () => await authClient.checkout({ slug: "pro" })} - > + <button + onClick={async () => { try { await authClient.checkout({ slug: "pro" }); } catch (e) { console.error(e); } }} + > Upgrade to Pro </button>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/cli/templates/auth/better-auth/web/react/react-router/src/routes/dashboard.tsx.hbs
(3 hunks)apps/cli/templates/auth/better-auth/web/solid/src/routes/dashboard.tsx.hbs
(1 hunks)apps/cli/templates/auth/better-auth/web/svelte/src/routes/dashboard/+page.svelte.hbs
(3 hunks)apps/cli/templates/payments/polar/web/react/react-router/src/routes/success.tsx.hbs
(1 hunks)apps/cli/templates/payments/polar/web/solid/src/routes/success.tsx.hbs
(1 hunks)apps/cli/templates/payments/polar/web/svelte/src/routes/success/+page.svelte.hbs
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{hbs,handlebars}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
In Handlebars templates, avoid generic if/else blocks; write explicit conditions (e.g., if (eq orm "prisma") and else if (eq orm "drizzle")).
Files:
apps/cli/templates/payments/polar/web/solid/src/routes/success.tsx.hbs
apps/cli/templates/payments/polar/web/svelte/src/routes/success/+page.svelte.hbs
apps/cli/templates/payments/polar/web/react/react-router/src/routes/success.tsx.hbs
apps/cli/templates/auth/better-auth/web/react/react-router/src/routes/dashboard.tsx.hbs
apps/cli/templates/auth/better-auth/web/solid/src/routes/dashboard.tsx.hbs
apps/cli/templates/auth/better-auth/web/svelte/src/routes/dashboard/+page.svelte.hbs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cursor Bugbot
🔇 Additional comments (3)
apps/cli/templates/auth/better-auth/web/react/react-router/src/routes/dashboard.tsx.hbs (1)
1-1
: UI import addition looks good.apps/cli/templates/auth/better-auth/web/solid/src/routes/dashboard.tsx.hbs (2)
15-23
: Verify TanStack Router redirect usage.Many setups require
throw redirect({...})
rather than passingthrow: true
. Confirm the API in use.- if (!session.data) { - redirect({ - to: "/login", - throw: true, - }); - } + if (!session.data) { + throw redirect({ to: "/login" }); + }
41-45
: LGTM: API data wiring via Solid Query is consistent and clear.Also applies to: 57-58
apps/cli/templates/auth/better-auth/web/solid/src/routes/dashboard.tsx.hbs
Show resolved
Hide resolved
apps/cli/templates/auth/better-auth/web/svelte/src/routes/dashboard/+page.svelte.hbs
Show resolved
Hide resolved
apps/cli/templates/auth/better-auth/web/svelte/src/routes/dashboard/+page.svelte.hbs
Show resolved
Hide resolved
apps/cli/templates/payments/polar/web/react/react-router/src/routes/success.tsx.hbs
Show resolved
Hide resolved
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/cli/templates/frontend/solid/package.json.hbs (1)
5-10
: Fix: test script references Vitest but it’s not installed.Running
pnpm/npm run test
will fail sincevitest
isn’t in devDependencies.Apply this diff to add Vitest:
"devDependencies": { - "typescript": "^5.9.2", - "vite": "^7.1.5", - "vite-plugin-solid": "^2.11.8" + "typescript": "^5.9.2", + "vite": "^7.1.5", + "vite-plugin-solid": "^2.11.8", + "vitest": "^2.0.0" }Also applies to: 21-25
🧹 Nitpick comments (8)
apps/cli/templates/payments/polar/web/nuxt/app/pages/success.vue.hbs (1)
2-3
: Make query param reactive and type‑safe (avoid unsafe cast).
route.query.checkout_id
can bestring | string[] | undefined
. Casting tostring
is unsafe and non‑reactive. Prefer a computed that normalizes the value and updates if the route changes. Also switch to camelCase for consistency.<script setup lang="ts"> const route = useRoute() -const checkout_id = route.query.checkout_id as string +const checkoutId = computed(() => { + const v = route.query.checkout_id + return typeof v === 'string' ? v : Array.isArray(v) ? v[0] : undefined +}) </script> @@ - <p v-if="checkout_id">Checkout ID: \{{ checkout_id }}</p> + <p v-if="checkoutId">Checkout ID: \{{ checkoutId }}</p>apps/cli/templates/auth/better-auth/web/nuxt/app/pages/dashboard.vue.hbs (4)
14-16
: Replaceany
with a minimal type (orunknown
) for safer TS.Avoid
any
to preserve type-safety.Apply:
-const customerState = ref<any>(null) +const customerState = ref<CustomerState | null>(null)Add (outside this block):
type CustomerState = { activeSubscriptions?: Array<unknown> }
25-31
: Handle fetch errors; consider reacting to late session availability.Currently an exception from
customer.state()
is unhandled; also if session appears after mount, state won’t load. Minimal fix:onMounted(async () => { if (session.value?.data) { - const { data } = await $authClient.customer.state() - customerState.value = data + try { + const { data } = await $authClient.customer.state() + customerState.value = data + } catch (err) { + console.error('Failed to fetch customer state', err) + customerState.value = null + } } })Optional: switch to a
watch
on() => !!session.value?.data
to fetch when the user logs in after mount.
33-35
: Avoid non-null assertion; use nullish coalescing for correctness and typing.-const hasProSubscription = computed(() => - customerState.value?.activeSubscriptions?.length! > 0 -) +const hasProSubscription = computed(() => + ((customerState.value?.activeSubscriptions?.length) ?? 0) > 0 +)
52-64
: Prevent “Free” flicker before state loads and avoid arrow wrappers in handlers.Show plan only after
customerState
is loaded; call methods directly in@click
.- <p class="mb-2">Plan: \{{ hasProSubscription ? "Pro" : "Free" }}</p> - <UButton - v-if="hasProSubscription" - @click="(() => { $authClient.customer.portal() })" - > - Manage Subscription - </UButton> - <UButton - v-else - @click="(() => { $authClient.checkout({ slug: 'pro' }) })" - > - Upgrade to Pro - </UButton> + <template v-if="customerState !== null"> + <p class="mb-2">Plan: \{{ hasProSubscription ? 'Pro' : 'Free' }}</p> + <UButton + v-if="hasProSubscription" + @click="$authClient.customer.portal()" + > + Manage Subscription + </UButton> + <UButton + v-else + @click="$authClient.checkout({ slug: 'pro' })" + > + Upgrade to Pro + </UButton> + </template> + <p v-else class="mb-2 text-gray-500">Loading plan…</p>apps/cli/templates/frontend/solid/package.json.hbs (3)
12-18
: Reclassify build-time plugins to devDependencies.
@tailwindcss/vite
,@tanstack/router-plugin
, andtailwindcss
are build-time only; keeping them in dependencies bloats production installs.Apply this diff:
"dependencies": { - "@tailwindcss/vite": "^4.1.13", - "@tanstack/router-plugin": "^1.131.44", "@tanstack/solid-form": "^1.20.0", "@tanstack/solid-router": "^1.131.44", "lucide-solid": "^0.544.0", "solid-js": "^1.9.9", - "tailwindcss": "^4.1.13", "zod": "^4.0.2" }, "devDependencies": { "typescript": "^5.9.2", "vite": "^7.1.5", - "vite-plugin-solid": "^2.11.8" + "vite-plugin-solid": "^2.11.8", + "@tailwindcss/vite": "^4.1.13", + "@tanstack/router-plugin": "^1.131.44", + "tailwindcss": "^4.1.13" }Also applies to: 21-25
1-4
: Add Node engine constraints (Vite/Tailwind v4 require modern Node).Prevents cryptic runtime errors on older Node.
Apply this diff:
{ "name": "web", "private": true, "type": "module", + "engines": { + "node": ">=18.18 || >=20" + },
12-18
: Avoid version drift: pull versions from the central map inconstants.ts
.If the CLI already maintains a
dependencyVersionMap
, render these with Handlebars variables instead of hard-coding here to keep templates in sync.Also applies to: 21-25
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
apps/cli/src/constants.ts
(4 hunks)apps/cli/templates/auth/better-auth/web/nuxt/app/pages/dashboard.vue.hbs
(2 hunks)apps/cli/templates/auth/better-auth/web/solid/src/routes/dashboard.tsx.hbs
(1 hunks)apps/cli/templates/frontend/solid/package.json.hbs
(1 hunks)apps/cli/templates/payments/polar/web/nuxt/app/pages/success.vue.hbs
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/cli/templates/auth/better-auth/web/solid/src/routes/dashboard.tsx.hbs
- apps/cli/src/constants.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{hbs,handlebars}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
In Handlebars templates, avoid generic if/else blocks; write explicit conditions (e.g., if (eq orm "prisma") and else if (eq orm "drizzle")).
Files:
apps/cli/templates/payments/polar/web/nuxt/app/pages/success.vue.hbs
apps/cli/templates/auth/better-auth/web/nuxt/app/pages/dashboard.vue.hbs
apps/cli/templates/frontend/solid/package.json.hbs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cursor Bugbot
🔇 Additional comments (3)
apps/cli/templates/payments/polar/web/nuxt/app/pages/success.vue.hbs (1)
9-9
: Good use of Handlebars escaping for Vue mustache.
\{{ ... }}
correctly preserves Vue interpolation in a .hbs file. Ensure consistency across other Vue-in-HBS templates.apps/cli/templates/auth/better-auth/web/nuxt/app/pages/dashboard.vue.hbs (2)
19-23
: LGTM: gated query with reactiveenabled
.Good use of
useQuery
+enabled
tied to session state.
49-50
: LGTM: status handling + label tweak.Status branches look correct for TanStack Query v5; “API” label reads clearer.
const hasProSubscription = computed(() => | ||
customerState.value?.activeSubscriptions?.length! > 0 | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Misused Non-Null Assertion with Optional Chaining
The non-null assertion operator !
is incorrectly used on length
in expressions like customerState?.activeSubscriptions?.length! > 0
. Since optional chaining can result in undefined
for length
, this assertion is misleading and represents incorrect TypeScript usage across several dashboard templates.
Additional Locations (5)
apps/cli/templates/auth/better-auth/web/react/react-router/src/routes/dashboard.tsx.hbs#L52-L53
apps/cli/templates/auth/better-auth/web/react/tanstack-router/src/routes/dashboard.tsx.hbs#L43-L45
apps/cli/templates/auth/better-auth/web/react/next/src/app/dashboard/dashboard.tsx.hbs#L31-L32
apps/cli/templates/auth/better-auth/web/react/tanstack-start/src/routes/dashboard.tsx.hbs#L43-L44
apps/cli/templates/auth/better-auth/web/solid/src/routes/dashboard.tsx.hbs#L39-L41
Summary by CodeRabbit
New Features
UI / Tools
Chores
Tests