create-better-t-stack 2.37.0 → 2.38.0

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.
Files changed (111) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/index.d.ts +11 -5
  3. package/dist/index.js +1 -1
  4. package/dist/{src-CGVrE3la.js → src-BR5HLmM2.js} +266 -104
  5. package/package.json +1 -1
  6. package/templates/addons/ruler/.ruler/bts.md.hbs +2 -2
  7. package/templates/api/orpc/native/utils/orpc.ts.hbs +2 -2
  8. package/templates/api/orpc/server/base/src/lib/context.ts.hbs +10 -10
  9. package/templates/api/orpc/server/base/src/lib/orpc.ts.hbs +1 -1
  10. package/templates/api/orpc/server/next/src/app/rpc/[...all]/route.ts.hbs +2 -2
  11. package/templates/api/orpc/web/nuxt/app/plugins/orpc.ts.hbs +1 -1
  12. package/templates/api/orpc/web/react/base/src/utils/orpc.ts.hbs +11 -1
  13. package/templates/api/orpc/web/solid/src/utils/orpc.ts.hbs +1 -1
  14. package/templates/api/orpc/web/svelte/src/lib/orpc.ts.hbs +1 -1
  15. package/templates/api/trpc/native/utils/trpc.ts.hbs +2 -2
  16. package/templates/api/trpc/server/base/src/lib/context.ts.hbs +10 -10
  17. package/templates/api/trpc/server/base/src/lib/trpc.ts.hbs +1 -1
  18. package/templates/api/trpc/web/react/base/src/utils/trpc.ts.hbs +2 -2
  19. package/templates/auth/clerk/convex/backend/convex/auth.config.ts.hbs +12 -0
  20. package/templates/auth/clerk/convex/backend/convex/privateData.ts.hbs +16 -0
  21. package/templates/auth/clerk/convex/native/base/app/(auth)/_layout.tsx.hbs +12 -0
  22. package/templates/auth/clerk/convex/native/base/app/(auth)/sign-in.tsx.hbs +67 -0
  23. package/templates/auth/clerk/convex/native/base/app/(auth)/sign-out.tsx.hbs +110 -0
  24. package/templates/auth/clerk/convex/native/base/components/sign-out-button.tsx.hbs +27 -0
  25. package/templates/auth/clerk/convex/web/react/next/src/app/dashboard/page.tsx.hbs +29 -0
  26. package/templates/auth/clerk/convex/web/react/next/src/middleware.ts.hbs +12 -0
  27. package/templates/auth/clerk/convex/web/react/react-router/src/routes/dashboard.tsx.hbs +32 -0
  28. package/templates/auth/clerk/convex/web/react/tanstack-router/src/routes/dashboard.tsx.hbs +37 -0
  29. package/templates/auth/clerk/convex/web/react/tanstack-start/src/routes/dashboard.tsx.hbs +37 -0
  30. package/templates/auth/clerk/convex/web/react/tanstack-start/src/server.ts.hbs +18 -0
  31. package/templates/backend/convex/packages/backend/package.json.hbs +1 -0
  32. package/templates/backend/server/elysia/src/index.ts.hbs +3 -3
  33. package/templates/backend/server/express/src/index.ts.hbs +6 -6
  34. package/templates/backend/server/fastify/src/index.ts.hbs +4 -4
  35. package/templates/backend/server/hono/src/index.ts.hbs +4 -4
  36. package/templates/backend/server/server-base/src/routers/index.ts.hbs +4 -4
  37. package/templates/deploy/alchemy/alchemy.run.ts.hbs +2 -2
  38. package/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs +35 -3
  39. package/templates/frontend/native/nativewind/app/_layout.tsx.hbs +28 -0
  40. package/templates/frontend/native/nativewind/package.json.hbs +1 -0
  41. package/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs +32 -0
  42. package/templates/frontend/native/unistyles/app/_layout.tsx.hbs +35 -0
  43. package/templates/frontend/native/unistyles/package.json.hbs +1 -0
  44. package/templates/frontend/nuxt/app/components/Header.vue.hbs +3 -3
  45. package/templates/frontend/react/next/src/app/layout.tsx.hbs +23 -15
  46. package/templates/frontend/react/next/src/components/providers.tsx.hbs +12 -0
  47. package/templates/frontend/react/react-router/src/root.tsx.hbs +28 -1
  48. package/templates/frontend/react/tanstack-router/src/main.tsx.hbs +19 -1
  49. package/templates/frontend/react/tanstack-start/src/router.tsx.hbs +8 -4
  50. package/templates/frontend/react/tanstack-start/src/routes/__root.tsx.hbs +52 -5
  51. package/templates/frontend/react/web-base/src/components/header.tsx.hbs +3 -3
  52. package/templates/frontend/solid/src/components/header.tsx.hbs +3 -3
  53. package/templates/frontend/svelte/src/components/Header.svelte.hbs +3 -3
  54. /package/templates/auth/{native → better-auth/native}/native-base/lib/auth-client.ts.hbs +0 -0
  55. /package/templates/auth/{native → better-auth/native}/nativewind/app/(drawer)/index.tsx.hbs +0 -0
  56. /package/templates/auth/{native → better-auth/native}/nativewind/components/sign-in.tsx.hbs +0 -0
  57. /package/templates/auth/{native → better-auth/native}/nativewind/components/sign-up.tsx.hbs +0 -0
  58. /package/templates/auth/{native → better-auth/native}/unistyles/app/(drawer)/index.tsx.hbs +0 -0
  59. /package/templates/auth/{native → better-auth/native}/unistyles/components/sign-in.tsx.hbs +0 -0
  60. /package/templates/auth/{native → better-auth/native}/unistyles/components/sign-up.tsx.hbs +0 -0
  61. /package/templates/auth/{server → better-auth/server}/base/src/lib/auth.ts.hbs +0 -0
  62. /package/templates/auth/{server → better-auth/server}/db/drizzle/mysql/src/db/schema/auth.ts +0 -0
  63. /package/templates/auth/{server → better-auth/server}/db/drizzle/postgres/src/db/schema/auth.ts +0 -0
  64. /package/templates/auth/{server → better-auth/server}/db/drizzle/sqlite/src/db/schema/auth.ts +0 -0
  65. /package/templates/auth/{server → better-auth/server}/db/mongoose/mongodb/src/db/models/auth.model.ts +0 -0
  66. /package/templates/auth/{server → better-auth/server}/db/prisma/mongodb/prisma/schema/auth.prisma +0 -0
  67. /package/templates/auth/{server → better-auth/server}/db/prisma/mysql/prisma/schema/auth.prisma +0 -0
  68. /package/templates/auth/{server → better-auth/server}/db/prisma/postgres/prisma/schema/auth.prisma +0 -0
  69. /package/templates/auth/{server → better-auth/server}/db/prisma/sqlite/prisma/schema/auth.prisma +0 -0
  70. /package/templates/auth/{server → better-auth/server}/next/src/app/api/auth/[...all]/route.ts +0 -0
  71. /package/templates/auth/{web → better-auth/web}/nuxt/app/components/SignInForm.vue +0 -0
  72. /package/templates/auth/{web → better-auth/web}/nuxt/app/components/SignUpForm.vue +0 -0
  73. /package/templates/auth/{web → better-auth/web}/nuxt/app/components/UserMenu.vue +0 -0
  74. /package/templates/auth/{web → better-auth/web}/nuxt/app/middleware/auth.ts +0 -0
  75. /package/templates/auth/{web → better-auth/web}/nuxt/app/pages/dashboard.vue.hbs +0 -0
  76. /package/templates/auth/{web → better-auth/web}/nuxt/app/pages/login.vue +0 -0
  77. /package/templates/auth/{web → better-auth/web}/nuxt/app/plugins/auth-client.ts +0 -0
  78. /package/templates/auth/{web → better-auth/web}/react/base/src/lib/auth-client.ts.hbs +0 -0
  79. /package/templates/auth/{web → better-auth/web}/react/next/src/app/dashboard/page.tsx.hbs +0 -0
  80. /package/templates/auth/{web → better-auth/web}/react/next/src/app/login/page.tsx +0 -0
  81. /package/templates/auth/{web → better-auth/web}/react/next/src/components/sign-in-form.tsx +0 -0
  82. /package/templates/auth/{web → better-auth/web}/react/next/src/components/sign-up-form.tsx +0 -0
  83. /package/templates/auth/{web → better-auth/web}/react/next/src/components/theme-provider.tsx +0 -0
  84. /package/templates/auth/{web → better-auth/web}/react/next/src/components/user-menu.tsx +0 -0
  85. /package/templates/auth/{web → better-auth/web}/react/react-router/src/components/sign-in-form.tsx +0 -0
  86. /package/templates/auth/{web → better-auth/web}/react/react-router/src/components/sign-up-form.tsx +0 -0
  87. /package/templates/auth/{web → better-auth/web}/react/react-router/src/components/user-menu.tsx +0 -0
  88. /package/templates/auth/{web → better-auth/web}/react/react-router/src/routes/dashboard.tsx.hbs +0 -0
  89. /package/templates/auth/{web → better-auth/web}/react/react-router/src/routes/login.tsx +0 -0
  90. /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/components/sign-in-form.tsx +0 -0
  91. /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/components/sign-up-form.tsx +0 -0
  92. /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/components/user-menu.tsx +0 -0
  93. /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/routes/dashboard.tsx.hbs +0 -0
  94. /package/templates/auth/{web → better-auth/web}/react/tanstack-router/src/routes/login.tsx +0 -0
  95. /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/components/sign-in-form.tsx +0 -0
  96. /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/components/sign-up-form.tsx +0 -0
  97. /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/components/user-menu.tsx +0 -0
  98. /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/routes/dashboard.tsx.hbs +0 -0
  99. /package/templates/auth/{web → better-auth/web}/react/tanstack-start/src/routes/login.tsx +0 -0
  100. /package/templates/auth/{web → better-auth/web}/solid/src/components/sign-in-form.tsx +0 -0
  101. /package/templates/auth/{web → better-auth/web}/solid/src/components/sign-up-form.tsx +0 -0
  102. /package/templates/auth/{web → better-auth/web}/solid/src/components/user-menu.tsx.hbs +0 -0
  103. /package/templates/auth/{web → better-auth/web}/solid/src/lib/auth-client.ts +0 -0
  104. /package/templates/auth/{web → better-auth/web}/solid/src/routes/dashboard.tsx.hbs +0 -0
  105. /package/templates/auth/{web → better-auth/web}/solid/src/routes/login.tsx +0 -0
  106. /package/templates/auth/{web → better-auth/web}/svelte/src/components/SignInForm.svelte +0 -0
  107. /package/templates/auth/{web → better-auth/web}/svelte/src/components/SignUpForm.svelte +0 -0
  108. /package/templates/auth/{web → better-auth/web}/svelte/src/components/UserMenu.svelte +0 -0
  109. /package/templates/auth/{web → better-auth/web}/svelte/src/lib/auth-client.ts +0 -0
  110. /package/templates/auth/{web → better-auth/web}/svelte/src/routes/dashboard/+page.svelte.hbs +0 -0
  111. /package/templates/auth/{web → better-auth/web}/svelte/src/routes/login/+page.svelte +0 -0
@@ -0,0 +1,37 @@
1
+ import { SignInButton, UserButton, useUser } from "@clerk/clerk-react";
2
+ import { api } from "@{{projectName}}/backend/convex/_generated/api";
3
+ import { createFileRoute } from "@tanstack/react-router";
4
+ import {
5
+ Authenticated,
6
+ AuthLoading,
7
+ Unauthenticated,
8
+ useQuery,
9
+ } from "convex/react";
10
+
11
+ export const Route = createFileRoute("/dashboard")({
12
+ component: RouteComponent,
13
+ });
14
+
15
+ function RouteComponent() {
16
+ const privateData = useQuery(api.privateData.get);
17
+ const user = useUser()
18
+
19
+ return (
20
+ <>
21
+ <Authenticated>
22
+ <div>
23
+ <h1>Dashboard</h1>
24
+ <p>Welcome {user.user?.fullName}</p>
25
+ <p>privateData: {privateData?.message}</p>
26
+ <UserButton />
27
+ </div>
28
+ </Authenticated>
29
+ <Unauthenticated>
30
+ <SignInButton />
31
+ </Unauthenticated>
32
+ <AuthLoading>
33
+ <div>Loading...</div>
34
+ </AuthLoading>
35
+ </>
36
+ );
37
+ }
@@ -0,0 +1,37 @@
1
+ import { SignInButton, UserButton, useUser } from "@clerk/tanstack-react-start";
2
+ import { api } from "@{{projectName}}/backend/convex/_generated/api";
3
+ import { createFileRoute } from "@tanstack/react-router";
4
+ import {
5
+ Authenticated,
6
+ AuthLoading,
7
+ Unauthenticated,
8
+ useQuery,
9
+ } from "convex/react";
10
+
11
+ export const Route = createFileRoute("/dashboard")({
12
+ component: RouteComponent,
13
+ });
14
+
15
+ function RouteComponent() {
16
+ const privateData = useQuery(api.privateData.get);
17
+ const user = useUser();
18
+
19
+ return (
20
+ <>
21
+ <Authenticated>
22
+ <div>
23
+ <h1>Dashboard</h1>
24
+ <p>Welcome {user.user?.fullName}</p>
25
+ <p>privateData: {privateData?.message}</p>
26
+ <UserButton />
27
+ </div>
28
+ </Authenticated>
29
+ <Unauthenticated>
30
+ <SignInButton />
31
+ </Unauthenticated>
32
+ <AuthLoading>
33
+ <div>Loading...</div>
34
+ </AuthLoading>
35
+ </>
36
+ );
37
+ }
@@ -0,0 +1,18 @@
1
+ import { createClerkHandler } from "@clerk/tanstack-react-start/server";
2
+ import {
3
+ createStartHandler,
4
+ defaultStreamHandler,
5
+ defineHandlerCallback,
6
+ } from "@tanstack/react-start/server";
7
+ import { createRouter } from "./router";
8
+
9
+ const handlerFactory = createClerkHandler(
10
+ createStartHandler({
11
+ createRouter,
12
+ }),
13
+ );
14
+
15
+ export default defineHandlerCallback(async (event) => {
16
+ const startHandler = await handlerFactory(defaultStreamHandler);
17
+ return startHandler(event);
18
+ });
@@ -9,6 +9,7 @@
9
9
  "license": "ISC",
10
10
  "description": "",
11
11
  "devDependencies": {
12
+ "@types/node": "^24.3.0",
12
13
  "typescript": "^5.9.2"
13
14
  },
14
15
  "dependencies": {
@@ -14,7 +14,7 @@ import { RPCHandler } from "@orpc/server/fetch";
14
14
  import { appRouter } from "./routers";
15
15
  import { createContext } from "./lib/context";
16
16
  {{/if}}
17
- {{#if auth}}
17
+ {{#if (eq auth "better-auth")}}
18
18
  import { auth } from "./lib/auth";
19
19
  {{/if}}
20
20
 
@@ -31,13 +31,13 @@ const app = new Elysia()
31
31
  cors({
32
32
  origin: process.env.CORS_ORIGIN || "",
33
33
  methods: ["GET", "POST", "OPTIONS"],
34
- {{#if auth}}
34
+ {{#if (eq auth "better-auth")}}
35
35
  allowedHeaders: ["Content-Type", "Authorization"],
36
36
  credentials: true,
37
37
  {{/if}}
38
38
  }),
39
39
  )
40
- {{#if auth}}
40
+ {{#if (eq auth "better-auth")}}
41
41
  .all("/api/auth/*", async (context) => {
42
42
  const { request } = context;
43
43
  if (["POST", "GET"].includes(request.method)) {
@@ -7,7 +7,7 @@ import { appRouter } from "./routers/index";
7
7
  {{#if (eq api "orpc")}}
8
8
  import { RPCHandler } from "@orpc/server/node";
9
9
  import { appRouter } from "./routers";
10
- {{#if auth}}
10
+ {{#if (eq auth "better-auth")}}
11
11
  import { createContext } from "./lib/context";
12
12
  {{/if}}
13
13
  {{/if}}
@@ -17,7 +17,7 @@ import express from "express";
17
17
  import { streamText, type UIMessage, convertToModelMessages } from "ai";
18
18
  import { google } from "@ai-sdk/google";
19
19
  {{/if}}
20
- {{#if auth}}
20
+ {{#if (eq auth "better-auth")}}
21
21
  import { auth } from "./lib/auth";
22
22
  import { toNodeHandler } from "better-auth/node";
23
23
  {{/if}}
@@ -28,14 +28,14 @@ app.use(
28
28
  cors({
29
29
  origin: process.env.CORS_ORIGIN || "",
30
30
  methods: ["GET", "POST", "OPTIONS"],
31
- {{#if auth}}
31
+ {{#if (eq auth "better-auth")}}
32
32
  allowedHeaders: ["Content-Type", "Authorization"],
33
33
  credentials: true,
34
34
  {{/if}}
35
35
  })
36
36
  );
37
37
 
38
- {{#if auth}}
38
+ {{#if (eq auth "better-auth")}}
39
39
  app.all("/api/auth{/*path}", toNodeHandler(auth));
40
40
  {{/if}}
41
41
 
@@ -54,7 +54,7 @@ const handler = new RPCHandler(appRouter);
54
54
  app.use("/rpc{*path}", async (req, res, next) => {
55
55
  const { matched } = await handler.handle(req, res, {
56
56
  prefix: "/rpc",
57
- {{#if auth}}
57
+ {{#if (eq auth "better-auth")}}
58
58
  context: await createContext({ req }),
59
59
  {{else}}
60
60
  context: {},
@@ -85,4 +85,4 @@ app.get("/", (_req, res) => {
85
85
  const port = process.env.PORT || 3000;
86
86
  app.listen(port, () => {
87
87
  console.log(`Server is running on port ${port}`);
88
- });
88
+ });
@@ -13,7 +13,7 @@ import { RPCHandler } from "@orpc/server/node";
13
13
  import { CORSPlugin } from "@orpc/server/plugins";
14
14
  import { appRouter } from "./routers/index";
15
15
  import { createServer } from "node:http";
16
- {{#if auth}}
16
+ {{#if (eq auth "better-auth")}}
17
17
  import { createContext } from "./lib/context";
18
18
  {{/if}}
19
19
  {{/if}}
@@ -23,7 +23,7 @@ import { streamText, type UIMessage, convertToModelMessages } from "ai";
23
23
  import { google } from "@ai-sdk/google";
24
24
  {{/if}}
25
25
 
26
- {{#if auth}}
26
+ {{#if (eq auth "better-auth")}}
27
27
  import { auth } from "./lib/auth";
28
28
  {{/if}}
29
29
 
@@ -77,7 +77,7 @@ const fastify = Fastify({
77
77
 
78
78
  fastify.register(fastifyCors, baseCorsConfig);
79
79
 
80
- {{#if auth}}
80
+ {{#if (eq auth "better-auth")}}
81
81
  fastify.route({
82
82
  method: ["GET", "POST"],
83
83
  url: "/api/auth/*",
@@ -149,4 +149,4 @@ fastify.listen({ port: 3000 }, (err) => {
149
149
  process.exit(1);
150
150
  }
151
151
  console.log("Server running on port 3000");
152
- });
152
+ });
@@ -14,7 +14,7 @@ import { trpcServer } from "@hono/trpc-server";
14
14
  import { createContext } from "./lib/context";
15
15
  import { appRouter } from "./routers/index";
16
16
  {{/if}}
17
- {{#if auth}}
17
+ {{#if (eq auth "better-auth")}}
18
18
  import { auth } from "./lib/auth";
19
19
  {{/if}}
20
20
  import { Hono } from "hono";
@@ -42,14 +42,14 @@ app.use(
42
42
  origin: env.CORS_ORIGIN || "",
43
43
  {{/if}}
44
44
  allowMethods: ["GET", "POST", "OPTIONS"],
45
- {{#if auth}}
45
+ {{#if (eq auth "better-auth")}}
46
46
  allowHeaders: ["Content-Type", "Authorization"],
47
47
  credentials: true,
48
48
  {{/if}}
49
49
  })
50
50
  );
51
51
 
52
- {{#if auth}}
52
+ {{#if (eq auth "better-auth")}}
53
53
  app.on(["POST", "GET"], "/api/auth/**", (c) => auth.handler(c.req.raw));
54
54
  {{/if}}
55
55
 
@@ -133,4 +133,4 @@ export default app;
133
133
  {{#if (eq runtime "workers")}}
134
134
  export default app;
135
135
  {{/if}}
136
- {{/if}}
136
+ {{/if}}
@@ -1,5 +1,5 @@
1
1
  {{#if (eq api "orpc")}}
2
- import { {{#if auth}}protectedProcedure, {{/if}}publicProcedure } from "../lib/orpc";
2
+ import { {{#if (eq auth "better-auth")}}protectedProcedure, {{/if}}publicProcedure } from "../lib/orpc";
3
3
  import type { RouterClient } from "@orpc/server";
4
4
  {{#if (includes examples "todo")}}
5
5
  import { todoRouter } from "./todo";
@@ -9,7 +9,7 @@ export const appRouter = {
9
9
  healthCheck: publicProcedure.handler(() => {
10
10
  return "OK";
11
11
  }),
12
- {{#if auth}}
12
+ {{#if (eq auth "better-auth")}}
13
13
  privateData: protectedProcedure.handler(({ context }) => {
14
14
  return {
15
15
  message: "This is private",
@@ -25,7 +25,7 @@ export type AppRouter = typeof appRouter;
25
25
  export type AppRouterClient = RouterClient<typeof appRouter>;
26
26
  {{else if (eq api "trpc")}}
27
27
  import {
28
- {{#if auth}}protectedProcedure, {{/if}}publicProcedure,
28
+ {{#if (eq auth "better-auth")}}protectedProcedure, {{/if}}publicProcedure,
29
29
  router,
30
30
  } from "../lib/trpc";
31
31
  {{#if (includes examples "todo")}}
@@ -36,7 +36,7 @@ export const appRouter = router({
36
36
  healthCheck: publicProcedure.query(() => {
37
37
  return "OK";
38
38
  }),
39
- {{#if auth}}
39
+ {{#if (eq auth "better-auth")}}
40
40
  privateData: protectedProcedure.query(({ ctx }) => {
41
41
  return {
42
42
  message: "This is private",
@@ -164,7 +164,7 @@ export const server = await Worker("server", {
164
164
  DATABASE_URL: alchemy.secret(process.env.DATABASE_URL),
165
165
  {{/if}}
166
166
  CORS_ORIGIN: process.env.CORS_ORIGIN || "",
167
- {{#if auth}}
167
+ {{#if (eq auth "better-auth")}}
168
168
  BETTER_AUTH_SECRET: alchemy.secret(process.env.BETTER_AUTH_SECRET),
169
169
  BETTER_AUTH_URL: process.env.BETTER_AUTH_URL || "",
170
170
  {{/if}}
@@ -190,4 +190,4 @@ console.log(`Web -> ${web.url}`);
190
190
  console.log(`Server -> ${server.url}`);
191
191
  {{/if}}
192
192
 
193
- await app.finalize();
193
+ await app.finalize();
@@ -9,9 +9,17 @@ import { useQuery } from "@tanstack/react-query";
9
9
  import { trpc } from "@/utils/trpc";
10
10
  {{/if}}
11
11
  {{#if (eq backend "convex")}}
12
+ {{#if (eq auth "clerk")}}
13
+ import { Link } from "expo-router";
14
+ import { Authenticated, AuthLoading, Unauthenticated, useQuery } from "convex/react";
15
+ import { api } from "@{{ projectName }}/backend/convex/_generated/api";
16
+ import { useUser } from "@clerk/clerk-expo";
17
+ import { SignOutButton } from "@/components/sign-out-button";
18
+ {{else}}
12
19
  import { useQuery } from "convex/react";
13
20
  import { api } from "@{{ projectName }}/backend/convex/_generated/api";
14
21
  {{/if}}
22
+ {{/if}}
15
23
 
16
24
  export default function Home() {
17
25
  {{#if (eq api "orpc")}}
@@ -21,21 +29,27 @@ export default function Home() {
21
29
  const healthCheck = useQuery(trpc.healthCheck.queryOptions());
22
30
  {{/if}}
23
31
  {{#if (eq backend "convex")}}
32
+ {{#if (eq auth "clerk")}}
33
+ const { user } = useUser();
24
34
  const healthCheck = useQuery(api.healthCheck.get);
35
+ const privateData = useQuery(api.privateData.get);
36
+ {{else}}
37
+ const healthCheck = useQuery(api.healthCheck.get);
38
+ {{/if}}
25
39
  {{/if}}
26
40
 
27
41
  return (
28
42
  <Container>
29
43
  <ScrollView showsVerticalScrollIndicator={false} className="flex-1">
30
44
  <Text className="font-mono text-foreground text-3xl font-bold mb-4">
31
- BETTER T STACK
32
- </Text>
45
+ BETTER T STACK
46
+ </Text>
33
47
  <View className="bg-card border border-border rounded-xl p-6 mb-6 shadow-sm">
34
48
  {{#if (eq backend "convex")}}
35
49
  <View className="flex-row items-center gap-3">
36
50
  <View
37
51
  className={`h-3 w-3 rounded-full ${
38
- healthCheck ? "bg-green-500" : "bg-orange-500"
52
+ healthCheck ? "bg-green-500" : "bg-orange-500"
39
53
  }`}
40
54
  />
41
55
  <View className="flex-1">
@@ -89,6 +103,24 @@ export default function Home() {
89
103
  {{/unless}}
90
104
  {{/if}}
91
105
  </View>
106
+ {{#if (and (eq backend "convex") (eq auth "clerk"))}}
107
+ <Authenticated>
108
+ <Text>Hello {user?.emailAddresses[0].emailAddress}</Text>
109
+ <Text>Private Data: {privateData?.message}</Text>
110
+ <SignOutButton />
111
+ </Authenticated>
112
+ <Unauthenticated>
113
+ <Link href="/(auth)/sign-in">
114
+ <Text>Sign in</Text>
115
+ </Link>
116
+ <Link href="/(auth)/sign-up">
117
+ <Text>Sign up</Text>
118
+ </Link>
119
+ </Unauthenticated>
120
+ <AuthLoading>
121
+ <Text>Loading...</Text>
122
+ </AuthLoading>
123
+ {{/if}}
92
124
  </ScrollView>
93
125
  </Container>
94
126
  );
@@ -3,6 +3,11 @@ import "@/polyfills";
3
3
  {{/if}}
4
4
  {{#if (eq backend "convex")}}
5
5
  import { ConvexProvider, ConvexReactClient } from "convex/react";
6
+ {{#if (eq auth "clerk")}}
7
+ import { ClerkProvider, useAuth } from "@clerk/clerk-expo";
8
+ import { ConvexProviderWithClerk } from "convex/react-clerk";
9
+ import { tokenCache } from "@clerk/clerk-expo/token-cache";
10
+ {{/if}}
6
11
  {{else}}
7
12
  {{#unless (eq api "none")}}
8
13
  import { QueryClientProvider } from "@tanstack/react-query";
@@ -72,6 +77,28 @@ export default function RootLayout() {
72
77
  }
73
78
  return (
74
79
  {{#if (eq backend "convex")}}
80
+ {{#if (eq auth "clerk")}}
81
+ <ClerkProvider
82
+ tokenCache={tokenCache}
83
+ publishableKey={process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY}
84
+ >
85
+ <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
86
+ <ThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
87
+ <StatusBar style={isDarkColorScheme ? "light" : "dark"} />
88
+ <GestureHandlerRootView style=\{{ flex: 1 }}>
89
+ <Stack>
90
+ <Stack.Screen name="(drawer)" options=\{{ headerShown: false }} />
91
+ <Stack.Screen name="(auth)" options=\{{ headerShown: false }} />
92
+ <Stack.Screen
93
+ name="modal"
94
+ options=\{{ title: "Modal", presentation: "modal" }}
95
+ />
96
+ </Stack>
97
+ </GestureHandlerRootView>
98
+ </ThemeProvider>
99
+ </ConvexProviderWithClerk>
100
+ </ClerkProvider>
101
+ {{else}}
75
102
  <ConvexProvider client={convex}>
76
103
  <ThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
77
104
  <StatusBar style={isDarkColorScheme ? "light" : "dark"} />
@@ -86,6 +113,7 @@ export default function RootLayout() {
86
113
  </GestureHandlerRootView>
87
114
  </ThemeProvider>
88
115
  </ConvexProvider>
116
+ {{/if}}
89
117
  {{else}}
90
118
  {{#unless (eq api "none")}}
91
119
  <QueryClientProvider client={queryClient}>
@@ -22,6 +22,7 @@
22
22
  {{/if}}
23
23
  "expo": "^53.0.4",
24
24
  "expo-constants": "~17.1.4",
25
+ "expo-crypto": "~14.1.5",
25
26
  "expo-linking": "~7.1.4",
26
27
  "expo-navigation-bar": "~4.2.3",
27
28
  "expo-router": "~5.0.3",
@@ -11,9 +11,17 @@ import { useQuery } from "@tanstack/react-query";
11
11
  import { trpc } from "@/utils/trpc";
12
12
  {{/if}}
13
13
  {{#if (eq backend "convex")}}
14
+ {{#if (eq auth "clerk")}}
15
+ import { Link } from "expo-router";
16
+ import { Authenticated, AuthLoading, Unauthenticated, useQuery } from "convex/react";
17
+ import { api } from "@{{ projectName }}/backend/convex/_generated/api";
18
+ import { useUser } from "@clerk/clerk-expo";
19
+ import { SignOutButton } from "@/components/sign-out-button";
20
+ {{else}}
14
21
  import { useQuery } from "convex/react";
15
22
  import { api } from "@{{ projectName }}/backend/convex/_generated/api";
16
23
  {{/if}}
24
+ {{/if}}
17
25
 
18
26
  export default function Home() {
19
27
  {{#if (eq api "orpc")}}
@@ -23,7 +31,13 @@ export default function Home() {
23
31
  const healthCheck = useQuery(trpc.healthCheck.queryOptions());
24
32
  {{/if}}
25
33
  {{#if (eq backend "convex")}}
34
+ {{#if (eq auth "clerk")}}
35
+ const { user } = useUser();
26
36
  const healthCheck = useQuery(api.healthCheck.get);
37
+ const privateData = useQuery(api.privateData.get);
38
+ {{else}}
39
+ const healthCheck = useQuery(api.healthCheck.get);
40
+ {{/if}}
27
41
  {{/if}}
28
42
 
29
43
  return (
@@ -105,6 +119,24 @@ export default function Home() {
105
119
  {{/unless}}
106
120
  {{/if}}
107
121
  </View>
122
+ {{#if (and (eq backend "convex") (eq auth "clerk"))}}
123
+ <Authenticated>
124
+ <Text>Hello {user?.emailAddresses[0].emailAddress}</Text>
125
+ <Text>Private Data: {privateData?.message}</Text>
126
+ <SignOutButton />
127
+ </Authenticated>
128
+ <Unauthenticated>
129
+ <Link href="/(auth)/sign-in">
130
+ <Text>Sign in</Text>
131
+ </Link>
132
+ <Link href="/(auth)/sign-up">
133
+ <Text>Sign up</Text>
134
+ </Link>
135
+ </Unauthenticated>
136
+ <AuthLoading>
137
+ <Text>Loading...</Text>
138
+ </AuthLoading>
139
+ {{/if}}
108
140
  </ScrollView>
109
141
  </Container>
110
142
  );
@@ -9,6 +9,11 @@ import { queryClient } from "@/utils/orpc";
9
9
  {{/if}}
10
10
  {{#if (eq backend "convex")}}
11
11
  import { ConvexProvider, ConvexReactClient } from "convex/react";
12
+ {{#if (eq auth "clerk")}}
13
+ import { ClerkProvider, useAuth } from "@clerk/clerk-expo";
14
+ import { ConvexProviderWithClerk } from "convex/react-clerk";
15
+ import { tokenCache } from "@clerk/clerk-expo/token-cache";
16
+ {{/if}}
12
17
  {{else}}
13
18
  {{#unless (eq api "none")}}
14
19
  import { QueryClientProvider } from "@tanstack/react-query";
@@ -34,6 +39,35 @@ export default function RootLayout() {
34
39
 
35
40
  return (
36
41
  {{#if (eq backend "convex")}}
42
+ {{#if (eq auth "clerk")}}
43
+ <ClerkProvider
44
+ tokenCache={tokenCache}
45
+ publishableKey={process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY}
46
+ >
47
+ <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
48
+ <GestureHandlerRootView style=\{{ flex: 1 }}>
49
+ <Stack
50
+ screenOptions=\{{
51
+ headerStyle: {
52
+ backgroundColor: theme.colors.background,
53
+ },
54
+ headerTitleStyle: {
55
+ color: theme.colors.foreground,
56
+ },
57
+ headerTintColor: theme.colors.foreground,
58
+ }}
59
+ >
60
+ <Stack.Screen name="(drawer)" options=\{{ headerShown: false }} />
61
+ <Stack.Screen name="(auth)" options=\{{ headerShown: false }} />
62
+ <Stack.Screen
63
+ name="modal"
64
+ options=\{{ title: "Modal", presentation: "modal" }}
65
+ />
66
+ </Stack>
67
+ </GestureHandlerRootView>
68
+ </ConvexProviderWithClerk>
69
+ </ClerkProvider>
70
+ {{else}}
37
71
  <ConvexProvider client={convex}>
38
72
  <GestureHandlerRootView style=\{{ flex: 1 }}>
39
73
  <Stack
@@ -55,6 +89,7 @@ export default function RootLayout() {
55
89
  </Stack>
56
90
  </GestureHandlerRootView>
57
91
  </ConvexProvider>
92
+ {{/if}}
58
93
  {{else}}
59
94
  {{#unless (eq api "none")}}
60
95
  <QueryClientProvider client={queryClient}>
@@ -21,6 +21,7 @@
21
21
  "babel-plugin-react-compiler": "^19.1.0-rc.2",
22
22
  "expo": "^53.0.17",
23
23
  "expo-constants": "~17.1.7",
24
+ "expo-crypto": "~14.1.5",
24
25
  "expo-linking": "~7.1.7",
25
26
  "expo-router": "~5.1.3",
26
27
  "expo-secure-store": "~14.2.3",
@@ -1,12 +1,12 @@
1
1
  <script setup lang="ts">
2
2
  import ModeToggle from './ModeToggle.vue'
3
- {{#if auth}}
3
+ {{#if (eq auth "better-auth")}}
4
4
  import UserMenu from './UserMenu.vue'
5
5
  {{/if}}
6
6
 
7
7
  const links = [
8
8
  { to: "/", label: "Home" },
9
- {{#if auth}}
9
+ {{#if (or (eq auth "better-auth") (eq auth "clerk"))}}
10
10
  { to: "/dashboard", label: "Dashboard" },
11
11
  {{/if}}
12
12
  {{#if (includes examples "todo")}}
@@ -34,7 +34,7 @@ const links = [
34
34
  </nav>
35
35
  <div class="flex items-center gap-2">
36
36
  <ModeToggle />
37
- {{#if auth}}
37
+ {{#if (eq auth "better-auth")}}
38
38
  <UserMenu />
39
39
  {{/if}}
40
40
  </div>
@@ -1,7 +1,8 @@
1
1
  import type { Metadata } from "next";
2
2
  import { Geist, Geist_Mono } from "next/font/google";
3
3
  import "../index.css";
4
- import Providers from "@/components/providers";
4
+ {{#if (eq auth "clerk")}}{{#if (eq backend "convex")}}import { ClerkProvider } from "@clerk/nextjs";
5
+ {{/if}}{{/if}}import Providers from "@/components/providers";
5
6
  import Header from "@/components/header";
6
7
 
7
8
  const geistSans = Geist({
@@ -24,18 +25,25 @@ export default function RootLayout({
24
25
  }: Readonly<{
25
26
  children: React.ReactNode;
26
27
  }>) {
27
- return (
28
- <html lang="en" suppressHydrationWarning>
29
- <body
30
- className={`${geistSans.variable} ${geistMono.variable} antialiased`}
31
- >
32
- <Providers>
33
- <div className="grid grid-rows-[auto_1fr] h-svh">
34
- <Header />
35
- {children}
36
- </div>
37
- </Providers>
38
- </body>
39
- </html>
40
- );
28
+ return (
29
+ <html lang="en" suppressHydrationWarning>
30
+ <body
31
+ className={`${geistSans.variable} ${geistMono.variable} antialiased`}
32
+ >
33
+ {{#if (and (eq auth "clerk") (eq backend "convex"))}}<ClerkProvider>
34
+ <Providers>
35
+ <div className="grid grid-rows-[auto_1fr] h-svh">
36
+ <Header />
37
+ {children}
38
+ </div>
39
+ </Providers>
40
+ </ClerkProvider>{{else}}<Providers>
41
+ <div className="grid grid-rows-[auto_1fr] h-svh">
42
+ <Header />
43
+ {children}
44
+ </div>
45
+ </Providers>{{/if}}
46
+ </body>
47
+ </html>
48
+ );
41
49
  }
@@ -1,7 +1,13 @@
1
1
  "use client";
2
2
 
3
3
  {{#if (eq backend "convex")}}
4
+ {{#if (eq auth "clerk")}}
5
+ import { useAuth } from "@clerk/nextjs";
6
+ import { ConvexReactClient } from "convex/react";
7
+ import { ConvexProviderWithClerk } from "convex/react-clerk";
8
+ {{else}}
4
9
  import { ConvexProvider, ConvexReactClient } from "convex/react";
10
+ {{/if}}
5
11
  {{else}}
6
12
  {{#unless (eq api "none")}}
7
13
  import { QueryClientProvider } from "@tanstack/react-query";
@@ -34,7 +40,13 @@ export default function Providers({
34
40
  disableTransitionOnChange
35
41
  >
36
42
  {{#if (eq backend "convex")}}
43
+ {{#if (eq auth "clerk")}}
44
+ <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
45
+ {children}
46
+ </ConvexProviderWithClerk>
47
+ {{else}}
37
48
  <ConvexProvider client={convex}>{children}</ConvexProvider>
49
+ {{/if}}
38
50
  {{else}}
39
51
  {{#unless (eq api "none")}}
40
52
  <QueryClientProvider client={queryClient}>