create-better-t-stack 3.1.8-canary.932e5243 → 3.2.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.
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{src-EpWSiOd8.js → src-JAo0_3IZ.js} +28 -10
- package/package.json +1 -1
- package/templates/auth/better-auth/convex/backend/convex/auth.ts.hbs +53 -40
- package/templates/auth/better-auth/convex/backend/convex/http.ts.hbs +1 -1
- package/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs +147 -147
- package/templates/frontend/native/unistyles/app/(drawer)/index.tsx.hbs +138 -139
- package/templates/frontend/native/unistyles/app/_layout.tsx.hbs +1 -1
- package/templates/frontend/native/unistyles/app.json.hbs +1 -1
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1390,7 +1390,7 @@ const getLatestCLIVersion = () => {
|
|
|
1390
1390
|
*/
|
|
1391
1391
|
function isTelemetryEnabled() {
|
|
1392
1392
|
const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
|
|
1393
|
-
const BTS_TELEMETRY = "
|
|
1393
|
+
const BTS_TELEMETRY = "1";
|
|
1394
1394
|
if (BTS_TELEMETRY_DISABLED !== void 0) return BTS_TELEMETRY_DISABLED !== "1";
|
|
1395
1395
|
if (BTS_TELEMETRY !== void 0) return BTS_TELEMETRY === "1";
|
|
1396
1396
|
return true;
|
|
@@ -1398,8 +1398,8 @@ function isTelemetryEnabled() {
|
|
|
1398
1398
|
|
|
1399
1399
|
//#endregion
|
|
1400
1400
|
//#region src/utils/analytics.ts
|
|
1401
|
-
const POSTHOG_API_KEY = "
|
|
1402
|
-
const POSTHOG_HOST = "
|
|
1401
|
+
const POSTHOG_API_KEY = "phc_8ZUxEwwfKMajJLvxz1daGd931dYbQrwKNficBmsdIrs";
|
|
1402
|
+
const POSTHOG_HOST = "https://us.i.posthog.com";
|
|
1403
1403
|
function generateSessionId() {
|
|
1404
1404
|
const rand = Math.random().toString(36).slice(2);
|
|
1405
1405
|
return `cli_${Date.now().toString(36)}${rand}`;
|
|
@@ -4674,7 +4674,8 @@ async function setupEnvironmentVariables(config) {
|
|
|
4674
4674
|
const hasNuxt = frontend.includes("nuxt");
|
|
4675
4675
|
const hasSvelte = frontend.includes("svelte");
|
|
4676
4676
|
const hasSolid = frontend.includes("solid");
|
|
4677
|
-
|
|
4677
|
+
const hasWebFrontend$1 = hasReactRouter || hasTanStackRouter || hasTanStackStart || hasNextJs || hasNuxt || hasSolid || hasSvelte;
|
|
4678
|
+
if (hasWebFrontend$1) {
|
|
4678
4679
|
const clientDir = path.join(projectDir, "apps/web");
|
|
4679
4680
|
if (await fs.pathExists(clientDir)) {
|
|
4680
4681
|
const baseVar = getClientServerVar(frontend, backend);
|
|
@@ -4747,6 +4748,11 @@ async function setupEnvironmentVariables(config) {
|
|
|
4747
4748
|
value: "",
|
|
4748
4749
|
condition: true
|
|
4749
4750
|
});
|
|
4751
|
+
if (backend === "convex" && auth === "better-auth") nativeVars.push({
|
|
4752
|
+
key: "EXPO_PUBLIC_CONVEX_SITE_URL",
|
|
4753
|
+
value: "https://<YOUR_CONVEX_URL>",
|
|
4754
|
+
condition: true
|
|
4755
|
+
});
|
|
4750
4756
|
await addEnvVariablesToFile(path.join(nativeDir, ".env"), nativeVars);
|
|
4751
4757
|
}
|
|
4752
4758
|
}
|
|
@@ -4755,12 +4761,23 @@ async function setupEnvironmentVariables(config) {
|
|
|
4755
4761
|
const convexBackendDir = path.join(projectDir, "packages/backend");
|
|
4756
4762
|
if (await fs.pathExists(convexBackendDir)) {
|
|
4757
4763
|
const envLocalPath = path.join(convexBackendDir, ".env.local");
|
|
4758
|
-
|
|
4764
|
+
const hasNative = frontend.includes("native-nativewind") || frontend.includes("native-unistyles");
|
|
4765
|
+
const hasWeb = hasWebFrontend$1;
|
|
4766
|
+
if (!await fs.pathExists(envLocalPath) || !(await fs.readFile(envLocalPath, "utf8")).includes("npx convex env set")) {
|
|
4767
|
+
const convexCommands = `# Set Convex environment variables
|
|
4759
4768
|
# npx convex env set BETTER_AUTH_SECRET=$(openssl rand -base64 32)
|
|
4760
|
-
# npx convex env set SITE_URL http://localhost:3001
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4769
|
+
${hasWeb ? "# npx convex env set SITE_URL http://localhost:3001\n" : ""}
|
|
4770
|
+
`;
|
|
4771
|
+
await fs.appendFile(envLocalPath, convexCommands);
|
|
4772
|
+
}
|
|
4773
|
+
const convexBackendVars = [];
|
|
4774
|
+
if (hasNative) convexBackendVars.push({
|
|
4775
|
+
key: "EXPO_PUBLIC_CONVEX_SITE_URL",
|
|
4776
|
+
value: "",
|
|
4777
|
+
condition: true,
|
|
4778
|
+
comment: "Same as CONVEX_URL but ends in .site"
|
|
4779
|
+
});
|
|
4780
|
+
if (hasWeb) convexBackendVars.push({
|
|
4764
4781
|
key: hasNextJs ? "NEXT_PUBLIC_CONVEX_SITE_URL" : "VITE_CONVEX_SITE_URL",
|
|
4765
4782
|
value: "",
|
|
4766
4783
|
condition: true,
|
|
@@ -4769,7 +4786,8 @@ async function setupEnvironmentVariables(config) {
|
|
|
4769
4786
|
key: "SITE_URL",
|
|
4770
4787
|
value: "http://localhost:3001",
|
|
4771
4788
|
condition: true
|
|
4772
|
-
}
|
|
4789
|
+
});
|
|
4790
|
+
await addEnvVariablesToFile(envLocalPath, convexBackendVars);
|
|
4773
4791
|
}
|
|
4774
4792
|
}
|
|
4775
4793
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-t-stack",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -2,56 +2,69 @@ import { createClient, type GenericCtx } from "@convex-dev/better-auth";
|
|
|
2
2
|
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
|
3
3
|
import { convex } from "@convex-dev/better-auth/plugins";
|
|
4
4
|
import { expo } from "@better-auth/expo";
|
|
5
|
-
{{else if (or (includes frontend "tanstack-start") (includes frontend "next"))}}
|
|
6
|
-
import { convex } from "@convex-dev/better-auth/plugins";
|
|
7
5
|
{{else}}
|
|
8
|
-
import { convex
|
|
6
|
+
import { convex } from "@convex-dev/better-auth/plugins";
|
|
7
|
+
{{/if}}
|
|
8
|
+
{{#if (or (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
|
|
9
|
+
import { crossDomain } from "@convex-dev/better-auth/plugins";
|
|
9
10
|
{{/if}}
|
|
10
11
|
import { components } from "./_generated/api";
|
|
11
12
|
import { DataModel } from "./_generated/dataModel";
|
|
12
13
|
import { query } from "./_generated/server";
|
|
13
14
|
import { betterAuth } from "better-auth";
|
|
15
|
+
import { v } from "convex/values";
|
|
14
16
|
|
|
17
|
+
{{#if (or (includes frontend "tanstack-start") (includes frontend "next") (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
|
|
15
18
|
const siteUrl = process.env.SITE_URL!;
|
|
19
|
+
{{/if}}
|
|
20
|
+
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
|
21
|
+
const nativeAppUrl = process.env.NATIVE_APP_URL || "mybettertapp://";
|
|
22
|
+
{{/if}}
|
|
16
23
|
|
|
17
24
|
export const authComponent = createClient<DataModel>(components.betterAuth);
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
26
|
+
function createAuth(
|
|
27
|
+
ctx: GenericCtx<DataModel>,
|
|
28
|
+
{ optionsOnly }: { optionsOnly?: boolean } = { optionsOnly: false }
|
|
29
|
+
) {
|
|
30
|
+
return betterAuth({
|
|
31
|
+
logger: {
|
|
32
|
+
disabled: optionsOnly,
|
|
33
|
+
},
|
|
34
|
+
{{#if (and (or (includes frontend "native-nativewind") (includes frontend "native-unistyles")) (or (includes frontend "tanstack-start") (includes frontend "next")))}}
|
|
35
|
+
baseURL: siteUrl,
|
|
36
|
+
trustedOrigins: [siteUrl, nativeAppUrl],
|
|
37
|
+
{{else if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
|
38
|
+
trustedOrigins: [nativeAppUrl],
|
|
39
|
+
{{else if (or (includes frontend "tanstack-start") (includes frontend "next"))}}
|
|
40
|
+
baseURL: siteUrl,
|
|
41
|
+
trustedOrigins: [siteUrl],
|
|
42
|
+
{{else}}
|
|
43
|
+
trustedOrigins: [siteUrl],
|
|
44
|
+
{{/if}}
|
|
45
|
+
database: authComponent.adapter(ctx),
|
|
46
|
+
emailAndPassword: {
|
|
47
|
+
enabled: true,
|
|
48
|
+
requireEmailVerification: false,
|
|
49
|
+
},
|
|
50
|
+
plugins: [
|
|
51
|
+
{{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
|
52
|
+
expo(),
|
|
53
|
+
{{/if}}
|
|
54
|
+
{{#if (or (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
|
|
55
|
+
crossDomain({ siteUrl }),
|
|
56
|
+
{{/if}}
|
|
57
|
+
convex(),
|
|
58
|
+
],
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { createAuth };
|
|
51
63
|
|
|
52
64
|
export const getCurrentUser = query({
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
65
|
+
args: {},
|
|
66
|
+
returns: v.any(),
|
|
67
|
+
handler: async function (ctx, args) {
|
|
68
|
+
return authComponent.getAuthUser(ctx);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
@@ -3,7 +3,7 @@ import { authComponent, createAuth } from "./auth";
|
|
|
3
3
|
|
|
4
4
|
const http = httpRouter();
|
|
5
5
|
|
|
6
|
-
{{#if (or (includes frontend "tanstack-start") (includes frontend "next"))}}
|
|
6
|
+
{{#if (or (includes frontend "tanstack-start") (includes frontend "next") (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
|
|
7
7
|
authComponent.registerRoutes(http, createAuth);
|
|
8
8
|
{{else}}
|
|
9
9
|
authComponent.registerRoutes(http, createAuth, { cors: true });
|
|
@@ -8,171 +8,171 @@ import { orpc } from "@/utils/orpc";
|
|
|
8
8
|
import { useQuery } from "@tanstack/react-query";
|
|
9
9
|
import { trpc } from "@/utils/trpc";
|
|
10
10
|
{{/if}}
|
|
11
|
-
{{#if (eq backend "convex")}}
|
|
12
|
-
{{#if (eq auth "clerk")}}
|
|
11
|
+
{{#if (and (eq backend "convex") (eq auth "clerk"))}}
|
|
13
12
|
import { Link } from "expo-router";
|
|
14
13
|
import { Authenticated, AuthLoading, Unauthenticated, useQuery } from "convex/react";
|
|
15
14
|
import { api } from "@{{ projectName }}/backend/convex/_generated/api";
|
|
16
15
|
import { useUser } from "@clerk/clerk-expo";
|
|
17
16
|
import { SignOutButton } from "@/components/sign-out-button";
|
|
18
|
-
{{else}}
|
|
19
|
-
{{#if (eq auth "better-auth")}}
|
|
17
|
+
{{else if (and (eq backend "convex") (eq auth "better-auth"))}}
|
|
20
18
|
import { useConvexAuth, useQuery } from "convex/react";
|
|
21
19
|
import { api } from "@{{ projectName }}/backend/convex/_generated/api";
|
|
22
20
|
import { authClient } from "@/lib/auth-client";
|
|
23
21
|
import { SignIn } from "@/components/sign-in";
|
|
24
22
|
import { SignUp } from "@/components/sign-up";
|
|
25
|
-
{{else}}
|
|
23
|
+
{{else if (eq backend "convex")}}
|
|
26
24
|
import { useQuery } from "convex/react";
|
|
27
25
|
import { api } from "@{{ projectName }}/backend/convex/_generated/api";
|
|
28
26
|
{{/if}}
|
|
29
|
-
{{/if}}
|
|
30
|
-
{{/if}}
|
|
31
27
|
|
|
32
28
|
export default function Home() {
|
|
33
|
-
{{#if (eq api "orpc")}}
|
|
34
|
-
const healthCheck = useQuery(orpc.healthCheck.queryOptions());
|
|
35
|
-
{{/if}}
|
|
36
|
-
{{#if (eq api "trpc")}}
|
|
37
|
-
const healthCheck = useQuery(trpc.healthCheck.queryOptions());
|
|
38
|
-
{{/if}}
|
|
39
|
-
{{#if (eq backend "convex")}}
|
|
40
|
-
{
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
{{
|
|
50
|
-
const healthCheck = useQuery(api.healthCheck.get);
|
|
51
|
-
{{/if}}
|
|
52
|
-
{{/if}}
|
|
53
|
-
{{/if}}
|
|
29
|
+
{{#if (eq api "orpc")}}
|
|
30
|
+
const healthCheck = useQuery(orpc.healthCheck.queryOptions());
|
|
31
|
+
{{/if}}
|
|
32
|
+
{{#if (eq api "trpc")}}
|
|
33
|
+
const healthCheck = useQuery(trpc.healthCheck.queryOptions());
|
|
34
|
+
{{/if}}
|
|
35
|
+
{{#if (and (eq backend "convex") (eq auth "clerk"))}}
|
|
36
|
+
const { user } = useUser();
|
|
37
|
+
const healthCheck = useQuery(api.healthCheck.get);
|
|
38
|
+
const privateData = useQuery(api.privateData.get);
|
|
39
|
+
{{else if (and (eq backend "convex") (eq auth "better-auth"))}}
|
|
40
|
+
const healthCheck = useQuery(api.healthCheck.get);
|
|
41
|
+
const { isAuthenticated } = useConvexAuth();
|
|
42
|
+
const user = useQuery(api.auth.getCurrentUser, isAuthenticated ? {} : "skip");
|
|
43
|
+
{{else if (eq backend "convex")}}
|
|
44
|
+
const healthCheck = useQuery(api.healthCheck.get);
|
|
45
|
+
{{/if}}
|
|
54
46
|
|
|
55
|
-
return (
|
|
56
|
-
<Container>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
47
|
+
return (
|
|
48
|
+
<Container>
|
|
49
|
+
<ScrollView className="flex-1">
|
|
50
|
+
<View className="px-4">
|
|
51
|
+
<Text className="font-mono text-foreground text-3xl font-bold mb-4">
|
|
52
|
+
BETTER T STACK
|
|
53
|
+
</Text>
|
|
54
|
+
|
|
55
|
+
{{#unless (and (eq backend "convex") (eq auth "better-auth"))}}
|
|
56
|
+
<View className="bg-card border border-border rounded-xl p-6 mb-6 shadow-sm">
|
|
57
|
+
{{#if (eq backend "convex")}}
|
|
58
|
+
<View className="flex-row items-center gap-3">
|
|
59
|
+
<View
|
|
60
|
+
className={`h-3 w-3 rounded-full ${
|
|
61
|
+
healthCheck ? "bg-green-500" : "bg-orange-500"
|
|
62
|
+
}`}
|
|
63
|
+
/>
|
|
64
|
+
<View className="flex-1">
|
|
65
|
+
<Text className="text-sm font-medium text-card-foreground">
|
|
66
|
+
Convex
|
|
67
|
+
</Text>
|
|
68
|
+
<Text className="text-muted-foreground">
|
|
69
|
+
{
|
|
70
|
+
healthCheck === undefined
|
|
71
|
+
? "Checking..."
|
|
72
|
+
: healthCheck === "OK"
|
|
73
|
+
? "Connected to API"
|
|
74
|
+
: "API Disconnected"
|
|
75
|
+
}
|
|
76
|
+
</Text>
|
|
77
|
+
</View>
|
|
78
|
+
</View>
|
|
79
|
+
{{else}}
|
|
80
|
+
{{#unless (eq api "none")}}
|
|
81
|
+
<View className="flex-row items-center gap-3">
|
|
82
|
+
<View
|
|
83
|
+
className={`h-3 w-3 rounded-full ${
|
|
84
|
+
healthCheck.data ? "bg-green-500" : "bg-orange-500"
|
|
85
|
+
}`}
|
|
86
|
+
/>
|
|
87
|
+
<View className="flex-1">
|
|
88
|
+
<Text className="text-sm font-medium text-card-foreground">
|
|
89
|
+
{{#if (eq api "orpc")}}ORPC{{else}}TRPC{{/if}}
|
|
90
|
+
</Text>
|
|
91
|
+
<Text className="text-xs text-muted-foreground">
|
|
92
|
+
{healthCheck.isLoading
|
|
93
|
+
? "Checking connection..."
|
|
94
|
+
: healthCheck.data
|
|
95
|
+
? "All systems operational"
|
|
96
|
+
: "Service unavailable"}
|
|
97
|
+
</Text>
|
|
98
|
+
</View>
|
|
99
|
+
</View>
|
|
100
|
+
{{/unless}}
|
|
101
|
+
{{/if}}
|
|
78
102
|
</View>
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
</
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
{{/unless}}
|
|
104
|
+
|
|
105
|
+
{{#if (and (eq backend "convex") (eq auth "clerk"))}}
|
|
106
|
+
<Authenticated>
|
|
107
|
+
<Text>Hello {user?.emailAddresses[0].emailAddress}</Text>
|
|
108
|
+
<Text>Private Data: {privateData?.message}</Text>
|
|
109
|
+
<SignOutButton />
|
|
110
|
+
</Authenticated>
|
|
111
|
+
<Unauthenticated>
|
|
112
|
+
<Link href="/(auth)/sign-in">
|
|
113
|
+
<Text>Sign in</Text>
|
|
114
|
+
</Link>
|
|
115
|
+
<Link href="/(auth)/sign-up">
|
|
116
|
+
<Text>Sign up</Text>
|
|
117
|
+
</Link>
|
|
118
|
+
</Unauthenticated>
|
|
119
|
+
<AuthLoading>
|
|
120
|
+
<Text>Loading...</Text>
|
|
121
|
+
</AuthLoading>
|
|
122
|
+
{{/if}}
|
|
123
|
+
|
|
124
|
+
{{#if (and (eq backend "convex") (eq auth "better-auth"))}}
|
|
125
|
+
{user ? (
|
|
126
|
+
<View className="mb-6 p-4 bg-card rounded-lg border border-border">
|
|
127
|
+
<View className="flex-row justify-between items-center mb-2">
|
|
128
|
+
<Text className="text-foreground text-base">
|
|
129
|
+
Welcome,{" "}
|
|
130
|
+
<Text className="font-medium">{user.name}</Text>
|
|
131
|
+
</Text>
|
|
132
|
+
</View>
|
|
133
|
+
<Text className="text-muted-foreground text-sm mb-4">
|
|
134
|
+
{user.email}
|
|
135
|
+
</Text>
|
|
136
|
+
<TouchableOpacity
|
|
137
|
+
className="bg-destructive py-2 px-4 rounded-md self-start"
|
|
138
|
+
onPress={() => {
|
|
139
|
+
authClient.signOut();
|
|
140
|
+
}}
|
|
141
|
+
>
|
|
142
|
+
<Text className="text-white font-medium">Sign Out</Text>
|
|
143
|
+
</TouchableOpacity>
|
|
144
|
+
</View>
|
|
145
|
+
) : null}
|
|
146
|
+
<View className="mb-6 rounded-lg border border-border p-4">
|
|
147
|
+
<Text className="mb-3 font-medium text-foreground">
|
|
148
|
+
API Status
|
|
109
149
|
</Text>
|
|
150
|
+
<View className="flex-row items-center gap-2">
|
|
151
|
+
<View
|
|
152
|
+
className={`h-3 w-3 rounded-full ${
|
|
153
|
+
healthCheck ? "bg-green-500" : "bg-red-500"
|
|
154
|
+
}`}
|
|
155
|
+
/>
|
|
156
|
+
<Text className="text-muted-foreground">
|
|
157
|
+
{
|
|
158
|
+
healthCheck === undefined
|
|
159
|
+
? "Checking..."
|
|
160
|
+
: healthCheck === "OK"
|
|
161
|
+
? "Connected to API"
|
|
162
|
+
: "API Disconnected"
|
|
163
|
+
}
|
|
164
|
+
</Text>
|
|
165
|
+
</View>
|
|
110
166
|
</View>
|
|
167
|
+
{!user && (
|
|
168
|
+
<>
|
|
169
|
+
<SignIn />
|
|
170
|
+
<SignUp />
|
|
171
|
+
</>
|
|
172
|
+
)}
|
|
173
|
+
{{/if}}
|
|
111
174
|
</View>
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
{{#if (and (eq backend "convex") (eq auth "clerk"))}}
|
|
116
|
-
<Authenticated>
|
|
117
|
-
<Text>Hello {user?.emailAddresses[0].emailAddress}</Text>
|
|
118
|
-
<Text>Private Data: {privateData?.message}</Text>
|
|
119
|
-
<SignOutButton />
|
|
120
|
-
</Authenticated>
|
|
121
|
-
<Unauthenticated>
|
|
122
|
-
<Link href="/(auth)/sign-in">
|
|
123
|
-
<Text>Sign in</Text>
|
|
124
|
-
</Link>
|
|
125
|
-
<Link href="/(auth)/sign-up">
|
|
126
|
-
<Text>Sign up</Text>
|
|
127
|
-
</Link>
|
|
128
|
-
</Unauthenticated>
|
|
129
|
-
<AuthLoading>
|
|
130
|
-
<Text>Loading...</Text>
|
|
131
|
-
</AuthLoading>
|
|
132
|
-
{{/if}}
|
|
133
|
-
{{#if (and (eq backend "convex") (eq auth "better-auth"))}}
|
|
134
|
-
{user ? (
|
|
135
|
-
<View className="mb-6 p-4 bg-card rounded-lg border border-border">
|
|
136
|
-
<View className="flex-row justify-between items-center mb-2">
|
|
137
|
-
<Text className="text-foreground text-base">
|
|
138
|
-
Welcome,{" "}
|
|
139
|
-
<Text className="font-medium">{user.name}</Text>
|
|
140
|
-
</Text>
|
|
141
|
-
</View>
|
|
142
|
-
<Text className="text-muted-foreground text-sm mb-4">
|
|
143
|
-
{user.email}
|
|
144
|
-
</Text>
|
|
145
|
-
|
|
146
|
-
<TouchableOpacity className="bg-destructive py-2 px-4 rounded-md self-start" onPress={()=> {
|
|
147
|
-
authClient.signOut();
|
|
148
|
-
}}
|
|
149
|
-
>
|
|
150
|
-
<Text className="text-white font-medium">Sign Out</Text>
|
|
151
|
-
</TouchableOpacity>
|
|
152
|
-
</View>
|
|
153
|
-
) : null}
|
|
154
|
-
<View className="mb-6 rounded-lg border border-border p-4">
|
|
155
|
-
<Text className="mb-3 font-medium text-foreground">API Status</Text>
|
|
156
|
-
<View className="flex-row items-center gap-2">
|
|
157
|
-
<View className={`h-3 w-3 rounded-full ${healthCheck ? "bg-green-500" : "bg-red-500" }`} />
|
|
158
|
-
<Text className="text-muted-foreground">
|
|
159
|
-
{healthCheck === undefined
|
|
160
|
-
? "Checking..."
|
|
161
|
-
: healthCheck === "OK"
|
|
162
|
-
? "Connected to API"
|
|
163
|
-
: "API Disconnected"}
|
|
164
|
-
</Text>
|
|
165
|
-
</View>
|
|
166
|
-
</View>
|
|
167
|
-
{!user && (
|
|
168
|
-
<>
|
|
169
|
-
<SignIn />
|
|
170
|
-
<SignUp />
|
|
171
|
-
</>
|
|
172
|
-
)}
|
|
173
|
-
{{/if}}
|
|
174
|
-
</View>
|
|
175
|
-
</ScrollView>
|
|
176
|
-
</Container>
|
|
177
|
-
);
|
|
175
|
+
</ScrollView>
|
|
176
|
+
</Container>
|
|
177
|
+
);
|
|
178
178
|
}
|
|
@@ -10,48 +10,40 @@ import { orpc } from "@/utils/orpc";
|
|
|
10
10
|
import { useQuery } from "@tanstack/react-query";
|
|
11
11
|
import { trpc } from "@/utils/trpc";
|
|
12
12
|
{{/if}}
|
|
13
|
-
{{#if (eq backend "convex")}}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
import { useQuery } from "convex/react";
|
|
29
|
-
import { api } from "@{{ projectName }}/backend/convex/_generated/api";
|
|
30
|
-
{{/if}}
|
|
31
|
-
{{/if}}
|
|
13
|
+
{{#if (and (eq backend "convex") (eq auth "clerk"))}}
|
|
14
|
+
import { Link } from "expo-router";
|
|
15
|
+
import { Authenticated, AuthLoading, Unauthenticated, useQuery } from "convex/react";
|
|
16
|
+
import { api } from "@{{ projectName }}/backend/convex/_generated/api";
|
|
17
|
+
import { useUser } from "@clerk/clerk-expo";
|
|
18
|
+
import { SignOutButton } from "@/components/sign-out-button";
|
|
19
|
+
{{else if (and (eq backend "convex") (eq auth "better-auth"))}}
|
|
20
|
+
import { useConvexAuth, useQuery } from "convex/react";
|
|
21
|
+
import { api } from "@{{ projectName }}/backend/convex/_generated/api";
|
|
22
|
+
import { authClient } from "@/lib/auth-client";
|
|
23
|
+
import { SignIn } from "@/components/sign-in";
|
|
24
|
+
import { SignUp } from "@/components/sign-up";
|
|
25
|
+
{{else if (eq backend "convex")}}
|
|
26
|
+
import { useQuery } from "convex/react";
|
|
27
|
+
import { api } from "@{{ projectName }}/backend/convex/_generated/api";
|
|
32
28
|
{{/if}}
|
|
33
29
|
|
|
34
30
|
export default function Home() {
|
|
35
31
|
{{#if (eq api "orpc")}}
|
|
36
|
-
|
|
32
|
+
const healthCheck = useQuery(orpc.healthCheck.queryOptions());
|
|
37
33
|
{{/if}}
|
|
38
34
|
{{#if (eq api "trpc")}}
|
|
39
|
-
|
|
35
|
+
const healthCheck = useQuery(trpc.healthCheck.queryOptions());
|
|
40
36
|
{{/if}}
|
|
41
|
-
{{#if (eq backend "convex")}}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
{{else}}
|
|
52
|
-
const healthCheck = useQuery(api.healthCheck.get);
|
|
53
|
-
{{/if}}
|
|
54
|
-
{{/if}}
|
|
37
|
+
{{#if (and (eq backend "convex") (eq auth "clerk"))}}
|
|
38
|
+
const { user } = useUser();
|
|
39
|
+
const healthCheck = useQuery(api.healthCheck.get);
|
|
40
|
+
const privateData = useQuery(api.privateData.get);
|
|
41
|
+
{{else if (and (eq backend "convex") (eq auth "better-auth"))}}
|
|
42
|
+
const healthCheck = useQuery(api.healthCheck.get);
|
|
43
|
+
const { isAuthenticated } = useConvexAuth();
|
|
44
|
+
const user = useQuery(api.auth.getCurrentUser, isAuthenticated ? {} : "skip");
|
|
45
|
+
{{else if (eq backend "convex")}}
|
|
46
|
+
const healthCheck = useQuery(api.healthCheck.get);
|
|
55
47
|
{{/if}}
|
|
56
48
|
|
|
57
49
|
return (
|
|
@@ -60,7 +52,11 @@ export default function Home() {
|
|
|
60
52
|
contentContainerStyle={styles.container}
|
|
61
53
|
showsVerticalScrollIndicator={false}
|
|
62
54
|
>
|
|
63
|
-
<Text style={styles.heroTitle}>
|
|
55
|
+
<Text style={styles.heroTitle}>
|
|
56
|
+
BETTER T STACK
|
|
57
|
+
</Text>
|
|
58
|
+
|
|
59
|
+
{{#unless (and (eq backend "convex") (eq auth "better-auth"))}}
|
|
64
60
|
<View style={styles.statusCard}>
|
|
65
61
|
<View style={styles.statusHeader}>
|
|
66
62
|
<Text style={styles.statusTitle}>System Status</Text>
|
|
@@ -70,123 +66,126 @@ export default function Home() {
|
|
|
70
66
|
</View>
|
|
71
67
|
{{#if (eq backend "convex")}}
|
|
72
68
|
{{#unless (eq auth "better-auth")}}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
</View>
|
|
69
|
+
<View style={styles.statusRow}>
|
|
70
|
+
<View
|
|
71
|
+
style={[
|
|
72
|
+
styles.statusDot,
|
|
73
|
+
healthCheck === "OK"
|
|
74
|
+
? styles.statusDotSuccess
|
|
75
|
+
: styles.statusDotWarning,
|
|
76
|
+
]}
|
|
77
|
+
/>
|
|
78
|
+
<View style={styles.statusContent}>
|
|
79
|
+
<Text style={styles.statusLabel}>Convex</Text>
|
|
80
|
+
<Text style={styles.statusDescription}>
|
|
81
|
+
{healthCheck === undefined
|
|
82
|
+
? "Checking connection..."
|
|
83
|
+
: healthCheck === "OK"
|
|
84
|
+
? "Connected to API"
|
|
85
|
+
: "API Disconnected"}
|
|
86
|
+
</Text>
|
|
92
87
|
</View>
|
|
88
|
+
</View>
|
|
93
89
|
{{/unless}}
|
|
94
90
|
{{else}}
|
|
95
91
|
{{#unless (eq api "none")}}
|
|
96
|
-
|
|
97
|
-
<View
|
|
98
|
-
style={[
|
|
99
|
-
styles.statusDot,
|
|
100
|
-
healthCheck.data
|
|
101
|
-
? styles.statusDotSuccess
|
|
102
|
-
: styles.statusDotWarning,
|
|
103
|
-
]}
|
|
104
|
-
/>
|
|
105
|
-
<View style={styles.statusContent}>
|
|
106
|
-
<Text style={styles.statusLabel}>
|
|
107
|
-
{{#if (eq api "orpc")}}ORPC{{/if}}
|
|
108
|
-
{{#if (eq api "trpc")}}TRPC{{/if}}
|
|
109
|
-
</Text>
|
|
110
|
-
<Text style={styles.statusDescription}>
|
|
111
|
-
{(healthCheck.isLoading)
|
|
112
|
-
? "Checking connection..."
|
|
113
|
-
: healthCheck.data
|
|
114
|
-
? "All systems operational"
|
|
115
|
-
: "Service unavailable"}
|
|
116
|
-
</Text>
|
|
117
|
-
</View>
|
|
118
|
-
</View>
|
|
119
|
-
{{/unless}}
|
|
120
|
-
{{/if}}
|
|
121
|
-
</View>
|
|
122
|
-
{{#if (and (eq backend "convex") (eq auth "clerk"))}}
|
|
123
|
-
<Authenticated>
|
|
124
|
-
<Text>
|
|
125
|
-
Hello {user?.emailAddresses[0].emailAddress}
|
|
126
|
-
</Text>
|
|
127
|
-
<Text>
|
|
128
|
-
Private Data: {privateData?.message}
|
|
129
|
-
</Text>
|
|
130
|
-
<SignOutButton />
|
|
131
|
-
</Authenticated>
|
|
132
|
-
<Unauthenticated>
|
|
133
|
-
<Link href="/(auth)/sign-in">
|
|
134
|
-
<Text>Sign in</Text>
|
|
135
|
-
</Link>
|
|
136
|
-
<Link href="/(auth)/sign-up">
|
|
137
|
-
<Text>Sign up</Text>
|
|
138
|
-
</Link>
|
|
139
|
-
</Unauthenticated>
|
|
140
|
-
<AuthLoading>
|
|
141
|
-
<Text>Loading...</Text>
|
|
142
|
-
</AuthLoading>
|
|
143
|
-
{{/if}}
|
|
144
|
-
{{#if (and (eq backend "convex") (eq auth "better-auth"))}}
|
|
145
|
-
{user ? (
|
|
146
|
-
<View style={styles.userCard}>
|
|
147
|
-
<View style={styles.userHeader}>
|
|
148
|
-
<Text style={styles.userWelcome}>
|
|
149
|
-
Welcome,{" "}
|
|
150
|
-
<Text style={styles.userName}>{user.name}</Text>
|
|
151
|
-
</Text>
|
|
152
|
-
</View>
|
|
153
|
-
<Text style={styles.userEmail}>{user.email}</Text>
|
|
154
|
-
<TouchableOpacity
|
|
155
|
-
style={styles.signOutButton}
|
|
156
|
-
onPress={() => {
|
|
157
|
-
authClient.signOut();
|
|
158
|
-
}}
|
|
159
|
-
>
|
|
160
|
-
<Text style={styles.signOutText}>Sign Out</Text>
|
|
161
|
-
</TouchableOpacity>
|
|
162
|
-
</View>
|
|
163
|
-
) : null}
|
|
164
|
-
<View style={styles.apiStatusCard}>
|
|
165
|
-
<Text style={styles.apiStatusTitle}>API Status</Text>
|
|
166
|
-
<View style={styles.apiStatusRow}>
|
|
92
|
+
<View style={styles.statusRow}>
|
|
167
93
|
<View
|
|
168
94
|
style={[
|
|
169
95
|
styles.statusDot,
|
|
170
|
-
healthCheck
|
|
96
|
+
healthCheck.data
|
|
171
97
|
? styles.statusDotSuccess
|
|
172
98
|
: styles.statusDotWarning,
|
|
173
99
|
]}
|
|
174
100
|
/>
|
|
175
|
-
<
|
|
176
|
-
{
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
101
|
+
<View style={styles.statusContent}>
|
|
102
|
+
<Text style={styles.statusLabel}>
|
|
103
|
+
{{#if (eq api "orpc")}}ORPC{{/if}}
|
|
104
|
+
{{#if (eq api "trpc")}}TRPC{{/if}}
|
|
105
|
+
</Text>
|
|
106
|
+
<Text style={styles.statusDescription}>
|
|
107
|
+
{healthCheck.isLoading
|
|
108
|
+
? "Checking connection..."
|
|
109
|
+
: healthCheck.data
|
|
110
|
+
? "Connected to API"
|
|
111
|
+
: "API Disconnected"}
|
|
112
|
+
</Text>
|
|
113
|
+
</View>
|
|
114
|
+
</View>
|
|
115
|
+
{{/unless}}
|
|
116
|
+
{{/if}}
|
|
117
|
+
</View>
|
|
118
|
+
{{/unless}}
|
|
119
|
+
|
|
120
|
+
{{#if (and (eq backend "convex") (eq auth "clerk"))}}
|
|
121
|
+
<Authenticated>
|
|
122
|
+
<Text>
|
|
123
|
+
Hello {user?.emailAddresses[0].emailAddress}
|
|
124
|
+
</Text>
|
|
125
|
+
<Text>
|
|
126
|
+
Private Data: {privateData?.message}
|
|
127
|
+
</Text>
|
|
128
|
+
<SignOutButton />
|
|
129
|
+
</Authenticated>
|
|
130
|
+
<Unauthenticated>
|
|
131
|
+
<Link href="/(auth)/sign-in">
|
|
132
|
+
<Text>Sign in</Text>
|
|
133
|
+
</Link>
|
|
134
|
+
<Link href="/(auth)/sign-up">
|
|
135
|
+
<Text>Sign up</Text>
|
|
136
|
+
</Link>
|
|
137
|
+
</Unauthenticated>
|
|
138
|
+
<AuthLoading>
|
|
139
|
+
<Text>Loading...</Text>
|
|
140
|
+
</AuthLoading>
|
|
141
|
+
{{/if}}
|
|
142
|
+
|
|
143
|
+
{{#if (and (eq backend "convex") (eq auth "better-auth"))}}
|
|
144
|
+
{user ? (
|
|
145
|
+
<View style={styles.userCard}>
|
|
146
|
+
<View style={styles.userHeader}>
|
|
147
|
+
<Text style={styles.userWelcome}>
|
|
148
|
+
Welcome,{" "}
|
|
149
|
+
<Text style={styles.userName}>{user.name}</Text>
|
|
181
150
|
</Text>
|
|
182
151
|
</View>
|
|
152
|
+
<Text style={styles.userEmail}>{user.email}</Text>
|
|
153
|
+
<TouchableOpacity
|
|
154
|
+
style={styles.signOutButton}
|
|
155
|
+
onPress={() => {
|
|
156
|
+
authClient.signOut();
|
|
157
|
+
}}
|
|
158
|
+
>
|
|
159
|
+
<Text style={styles.signOutText}>Sign Out</Text>
|
|
160
|
+
</TouchableOpacity>
|
|
183
161
|
</View>
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
162
|
+
) : null}
|
|
163
|
+
<View style={styles.apiStatusCard}>
|
|
164
|
+
<Text style={styles.apiStatusTitle}>API Status</Text>
|
|
165
|
+
<View style={styles.apiStatusRow}>
|
|
166
|
+
<View
|
|
167
|
+
style={[
|
|
168
|
+
styles.statusDot,
|
|
169
|
+
healthCheck === "OK"
|
|
170
|
+
? styles.statusDotSuccess
|
|
171
|
+
: styles.statusDotWarning,
|
|
172
|
+
]}
|
|
173
|
+
/>
|
|
174
|
+
<Text style={styles.apiStatusText}>
|
|
175
|
+
{healthCheck === undefined
|
|
176
|
+
? "Checking..."
|
|
177
|
+
: healthCheck === "OK"
|
|
178
|
+
? "Connected to API"
|
|
179
|
+
: "API Disconnected"}
|
|
180
|
+
</Text>
|
|
181
|
+
</View>
|
|
182
|
+
</View>
|
|
183
|
+
{!user && (
|
|
184
|
+
<>
|
|
185
|
+
<SignIn />
|
|
186
|
+
<SignUp />
|
|
187
|
+
</>
|
|
188
|
+
)}
|
|
190
189
|
{{/if}}
|
|
191
190
|
</ScrollView>
|
|
192
191
|
</Container>
|