feat(cli): add polar as better-auth plugin (#578)

This commit is contained in:
Aman Varshney
2025-09-16 17:53:44 +05:30
committed by GitHub
parent 3f22373cc3
commit ba3d62b6b9
77 changed files with 1221 additions and 308 deletions

View File

@@ -30,7 +30,8 @@ export function TechIcon({
icon.includes("prisma") ||
icon.includes("express") ||
icon.includes("clerk") ||
icon.includes("planetscale"))
icon.includes("planetscale") ||
icon.includes("polar"))
) {
iconSrc = icon.replace(".svg", "-light.svg");
}

View File

@@ -818,6 +818,64 @@ export const analyzeStackCompatibility = (
});
}
if (nextStack.payments === "polar") {
if (nextStack.auth !== "better-auth") {
notes.payments.notes.push(
"Polar payments requires Better Auth. Payments will be set to 'None'.",
);
notes.auth.notes.push(
"Polar payments requires Better Auth. Payments will be disabled.",
);
notes.payments.hasIssue = true;
notes.auth.hasIssue = true;
nextStack.payments = "none";
changed = true;
changes.push({
category: "payments",
message: "Payments set to 'None' (Polar requires Better Auth)",
});
}
if (nextStack.backend === "convex") {
notes.payments.notes.push(
"Polar payments is not compatible with Convex backend. Payments will be set to 'None'.",
);
notes.backend.notes.push(
"Polar payments is not compatible with Convex backend. Payments will be disabled.",
);
notes.payments.hasIssue = true;
notes.backend.hasIssue = true;
nextStack.payments = "none";
changed = true;
changes.push({
category: "payments",
message:
"Payments set to 'None' (Polar not compatible with Convex backend)",
});
}
const hasWebFrontend = nextStack.webFrontend.some((f) => f !== "none");
if (
!hasWebFrontend &&
nextStack.nativeFrontend.some((f) => f !== "none")
) {
notes.payments.notes.push(
"Polar payments requires a web frontend. Payments will be set to 'None'.",
);
notes.webFrontend.notes.push(
"Polar payments requires a web frontend. Payments will be disabled.",
);
notes.payments.hasIssue = true;
notes.webFrontend.hasIssue = true;
nextStack.payments = "none";
changed = true;
changes.push({
category: "payments",
message: "Payments set to 'None' (Polar requires web frontend)",
});
}
}
const incompatibleAddons: string[] = [];
const isPWACompat = hasPWACompatibleFrontend(nextStack.webFrontend);
const isTauriCompat = hasTauriCompatibleFrontend(nextStack.webFrontend);
@@ -1536,6 +1594,22 @@ export const getDisabledReason = (
}
}
if (category === "payments" && optionId === "polar") {
if (finalStack.auth !== "better-auth") {
return "Polar payments requires Better Auth. Select Better Auth first.";
}
if (finalStack.backend === "convex") {
return "Polar payments is not compatible with Convex backend. Try Hono, Express, Fastify, or Elysia.";
}
const hasWebFrontend = finalStack.webFrontend.some((f) => f !== "none");
if (
!hasWebFrontend &&
finalStack.nativeFrontend.some((f) => f !== "none")
) {
return "Polar payments requires a web frontend. Select a web frontend first.";
}
}
if (category === "dbSetup" && optionId === "planetscale") {
if (finalStack.database !== "postgres" && finalStack.database !== "mysql") {
return "PlanetScale requires PostgreSQL or MySQL database. Select PostgreSQL or MySQL first.";

View File

@@ -427,6 +427,24 @@ export const TECH_OPTIONS: Record<
color: "from-red-400 to-red-600",
},
],
payments: [
{
id: "polar",
name: "Polar",
description: "Turn your software into a business. 6 lines of code.",
icon: `${ICON_BASE_URL}/polar.svg`,
color: "from-purple-400 to-purple-600",
default: false,
},
{
id: "none",
name: "No Payments",
description: "Skip payments integration",
icon: "",
color: "from-gray-400 to-gray-600",
default: true,
},
],
packageManager: [
{
id: "npm",
@@ -604,6 +622,7 @@ export const PRESET_TEMPLATES = [
orm: "drizzle",
dbSetup: "none",
auth: "better-auth",
payments: "none",
packageManager: "bun",
addons: ["turborepo"],
examples: [],
@@ -629,6 +648,7 @@ export const PRESET_TEMPLATES = [
orm: "none",
dbSetup: "none",
auth: "none",
payments: "none",
packageManager: "bun",
addons: ["turborepo"],
examples: ["todo"],
@@ -654,6 +674,7 @@ export const PRESET_TEMPLATES = [
orm: "drizzle",
dbSetup: "none",
auth: "better-auth",
payments: "none",
packageManager: "bun",
addons: ["turborepo"],
examples: [],
@@ -679,6 +700,7 @@ export const PRESET_TEMPLATES = [
orm: "drizzle",
dbSetup: "none",
auth: "better-auth",
payments: "none",
packageManager: "bun",
addons: ["turborepo"],
examples: [],
@@ -704,6 +726,7 @@ export const PRESET_TEMPLATES = [
orm: "drizzle",
dbSetup: "turso",
auth: "better-auth",
payments: "polar",
packageManager: "bun",
addons: ["pwa", "biome", "husky", "tauri", "starlight", "turborepo"],
examples: ["todo", "ai"],
@@ -727,6 +750,7 @@ export type StackState = {
orm: string;
dbSetup: string;
auth: string;
payments: string;
packageManager: string;
addons: string[];
examples: string[];
@@ -748,6 +772,7 @@ export const DEFAULT_STACK: StackState = {
orm: "drizzle",
dbSetup: "none",
auth: "better-auth",
payments: "none",
packageManager: "bun",
addons: ["turborepo"],
examples: [],

View File

@@ -12,6 +12,7 @@ export const stackUrlKeys: UrlKeys<Record<keyof StackState, unknown>> = {
orm: "orm",
dbSetup: "dbs",
auth: "au",
payments: "pay",
packageManager: "pm",
addons: "add",
examples: "ex",

View File

@@ -43,6 +43,9 @@ export const stackParsers = {
auth: parseAsStringEnum<StackState["auth"]>(getValidIds("auth")).withDefault(
DEFAULT_STACK.auth,
),
payments: parseAsStringEnum<StackState["payments"]>(
getValidIds("payments"),
).withDefault(DEFAULT_STACK.payments),
packageManager: parseAsStringEnum<StackState["packageManager"]>(
getValidIds("packageManager"),
).withDefault(DEFAULT_STACK.packageManager),

View File

@@ -44,6 +44,9 @@ const serverStackParsers = {
auth: parseAsStringEnumServer<StackState["auth"]>(
getValidIds("auth"),
).withDefault(DEFAULT_STACK.auth),
payments: parseAsStringEnumServer<StackState["payments"]>(
getValidIds("payments"),
).withDefault(DEFAULT_STACK.payments),
packageManager: parseAsStringEnumServer<StackState["packageManager"]>(
getValidIds("packageManager"),
).withDefault(DEFAULT_STACK.packageManager),

View File

@@ -18,6 +18,7 @@ const CATEGORY_ORDER: Array<keyof typeof TECH_OPTIONS> = [
"webDeploy",
"serverDeploy",
"auth",
"payments",
"packageManager",
"addons",
"examples",
@@ -88,6 +89,7 @@ export function generateStackCommand(stack: StackState) {
`--runtime ${stack.runtime}`,
`--api ${stack.api}`,
`--auth ${stack.auth}`,
`--payments ${stack.payments}`,
`--database ${stack.database}`,
`--orm ${stack.orm}`,
`--db-setup ${stack.dbSetup}`,

View File

@@ -10,6 +10,7 @@ export type TechCategory =
| "webDeploy"
| "serverDeploy"
| "auth"
| "payments"
| "packageManager"
| "addons"
| "examples"