create-better-t-stack 3.2.23 → 3.3.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 (86) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.js +1 -1
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.js +1 -1
  5. package/dist/{src-Cx7HDf0b.js → src-82W1Q-C5.js} +82 -54
  6. package/package.json +1 -1
  7. package/templates/addons/biome/biome.json.hbs +5 -0
  8. package/templates/auth/better-auth/convex/backend/convex/auth.ts.hbs +5 -5
  9. package/templates/auth/better-auth/convex/backend/convex/http.ts.hbs +1 -1
  10. package/templates/auth/better-auth/convex/native/bare/components/sign-in.tsx.hbs +127 -0
  11. package/templates/auth/better-auth/convex/native/bare/components/sign-up.tsx.hbs +138 -0
  12. package/templates/auth/better-auth/convex/native/uniwind/components/sign-in.tsx.hbs +91 -0
  13. package/templates/auth/better-auth/convex/native/uniwind/components/sign-up.tsx.hbs +102 -0
  14. package/templates/auth/better-auth/native/bare/app/(drawer)/index.tsx.hbs +186 -0
  15. package/templates/auth/better-auth/native/bare/components/sign-in.tsx.hbs +131 -0
  16. package/templates/auth/better-auth/native/bare/components/sign-up.tsx.hbs +150 -0
  17. package/templates/auth/better-auth/native/unistyles/app/(drawer)/index.tsx.hbs +9 -1
  18. package/templates/auth/better-auth/native/unistyles/components/sign-in.tsx.hbs +5 -0
  19. package/templates/auth/better-auth/native/unistyles/components/sign-up.tsx.hbs +5 -0
  20. package/templates/auth/better-auth/native/uniwind/app/(drawer)/index.tsx.hbs +123 -0
  21. package/templates/auth/better-auth/native/uniwind/components/sign-in.tsx.hbs +90 -0
  22. package/templates/auth/better-auth/native/uniwind/components/sign-up.tsx.hbs +116 -0
  23. package/templates/auth/better-auth/server/base/src/index.ts.hbs +5 -5
  24. package/templates/examples/ai/native/bare/app/(drawer)/ai.tsx.hbs +287 -0
  25. package/templates/examples/ai/native/{nativewind → bare}/polyfills.js +1 -0
  26. package/templates/examples/ai/native/{nativewind → uniwind}/app/(drawer)/ai.tsx.hbs +52 -51
  27. package/templates/examples/ai/native/uniwind/polyfills.js +26 -0
  28. package/templates/examples/todo/native/bare/app/(drawer)/todos.tsx.hbs +521 -0
  29. package/templates/examples/todo/native/uniwind/app/(drawer)/todos.tsx.hbs +295 -0
  30. package/templates/extras/bunfig.toml.hbs +3 -3
  31. package/templates/frontend/native/bare/_gitignore +18 -0
  32. package/templates/frontend/native/{nativewind → bare}/app/(drawer)/(tabs)/_layout.tsx.hbs +7 -12
  33. package/templates/frontend/native/bare/app/(drawer)/(tabs)/index.tsx.hbs +43 -0
  34. package/templates/frontend/native/bare/app/(drawer)/(tabs)/two.tsx.hbs +43 -0
  35. package/templates/frontend/native/{nativewind → bare}/app/(drawer)/_layout.tsx.hbs +24 -1
  36. package/templates/frontend/native/bare/app/(drawer)/index.tsx.hbs +234 -0
  37. package/templates/frontend/native/bare/app/+not-found.tsx.hbs +65 -0
  38. package/templates/frontend/native/bare/app/_layout.tsx.hbs +163 -0
  39. package/templates/frontend/native/bare/app/modal.tsx.hbs +34 -0
  40. package/templates/frontend/native/{nativewind → bare}/app.json.hbs +1 -0
  41. package/templates/frontend/native/bare/components/container.tsx.hbs +25 -0
  42. package/templates/frontend/native/bare/components/header-button.tsx.hbs +47 -0
  43. package/templates/frontend/native/{nativewind → bare}/components/tabbar-icon.tsx.hbs +1 -0
  44. package/templates/frontend/native/{nativewind → bare}/lib/android-navigation-bar.tsx.hbs +1 -0
  45. package/templates/frontend/native/{nativewind → bare}/lib/constants.ts.hbs +1 -0
  46. package/templates/frontend/native/bare/lib/use-color-scheme.ts.hbs +20 -0
  47. package/templates/frontend/native/bare/metro.config.js.hbs +9 -0
  48. package/templates/frontend/native/{nativewind → bare}/package.json.hbs +1 -2
  49. package/templates/frontend/native/bare/tsconfig.json.hbs +11 -0
  50. package/templates/frontend/native/{nativewind → uniwind}/_gitignore +4 -8
  51. package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/_layout.tsx.hbs +46 -0
  52. package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/index.tsx.hbs +15 -0
  53. package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/two.tsx.hbs +15 -0
  54. package/templates/frontend/native/uniwind/app/(drawer)/_layout.tsx.hbs +83 -0
  55. package/templates/frontend/native/uniwind/app/(drawer)/index.tsx.hbs +151 -0
  56. package/templates/frontend/native/uniwind/app/+not-found.tsx.hbs +32 -0
  57. package/templates/frontend/native/uniwind/app/_layout.tsx.hbs +131 -0
  58. package/templates/frontend/native/uniwind/app/modal.tsx.hbs +53 -0
  59. package/templates/frontend/native/uniwind/app.json.hbs +19 -0
  60. package/templates/frontend/native/uniwind/components/container.tsx.hbs +33 -0
  61. package/templates/frontend/native/uniwind/components/theme-toggle.tsx.hbs +35 -0
  62. package/templates/frontend/native/uniwind/contexts/app-theme-context.tsx.hbs +62 -0
  63. package/templates/frontend/native/uniwind/global.css +5 -0
  64. package/templates/frontend/native/uniwind/metro.config.js.hbs +13 -0
  65. package/templates/frontend/native/uniwind/package.json.hbs +54 -0
  66. package/templates/frontend/native/{nativewind → uniwind}/tsconfig.json.hbs +4 -8
  67. package/templates/auth/better-auth/convex/native/nativewind/components/sign-in.tsx.hbs +0 -86
  68. package/templates/auth/better-auth/convex/native/nativewind/components/sign-up.tsx.hbs +0 -97
  69. package/templates/auth/better-auth/native/nativewind/app/(drawer)/index.tsx.hbs +0 -95
  70. package/templates/auth/better-auth/native/nativewind/components/sign-in.tsx.hbs +0 -93
  71. package/templates/auth/better-auth/native/nativewind/components/sign-up.tsx.hbs +0 -104
  72. package/templates/examples/todo/native/nativewind/app/(drawer)/todos.tsx.hbs +0 -295
  73. package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/index.tsx.hbs +0 -19
  74. package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/two.tsx.hbs +0 -19
  75. package/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs +0 -178
  76. package/templates/frontend/native/nativewind/app/+not-found.tsx.hbs +0 -29
  77. package/templates/frontend/native/nativewind/app/_layout.tsx.hbs +0 -175
  78. package/templates/frontend/native/nativewind/app/modal.tsx.hbs +0 -14
  79. package/templates/frontend/native/nativewind/babel.config.js.hbs +0 -14
  80. package/templates/frontend/native/nativewind/components/container.tsx.hbs +0 -8
  81. package/templates/frontend/native/nativewind/components/header-button.tsx.hbs +0 -26
  82. package/templates/frontend/native/nativewind/global.css +0 -50
  83. package/templates/frontend/native/nativewind/lib/use-color-scheme.ts.hbs +0 -12
  84. package/templates/frontend/native/nativewind/metro.config.js.hbs +0 -12
  85. package/templates/frontend/native/nativewind/tailwind.config.js.hbs +0 -59
  86. /package/templates/auth/clerk/convex/native/base/app/(auth)/{sign-out.tsx.hbs → sign-up.tsx.hbs} +0 -0
package/README.md CHANGED
@@ -57,7 +57,7 @@ Options:
57
57
  --orm <type> ORM type (none, drizzle, prisma, mongoose)
58
58
  --auth Include authentication
59
59
  --no-auth Exclude authentication
60
- --frontend <types...> Frontend types (tanstack-router, react-router, tanstack-start, next, nuxt, svelte, solid, native-nativewind, native-unistyles, none)
60
+ --frontend <types...> Frontend types (tanstack-router, react-router, tanstack-start, next, nuxt, svelte, solid, native-bare, native-uniwind, native-unistyles, none)
61
61
  --addons <types...> Additional addons (pwa, tauri, starlight, biome, husky, turborepo, fumadocs, ultracite, oxlint, none)
62
62
  --examples <types...> Examples to include (todo, ai, none)
63
63
  --git Initialize git repository
@@ -119,7 +119,7 @@ npx create-better-t-stack my-app --backend elysia --runtime node
119
119
  Create a project with multiple frontend options (one web + one native):
120
120
 
121
121
  ```bash
122
- npx create-better-t-stack my-app --frontend tanstack-router native-nativewind
122
+ npx create-better-t-stack my-app --frontend tanstack-router native-bare
123
123
  ```
124
124
 
125
125
  Create a project with examples:
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { n as createBtsCli } from "./src-Cx7HDf0b.js";
2
+ import { n as createBtsCli } from "./src-82W1Q-C5.js";
3
3
 
4
4
  //#region src/cli.ts
5
5
  createBtsCli().run();
package/dist/index.d.ts CHANGED
@@ -43,7 +43,8 @@ declare const FrontendSchema: z.ZodEnum<{
43
43
  "tanstack-start": "tanstack-start";
44
44
  next: "next";
45
45
  nuxt: "nuxt";
46
- "native-nativewind": "native-nativewind";
46
+ "native-bare": "native-bare";
47
+ "native-uniwind": "native-uniwind";
47
48
  "native-unistyles": "native-unistyles";
48
49
  svelte: "svelte";
49
50
  solid: "solid";
@@ -242,7 +243,8 @@ declare const router: {
242
243
  "tanstack-start": "tanstack-start";
243
244
  next: "next";
244
245
  nuxt: "nuxt";
245
- "native-nativewind": "native-nativewind";
246
+ "native-bare": "native-bare";
247
+ "native-uniwind": "native-uniwind";
246
248
  "native-unistyles": "native-unistyles";
247
249
  svelte: "svelte";
248
250
  solid: "solid";
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-Cx7HDf0b.js";
2
+ import { a as router, i as init, n as createBtsCli, o as sponsors, r as docs, t as builder } from "./src-82W1Q-C5.js";
3
3
 
4
4
  export { builder, createBtsCli, docs, init, router, sponsors };
@@ -146,7 +146,7 @@ const dependencyVersionMap = {
146
146
  "nitro-cloudflare-dev": "^0.2.2",
147
147
  "@sveltejs/adapter-cloudflare": "^7.2.1",
148
148
  "@cloudflare/workers-types": "^4.20250822.0",
149
- alchemy: "^0.75.1",
149
+ alchemy: "^0.77.0",
150
150
  dotenv: "^17.2.2",
151
151
  tsdown: "^0.15.5",
152
152
  zod: "^4.1.11",
@@ -216,7 +216,8 @@ const FrontendSchema = z.enum([
216
216
  "tanstack-start",
217
217
  "next",
218
218
  "nuxt",
219
- "native-nativewind",
219
+ "native-bare",
220
+ "native-uniwind",
220
221
  "native-unistyles",
221
222
  "svelte",
222
223
  "solid",
@@ -337,13 +338,13 @@ function isWebFrontend(value) {
337
338
  function splitFrontends(values = []) {
338
339
  return {
339
340
  web: values.filter((f) => isWebFrontend(f)),
340
- native: values.filter((f) => f === "native-nativewind" || f === "native-unistyles")
341
+ native: values.filter((f) => f === "native-bare" || f === "native-uniwind" || f === "native-unistyles")
341
342
  };
342
343
  }
343
344
  function ensureSingleWebAndNative(frontends) {
344
345
  const { web, native } = splitFrontends(frontends);
345
346
  if (web.length > 1) exitWithError("Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next, nuxt, svelte, solid");
346
- if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-nativewind, native-unistyles");
347
+ if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-bare, native-uniwind, native-unistyles");
347
348
  }
348
349
  const FULLSTACK_FRONTENDS$1 = ["next", "tanstack-start"];
349
350
  function validateSelfBackendCompatibility(providedFlags, options, config) {
@@ -352,7 +353,7 @@ function validateSelfBackendCompatibility(providedFlags, options, config) {
352
353
  if (backend === "self") {
353
354
  const { web, native } = splitFrontends(frontends);
354
355
  if (!(web.length === 1 && FULLSTACK_FRONTENDS$1.includes(web[0]))) exitWithError("Backend 'self' (fullstack) currently only supports Next.js and TanStack Start frontends. Please use --frontend next or --frontend tanstack-start. Support for Nuxt and SvelteKit will be added in a future update.");
355
- if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-nativewind, native-unistyles");
356
+ if (native.length > 1) exitWithError("Cannot select multiple native frameworks. Choose only one of: native-bare, native-uniwind, native-unistyles");
356
357
  }
357
358
  const hasFullstackFrontend = frontends.some((f) => FULLSTACK_FRONTENDS$1.includes(f));
358
359
  if (providedFlags.has("backend") && !hasFullstackFrontend && backend === "self") exitWithError("Backend 'self' (fullstack) currently only supports Next.js and TanStack Start frontends. Please use --frontend next or --frontend tanstack-start or choose a different backend. Support for Nuxt and SvelteKit will be added in a future update.");
@@ -622,7 +623,8 @@ async function getAuthChoice(auth, backend, frontend) {
622
623
  "tanstack-router",
623
624
  "tanstack-start",
624
625
  "next",
625
- "native-nativewind",
626
+ "native-bare",
627
+ "native-uniwind",
626
628
  "native-unistyles"
627
629
  ].includes(f));
628
630
  const hasClerkCompatibleFrontends = frontend?.some((f) => [
@@ -630,7 +632,8 @@ async function getAuthChoice(auth, backend, frontend) {
630
632
  "tanstack-router",
631
633
  "tanstack-start",
632
634
  "next",
633
- "native-nativewind",
635
+ "native-bare",
636
+ "native-uniwind",
634
637
  "native-unistyles"
635
638
  ].includes(f));
636
639
  const options = [];
@@ -965,16 +968,24 @@ async function getFrontendChoice(frontendOptions, backend, auth) {
965
968
  if (frontendTypes.includes("native")) {
966
969
  const nativeFramework = await select({
967
970
  message: "Choose native",
968
- options: [{
969
- value: "native-nativewind",
970
- label: "NativeWind",
971
- hint: "Use Tailwind CSS for React Native"
972
- }, {
973
- value: "native-unistyles",
974
- label: "Unistyles",
975
- hint: "Consistent styling for React Native"
976
- }],
977
- initialValue: "native-nativewind"
971
+ options: [
972
+ {
973
+ value: "native-bare",
974
+ label: "Bare",
975
+ hint: "Bare Expo without styling library"
976
+ },
977
+ {
978
+ value: "native-uniwind",
979
+ label: "Uniwind",
980
+ hint: "Use Tailwind CSS for React Native"
981
+ },
982
+ {
983
+ value: "native-unistyles",
984
+ label: "Unistyles",
985
+ hint: "Consistent styling for React Native"
986
+ }
987
+ ],
988
+ initialValue: "native-bare"
978
989
  });
979
990
  if (isCancel(nativeFramework)) return exitCancelled("Operation cancelled");
980
991
  result.push(nativeFramework);
@@ -1733,7 +1744,8 @@ function validateConvexConstraints(config, providedFlags) {
1733
1744
  "tanstack-router",
1734
1745
  "tanstack-start",
1735
1746
  "next",
1736
- "native-nativewind",
1747
+ "native-bare",
1748
+ "native-uniwind",
1737
1749
  "native-unistyles"
1738
1750
  ];
1739
1751
  if (!config.frontend?.some((f) => supportedFrontends.includes(f))) exitWithError("Better-Auth with Convex backend requires a supported frontend (TanStack Router, TanStack Start, Next.js, or Native).");
@@ -2306,7 +2318,8 @@ function getFrameworksFromFrontend(frontend) {
2306
2318
  "tanstack-start": "react",
2307
2319
  next: "next",
2308
2320
  nuxt: "vue",
2309
- "native-nativewind": "react",
2321
+ "native-bare": "react",
2322
+ "native-uniwind": "react",
2310
2323
  "native-unistyles": "react",
2311
2324
  svelte: "svelte",
2312
2325
  solid: "solid"
@@ -2759,7 +2772,8 @@ async function setupFrontendTemplates(projectDir, context) {
2759
2772
  const hasNuxtWeb = context.frontend.includes("nuxt");
2760
2773
  const hasSvelteWeb = context.frontend.includes("svelte");
2761
2774
  const hasSolidWeb = context.frontend.includes("solid");
2762
- const hasNativeWind = context.frontend.includes("native-nativewind");
2775
+ const hasNativeBare = context.frontend.includes("native-bare");
2776
+ const hasNativeUniwind = context.frontend.includes("native-uniwind");
2763
2777
  const hasUnistyles = context.frontend.includes("native-unistyles");
2764
2778
  const isConvex = context.backend === "convex";
2765
2779
  if (hasReactWeb || hasNuxtWeb || hasSvelteWeb || hasSolidWeb) {
@@ -2809,13 +2823,14 @@ async function setupFrontendTemplates(projectDir, context) {
2809
2823
  }
2810
2824
  }
2811
2825
  }
2812
- if (hasNativeWind || hasUnistyles) {
2826
+ if (hasNativeBare || hasNativeUniwind || hasUnistyles) {
2813
2827
  const nativeAppDir = path.join(projectDir, "apps/native");
2814
2828
  await fs.ensureDir(nativeAppDir);
2815
2829
  const nativeBaseCommonDir = path.join(PKG_ROOT, "templates/frontend/native/base");
2816
2830
  if (await fs.pathExists(nativeBaseCommonDir)) await processAndCopyFiles("**/*", nativeBaseCommonDir, nativeAppDir, context);
2817
2831
  let nativeFrameworkPath = "";
2818
- if (hasNativeWind) nativeFrameworkPath = "nativewind";
2832
+ if (hasNativeBare) nativeFrameworkPath = "bare";
2833
+ else if (hasNativeUniwind) nativeFrameworkPath = "uniwind";
2819
2834
  else if (hasUnistyles) nativeFrameworkPath = "unistyles";
2820
2835
  const nativeSpecificDir = path.join(PKG_ROOT, `templates/frontend/native/${nativeFrameworkPath}`);
2821
2836
  if (await fs.pathExists(nativeSpecificDir)) await processAndCopyFiles("**/*", nativeSpecificDir, nativeAppDir, context, true);
@@ -2889,9 +2904,10 @@ async function setupAuthTemplate(projectDir, context) {
2889
2904
  const hasNuxtWeb = context.frontend.includes("nuxt");
2890
2905
  const hasSvelteWeb = context.frontend.includes("svelte");
2891
2906
  const hasSolidWeb = context.frontend.includes("solid");
2892
- const hasNativeWind = context.frontend.includes("native-nativewind");
2907
+ const hasNativeBare = context.frontend.includes("native-bare");
2908
+ const hasUniwind = context.frontend.includes("native-uniwind");
2893
2909
  const hasUnistyles = context.frontend.includes("native-unistyles");
2894
- const hasNative = hasNativeWind || hasUnistyles;
2910
+ const hasNative = hasNativeBare || hasUniwind || hasUnistyles;
2895
2911
  const authProvider = context.auth;
2896
2912
  if (context.backend === "convex" && authProvider === "clerk") {
2897
2913
  const convexBackendDestDir = path.join(projectDir, "packages/backend");
@@ -2915,11 +2931,10 @@ async function setupAuthTemplate(projectDir, context) {
2915
2931
  if (nativeAppDirExists) {
2916
2932
  const convexClerkNativeBaseSrc = path.join(PKG_ROOT, "templates/auth/clerk/convex/native/base");
2917
2933
  if (await fs.pathExists(convexClerkNativeBaseSrc)) await processAndCopyFiles("**/*", convexClerkNativeBaseSrc, nativeAppDir, context);
2918
- const hasNativeWind$1 = context.frontend.includes("native-nativewind");
2919
- const hasUnistyles$1 = context.frontend.includes("native-unistyles");
2920
2934
  let nativeFrameworkPath = "";
2921
- if (hasNativeWind$1) nativeFrameworkPath = "nativewind";
2922
- else if (hasUnistyles$1) nativeFrameworkPath = "unistyles";
2935
+ if (hasNativeBare) nativeFrameworkPath = "bare";
2936
+ else if (hasUniwind) nativeFrameworkPath = "uniwind";
2937
+ else if (hasUnistyles) nativeFrameworkPath = "unistyles";
2923
2938
  if (nativeFrameworkPath) {
2924
2939
  const convexClerkNativeFrameworkSrc = path.join(PKG_ROOT, `templates/auth/clerk/convex/native/${nativeFrameworkPath}`);
2925
2940
  if (await fs.pathExists(convexClerkNativeFrameworkSrc)) await processAndCopyFiles("**/*", convexClerkNativeFrameworkSrc, nativeAppDir, context);
@@ -2952,7 +2967,8 @@ async function setupAuthTemplate(projectDir, context) {
2952
2967
  const convexBetterAuthNativeBaseSrc = path.join(PKG_ROOT, "templates/auth/better-auth/convex/native/base");
2953
2968
  if (await fs.pathExists(convexBetterAuthNativeBaseSrc)) await processAndCopyFiles("**/*", convexBetterAuthNativeBaseSrc, nativeAppDir, context);
2954
2969
  let nativeFrameworkPath = "";
2955
- if (hasNativeWind) nativeFrameworkPath = "nativewind";
2970
+ if (hasNativeBare) nativeFrameworkPath = "bare";
2971
+ else if (hasUniwind) nativeFrameworkPath = "uniwind";
2956
2972
  else if (hasUnistyles) nativeFrameworkPath = "unistyles";
2957
2973
  if (nativeFrameworkPath) {
2958
2974
  const convexBetterAuthNativeFrameworkSrc = path.join(PKG_ROOT, `templates/auth/better-auth/convex/native/${nativeFrameworkPath}`);
@@ -3011,7 +3027,8 @@ async function setupAuthTemplate(projectDir, context) {
3011
3027
  const authNativeBaseSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/native/base`);
3012
3028
  if (await fs.pathExists(authNativeBaseSrc)) await processAndCopyFiles("**/*", authNativeBaseSrc, nativeAppDir, context);
3013
3029
  let nativeFrameworkAuthPath = "";
3014
- if (hasNativeWind) nativeFrameworkAuthPath = "nativewind";
3030
+ if (hasNativeBare) nativeFrameworkAuthPath = "bare";
3031
+ else if (hasUniwind) nativeFrameworkAuthPath = "uniwind";
3015
3032
  else if (hasUnistyles) nativeFrameworkAuthPath = "unistyles";
3016
3033
  if (nativeFrameworkAuthPath) {
3017
3034
  const authNativeFrameworkSrc = path.join(PKG_ROOT, `templates/auth/${authProvider}/native/${nativeFrameworkAuthPath}`);
@@ -3155,11 +3172,13 @@ async function setupExamplesTemplate(projectDir, context) {
3155
3172
  }
3156
3173
  }
3157
3174
  if (nativeAppDirExists) {
3158
- const hasNativeWind = context.frontend.includes("native-nativewind");
3175
+ const hasNativeBare = context.frontend.includes("native-bare");
3176
+ const hasUniwind = context.frontend.includes("native-uniwind");
3159
3177
  const hasUnistyles = context.frontend.includes("native-unistyles");
3160
- if (hasNativeWind || hasUnistyles) {
3178
+ if (hasNativeBare || hasUniwind || hasUnistyles) {
3161
3179
  let nativeFramework = "";
3162
- if (hasNativeWind) nativeFramework = "nativewind";
3180
+ if (hasNativeBare) nativeFramework = "bare";
3181
+ else if (hasUniwind) nativeFramework = "uniwind";
3163
3182
  else if (hasUnistyles) nativeFramework = "unistyles";
3164
3183
  const exampleNativeSrc = path.join(exampleBaseDir, `native/${nativeFramework}`);
3165
3184
  if (await fs.pathExists(exampleNativeSrc)) await processAndCopyFiles("**/*", exampleNativeSrc, nativeAppDir, context, false);
@@ -3169,9 +3188,10 @@ async function setupExamplesTemplate(projectDir, context) {
3169
3188
  }
3170
3189
  async function handleExtras(projectDir, context) {
3171
3190
  const extrasDir = path.join(PKG_ROOT, "templates/extras");
3172
- const hasNativeWind = context.frontend.includes("native-nativewind");
3191
+ const hasNativeBare = context.frontend.includes("native-bare");
3192
+ const hasUniwind = context.frontend.includes("native-uniwind");
3173
3193
  const hasUnistyles = context.frontend.includes("native-unistyles");
3174
- const hasNative = hasNativeWind || hasUnistyles;
3194
+ const hasNative = hasNativeBare || hasUniwind || hasUnistyles;
3175
3195
  if (context.packageManager === "pnpm") {
3176
3196
  const pnpmWorkspaceSrc = path.join(extrasDir, "pnpm-workspace.yaml");
3177
3197
  const pnpmWorkspaceDest = path.join(projectDir, "pnpm-workspace.yaml");
@@ -4032,6 +4052,7 @@ async function setupCatalogs(projectDir, options) {
4032
4052
  const packagePaths = [
4033
4053
  "apps/server",
4034
4054
  "apps/web",
4055
+ "apps/native",
4035
4056
  "apps/fumadocs",
4036
4057
  "apps/docs",
4037
4058
  "packages/api",
@@ -4162,7 +4183,7 @@ async function setupExamples(config) {
4162
4183
  const hasSvelte = frontend.includes("svelte");
4163
4184
  const hasReactWeb = frontend.includes("react-router") || frontend.includes("tanstack-router") || frontend.includes("next") || frontend.includes("tanstack-start");
4164
4185
  const hasNext = frontend.includes("next");
4165
- const hasReactNative = frontend.includes("native-nativewind") || frontend.includes("native-unistyles");
4186
+ const hasReactNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
4166
4187
  if (webClientDirExists) {
4167
4188
  const dependencies = ["ai"];
4168
4189
  if (hasNuxt) dependencies.push("@ai-sdk/vue");
@@ -4207,7 +4228,11 @@ function getFrontendType(frontend) {
4207
4228
  "tanstack-start",
4208
4229
  "next"
4209
4230
  ];
4210
- const nativeFrontends = ["native-nativewind", "native-unistyles"];
4231
+ const nativeFrontends = [
4232
+ "native-bare",
4233
+ "native-uniwind",
4234
+ "native-unistyles"
4235
+ ];
4211
4236
  return {
4212
4237
  hasReactWeb: frontend.some((f) => reactBasedFrontends.includes(f)),
4213
4238
  hasNuxtWeb: frontend.includes("nuxt"),
@@ -4282,13 +4307,14 @@ function getQueryDependencies(frontend) {
4282
4307
  "tanstack-router",
4283
4308
  "tanstack-start",
4284
4309
  "next",
4285
- "native-nativewind",
4310
+ "native-bare",
4311
+ "native-uniwind",
4286
4312
  "native-unistyles"
4287
4313
  ];
4288
4314
  const deps = {};
4289
4315
  if (frontend.some((f) => reactBasedFrontends.includes(f))) {
4290
- const hasReactWeb = frontend.some((f) => f !== "native-nativewind" && f !== "native-unistyles" && reactBasedFrontends.includes(f));
4291
- const hasNative = frontend.includes("native-nativewind") || frontend.includes("native-unistyles");
4316
+ const hasReactWeb = frontend.some((f) => f !== "native-bare" && f !== "native-uniwind" && f !== "native-unistyles" && reactBasedFrontends.includes(f));
4317
+ const hasNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
4292
4318
  if (hasReactWeb) deps.web = {
4293
4319
  dependencies: ["@tanstack/react-query"],
4294
4320
  devDependencies: ["@tanstack/react-query-devtools"]
@@ -4440,7 +4466,7 @@ async function setupBetterAuthPlugins(projectDir, config) {
4440
4466
  pluginsToAdd.push("nextCookies()");
4441
4467
  importsToAdd.push("import { nextCookies } from \"better-auth/next-js\";");
4442
4468
  }
4443
- if (config.frontend?.includes("native-nativewind") || config.frontend?.includes("native-unistyles")) {
4469
+ if (config.frontend?.includes("native-bare") || config.frontend?.includes("native-uniwind") || config.frontend?.includes("native-unistyles")) {
4444
4470
  pluginsToAdd.push("expo()");
4445
4471
  importsToAdd.push("import { expo } from \"@better-auth/expo\";");
4446
4472
  }
@@ -4497,7 +4523,7 @@ async function setupAuth(config) {
4497
4523
  if (auth === "better-auth") {
4498
4524
  const convexBackendDir = path.join(projectDir, "packages/backend");
4499
4525
  const convexBackendDirExists = await fs.pathExists(convexBackendDir);
4500
- const hasNativeForBA = frontend.includes("native-nativewind") || frontend.includes("native-unistyles");
4526
+ const hasNativeForBA = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
4501
4527
  if (convexBackendDirExists) {
4502
4528
  await addPackageDependency({
4503
4529
  dependencies: ["better-auth", "@convex-dev/better-auth"],
@@ -4530,9 +4556,10 @@ async function setupAuth(config) {
4530
4556
  projectDir: clientDir
4531
4557
  });
4532
4558
  }
4533
- const hasNativeWind$1 = frontend.includes("native-nativewind");
4559
+ const hasNativeBare$1 = frontend.includes("native-bare");
4560
+ const hasNativeUniwind$1 = frontend.includes("native-uniwind");
4534
4561
  const hasUnistyles$1 = frontend.includes("native-unistyles");
4535
- if (nativeDirExists && (hasNativeWind$1 || hasUnistyles$1)) await addPackageDependency({
4562
+ if (nativeDirExists && (hasNativeBare$1 || hasNativeUniwind$1 || hasUnistyles$1)) await addPackageDependency({
4536
4563
  dependencies: [
4537
4564
  "better-auth",
4538
4565
  "@better-auth/expo",
@@ -4545,9 +4572,10 @@ async function setupAuth(config) {
4545
4572
  projectDir: nativeDir
4546
4573
  });
4547
4574
  }
4548
- const hasNativeWind = frontend.includes("native-nativewind");
4575
+ const hasNativeBare = frontend.includes("native-bare");
4576
+ const hasNativeUniwind = frontend.includes("native-uniwind");
4549
4577
  const hasUnistyles = frontend.includes("native-unistyles");
4550
- if (auth === "clerk" && nativeDirExists && (hasNativeWind || hasUnistyles)) await addPackageDependency({
4578
+ if (auth === "clerk" && nativeDirExists && (hasNativeBare || hasNativeUniwind || hasUnistyles)) await addPackageDependency({
4551
4579
  dependencies: ["@clerk/clerk-expo"],
4552
4580
  projectDir: nativeDir
4553
4581
  });
@@ -4573,7 +4601,7 @@ async function setupAuth(config) {
4573
4601
  projectDir: clientDir
4574
4602
  });
4575
4603
  }
4576
- if ((frontend.includes("native-nativewind") || frontend.includes("native-unistyles")) && nativeDirExists) {
4604
+ if ((frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles")) && nativeDirExists) {
4577
4605
  if (auth === "better-auth") {
4578
4606
  await addPackageDependency({
4579
4607
  dependencies: ["better-auth", "@better-auth/expo"],
@@ -4740,7 +4768,7 @@ async function setupEnvironmentVariables(config) {
4740
4768
  await addEnvVariablesToFile(path.join(clientDir, ".env"), clientVars);
4741
4769
  }
4742
4770
  }
4743
- if (frontend.includes("native-nativewind") || frontend.includes("native-unistyles")) {
4771
+ if (frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles")) {
4744
4772
  const nativeDir = path.join(projectDir, "apps/native");
4745
4773
  if (await fs.pathExists(nativeDir)) {
4746
4774
  let envVarName = "EXPO_PUBLIC_SERVER_URL";
@@ -4773,7 +4801,7 @@ async function setupEnvironmentVariables(config) {
4773
4801
  const convexBackendDir = path.join(projectDir, "packages/backend");
4774
4802
  if (await fs.pathExists(convexBackendDir)) {
4775
4803
  const envLocalPath = path.join(convexBackendDir, ".env.local");
4776
- const hasNative = frontend.includes("native-nativewind") || frontend.includes("native-unistyles");
4804
+ const hasNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
4777
4805
  const hasWeb = hasWebFrontend$1;
4778
4806
  if (!await fs.pathExists(envLocalPath) || !(await fs.readFile(envLocalPath, "utf8")).includes("npx convex env set")) {
4779
4807
  const convexCommands = `# Set Convex environment variables
@@ -6082,7 +6110,7 @@ function generateReadmeContent(options) {
6082
6110
  const { projectName, packageManager, database, auth, addons = [], orm = "drizzle", runtime = "bun", frontend = ["tanstack-router"], backend = "hono", api = "trpc", webDeploy, serverDeploy } = options;
6083
6111
  const isConvex = backend === "convex";
6084
6112
  const hasReactRouter = frontend.includes("react-router");
6085
- const hasNative = frontend.includes("native-nativewind") || frontend.includes("native-unistyles");
6113
+ const hasNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
6086
6114
  const hasSvelte = frontend.includes("svelte");
6087
6115
  const packageManagerRunCmd = `${packageManager} run`;
6088
6116
  let webPort = "3001";
@@ -6208,7 +6236,7 @@ function generateProjectStructure(projectName, frontend, backend, addons, isConv
6208
6236
  else structure.push(`│ ├── web/ # Frontend application (${frontendType})`);
6209
6237
  }
6210
6238
  }
6211
- if (frontend.includes("native-nativewind") || frontend.includes("native-unistyles")) if (isBackendSelf) structure.push("│ ├── native/ # Mobile application (React Native, Expo)");
6239
+ if (frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles")) if (isBackendSelf) structure.push("│ ├── native/ # Mobile application (React Native, Expo)");
6212
6240
  else structure.push("│ ├── native/ # Mobile application (React Native, Expo)");
6213
6241
  if (addons.includes("starlight")) if (isBackendSelf) structure.push("│ ├── docs/ # Documentation site (Astro Starlight)");
6214
6242
  else structure.push("│ ├── docs/ # Documentation site (Astro Starlight)");
@@ -6237,7 +6265,7 @@ function generateFeaturesList(database, auth, addons, orm, runtime, frontend, ba
6237
6265
  const isBackendNone = backend === "none";
6238
6266
  const hasTanstackRouter = frontend.includes("tanstack-router");
6239
6267
  const hasReactRouter = frontend.includes("react-router");
6240
- const hasNative = frontend.includes("native-nativewind") || frontend.includes("native-unistyles");
6268
+ const hasNative = frontend.includes("native-bare") || frontend.includes("native-uniwind") || frontend.includes("native-unistyles");
6241
6269
  const hasNext = frontend.includes("next");
6242
6270
  const hasTanstackStart = frontend.includes("tanstack-start");
6243
6271
  const hasSvelte = frontend.includes("svelte");
@@ -6516,7 +6544,7 @@ async function displayPostInstallInstructions(config) {
6516
6544
  const databaseInstructions = !isConvex && database !== "none" ? await getDatabaseInstructions(database, orm, runCmd, runtime, dbSetup, serverDeploy, backend) : "";
6517
6545
  const tauriInstructions = addons?.includes("tauri") ? getTauriInstructions(runCmd) : "";
6518
6546
  const lintingInstructions = hasHuskyOrBiome ? getLintingInstructions(runCmd) : "";
6519
- const nativeInstructions = frontend?.includes("native-nativewind") || frontend?.includes("native-unistyles") ? getNativeInstructions(isConvex, isBackendSelf, frontend || []) : "";
6547
+ const nativeInstructions = frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles") ? getNativeInstructions(isConvex, isBackendSelf, frontend || []) : "";
6520
6548
  const pwaInstructions = addons?.includes("pwa") && frontend?.includes("react-router") ? getPwaInstructions() : "";
6521
6549
  const starlightInstructions = addons?.includes("starlight") ? getStarlightInstructions(runCmd) : "";
6522
6550
  const clerkInstructions = isConvex && config.auth === "clerk" ? getClerkInstructions() : "";
@@ -6532,7 +6560,7 @@ async function displayPostInstallInstructions(config) {
6532
6560
  "svelte",
6533
6561
  "solid"
6534
6562
  ].includes(f));
6535
- const hasNative = frontend?.includes("native-nativewind") || frontend?.includes("native-unistyles");
6563
+ const hasNative = frontend?.includes("native-bare") || frontend?.includes("native-uniwind") || frontend?.includes("native-unistyles");
6536
6564
  const bunWebNativeWarning = packageManager === "bun" && hasNative && hasWeb ? getBunWebNativeWarning() : "";
6537
6565
  const noOrmWarning = !isConvex && database !== "none" && orm === "none" ? getNoOrmWarning() : "";
6538
6566
  const hasReactRouter = frontend?.includes("react-router");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "3.2.23",
3
+ "version": "3.3.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",
@@ -66,6 +66,11 @@
66
66
  "formatter": {
67
67
  "quoteStyle": "double"
68
68
  }
69
+ },
70
+ "css": {
71
+ "parser": {
72
+ "tailwindDirectives": true
73
+ }
69
74
  }
70
75
  {{#if (or (includes frontend "svelte") (includes frontend "nuxt"))}}
71
76
  ,
@@ -1,5 +1,5 @@
1
1
  import { createClient, type GenericCtx } from "@convex-dev/better-auth";
2
- {{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
2
+ {{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
3
3
  import { convex } from "@convex-dev/better-auth/plugins";
4
4
  import { expo } from "@better-auth/expo";
5
5
  {{else}}
@@ -17,7 +17,7 @@ import { v } from "convex/values";
17
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"))}}
18
18
  const siteUrl = process.env.SITE_URL!;
19
19
  {{/if}}
20
- {{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
20
+ {{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
21
21
  const nativeAppUrl = process.env.NATIVE_APP_URL || "mybettertapp://";
22
22
  {{/if}}
23
23
 
@@ -31,10 +31,10 @@ function createAuth(
31
31
  logger: {
32
32
  disabled: optionsOnly,
33
33
  },
34
- {{#if (and (or (includes frontend "native-nativewind") (includes frontend "native-unistyles")) (or (includes frontend "tanstack-start") (includes frontend "next")))}}
34
+ {{#if (and (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles")) (or (includes frontend "tanstack-start") (includes frontend "next")))}}
35
35
  baseURL: siteUrl,
36
36
  trustedOrigins: [siteUrl, nativeAppUrl],
37
- {{else if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
37
+ {{else if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
38
38
  trustedOrigins: [nativeAppUrl],
39
39
  {{else if (or (includes frontend "tanstack-start") (includes frontend "next"))}}
40
40
  baseURL: siteUrl,
@@ -48,7 +48,7 @@ function createAuth(
48
48
  requireEmailVerification: false,
49
49
  },
50
50
  plugins: [
51
- {{#if (or (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
51
+ {{#if (or (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
52
52
  expo(),
53
53
  {{/if}}
54
54
  {{#if (or (includes frontend "tanstack-router") (includes frontend "react-router") (includes frontend "nuxt") (includes frontend "svelte") (includes frontend "solid"))}}
@@ -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") (includes frontend "native-nativewind") (includes frontend "native-unistyles"))}}
6
+ {{#if (or (includes frontend "tanstack-start") (includes frontend "next") (includes frontend "native-bare") (includes frontend "native-uniwind") (includes frontend "native-unistyles"))}}
7
7
  authComponent.registerRoutes(http, createAuth);
8
8
  {{else}}
9
9
  authComponent.registerRoutes(http, createAuth, { cors: true });
@@ -0,0 +1,127 @@
1
+ import { authClient } from "@/lib/auth-client";
2
+ import { useState } from "react";
3
+ import {
4
+ ActivityIndicator,
5
+ Text,
6
+ TextInput,
7
+ TouchableOpacity,
8
+ View,
9
+ StyleSheet,
10
+ } from "react-native";
11
+ import { useColorScheme } from "@/lib/use-color-scheme";
12
+ import { NAV_THEME } from "@/lib/constants";
13
+
14
+ function SignIn() {
15
+ const { colorScheme } = useColorScheme();
16
+ const theme = colorScheme === "dark" ? NAV_THEME.dark : NAV_THEME.light;
17
+ const [email, setEmail] = useState("");
18
+ const [password, setPassword] = useState("");
19
+ const [isLoading, setIsLoading] = useState(false);
20
+ const [error, setError] = useState<string | null>(null);
21
+
22
+ async function handleLogin() {
23
+ setIsLoading(true);
24
+ setError(null);
25
+
26
+ await authClient.signIn.email(
27
+ {
28
+ email,
29
+ password,
30
+ },
31
+ {
32
+ onError(error) {
33
+ setError(error.error?.message || "Failed to sign in");
34
+ setIsLoading(false);
35
+ },
36
+ onSuccess() {
37
+ setEmail("");
38
+ setPassword("");
39
+ },
40
+ onFinished() {
41
+ setIsLoading(false);
42
+ },
43
+ }
44
+ );
45
+ }
46
+
47
+ return (
48
+ <View style={[styles.card, { backgroundColor: theme.card, borderColor: theme.border }]}>
49
+ <Text style={[styles.title, { color: theme.text }]}>Sign In</Text>
50
+
51
+ {error ? (
52
+ <View style={[styles.errorContainer, { backgroundColor: theme.notification + "20" }]}>
53
+ <Text style={[styles.errorText, { color: theme.notification }]}>{error}</Text>
54
+ </View>
55
+ ) : null}
56
+
57
+ <TextInput
58
+ style={[styles.input, { color: theme.text, borderColor: theme.border, backgroundColor: theme.background }]}
59
+ placeholder="Email"
60
+ placeholderTextColor={theme.text}
61
+ value={email}
62
+ onChangeText={setEmail}
63
+ keyboardType="email-address"
64
+ autoCapitalize="none"
65
+ />
66
+
67
+ <TextInput
68
+ style={[styles.input, { color: theme.text, borderColor: theme.border, backgroundColor: theme.background }]}
69
+ placeholder="Password"
70
+ placeholderTextColor={theme.text}
71
+ value={password}
72
+ onChangeText={setPassword}
73
+ secureTextEntry
74
+ />
75
+
76
+ <TouchableOpacity
77
+ onPress={handleLogin}
78
+ disabled={isLoading}
79
+ style={[styles.button, { backgroundColor: theme.primary, opacity: isLoading ? 0.5 : 1 }]}
80
+ >
81
+ {isLoading ? (
82
+ <ActivityIndicator size="small" color="#ffffff" />
83
+ ) : (
84
+ <Text style={styles.buttonText}>Sign In</Text>
85
+ )}
86
+ </TouchableOpacity>
87
+ </View>
88
+ );
89
+ }
90
+
91
+ const styles = StyleSheet.create({
92
+ card: {
93
+ marginTop: 16,
94
+ padding: 16,
95
+ borderWidth: 1,
96
+ },
97
+ title: {
98
+ fontSize: 18,
99
+ fontWeight: "bold",
100
+ marginBottom: 12,
101
+ },
102
+ errorContainer: {
103
+ marginBottom: 12,
104
+ padding: 8,
105
+ },
106
+ errorText: {
107
+ fontSize: 14,
108
+ },
109
+ input: {
110
+ borderWidth: 1,
111
+ padding: 12,
112
+ fontSize: 16,
113
+ marginBottom: 12,
114
+ },
115
+ button: {
116
+ padding: 12,
117
+ alignItems: "center",
118
+ justifyContent: "center",
119
+ },
120
+ buttonText: {
121
+ color: "#ffffff",
122
+ fontSize: 16,
123
+ },
124
+ });
125
+
126
+ export { SignIn };
127
+