@better-t-stack/template-generator 3.26.0 → 3.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -705,8 +705,8 @@ function renameDevScriptsForAlchemy(vfs, config) {
705
705
  //#region src/utils/add-deps.ts
706
706
  const dependencyVersionMap = {
707
707
  typescript: "^5",
708
- "better-auth": "1.5.2",
709
- "@better-auth/expo": "1.5.2",
708
+ "better-auth": "1.5.5",
709
+ "@better-auth/expo": "1.5.5",
710
710
  "@clerk/backend": "^3.2.1",
711
711
  "@clerk/express": "^2.0.5",
712
712
  "@clerk/fastify": "^3.1.3",
@@ -776,17 +776,17 @@ const dependencyVersionMap = {
776
776
  "@orpc/openapi": "^1.12.2",
777
777
  "@orpc/zod": "^1.12.2",
778
778
  "@orpc/tanstack-query": "^1.13.6",
779
- "@trpc/tanstack-react-query": "^11.7.2",
780
- "@trpc/server": "^11.7.2",
781
- "@trpc/client": "^11.7.2",
779
+ "@trpc/tanstack-react-query": "^11.13.4",
780
+ "@trpc/server": "^11.13.4",
781
+ "@trpc/client": "^11.13.4",
782
782
  next: "^16.2.0",
783
- convex: "^1.32.0",
783
+ convex: "^1.33.1",
784
784
  "@convex-dev/react-query": "^0.1.0",
785
785
  "@convex-dev/agent": "^0.3.2",
786
786
  "convex-svelte": "^0.0.12",
787
787
  "convex-nuxt": "0.1.5",
788
788
  "convex-vue": "^0.1.5",
789
- "@convex-dev/better-auth": "^0.10.13",
789
+ "@convex-dev/better-auth": "^0.11.3",
790
790
  "@tanstack/svelte-query": "^5.85.3",
791
791
  "@tanstack/svelte-query-devtools": "^5.85.3",
792
792
  "@tanstack/vue-query-devtools": "^6.1.5",
@@ -815,7 +815,7 @@ const dependencyVersionMap = {
815
815
  "@t3-oss/env-core": "^0.13.1",
816
816
  "@t3-oss/env-nextjs": "^0.13.1",
817
817
  "@t3-oss/env-nuxt": "^0.13.1",
818
- "@polar-sh/better-auth": "^1.6.4",
818
+ "@polar-sh/better-auth": "^1.8.3",
819
819
  "@polar-sh/sdk": "^0.42.2"
820
820
  };
821
821
  /**
@@ -1335,6 +1335,7 @@ function addConvexDeps(vfs, frontend, frontendType) {
1335
1335
 
1336
1336
  //#endregion
1337
1337
  //#region src/processors/auth-deps.ts
1338
+ const CONVEX_BETTER_AUTH_VERSION = "1.5.3";
1338
1339
  function processAuthDeps(vfs, config) {
1339
1340
  const { auth, backend } = config;
1340
1341
  if (!auth || auth === "none") return;
@@ -1396,13 +1397,13 @@ function processConvexAuthDeps(vfs, config) {
1396
1397
  vfs,
1397
1398
  packagePath: backendPath,
1398
1399
  dependencies: ["better-auth", "@convex-dev/better-auth"],
1399
- customDependencies: { "better-auth": "1.4.9" }
1400
+ customDependencies: { "better-auth": CONVEX_BETTER_AUTH_VERSION }
1400
1401
  });
1401
1402
  if (hasNative) addPackageDependency({
1402
1403
  vfs,
1403
1404
  packagePath: backendPath,
1404
1405
  dependencies: ["@better-auth/expo"],
1405
- customDependencies: { "@better-auth/expo": "1.4.9" }
1406
+ customDependencies: { "@better-auth/expo": CONVEX_BETTER_AUTH_VERSION }
1406
1407
  });
1407
1408
  }
1408
1409
  if (webExists) {
@@ -1410,7 +1411,7 @@ function processConvexAuthDeps(vfs, config) {
1410
1411
  vfs,
1411
1412
  packagePath: webPath,
1412
1413
  dependencies: ["better-auth", "@convex-dev/better-auth"],
1413
- customDependencies: { "better-auth": "1.4.9" }
1414
+ customDependencies: { "better-auth": CONVEX_BETTER_AUTH_VERSION }
1414
1415
  });
1415
1416
  if (hasReactWebAuthForms) addPackageDependency({
1416
1417
  vfs,
@@ -1438,8 +1439,8 @@ function processConvexAuthDeps(vfs, config) {
1438
1439
  "@tanstack/react-form"
1439
1440
  ],
1440
1441
  customDependencies: {
1441
- "better-auth": "1.4.9",
1442
- "@better-auth/expo": "1.4.9"
1442
+ "better-auth": CONVEX_BETTER_AUTH_VERSION,
1443
+ "@better-auth/expo": CONVEX_BETTER_AUTH_VERSION
1443
1444
  }
1444
1445
  });
1445
1446
  }
@@ -1878,9 +1879,16 @@ function processEnvDeps(vfs, config) {
1878
1879
  if (!vfs.exists(envPath)) return;
1879
1880
  const { frontend, backend, runtime } = config;
1880
1881
  const deps = ["zod"];
1881
- if (frontend.includes("next")) deps.push("@t3-oss/env-nextjs");
1882
- else if (frontend.includes("nuxt")) deps.push("@t3-oss/env-nuxt");
1883
- else deps.push("@t3-oss/env-core");
1882
+ const hasNative = frontend.some((value) => [
1883
+ "native-bare",
1884
+ "native-uniwind",
1885
+ "native-unistyles"
1886
+ ].includes(value));
1887
+ const hasNextJs = frontend.includes("next");
1888
+ const hasNuxt = frontend.includes("nuxt");
1889
+ if (hasNextJs) deps.push("@t3-oss/env-nextjs");
1890
+ else if (hasNuxt) deps.push("@t3-oss/env-nuxt");
1891
+ if (hasNative || !hasNextJs && !hasNuxt) deps.push("@t3-oss/env-core");
1884
1892
  if (backend !== "convex" && backend !== "none" && runtime !== "workers" && !deps.includes("@t3-oss/env-core")) deps.push("@t3-oss/env-core");
1885
1893
  addPackageDependency({
1886
1894
  vfs,
@@ -2050,7 +2058,7 @@ function buildConvexBackendVars(frontend, auth, examples) {
2050
2058
  const hasNextJs = frontend.includes("next");
2051
2059
  const hasNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
2052
2060
  const hasWeb = frontend.includes("react-router") || frontend.includes("tanstack-router") || frontend.includes("tanstack-start") || hasNextJs || frontend.includes("nuxt") || frontend.includes("solid") || frontend.includes("svelte") || frontend.includes("astro");
2053
- const defaultSiteUrl = hasNative && !hasWeb ? "http://localhost:8081" : "http://localhost:3001";
2061
+ const defaultSiteUrl = hasNative && !hasWeb ? "http://localhost:8081" : frontend.includes("react-router") || frontend.includes("tanstack-router") || frontend.includes("svelte") ? "http://localhost:5173" : frontend.includes("astro") ? "http://localhost:4321" : "http://localhost:3001";
2054
2062
  const vars = [];
2055
2063
  if (examples?.includes("ai")) vars.push({
2056
2064
  key: "GOOGLE_GENERATIVE_AI_API_KEY",
@@ -2088,7 +2096,7 @@ function buildConvexBackendVars(frontend, auth, examples) {
2088
2096
  function buildConvexCommentBlocks(frontend, auth, examples) {
2089
2097
  const hasNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
2090
2098
  const hasWeb = frontend.includes("react-router") || frontend.includes("tanstack-router") || frontend.includes("tanstack-start") || frontend.includes("next") || frontend.includes("nuxt") || frontend.includes("solid") || frontend.includes("svelte") || frontend.includes("astro");
2091
- const defaultSiteUrl = hasNative && !hasWeb ? "http://localhost:8081" : "http://localhost:3001";
2099
+ const defaultSiteUrl = hasNative && !hasWeb ? "http://localhost:8081" : frontend.includes("react-router") || frontend.includes("tanstack-router") || frontend.includes("svelte") ? "http://localhost:5173" : frontend.includes("astro") ? "http://localhost:4321" : "http://localhost:3001";
2092
2100
  let commentBlocks = "";
2093
2101
  if (examples?.includes("ai")) commentBlocks += `# Set Google AI API key for AI agent
2094
2102
  # npx convex env set GOOGLE_GENERATIVE_AI_API_KEY=your_google_api_key
@@ -2101,11 +2109,12 @@ ${hasWeb || hasNative ? `# npx convex env set SITE_URL ${defaultSiteUrl}\n` : ""
2101
2109
  }
2102
2110
  function buildServerVars(backend, frontend, auth, api, database, dbSetup, runtime, webDeploy, serverDeploy, payments, examples) {
2103
2111
  const hasReactRouter = frontend.includes("react-router");
2112
+ const hasTanStackRouter = frontend.includes("tanstack-router");
2104
2113
  const hasSvelte = frontend.includes("svelte");
2105
2114
  const hasAstro = frontend.includes("astro");
2106
2115
  let corsOrigin = "http://localhost:3001";
2107
2116
  if (hasAstro) corsOrigin = "http://localhost:4321";
2108
- else if (hasReactRouter || hasSvelte) corsOrigin = "http://localhost:5173";
2117
+ else if (hasReactRouter || hasTanStackRouter || hasSvelte) corsOrigin = "http://localhost:5173";
2109
2118
  else if (backend === "self") corsOrigin = "http://localhost:3001";
2110
2119
  let databaseUrl = null;
2111
2120
  if (database !== "none" && dbSetup === "none") switch (database) {
@@ -2615,6 +2624,7 @@ function generateReadmeContent(options) {
2615
2624
  const { projectName, packageManager, database, auth, addons = [], orm = "drizzle", runtime = "bun", frontend = ["tanstack-router"], backend = "hono", api = "trpc", webDeploy, serverDeploy } = options;
2616
2625
  const isConvex = backend === "convex";
2617
2626
  const hasReactRouter = frontend.includes("react-router");
2627
+ const hasTanStackRouter = frontend.includes("tanstack-router");
2618
2628
  const hasNative = hasNativeFrontend(frontend);
2619
2629
  const hasReactWeb = frontend.some((f) => [
2620
2630
  "tanstack-router",
@@ -2625,7 +2635,7 @@ function generateReadmeContent(options) {
2625
2635
  const hasSvelte = frontend.includes("svelte");
2626
2636
  const hasAstro = frontend.includes("astro");
2627
2637
  const packageManagerRunCmd = `${packageManager} run`;
2628
- const webPort = hasReactRouter || hasSvelte ? "5173" : hasAstro ? "4321" : "3001";
2638
+ const webPort = hasReactRouter || hasTanStackRouter || hasSvelte ? "5173" : hasAstro ? "4321" : "3001";
2629
2639
  const stackDescription = generateStackDescription(frontend, backend, api, isConvex);
2630
2640
  return `# ${projectName}
2631
2641
 
@@ -5869,7 +5879,14 @@ import { authComponent, createAuth } from "./auth";
5869
5879
  const http = httpRouter();
5870
5880
 
5871
5881
  {{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles") (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
5882
+ {{#if (or (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
5883
+ authComponent.registerRoutesLazy(http, createAuth, {
5884
+ cors: true,
5885
+ trustedOrigins: [process.env.SITE_URL!],
5886
+ });
5887
+ {{else}}
5872
5888
  authComponent.registerRoutes(http, createAuth, { cors: true });
5889
+ {{/if}}
5873
5890
  {{else}}
5874
5891
  authComponent.registerRoutes(http, createAuth);
5875
5892
  {{/if}}
@@ -7585,6 +7602,402 @@ export const {
7585
7602
  convexUrl: env.NEXT_PUBLIC_CONVEX_URL,
7586
7603
  convexSiteUrl: env.NEXT_PUBLIC_CONVEX_SITE_URL,
7587
7604
  });
7605
+ `],
7606
+ ["auth/better-auth/convex/web/react/react-router/src/components/sign-in-form.tsx.hbs", `import { authClient } from "@/lib/auth-client";
7607
+ import { useForm } from "@tanstack/react-form";
7608
+ import { useNavigate } from "react-router";
7609
+ import { toast } from "sonner";
7610
+ import z from "zod";
7611
+ import { Button } from "@{{projectName}}/ui/components/button";
7612
+ import { Input } from "@{{projectName}}/ui/components/input";
7613
+ import { Label } from "@{{projectName}}/ui/components/label";
7614
+
7615
+ export default function SignInForm({
7616
+ onSwitchToSignUp,
7617
+ }: {
7618
+ onSwitchToSignUp: () => void;
7619
+ }) {
7620
+ const navigate = useNavigate();
7621
+
7622
+ const form = useForm({
7623
+ defaultValues: {
7624
+ email: "",
7625
+ password: "",
7626
+ },
7627
+ onSubmit: async ({ value }) => {
7628
+ await authClient.signIn.email(
7629
+ {
7630
+ email: value.email,
7631
+ password: value.password,
7632
+ },
7633
+ {
7634
+ onSuccess: () => {
7635
+ navigate("/dashboard");
7636
+ toast.success("Sign in successful");
7637
+ },
7638
+ onError: (error) => {
7639
+ toast.error(error.error.message || error.error.statusText);
7640
+ },
7641
+ },
7642
+ );
7643
+ },
7644
+ validators: {
7645
+ onSubmit: z.object({
7646
+ email: z.email("Invalid email address"),
7647
+ password: z.string().min(8, "Password must be at least 8 characters"),
7648
+ }),
7649
+ },
7650
+ });
7651
+
7652
+ return (
7653
+ <div className="mx-auto mt-10 w-full max-w-md p-6">
7654
+ <h1 className="mb-6 text-center text-3xl font-bold">Welcome Back</h1>
7655
+
7656
+ <form
7657
+ onSubmit={(e) => {
7658
+ e.preventDefault();
7659
+ e.stopPropagation();
7660
+ form.handleSubmit();
7661
+ }}
7662
+ className="space-y-4"
7663
+ >
7664
+ <div>
7665
+ <form.Field name="email">
7666
+ {(field) => (
7667
+ <div className="space-y-2">
7668
+ <Label htmlFor={field.name}>Email</Label>
7669
+ <Input
7670
+ id={field.name}
7671
+ name={field.name}
7672
+ type="email"
7673
+ value={field.state.value}
7674
+ onBlur={field.handleBlur}
7675
+ onChange={(e) => field.handleChange(e.target.value)}
7676
+ />
7677
+ {field.state.meta.errors.map((error, index) => (
7678
+ <p key={\`\${field.name}-error-\${index}\`} className="text-red-500">
7679
+ {error?.message}
7680
+ </p>
7681
+ ))}
7682
+ </div>
7683
+ )}
7684
+ </form.Field>
7685
+ </div>
7686
+
7687
+ <div>
7688
+ <form.Field name="password">
7689
+ {(field) => (
7690
+ <div className="space-y-2">
7691
+ <Label htmlFor={field.name}>Password</Label>
7692
+ <Input
7693
+ id={field.name}
7694
+ name={field.name}
7695
+ type="password"
7696
+ value={field.state.value}
7697
+ onBlur={field.handleBlur}
7698
+ onChange={(e) => field.handleChange(e.target.value)}
7699
+ />
7700
+ {field.state.meta.errors.map((error, index) => (
7701
+ <p key={\`\${field.name}-error-\${index}\`} className="text-red-500">
7702
+ {error?.message}
7703
+ </p>
7704
+ ))}
7705
+ </div>
7706
+ )}
7707
+ </form.Field>
7708
+ </div>
7709
+
7710
+ <form.Subscribe
7711
+ selector={(state) => ({
7712
+ canSubmit: state.canSubmit,
7713
+ isSubmitting: state.isSubmitting,
7714
+ })}
7715
+ >
7716
+ {({ canSubmit, isSubmitting }) => (
7717
+ <Button type="submit" className="w-full" disabled={!canSubmit || isSubmitting}>
7718
+ {isSubmitting ? "Submitting..." : "Sign In"}
7719
+ </Button>
7720
+ )}
7721
+ </form.Subscribe>
7722
+ </form>
7723
+
7724
+ <div className="mt-4 text-center">
7725
+ <Button
7726
+ variant="link"
7727
+ onClick={onSwitchToSignUp}
7728
+ className="text-indigo-600 hover:text-indigo-800"
7729
+ >
7730
+ Need an account? Sign Up
7731
+ </Button>
7732
+ </div>
7733
+ </div>
7734
+ );
7735
+ }
7736
+ `],
7737
+ ["auth/better-auth/convex/web/react/react-router/src/components/sign-up-form.tsx.hbs", `import { authClient } from "@/lib/auth-client";
7738
+ import { useForm } from "@tanstack/react-form";
7739
+ import { useNavigate } from "react-router";
7740
+ import { toast } from "sonner";
7741
+ import z from "zod";
7742
+ import { Button } from "@{{projectName}}/ui/components/button";
7743
+ import { Input } from "@{{projectName}}/ui/components/input";
7744
+ import { Label } from "@{{projectName}}/ui/components/label";
7745
+
7746
+ export default function SignUpForm({
7747
+ onSwitchToSignIn,
7748
+ }: {
7749
+ onSwitchToSignIn: () => void;
7750
+ }) {
7751
+ const navigate = useNavigate();
7752
+
7753
+ const form = useForm({
7754
+ defaultValues: {
7755
+ email: "",
7756
+ password: "",
7757
+ name: "",
7758
+ },
7759
+ onSubmit: async ({ value }) => {
7760
+ await authClient.signUp.email(
7761
+ {
7762
+ email: value.email,
7763
+ password: value.password,
7764
+ name: value.name,
7765
+ },
7766
+ {
7767
+ onSuccess: () => {
7768
+ navigate("/dashboard");
7769
+ toast.success("Sign up successful");
7770
+ },
7771
+ onError: (error) => {
7772
+ toast.error(error.error.message || error.error.statusText);
7773
+ },
7774
+ },
7775
+ );
7776
+ },
7777
+ validators: {
7778
+ onSubmit: z.object({
7779
+ name: z.string().min(2, "Name must be at least 2 characters"),
7780
+ email: z.email("Invalid email address"),
7781
+ password: z.string().min(8, "Password must be at least 8 characters"),
7782
+ }),
7783
+ },
7784
+ });
7785
+
7786
+ return (
7787
+ <div className="mx-auto mt-10 w-full max-w-md p-6">
7788
+ <h1 className="mb-6 text-center text-3xl font-bold">Create Account</h1>
7789
+
7790
+ <form
7791
+ onSubmit={(e) => {
7792
+ e.preventDefault();
7793
+ e.stopPropagation();
7794
+ form.handleSubmit();
7795
+ }}
7796
+ className="space-y-4"
7797
+ >
7798
+ <div>
7799
+ <form.Field name="name">
7800
+ {(field) => (
7801
+ <div className="space-y-2">
7802
+ <Label htmlFor={field.name}>Name</Label>
7803
+ <Input
7804
+ id={field.name}
7805
+ name={field.name}
7806
+ value={field.state.value}
7807
+ onBlur={field.handleBlur}
7808
+ onChange={(e) => field.handleChange(e.target.value)}
7809
+ />
7810
+ {field.state.meta.errors.map((error, index) => (
7811
+ <p key={\`\${field.name}-error-\${index}\`} className="text-red-500">
7812
+ {error?.message}
7813
+ </p>
7814
+ ))}
7815
+ </div>
7816
+ )}
7817
+ </form.Field>
7818
+ </div>
7819
+
7820
+ <div>
7821
+ <form.Field name="email">
7822
+ {(field) => (
7823
+ <div className="space-y-2">
7824
+ <Label htmlFor={field.name}>Email</Label>
7825
+ <Input
7826
+ id={field.name}
7827
+ name={field.name}
7828
+ type="email"
7829
+ value={field.state.value}
7830
+ onBlur={field.handleBlur}
7831
+ onChange={(e) => field.handleChange(e.target.value)}
7832
+ />
7833
+ {field.state.meta.errors.map((error, index) => (
7834
+ <p key={\`\${field.name}-error-\${index}\`} className="text-red-500">
7835
+ {error?.message}
7836
+ </p>
7837
+ ))}
7838
+ </div>
7839
+ )}
7840
+ </form.Field>
7841
+ </div>
7842
+
7843
+ <div>
7844
+ <form.Field name="password">
7845
+ {(field) => (
7846
+ <div className="space-y-2">
7847
+ <Label htmlFor={field.name}>Password</Label>
7848
+ <Input
7849
+ id={field.name}
7850
+ name={field.name}
7851
+ type="password"
7852
+ value={field.state.value}
7853
+ onBlur={field.handleBlur}
7854
+ onChange={(e) => field.handleChange(e.target.value)}
7855
+ />
7856
+ {field.state.meta.errors.map((error, index) => (
7857
+ <p key={\`\${field.name}-error-\${index}\`} className="text-red-500">
7858
+ {error?.message}
7859
+ </p>
7860
+ ))}
7861
+ </div>
7862
+ )}
7863
+ </form.Field>
7864
+ </div>
7865
+
7866
+ <form.Subscribe
7867
+ selector={(state) => ({
7868
+ canSubmit: state.canSubmit,
7869
+ isSubmitting: state.isSubmitting,
7870
+ })}
7871
+ >
7872
+ {({ canSubmit, isSubmitting }) => (
7873
+ <Button type="submit" className="w-full" disabled={!canSubmit || isSubmitting}>
7874
+ {isSubmitting ? "Submitting..." : "Sign Up"}
7875
+ </Button>
7876
+ )}
7877
+ </form.Subscribe>
7878
+ </form>
7879
+
7880
+ <div className="mt-4 text-center">
7881
+ <Button
7882
+ variant="link"
7883
+ onClick={onSwitchToSignIn}
7884
+ className="text-indigo-600 hover:text-indigo-800"
7885
+ >
7886
+ Already have an account? Sign In
7887
+ </Button>
7888
+ </div>
7889
+ </div>
7890
+ );
7891
+ }
7892
+ `],
7893
+ ["auth/better-auth/convex/web/react/react-router/src/components/user-menu.tsx.hbs", `import { useNavigate } from "react-router";
7894
+
7895
+ import {
7896
+ DropdownMenu,
7897
+ DropdownMenuContent,
7898
+ DropdownMenuGroup,
7899
+ DropdownMenuItem,
7900
+ DropdownMenuLabel,
7901
+ DropdownMenuSeparator,
7902
+ DropdownMenuTrigger,
7903
+ } from "@{{projectName}}/ui/components/dropdown-menu";
7904
+ import { authClient } from "@/lib/auth-client";
7905
+ import { useQuery } from "convex/react";
7906
+ import { api } from "@{{projectName}}/backend/convex/_generated/api";
7907
+
7908
+ import { Button } from "@{{projectName}}/ui/components/button";
7909
+
7910
+ export default function UserMenu() {
7911
+ const navigate = useNavigate();
7912
+ const user = useQuery(api.auth.getCurrentUser);
7913
+
7914
+ return (
7915
+ <DropdownMenu>
7916
+ <DropdownMenuTrigger render={<Button variant="outline" />}>
7917
+ {user?.name}
7918
+ </DropdownMenuTrigger>
7919
+ <DropdownMenuContent className="bg-card">
7920
+ <DropdownMenuGroup>
7921
+ <DropdownMenuLabel>My Account</DropdownMenuLabel>
7922
+ <DropdownMenuSeparator />
7923
+ <DropdownMenuItem>{user?.email}</DropdownMenuItem>
7924
+ <DropdownMenuItem
7925
+ variant="destructive"
7926
+ onClick={() => {
7927
+ authClient.signOut({
7928
+ fetchOptions: {
7929
+ onSuccess: () => {
7930
+ navigate("/dashboard");
7931
+ },
7932
+ },
7933
+ });
7934
+ }}
7935
+ >
7936
+ Sign Out
7937
+ </DropdownMenuItem>
7938
+ </DropdownMenuGroup>
7939
+ </DropdownMenuContent>
7940
+ </DropdownMenu>
7941
+ );
7942
+ }
7943
+ `],
7944
+ ["auth/better-auth/convex/web/react/react-router/src/lib/auth-client.ts.hbs", `import { createAuthClient } from "better-auth/react";
7945
+ import {
7946
+ convexClient,
7947
+ crossDomainClient,
7948
+ } from "@convex-dev/better-auth/client/plugins";
7949
+ import { env } from "@{{projectName}}/env/web";
7950
+
7951
+ export const authClient = createAuthClient({
7952
+ baseURL: env.VITE_CONVEX_SITE_URL,
7953
+ plugins: [crossDomainClient(), convexClient()],
7954
+ });
7955
+ `],
7956
+ ["auth/better-auth/convex/web/react/react-router/src/routes/dashboard.tsx.hbs", `import SignInForm from "@/components/sign-in-form";
7957
+ import SignUpForm from "@/components/sign-up-form";
7958
+ import UserMenu from "@/components/user-menu";
7959
+ import { api } from "@{{projectName}}/backend/convex/_generated/api";
7960
+ import {
7961
+ Authenticated,
7962
+ AuthLoading,
7963
+ Unauthenticated,
7964
+ useQuery,
7965
+ } from "convex/react";
7966
+ import { useState } from "react";
7967
+
7968
+ function PrivateDashboardContent() {
7969
+ const privateData = useQuery(api.privateData.get);
7970
+
7971
+ return (
7972
+ <div>
7973
+ <h1>Dashboard</h1>
7974
+ <p>privateData: {privateData?.message}</p>
7975
+ <UserMenu />
7976
+ </div>
7977
+ );
7978
+ }
7979
+
7980
+ export default function Dashboard() {
7981
+ const [showSignIn, setShowSignIn] = useState(false);
7982
+
7983
+ return (
7984
+ <>
7985
+ <Authenticated>
7986
+ <PrivateDashboardContent />
7987
+ </Authenticated>
7988
+ <Unauthenticated>
7989
+ {showSignIn ? (
7990
+ <SignInForm onSwitchToSignUp={() => setShowSignIn(false)} />
7991
+ ) : (
7992
+ <SignUpForm onSwitchToSignIn={() => setShowSignIn(true)} />
7993
+ )}
7994
+ </Unauthenticated>
7995
+ <AuthLoading>
7996
+ <div>Loading...</div>
7997
+ </AuthLoading>
7998
+ </>
7999
+ );
8000
+ }
7588
8001
  `],
7589
8002
  ["auth/better-auth/convex/web/react/tanstack-router/src/components/sign-in-form.tsx.hbs", `import { authClient } from "@/lib/auth-client";
7590
8003
  import { useForm } from "@tanstack/react-form";
@@ -7661,8 +8074,8 @@ export default function SignInForm({
7661
8074
  onBlur={field.handleBlur}
7662
8075
  onChange={(e) => field.handleChange(e.target.value)}
7663
8076
  />
7664
- {field.state.meta.errors.map((error) => (
7665
- <p key={error?.message} className="text-red-500">
8077
+ {field.state.meta.errors.map((error, index) => (
8078
+ <p key={\`\${field.name}-error-\${index}\`} className="text-red-500">
7666
8079
  {error?.message}
7667
8080
  </p>
7668
8081
  ))}
@@ -7684,8 +8097,8 @@ export default function SignInForm({
7684
8097
  onBlur={field.handleBlur}
7685
8098
  onChange={(e) => field.handleChange(e.target.value)}
7686
8099
  />
7687
- {field.state.meta.errors.map((error) => (
7688
- <p key={error?.message} className="text-red-500">
8100
+ {field.state.meta.errors.map((error, index) => (
8101
+ <p key={\`\${field.name}-error-\${index}\`} className="text-red-500">
7689
8102
  {error?.message}
7690
8103
  </p>
7691
8104
  ))}
@@ -7797,8 +8210,8 @@ export default function SignUpForm({
7797
8210
  onBlur={field.handleBlur}
7798
8211
  onChange={(e) => field.handleChange(e.target.value)}
7799
8212
  />
7800
- {field.state.meta.errors.map((error) => (
7801
- <p key={error?.message} className="text-red-500">
8213
+ {field.state.meta.errors.map((error, index) => (
8214
+ <p key={\`\${field.name}-error-\${index}\`} className="text-red-500">
7802
8215
  {error?.message}
7803
8216
  </p>
7804
8217
  ))}
@@ -7820,8 +8233,8 @@ export default function SignUpForm({
7820
8233
  onBlur={field.handleBlur}
7821
8234
  onChange={(e) => field.handleChange(e.target.value)}
7822
8235
  />
7823
- {field.state.meta.errors.map((error) => (
7824
- <p key={error?.message} className="text-red-500">
8236
+ {field.state.meta.errors.map((error, index) => (
8237
+ <p key={\`\${field.name}-error-\${index}\`} className="text-red-500">
7825
8238
  {error?.message}
7826
8239
  </p>
7827
8240
  ))}
@@ -7843,8 +8256,8 @@ export default function SignUpForm({
7843
8256
  onBlur={field.handleBlur}
7844
8257
  onChange={(e) => field.handleChange(e.target.value)}
7845
8258
  />
7846
- {field.state.meta.errors.map((error) => (
7847
- <p key={error?.message} className="text-red-500">
8259
+ {field.state.meta.errors.map((error, index) => (
8260
+ <p key={\`\${field.name}-error-\${index}\`} className="text-red-500">
7848
8261
  {error?.message}
7849
8262
  </p>
7850
8263
  ))}
@@ -7961,18 +8374,25 @@ export const Route = createFileRoute("/dashboard")({
7961
8374
  component: RouteComponent,
7962
8375
  });
7963
8376
 
8377
+ function PrivateDashboardContent() {
8378
+ const privateData = useQuery(api.privateData.get);
8379
+
8380
+ return (
8381
+ <div>
8382
+ <h1>Dashboard</h1>
8383
+ <p>privateData: {privateData?.message}</p>
8384
+ <UserMenu />
8385
+ </div>
8386
+ );
8387
+ }
8388
+
7964
8389
  function RouteComponent() {
7965
8390
  const [showSignIn, setShowSignIn] = useState(false);
7966
- const privateData = useQuery(api.privateData.get);
7967
8391
 
7968
8392
  return (
7969
8393
  <>
7970
8394
  <Authenticated>
7971
- <div>
7972
- <h1>Dashboard</h1>
7973
- <p>privateData: {privateData?.message}</p>
7974
- <UserMenu />
7975
- </div>
8395
+ <PrivateDashboardContent />
7976
8396
  </Authenticated>
7977
8397
  <Unauthenticated>
7978
8398
  {showSignIn ? (
@@ -24802,6 +25222,9 @@ export const unstable_settings = {
24802
25222
 
24803
25223
  {{#if (eq backend "convex")}}
24804
25224
  const convex = new ConvexReactClient(env.EXPO_PUBLIC_CONVEX_URL, {
25225
+ {{#if (eq auth "better-auth")}}
25226
+ expectAuth: true,
25227
+ {{/if}}
24805
25228
  unsavedChangesWarning: false,
24806
25229
  });
24807
25230
  {{/if}}
@@ -25850,6 +26273,9 @@ export const unstable_settings = {
25850
26273
 
25851
26274
  {{#if (eq backend "convex")}}
25852
26275
  const convex = new ConvexReactClient(env.EXPO_PUBLIC_CONVEX_URL, {
26276
+ {{#if (eq auth "better-auth")}}
26277
+ expectAuth: true,
26278
+ {{/if}}
25853
26279
  unsavedChangesWarning: false,
25854
26280
  });
25855
26281
  {{/if}}
@@ -27150,6 +27576,9 @@ export const unstable_settings = {
27150
27576
 
27151
27577
  {{#if (eq backend "convex")}}
27152
27578
  const convex = new ConvexReactClient(env.EXPO_PUBLIC_CONVEX_URL, {
27579
+ {{#if (eq auth "better-auth")}}
27580
+ expectAuth: true,
27581
+ {{/if}}
27153
27582
  unsavedChangesWarning: false,
27154
27583
  });
27155
27584
  {{/if}}
@@ -27946,7 +28375,7 @@ module.exports = uniwindConfig;
27946
28375
  "expo-secure-store": "~55.0.8",
27947
28376
  "expo-status-bar": "~55.0.4",
27948
28377
  "expo-web-browser": "~55.0.9",
27949
- "heroui-native": "^1.0.0-rc.3",
28378
+ "heroui-native": "^1.0.0",
27950
28379
  "react": "19.2.0",
27951
28380
  "react-dom": "19.2.0",
27952
28381
  "react-native": "0.83.2",
@@ -27960,8 +28389,8 @@ module.exports = uniwindConfig;
27960
28389
  "react-native-worklets": "0.7.2",
27961
28390
  "tailwind-merge": "^3.4.0",
27962
28391
  "tailwind-variants": "^3.2.2",
27963
- "tailwindcss": "^4.1.18",
27964
- "uniwind": "^1.4.0"
28392
+ "tailwindcss": "^4.2.2",
28393
+ "uniwind": "^1.6.0"
27965
28394
  },
27966
28395
  "devDependencies": {
27967
28396
  "@types/node": "^24.10.0",
@@ -28830,6 +29259,9 @@ import { ConvexReactClient } from "convex/react";
28830
29259
  import { env } from "@{{projectName}}/env/web";
28831
29260
  {{#if (eq auth "clerk")}}
28832
29261
  import { ConvexProviderWithClerk } from "convex/react-clerk";
29262
+ {{else if (eq auth "better-auth")}}
29263
+ import { ConvexBetterAuthProvider } from "@convex-dev/better-auth/react";
29264
+ import { authClient } from "@/lib/auth-client";
28833
29265
  {{else}}
28834
29266
  import { ConvexProvider } from "convex/react";
28835
29267
  {{/if}}
@@ -28899,10 +29331,18 @@ export function Layout({ children }: { children: React.ReactNode }) {
28899
29331
  {{#if (eq backend "convex")}}
28900
29332
  {{#if (eq auth "clerk")}}
28901
29333
  export default function App({ loaderData }: Route.ComponentProps) {
29334
+ {{else if (eq auth "better-auth")}}
29335
+ export default function App() {
28902
29336
  {{else}}
28903
29337
  export default function App() {
28904
29338
  {{/if}}
29339
+ {{#if (eq auth "better-auth")}}
29340
+ const convex = new ConvexReactClient(env.VITE_CONVEX_URL, {
29341
+ expectAuth: true,
29342
+ });
29343
+ {{else}}
28905
29344
  const convex = new ConvexReactClient(env.VITE_CONVEX_URL);
29345
+ {{/if}}
28906
29346
  {{#if (eq auth "clerk")}}
28907
29347
  return (
28908
29348
  <ClerkProvider loaderData={loaderData}>
@@ -28922,6 +29362,23 @@ export default function App() {
28922
29362
  </ConvexProviderWithClerk>
28923
29363
  </ClerkProvider>
28924
29364
  );
29365
+ {{else if (eq auth "better-auth")}}
29366
+ return (
29367
+ <ConvexBetterAuthProvider client={convex} authClient={authClient}>
29368
+ <ThemeProvider
29369
+ attribute="class"
29370
+ defaultTheme="dark"
29371
+ disableTransitionOnChange
29372
+ storageKey="vite-ui-theme"
29373
+ >
29374
+ <div className="grid grid-rows-[auto_1fr] h-svh">
29375
+ <Header />
29376
+ <Outlet />
29377
+ </div>
29378
+ <Toaster richColors />
29379
+ </ThemeProvider>
29380
+ </ConvexBetterAuthProvider>
29381
+ );
28925
29382
  {{else}}
28926
29383
  return (
28927
29384
  <ConvexProvider client={convex}>
@@ -29340,7 +29797,13 @@ import { routeTree } from "./routeTree.gen";
29340
29797
  {{else}}
29341
29798
  import { ConvexProvider } from "convex/react";
29342
29799
  {{/if}}
29800
+ {{#if (eq auth "better-auth")}}
29801
+ const convex = new ConvexReactClient(env.VITE_CONVEX_URL, {
29802
+ expectAuth: true,
29803
+ });
29804
+ {{else}}
29343
29805
  const convex = new ConvexReactClient(env.VITE_CONVEX_URL);
29806
+ {{/if}}
29344
29807
  {{/if}}
29345
29808
 
29346
29809
  {{#if (and (eq auth "clerk") (ne backend "convex") (ne api "none"))}}
@@ -32631,7 +33094,7 @@ function SuccessPage() {
32631
33094
  </div>
32632
33095
  `]
32633
33096
  ]);
32634
- const TEMPLATE_COUNT = 457;
33097
+ const TEMPLATE_COUNT = 462;
32635
33098
 
32636
33099
  //#endregion
32637
33100
  export { EMBEDDED_TEMPLATES, GeneratorError, Handlebars, TEMPLATE_COUNT, VirtualFileSystem, dependencyVersionMap, generate, generateReproducibleCommand, isBinaryFile, processAddonTemplates, processAddonsDeps, processFileContent, processTemplateString, transformFilename, writeBtsConfigToVfs };