create-better-t-stack 3.6.1 → 3.6.3

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as createBtsCli } from "./src-DaTuAN3w.js";
2
+ import { n as createBtsCli } from "./src-BN3eh8p0.js";
3
3
 
4
4
  //#region src/cli.ts
5
5
  createBtsCli().run();
package/dist/index.d.ts CHANGED
@@ -126,6 +126,7 @@ declare const TemplateSchema: z.ZodEnum<{
126
126
  mern: "mern";
127
127
  pern: "pern";
128
128
  t3: "t3";
129
+ uniwind: "uniwind";
129
130
  none: "none";
130
131
  }>;
131
132
  type Template = z.infer<typeof TemplateSchema>;
@@ -221,6 +222,7 @@ declare const router: {
221
222
  mern: "mern";
222
223
  pern: "pern";
223
224
  t3: "t3";
225
+ uniwind: "uniwind";
224
226
  none: "none";
225
227
  }>>;
226
228
  yes: z$1.ZodDefault<z$1.ZodOptional<z$1.ZodBoolean>>;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { a as router, i as init, n as createBtsCli, o as sponsors, r as docs, t as builder } from "./src-DaTuAN3w.js";
2
+ import { a as router, i as init, n as createBtsCli, o as sponsors, r as docs, t as builder } from "./src-BN3eh8p0.js";
3
3
 
4
4
  export { builder, createBtsCli, docs, init, router, sponsors };
@@ -88,6 +88,7 @@ const dependencyVersionMap = {
88
88
  "@prisma/adapter-better-sqlite3": "^7.0.0",
89
89
  "@prisma/adapter-pg": "^7.0.0",
90
90
  "@prisma/adapter-planetscale": "^7.0.0",
91
+ "@prisma/adapter-ppg": "^7.0.0",
91
92
  mongoose: "^8.14.0",
92
93
  "vite-plugin-pwa": "^1.0.1",
93
94
  "@vite-pwa/assets-generator": "^1.0.0",
@@ -295,6 +296,7 @@ const TemplateSchema = z.enum([
295
296
  "mern",
296
297
  "pern",
297
298
  "t3",
299
+ "uniwind",
298
300
  "none"
299
301
  ]).describe("Predefined project template");
300
302
 
@@ -1632,6 +1634,21 @@ const TEMPLATE_PRESETS = {
1632
1634
  webDeploy: "none",
1633
1635
  serverDeploy: "none"
1634
1636
  },
1637
+ uniwind: {
1638
+ database: "none",
1639
+ orm: "none",
1640
+ backend: "none",
1641
+ runtime: "none",
1642
+ frontend: ["native-uniwind"],
1643
+ api: "none",
1644
+ auth: "none",
1645
+ payments: "none",
1646
+ addons: ["none"],
1647
+ examples: ["none"],
1648
+ dbSetup: "none",
1649
+ webDeploy: "none",
1650
+ serverDeploy: "none"
1651
+ },
1635
1652
  none: null
1636
1653
  };
1637
1654
  function getTemplateConfig(template) {
@@ -1645,6 +1662,7 @@ function getTemplateDescription(template) {
1645
1662
  mern: "MongoDB + Express + React + Node.js - Classic MERN stack",
1646
1663
  pern: "PostgreSQL + Express + React + Node.js - Popular PERN stack",
1647
1664
  t3: "T3 Stack - Next.js + tRPC + Prisma + PostgreSQL + Better Auth",
1665
+ uniwind: "Expo + Uniwind native app with no backend services",
1648
1666
  none: "No template - Full customization"
1649
1667
  }[template] || "";
1650
1668
  }
@@ -5216,31 +5234,6 @@ async function setupWithCreateDb(serverDir, packageManager) {
5216
5234
  return null;
5217
5235
  }
5218
5236
  }
5219
- async function initPrismaDatabase(serverDir, packageManager) {
5220
- try {
5221
- const prismaDir = path.join(serverDir, "prisma");
5222
- await fs.ensureDir(prismaDir);
5223
- log.info("Starting Prisma PostgreSQL setup.");
5224
- await execa(getPackageExecutionCommand(packageManager, "prisma init --db"), {
5225
- cwd: serverDir,
5226
- stdio: "inherit",
5227
- shell: true
5228
- });
5229
- log.info(pc.yellow("Please copy the Prisma Postgres URL.\nIt looks like: postgresql://user:password@host:5432/db?sslmode=require"));
5230
- const databaseUrl = await text({
5231
- message: "Paste your Prisma Postgres database URL:",
5232
- validate(value) {
5233
- if (!value) return "Please enter a database URL";
5234
- if (!value.startsWith("postgresql://")) return "URL should start with postgresql://";
5235
- }
5236
- });
5237
- if (isCancel(databaseUrl)) return null;
5238
- return { databaseUrl };
5239
- } catch (error) {
5240
- if (error instanceof Error) consola$1.error(error.message);
5241
- return null;
5242
- }
5243
- }
5244
5237
  async function writeEnvFile$1(projectDir, backend, config) {
5245
5238
  try {
5246
5239
  const targetApp = backend === "self" ? "apps/web" : "apps/server";
@@ -5260,16 +5253,6 @@ async function writeEnvFile$1(projectDir, backend, config) {
5260
5253
  consola$1.error("Failed to update environment configuration");
5261
5254
  }
5262
5255
  }
5263
- async function addDotenvImportToPrismaConfig(projectDir, backend) {
5264
- try {
5265
- const prismaConfigPath = path.join(projectDir, "packages/db/prisma.config.ts");
5266
- let content = await fs.readFile(prismaConfigPath, "utf8");
5267
- content = `import dotenv from "dotenv";\ndotenv.config({ path: "${backend === "self" ? "../../apps/web/.env" : "../../apps/server/.env"}" });\n${content}`;
5268
- await fs.writeFile(prismaConfigPath, content);
5269
- } catch (_error) {
5270
- consola$1.error("Failed to update prisma.config.ts");
5271
- }
5272
- }
5273
5256
  function displayManualSetupInstructions$1(target) {
5274
5257
  log.info(`Manual Prisma PostgreSQL Setup Instructions:
5275
5258
 
@@ -5281,7 +5264,7 @@ function displayManualSetupInstructions$1(target) {
5281
5264
  DATABASE_URL="your_database_url"`);
5282
5265
  }
5283
5266
  async function setupPrismaPostgres(config, cliInput) {
5284
- const { packageManager, projectDir, orm, backend } = config;
5267
+ const { packageManager, projectDir, backend } = config;
5285
5268
  const manualDb = cliInput?.manualDb ?? false;
5286
5269
  const dbDir = path.join(projectDir, "packages/db");
5287
5270
  try {
@@ -5291,47 +5274,28 @@ async function setupPrismaPostgres(config, cliInput) {
5291
5274
  displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
5292
5275
  return;
5293
5276
  }
5294
- const mode = await select({
5277
+ const setupMode = await select({
5295
5278
  message: "Prisma Postgres setup: choose mode",
5296
5279
  options: [{
5297
- label: "Automatic",
5280
+ label: "Automatic (create-db)",
5298
5281
  value: "auto",
5299
- hint: "Automated setup with provider CLI, sets .env"
5282
+ hint: "Provision a database via Prisma's create-db CLI"
5300
5283
  }, {
5301
5284
  label: "Manual",
5302
5285
  value: "manual",
5303
- hint: "Manual setup, add env vars yourself"
5286
+ hint: "Add your own DATABASE_URL later"
5304
5287
  }],
5305
5288
  initialValue: "auto"
5306
5289
  });
5307
- if (isCancel(mode)) return exitCancelled("Operation cancelled");
5308
- if (mode === "manual") {
5290
+ if (isCancel(setupMode)) return;
5291
+ if (setupMode === "manual") {
5309
5292
  await writeEnvFile$1(projectDir, backend);
5310
5293
  displayManualSetupInstructions$1(backend === "self" ? "apps/web" : "apps/server");
5311
5294
  return;
5312
5295
  }
5313
- const setupOptions = [{
5314
- label: "Quick setup with create-db",
5315
- value: "create-db",
5316
- hint: "Fastest, automated database creation (no auth)"
5317
- }];
5318
- if (orm === "prisma") setupOptions.push({
5319
- label: "Custom setup with Prisma Init",
5320
- value: "custom",
5321
- hint: "More control (requires auth)"
5322
- });
5323
- const setupMethod = await select({
5324
- message: "Choose your Prisma Postgres setup method:",
5325
- options: setupOptions,
5326
- initialValue: "create-db"
5327
- });
5328
- if (isCancel(setupMethod)) return exitCancelled("Operation cancelled");
5329
- let prismaConfig = null;
5330
- if (setupMethod === "create-db") prismaConfig = await setupWithCreateDb(dbDir, packageManager);
5331
- else prismaConfig = await initPrismaDatabase(dbDir, packageManager);
5296
+ const prismaConfig = await setupWithCreateDb(dbDir, packageManager);
5332
5297
  if (prismaConfig) {
5333
5298
  await writeEnvFile$1(projectDir, backend, prismaConfig);
5334
- if (orm === "prisma") await addDotenvImportToPrismaConfig(projectDir, backend);
5335
5299
  log.success(pc.green("Prisma Postgres database configured successfully!"));
5336
5300
  if (prismaConfig.claimUrl) log.info(pc.blue(`Claim URL saved to .env: ${prismaConfig.claimUrl}`));
5337
5301
  } else {
@@ -5748,7 +5712,8 @@ async function setupDatabase(config, cliInput) {
5748
5712
  else if (database === "postgres") if (dbSetup === "neon") {
5749
5713
  prismaDependencies.push("@prisma/adapter-neon", "@neondatabase/serverless", "ws");
5750
5714
  prismaDevDependencies.push("@types/ws");
5751
- } else {
5715
+ } else if (dbSetup === "prisma-postgres") prismaDependencies.push("@prisma/adapter-ppg");
5716
+ else {
5752
5717
  prismaDependencies.push("@prisma/adapter-pg");
5753
5718
  prismaDependencies.push("pg");
5754
5719
  prismaDevDependencies.push("@types/pg");
@@ -6326,7 +6291,7 @@ async function displayPostInstallInstructions(config) {
6326
6291
  const databaseInstructions = !isConvex && database !== "none" ? await getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, serverDeploy, backend) : "";
6327
6292
  const tauriInstructions = addons?.includes("tauri") ? getTauriInstructions(runCmd) : "";
6328
6293
  const lintingInstructions = hasHuskyOrBiome ? getLintingInstructions(runCmd) : "";
6329
- const nativeInstructions = frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles") ? getNativeInstructions(isConvex, isBackendSelf, frontend || []) : "";
6294
+ const nativeInstructions = (frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles")) && backend !== "none" ? getNativeInstructions(isConvex, isBackendSelf, frontend || []) : "";
6330
6295
  const pwaInstructions = addons?.includes("pwa") && frontend?.includes("react-router") ? getPwaInstructions() : "";
6331
6296
  const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
6332
6297
  const clerkInstructions = isConvex && config.auth === "clerk" ? getClerkInstructions() : "";
@@ -6363,16 +6328,19 @@ async function displayPostInstallInstructions(config) {
6363
6328
  output += `${pc.cyan(`${stepCounter++}.`)} ${runCmd} dev\n`;
6364
6329
  }
6365
6330
  }
6366
- output += `${pc.bold("Your project will be available at:")}\n`;
6367
- if (hasWeb) output += `${pc.cyan("")} Frontend: http://localhost:${webPort}\n`;
6368
- else if (!hasNative && !addons?.includes("starlight")) output += `${pc.yellow("NOTE:")} You are creating a backend-only app\n (no frontend selected)\n`;
6369
- if (!isConvex && !isBackendSelf) {
6370
- output += `${pc.cyan("")} Backend API: http://localhost:3000\n`;
6371
- if (api === "orpc") output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/api-reference\n`;
6331
+ const hasStandaloneBackend = backend !== "none";
6332
+ if (hasWeb || hasStandaloneBackend || addons?.includes("starlight") || addons?.includes("fumadocs")) {
6333
+ output += `${pc.bold("Your project will be available at:")}\n`;
6334
+ if (hasWeb) output += `${pc.cyan("•")} Frontend: http://localhost:${webPort}\n`;
6335
+ else if (!hasNative && !addons?.includes("starlight")) output += `${pc.yellow("NOTE:")} You are creating a backend-only app\n (no frontend selected)\n`;
6336
+ if (!isConvex && !isBackendSelf && hasStandaloneBackend) {
6337
+ output += `${pc.cyan("•")} Backend API: http://localhost:3000\n`;
6338
+ if (api === "orpc") output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/api-reference\n`;
6339
+ }
6340
+ if (isBackendSelf && api === "orpc") output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:${webPort}/api/rpc/api-reference\n`;
6341
+ if (addons?.includes("starlight")) output += `${pc.cyan("•")} Docs: http://localhost:4321\n`;
6342
+ if (addons?.includes("fumadocs")) output += `${pc.cyan("•")} Fumadocs: http://localhost:4000\n`;
6372
6343
  }
6373
- if (isBackendSelf && api === "orpc") output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:${webPort}/api/rpc/api-reference\n`;
6374
- if (addons?.includes("starlight")) output += `${pc.cyan("•")} Docs: http://localhost:4321\n`;
6375
- if (addons?.includes("fumadocs")) output += `${pc.cyan("•")} Fumadocs: http://localhost:4000\n`;
6376
6344
  if (nativeInstructions) output += `\n${nativeInstructions.trim()}\n`;
6377
6345
  if (databaseInstructions) output += `\n${databaseInstructions.trim()}\n`;
6378
6346
  if (tauriInstructions) output += `\n${tauriInstructions.trim()}\n`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "3.6.1",
3
+ "version": "3.6.3",
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",
@@ -1,6 +1,5 @@
1
1
  import path from "node:path";
2
2
  import { defineConfig, env } from 'prisma/config'
3
- {{#unless (eq dbSetup "prisma-postgres")}}
4
3
  import dotenv from 'dotenv'
5
4
 
6
5
  dotenv.config({
@@ -10,7 +9,6 @@ dotenv.config({
10
9
  path: "../../apps/server/.env",
11
10
  {{/if}}
12
11
  })
13
- {{/unless}}
14
12
 
15
13
  export default defineConfig({
16
14
  schema: path.join("prisma", "schema"),
@@ -13,6 +13,15 @@ const prisma = new PrismaClient({
13
13
  }),
14
14
  });
15
15
 
16
+ {{else if (eq dbSetup "prisma-postgres")}}
17
+ import { PrismaPostgresAdapter } from "@prisma/adapter-ppg";
18
+
19
+ const adapter = new PrismaPostgresAdapter({
20
+ connectionString: env.DATABASE_URL || "",
21
+ });
22
+
23
+ const prisma = new PrismaClient({ adapter });
24
+
16
25
  {{else}}
17
26
  import { PrismaPg } from "@prisma/adapter-pg";
18
27
 
@@ -38,6 +47,15 @@ const adapter = new PrismaNeon({
38
47
 
39
48
  const prisma = new PrismaClient({ adapter });
40
49
 
50
+ {{else if (eq dbSetup "prisma-postgres")}}
51
+ import { PrismaPostgresAdapter } from "@prisma/adapter-ppg";
52
+
53
+ const adapter = new PrismaPostgresAdapter({
54
+ connectionString: process.env.DATABASE_URL || "",
55
+ });
56
+
57
+ const prisma = new PrismaClient({ adapter });
58
+
41
59
  {{else}}
42
60
  import { PrismaPg } from "@prisma/adapter-pg";
43
61
 
@@ -24,128 +24,124 @@ import { SignUp } from "@/components/sign-up";
24
24
  import { useQuery } from "convex/react";
25
25
  import { api } from "@{{projectName}}/backend/convex/_generated/api";
26
26
  {{/if}}
27
+ {{#unless (eq backend "none")}}
27
28
  import { Ionicons } from "@expo/vector-icons";
29
+ {{/unless}}
28
30
  import { Card, Chip, useThemeColor } from "heroui-native";
29
31
 
30
32
  export default function Home() {
31
33
  {{#if (eq api "orpc")}}
32
- const healthCheck = useQuery(orpc.healthCheck.queryOptions());
34
+ const healthCheck = useQuery(orpc.healthCheck.queryOptions());
33
35
  {{/if}}
34
36
  {{#if (eq api "trpc")}}
35
- const healthCheck = useQuery(trpc.healthCheck.queryOptions());
37
+ const healthCheck = useQuery(trpc.healthCheck.queryOptions());
36
38
  {{/if}}
37
39
  {{#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);
40
+ const { user } = useUser();
41
+ const healthCheck = useQuery(api.healthCheck.get);
42
+ const privateData = useQuery(api.privateData.get);
41
43
  {{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");
44
+ const healthCheck = useQuery(api.healthCheck.get);
45
+ const { isAuthenticated } = useConvexAuth();
46
+ const user = useQuery(api.auth.getCurrentUser, isAuthenticated ? {} : "skip");
45
47
  {{else if (eq backend "convex")}}
46
- const healthCheck = useQuery(api.healthCheck.get);
48
+ const healthCheck = useQuery(api.healthCheck.get);
47
49
  {{/if}}
48
- const mutedColor = useThemeColor("muted");
49
- const successColor = useThemeColor("success");
50
- const dangerColor = useThemeColor("danger");
50
+ {{#unless (eq backend "none")}}
51
+ const mutedColor = useThemeColor("muted");
52
+ const successColor = useThemeColor("success");
53
+ const dangerColor = useThemeColor("danger");
51
54
 
52
55
  {{#if (eq backend "convex")}}
53
- const isConnected = healthCheck === "OK";
54
- const isLoading = healthCheck === undefined;
56
+ const isConnected = healthCheck === "OK";
57
+ const isLoading = healthCheck === undefined;
55
58
  {{else}}
56
59
  {{#unless (eq api "none")}}
57
- const isConnected = healthCheck?.data === "OK";
58
- const isLoading = healthCheck?.isLoading;
60
+ const isConnected = healthCheck?.data === "OK";
61
+ const isLoading = healthCheck?.isLoading;
59
62
  {{/unless}}
60
63
  {{/if}}
64
+ {{/unless}}
61
65
 
62
- return (
63
- <Container className="p-6">
64
- <View className="py-4 mb-6">
65
- <Text className="text-4xl font-bold text-foreground mb-2">
66
- BETTER T STACK
67
- </Text>
68
- </View>
69
-
70
- {{#unless (and (eq backend "convex") (eq auth "better-auth"))}}
71
- <Card variant="secondary" className="p-6">
72
- <View className="flex-row items-center justify-between mb-4">
73
- <Card.Title>System Status</Card.Title>
74
- <Chip
75
- variant="secondary"
76
- color={isConnected ? "success" : "danger"}
77
- size="sm"
78
- >
79
- <Chip.Label>
80
- {isConnected ? "LIVE" : "OFFLINE"}
81
- </Chip.Label>
82
- </Chip>
83
- </View>
84
- <Card className="p-4">
85
- <View className="flex-row items-center">
86
- <View
87
- className={`w-3 h-3 rounded-full mr-3 ${
88
- isConnected ? "bg-success" : "bg-muted"
89
- }`}
90
- />
91
- <View className="flex-1">
92
- <Text className="text-foreground font-medium mb-1">
93
- {{#if (eq backend "convex")}}
94
- Convex Backend
95
- {{else}}
96
- {{#unless (eq api "none")}}
97
- {{#if (eq api "orpc")}}ORPC{{else}}TRPC{{/if}} Backend
98
- {{/unless}}
99
- {{/if}}
100
- </Text>
101
- <Card.Description>
102
- {isLoading
103
- ? "Checking connection..."
104
- : isConnected
105
- ? "Connected to API"
106
- : "API Disconnected"}
107
- </Card.Description>
108
- </View>
109
- {isLoading && (
110
- <Ionicons name="hourglass-outline" size={20} color={mutedColor} />
111
- )}
112
- {!isLoading && isConnected && (
113
- <Ionicons name="checkmark-circle" size={20} color={successColor} />
114
- )}
115
- {!isLoading && !isConnected && (
116
- <Ionicons name="close-circle" size={20} color={dangerColor} />
117
- )}
118
- </View>
119
- </Card>
120
- </Card>
121
- {{/unless}}
66
+ return (
67
+ <Container className="p-6">
68
+ <View className="py-4 mb-6">
69
+ <Text className="text-4xl font-bold text-foreground mb-2">
70
+ BETTER T STACK
71
+ </Text>
72
+ </View>
122
73
 
123
- {{#if (and (eq backend "convex") (eq auth "clerk"))}}
124
- <Authenticated>
125
- <Card variant="secondary" className="mt-6 p-4">
126
- <Text className="text-foreground text-base mb-2">
127
- Hello {user?.emailAddresses[0].emailAddress}
128
- </Text>
129
- <Text className="text-muted text-sm mb-4">
130
- Private Data: {privateData?.message}
74
+ {{#unless (or (eq backend "none") (and (eq backend "convex") (eq auth "better-auth")))}}
75
+ <Card variant="secondary" className="p-6">
76
+ <View className="flex-row items-center justify-between mb-4">
77
+ <Card.Title>System Status</Card.Title>
78
+ <Chip variant="secondary" color={isConnected ? "success" : "danger" } size="sm">
79
+ <Chip.Label>
80
+ {isConnected ? "LIVE" : "OFFLINE"}
81
+ </Chip.Label>
82
+ </Chip>
83
+ </View>
84
+ <Card className="p-4">
85
+ <View className="flex-row items-center">
86
+ <View className={`w-3 h-3 rounded-full mr-3 ${ isConnected ? "bg-success" : "bg-muted" }`} />
87
+ <View className="flex-1">
88
+ <Text className="text-foreground font-medium mb-1">
89
+ {{#if (eq backend "convex")}}
90
+ Convex Backend
91
+ {{else}}
92
+ {{#unless (eq api "none")}}
93
+ {{#if (eq api "orpc")}}ORPC{{else}}TRPC{{/if}} Backend
94
+ {{/unless}}
95
+ {{/if}}
131
96
  </Text>
132
- <SignOutButton />
133
- </Card>
134
- </Authenticated>
135
- <Unauthenticated>
136
- <View className="mt-6 gap-4">
137
- <Link href="/(auth)/sign-in" asChild>
138
- <Text className="text-primary font-semibold">Sign in</Text>
139
- </Link>
140
- <Link href="/(auth)/sign-up" asChild>
141
- <Text className="text-primary font-semibold">Sign up</Text>
142
- </Link>
97
+ <Card.Description>
98
+ {isLoading
99
+ ? "Checking connection..."
100
+ : isConnected
101
+ ? "Connected to API"
102
+ : "API Disconnected"}
103
+ </Card.Description>
143
104
  </View>
144
- </Unauthenticated>
145
- <AuthLoading>
146
- <Text className="text-muted">Loading...</Text>
147
- </AuthLoading>
148
- {{/if}}
149
- </Container>
150
- );
105
+ {isLoading && (
106
+ <Ionicons name="hourglass-outline" size={20} color={mutedColor} />
107
+ )}
108
+ {!isLoading && isConnected && (
109
+ <Ionicons name="checkmark-circle" size={20} color={successColor} />
110
+ )}
111
+ {!isLoading && !isConnected && (
112
+ <Ionicons name="close-circle" size={20} color={dangerColor} />
113
+ )}
114
+ </View>
115
+ </Card>
116
+ </Card>
117
+ {{/unless}}
118
+
119
+ {{#if (and (eq backend "convex") (eq auth "clerk"))}}
120
+ <Authenticated>
121
+ <Card variant="secondary" className="mt-6 p-4">
122
+ <Text className="text-foreground text-base mb-2">
123
+ Hello {user?.emailAddresses[0].emailAddress}
124
+ </Text>
125
+ <Text className="text-muted text-sm mb-4">
126
+ Private Data: {privateData?.message}
127
+ </Text>
128
+ <SignOutButton />
129
+ </Card>
130
+ </Authenticated>
131
+ <Unauthenticated>
132
+ <View className="mt-6 gap-4">
133
+ <Link href="/(auth)/sign-in" asChild>
134
+ <Text className="text-primary font-semibold">Sign in</Text>
135
+ </Link>
136
+ <Link href="/(auth)/sign-up" asChild>
137
+ <Text className="text-primary font-semibold">Sign up</Text>
138
+ </Link>
139
+ </View>
140
+ </Unauthenticated>
141
+ <AuthLoading>
142
+ <Text className="text-muted">Loading...</Text>
143
+ </AuthLoading>
144
+ {{/if}}
145
+ </Container>
146
+ );
151
147
  }
@@ -13,7 +13,7 @@
13
13
  "dependencies": {
14
14
  "@expo/metro-runtime": "~6.1.2",
15
15
  "@expo/vector-icons": "^15.0.3",
16
- "@gorhom/bottom-sheet": "^5",
16
+ "@gorhom/bottom-sheet": "^5.2.6",
17
17
  "@react-navigation/drawer": "^7.3.9",
18
18
  "@react-navigation/elements": "^2.8.1",
19
19
  {{#if (includes examples "ai")}}
@@ -29,22 +29,22 @@
29
29
  "expo-router": "~6.0.14",
30
30
  "expo-secure-store": "~15.0.7",
31
31
  "expo-status-bar": "~3.0.8",
32
- "heroui-native": "^1.0.0-beta.1",
32
+ "heroui-native": "1.0.0-beta.3",
33
33
  "react": "19.1.0",
34
34
  "react-dom": "19.1.0",
35
35
  "react-native": "0.81.5",
36
36
  "react-native-gesture-handler": "~2.28.0",
37
37
  "react-native-keyboard-controller": "1.18.5",
38
- "react-native-reanimated": "~4.1.0",
38
+ "react-native-reanimated": "~4.1.5",
39
39
  "react-native-safe-area-context": "5.6.0",
40
40
  "react-native-screens": "~4.16.0",
41
41
  "react-native-svg": "15.12.1",
42
42
  "react-native-web": "^0.21.0",
43
43
  "react-native-worklets": "0.5.1",
44
- "tailwind-merge": "^3.3.1",
45
- "tailwind-variants": "^3.1.0",
46
- "tailwindcss": "~4.1.16",
47
- "uniwind": "^1.0.0"
44
+ "tailwind-merge": "^3.4.0",
45
+ "tailwind-variants": "3.1.1",
46
+ "tailwindcss": "~4.1.17",
47
+ "uniwind": "^1.0.4"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/node": "^24.10.0",