create-better-t-stack 1.13.1 → 2.0.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 (223) hide show
  1. package/dist/index.js +100 -186
  2. package/package.json +72 -67
  3. package/templates/api/orpc/server/base/src/lib/context.ts.hbs +105 -0
  4. package/templates/api/orpc/server/base/src/lib/orpc.ts.hbs +17 -0
  5. package/templates/api/orpc/server/next/src/app/rpc/[...all]/route.ts.hbs +23 -0
  6. package/templates/api/orpc/web/base/src/utils/orpc.ts.hbs +57 -0
  7. package/templates/api/trpc/server/base/src/lib/context.ts.hbs +108 -0
  8. package/{template/with-auth/apps/server/src/lib/trpc.ts → templates/api/trpc/server/base/src/lib/trpc.ts.hbs} +2 -0
  9. package/templates/api/trpc/web/base/src/utils/trpc.ts.hbs +100 -0
  10. package/templates/auth/server/base/src/lib/auth.ts.hbs +30 -0
  11. package/templates/auth/web/base/src/lib/auth-client.ts.hbs +10 -0
  12. package/{template/with-auth/apps/web-next/src/app/dashboard/page.tsx → templates/auth/web/next/src/app/dashboard/page.tsx.hbs} +10 -0
  13. package/{template/with-auth/apps/web-react-router/src/routes/dashboard.tsx → templates/auth/web/react-router/src/routes/dashboard.tsx.hbs} +10 -0
  14. package/{template/with-auth/apps/web-tanstack-router/src/routes/dashboard.tsx → templates/auth/web/tanstack-router/src/routes/dashboard.tsx.hbs} +10 -0
  15. package/{template/with-auth/apps/web-tanstack-start/src/routes/dashboard.tsx → templates/auth/web/tanstack-start/src/routes/dashboard.tsx.hbs} +15 -0
  16. package/{template/with-auth/apps/server/src/with-elysia-index.ts → templates/backend/elysia/src/index.ts.hbs} +38 -3
  17. package/templates/backend/express/src/index.ts.hbs +78 -0
  18. package/templates/backend/hono/src/index.ts.hbs +105 -0
  19. package/{template/with-next/apps/server → templates/backend/next}/package.json +0 -2
  20. package/{template/base/apps/server → templates/backend/server-base}/package.json +0 -1
  21. package/templates/backend/server-base/src/routers/index.ts.hbs +51 -0
  22. package/templates/base/package.json +10 -0
  23. package/templates/examples/todo/server/drizzle/base/src/routers/todo.ts.hbs +79 -0
  24. package/{template/with-drizzle-sqlite/apps/server → templates/examples/todo/server/drizzle/sqlite}/src/db/schema/todo.ts +2 -2
  25. package/{template/examples/todo/apps/web-react-router/src/routes/todos.tsx → templates/examples/todo/web/react-router/src/routes/todos.tsx.hbs} +28 -0
  26. package/{template/examples/todo/apps/web-tanstack-router/src/routes/todos.tsx → templates/examples/todo/web/tanstack-router/src/routes/todos.tsx.hbs} +28 -0
  27. package/{template/examples/todo/apps/web-tanstack-start/src/routes/todos.tsx → templates/examples/todo/web/tanstack-start/src/routes/todos.tsx.hbs} +33 -0
  28. package/{template/base/apps/web-next → templates/frontend/next}/package.json +0 -2
  29. package/{template/base/apps/web-next/src/app/page.tsx → templates/frontend/next/src/app/page.tsx.hbs} +10 -0
  30. package/{template/base/apps/web-next/src/components/providers.tsx → templates/frontend/next/src/components/providers.tsx.hbs} +12 -0
  31. package/{template/base/apps/web-react-router → templates/frontend/react-router}/package.json +0 -3
  32. package/{template/base/apps/web-react-router/src/root.tsx → templates/frontend/react-router/src/root.tsx.hbs} +28 -1
  33. package/{template/base/apps/web-react-router/src/routes/_index.tsx → templates/frontend/react-router/src/routes/_index.tsx.hbs} +11 -0
  34. package/templates/frontend/react-router/vite.config.ts.hbs +37 -0
  35. package/{template/base/apps/web-tanstack-router → templates/frontend/tanstack-router}/package.json +0 -4
  36. package/{template/base/apps/web-tanstack-router/src/main.tsx → templates/frontend/tanstack-router/src/main.tsx.hbs} +20 -0
  37. package/{template/base/apps/web-tanstack-router/src/routes/__root.tsx → templates/frontend/tanstack-router/src/routes/__root.tsx.hbs} +48 -0
  38. package/{template/base/apps/web-tanstack-router/src/routes/index.tsx → templates/frontend/tanstack-router/src/routes/index.tsx.hbs} +10 -0
  39. package/templates/frontend/tanstack-router/vite.config.ts.hbs +43 -0
  40. package/{template/base/apps/web-tanstack-start → templates/frontend/tanstack-start}/package.json +0 -3
  41. package/{template/with-auth/apps/web-tanstack-start/src/router.tsx → templates/frontend/tanstack-start/src/router.tsx.hbs} +29 -3
  42. package/{template/base/apps/web-tanstack-start/src/routes/__root.tsx → templates/frontend/tanstack-start/src/routes/__root.tsx.hbs} +13 -0
  43. package/{template/base/apps/web-tanstack-start/src/routes/index.tsx → templates/frontend/tanstack-start/src/routes/index.tsx.hbs} +11 -0
  44. package/templates/frontend/web-base/src/components/header.tsx.hbs +80 -0
  45. package/template/base/apps/server/src/lib/trpc.ts +0 -8
  46. package/template/base/apps/server/src/routers/index.ts +0 -11
  47. package/template/base/apps/web-base/src/utils/trpc.ts +0 -33
  48. package/template/base/apps/web-next/src/components/header.tsx +0 -30
  49. package/template/base/apps/web-next/src/utils/trpc.ts +0 -33
  50. package/template/base/apps/web-react-router/src/components/header.tsx +0 -31
  51. package/template/base/apps/web-react-router/vite.config.ts +0 -8
  52. package/template/base/apps/web-tanstack-router/src/components/header.tsx +0 -31
  53. package/template/base/apps/web-tanstack-router/vite.config.ts +0 -14
  54. package/template/base/apps/web-tanstack-start/src/components/header.tsx +0 -27
  55. package/template/base/apps/web-tanstack-start/src/router.tsx +0 -70
  56. package/template/base/apps/web-tanstack-start/src/utils/trpc.ts +0 -5
  57. package/template/base/package.json +0 -18
  58. package/template/examples/todo/apps/server/src/routers/with-drizzle-todo.ts +0 -34
  59. package/template/with-auth/apps/server/src/lib/with-elysia-context.ts +0 -18
  60. package/template/with-auth/apps/server/src/lib/with-express-context.ts +0 -14
  61. package/template/with-auth/apps/server/src/lib/with-hono-context.ts +0 -18
  62. package/template/with-auth/apps/server/src/lib/with-next-context.ts +0 -14
  63. package/template/with-auth/apps/server/src/routers/index.ts +0 -17
  64. package/template/with-auth/apps/server/src/with-drizzle-mysql-lib/auth.ts +0 -15
  65. package/template/with-auth/apps/server/src/with-drizzle-postgres-lib/auth.ts +0 -15
  66. package/template/with-auth/apps/server/src/with-drizzle-sqlite-lib/auth.ts +0 -15
  67. package/template/with-auth/apps/server/src/with-express-index.ts +0 -34
  68. package/template/with-auth/apps/server/src/with-hono-index.ts +0 -39
  69. package/template/with-auth/apps/server/src/with-prisma-mongodb-lib/auth.ts +0 -11
  70. package/template/with-auth/apps/server/src/with-prisma-mysql-lib/auth.ts +0 -11
  71. package/template/with-auth/apps/server/src/with-prisma-postgres-lib/auth.ts +0 -11
  72. package/template/with-auth/apps/server/src/with-prisma-sqlite-lib/auth.ts +0 -11
  73. package/template/with-auth/apps/web-base/src/lib/auth-client.ts +0 -5
  74. package/template/with-auth/apps/web-next/src/components/header.tsx +0 -33
  75. package/template/with-auth/apps/web-next/src/lib/auth-client.ts +0 -5
  76. package/template/with-auth/apps/web-next/src/utils/trpc.ts +0 -39
  77. package/template/with-auth/apps/web-react-router/src/components/header.tsx +0 -34
  78. package/template/with-auth/apps/web-react-router/src/utils/trpc.ts +0 -39
  79. package/template/with-auth/apps/web-tanstack-router/src/components/header.tsx +0 -34
  80. package/template/with-auth/apps/web-tanstack-router/src/utils/trpc.ts +0 -39
  81. package/template/with-auth/apps/web-tanstack-start/src/components/header.tsx +0 -32
  82. package/template/with-elysia/apps/server/src/index.ts +0 -27
  83. package/template/with-elysia/apps/server/src/lib/context.ts +0 -13
  84. package/template/with-express/apps/server/src/index.ts +0 -29
  85. package/template/with-express/apps/server/src/lib/context.ts +0 -9
  86. package/template/with-hono/apps/server/src/index.ts +0 -33
  87. package/template/with-hono/apps/server/src/lib/context.ts +0 -13
  88. package/template/with-next/apps/server/src/lib/context.ts +0 -9
  89. /package/{template/with-biome → templates/addons/biome}/biome.json +0 -0
  90. /package/{template/with-husky → templates/addons/husky}/.husky/pre-commit +0 -0
  91. /package/{template/with-pwa → templates/addons/pwa}/apps/web/public/logo.png +0 -0
  92. /package/{template/with-pwa → templates/addons/pwa}/apps/web/pwa-assets.config.ts +0 -0
  93. /package/{template/base → templates/addons/turborepo}/turbo.json +0 -0
  94. /package/{template/with-next/apps/server → templates/api/trpc/server/next}/src/app/trpc/[trpc]/route.ts +0 -0
  95. /package/{template/with-auth/apps → templates/auth}/native/app/(drawer)/index.tsx +0 -0
  96. /package/{template/with-auth/apps → templates/auth}/native/components/sign-in.tsx +0 -0
  97. /package/{template/with-auth/apps → templates/auth}/native/components/sign-up.tsx +0 -0
  98. /package/{template/with-auth/apps → templates/auth}/native/lib/auth-client.ts +0 -0
  99. /package/{template/with-auth/apps → templates/auth}/native/utils/trpc.ts +0 -0
  100. /package/{template/with-drizzle-mysql/apps/server → templates/auth/server/db/drizzle/mysql}/src/db/schema/auth.ts +0 -0
  101. /package/{template/with-drizzle-postgres/apps/server → templates/auth/server/db/drizzle/postgres}/src/db/schema/auth.ts +0 -0
  102. /package/{template/with-drizzle-sqlite/apps/server → templates/auth/server/db/drizzle/sqlite}/src/db/schema/auth.ts +0 -0
  103. /package/{template/with-prisma-sqlite/apps/server → templates/auth/server/db/prisma/mongodb}/prisma/schema/auth.prisma +0 -0
  104. /package/{template/with-prisma-mysql/apps/server → templates/auth/server/db/prisma/mysql}/prisma/schema/auth.prisma +0 -0
  105. /package/{template/with-prisma-postgres/apps/server → templates/auth/server/db/prisma/postgres}/prisma/schema/auth.prisma +0 -0
  106. /package/{template/with-prisma-mongodb/apps/server → templates/auth/server/db/prisma/sqlite}/prisma/schema/auth.prisma +0 -0
  107. /package/{template/with-auth/apps/server/src/with-next-app → templates/auth/server/next/src/app}/api/auth/[...all]/route.ts +0 -0
  108. /package/{template/with-auth/apps/web-next → templates/auth/web/next}/src/app/login/page.tsx +0 -0
  109. /package/{template/with-auth/apps/web-next → templates/auth/web/next}/src/components/sign-in-form.tsx +0 -0
  110. /package/{template/with-auth/apps/web-next → templates/auth/web/next}/src/components/sign-up-form.tsx +0 -0
  111. /package/{template/with-auth/apps/web-next → templates/auth/web/next}/src/components/theme-provider.tsx +0 -0
  112. /package/{template/with-auth/apps/web-next → templates/auth/web/next}/src/components/user-menu.tsx +0 -0
  113. /package/{template/with-auth/apps/web-react-router → templates/auth/web/react-router}/src/components/sign-in-form.tsx +0 -0
  114. /package/{template/with-auth/apps/web-react-router → templates/auth/web/react-router}/src/components/sign-up-form.tsx +0 -0
  115. /package/{template/with-auth/apps/web-react-router → templates/auth/web/react-router}/src/components/user-menu.tsx +0 -0
  116. /package/{template/with-auth/apps/web-react-router → templates/auth/web/react-router}/src/routes/login.tsx +0 -0
  117. /package/{template/with-auth/apps/web-tanstack-start → templates/auth/web/tanstack-router}/src/components/sign-in-form.tsx +0 -0
  118. /package/{template/with-auth/apps/web-tanstack-start → templates/auth/web/tanstack-router}/src/components/sign-up-form.tsx +0 -0
  119. /package/{template/with-auth/apps/web-tanstack-start → templates/auth/web/tanstack-router}/src/components/user-menu.tsx +0 -0
  120. /package/{template/with-auth/apps/web-tanstack-start → templates/auth/web/tanstack-router}/src/routes/login.tsx +0 -0
  121. /package/{template/with-auth/apps/web-tanstack-router → templates/auth/web/tanstack-start}/src/components/sign-in-form.tsx +0 -0
  122. /package/{template/with-auth/apps/web-tanstack-router → templates/auth/web/tanstack-start}/src/components/sign-up-form.tsx +0 -0
  123. /package/{template/with-auth/apps/web-tanstack-router → templates/auth/web/tanstack-start}/src/components/user-menu.tsx +0 -0
  124. /package/{template/with-auth/apps/web-tanstack-router → templates/auth/web/tanstack-start}/src/routes/login.tsx +0 -0
  125. /package/{template/with-next/apps/server → templates/backend/next}/next-env.d.ts +0 -0
  126. /package/{template/with-next/apps/server → templates/backend/next}/next.config.ts +0 -0
  127. /package/{template/with-next/apps/server → templates/backend/next}/src/app/route.ts +0 -0
  128. /package/{template/with-next/apps/server → templates/backend/next}/src/middleware.ts +0 -0
  129. /package/{template/with-next/apps/server → templates/backend/next}/tsconfig.json +0 -0
  130. /package/{template/base/apps/server → templates/backend/server-base}/_gitignore +0 -0
  131. /package/{template/base/apps/server → templates/backend/server-base}/tsconfig.json +0 -0
  132. /package/{template → templates}/base/_gitignore +0 -0
  133. /package/{template/with-drizzle-mysql/apps/server → templates/db/drizzle/mysql}/drizzle.config.ts +0 -0
  134. /package/{template/with-drizzle-mysql/apps/server → templates/db/drizzle/mysql}/src/db/index.ts +0 -0
  135. /package/{template/with-drizzle-postgres/apps/server → templates/db/drizzle/postgres}/drizzle.config.ts +0 -0
  136. /package/{template/with-drizzle-postgres/apps/server → templates/db/drizzle/postgres}/src/db/index.ts +0 -0
  137. /package/{template/with-drizzle-sqlite/apps/server → templates/db/drizzle/sqlite}/drizzle.config.ts +0 -0
  138. /package/{template/with-drizzle-sqlite/apps/server → templates/db/drizzle/sqlite}/src/db/index.ts +0 -0
  139. /package/{template/with-prisma-sqlite/apps/server → templates/db/prisma/mongodb}/prisma/index.ts +0 -0
  140. /package/{template/with-prisma-mongodb/apps/server → templates/db/prisma/mongodb}/prisma/schema/schema.prisma +0 -0
  141. /package/{template/with-prisma-postgres/apps/server → templates/db/prisma/mysql}/prisma/index.ts +0 -0
  142. /package/{template/with-prisma-mysql/apps/server → templates/db/prisma/mysql}/prisma/schema/schema.prisma +0 -0
  143. /package/{template/with-prisma-mysql/apps/server → templates/db/prisma/postgres}/prisma/index.ts +0 -0
  144. /package/{template/with-prisma-postgres/apps/server → templates/db/prisma/postgres}/prisma/schema/schema.prisma +0 -0
  145. /package/{template/with-prisma-mongodb/apps/server → templates/db/prisma/sqlite}/prisma/index.ts +0 -0
  146. /package/{template/with-prisma-sqlite/apps/server → templates/db/prisma/sqlite}/prisma/schema/schema.prisma +0 -0
  147. /package/{template/examples/ai/apps/web-react-router → templates/examples/ai/apps/react-router}/src/routes/ai.tsx +0 -0
  148. /package/{template/examples/ai/apps/web-tanstack-start → templates/examples/ai/apps/tanstack-router}/src/routes/ai.tsx +0 -0
  149. /package/{template/examples/ai/apps/web-tanstack-router → templates/examples/ai/apps/tanstack-start}/src/routes/ai.tsx +0 -0
  150. /package/{template/with-drizzle-mysql/apps/server → templates/examples/todo/server/drizzle/mysql}/src/db/schema/todo.ts +0 -0
  151. /package/{template/with-drizzle-postgres/apps/server → templates/examples/todo/server/drizzle/postgres}/src/db/schema/todo.ts +0 -0
  152. /package/{template/examples/todo/apps/server/src/routers/with-prisma-todo.ts → templates/examples/todo/server/prisma/base/trpc/src/routers/todo.ts} +0 -0
  153. /package/{template/with-prisma-mongodb/apps/server → templates/examples/todo/server/prisma/mongodb}/prisma/schema/todo.prisma +0 -0
  154. /package/{template/with-prisma-sqlite/apps/server → templates/examples/todo/server/prisma/mysql}/prisma/schema/todo.prisma +0 -0
  155. /package/{template/with-prisma-postgres/apps/server → templates/examples/todo/server/prisma/postgres}/prisma/schema/todo.prisma +0 -0
  156. /package/{template/with-prisma-mysql/apps/server → templates/examples/todo/server/prisma/sqlite}/prisma/schema/todo.prisma +0 -0
  157. /package/{template/with-pnpm → templates/extras}/pnpm-workspace.yaml +0 -0
  158. /package/{template/base/apps → templates/frontend}/native/_gitignore +0 -0
  159. /package/{template/base/apps → templates/frontend}/native/app/(drawer)/(tabs)/_layout.tsx +0 -0
  160. /package/{template/base/apps → templates/frontend}/native/app/(drawer)/(tabs)/index.tsx +0 -0
  161. /package/{template/base/apps → templates/frontend}/native/app/(drawer)/(tabs)/two.tsx +0 -0
  162. /package/{template/base/apps → templates/frontend}/native/app/(drawer)/_layout.tsx +0 -0
  163. /package/{template/base/apps → templates/frontend}/native/app/(drawer)/index.tsx +0 -0
  164. /package/{template/base/apps → templates/frontend}/native/app/+html.tsx +0 -0
  165. /package/{template/base/apps → templates/frontend}/native/app/+not-found.tsx +0 -0
  166. /package/{template/base/apps → templates/frontend}/native/app/_layout.tsx +0 -0
  167. /package/{template/base/apps → templates/frontend}/native/app/modal.tsx +0 -0
  168. /package/{template/base/apps → templates/frontend}/native/app-env.d.ts +0 -0
  169. /package/{template/base/apps → templates/frontend}/native/app.json +0 -0
  170. /package/{template/base/apps → templates/frontend}/native/assets/adaptive-icon.png +0 -0
  171. /package/{template/base/apps → templates/frontend}/native/assets/favicon.png +0 -0
  172. /package/{template/base/apps → templates/frontend}/native/assets/icon.png +0 -0
  173. /package/{template/base/apps → templates/frontend}/native/assets/splash.png +0 -0
  174. /package/{template/base/apps → templates/frontend}/native/babel.config.js +0 -0
  175. /package/{template/base/apps → templates/frontend}/native/components/container.tsx +0 -0
  176. /package/{template/base/apps → templates/frontend}/native/components/header-button.tsx +0 -0
  177. /package/{template/base/apps → templates/frontend}/native/components/tabbar-icon.tsx +0 -0
  178. /package/{template/base/apps → templates/frontend}/native/global.css +0 -0
  179. /package/{template/base/apps → templates/frontend}/native/lib/android-navigation-bar.tsx +0 -0
  180. /package/{template/base/apps → templates/frontend}/native/lib/constants.ts +0 -0
  181. /package/{template/base/apps → templates/frontend}/native/lib/use-color-scheme.ts +0 -0
  182. /package/{template/base/apps → templates/frontend}/native/metro.config.js +0 -0
  183. /package/{template/base/apps → templates/frontend}/native/package.json +0 -0
  184. /package/{template/base/apps → templates/frontend}/native/tailwind.config.js +0 -0
  185. /package/{template/base/apps → templates/frontend}/native/tsconfig.json +0 -0
  186. /package/{template/base/apps → templates/frontend}/native/utils/trpc.ts +0 -0
  187. /package/{template/base/apps/web-next → templates/frontend/next}/next-env.d.ts +0 -0
  188. /package/{template/base/apps/web-next → templates/frontend/next}/next.config.ts +0 -0
  189. /package/{template/base/apps/web-next → templates/frontend/next}/postcss.config.mjs +0 -0
  190. /package/{template/base/apps/web-next → templates/frontend/next}/src/app/favicon.ico +0 -0
  191. /package/{template/base/apps/web-next → templates/frontend/next}/src/app/layout.tsx +0 -0
  192. /package/{template/base/apps/web-next → templates/frontend/next}/src/components/mode-toggle.tsx +0 -0
  193. /package/{template/base/apps/web-next → templates/frontend/next}/src/components/theme-provider.tsx +0 -0
  194. /package/{template/base/apps/web-next → templates/frontend/next}/tsconfig.json +0 -0
  195. /package/{template/base/apps/web-react-router → templates/frontend/react-router}/public/favicon.ico +0 -0
  196. /package/{template/base/apps/web-react-router → templates/frontend/react-router}/react-router.config.ts +0 -0
  197. /package/{template/base/apps/web-tanstack-router → templates/frontend/react-router}/src/components/mode-toggle.tsx +0 -0
  198. /package/{template/base/apps/web-tanstack-router → templates/frontend/react-router}/src/components/theme-provider.tsx +0 -0
  199. /package/{template/base/apps/web-react-router → templates/frontend/react-router}/src/routes.ts +0 -0
  200. /package/{template/base/apps/web-react-router → templates/frontend/react-router}/tsconfig.json +0 -0
  201. /package/{template/base/apps/web-tanstack-router → templates/frontend/tanstack-router}/index.html +0 -0
  202. /package/{template/base/apps/web-react-router → templates/frontend/tanstack-router}/src/components/mode-toggle.tsx +0 -0
  203. /package/{template/base/apps/web-react-router → templates/frontend/tanstack-router}/src/components/theme-provider.tsx +0 -0
  204. /package/{template/base/apps/web-tanstack-router → templates/frontend/tanstack-router}/tsconfig.json +0 -0
  205. /package/{template/base/apps/web-tanstack-start → templates/frontend/tanstack-start}/app.config.ts +0 -0
  206. /package/{template/base/apps/web-tanstack-start → templates/frontend/tanstack-start}/public/robots.txt +0 -0
  207. /package/{template/base/apps/web-tanstack-start → templates/frontend/tanstack-start}/src/api.ts +0 -0
  208. /package/{template/base/apps/web-tanstack-start → templates/frontend/tanstack-start}/src/client.tsx +0 -0
  209. /package/{template/base/apps/web-tanstack-start → templates/frontend/tanstack-start}/src/ssr.tsx +0 -0
  210. /package/{template/base/apps/web-tanstack-start → templates/frontend/tanstack-start}/tsconfig.json +0 -0
  211. /package/{template/base/apps → templates/frontend}/web-base/_gitignore +0 -0
  212. /package/{template/base/apps → templates/frontend}/web-base/components.json +0 -0
  213. /package/{template/base/apps → templates/frontend}/web-base/src/components/loader.tsx +0 -0
  214. /package/{template/base/apps → templates/frontend}/web-base/src/components/ui/button.tsx +0 -0
  215. /package/{template/base/apps → templates/frontend}/web-base/src/components/ui/card.tsx +0 -0
  216. /package/{template/base/apps → templates/frontend}/web-base/src/components/ui/checkbox.tsx +0 -0
  217. /package/{template/base/apps → templates/frontend}/web-base/src/components/ui/dropdown-menu.tsx +0 -0
  218. /package/{template/base/apps → templates/frontend}/web-base/src/components/ui/input.tsx +0 -0
  219. /package/{template/base/apps → templates/frontend}/web-base/src/components/ui/label.tsx +0 -0
  220. /package/{template/base/apps → templates/frontend}/web-base/src/components/ui/skeleton.tsx +0 -0
  221. /package/{template/base/apps → templates/frontend}/web-base/src/components/ui/sonner.tsx +0 -0
  222. /package/{template/base/apps → templates/frontend}/web-base/src/index.css +0 -0
  223. /package/{template/base/apps → templates/frontend}/web-base/src/lib/utils.ts +0 -0
package/dist/index.js CHANGED
@@ -1,33 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import{cancel as $,intro as Cn,log as L,outro as Fn,spinner as Rn}from"@clack/prompts";import y from"picocolors";import In from"yargs";import{hideBin as On}from"yargs/helpers";import Se from"node:path";import{fileURLToPath as Xt}from"node:url";var ae=()=>{let e=process.env.npm_config_user_agent;return e?.startsWith("pnpm")?"pnpm":e?.startsWith("bun")?"bun":"npm"};var Zt=Xt(import.meta.url),er=Se.dirname(Zt),v=Se.join(er,"../"),h={projectName:"my-better-t-app",frontend:["tanstack-router"],database:"sqlite",orm:"drizzle",auth:!0,addons:[],examples:[],git:!0,packageManager:ae(),noInstall:!1,dbSetup:"none",backend:"hono",runtime:"bun"},me={"better-auth":"^1.2.5","@better-auth/expo":"^1.2.5","drizzle-orm":"^0.38.4","drizzle-kit":"^0.30.5","@libsql/client":"^0.14.0",pg:"^8.14.1","@types/pg":"^8.11.11",mysql2:"^3.14.0","@prisma/client":"^6.6.0",prisma:"^6.6.0","vite-plugin-pwa":"^0.21.2","@vite-pwa/assets-generator":"^0.2.6","@tauri-apps/cli":"^2.4.0","@biomejs/biome":"1.9.4",husky:"^9.1.7","lint-staged":"^15.5.0","@hono/node-server":"^1.14.0",tsx:"^4.19.2","@types/node":"^22.13.11","@types/bun":"^1.2.6","@elysiajs/node":"^1.2.6","@elysiajs/cors":"^1.2.0","@elysiajs/trpc":"^1.1.0",elysia:"^1.2.25","@hono/trpc-server":"^0.3.4",hono:"^4.7.6",cors:"^2.8.5",express:"^5.1.0","@types/express":"^5.0.1","@types/cors":"^2.8.17",ai:"^4.2.8","@ai-sdk/google":"^1.2.3","@prisma/extension-accelerate":"^1.3.0"};import ka from"node:path";import{cancel as $a,spinner as Sa}from"@clack/prompts";import Aa from"fs-extra";import Pt from"picocolors";import N from"node:path";import A from"fs-extra";import tr from"node:path";import Ae from"fs-extra";var g=e=>{let{dependencies:r=[],devDependencies:t=[],projectDir:a}=e,n=tr.join(a,"package.json"),s=Ae.readJSONSync(n);s.dependencies||(s.dependencies={}),s.devDependencies||(s.devDependencies={});for(let o of r){let i=me[o];s.dependencies[o]=i}for(let o of t){let i=me[o];s.devDependencies[o]=i}Ae.writeJSONSync(n,s,{spaces:2})};import rr from"node:path";import{log as ar,spinner as nr}from"@clack/prompts";import{execa as sr}from"execa";import Ee from"picocolors";async function De(e,r){let t=nr();try{t.start("Setting up Starlight documentation site...");let a,n;switch(r){case"npm":a="npx",n=["create-astro@latest"];break;case"pnpm":a="pnpm",n=["dlx","create-astro@latest"];break;case"bun":a="bunx",n=["create-astro@latest"];break;default:a="npx",n=["create-astro@latest"]}n=[...n,"docs","--template","starlight","--no-install","--add","tailwind","--no-git","--skip-houston"],await sr(a,n,{cwd:rr.join(e,"apps"),env:{CI:"true"}}),t.stop("Starlight documentation site setup successfully!")}catch(a){throw t.stop(Ee.red("Failed to set up Starlight documentation site")),a instanceof Error&&ar.error(Ee.red(a.message)),a}}import ne from"node:path";import{log as or,spinner as ir}from"@clack/prompts";import{execa as cr}from"execa";import se from"fs-extra";import Te from"picocolors";async function Ce(e,r,t){let a=ir(),n=ne.join(e,"apps/web");if(await se.pathExists(n))try{a.start("Setting up Tauri desktop app support..."),g({devDependencies:["@tauri-apps/cli"],projectDir:n});let s=ne.join(n,"package.json");if(await se.pathExists(s)){let d=await se.readJson(s);d.scripts={...d.scripts,tauri:"tauri","desktop:dev":"tauri dev","desktop:build":"tauri build"},await se.writeJson(s,d,{spaces:2})}let o,i;switch(r){case"npm":o="npx",i=["@tauri-apps/cli@latest"];break;case"pnpm":o="pnpm",i=["dlx","@tauri-apps/cli@latest"];break;case"bun":o="bunx",i=["@tauri-apps/cli@latest"];break;default:o="npx",i=["@tauri-apps/cli@latest"]}let p=t.includes("react-router")?"http://localhost:5173":"http://localhost:3001";i=[...i,"init",`--app-name=${ne.basename(e)}`,`--window-title=${ne.basename(e)}`,"--frontend-dist=dist",`--dev-url=${p}`,`--before-dev-command=${r} run dev`,`--before-build-command=${r} run build`],await cr(o,i,{cwd:n,env:{CI:"true"}}),a.stop("Tauri desktop app support configured successfully!")}catch(s){throw a.stop(Te.red("Failed to set up Tauri")),s instanceof Error&&or.error(Te.red(s.message)),s}}async function Fe(e,r,t,a){let n=a.includes("react-router")||a.includes("tanstack-router");r.includes("pwa")&&n&&await dr(e,a),r.includes("tauri")&&n&&await Ce(e,t,a),r.includes("biome")&&await lr(e),r.includes("husky")&&await ur(e),r.includes("starlight")&&await De(e,t)}function pr(e,r){return N.join(e,"apps/web")}async function lr(e){let r=N.join(v,"template/with-biome");await A.pathExists(r)&&await A.copy(r,e,{overwrite:!0}),g({devDependencies:["@biomejs/biome"],projectDir:e});let t=N.join(e,"package.json");if(await A.pathExists(t)){let a=await A.readJson(t);a.scripts={...a.scripts,check:"biome check --write ."},await A.writeJson(t,a,{spaces:2})}}async function ur(e){let r=N.join(v,"template/with-husky");await A.pathExists(r)&&await A.copy(r,e,{overwrite:!0}),g({devDependencies:["husky","lint-staged"],projectDir:e});let t=N.join(e,"package.json");if(await A.pathExists(t)){let a=await A.readJson(t);a.scripts={...a.scripts,prepare:"husky"},a["lint-staged"]={"*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}":["biome check --write ."]},await A.writeJson(t,a,{spaces:2})}}async function dr(e,r){let t=N.join(v,"template/with-pwa");await A.pathExists(t)&&await A.copy(t,e,{overwrite:!0});let a=pr(e,r);if(!await A.pathExists(a))return;g({dependencies:["vite-plugin-pwa"],devDependencies:["@vite-pwa/assets-generator"],projectDir:a});let n=N.join(a,"vite.config.ts");if(await A.pathExists(n)){let o=await A.readFile(n,"utf8");if(!o.includes("vite-plugin-pwa")){let l=o.match(/^import .* from ['"](.*)['"]/m);l?o=o.replace(l[0],`import { VitePWA } from "vite-plugin-pwa";
3
- ${l[0]}`):o=`import { VitePWA } from "vite-plugin-pwa";
4
- ${o}`}let i=`VitePWA({
5
- registerType: "autoUpdate",
6
- manifest: {
7
- name: "My App",
8
- short_name: "My App",
9
- description: "My App",
10
- theme_color: "#0c0c0c",
11
- },
12
- pwaAssets: {
13
- disabled: false,
14
- config: true,
15
- },
16
- devOptions: {
17
- enabled: true,
18
- },
19
- })`;o.includes("VitePWA(")||(r.includes("react-router")?o=o.replace(/plugins: \[\s*tailwindcss\(\)/,`plugins: [
20
- tailwindcss(),
21
- ${i}`):r.includes("tanstack-router")?o=o.replace(/plugins: \[\s*tailwindcss\(\)/,`plugins: [
22
- tailwindcss(),
23
- ${i}`):o=o.replace(/plugins: \[/,`plugins: [
24
- ${i},`)),await A.writeFile(n,o)}let s=N.join(a,"package.json");if(await A.pathExists(s)){let o=await A.readJson(s);o.scripts={...o.scripts,"generate-pwa-assets":"pwa-assets-generator"},await A.writeJson(s,o,{spaces:2})}}import fe from"node:path";import{log as Re}from"@clack/prompts";import Ie from"picocolors";function Oe(e=32){let r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",t="",a=r.length;for(let n=0;n<e;n++)t+=r.charAt(Math.floor(Math.random()*a));return t}async function Be(e,r,t=[]){if(!r)return;let a=fe.join(e,"apps/server"),n=fe.join(e,"apps/web"),s=fe.join(e,"apps/native");try{g({dependencies:["better-auth"],projectDir:a}),(t.includes("react-router")||t.includes("tanstack-router")||t.includes("tanstack-start"))&&g({dependencies:["better-auth"],projectDir:n}),t.includes("native")&&(g({dependencies:["better-auth","@better-auth/expo"],projectDir:s}),g({dependencies:["@better-auth/expo"],projectDir:a}))}catch(o){throw Re.error(Ie.red("Failed to configure authentication")),o instanceof Error&&Re.error(Ie.red(o.message)),o}}import mr from"node:path";async function Le(e,r,t){let a=mr.join(e,"apps/server"),n=[],s=[];r==="hono"?(n.push("hono","@hono/trpc-server"),t==="node"&&(n.push("@hono/node-server"),s.push("tsx","@types/node"))):r==="elysia"?(n.push("elysia","@elysiajs/cors","@elysiajs/trpc"),t==="node"&&(n.push("@elysiajs/node"),s.push("tsx","@types/node"))):r==="express"&&(n.push("express","cors"),s.push("@types/express","@types/cors"),t==="node"&&s.push("tsx","@types/node")),t==="bun"&&s.push("@types/bun"),g({dependencies:n,devDependencies:s,projectDir:a})}import fr from"node:path";import hr from"fs-extra";async function Ne(e,r){let t=fr.join(e,"README.md"),a=gr(r);try{await hr.writeFile(t,a)}catch(n){console.error("Failed to create README.md file:",n)}}function gr(e){let{projectName:r,packageManager:t,database:a,auth:n,addons:s=[],orm:o="drizzle",runtime:i="bun",frontend:l=["tanstack-router"]}=e,p=l.includes("react-router"),d=l.includes("tanstack-router"),P=l.includes("native"),x=t==="npm"?"npm run":t,j=p?"5173":"3001";return`# ${r}
25
-
26
- This project was created with [Better-T-Stack](https://github.com/AmanVarshney01/create-better-t-stack), a modern TypeScript stack that combines React, ${d?"TanStack Router":"React Router"}, Hono, tRPC, and more.
2
+ import{cancel as Vn,intro as Gn,log as _,outro as Jn}from"@clack/prompts";import{consola as v}from"consola";import z from"picocolors";import Qn from"yargs";import{hideBin as Hn}from"yargs/helpers";import Ie from"node:path";import{fileURLToPath as mr}from"node:url";var re=()=>{let e=process.env.npm_config_user_agent;return e?.startsWith("pnpm")?"pnpm":e?.startsWith("bun")?"bun":"npm"};var fr=mr(import.meta.url),gr=Ie.dirname(fr),P=Ie.join(gr,"../"),h={projectName:"my-better-t-app",frontend:["tanstack-router"],database:"sqlite",orm:"drizzle",auth:!0,addons:[],examples:[],git:!0,packageManager:re(),install:!0,dbSetup:"none",backend:"hono",runtime:"bun",api:"trpc"},he={"better-auth":"^1.2.6","@better-auth/expo":"^1.2.6","drizzle-orm":"^0.38.4","drizzle-kit":"^0.30.5","@libsql/client":"^0.14.0",pg:"^8.14.1","@types/pg":"^8.11.11",mysql2:"^3.14.0","@prisma/client":"^6.6.0",prisma:"^6.6.0","vite-plugin-pwa":"^0.21.2","@vite-pwa/assets-generator":"^0.2.6","@tauri-apps/cli":"^2.4.0","@biomejs/biome":"1.9.4",husky:"^9.1.7","lint-staged":"^15.5.0","@hono/node-server":"^1.14.0",tsx:"^4.19.2","@types/node":"^22.13.11","@types/bun":"^1.2.6","@elysiajs/node":"^1.2.6","@elysiajs/cors":"^1.2.0","@elysiajs/trpc":"^1.1.0",elysia:"^1.2.25","@hono/trpc-server":"^0.3.4",hono:"^4.7.6",cors:"^2.8.5",express:"^5.1.0","@types/express":"^5.0.1","@types/cors":"^2.8.17",turbo:"^2.4.2",ai:"^4.2.8","@ai-sdk/google":"^1.2.3","@prisma/extension-accelerate":"^1.3.0","@orpc/server":"^1.0.3","@orpc/react-query":"^1.0.3","@orpc/client":"^1.0.3","@trpc/tanstack-react-query":"^11.0.0","@trpc/server":"^11.0.0","@trpc/client":"^11.0.0"};import Ra from"node:path";import{cancel as Ba,log as Na,spinner as Ia}from"@clack/prompts";import Ma from"fs-extra";import Tt from"picocolors";import Y from"node:path";import B from"fs-extra";import hr from"node:path";import Me from"fs-extra";var g=async e=>{let{dependencies:r=[],devDependencies:t=[],projectDir:a}=e,n=hr.join(a,"package.json"),o=await Me.readJson(n);o.dependencies||(o.dependencies={}),o.devDependencies||(o.devDependencies={});for(let i of r){let s=he[i];s?o.dependencies[i]=s:console.warn(`Warning: Dependency ${i} not found in version map.`)}for(let i of t){let s=he[i];s?o.devDependencies[i]=s:console.warn(`Warning: Dev dependency ${i} not found in version map.`)}await Me.writeJson(n,o,{spaces:2})};import Le from"node:path";import{spinner as br}from"@clack/prompts";import wr from"consola";import{execa as yr}from"execa";import Oe from"picocolors";function R(e,r){switch(e){case"pnpm":return`pnpm dlx ${r}`;case"bun":return`bunx ${r}`;default:return`npx ${r}`}}async function Ue(e){let{projectName:r,packageManager:t}=e,a=Le.resolve(process.cwd(),r),n=br();try{n.start("Setting up Starlight docs...");let s=`create-astro@latest ${["docs","--template","starlight","--no-install","--add","tailwind","--no-git","--skip-houston"].join(" ")}`,c=R(t,s);await yr(c,{cwd:Le.join(a,"apps"),env:{CI:"true"},shell:!0}),n.stop("Starlight docs setup successfully!")}catch(o){throw n.stop(Oe.red("Failed to set up Starlight docs")),o instanceof Error&&wr.error(Oe.red(o.message)),o}}import H from"node:path";import{spinner as Pr}from"@clack/prompts";import{consola as vr}from"consola";import{execa as jr}from"execa";import ae from"fs-extra";import _e from"picocolors";async function ze(e){let{projectName:r,packageManager:t,frontend:a}=e,n=H.resolve(process.cwd(),r),o=Pr(),i=H.join(n,"apps/web");if(await ae.pathExists(i))try{o.start("Setting up Tauri desktop app support..."),await g({devDependencies:["@tauri-apps/cli"],projectDir:i});let s=H.join(i,"package.json");if(await ae.pathExists(s)){let A=await ae.readJson(s);A.scripts={...A.scripts,tauri:"tauri","desktop:dev":"tauri dev","desktop:build":"tauri build"},await ae.writeJson(s,A,{spaces:2})}let p=a.includes("react-router")?"http://localhost:5173":"http://localhost:3001",f=`@tauri-apps/cli@latest ${["init",`--app-name=${H.basename(n)}`,`--window-title=${H.basename(n)}`,"--frontend-dist=../dist",`--dev-url=${p}`,`--before-dev-command="${t} run dev"`,`--before-build-command="${t} run build"`].join(" ")}`,k=R(t,f);await jr(k,{cwd:i,env:{CI:"true"},shell:!0}),o.stop("Tauri desktop app support configured successfully!")}catch(s){throw o.stop(_e.red("Failed to set up Tauri")),s instanceof Error&&vr.error(_e.red(s.message)),s}}async function We(e){let{projectName:r,addons:t,packageManager:a,frontend:n}=e,o=Y.resolve(process.cwd(),r),i=n.includes("react-router")||n.includes("tanstack-router");t.includes("turborepo")&&await g({devDependencies:["turbo"],projectDir:o}),t.includes("pwa")&&i&&await Sr(o,n),t.includes("tauri")&&i&&await ze(e),t.includes("biome")&&await xr(o),t.includes("husky")&&await Ar(o),t.includes("starlight")&&await Ue(e)}function kr(e,r){return Y.join(e,"apps/web")}async function xr(e){await g({devDependencies:["@biomejs/biome"],projectDir:e});let r=Y.join(e,"package.json");if(await B.pathExists(r)){let t=await B.readJson(r);t.scripts={...t.scripts,check:"biome check --write ."},await B.writeJson(r,t,{spaces:2})}}async function Ar(e){await g({devDependencies:["husky","lint-staged"],projectDir:e});let r=Y.join(e,"package.json");if(await B.pathExists(r)){let t=await B.readJson(r);t.scripts={...t.scripts,prepare:"husky"},t["lint-staged"]={"*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}":["biome check --write ."]},await B.writeJson(r,t,{spaces:2})}}async function Sr(e,r){let t=kr(e,r);if(!await B.pathExists(t))return;await g({dependencies:["vite-plugin-pwa"],devDependencies:["@vite-pwa/assets-generator"],projectDir:t});let a=Y.join(t,"package.json");if(await B.pathExists(a)){let n=await B.readJson(a);n.scripts={...n.scripts,"generate-pwa-assets":"pwa-assets-generator"},await B.writeJson(a,n,{spaces:2})}}import*as K from"node:path";async function qe(e){if(e.api==="none")return;let{api:r,projectName:t}=e,a=K.resolve(process.cwd(),t),n=K.join(a,"apps/web"),o=K.join(a,"apps/server");r==="orpc"&&(await g({dependencies:["@orpc/react-query","@orpc/server","@orpc/client"],projectDir:n}),await g({dependencies:["@orpc/server","@orpc/client"],projectDir:o})),r==="trpc"&&(await g({dependencies:["@trpc/tanstack-react-query","@trpc/server","@trpc/client"],projectDir:n}),await g({dependencies:["@trpc/server","@trpc/client"],projectDir:o}))}import ne from"node:path";import Ve from"consola";import Ge from"picocolors";function Je(e=32){let r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",t="",a=r.length;for(let n=0;n<e;n++)t+=r.charAt(Math.floor(Math.random()*a));return t}async function Qe(e){let{projectName:r,auth:t,frontend:a}=e;if(!t)return;let n=ne.resolve(process.cwd(),r),o=ne.join(n,"apps/server"),i=ne.join(n,"apps/web"),s=ne.join(n,"apps/native");try{await g({dependencies:["better-auth"],projectDir:o}),(a.includes("react-router")||a.includes("tanstack-router")||a.includes("tanstack-start"))&&await g({dependencies:["better-auth"],projectDir:i}),a.includes("native")&&(await g({dependencies:["better-auth","@better-auth/expo"],projectDir:s}),await g({dependencies:["@better-auth/expo"],projectDir:o}))}catch(c){throw Ve.error(Ge.red("Failed to configure authentication")),c instanceof Error&&Ve.error(Ge.red(c.message)),c}}import He from"node:path";async function Ye(e){let{projectName:r,backend:t,runtime:a}=e,n=He.resolve(process.cwd(),r),o=t,i=He.join(n,"apps/server"),s=[],c=[];o==="hono"?(s.push("hono","@hono/trpc-server"),a==="node"&&(s.push("@hono/node-server"),c.push("tsx","@types/node"))):o==="elysia"?(s.push("elysia","@elysiajs/cors","@elysiajs/trpc"),a==="node"&&(s.push("@elysiajs/node"),c.push("tsx","@types/node"))):o==="express"&&(s.push("express","cors"),c.push("@types/express","@types/cors"),a==="node"&&c.push("tsx","@types/node")),a==="bun"&&c.push("@types/bun"),await g({dependencies:s,devDependencies:c,projectDir:i})}import Dr from"node:path";import $r from"consola";import Cr from"fs-extra";async function Ke(e,r){let t=Dr.join(e,"README.md"),a=Er(r);try{await Cr.writeFile(t,a)}catch(n){$r.error("Failed to create README.md file:",n)}}function Er(e){let{projectName:r,packageManager:t,database:a,auth:n,addons:o=[],orm:i="drizzle",runtime:s="bun",frontend:c=["tanstack-router"],backend:p="hono"}=e,w=c.includes("react-router"),y=c.includes("tanstack-router"),f=c.includes("native"),k=c.includes("next"),A=c.includes("tanstack-start"),E=t==="npm"?"npm run":t,x="3001";return w?x="5173":k&&(x="3000"),`# ${r}
3
+
4
+ This project was created with [Better-T-Stack](https://github.com/AmanVarshney01/create-better-t-stack), a modern TypeScript stack that combines React, ${y?"TanStack Router":w?"React Router":k?"Next.js":A?"TanStack Start":""}, ${p[0].toUpperCase()+p.slice(1)}, tRPC, and more.
27
5
 
28
6
  ## Features
29
7
 
30
- ${br(a,n,s,o,i,l)}
8
+ ${Tr(a,n,o,i,s,c,p)}
31
9
 
32
10
  ## Getting Started
33
11
 
@@ -37,20 +15,20 @@ First, install the dependencies:
37
15
  ${t} install
38
16
  \`\`\`
39
17
 
40
- ${wr(a,n,x,o)}
18
+ ${Fr(a,n,E,i)}
41
19
 
42
20
  Then, run the development server:
43
21
 
44
22
  \`\`\`bash
45
- ${x} dev
23
+ ${E} dev
46
24
  \`\`\`
47
25
 
48
- ${d||p?`Open [http://localhost:${j}](http://localhost:${j}) in your browser to see the web application.`:""}
49
- ${P?`Use the Expo Go app to run the mobile application.
26
+ ${y||w||k||A?`Open [http://localhost:${x}](http://localhost:${x}) in your browser to see the web application.`:""}
27
+ ${f?`Use the Expo Go app to run the mobile application.
50
28
  `:""}
51
29
  The API is running at [http://localhost:3000](http://localhost:3000).
52
30
 
53
- ${s.includes("pwa")&&p?`
31
+ ${o.includes("pwa")&&w?`
54
32
  ## PWA Support with React Router v7
55
33
 
56
34
  There is a known compatibility issue between VitePWA and React Router v7.
@@ -62,16 +40,17 @@ See: https://github.com/vite-pwa/vite-plugin-pwa/issues/809
62
40
  \`\`\`
63
41
  ${r}/
64
42
  \u251C\u2500\u2500 apps/
65
- ${d||p?`\u2502 \u251C\u2500\u2500 web/ # Frontend application (React, ${d?"TanStack Router":"React Router"})
66
- `:""}${P?`\u2502 \u251C\u2500\u2500 native/ # Mobile application (React Native, Expo)
67
- `:""}\u2502 \u2514\u2500\u2500 server/ # Backend API (Hono, tRPC)
43
+ ${y||w||k||A?`\u2502 \u251C\u2500\u2500 web/ # Frontend application (${y?"React + TanStack Router":w?"React + React Router":k?"Next.js":"React + TanStack Start"})
44
+ `:""}${f?`\u2502 \u251C\u2500\u2500 native/ # Mobile application (React Native, Expo)
45
+ `:""}${o.includes("starlight")?`\u2502 \u251C\u2500\u2500 docs/ # Documentation site (Astro Starlight)
46
+ `:""}\u2502 \u2514\u2500\u2500 server/ # Backend API (${p[0].toUpperCase()+p.slice(1)}, tRPC)
68
47
  \`\`\`
69
48
 
70
49
  ## Available Scripts
71
50
 
72
- ${yr(x,a,o,n,P)}
73
- `}function br(e,r,t,a,n,s){let o=s.includes("tanstack-router"),i=s.includes("react-router"),l=s.includes("native"),p=["- **TypeScript** - For type safety and improved developer experience"];o?p.push("- **TanStack Router** - File-based routing with full type safety"):i&&p.push("- **React Router** - Declarative routing for React"),l&&(p.push("- **React Native** - Build mobile apps using React"),p.push("- **Expo** - Tools for React Native development")),p.push("- **TailwindCSS** - Utility-first CSS for rapid UI development","- **shadcn/ui** - Reusable UI components","- **Hono** - Lightweight, performant server framework","- **tRPC** - End-to-end type-safe APIs",`- **${n==="bun"?"Bun":"Node.js"}** - Runtime environment`),e!=="none"&&p.push(`- **${a==="drizzle"?"Drizzle":"Prisma"}** - TypeScript-first ORM`,`- **${e==="sqlite"?"SQLite/Turso":"PostgreSQL"}** - Database engine`),r&&p.push("- **Authentication** - Email & password authentication with Better Auth");for(let d of t)d==="pwa"?p.push("- **PWA** - Progressive Web App support"):d==="tauri"?p.push("- **Tauri** - Build native desktop applications"):d==="biome"?p.push("- **Biome** - Linting and formatting"):d==="husky"&&p.push("- **Husky** - Git hooks for code quality");return p.join(`
74
- `)}function wr(e,r,t,a){if(e==="none")return"";let n=`## Database Setup
51
+ ${Rr(E,a,i,n,f,o,p)}
52
+ `}function Tr(e,r,t,a,n,o,i){let s=o.includes("tanstack-router"),c=o.includes("react-router"),p=o.includes("native"),w=o.includes("next"),y=o.includes("tanstack-start"),f=["- **TypeScript** - For type safety and improved developer experience"];s?f.push("- **TanStack Router** - File-based routing with full type safety"):c?f.push("- **React Router** - Declarative routing for React"):w?f.push("- **Next.js** - Full-stack React framework"):y&&f.push("- **TanStack Start** - SSR framework with TanStack Router"),p&&(f.push("- **React Native** - Build mobile apps using React"),f.push("- **Expo** - Tools for React Native development")),f.push("- **TailwindCSS** - Utility-first CSS for rapid UI development","- **shadcn/ui** - Reusable UI components"),i==="hono"?f.push("- **Hono** - Lightweight, performant server framework"):i==="express"?f.push("- **Express** - Fast, unopinionated web framework"):i==="elysia"?f.push("- **Elysia** - Type-safe, high-performance framework"):i==="next"&&f.push("- **Next.js** - Full-stack React framework"),f.push("- **tRPC** - End-to-end type-safe APIs",`- **${n==="bun"?"Bun":"Node.js"}** - Runtime environment`),e!=="none"&&f.push(`- **${a==="drizzle"?"Drizzle":"Prisma"}** - TypeScript-first ORM`,`- **${e==="sqlite"?"SQLite/Turso":e==="postgres"?"PostgreSQL":e==="mysql"?"MySQL":"MongoDB"}** - Database engine`),r&&f.push("- **Authentication** - Email & password authentication with Better Auth");for(let k of t)k==="pwa"?f.push("- **PWA** - Progressive Web App support"):k==="tauri"?f.push("- **Tauri** - Build native desktop applications"):k==="biome"?f.push("- **Biome** - Linting and formatting"):k==="husky"?f.push("- **Husky** - Git hooks for code quality"):k==="starlight"&&f.push("- **Starlight** - Documentation site with Astro");return f.join(`
53
+ `)}function Fr(e,r,t,a){if(e==="none")return"";let n=`## Database Setup
75
54
 
76
55
  `;return e==="sqlite"?n+=`This project uses SQLite${a==="drizzle"?" with Drizzle ORM":" with Prisma"}.
77
56
 
@@ -81,69 +60,76 @@ cd apps/server && ${t} db:local
81
60
  \`\`\`
82
61
 
83
62
  2. Update your \`.env\` file in the \`apps/server\` directory with the appropriate connection details if needed.
84
- `:e==="postgres"&&(n+=`This project uses PostgreSQL${a==="drizzle"?" with Drizzle ORM":" with Prisma"}.
63
+ `:e==="postgres"?n+=`This project uses PostgreSQL${a==="drizzle"?" with Drizzle ORM":" with Prisma"}.
85
64
 
86
65
  1. Make sure you have a PostgreSQL database set up.
87
66
  2. Update your \`apps/server/.env\` file with your PostgreSQL connection details.
67
+ `:e==="mysql"?n+=`This project uses MySQL${a==="drizzle"?" with Drizzle ORM":" with Prisma"}.
68
+
69
+ 1. Make sure you have a MySQL database set up.
70
+ 2. Update your \`apps/server/.env\` file with your MySQL connection details.
71
+ `:e==="mongodb"&&(n+=`This project uses MongoDB with Prisma ORM.
72
+
73
+ 1. Make sure you have MongoDB set up.
74
+ 2. Update your \`apps/server/.env\` file with your MongoDB connection URI.
88
75
  `),n+=`
89
- ${r?"4":"3"}. ${a==="prisma"?`Generate the Prisma client and push the schema:
76
+ 3. ${a==="prisma"?`Generate the Prisma client and push the schema:
90
77
  \`\`\`bash
91
78
  ${t} db:push
92
79
  \`\`\``:`Apply the schema to your database:
93
80
  \`\`\`bash
94
81
  ${t} db:push
95
82
  \`\`\``}
96
- `,n}function yr(e,r,t,a,n){let s=`- \`${e} dev\`: Start both web and server in development mode
97
- - \`${e} build\`: Build both web and server
83
+ `,n}function Rr(e,r,t,a,n,o,i){let s=`- \`${e} dev\`: Start all applications in development mode
84
+ - \`${e} build\`: Build all applications
98
85
  - \`${e} dev:web\`: Start only the web application
99
86
  - \`${e} dev:server\`: Start only the server
100
87
  - \`${e} check-types\`: Check TypeScript types across all apps`;return n&&(s+=`
101
88
  - \`${e} dev:native\`: Start the React Native/Expo development server`),r!=="none"&&(s+=`
102
89
  - \`${e} db:push\`: Push schema changes to database
103
90
  - \`${e} db:studio\`: Open database studio UI`,r==="sqlite"&&t==="drizzle"&&(s+=`
104
- - \`cd apps/server && ${e} db:local\`: Start the local SQLite database`)),s}import Xe from"node:path";import{log as Kr,spinner as Yr}from"@clack/prompts";import Xr from"fs-extra";import Ze from"picocolors";import ge from"node:path";import{cancel as Pr,isCancel as jr,log as I,spinner as ze,text as vr}from"@clack/prompts";import{execa as xr}from"execa";import Y from"fs-extra";import T from"picocolors";import{execa as Me}from"execa";async function oe(e){try{return process.platform==="win32"?(await Me("where",[e])).exitCode===0:(await Me("which",[e])).exitCode===0}catch{return!1}}async function kr(){let e=ze();e.start("Checking for MongoDB Atlas CLI");try{let r=await oe("atlas");return e.stop(r?"MongoDB Atlas CLI found":T.yellow("MongoDB Atlas CLI not found")),r}catch{return e.stop(T.red("Error checking for MongoDB Atlas CLI")),!1}}async function $r(e){try{if(!await kr())return I.error(T.red("MongoDB Atlas CLI not found.")),I.info(T.yellow("Please install it from: https://www.mongodb.com/docs/atlas/cli/current/install-atlas-cli/")),null;I.info(T.blue("Running MongoDB Atlas setup...")),await xr("atlas",["deployments","setup"],{cwd:e,stdio:"inherit"}),I.info(T.green("Atlas setup complete!"));let t=await vr({message:"Enter your MongoDB connection string:",placeholder:"mongodb+srv://username:password@cluster.mongodb.net/database",validate(a){if(!a)return"Please enter a connection string";if(!a.startsWith("mongodb"))return"URL should start with mongodb:// or mongodb+srv://"}});return jr(t)?(Pr("MongoDB setup cancelled"),null):{connectionString:t}}catch(r){return r instanceof Error&&I.error(T.red(r.message)),null}}async function he(e,r){try{let t=ge.join(e,"apps/server",".env");await Y.ensureDir(ge.dirname(t));let a="";await Y.pathExists(t)&&(a=await Y.readFile(t,"utf8"));let n=r?`DATABASE_URL="${r.connectionString}"`:'DATABASE_URL="mongodb://localhost:27017/mydb"';a.includes("DATABASE_URL=")?a=a.replace(/DATABASE_URL=.*(\r?\n|$)/,`${n}$1`):a+=`
105
- ${n}`,await Y.writeFile(t,a.trim())}catch(t){throw I.error("Failed to update environment configuration"),t}}function _e(){I.info(`
106
- ${T.green("MongoDB Atlas Manual Setup Instructions:")}
91
+ - \`cd apps/server && ${e} db:local\`: Start the local SQLite database`)),o.includes("biome")&&(s+=`
92
+ - \`${e} check\`: Run Biome formatting and linting`),o.includes("pwa")&&(s+=`
93
+ - \`cd apps/web && ${e} generate-pwa-assets\`: Generate PWA assets`),o.includes("tauri")&&(s+=`
94
+ - \`cd apps/web && ${e} desktop:dev\`: Start Tauri desktop app in development
95
+ - \`cd apps/web && ${e} desktop:build\`: Build Tauri desktop app`),o.includes("starlight")&&(s+=`
96
+ - \`cd apps/docs && ${e} dev\`: Start documentation site
97
+ - \`cd apps/docs && ${e} build\`: Build documentation site`),s}import $e from"node:path";import{spinner as ua}from"@clack/prompts";import ma from"consola";import fa from"fs-extra";import ct from"picocolors";import se from"node:path";import{cancel as Br,isCancel as Nr,log as W,spinner as et,text as Ir}from"@clack/prompts";import ie from"consola";import{execa as Mr}from"execa";import X from"fs-extra";import D from"picocolors";import{execa as Xe}from"execa";async function oe(e){try{return process.platform==="win32"?(await Xe("where",[e])).exitCode===0:(await Xe("which",[e])).exitCode===0}catch{return!1}}async function Lr(){let e=et();e.start("Checking for MongoDB Atlas CLI");try{let r=await oe("atlas");return e.stop(r?"MongoDB Atlas CLI found":D.yellow("MongoDB Atlas CLI not found")),r}catch{return e.stop(D.red("Error checking for MongoDB Atlas CLI")),!1}}async function Or(e){try{if(!await Lr())return ie.error(D.red("MongoDB Atlas CLI not found.")),W.info(D.yellow("Please install it from: https://www.mongodb.com/docs/atlas/cli/current/install-atlas-cli/")),null;W.info(D.blue("Running MongoDB Atlas setup...")),await Mr("atlas",["deployments","setup"],{cwd:e,stdio:"inherit"}),W.info(D.green("Atlas setup complete!"));let t=await Ir({message:"Enter your MongoDB connection string:",placeholder:"mongodb+srv://username:password@cluster.mongodb.net/database",validate(a){if(!a)return"Please enter a connection string";if(!a.startsWith("mongodb"))return"URL should start with mongodb:// or mongodb+srv://"}});return Nr(t)?(Br("MongoDB setup cancelled"),null):{connectionString:t}}catch(r){return r instanceof Error&&ie.error(D.red(r.message)),null}}async function be(e,r){try{let t=se.join(e,"apps/server",".env");await X.ensureDir(se.dirname(t));let a="";await X.pathExists(t)&&(a=await X.readFile(t,"utf8"));let n=r?`DATABASE_URL="${r.connectionString}"`:'DATABASE_URL="mongodb://localhost:27017/mydb"';a.includes("DATABASE_URL=")?a=a.replace(/DATABASE_URL=.*(\r?\n|$)/,`${n}$1`):a+=`
98
+ ${n}`,await X.writeFile(t,a.trim())}catch(t){throw ie.error("Failed to update environment configuration"),t}}function Ze(){W.info(`
99
+ ${D.green("MongoDB Atlas Manual Setup Instructions:")}
107
100
 
108
101
  1. Install Atlas CLI:
109
- ${T.blue("https://www.mongodb.com/docs/atlas/cli/stable/install-atlas-cli/")}
102
+ ${D.blue("https://www.mongodb.com/docs/atlas/cli/stable/install-atlas-cli/")}
110
103
 
111
104
  2. Run the following command and follow the prompts:
112
- ${T.blue("atlas deployments setup")}
105
+ ${D.blue("atlas deployments setup")}
113
106
 
114
107
  3. Get your connection string from the Atlas dashboard:
115
- Format: ${T.dim("mongodb+srv://USERNAME:PASSWORD@CLUSTER.mongodb.net/DATABASE_NAME")}
108
+ Format: ${D.dim("mongodb+srv://USERNAME:PASSWORD@CLUSTER.mongodb.net/DATABASE_NAME")}
116
109
 
117
110
  4. Add the connection string to your .env file:
118
- ${T.dim('DATABASE_URL="your_connection_string"')}
119
- `)}async function Ue(e){let r=ze();r.start("Setting up MongoDB Atlas");let t=ge.join(e,"apps/server");try{await Y.ensureDir(t),r.stop("Starting MongoDB Atlas setup");let a=await $r(t);a?(await he(e,a),I.success(T.green("MongoDB Atlas setup complete! Connection saved to .env file."))):(I.warn(T.yellow("Falling back to local MongoDB configuration")),await he(e),_e())}catch(a){r.stop(T.red("MongoDB Atlas setup failed")),I.error(T.red(`Error during MongoDB Atlas setup: ${a instanceof Error?a.message:String(a)}`));try{await he(e),_e()}catch{}}}import ie from"node:path";import{cancel as Sr,isCancel as Ar,log as V,spinner as be,text as Er}from"@clack/prompts";import{execa as Ve}from"execa";import we from"fs-extra";import q from"picocolors";function We(e,r){let t,a;switch(e){case"pnpm":t="pnpm",a=["dlx","neonctl",...r];break;case"bun":t="bunx",a=["neonctl",...r];break;default:t="npx",a=["neonctl",...r]}return{cmd:t,cmdArgs:a}}async function Ge(e,r,t){let a=t?be():null;try{let{cmd:n,cmdArgs:s}=We(e,r);a&&a.start(t);let o=await Ve(n,s);return a&&a.stop(t),o}catch(n){throw a&&a.stop(q.red(`Failed: ${t}`)),n}}async function Dr(e){try{let{cmd:r,cmdArgs:t}=We(e,["projects","list"]),a=await Ve(r,t);return!a.stdout.includes("not authenticated")&&!a.stdout.includes("error")}catch{return!1}}async function Tr(e){try{return await Ge(e,["auth"],"Authenticating with Neon..."),V.success("Authenticated with Neon successfully!"),!0}catch(r){throw V.error(q.red("Failed to authenticate with Neon")),r}}async function Cr(e,r){try{let{stdout:t}=await Ge(r,["projects","create","--name",e,"--output","json"],`Creating Neon project "${e}"...`),a=JSON.parse(t);if(a.project&&a.connection_uris&&a.connection_uris.length>0){let n=a.project.id,s=a.connection_uris[0].connection_uri,o=a.connection_uris[0].connection_parameters;return{connectionString:s,projectId:n,dbName:o.database,roleName:o.role}}return V.error(q.red("Failed to extract connection information from response")),null}catch(t){throw V.error(q.red("Failed to create Neon project")),t}}async function qe(e,r){let t=ie.join(e,"apps/server",".env"),a=r?`DATABASE_URL="${r.connectionString}"`:'DATABASE_URL="postgresql://postgres:postgres@localhost:5432/mydb?schema=public"';return await we.ensureDir(ie.dirname(t)),await we.writeFile(t,a),!0}function Fr(){V.info(`Manual Neon PostgreSQL Setup Instructions:
120
-
121
- 1. Visit https://neon.tech and create an account
122
- 2. Create a new project from the dashboard
123
- 3. Get your connection string
124
- 4. Add the database URL to the .env file in apps/server/.env
125
-
126
- DATABASE_URL="your_connection_string"`)}async function Je(e,r){let t=be();t.start("Setting up Neon PostgreSQL");try{let a=await Dr(r);t.stop("Setting up Neon PostgreSQL"),a||(V.info("Please authenticate with Neon to continue:"),await Tr(r));let n=ie.basename(e),s=await Er({message:"Enter a name for your Neon project:",defaultValue:n,initialValue:n});Ar(s)&&(Sr(q.red("Operation cancelled")),process.exit(0));let o=await Cr(s,r);if(!o)throw new Error("Failed to create project - couldn't get connection information");let i=be();i.start("Configuring database connection"),await we.ensureDir(ie.join(e,"apps/server")),await qe(e,o),i.stop("Neon database configured successfully!")}catch(a){t.stop(q.red("Neon PostgreSQL setup failed")),a instanceof Error&&V.error(q.red(a.message)),await qe(e),Fr()}}import H from"node:path";import{cancel as Rr,isCancel as Ir,log as M,password as Or,spinner as Pe}from"@clack/prompts";import{execa as Br}from"execa";import O from"fs-extra";import Q from"picocolors";async function Lr(e,r){let t=Pe();try{t.start("Initializing Prisma PostgreSQL");let a=H.join(e,"prisma");await O.ensureDir(a);let n=r==="npm"?"npx":r==="pnpm"?"pnpm dlx":"bunx";t.stop("Initializing Prisma. Follow the prompts below:"),await Br(n,["prisma","init","--db"],{cwd:e,stdio:"inherit"}),M.info(Q.yellow(`Please copy the Prisma Postgres URL from the output above.
127
- It looks like: prisma+postgres://accelerate.prisma-data.net/?api_key=...`));let s=await Or({message:"Paste your Prisma Postgres database URL:",validate(o){if(!o)return"Please enter a database URL";if(!o.startsWith("prisma+postgres://"))return"URL should start with prisma+postgres://"}});return Ir(s)?(Rr("Database setup cancelled"),null):{databaseUrl:s}}catch(a){return t.stop(Q.red("Failed to initialize Prisma PostgreSQL")),a instanceof Error&&M.error(a.message),null}}async function ye(e,r){try{let t=H.join(e,"apps/server",".env");await O.ensureDir(H.dirname(t));let a="";await O.pathExists(t)&&(a=await O.readFile(t,"utf8"));let n=r?`DATABASE_URL="${r.databaseUrl}"`:'DATABASE_URL="postgresql://postgres:postgres@localhost:5432/mydb?schema=public"';a.includes("DATABASE_URL=")?a=a.replace(/DATABASE_URL=.*(\r?\n|$)/,`${n}$1`):a+=`
128
- ${n}`,await O.writeFile(t,a.trim())}catch(t){throw M.error("Failed to update environment configuration"),t}}function Qe(){M.info(`Manual Prisma PostgreSQL Setup Instructions:
111
+ ${D.dim('DATABASE_URL="your_connection_string"')}
112
+ `)}async function tt(e){let{projectName:r}=e,t=se.resolve(process.cwd(),r),a=et();a.start("Setting up MongoDB Atlas");let n=se.join(t,"apps/server");try{await X.ensureDir(n),a.stop("Starting MongoDB Atlas setup");let o=await Or(n);o?(await be(t,o),W.success(D.green("MongoDB Atlas setup complete! Connection saved to .env file."))):(W.warn(D.yellow("Falling back to local MongoDB configuration")),await be(t),Ze())}catch(o){a.stop(D.red("MongoDB Atlas setup failed")),ie.error(D.red(`Error during MongoDB Atlas setup: ${o instanceof Error?o.message:String(o)}`));try{await be(t),Ze()}catch{}}}import L from"node:path";import{cancel as Ur,isCancel as _r,log as Z,password as zr,spinner as ye}from"@clack/prompts";import{consola as Pe}from"consola";import{execa as Wr}from"execa";import N from"fs-extra";import q from"picocolors";async function qr(e,r){let t=ye();try{t.start("Initializing Prisma PostgreSQL");let a=L.join(e,"prisma");await N.ensureDir(a),t.stop("Initializing Prisma. Follow the prompts below:");let n=R(r,"prisma init --db");await Wr(n,{cwd:e,stdio:"inherit",shell:!0}),Z.info(q.yellow(`Please copy the Prisma Postgres URL from the output above.
113
+ It looks like: prisma+postgres://accelerate.prisma-data.net/?api_key=...`));let o=await zr({message:"Paste your Prisma Postgres database URL:",validate(i){if(!i)return"Please enter a database URL";if(!i.startsWith("prisma+postgres://"))return"URL should start with prisma+postgres://"}});return _r(o)?(Ur("Database setup cancelled"),null):{databaseUrl:o}}catch(a){return t.stop(q.red("Failed to initialize Prisma PostgreSQL")),a instanceof Error&&Pe.error(a.message),null}}async function we(e,r){try{let t=L.join(e,"apps/server",".env");await N.ensureDir(L.dirname(t));let a="";await N.pathExists(t)&&(a=await N.readFile(t,"utf8"));let n=r?`DATABASE_URL="${r.databaseUrl}"`:'DATABASE_URL="postgresql://postgres:postgres@localhost:5432/mydb?schema=public"';a.includes("DATABASE_URL=")?a=a.replace(/DATABASE_URL=.*(\r?\n|$)/,`${n}$1`):a+=`
114
+ ${n}`,await N.writeFile(t,a.trim())}catch(t){throw Pe.error("Failed to update environment configuration"),t}}function rt(){Z.info(`Manual Prisma PostgreSQL Setup Instructions:
129
115
 
130
116
  1. Visit https://console.prisma.io and create an account
131
117
  2. Create a new PostgreSQL database from the dashboard
132
118
  3. Get your database URL
133
119
  4. Add the database URL to the .env file in apps/server/.env
134
120
 
135
- DATABASE_URL="your_database_url"`)}async function Nr(e){try{g({dependencies:["@prisma/extension-accelerate"],projectDir:e});let r=H.join(e,"prisma/index.ts");await O.writeFile(r,`
121
+ DATABASE_URL="your_database_url"`)}async function Vr(e){try{await g({dependencies:["@prisma/extension-accelerate"],projectDir:e});let r=L.join(e,"prisma/index.ts");await N.writeFile(r,`
136
122
  import { PrismaClient } from '@prisma/client';
137
123
  import { withAccelerate } from "@prisma/extension-accelerate";
138
124
 
139
125
  const prisma = new PrismaClient().$extends(withAccelerate());
140
126
 
141
127
  export default prisma;
142
- `.trim());let a=H.join(e,"src/db/index.ts");if(await O.pathExists(a)){let n=await O.readFile(a,"utf8");n.includes("@prisma/extension-accelerate")||(n=`import { withAccelerate } from "@prisma/extension-accelerate";
143
- ${n}`,n=n.replace("export const db = new PrismaClient();","export const db = new PrismaClient().$extends(withAccelerate());"),await O.writeFile(a,n))}return!0}catch{return M.warn(Q.yellow("Could not add Prisma Accelerate extension automatically")),!1}}async function He(e,r="npm"){let t=H.join(e,"apps/server"),a=Pe();a.start("Setting up Prisma PostgreSQL");try{await O.ensureDir(t),a.stop("Starting Prisma setup");let n=await Lr(t,r);if(n)await ye(e,n),await Nr(t),M.success(Q.green("Prisma PostgreSQL database configured successfully!"));else{let s=Pe();s.start("Setting up fallback configuration"),await ye(e),s.stop("Manual setup required"),Qe()}}catch(n){a.stop(Q.red("Prisma PostgreSQL setup failed")),M.error(Q.red(`Error during Prisma PostgreSQL setup: ${n instanceof Error?n.message:String(n)}`));try{await ye(e),Qe()}catch{}M.info("Setup completed with manual configuration required.")}}import Mr from"node:os";import je from"node:path";import{cancel as ve,confirm as _r,isCancel as xe,log as _,select as zr,spinner as K,text as Ur}from"@clack/prompts";import{$ as B}from"execa";import Ke from"fs-extra";import D from"picocolors";async function qr(){return oe("turso")}async function Vr(){try{return!(await B`turso auth whoami`).stdout.includes("You are not logged in")}catch{return!1}}async function Wr(){let e=K();try{return e.start("Logging in to Turso..."),await B`turso auth login`,e.stop("Logged in to Turso successfully!"),!0}catch(r){throw e.stop(D.red("Failed to log in to Turso")),r}}async function Gr(e){let r=K();try{if(r.start("Installing Turso CLI..."),e)await B`brew install tursodatabase/tap/turso`;else{let{stdout:t}=await B`curl -sSfL https://get.tur.so/install.sh`;await B`bash -c '${t}'`}return r.stop("Turso CLI installed successfully!"),!0}catch(t){throw t instanceof Error&&t.message.includes("User force closed")?(r.stop("Turso CLI installation cancelled"),_.warn(D.yellow("Turso CLI installation cancelled by user")),new Error("Installation cancelled")):(r.stop(D.red("Failed to install Turso CLI")),t)}}async function Jr(){let e=K();try{e.start("Fetching Turso groups...");let{stdout:r}=await B`turso group list`,t=r.trim().split(`
144
- `);if(t.length<=1)return e.stop("No Turso groups found"),[];let a=t.slice(1).map(n=>{let[s,o,i,l]=n.trim().split(/\s{2,}/);return{name:s,locations:o,version:i,status:l}});return e.stop(`Found ${a.length} Turso groups`),a}catch(r){return e.stop(D.red("Error fetching Turso groups")),console.error("Error fetching Turso groups:",r),[]}}async function Qr(){let e=await Jr();if(e.length===0)return null;if(e.length===1)return _.info(`Using the only available group: ${D.blue(e[0].name)}`),e[0].name;let r=e.map(a=>({value:a.name,label:`${a.name} (${a.locations})`})),t=await zr({message:"Select a Turso database group:",options:r});return xe(t)&&(ve(D.red("Operation cancelled")),process.exit(0)),t}async function Hr(e,r){let t=K();try{t.start(`Creating Turso database "${e}"${r?` in group "${r}"`:""}...`),r?await B`turso db create ${e} --group ${r}`:await B`turso db create ${e}`,t.stop(`Created database "${e}"`)}catch(a){throw t.stop(D.red(`Failed to create database "${e}"`)),a instanceof Error&&a.message.includes("already exists")?new Error("DATABASE_EXISTS"):a}t.start("Retrieving database connection details...");try{let{stdout:a}=await B`turso db show ${e} --url`,{stdout:n}=await B`turso db tokens create ${e}`;return t.stop("Retrieved database connection details"),{dbUrl:a.trim(),authToken:n.trim()}}catch(a){throw t.stop(D.red("Failed to retrieve database connection details")),a}}async function X(e,r){let t=je.join(e,"apps/server",".env"),a=r?`DATABASE_URL="${r.dbUrl}"
128
+ `.trim());let a=L.join(e,"src/db/index.ts");if(await N.pathExists(a)){let n=await N.readFile(a,"utf8");n.includes("@prisma/extension-accelerate")||(n=`import { withAccelerate } from "@prisma/extension-accelerate";
129
+ ${n}`,n=n.replace("export const db = new PrismaClient();","export const db = new PrismaClient().$extends(withAccelerate());"),await N.writeFile(a,n))}return!0}catch{return Z.warn(q.yellow("Could not add Prisma Accelerate extension automatically")),!1}}async function at(e){let{projectName:r,packageManager:t}=e,a=L.resolve(process.cwd(),r),n=L.join(a,"apps/server"),o=ye();o.start("Setting up Prisma PostgreSQL");try{await N.ensureDir(n),o.stop("Starting Prisma setup");let i=await qr(n,t);if(i)await we(a,i),await Vr(n),Z.success(q.green("Prisma PostgreSQL database configured successfully!"));else{let s=ye();s.start("Setting up fallback configuration"),await we(a),s.stop("Manual setup required"),rt()}}catch(i){o.stop(q.red("Prisma PostgreSQL setup failed")),Pe.error(q.red(`Error during Prisma PostgreSQL setup: ${i instanceof Error?i.message:String(i)}`));try{await we(a),rt()}catch{}Z.info("Setup completed with manual configuration required.")}}import Gr from"node:os";import pe from"node:path";import{cancel as je,confirm as Jr,isCancel as ke,log as V,select as Qr,spinner as G,text as Hr}from"@clack/prompts";import Yr from"consola";import{$ as I}from"execa";import nt from"fs-extra";import $ from"picocolors";async function Kr(){return oe("turso")}async function Xr(){try{return!(await I`turso auth whoami`).stdout.includes("You are not logged in")}catch{return!1}}async function Zr(){let e=G();try{return e.start("Logging in to Turso..."),await I`turso auth login`,e.stop("Logged in to Turso successfully!"),!0}catch(r){throw e.stop($.red("Failed to log in to Turso")),r}}async function ea(e){let r=G();try{if(r.start("Installing Turso CLI..."),e)await I`brew install tursodatabase/tap/turso`;else{let{stdout:t}=await I`curl -sSfL https://get.tur.so/install.sh`;await I`bash -c '${t}'`}return r.stop("Turso CLI installed successfully!"),!0}catch(t){throw t instanceof Error&&t.message.includes("User force closed")?(r.stop("Turso CLI installation cancelled"),V.warn($.yellow("Turso CLI installation cancelled by user")),new Error("Installation cancelled")):(r.stop($.red("Failed to install Turso CLI")),t)}}async function ta(){let e=G();try{e.start("Fetching Turso groups...");let{stdout:r}=await I`turso group list`,t=r.trim().split(`
130
+ `);if(t.length<=1)return e.stop("No Turso groups found"),[];let a=t.slice(1).map(n=>{let[o,i,s,c]=n.trim().split(/\s{2,}/);return{name:o,locations:i,version:s,status:c}});return e.stop(`Found ${a.length} Turso groups`),a}catch(r){return e.stop($.red("Error fetching Turso groups")),console.error("Error fetching Turso groups:",r),[]}}async function ra(){let e=await ta();if(e.length===0)return null;if(e.length===1)return V.info(`Using the only available group: ${$.blue(e[0].name)}`),e[0].name;let r=e.map(a=>({value:a.name,label:`${a.name} (${a.locations})`})),t=await Qr({message:"Select a Turso database group:",options:r});return ke(t)&&(je($.red("Operation cancelled")),process.exit(0)),t}async function aa(e,r){let t=G();try{t.start(`Creating Turso database "${e}"${r?` in group "${r}"`:""}...`),r?await I`turso db create ${e} --group ${r}`:await I`turso db create ${e}`,t.stop(`Created database "${e}"`)}catch(a){throw t.stop($.red(`Failed to create database "${e}"`)),a instanceof Error&&a.message.includes("already exists")?new Error("DATABASE_EXISTS"):a}t.start("Retrieving database connection details...");try{let{stdout:a}=await I`turso db show ${e} --url`,{stdout:n}=await I`turso db tokens create ${e}`;return t.stop("Retrieved database connection details"),{dbUrl:a.trim(),authToken:n.trim()}}catch(a){throw t.stop($.red("Failed to retrieve database connection details")),a}}async function ce(e,r){let t=pe.join(e,"apps/server",".env"),a=r?`DATABASE_URL="${r.dbUrl}"
145
131
  DATABASE_AUTH_TOKEN="${r.authToken}"`:`DATABASE_URL=
146
- DATABASE_AUTH_TOKEN=`;await Ke.ensureDir(je.dirname(t)),await Ke.writeFile(t,a)}function ce(){_.info(`Manual Turso Setup Instructions:
132
+ DATABASE_AUTH_TOKEN=`;await nt.ensureDir(pe.dirname(t)),await nt.writeFile(t,a)}function ve(){V.info(`Manual Turso Setup Instructions:
147
133
 
148
134
  1. Visit https://turso.tech and create an account
149
135
  2. Create a new database from the dashboard
@@ -151,134 +137,62 @@ DATABASE_AUTH_TOKEN=`;await Ke.ensureDir(je.dirname(t)),await Ke.writeFile(t,a)}
151
137
  4. Add these credentials to the .env file in apps/server/.env
152
138
 
153
139
  DATABASE_URL=your_database_url
154
- DATABASE_AUTH_TOKEN=your_auth_token`)}async function Ye(e,r){let t=K();t.start("Setting up Turso database");try{if(!r){t.stop("Skipping Turso setup"),await X(e),_.info(D.blue("Skipping Turso setup. Setting up empty configuration.")),ce();return}let a=Mr.platform(),n=a==="darwin";if(!(a!=="win32")){t.stop(D.yellow("Turso setup not supported on Windows")),_.warn(D.yellow("Automatic Turso setup is not supported on Windows.")),await X(e),ce();return}if(t.stop("Checking Turso CLI"),!await qr()){let x=await _r({message:"Would you like to install Turso CLI?",initialValue:!0});if(xe(x)&&(ve(D.red("Operation cancelled")),process.exit(0)),!x){await X(e),ce();return}await Gr(n)}await Vr()||await Wr();let l=await Qr(),p=!1,d="",P=je.basename(e);for(;!p;){let x=await Ur({message:"Enter a name for your database:",defaultValue:P,initialValue:P,placeholder:P});xe(x)&&(ve(D.red("Operation cancelled")),process.exit(0)),d=x;try{let j=await Hr(d,l),S=K();S.start("Writing configuration to .env file"),await X(e,j),S.stop("Turso database configured successfully!"),p=!0}catch(j){if(j instanceof Error&&j.message==="DATABASE_EXISTS")_.warn(D.yellow(`Database "${D.red(d)}" already exists`)),P=`${d}-${Math.floor(Math.random()*1e3)}`;else throw j}}}catch(a){t.stop(D.red("Failed to set up Turso database")),_.error(D.red(`Error during Turso setup: ${a instanceof Error?a.message:String(a)}`)),await X(e),ce(),_.success("Setup completed with manual configuration required.")}}async function et(e,r,t,a,n,s,o,i){let l=Yr(),p=Xe.join(e,"apps/server");if(r==="none"){await Xr.remove(Xe.join(p,"src/db"));return}try{t==="prisma"?g({dependencies:["@prisma/client"],devDependencies:["prisma"],projectDir:p}):t==="drizzle"&&(r==="sqlite"?g({dependencies:["drizzle-orm","@libsql/client"],devDependencies:["drizzle-kit"],projectDir:p}):r==="postgres"?g({dependencies:["drizzle-orm","pg"],devDependencies:["drizzle-kit","@types/pg"],projectDir:p}):r==="mysql"&&g({dependencies:["drizzle-orm","mysql2"],devDependencies:["drizzle-kit"],projectDir:p})),r==="sqlite"&&n?await Ye(e,t==="drizzle"):r==="postgres"?t==="prisma"&&s?await He(e,a):i&&await Je(e,a):r==="mongodb"&&o&&await Ue(e)}catch(d){throw l.stop(Ze.red("Failed to set up database")),d instanceof Error&&Kr.error(Ze.red(d.message)),d}}import W from"node:path";import pe from"fs-extra";async function ke(e,r){await pe.ensureDir(W.dirname(e));let t="";await pe.pathExists(e)&&(t=await pe.readFile(e,"utf8"));let a=!1;for(let{key:n,value:s,condition:o}of r)if(o){let i=new RegExp(`^${n}=.*$`,"m");i.test(t)?s&&(t=t.replace(i,`${n}=${s}`),a=!0):(t+=`
155
- ${n}=${s}`,a=!0)}a&&await pe.writeFile(e,t.trim())}async function tt(e,r){let t=W.join(e,"apps/server"),a=W.join(t,".env"),n=r.frontend.includes("react-router"),s=r.frontend.includes("tanstack-router"),o=r.frontend.includes("tanstack-start"),i=r.frontend.includes("next"),l=n||s||o||i,p="http://localhost:3000";n?p="http://localhost:5173":(s||o||i)&&(p="http://localhost:3001");let d="",P=r.dbSetup==="turso"||r.dbSetup==="prisma-postgres"||r.dbSetup==="mongodb-atlas"||r.dbSetup==="neon";P||(r.database==="postgres"?d="postgresql://postgres:postgres@localhost:5432/mydb?schema=public":r.database==="mysql"?d="mysql://root:password@localhost:3306/mydb":r.database==="mongodb"?d="mongodb://localhost:27017/mydatabase":r.database==="sqlite"&&(d="file:./local.db"));let x=[{key:"CORS_ORIGIN",value:p,condition:!0},{key:"BETTER_AUTH_SECRET",value:Oe(),condition:!!r.auth},{key:"BETTER_AUTH_URL",value:"http://localhost:3000",condition:!!r.auth},{key:"DATABASE_URL",value:d,condition:r.database!=="none"&&d!==""&&!P},{key:"GOOGLE_GENERATIVE_AI_API_KEY",value:"",condition:r.examples?.includes("ai")||!1}];if(await ke(a,x),l){let j=W.join(e,"apps/web"),S="VITE_SERVER_URL";i&&(S="NEXT_PUBLIC_SERVER_URL");let k=[{key:S,value:"http://localhost:3000",condition:!0}];await ke(W.join(j,".env"),k)}if(r.frontend.includes("native")){let j=W.join(e,"apps/native"),S=[{key:"EXPO_PUBLIC_SERVER_URL",value:"http://localhost:3000",condition:!0}];await ke(W.join(j,".env"),S)}}import E from"node:path";import b from"fs-extra";async function rt(e,r,t,a,n,s=["tanstack-router"]){let o=s.includes("tanstack-router"),i=s.includes("tanstack-start"),l=s.includes("react-router"),p=o||l||i,d;o?d="web-tanstack-router":i?d="web-tanstack-start":d="web-react-router";let P=await b.pathExists(E.join(e,"apps/web"));r.includes("todo")&&p&&P?await ra(e,t,a,d):await sa(e,t),r.includes("ai")&&(n==="hono"||n==="express")&&p&&P&&await Zr(e,d)}async function Zr(e,r){let t=E.join(v,"template/examples/ai");if(await b.pathExists(t)){let a=E.join(t,`apps/${r}/src/routes/ai.tsx`),n=E.join(e,"apps/web/src/routes/ai.tsx");await b.pathExists(a)&&await b.copy(a,n,{overwrite:!0}),await ta(e,r);let s=E.join(e,"apps/web");g({dependencies:["ai"],projectDir:s});let o=E.join(e,"apps/server");g({dependencies:["ai","@ai-sdk/google"],projectDir:o}),await ea(e)}}async function ea(e){let r=E.join(e,"apps/server/src/index.ts");if(await b.pathExists(r)){let t=await b.readFile(r,"utf8"),a=t.includes("hono"),n=t.includes("express");if(a){let s=`import { streamText } from "ai";
156
- import { google } from "@ai-sdk/google";
157
- import { stream } from "hono/streaming";`,o=`
158
- // AI chat endpoint
159
- app.post("/ai", async (c) => {
160
- const body = await c.req.json();
161
- const messages = body.messages || [];
162
-
163
- const result = streamText({
164
- model: google("gemini-1.5-flash"),
165
- messages,
166
- });
167
-
168
- c.header("X-Vercel-AI-Data-Stream", "v1");
169
- c.header("Content-Type", "text/plain; charset=utf-8");
170
-
171
- return stream(c, (stream) => stream.pipe(result.toDataStream()));
172
- });`;if(t.includes("import {")){let l=t.lastIndexOf("import"),p=t.indexOf(`
173
- `,l);t=`${t.substring(0,p+1)}
174
- ${s}
175
- ${t.substring(p+1)}`}else t=`${s}
176
-
177
- ${t}`;let i=t.indexOf('app.use("/trpc"')||t.indexOf("app.use(trpc(");if(i!==-1)t=`${t.substring(0,i)}${o}
178
-
179
- ${t.substring(i)}`;else{let l=t.indexOf("export default");l!==-1?t=`${t.substring(0,l)}${o}
180
-
181
- ${t.substring(l)}`:t=`${t}
182
-
183
- ${o}`}}else if(n){let s=`import { streamText } from "ai";
184
- import { google } from "@ai-sdk/google";`,o=`
185
- // AI chat endpoint
186
- app.post("/ai", async (req, res) => {
187
- const { messages = [] } = req.body;
188
-
189
- const result = streamText({
190
- model: google("gemini-1.5-flash"),
191
- messages,
192
- });
193
-
194
- result.pipeDataStreamToResponse(res);
195
- });`;if(t.includes("import {")||t.includes("import ")){let l=t.lastIndexOf("import"),p=t.indexOf(`
196
- `,l);t=`${t.substring(0,p+1)}
197
- ${s}
198
- ${t.substring(p+1)}`}else t=`${s}
199
-
200
- ${t}`;let i=t.indexOf('app.use("/trpc"');if(i!==-1)t=`${t.substring(0,i)}${o}
201
-
202
- ${t.substring(i)}`;else{let l=t.indexOf("app.listen(");if(l!==-1){let p=t.lastIndexOf(`
203
- `,l);t=`${t.substring(0,p)}${o}
204
-
205
- ${t.substring(p)}`}else t=`${t}
206
-
207
- ${o}`}}await b.writeFile(r,t)}}async function ta(e,r){let t=E.join(e,"apps/web/src/components/header.tsx");if(await b.pathExists(t)){let a=await b.readFile(t,"utf8"),n=/const links = \[\s*([^;]*?)\s*\];/s,s=a.match(n);if(s){let o=s[1];if(!o.includes('"/ai"')){let i=`const links = [
208
- ${o}${o.trim().endsWith(",")?"":","}
209
- { to: "/ai", label: "AI Chat" },
210
- ];`;a=a.replace(n,i),await b.writeFile(t,a)}}}}async function ra(e,r,t,a){let n=E.join(v,"template/examples/todo");if(await b.pathExists(n)){let s=E.join(n,`apps/${a}/src/routes/todos.tsx`),o=E.join(e,"apps/web/src/routes/todos.tsx");if(await b.pathExists(s)&&await b.copy(s,o,{overwrite:!0}),r!=="none"){let i=E.join(n,`apps/server/src/routers/with-${r}-todo.ts`),l=E.join(e,"apps/server/src/routers/todo.ts");await b.pathExists(i)&&await b.copy(i,l,{overwrite:!0}),await aa(e)}await na(e,a)}}async function aa(e){let r=E.join(e,"apps/server/src/routers/index.ts");if(await b.pathExists(r)){let t=await b.readFile(r,"utf8");if(!t.includes("import { todoRouter }")){let a=t.lastIndexOf("import"),n=t.indexOf(`
211
-
212
- `,a);n!==-1?t=`${t.slice(0,n)}
213
- import { todoRouter } from "./todo";${t.slice(n)}`:t=`import { todoRouter } from "./todo";
214
- ${t}`;let s=t.indexOf("export const appRouter = router({");if(s!==-1){let o=t.indexOf("{",s)+1;t=`${t.slice(0,o)}
215
- todo: todoRouter,${t.slice(o)}`}await b.writeFile(r,t)}}}async function na(e,r){let t=E.join(e,"apps/web/src/components/header.tsx");if(await b.pathExists(t)){let a=await b.readFile(t,"utf8"),n=/const links = \[\s*([^;]*?)\s*\];/s,s=a.match(n);if(s){let o=s[1];if(!o.includes('"/todos"')){let i=`const links = [
216
- ${o}${o.trim().endsWith(",")?"":","}
217
- { to: "/todos", label: "Todos" },
218
- ];`;a=a.replace(n,i),await b.writeFile(t,a)}}}}async function sa(e,r){if(r==="drizzle"){let a=E.join(e,"apps/server/src/db/schema/todo.ts");await b.pathExists(a)&&await b.remove(a)}else if(r==="prisma"){let a=E.join(e,"apps/server/prisma/schema/todo.prisma");await b.pathExists(a)&&await b.remove(a)}let t=E.join(e,"apps/server/src/routers/todo.ts");await b.pathExists(t)&&await b.remove(t),await oa(e)}async function oa(e){let r=E.join(e,"apps/server/src/routers/index.ts");if(await b.pathExists(r)){let t=await b.readFile(r,"utf8");t=t.replace(/import { todoRouter } from ".\/todo";/,""),t=t.replace(/todo: todoRouter,/,""),await b.writeFile(r,t)}}import{log as at,spinner as nt}from"@clack/prompts";import{$ as st}from"execa";import le from"picocolors";async function ot({projectDir:e,packageManager:r,addons:t=[]}){let a=nt();try{a.start(`Running ${r} install...`),await st({cwd:e,stderr:"inherit"})`${r} install`,a.stop("Dependencies installed successfully"),(t.includes("biome")||t.includes("husky"))&&await ia(e,r)}catch(n){throw a.stop(le.red("Failed to install dependencies")),n instanceof Error&&at.error(le.red(`Installation error: ${n.message}`)),n}}async function ia(e,r){let t=nt();try{t.start("Running Biome format check..."),await st({cwd:e,stderr:"inherit"})`${r} biome check --write .`,t.stop("Biome check completed successfully")}catch{t.stop(le.yellow("Biome check encountered issues")),at.warn(le.yellow("Some files may need manual formatting"))}}import{note as ca}from"@clack/prompts";import w from"picocolors";function it(e,r,t,a,n,s,o,i,l){let p=t==="npm"?"npm run":t,d=`cd ${r}`,P=s?.includes("husky")||s?.includes("biome"),x=e!=="none"?ua(e,n,p,o):"",j=s?.includes("tauri")?da(p):"",S=P?la(p):"",k=i?.includes("native")?pa():"",F=s?.includes("pwa")&&i?.includes("react-router")?ma():"",R=s?.includes("starlight")?fa(p):"",J=i?.includes("tanstack-router"),ee=i?.includes("tanstack-start"),te=i?.includes("react-router"),re=J||te||ee,Ht=i?.includes("native"),Kt=re||Ht,Yt=te?"5173":"3001";ca(`${w.cyan("1.")} ${d}
219
- ${a?"":`${w.cyan("2.")} ${t} install
220
- `}${w.cyan(a?"2.":"3.")} ${p} dev
221
-
222
- ${w.bold("Your project will be available at:")}
223
- ${Kt?`${re?`${w.cyan("\u2022")} Frontend: http://localhost:${Yt}
224
- `:""}`:`${w.yellow("NOTE:")} You are creating a backend-only app (no frontend selected)
225
- `}${w.cyan("\u2022")} API: http://localhost:3000
226
- ${s?.includes("starlight")?`${w.cyan("\u2022")} Docs: http://localhost:4321
227
- `:""}${k?`
228
- ${k.trim()}`:""}${x?`
229
- ${x.trim()}`:""}${j?`
230
- ${j.trim()}`:""}${S?`
231
- ${S.trim()}`:""}${F?`
232
- ${F.trim()}`:""}${R?`
233
- ${R.trim()}`:""}
234
-
235
- ${w.bold("Like Better-T Stack?")} Please consider giving us a star on GitHub:
236
- ${w.cyan("https://github.com/AmanVarshney01/create-better-t-stack")}`,"Next steps")}function pa(){return`${w.yellow("NOTE:")} For Expo connectivity issues, update apps/native/.env
140
+ DATABASE_AUTH_TOKEN=your_auth_token`)}async function ot(e){let{projectName:r,orm:t}=e,a=pe.resolve(process.cwd(),r),n=t==="drizzle",o=G();o.start("Setting up Turso database");try{let i=Gr.platform(),s=i==="darwin",c=i==="linux";if(i==="win32"){o.stop($.yellow("Turso setup not supported on Windows")),V.warn($.yellow("Automatic Turso setup is not supported on Windows.")),await ce(a),ve();return}if(o.stop("Checking Turso CLI"),!await Kr()){let x=await Jr({message:"Would you like to install Turso CLI?",initialValue:!0});if(ke(x)&&(je($.red("Operation cancelled")),process.exit(0)),!x){await ce(a),ve();return}await ea(s)}await Xr()||await Zr();let f=await ra(),k=!1,A="",E=pe.basename(a);for(;!k;){let x=await Hr({message:"Enter a name for your database:",defaultValue:E,initialValue:E,placeholder:E});ke(x)&&(je($.red("Operation cancelled")),process.exit(0)),A=x;try{let F=await aa(A,f),Q=G();Q.start("Writing configuration to .env file"),await ce(a,F),Q.stop("Turso database configured successfully!"),k=!0}catch(F){if(F instanceof Error&&F.message==="DATABASE_EXISTS")V.warn($.yellow(`Database "${$.red(A)}" already exists`)),E=`${A}-${Math.floor(Math.random()*1e3)}`;else throw F}}}catch(i){o.stop($.red("Failed to set up Turso database")),Yr.error($.red(`Error during Turso setup: ${i instanceof Error?i.message:String(i)}`)),await ce(a),ve(),V.success("Setup completed with manual configuration required.")}}import ee from"node:path";import{cancel as na,isCancel as oa,log as Se,spinner as xe,text as sa}from"@clack/prompts";import{consola as le}from"consola";import{execa as ia}from"execa";import Ae from"fs-extra";import O from"picocolors";async function De(e,r,t){let a=xe();try{let n=R(e,r);a&&a.start(t);let o=await ia(n,{shell:!0});return a&&a.stop(t),o}catch(n){throw a&&a.stop(O.red(`Failed: ${t}`)),n}}async function ca(e){try{let t=await De(e,"neonctl projects list");return!t.stdout.includes("not authenticated")&&!t.stdout.includes("error")}catch{return!1}}async function pa(e){try{return await De(e,"neonctl auth","Authenticating with Neon..."),Se.success("Authenticated with Neon successfully!"),!0}catch(r){throw le.error(O.red("Failed to authenticate with Neon")),r}}async function la(e,r){try{let t=`neonctl projects create --name "${e}" --output json`,{stdout:a}=await De(r,t,`Creating Neon project "${e}"...`),n=JSON.parse(a);if(n.project&&n.connection_uris&&n.connection_uris.length>0){let o=n.project.id,i=n.connection_uris[0].connection_uri,s=n.connection_uris[0].connection_parameters;return{connectionString:i,projectId:o,dbName:s.database,roleName:s.role}}return le.error(O.red("Failed to extract connection information from response")),null}catch(t){throw le.error(O.red("Failed to create Neon project")),t}}async function st(e,r){let t=ee.join(e,"apps/server",".env"),a=r?`DATABASE_URL="${r.connectionString}"`:'DATABASE_URL="postgresql://postgres:postgres@localhost:5432/mydb?schema=public"';return await Ae.ensureDir(ee.dirname(t)),await Ae.writeFile(t,a),!0}function da(){Se.info(`Manual Neon PostgreSQL Setup Instructions:
141
+
142
+ 1. Visit https://neon.tech and create an account
143
+ 2. Create a new project from the dashboard
144
+ 3. Get your connection string
145
+ 4. Add the database URL to the .env file in apps/server/.env
146
+
147
+ DATABASE_URL="your_connection_string"`)}async function it(e){let{projectName:r,packageManager:t}=e,a=ee.resolve(process.cwd(),r),n=xe();n.start("Setting up Neon PostgreSQL");try{let o=await ca(t);n.stop("Setting up Neon PostgreSQL"),o||(Se.info("Please authenticate with Neon to continue:"),await pa(t));let i=ee.basename(a),s=await sa({message:"Enter a name for your Neon project:",defaultValue:i,initialValue:i});oa(s)&&(na(O.red("Operation cancelled")),process.exit(0));let c=await la(s,t);if(!c)throw new Error("Failed to create project - couldn't get connection information");let p=xe();p.start("Configuring database connection"),await Ae.ensureDir(ee.join(a,"apps/server")),await st(a,c),p.stop("Neon database configured successfully!")}catch(o){n.stop(O.red("Neon PostgreSQL setup failed")),o instanceof Error&&le.error(O.red(o.message)),await st(a),da()}}async function pt(e){let{projectName:r,database:t,orm:a,packageManager:n,dbSetup:o}=e,i=$e.resolve(process.cwd(),r),s=ua(),c=$e.join(i,"apps/server");if(t==="none"){await fa.remove($e.join(c,"src/db"));return}try{a==="prisma"?await g({dependencies:["@prisma/client"],devDependencies:["prisma"],projectDir:c}):a==="drizzle"&&(t==="sqlite"?await g({dependencies:["drizzle-orm","@libsql/client"],devDependencies:["drizzle-kit"],projectDir:c}):t==="postgres"?await g({dependencies:["drizzle-orm","pg"],devDependencies:["drizzle-kit","@types/pg"],projectDir:c}):t==="mysql"&&await g({dependencies:["drizzle-orm","mysql2"],devDependencies:["drizzle-kit"],projectDir:c})),t==="sqlite"&&o==="turso"?await ot(e):t==="postgres"?a==="prisma"&&o==="prisma-postgres"?await at(e):o==="neon"&&await it(e):t==="mongodb"&&o==="mongodb-atlas"&&await tt(e)}catch(p){throw s.stop(ct.red("Failed to set up database")),p instanceof Error&&ma.error(ct.red(p.message)),p}}import M from"node:path";import de from"fs-extra";async function Ce(e,r){await de.ensureDir(M.dirname(e));let t="";await de.pathExists(e)&&(t=await de.readFile(e,"utf8"));let a=!1;for(let{key:n,value:o,condition:i}of r)if(i){let s=new RegExp(`^${n}=.*$`,"m");s.test(t)?o&&(t=t.replace(s,`${n}=${o}`),a=!0):(t+=`
148
+ ${n}=${o}`,a=!0)}a&&await de.writeFile(e,t.trim())}async function lt(e){let{projectName:r}=e,t=M.resolve(process.cwd(),r),a=e,n=M.join(t,"apps/server"),o=M.join(n,".env"),i=a.frontend.includes("react-router"),s=a.frontend.includes("tanstack-router"),c=a.frontend.includes("tanstack-start"),p=a.frontend.includes("next"),w=i||s||c||p,y="http://localhost:3000";i?y="http://localhost:5173":(s||c||p)&&(y="http://localhost:3001");let f="",k=a.dbSetup==="turso"||a.dbSetup==="prisma-postgres"||a.dbSetup==="mongodb-atlas"||a.dbSetup==="neon";k||(a.database==="postgres"?f="postgresql://postgres:postgres@localhost:5432/mydb?schema=public":a.database==="mysql"?f="mysql://root:password@localhost:3306/mydb":a.database==="mongodb"?f="mongodb://localhost:27017/mydatabase":a.database==="sqlite"&&(f="file:./local.db"));let A=[{key:"CORS_ORIGIN",value:y,condition:!0},{key:"BETTER_AUTH_SECRET",value:Je(),condition:!!a.auth},{key:"BETTER_AUTH_URL",value:"http://localhost:3000",condition:!!a.auth},{key:"DATABASE_URL",value:f,condition:a.database!=="none"&&f!==""&&!k},{key:"GOOGLE_GENERATIVE_AI_API_KEY",value:"",condition:a.examples?.includes("ai")||!1}];if(await Ce(o,A),w){let E=M.join(t,"apps/web"),x="VITE_SERVER_URL";p&&(x="NEXT_PUBLIC_SERVER_URL");let F=[{key:x,value:"http://localhost:3000",condition:!0}];await Ce(M.join(E,".env"),F)}if(a.frontend.includes("native")){let E=M.join(t,"apps/native"),x=[{key:"EXPO_PUBLIC_SERVER_URL",value:"http://localhost:3000",condition:!0}];await Ce(M.join(E,".env"),x)}}import Ee from"node:path";async function dt(e){let{projectName:r,examples:t,orm:a,auth:n,backend:o,frontend:i=["tanstack-router"]}=e,s=Ee.resolve(process.cwd(),r);if(t.includes("ai")){let c=Ee.join(s,"apps/web");await g({dependencies:["ai"],projectDir:c});let p=Ee.join(s,"apps/server");await g({dependencies:["ai","@ai-sdk/google"],projectDir:p})}}import{log as ga,spinner as ut}from"@clack/prompts";import ha from"consola";import{$ as mt}from"execa";import ue from"picocolors";async function ft({projectDir:e,packageManager:r,addons:t=[]}){let a=ut();try{a.start(`Running ${r} install...`),await mt({cwd:e,stderr:"inherit"})`${r} install`,a.stop("Dependencies installed successfully"),(t.includes("biome")||t.includes("husky"))&&await ba(e,r)}catch(n){throw a.stop(ue.red("Failed to install dependencies")),n instanceof Error&&ha.error(ue.red(`Installation error: ${n.message}`)),n}}async function ba(e,r){let t=ut();try{t.start("Running Biome format check..."),await mt({cwd:e,stderr:"inherit"})`${r} biome check --write .`,t.stop("Biome check completed successfully")}catch{t.stop(ue.yellow("Biome check encountered issues")),ga.warn(ue.yellow("Some files may need manual formatting"))}}import{consola as wa}from"consola";import b from"picocolors";function gt(e){let{database:r,projectName:t,packageManager:a,depsInstalled:n,orm:o,addons:i,runtime:s,frontend:c,dbSetup:p}=e,w=a==="npm"?"npm run":a,y=`cd ${t}`,f=i?.includes("husky")||i?.includes("biome"),k=r!=="none"?va(r,o,w,s):"",A=i?.includes("tauri")?ja(w):"",E=f?Pa(w):"",x=c?.includes("native")?ya():"",F=i?.includes("pwa")&&c?.includes("react-router")?ka():"",Q=i?.includes("starlight")?xa(w):"",ir=c?.includes("tanstack-router"),cr=c?.includes("tanstack-start"),Be=c?.includes("react-router"),Ne=ir||Be||cr,pr=c?.includes("native"),lr=Ne||pr,dr=Be?"5173":"3001",ur=R(a,"taze -r");wa.box(`${b.bold("Next steps")}
149
+ ${b.cyan("1.")} ${y}
150
+ ${n?"":`${b.cyan("2.")} ${a} install
151
+ `}${b.cyan(n?"2.":"3.")} ${w} dev
152
+
153
+ ${b.bold("Your project will be available at:")}
154
+ ${lr?`${Ne?`${b.cyan("\u2022")} Frontend: http://localhost:${dr}
155
+ `:""}`:`${b.yellow("NOTE:")} You are creating a backend-only app (no frontend selected)
156
+ `}${b.cyan("\u2022")} Backend: http://localhost:3000
157
+ ${i?.includes("starlight")?`${b.cyan("\u2022")} Docs: http://localhost:4321
158
+ `:""}${x?`
159
+ ${x.trim()}`:""}${k?`
160
+ ${k.trim()}`:""}${A?`
161
+ ${A.trim()}`:""}${E?`
162
+ ${E.trim()}`:""}${F?`
163
+ ${F.trim()}`:""}${Q?`
164
+ ${Q.trim()}`:""}
165
+
166
+ ${b.bold(`Update all dependencies:
167
+ `)}${b.cyan(ur)}
168
+
169
+ ${b.bold("Like Better-T Stack?")} Please consider giving us a star on GitHub:
170
+ ${b.cyan("https://github.com/AmanVarshney01/create-better-t-stack")}`)}function ya(){return`${b.yellow("NOTE:")} For Expo connectivity issues, update apps/native/.env
237
171
  with your local IP:
238
172
  EXPO_PUBLIC_SERVER_URL=http://192.168.0.103:3000
239
- `}function la(e){return`${w.bold("Linting and formatting:")}
240
- ${w.cyan("\u2022")} Format and lint fix: ${`${e} check`}
173
+ `}function Pa(e){return`${b.bold("Linting and formatting:")}
174
+ ${b.cyan("\u2022")} Format and lint fix: ${`${e} check`}
241
175
 
242
- `}function ua(e,r,t,a){let n=[];return r==="prisma"?(e==="sqlite"&&n.push(`${w.yellow("NOTE:")} Turso support with Prisma is in Early Access and requires additional setup.`,"Learn more at: https://www.prisma.io/docs/orm/overview/databases/turso"),a==="bun"&&n.push(`${w.yellow("NOTE:")} Prisma with Bun may require additional configuration. If you encounter errors,
243
- follow the guidance provided in the error messages`),n.push(`${w.cyan("\u2022")} Apply schema: ${`${t} db:push`}`),n.push(`${w.cyan("\u2022")} Database UI: ${`${t} db:studio`}`)):r==="drizzle"&&(n.push(`${w.cyan("\u2022")} Apply schema: ${`${t} db:push`}`),n.push(`${w.cyan("\u2022")} Database UI: ${`${t} db:studio`}`)),n.length?`${w.bold("Database commands:")}
176
+ `}function va(e,r,t,a){let n=[];return r==="prisma"?(e==="sqlite"&&n.push(`${b.yellow("NOTE:")} Turso support with Prisma is in Early Access and requires additional setup.`,"Learn more at: https://www.prisma.io/docs/orm/overview/databases/turso"),a==="bun"&&n.push(`${b.yellow("NOTE:")} Prisma with Bun may require additional configuration. If you encounter errors,
177
+ follow the guidance provided in the error messages`),n.push(`${b.cyan("\u2022")} Apply schema: ${`${t} db:push`}`),n.push(`${b.cyan("\u2022")} Database UI: ${`${t} db:studio`}`)):r==="drizzle"&&(n.push(`${b.cyan("\u2022")} Apply schema: ${`${t} db:push`}`),n.push(`${b.cyan("\u2022")} Database UI: ${`${t} db:studio`}`)),n.length?`${b.bold("Database commands:")}
244
178
  ${n.join(`
245
179
  `)}
246
180
 
247
- `:""}function da(e){return`
248
- ${w.bold("Desktop app with Tauri:")}
249
- ${w.cyan("\u2022")} Start desktop app: ${`cd apps/web && ${e} desktop:dev`}
250
- ${w.cyan("\u2022")} Build desktop app: ${`cd apps/web && ${e} desktop:build`}
251
- ${w.yellow("NOTE:")} Tauri requires Rust and platform-specific dependencies.
181
+ `:""}function ja(e){return`
182
+ ${b.bold("Desktop app with Tauri:")}
183
+ ${b.cyan("\u2022")} Start desktop app: ${`cd apps/web && ${e} desktop:dev`}
184
+ ${b.cyan("\u2022")} Build desktop app: ${`cd apps/web && ${e} desktop:build`}
185
+ ${b.yellow("NOTE:")} Tauri requires Rust and platform-specific dependencies.
252
186
  See: https://v2.tauri.app/start/prerequisites/
253
187
 
254
- `}function ma(){return`${w.bold("PWA with React Router v7:")}
255
- ${w.yellow("NOTE:")} There is a known compatibility issue between VitePWA and React Router v7.
188
+ `}function ka(){return`${b.bold("PWA with React Router v7:")}
189
+ ${b.yellow("NOTE:")} There is a known compatibility issue between VitePWA and React Router v7.
256
190
  See: https://github.com/vite-pwa/vite-plugin-pwa/issues/809
257
- `}function fa(e){return`${w.bold("Documentation with Starlight:")}
258
- ${w.cyan("\u2022")} Start docs site: ${`cd apps/docs && ${e} dev`}
259
- ${w.cyan("\u2022")} Build docs site: ${`cd apps/docs && ${e} build`}
260
- `}import ue from"node:path";import{log as ha}from"@clack/prompts";import{$ as ct,execa as ga}from"execa";import z from"fs-extra";import ba from"picocolors";async function pt(e,r){await wa(e,r),await ya(e,r)}async function wa(e,r){let t=ue.join(e,"package.json");if(await z.pathExists(t)){let a=await z.readJson(t);a.name=r.projectName;let{stdout:n}=await ga(r.packageManager,["-v"],{cwd:e});if(a.packageManager=`${r.packageManager}@${n.trim()}`,await z.writeJson(t,a,{spaces:2}),r.packageManager==="pnpm"){let s=ue.join(v,"template/with-pnpm/pnpm-workspace.yaml"),o=ue.join(e,"pnpm-workspace.yaml");await z.pathExists(s)&&await z.copy(s,o)}}}async function ya(e,r){let t=ue.join(e,"apps/server/package.json");if(await z.pathExists(t)){let a=await z.readJson(t);r.database!=="none"&&(r.database==="sqlite"&&(a.scripts["db:local"]="turso dev --db-file local.db"),r.orm==="prisma"?(a.scripts["db:push"]="prisma db push --schema ./prisma/schema",a.scripts["db:studio"]="prisma studio"):r.orm==="drizzle"&&(a.scripts["db:push"]="drizzle-kit push",a.scripts["db:studio"]="drizzle-kit studio")),await z.writeJson(t,a,{spaces:2})}}async function lt(e,r){if(!r)return;if((await ct({cwd:e,reject:!1,stderr:"pipe"})`git --version`).exitCode!==0){ha.warn(ba.yellow("Git is not installed"));return}let a=await ct({cwd:e,reject:!1,stderr:"pipe"})`git init`;if(a.exitCode!==0)throw new Error(`Git initialization failed: ${a.stderr}`)}import de from"node:path";import U from"fs-extra";async function ut(e,r,t){if(t==="next")return;let a=de.join(e,"apps/server"),n=de.join(a,"src/index.ts"),s=await U.readFile(n,"utf-8");r==="bun"?await Pa(a,n,s,t):r==="node"&&await ja(a,n,s,t)}async function Pa(e,r,t,a){let n=de.join(e,"package.json"),s=await U.readJson(n);if(s.scripts={...s.scripts,dev:"bun run --hot src/index.ts",start:"bun run dist/src/index.js"},await U.writeJson(n,s,{spaces:2}),g({devDependencies:["@types/bun"],projectDir:e}),a==="hono"){let o=`${t}
261
-
262
- export default app;
263
- `;await U.writeFile(r,o)}}async function ja(e,r,t,a){let n=de.join(e,"package.json"),s=await U.readJson(n);if(s.scripts={...s.scripts,dev:"tsx watch src/index.ts",start:"node dist/src/index.js"},await U.writeJson(n,s,{spaces:2}),g({devDependencies:["tsx","@types/node"],projectDir:e}),a==="hono"){g({dependencies:["@hono/node-server"],projectDir:e});let o=`import { serve } from "@hono/node-server";
264
- `,i=`
265
- serve(
266
- {
267
- fetch: app.fetch,
268
- port: 3000,
269
- },
270
- (info) => {
271
- console.log(\`Server is running on http://localhost:\${info.port}\`);
272
- },
273
- );
274
- `;if(!t.includes("@hono/node-server")){let l=t.lastIndexOf("import"),p=t.substring(0,l),d=t.substring(l),P=p+o+d+i;await U.writeFile(r,P)}}else if(a==="elysia"&&(g({dependencies:["@elysiajs/node"],projectDir:e}),!t.includes("@elysiajs/node"))){let o=`import { node } from "@elysiajs/node";
275
- `,i=t.indexOf(`
276
- `,t.indexOf("import")),l=t.substring(0,i+1),p=t.substring(i+1),d=l+o+p;d=d.replace(/const app = new Elysia\([^)]*\)/,"const app = new Elysia({ adapter: node() })"),await U.writeFile(r,d)}}import u from"node:path";import c from"fs-extra";async function mt(e){let r=u.join(v,"template/base");if(!await c.pathExists(r))throw new Error(`Template directory not found: ${r}`);await c.ensureDir(e);let t=await c.readdir(r);for(let s of t){let o=u.join(r,s),i=u.join(e,s);s!=="apps"&&(await c.stat(o).then(l=>l.isDirectory())?await c.copy(o,i):await c.copy(o,i))}await c.ensureDir(u.join(e,"apps"));let a=u.join(r,"apps/server"),n=u.join(e,"apps/server");await c.pathExists(a)&&await c.copy(a,n)}async function ft(e,r){let t=r.includes("tanstack-router"),a=r.includes("tanstack-start"),n=r.includes("react-router"),s=r.includes("next"),o=r.includes("native");if(t||n||a||s){let i=u.join(e,"apps/web");await c.ensureDir(i);let l=u.join(v,"template/base/apps/web-base");if(await c.pathExists(l)&&await c.copy(l,i),t){let d=u.join(v,"template/base/apps/web-tanstack-router");await c.pathExists(d)&&await c.copy(d,i,{overwrite:!0})}else if(a){let d=u.join(v,"template/base/apps/web-tanstack-start");await c.pathExists(d)&&await c.copy(d,i,{overwrite:!0})}else if(n){let d=u.join(v,"template/base/apps/web-react-router");await c.pathExists(d)&&await c.copy(d,i,{overwrite:!0})}else if(s){let d=u.join(v,"template/base/apps/web-next");await c.pathExists(d)&&await c.copy(d,i,{overwrite:!0})}let p=u.join(i,"package.json");if(await c.pathExists(p)){let d=await c.readJson(p);d.name="web",await c.writeJson(p,d,{spaces:2})}}if(o){let i=u.join(v,"template/base/apps/native"),l=u.join(e,"apps/native");await c.pathExists(i)&&await c.copy(i,l),await c.writeFile(u.join(e,".npmrc"),`node-linker=hoisted
277
- `)}}async function ht(e,r){if(r==="next"){let a=u.join(e,"apps/server"),n=u.join(v,"template/with-next/apps/server");if(await c.ensureDir(a),await c.pathExists(n)){await c.copy(n,a,{overwrite:!0});let s=u.join(a,"package.json");if(await c.pathExists(s)){let o=await c.readJson(s);o.name="server",await c.writeJson(s,o,{spaces:2})}}return}let t=u.join(v,`template/with-${r}`);await c.pathExists(t)&&await c.copy(t,e,{overwrite:!0})}async function gt(e,r,t,a){if(r==="none"||t==="none")return;let n=u.join(v,xa(r,t));if(await c.pathExists(n)&&(await c.copy(n,e,{overwrite:!0}),!a)){if(r==="prisma"){let s=u.join(e,"apps/server/prisma/schema/auth.prisma");await c.pathExists(s)&&await c.remove(s)}else if(r==="drizzle"){let s=u.join(e,"apps/server/src/db/schema/auth.ts");await c.pathExists(s)&&await c.remove(s)}}}async function bt(e,r,t,a,n,s){if(!r)return;let o=u.join(v,"template/with-auth");if(await c.pathExists(o)){let i=s.includes("react-router"),l=s.includes("tanstack-router"),p=s.includes("tanstack-start"),d=s.includes("next");if(i||l||p||d){let j=u.join(e,"apps/web"),S=u.join(o,"apps/web-base");if(await c.pathExists(S)&&await c.copy(S,j,{overwrite:!0}),i){let k=u.join(o,"apps/web-react-router");await c.pathExists(k)&&await c.copy(k,j,{overwrite:!0})}if(l){let k=u.join(o,"apps/web-tanstack-router");await c.pathExists(k)&&await c.copy(k,j,{overwrite:!0})}if(p){let k=u.join(o,"apps/web-tanstack-start");await c.pathExists(k)&&await c.copy(k,j,{overwrite:!0})}if(d){let k=u.join(o,"apps/web-next");await c.pathExists(k)&&await c.copy(k,j,{overwrite:!0})}}let P=u.join(o,"apps/server/src"),x=u.join(e,"apps/server/src");if(await c.copy(u.join(P,"lib/trpc.ts"),u.join(x,"lib/trpc.ts"),{overwrite:!0}),await c.copy(u.join(P,"routers/index.ts"),u.join(x,"routers/index.ts"),{overwrite:!0}),t==="next"){if(await c.pathExists(u.join(o,"apps/server/src/with-next-app"))){let F=u.join(o,"apps/server/src/with-next-app"),R=u.join(e,"apps/server/src/app");await c.ensureDir(R);let J=await c.readdir(F);for(let ee of J){let te=u.join(F,ee),re=u.join(R,ee);await c.copy(te,re,{overwrite:!0})}}await c.copy(u.join(P,"lib","with-next-context.ts"),u.join(x,"lib/context.ts"),{overwrite:!0});let S=dt(a,n),k=u.join(P,S);if(await c.pathExists(k)){let F=await c.readdir(k);for(let R of F)await c.copy(u.join(k,R),u.join(x,"lib",R),{overwrite:!0})}}else{let j=`with-${t}-context.ts`;await c.copy(u.join(P,"lib",j),u.join(x,"lib/context.ts"),{overwrite:!0});let S=`with-${t}-index.ts`;await c.copy(u.join(P,S),u.join(x,"index.ts"),{overwrite:!0});let k=dt(a,n),F=u.join(P,k);if(await c.pathExists(F)){let R=await c.readdir(F);for(let J of R)await c.copy(u.join(F,J),u.join(x,"lib",J),{overwrite:!0})}}if(s.includes("native")){let j=u.join(o,"apps/native"),S=u.join(e,"apps/native");await c.pathExists(j)&&await c.copy(j,S,{overwrite:!0}),g({dependencies:["@better-auth/expo"],projectDir:u.join(e,"apps/server")}),await va(e,a,n)}}}async function va(e,r,t){let a=u.join(e,"apps/server"),n;if(r==="drizzle"?t==="sqlite"?n=u.join(a,"src/lib/auth.ts"):t==="postgres"&&(n=u.join(a,"src/lib/auth.ts")):r==="prisma"&&(t==="sqlite"?n=u.join(a,"src/lib/auth.ts"):t==="postgres"&&(n=u.join(a,"src/lib/auth.ts"))),n&&await c.pathExists(n)){let s=await c.readFile(n,"utf8");if(!s.includes("@better-auth/expo")){let o=`import { expo } from "@better-auth/expo";
278
- `,i=s.lastIndexOf("import"),l=s.indexOf(`
279
- `,i)+1;s=s.substring(0,l)+o+s.substring(l)}s.includes("plugins:")?s.includes("expo()")||(s=s.replace(/plugins: \[(.*?)\]/s,(o,i)=>`plugins: [${i}${i.trim()?", ":""}expo()]`)):s=s.replace(/}\);/,` plugins: [expo()],
280
- });`),s.includes("my-better-t-app://")||(s=s.replace(/trustedOrigins: \[(.*?)\]/s,(o,i)=>`trustedOrigins: [${i}${i.trim()?", ":""}"my-better-t-app://"]`)),await c.writeFile(n,s)}}async function wt(e){let r=await yt(e);for(let t of r)if(await c.pathExists(t)){let a=u.join(u.dirname(t),".gitignore");await c.move(t,a,{overwrite:!0})}}async function yt(e){let r=[],t=u.join(e,"_gitignore");await c.pathExists(t)&&r.push(t);try{let a=await c.readdir(e,{withFileTypes:!0});for(let n of a)if(n.isDirectory()&&n.name!=="node_modules"){let s=u.join(e,n.name),o=await yt(s);r.push(...o)}}catch{}return r}function xa(e,r){if(e==="drizzle"){if(r==="sqlite")return"template/with-drizzle-sqlite";if(r==="postgres")return"template/with-drizzle-postgres";if(r==="mysql")return"template/with-drizzle-mysql"}if(e==="prisma"){if(r==="sqlite")return"template/with-prisma-sqlite";if(r==="postgres")return"template/with-prisma-postgres";if(r==="mysql")return"template/with-prisma-mysql";if(r==="mongodb")return"template/with-prisma-mongodb"}return"template/base"}function dt(e,r){if(e==="drizzle"){if(r==="sqlite")return"with-drizzle-sqlite-lib";if(r==="postgres")return"with-drizzle-postgres-lib";if(r==="mysql")return"with-drizzle-mysql-lib"}if(e==="prisma"){if(r==="sqlite")return"with-prisma-sqlite-lib";if(r==="postgres")return"with-prisma-postgres-lib";if(r==="mysql")return"with-prisma-mysql-lib";if(r==="mongodb")return"with-prisma-mongodb-lib"}throw new Error("Invalid ORM or database configuration for auth setup")}async function jt(e){let r=Sa(),t=ka.resolve(process.cwd(),e.projectName);try{return await Aa.ensureDir(t),await mt(t),await ft(t,e.frontend),await wt(t),await ht(t,e.backend),await Le(t,e.backend,e.runtime),await gt(t,e.orm,e.database,e.auth),await et(t,e.database,e.orm,e.packageManager,e.dbSetup==="turso",e.dbSetup==="prisma-postgres",e.dbSetup==="mongodb-atlas",e.dbSetup==="neon"),await bt(t,e.auth,e.backend,e.orm,e.database,e.frontend),await Be(t,e.auth,e.frontend),await ut(t,e.runtime,e.backend),await rt(t,e.examples,e.orm,e.auth,e.backend,e.frontend),await tt(t,e),await lt(t,e.git),e.addons.length>0&&await Fe(t,e.addons,e.packageManager,e.frontend),await pt(t,e),await Ne(t,e),e.noInstall||await ot({projectDir:t,packageManager:e.packageManager,addons:e.addons}),it(e.database,e.projectName,e.packageManager,!e.noInstall,e.orm,e.addons,e.runtime,e.frontend),t}catch(a){throw r.message(Pt.red("Failed")),a instanceof Error&&($a(Pt.red(`Error during project creation: ${a.message}`)),process.exit(1)),a}}import{cancel as Sn,group as An}from"@clack/prompts";import En from"picocolors";import{cancel as Ea,isCancel as Da,multiselect as Ta}from"@clack/prompts";import Ca from"picocolors";async function vt(e,r){if(e!==void 0)return e;let t=r?.includes("react-router")||r?.includes("tanstack-router"),a=[{value:"starlight",label:"Starlight",hint:"Add Astro Starlight documentation site"},{value:"biome",label:"Biome",hint:"Add Biome for linting and formatting"},{value:"husky",label:"Husky",hint:"Add Git hooks with Husky, lint-staged (requires Biome)"}],s=t?[...[{value:"pwa",label:"PWA (Progressive Web App)",hint:"Make your app installable and work offline"},{value:"tauri",label:"Tauri Desktop App",hint:"Build native desktop apps from your web frontend"}],...a]:a,o=h.addons.filter(l=>t||l!=="pwa"&&l!=="tauri"),i=await Ta({message:"Select addons",options:s,initialValues:o,required:!1});return Da(i)&&(Ea(Ca.red("Operation cancelled")),process.exit(0)),i.includes("husky")&&!i.includes("biome")&&i.push("biome"),i}import{cancel as Fa,confirm as Ra,isCancel as Ia}from"@clack/prompts";import Oa from"picocolors";async function xt(e,r,t){if(!r)return!1;if(e!==void 0)return e;let a=await Ra({message:"Add authentication with Better-Auth?",initialValue:h.auth});return Ia(a)&&(Fa(Oa.red("Operation cancelled")),process.exit(0)),a}import{cancel as Ba,isCancel as La,select as Na}from"@clack/prompts";import Ma from"picocolors";async function kt(e){if(e!==void 0)return e;let r=await Na({message:"Select backend framework",options:[{value:"hono",label:"Hono",hint:"Lightweight, ultrafast web framework"},{value:"next",label:"Next.js",hint:"Full-stack framework with API routes"},{value:"express",label:"Express",hint:"Fast, unopinionated, minimalist web framework for Node.js"},{value:"elysia",label:"Elysia",hint:"Ergonomic web framework for building backend servers"}],initialValue:h.backend});return La(r)&&(Ba(Ma.red("Operation cancelled")),process.exit(0)),r}import{cancel as _a,isCancel as za,select as Ua}from"@clack/prompts";import qa from"picocolors";async function $t(e){if(e!==void 0)return e;let r=await Ua({message:"Select database",options:[{value:"none",label:"None",hint:"No database setup"},{value:"sqlite",label:"SQLite",hint:"lightweight, server-less, embedded relational database management system"},{value:"postgres",label:"PostgreSQL",hint:"powerful, open source object-relational database system"},{value:"mysql",label:"MySQL",hint:"popular open-source relational database system"},{value:"mongodb",label:"MongoDB",hint:"open-source NoSQL database that stores data in JSON-like documents called BSON"}],initialValue:h.database});return za(r)&&(_a(qa.red("Operation cancelled")),process.exit(0)),r}import{cancel as Va,isCancel as Wa,select as Ga}from"@clack/prompts";import Ja from"picocolors";async function St(e,r,t){if(r!==void 0)return r;if(e==="sqlite"&&t==="prisma")return"none";let a=[];if(e==="sqlite")a=[{value:"turso",label:"Turso",hint:"SQLite for Production. Powered by libSQL"},{value:"none",label:"None",hint:"Manual setup"}];else if(e==="postgres")a=[{value:"neon",label:"Neon Postgres",hint:"Serverless Postgres with branching capability"},...t==="prisma"?[{value:"prisma-postgres",label:"Prisma Postgres",hint:"Instant Postgres for Global Applications"}]:[],{value:"none",label:"None",hint:"Manual setup"}];else if(e==="mongodb")a=[{value:"mongodb-atlas",label:"MongoDB Atlas",hint:"The most effective way to deploy MongoDB"},{value:"none",label:"None",hint:"Manual setup"}];else return"none";let n=await Ga({message:`Select ${e} setup option`,options:a,initialValue:"none"});return Wa(n)&&(Va(Ja.red("Operation cancelled")),process.exit(0)),n}import{cancel as Qa,isCancel as Ha,multiselect as At}from"@clack/prompts";import Ka from"picocolors";async function Et(e,r,t,a){if(e!==void 0)return e;if(r==="none")return[];if(!(t?.includes("react-router")||t?.includes("tanstack-router")||t?.includes("tanstack-start")))return[];let s=[];return a==="elysia"&&(s=await At({message:"Include examples",options:[{value:"todo",label:"Todo App",hint:"A simple CRUD example app"}],required:!1,initialValues:h.examples})),(a==="hono"||a==="express")&&(s=await At({message:"Include examples",options:[{value:"todo",label:"Todo App",hint:"A simple CRUD example app"},{value:"ai",label:"AI Chat",hint:"A simple AI chat interface using AI SDK"}],required:!1,initialValues:h.examples})),Ha(s)&&(Qa(Ka.red("Operation cancelled")),process.exit(0)),s}import{cancel as Dt,isCancel as Tt,multiselect as Ya,select as Xa}from"@clack/prompts";import Ct from"picocolors";async function Ft(e){if(e!==void 0)return e;let r=await Ya({message:"Select platforms to develop for",options:[{value:"web",label:"Web",hint:"React Web Application"},{value:"native",label:"Native",hint:"Create a React Native/Expo app"}],required:!1,initialValues:h.frontend.some(a=>a==="tanstack-router"||a==="react-router"||a==="tanstack-start"||a==="next")?["web"]:[]});Tt(r)&&(Dt(Ct.red("Operation cancelled")),process.exit(0));let t=[];if(r.includes("web")){let a=await Xa({message:"Choose frontend framework",options:[{value:"tanstack-router",label:"TanStack Router",hint:"Modern and scalable routing for React Applications"},{value:"react-router",label:"React Router",hint:"A user\u2011obsessed, standards\u2011focused, multi\u2011strategy router"},{value:"next",label:"Next.js",hint:"The React Framework for the Web"},{value:"tanstack-start",label:"TanStack Start (beta)",hint:"SSR, Server Functions, API Routes and more with TanStack Router"}],initialValue:h.frontend.find(n=>n==="tanstack-router"||n==="react-router"||n==="tanstack-start"||n==="next")||"tanstack-router"});Tt(a)&&(Dt(Ct.red("Operation cancelled")),process.exit(0)),t.push(a)}return r.includes("native")&&t.push("native"),t}import{cancel as Za,confirm as en,isCancel as tn}from"@clack/prompts";import rn from"picocolors";async function Rt(e){if(e!==void 0)return e;let r=await en({message:"Initialize git repository?",initialValue:h.git});return tn(r)&&(Za(rn.red("Operation cancelled")),process.exit(0)),r}import{cancel as an,confirm as nn,isCancel as sn}from"@clack/prompts";import on from"picocolors";async function It(e){if(e!==void 0)return e;let r=await nn({message:"Install dependencies?",initialValue:!h.noInstall});return sn(r)&&(an(on.red("Operation cancelled")),process.exit(0)),!r}import{cancel as cn,isCancel as pn,log as ln,select as un}from"@clack/prompts";import dn from"picocolors";async function Ot(e,r,t){if(!r)return"none";if(e!==void 0)return e;if(t==="mongodb")return ln.info("Only Prisma is supported with MongoDB."),"prisma";let a=await un({message:"Select ORM",options:[{value:"drizzle",label:"Drizzle",hint:"lightweight and performant TypeScript ORM"},{value:"prisma",label:"Prisma",hint:"Powerful, feature-rich ORM"}],initialValue:h.orm});return pn(a)&&(cn(dn.red("Operation cancelled")),process.exit(0)),a}import{cancel as mn,isCancel as fn,select as hn}from"@clack/prompts";import gn from"picocolors";async function Bt(e){if(e!==void 0)return e;let r=ae(),t=await hn({message:"Choose package manager",options:[{value:"npm",label:"npm",hint:"Node Package Manager"},{value:"pnpm",label:"pnpm",hint:"Fast, disk space efficient package manager"},{value:"bun",label:"bun",hint:"All-in-one JavaScript runtime & toolkit"}],initialValue:r});return fn(t)&&(mn(gn.red("Operation cancelled")),process.exit(0)),t}import Z from"node:path";import{cancel as bn,isCancel as wn,text as yn}from"@clack/prompts";import G from"fs-extra";import Pn from"picocolors";var jn=["<",">",":",'"',"|","?","*"],Lt=255;function Nt(e){if(e!=="."){if(!e)return"Project name cannot be empty";if(e.length>Lt)return`Project name must be less than ${Lt} characters`;if(jn.some(r=>e.includes(r)))return"Project name contains invalid characters";if(e.startsWith(".")||e.startsWith("-"))return"Project name cannot start with a dot or dash";if(e.toLowerCase()==="node_modules")return"Project name is reserved"}}async function Mt(e){if(e)if(e==="."){let s=process.cwd();if(G.readdirSync(s).length===0)return e}else{let s=Z.basename(e);if(!Nt(s)){let i=Z.resolve(process.cwd(),e);if(!G.pathExistsSync(i)||G.readdirSync(i).length===0)return e}}let r=!1,t="",a=h.projectName,n=1;for(;G.pathExistsSync(Z.resolve(process.cwd(),a));)a=`${h.projectName}-${n}`,n++;for(;!r;){let s=await yn({message:"Enter your project name or path (relative to current directory)",placeholder:a,initialValue:e,defaultValue:a,validate:o=>{let i=o.trim()||a;if(i==="."){if(G.readdirSync(process.cwd()).length>0)return"Current directory is not empty. Please choose a different directory.";r=!0;return}let l=Z.resolve(process.cwd(),i),p=Z.basename(l),d=Nt(p);if(d)return d;if(!l.startsWith(process.cwd()))return"Project path must be within current directory";if(G.pathExistsSync(l)&&G.readdirSync(l).length>0)return`Directory "${i}" already exists and is not empty. Please choose a different name or path.`;r=!0}});wn(s)&&(bn(Pn.red("Operation cancelled.")),process.exit(0)),t=s||a}return t}import{cancel as vn,isCancel as xn,select as kn}from"@clack/prompts";import $n from"picocolors";async function _t(e,r){if(e!==void 0)return e;if(r==="next")return"node";let t=await kn({message:"Select runtime",options:[{value:"bun",label:"Bun",hint:"Fast all-in-one JavaScript runtime"},{value:"node",label:"Node.js",hint:"Traditional Node.js runtime"}],initialValue:h.runtime});return xn(t)&&(vn($n.red("Operation cancelled")),process.exit(0)),t}async function zt(e){let r=await An({projectName:async()=>Mt(e.projectName),frontend:()=>Ft(e.frontend),backend:()=>kt(e.backend),runtime:({results:t})=>_t(e.runtime,t.backend),database:()=>$t(e.database),orm:({results:t})=>Ot(e.orm,t.database!=="none",t.database),auth:({results:t})=>xt(e.auth,t.database!=="none",t.frontend),addons:({results:t})=>vt(e.addons,t.frontend),examples:({results:t})=>Et(e.examples,t.database,t.frontend,t.backend),dbSetup:({results:t})=>St(t.database??"none",e.dbSetup,t.orm),git:()=>Rt(e.git),packageManager:()=>Bt(e.packageManager),noInstall:()=>It(e.noInstall)},{onCancel:()=>{Sn(En.red("Operation cancelled")),process.exit(0)}});return{projectName:r.projectName,frontend:r.frontend,database:r.database,orm:r.orm,auth:r.auth,addons:r.addons,examples:r.examples,git:r.git,packageManager:r.packageManager,noInstall:r.noInstall,dbSetup:r.dbSetup,backend:r.backend,runtime:r.runtime}}import C from"picocolors";function $e(e){let r=[];if(e.projectName&&r.push(`${C.blue("Project Name:")} ${e.projectName}`),e.frontend!==void 0){let t=e.frontend.length>0?e.frontend.join(", "):"none";r.push(`${C.blue("Frontend:")} ${t}`)}if(e.backend!==void 0&&r.push(`${C.blue("Backend Framework:")} ${e.backend}`),e.runtime!==void 0&&r.push(`${C.blue("Runtime:")} ${e.runtime}`),e.database!==void 0&&r.push(`${C.blue("Database:")} ${e.database}`),e.orm!==void 0&&r.push(`${C.blue("ORM:")} ${e.orm}`),e.auth!==void 0&&r.push(`${C.blue("Authentication:")} ${e.auth}`),e.addons!==void 0){let t=e.addons.length>0?e.addons.join(", "):"none";r.push(`${C.blue("Addons:")} ${t}`)}if(e.examples!==void 0){let t=e.examples.length>0?e.examples.join(", "):"none";r.push(`${C.blue("Examples:")} ${t}`)}return e.git!==void 0&&r.push(`${C.blue("Git Init:")} ${e.git}`),e.packageManager!==void 0&&r.push(`${C.blue("Package Manager:")} ${e.packageManager}`),e.noInstall!==void 0&&r.push(`${C.blue("Skip Install:")} ${e.noInstall}`),e.dbSetup!==void 0&&r.push(`${C.blue("Database Setup:")} ${e.dbSetup}`),r.join(`
281
- `)}function Ut(e){let r=[];e.database==="none"?r.push("--database none"):(r.push(`--database ${e.database}`),e.orm&&r.push(`--orm ${e.orm}`),e.dbSetup&&r.push(`--db-setup ${e.dbSetup}`)),r.push(e.auth?"--auth":"--no-auth"),r.push(e.git?"--git":"--no-git"),r.push(e.noInstall?"--no-install":"--install"),e.runtime&&r.push(`--runtime ${e.runtime}`),e.backend&&r.push(`--backend ${e.backend}`),e.frontend&&e.frontend.length>0&&r.push(`--frontend ${e.frontend.join(" ")}`),e.addons&&e.addons.length>0?r.push(`--addons ${e.addons.join(" ")}`):r.push("--addons none"),e.examples&&e.examples.length>0?r.push(`--examples ${e.examples.join(" ")}`):r.push("--examples none"),e.packageManager&&r.push(`--package-manager ${e.packageManager}`);let t="",a=e.packageManager;a==="npm"?t="npx create-better-t-stack@latest":a==="pnpm"?t="pnpm create better-t-stack@latest":a==="bun"&&(t="bun create better-t-stack@latest");let n=e.projectName?` ${e.projectName}`:"";return`${t}${n} ${r.join(" ")}`}import Dn from"node:path";import Tn from"fs-extra";var qt=()=>{let e=Dn.join(v,"package.json");return Tn.readJSONSync(e).version??"1.0.0"};import Vt from"gradient-string";var Wt=`
191
+ `}function xa(e){return`${b.bold("Documentation with Starlight:")}
192
+ ${b.cyan("\u2022")} Start docs site: ${`cd apps/docs && ${e} dev`}
193
+ ${b.cyan("\u2022")} Build docs site: ${`cd apps/docs && ${e} build`}
194
+ `}import bt from"node:path";import{log as Aa}from"@clack/prompts";import{$ as ht,execa as Sa}from"execa";import J from"fs-extra";import Da from"picocolors";async function wt(e,r){await $a(e,r),await Ca(e,r)}async function $a(e,r){let t=bt.join(e,"package.json");if(await J.pathExists(t)){let a=await J.readJson(t);a.name=r.projectName;let n={dev:"turbo dev",build:"turbo build","check-types":"turbo check-types","dev:native":"turbo -F native dev","dev:web":"turbo -F web dev","dev:server":"turbo -F server dev","db:push":"turbo -F server db:push","db:studio":"turbo -F server db:studio"},o={dev:"pnpm -r --parallel dev",build:"pnpm -r build","check-types":"pnpm -r check-types","dev:native":"pnpm --filter native dev","dev:web":"pnpm --filter web dev","dev:server":"pnpm --filter server dev","db:push":"pnpm --filter server db:push","db:studio":"pnpm --filter server db:studio"},i={dev:"npm run dev --workspaces",build:"npm run build --workspaces","check-types":"npm run check-types --workspaces","dev:native":"npm run dev --workspace native","dev:web":"npm run dev --workspace web","dev:server":"npm run dev --workspace server","db:push":"npm run db:push --workspace server","db:studio":"npm run db:studio --workspace server"},s={dev:"bun run --filter '*' dev",build:"bun run --filter '*' build","check-types":"bun run --filter '*' check-types","dev:native":"bun run --filter native dev","dev:web":"bun run --filter web dev","dev:server":"bun run --filter server dev","db:push":"bun run --filter server db:push","db:studio":"bun run --filter server db:studio"};r.addons.includes("turborepo")?a.scripts=n:r.packageManager==="pnpm"?a.scripts=o:r.packageManager==="npm"?a.scripts=i:r.packageManager==="bun"?a.scripts=s:a.scripts={};let{stdout:c}=await Sa(r.packageManager,["-v"],{cwd:e});a.packageManager=`${r.packageManager}@${c.trim()}`,await J.writeJson(t,a,{spaces:2})}}async function Ca(e,r){let t=bt.join(e,"apps/server/package.json");if(await J.pathExists(t)){let a=await J.readJson(t);r.database!=="none"&&(r.database==="sqlite"&&r.orm==="drizzle"&&(a.scripts["db:local"]="turso dev --db-file local.db"),r.orm==="prisma"?(a.scripts["db:push"]="prisma db push --schema ./prisma/schema",a.scripts["db:studio"]="prisma studio"):r.orm==="drizzle"&&(a.scripts["db:push"]="drizzle-kit push",a.scripts["db:studio"]="drizzle-kit studio")),await J.writeJson(t,a,{spaces:2})}}async function yt(e,r){if(!r)return;if((await ht({cwd:e,reject:!1,stderr:"pipe"})`git --version`).exitCode!==0){Aa.warn(Da.yellow("Git is not installed"));return}let a=await ht({cwd:e,reject:!1,stderr:"pipe"})`git init`;if(a.exitCode!==0)throw new Error(`Git initialization failed: ${a.stderr}`)}import me from"node:path";import fe from"fs-extra";async function Pt(e){let{projectName:r,runtime:t,backend:a}=e,n=me.resolve(process.cwd(),r);if(a==="next")return;let o=me.join(n,"apps/server");t==="bun"?await Ea(o,a):t==="node"&&await Ta(o,a)}async function Ea(e,r){let t=me.join(e,"package.json"),a=await fe.readJson(t);a.scripts={...a.scripts,dev:"bun run --hot src/index.ts",start:"bun run dist/src/index.js"},await fe.writeJson(t,a,{spaces:2}),await g({devDependencies:["@types/bun"],projectDir:e})}async function Ta(e,r){let t=me.join(e,"package.json"),a=await fe.readJson(t);a.scripts={...a.scripts,dev:"tsx watch src/index.ts",start:"node dist/src/index.js"},await fe.writeJson(t,a,{spaces:2}),await g({devDependencies:["tsx","@types/node"],projectDir:e}),r==="hono"?await g({dependencies:["@hono/node-server"],projectDir:e}):r==="elysia"&&await g({dependencies:["@elysiajs/node"],projectDir:e})}import l from"node:path";import S from"consola";import m from"fs-extra";import{globby as vt}from"globby";import C from"picocolors";import Fa from"node:path";import Te from"fs-extra";import ge from"handlebars";async function Fe(e,r,t){try{let a=await Te.readFile(e,"utf-8"),o=ge.compile(a)(t);await Te.ensureDir(Fa.dirname(r)),await Te.writeFile(r,o)}catch(a){throw console.error(`Error processing template ${e}:`,a),new Error(`Failed to process template ${e}`)}}ge.registerHelper("or",(e,r)=>e||r);ge.registerHelper("eq",(e,r)=>e===r);ge.registerHelper("includes",(e,r)=>Array.isArray(e)&&e.includes(r));async function j(e,r,t,a,n=!0){let o=await vt(e,{cwd:r,dot:!0,onlyFiles:!0,absolute:!1});for(let i of o){let s=l.join(r,i),c=i;i.endsWith(".hbs")&&(c=i.slice(0,-4));let p=l.join(t,c);if(await m.ensureDir(l.dirname(p)),s.endsWith(".hbs"))await Fe(s,p,a);else{if(!n&&await m.pathExists(p))continue;await m.copy(s,p,{overwrite:!0})}}}async function jt(e,r){let t=l.join(P,"templates/base");await j(["package.json","_gitignore"],t,e,r)}async function kt(e,r){let t=r.frontend.filter(n=>n==="tanstack-router"||n==="react-router"||n==="tanstack-start"||n==="next"),a=r.frontend.includes("native");if(t.length>0){let n=l.join(e,"apps/web");await m.ensureDir(n);let o=l.join(P,"templates/frontend/web-base");await m.pathExists(o)&&await j("**/*",o,n,r);for(let i of t){let s=l.join(P,`templates/frontend/${i}`);await m.pathExists(s)&&await j("**/*",s,n,r)}if(r.api!=="none"){let i=t[0],s=l.join(P,`templates/api/${r.api}/web/base`);await m.pathExists(s)&&await j("**/*",s,n,r);let c=l.join(P,`templates/api/${r.api}/web/${i}`);await m.pathExists(c)&&await j("**/*",c,n,r)}}if(a){let n=l.join(e,"apps/native");await m.ensureDir(n);let o=l.join(P,"templates/frontend/native");if(await m.pathExists(o)&&await j("**/*",o,n,r),r.api!=="none"){let i=l.join(P,`templates/api/${r.api}/native`);await m.pathExists(i)&&await j("**/*",i,n,r)}}}async function xt(e,r){if(r.backend==="none")return;let t=l.join(e,"apps/server");await m.ensureDir(t);let a=l.join(P,"templates/backend/server-base");await m.pathExists(a)?await j("**/*",a,t,r):S.warn(C.yellow(`Warning: server-base template not found at ${a}`));let n=l.join(P,`templates/backend/${r.backend}`);if(await m.pathExists(n)?await j("**/*",n,t,r):S.warn(C.yellow(`Warning: Backend template directory not found, skipping: ${n}`)),r.api!=="none"){let o=l.join(P,`templates/api/${r.api}/server/base`);await m.pathExists(o)&&await j("**/*",o,t,r);let i=l.join(P,`templates/api/${r.api}/server/${r.backend}`);await m.pathExists(i)&&await j("**/*",i,t,r)}}async function At(e,r){if(r.orm==="none"||r.database==="none")return;let t=l.join(e,"apps/server");await m.ensureDir(t);let a=l.join(P,`templates/db/${r.orm}/${r.database}`);await m.pathExists(a)?await j("**/*",a,t,r):S.warn(C.yellow(`Warning: Database/ORM template directory not found, skipping: ${a}`))}async function St(e,r){if(!r.auth)return;let t=l.join(e,"apps/server"),a=l.join(e,"apps/web"),n=l.join(e,"apps/native"),o=r.frontend.filter(s=>s==="tanstack-router"||s==="react-router"||s==="tanstack-start"||s==="next"),i=r.frontend.includes("native");if(await m.pathExists(t)){let s=l.join(P,"templates/auth/server/base");await m.pathExists(s)?await j("**/*",s,t,r):S.warn(C.yellow(`Warning: Base auth server template not found at ${s}`));let c=l.join(P,"templates/auth/server/next");if(await m.pathExists(c)?await j("**/*",c,t,r):S.warn(C.yellow(`Warning: Next auth server template not found at ${c}`)),r.orm!=="none"&&r.database!=="none"){let p=r.orm,w=r.database,y="";p==="drizzle"?y=l.join(P,`templates/auth/server/db/drizzle/${w}`):p==="prisma"&&(y=l.join(P,`templates/auth/server/db/prisma/${w}`)),y&&await m.pathExists(y)?await j("**/*",y,t,r):S.warn(C.yellow(`Warning: Auth template for ${p}/${w} not found at ${y}`))}}else S.warn(C.yellow("Warning: apps/server directory does not exist, skipping server-side auth setup."));if(o.length>0&&await m.pathExists(a)){let s=l.join(P,"templates/auth/web/base");await m.pathExists(s)?await j("**/*",s,a,r):S.warn(C.yellow(`Warning: Base auth web template not found at ${s}`));for(let c of o){let p=l.join(P,`templates/auth/web/${c}`);await m.pathExists(p)?await j("**/*",p,a,r):S.warn(C.yellow(`Warning: Auth web template for ${c} not found at ${p}`))}}if(i&&await m.pathExists(n)){let s=l.join(P,"templates/auth/native");await m.pathExists(s)?await j("**/*",s,n,r):S.warn(C.yellow(`Warning: Auth native template not found at ${s}`))}}async function Dt(e,r){if(r.addons.includes("turborepo")){let t=l.join(P,"templates/addons/turborepo");await m.pathExists(t)?await j("**/*",t,e,r):S.warn(C.yellow("Warning: Turborepo addon template not found."))}if(r.addons.includes("husky")){let t=l.join(P,"templates/addons/husky");await m.pathExists(t)?await j("**/*",t,e,r):S.warn(C.yellow("Warning: Husky addon template not found."))}if(r.addons.includes("biome")){let t=l.join(P,"templates/addons/biome");await m.pathExists(t)?await j("**/*",t,e,r):S.warn(C.yellow("Warning: Biome addon template not found."))}if(r.addons.includes("pwa")){let t=l.join(P,"templates/addons/pwa/apps/web"),a=l.join(e,"apps/web");await m.pathExists(t)?await m.pathExists(a)?await j("**/*",t,a,r):S.warn(C.yellow("Warning: apps/web directory not found, cannot setup PWA addon.")):S.warn(C.yellow("Warning: PWA addon template not found."))}}async function $t(e,r){if(!r.examples||r.examples.length===0)return;let t=l.join(e,"apps/server"),a=l.join(e,"apps/web");for(let n of r.examples){let o=l.join(P,`templates/examples/${n}`);if(await m.pathExists(t)){let i=l.join(o,"server");if(await m.pathExists(i)&&r.orm!=="none"){let s=l.join(i,r.orm,"base");if(await m.pathExists(s)&&await j("**/*",s,t,r,!1),r.database!=="none"){let c=l.join(i,r.orm,r.database);await m.pathExists(c)&&await j("**/*",c,t,r,!1)}}}if(await m.pathExists(a)){let i=l.join(o,"web");if(await m.pathExists(i)){let s=r.frontend.filter(c=>["next","react-router","tanstack-router","tanstack-start"].includes(c));for(let c of s){let p=l.join(i,c);await m.pathExists(p)&&await j("**/*",p,a,r,!1)}}}}}async function Ct(e,r){let t=await vt(["**/.gitignore.hbs","**/_gitignore"],{cwd:e,dot:!0,onlyFiles:!0,absolute:!0,ignore:["**/node_modules/**","**/.git/**"]});for(let a of t){let n=l.dirname(a),o=l.basename(a),i=l.join(n,".gitignore");try{o===".gitignore.hbs"?(await Fe(a,i,r),await m.remove(a)):o==="_gitignore"&&await m.move(a,i,{overwrite:!0})}catch(s){S.error(`Error processing gitignore file ${a}:`,s)}}}async function Et(e,r){if(r.packageManager==="pnpm"){let t=l.join(P,"templates/extras/pnpm-workspace.yaml"),a=l.join(e,"pnpm-workspace.yaml");await m.pathExists(t)?await m.copy(t,a):S.warn(C.yellow("Warning: pnpm-workspace.yaml template not found."))}}async function Ft(e){let r=Ia(),t=Ra.resolve(process.cwd(),e.projectName);try{return await Ma.ensureDir(t),await jt(t,e),await kt(t,e),await xt(t,e),await Ye(e),await At(t,e),await pt(e),await St(t,e),await Qe(e),await Dt(t,e),e.addons.length>0&&e.addons[0]!=="none"&&await We(e),await $t(t,e),await Et(t,e),e.examples.length>0&&e.examples[0]!=="none"&&await dt(e),await qe(e),await Pt(e),await lt(e),await wt(t,e),await Ke(t,e),await yt(t,e.git),await Ct(t,e),Na.success("Project template successfully scaffolded!"),e.install&&await ft({projectDir:t,packageManager:e.packageManager,addons:e.addons}),gt({...e,depsInstalled:e.install}),t}catch(a){throw r.stop(Tt.red("Failed")),a instanceof Error&&(Ba(Tt.red(`Error during project creation: ${a.message}`)),console.error(a.stack),process.exit(1)),a}}import{cancel as Un,group as _n}from"@clack/prompts";import zn from"picocolors";import{cancel as La,isCancel as Oa,multiselect as Ua}from"@clack/prompts";import _a from"picocolors";async function Rt(e,r){if(e!==void 0)return e;let t=r?.includes("react-router")||r?.includes("tanstack-router"),a=[{value:"starlight",label:"Starlight",hint:"Add Astro Starlight documentation site"},{value:"biome",label:"Biome",hint:"Add Biome for linting and formatting"},{value:"husky",label:"Husky",hint:"Add Git hooks with Husky, lint-staged (requires Biome)"},{value:"turborepo",label:"Turborepo",hint:"Optimize builds for monorepos"}],o=t?[...[{value:"pwa",label:"PWA (Progressive Web App)",hint:"Make your app installable and work offline"},{value:"tauri",label:"Tauri Desktop App",hint:"Build native desktop apps from your web frontend"}],...a]:a,i=h.addons.filter(c=>t||c!=="pwa"&&c!=="tauri"),s=await Ua({message:"Select addons",options:o,initialValues:i,required:!1});return Oa(s)&&(La(_a.red("Operation cancelled")),process.exit(0)),s.includes("husky")&&!s.includes("biome")&&s.push("biome"),s}import{cancel as za,isCancel as Wa,select as qa}from"@clack/prompts";import Va from"picocolors";async function Bt(e,r){if(e)return e;let t=r?.includes("native"),a=[{value:"trpc",label:"tRPC",hint:"End-to-end typesafe APIs made easy"},{value:"orpc",label:"oRPC",hint:"End-to-end type-safe APIs that adhere to OpenAPI standards"},{value:"none",label:"None",hint:"No API integration (skip API setup)"}];t&&(a=[{value:"trpc",label:"tRPC",hint:"End-to-end typesafe APIs made easy (Required for Native frontend)"}]);let n=await qa({message:"Select API type",options:a,initialValue:t?"trpc":h.api});return Wa(n)&&(za(Va.red("Operation cancelled")),process.exit(0)),t&&n!=="trpc"?"trpc":n}import{cancel as Ga,confirm as Ja,isCancel as Qa}from"@clack/prompts";import Ha from"picocolors";async function Nt(e,r){if(!r)return!1;if(e!==void 0)return e;let t=await Ja({message:"Add authentication with Better-Auth?",initialValue:h.auth});return Qa(t)&&(Ga(Ha.red("Operation cancelled")),process.exit(0)),t}import{cancel as Ya,isCancel as Ka,select as Xa}from"@clack/prompts";import Za from"picocolors";async function It(e){if(e!==void 0)return e;let r=await Xa({message:"Select backend framework",options:[{value:"hono",label:"Hono",hint:"Lightweight, ultrafast web framework"},{value:"next",label:"Next.js",hint:"Full-stack framework with API routes"},{value:"express",label:"Express",hint:"Fast, unopinionated, minimalist web framework for Node.js"},{value:"elysia",label:"Elysia",hint:"Ergonomic web framework for building backend servers"}],initialValue:h.backend});return Ka(r)&&(Ya(Za.red("Operation cancelled")),process.exit(0)),r}import{cancel as en,isCancel as tn,select as rn}from"@clack/prompts";import an from"picocolors";async function Mt(e){if(e!==void 0)return e;let r=await rn({message:"Select database",options:[{value:"none",label:"None",hint:"No database setup"},{value:"sqlite",label:"SQLite",hint:"lightweight, server-less, embedded relational database management system"},{value:"postgres",label:"PostgreSQL",hint:"powerful, open source object-relational database system"},{value:"mysql",label:"MySQL",hint:"popular open-source relational database system"},{value:"mongodb",label:"MongoDB",hint:"open-source NoSQL database that stores data in JSON-like documents called BSON"}],initialValue:h.database});return tn(r)&&(en(an.red("Operation cancelled")),process.exit(0)),r}import{cancel as nn,isCancel as on,select as sn}from"@clack/prompts";import cn from"picocolors";async function Lt(e,r,t){if(r!==void 0)return r;if(e==="sqlite"&&t==="prisma")return"none";let a=[];if(e==="sqlite")a=[{value:"turso",label:"Turso",hint:"SQLite for Production. Powered by libSQL"},{value:"none",label:"None",hint:"Manual setup"}];else if(e==="postgres")a=[{value:"neon",label:"Neon Postgres",hint:"Serverless Postgres with branching capability"},...t==="prisma"?[{value:"prisma-postgres",label:"Prisma Postgres",hint:"Instant Postgres for Global Applications"}]:[],{value:"none",label:"None",hint:"Manual setup"}];else if(e==="mongodb")a=[{value:"mongodb-atlas",label:"MongoDB Atlas",hint:"The most effective way to deploy MongoDB"},{value:"none",label:"None",hint:"Manual setup"}];else return"none";let n=await sn({message:`Select ${e} setup option`,options:a,initialValue:"none"});return on(n)&&(nn(cn.red("Operation cancelled")),process.exit(0)),n}import{cancel as pn,isCancel as ln,multiselect as Ot}from"@clack/prompts";import dn from"picocolors";async function Ut(e,r,t,a){if(e!==void 0)return e;if(r==="none")return[];if(!(t?.includes("react-router")||t?.includes("tanstack-router")||t?.includes("tanstack-start")))return[];let o=[];return a==="elysia"&&(o=await Ot({message:"Include examples",options:[{value:"todo",label:"Todo App",hint:"A simple CRUD example app"}],required:!1,initialValues:h.examples})),(a==="hono"||a==="express")&&(o=await Ot({message:"Include examples",options:[{value:"todo",label:"Todo App",hint:"A simple CRUD example app"},{value:"ai",label:"AI Chat",hint:"A simple AI chat interface using AI SDK"}],required:!1,initialValues:h.examples})),ln(o)&&(pn(dn.red("Operation cancelled")),process.exit(0)),o}import{cancel as _t,isCancel as zt,multiselect as un,select as mn}from"@clack/prompts";import Wt from"picocolors";async function qt(e){if(e!==void 0)return e;let r=await un({message:"Select platforms to develop for",options:[{value:"web",label:"Web",hint:"React Web Application"},{value:"native",label:"Native",hint:"Create a React Native/Expo app"}],required:!1,initialValues:h.frontend.some(a=>a==="tanstack-router"||a==="react-router"||a==="tanstack-start"||a==="next")?["web"]:[]});zt(r)&&(_t(Wt.red("Operation cancelled")),process.exit(0));let t=[];if(r.includes("web")){let a=await mn({message:"Choose frontend framework",options:[{value:"tanstack-router",label:"TanStack Router",hint:"Modern and scalable routing for React Applications"},{value:"react-router",label:"React Router",hint:"A user\u2011obsessed, standards\u2011focused, multi\u2011strategy router"},{value:"next",label:"Next.js",hint:"The React Framework for the Web"},{value:"tanstack-start",label:"TanStack Start (beta)",hint:"SSR, Server Functions, API Routes and more with TanStack Router"}],initialValue:h.frontend.find(n=>n==="tanstack-router"||n==="react-router"||n==="tanstack-start"||n==="next")||"tanstack-router"});zt(a)&&(_t(Wt.red("Operation cancelled")),process.exit(0)),t.push(a)}return r.includes("native")&&t.push("native"),t}import{cancel as fn,confirm as gn,isCancel as hn}from"@clack/prompts";import bn from"picocolors";async function Vt(e){if(e!==void 0)return e;let r=await gn({message:"Initialize git repository?",initialValue:h.git});return hn(r)&&(fn(bn.red("Operation cancelled")),process.exit(0)),r}import{cancel as wn,confirm as yn,isCancel as Pn}from"@clack/prompts";import vn from"picocolors";async function Gt(e){if(e!==void 0)return e;let r=await yn({message:"Install dependencies?",initialValue:h.install});return Pn(r)&&(wn(vn.red("Operation cancelled")),process.exit(0)),r}import{cancel as jn,isCancel as kn,log as xn,select as An}from"@clack/prompts";import Sn from"picocolors";async function Jt(e,r,t){if(!r)return"none";if(e!==void 0)return e;if(t==="mongodb")return xn.info("Only Prisma is supported with MongoDB."),"prisma";let a=await An({message:"Select ORM",options:[{value:"drizzle",label:"Drizzle",hint:"lightweight and performant TypeScript ORM"},{value:"prisma",label:"Prisma",hint:"Powerful, feature-rich ORM"}],initialValue:h.orm});return kn(a)&&(jn(Sn.red("Operation cancelled")),process.exit(0)),a}import{cancel as Dn,isCancel as $n,select as Cn}from"@clack/prompts";import En from"picocolors";async function Qt(e){if(e!==void 0)return e;let r=re(),t=await Cn({message:"Choose package manager",options:[{value:"npm",label:"npm",hint:"Node Package Manager"},{value:"pnpm",label:"pnpm",hint:"Fast, disk space efficient package manager"},{value:"bun",label:"bun",hint:"All-in-one JavaScript runtime & toolkit"}],initialValue:r});return $n(t)&&(Dn(En.red("Operation cancelled")),process.exit(0)),t}import te from"node:path";import{cancel as Tn,isCancel as Fn,text as Rn}from"@clack/prompts";import U from"fs-extra";import Bn from"picocolors";var Nn=["<",">",":",'"',"|","?","*"],Ht=255;function Yt(e){if(e!=="."){if(!e)return"Project name cannot be empty";if(e.length>Ht)return`Project name must be less than ${Ht} characters`;if(Nn.some(r=>e.includes(r)))return"Project name contains invalid characters";if(e.startsWith(".")||e.startsWith("-"))return"Project name cannot start with a dot or dash";if(e.toLowerCase()==="node_modules")return"Project name is reserved"}}async function Kt(e){if(e)if(e==="."){let o=process.cwd();if(U.readdirSync(o).length===0)return e}else{let o=te.basename(e);if(!Yt(o)){let s=te.resolve(process.cwd(),e);if(!U.pathExistsSync(s)||U.readdirSync(s).length===0)return e}}let r=!1,t="",a=h.projectName,n=1;for(;U.pathExistsSync(te.resolve(process.cwd(),a));)a=`${h.projectName}-${n}`,n++;for(;!r;){let o=await Rn({message:"Enter your project name or path (relative to current directory)",placeholder:a,initialValue:e,defaultValue:a,validate:i=>{let s=i.trim()||a;if(s==="."){if(U.readdirSync(process.cwd()).length>0)return"Current directory is not empty. Please choose a different directory.";r=!0;return}let c=te.resolve(process.cwd(),s),p=te.basename(c),w=Yt(p);if(w)return w;if(!c.startsWith(process.cwd()))return"Project path must be within current directory";if(U.pathExistsSync(c)&&U.readdirSync(c).length>0)return`Directory "${s}" already exists and is not empty. Please choose a different name or path.`;r=!0}});Fn(o)&&(Tn(Bn.red("Operation cancelled.")),process.exit(0)),t=o||a}return t}import{cancel as In,isCancel as Mn,select as Ln}from"@clack/prompts";import On from"picocolors";async function Xt(e,r){if(e!==void 0)return e;if(r==="next")return"node";let t=await Ln({message:"Select runtime",options:[{value:"bun",label:"Bun",hint:"Fast all-in-one JavaScript runtime"},{value:"node",label:"Node.js",hint:"Traditional Node.js runtime"}],initialValue:h.runtime});return Mn(t)&&(In(On.red("Operation cancelled")),process.exit(0)),t}async function Zt(e){let r=await _n({projectName:async()=>Kt(e.projectName),frontend:()=>qt(e.frontend),backend:()=>It(e.backend),runtime:({results:t})=>Xt(e.runtime,t.backend),database:()=>Mt(e.database),orm:({results:t})=>Jt(e.orm,t.database!=="none",t.database),api:({results:t})=>Bt(e.api,t.frontend),auth:({results:t})=>Nt(e.auth,t.database!=="none"),addons:({results:t})=>Rt(e.addons,t.frontend),examples:({results:t})=>Ut(e.examples,t.database,t.frontend,t.backend),dbSetup:({results:t})=>Lt(t.database??"none",e.dbSetup,t.orm),git:()=>Vt(e.git),packageManager:()=>Qt(e.packageManager),install:()=>Gt(e.install)},{onCancel:()=>{Un(zn.red("Operation cancelled")),process.exit(0)}});return{projectName:r.projectName,frontend:r.frontend,database:r.database,orm:r.orm,auth:r.auth,addons:r.addons,examples:r.examples,git:r.git,packageManager:r.packageManager,install:r.install,dbSetup:r.dbSetup,backend:r.backend,runtime:r.runtime,api:r.api}}import T from"picocolors";function Re(e){let r=[];if(e.projectName&&r.push(`${T.blue("Project Name:")} ${e.projectName}`),e.frontend!==void 0){let t=Array.isArray(e.frontend)?e.frontend:[e.frontend],a=t.length>0&&t[0]!==void 0&&t[0]!==""?t.join(", "):"none";r.push(`${T.blue("Frontend:")} ${a}`)}if(e.backend!==void 0&&r.push(`${T.blue("Backend Framework:")} ${String(e.backend)}`),e.runtime!==void 0&&r.push(`${T.blue("Runtime:")} ${String(e.runtime)}`),e.api!==void 0&&r.push(`${T.blue("API:")} ${String(e.api)}`),e.database!==void 0&&r.push(`${T.blue("Database:")} ${String(e.database)}`),e.orm!==void 0&&r.push(`${T.blue("ORM:")} ${String(e.orm)}`),e.auth!==void 0){let t=typeof e.auth=="boolean"?e.auth?"Yes":"No":String(e.auth);r.push(`${T.blue("Authentication:")} ${t}`)}if(e.addons!==void 0){let t=Array.isArray(e.addons)?e.addons:[e.addons],a=t.length>0&&t[0]!==void 0?t.join(", "):"none";r.push(`${T.blue("Addons:")} ${a}`)}if(e.examples!==void 0){let t=Array.isArray(e.examples)?e.examples:[e.examples],a=t.length>0&&t[0]!==void 0?t.join(", "):"none";r.push(`${T.blue("Examples:")} ${a}`)}if(e.git!==void 0){let t=typeof e.git=="boolean"?e.git?"Yes":"No":String(e.git);r.push(`${T.blue("Git Init:")} ${t}`)}if(e.packageManager!==void 0&&r.push(`${T.blue("Package Manager:")} ${String(e.packageManager)}`),e.install!==void 0){let t=typeof e.install=="boolean"?e.install?"Yes":"No":String(e.install);r.push(`${T.blue("Install Dependencies:")} ${t}`)}return e.dbSetup!==void 0&&r.push(`${T.blue("Database Setup:")} ${String(e.dbSetup)}`),r.length===0?T.yellow("No configuration selected."):r.join(`
195
+ `)}function er(e){let r=[];e.database==="none"?r.push("--database none"):(r.push(`--database ${e.database}`),e.orm&&r.push(`--orm ${e.orm}`),e.dbSetup&&r.push(`--db-setup ${e.dbSetup}`)),e.api&&r.push(`--api ${e.api}`),r.push(e.auth?"--auth":"--no-auth"),r.push(e.git?"--git":"--no-git"),r.push(e.install?"--install":"--no-install"),e.runtime&&r.push(`--runtime ${e.runtime}`),e.backend&&r.push(`--backend ${e.backend}`),e.frontend&&e.frontend.length>0&&r.push(`--frontend ${e.frontend.join(" ")}`),e.addons&&e.addons.length>0?r.push(`--addons ${e.addons.join(" ")}`):r.push("--addons none"),e.examples&&e.examples.length>0?r.push(`--examples ${e.examples.join(" ")}`):r.push("--examples none"),e.packageManager&&r.push(`--package-manager ${e.packageManager}`);let t="",a=e.packageManager;a==="npm"?t="npx create-better-t-stack@latest":a==="pnpm"?t="pnpm create better-t-stack@latest":a==="bun"&&(t="bun create better-t-stack@latest");let n=e.projectName?` ${e.projectName}`:"";return`${t}${n} ${r.join(" ")}`}import Wn from"node:path";import qn from"fs-extra";var tr=()=>{let e=Wn.join(P,"package.json");return qn.readJSONSync(e).version??"1.0.0"};import rr from"gradient-string";var ar=`
282
196
  \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557
283
197
  \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
284
198
  \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D
@@ -292,10 +206,10 @@ serve(
292
206
  \u2588\u2588\u2551 \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2588\u2588\u2557
293
207
  \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2557
294
208
  \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
295
- `,Gt={pink:"#F5C2E7",mauve:"#CBA6F7",red:"#F38BA8",maroon:"#E78284",peach:"#FAB387",yellow:"#F9E2AF",green:"#A6E3A1",teal:"#94E2D5",sky:"#89DCEB",sapphire:"#74C7EC",lavender:"#B4BEFE"},Jt=()=>{let e=process.stdout.columns||80,r=Wt.split(`
296
- `),t=Math.max(...r.map(a=>a.length));e<t?console.log(Vt(Object.values(Gt)).multiline(`
209
+ `,nr={pink:"#F5C2E7",mauve:"#CBA6F7",red:"#F38BA8",maroon:"#E78284",peach:"#FAB387",yellow:"#F9E2AF",green:"#A6E3A1",teal:"#94E2D5",sky:"#89DCEB",sapphire:"#74C7EC",lavender:"#B4BEFE"},or=()=>{let e=process.stdout.columns||80,r=ar.split(`
210
+ `),t=Math.max(...r.map(a=>a.length));e<t?console.log(rr(Object.values(nr)).multiline(`
297
211
  \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
298
212
  \u2551 Better T-Stack \u2551
299
213
  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
300
- `)):console.log(Vt(Object.values(Gt)).multiline(Wt))};var Qt=()=>process.exit(0);process.on("SIGINT",Qt);process.on("SIGTERM",Qt);async function Bn(){let e=Date.now(),r=Rn();try{let t=await In(On(process.argv)).scriptName("create-better-t-stack").usage("$0 [project-directory] [options]","Create a new Better-T Stack project").positional("project-directory",{describe:"Project name/directory",type:"string"}).option("yes",{alias:"y",type:"boolean",describe:"Use default configuration and skip prompts",default:!1}).option("database",{type:"string",describe:"Database type",choices:["none","sqlite","postgres","mysql","mongodb"]}).option("orm",{type:"string",describe:"ORM type",choices:["drizzle","prisma","none"]}).option("auth",{type:"boolean",describe:"Include authentication"}).option("frontend",{type:"array",string:!0,describe:"Frontend types",choices:["tanstack-router","react-router","tanstack-start","next","native","none"]}).option("addons",{type:"array",string:!0,describe:"Additional addons",choices:["pwa","tauri","starlight","biome","husky","none"]}).option("examples",{type:"array",string:!0,describe:"Examples to include",choices:["todo","ai","none"]}).option("git",{type:"boolean",describe:"Initialize git repository"}).option("package-manager",{alias:"pm",type:"string",describe:"Package manager",choices:["npm","pnpm","bun"]}).option("install",{type:"boolean",describe:"Install dependencies (use --no-install to explicitly skip)"}).option("db-setup",{type:"string",describe:"Database setup",choices:["turso","neon","prisma-postgres","mongodb-atlas","none"]}).option("backend",{type:"string",describe:"Backend framework",choices:["hono","express","next","elysia"]}).option("runtime",{type:"string",describe:"Runtime",choices:["bun","node"]}).completion().recommendCommands().version(qt()).alias("version","v").help().alias("help","h").strict().wrap(null).parse();Jt(),Cn(y.magenta("Creating a new Better-T-Stack project"));let a=t,n=a.projectDirectory,s=Ln(a,n);!a.yes&&Object.keys(s).length>0&&(L.info(y.yellow("Using these pre-selected options:")),L.message($e(s)),L.message(""));let o=a.yes?{...h,projectName:n??h.projectName,...s}:await zt(s);a.yes&&(L.info(y.yellow("Using these default options:")),L.message($e(o)),L.message("")),await jt(o),L.success(`You can reproduce this setup with the following command:
301
- ${y.white(Ut(o))}`);let i=((Date.now()-e)/1e3).toFixed(2);Fn(y.magenta(`Project created successfully in ${y.bold(i)} seconds!`))}catch(t){r.stop(y.red("Failed")),t instanceof Error?(t.name==="YError"?$(y.red(`Invalid arguments: ${t.message}`)):$(y.red(`An unexpected error occurred: ${t.message}`)),process.exit(1)):($(y.red("An unexpected error occurred.")),console.error(t),process.exit(1))}}function Ln(e,r){let t={};if(e.database&&(t.database=e.database),e.orm&&(e.orm==="none"?t.orm="none":t.orm=e.orm),(t.database??e.database)==="mongodb"&&(t.orm??e.orm)==="drizzle"&&($(y.red("MongoDB is only available with Prisma. Cannot use --database mongodb with --orm drizzle")),process.exit(1)),e.dbSetup){let n=e.dbSetup;n!=="none"?(t.dbSetup=n,n==="turso"?(e.database&&e.database!=="sqlite"&&($(y.red(`Turso setup requires a SQLite database. Cannot use --db-setup turso with --database ${e.database}`)),process.exit(1)),t.database="sqlite",e.orm==="prisma"&&($(y.red("Turso setup is not compatible with Prisma. Cannot use --db-setup turso with --orm prisma")),process.exit(1)),t.orm="drizzle"):n==="prisma-postgres"?(e.database&&e.database!=="postgres"&&($(y.red("Prisma PostgreSQL setup requires PostgreSQL database. Cannot use --db-setup prisma-postgres with a different database type.")),process.exit(1)),t.database="postgres",e.orm&&e.orm!=="prisma"&&e.orm!=="none"&&($(y.red("Prisma PostgreSQL setup requires Prisma ORM. Cannot use --db-setup prisma-postgres with a different ORM.")),process.exit(1)),t.orm="prisma"):n==="mongodb-atlas"?(e.database&&e.database!=="mongodb"&&($(y.red("MongoDB Atlas setup requires MongoDB database. Cannot use --db-setup mongodb-atlas with a different database type.")),process.exit(1)),t.database="mongodb",t.orm="prisma"):n==="neon"&&(e.database&&e.database!=="postgres"&&($(y.red("Neon PostgreSQL setup requires PostgreSQL database. Cannot use --db-setup neon with a different database type.")),process.exit(1)),t.database="postgres")):t.dbSetup="none"}if((t.database??e.database)==="none"){e.auth===!0&&($(y.red("Authentication requires a database. Cannot use --auth with --database none.")),process.exit(1));let n=t.orm??e.orm;n&&n!=="none"&&($(y.red(`Cannot use ORM with no database. Cannot use --orm ${n} with --database none.`)),process.exit(1)),t.orm="none";let s=t.dbSetup??e.dbSetup;s&&s!=="none"&&($(y.red(`Database setup requires a database. Cannot use --db-setup ${s} with --database none.`)),process.exit(1)),t.dbSetup="none"}if(e.auth!==void 0&&(t.auth=e.auth),e.backend&&(t.backend=e.backend),e.runtime&&(t.runtime=e.runtime),e.frontend&&e.frontend.length>0)if(e.frontend.includes("none"))e.frontend.length>1&&($(y.red("Cannot combine 'none' with other frontend options.")),process.exit(1)),t.frontend=[];else{let n=e.frontend.filter(o=>o!=="none");n.filter(o=>o==="tanstack-router"||o==="react-router"||o==="tanstack-start").length>1&&($(y.red("Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router")),process.exit(1)),t.frontend=n}if(e.addons&&e.addons.length>0)if(e.addons.includes("none"))e.addons.length>1&&($(y.red("Cannot combine 'none' with other addons.")),process.exit(1)),t.addons=[];else{let n=e.addons.filter(p=>p!=="none"),s=["pwa","tauri"],o=n.some(p=>s.includes(p)),l=(t.frontend??(e.yes?h.frontend:void 0))?.some(p=>p==="tanstack-router"||p==="react-router");o&&!l&&(e.frontend?($(y.red("PWA and Tauri addons require tanstack-router or react-router. Cannot use these addons with your frontend selection.")),process.exit(1)):e.yes&&($(y.red("PWA and Tauri addons require tanstack-router or react-router (default frontend incompatible).")),process.exit(1))),n.includes("husky")&&!n.includes("biome")&&n.push("biome"),t.addons=[...new Set(n)]}if(e.examples&&e.examples.length>0)if(e.examples.includes("none"))e.examples.length>1&&($(y.red("Cannot combine 'none' with other examples.")),process.exit(1)),t.examples=[];else{let n=e.examples.filter(l=>l!=="none"),s=t.backend??e.backend;n.includes("ai")&&s==="elysia"&&!(e.yes&&h.backend!=="elysia")&&($(y.red("AI example is only compatible with Hono backend. Cannot use --examples ai with --backend elysia")),process.exit(1)),(t.frontend??e.frontend?.filter(l=>l!=="none")??(e.yes?h.frontend:void 0))?.some(l=>["tanstack-router","react-router","tanstack-start"].includes(l))||(e.frontend?($(y.red("Examples require a web frontend (tanstack-router, react-router, or tanstack-start). Cannot use --examples with your frontend selection.")),process.exit(1)):e.yes&&($(y.red("Examples require a web frontend (tanstack-router, react-router, or tanstack-start) (default frontend incompatible).")),process.exit(1))),t.examples=n}return e.packageManager&&(t.packageManager=e.packageManager),e.git!==void 0&&(t.git=e.git),e.install!==void 0&&(t.noInstall=!e.install),r&&(t.projectName=r),t}Bn().catch(e=>{L.error("Aborting installation due to unexpected error..."),e instanceof Error?(L.error(e.message),console.error(e.stack)):(L.error("An unknown error has occurred. Please open an issue on GitHub with the below:"),console.error(e)),process.exit(1)});
214
+ `)):console.log(rr(Object.values(nr)).multiline(ar))};var sr=()=>process.exit(0);process.on("SIGINT",sr);process.on("SIGTERM",sr);async function Yn(){let e=Date.now();try{let t=await Qn(Hn(process.argv)).scriptName("create-better-t-stack").usage("$0 [project-directory] [options]","Create a new Better-T Stack project").positional("project-directory",{describe:"Project name/directory",type:"string"}).option("yes",{alias:"y",type:"boolean",describe:"Use default configuration and skip prompts",default:!1}).option("database",{type:"string",describe:"Database type",choices:["none","sqlite","postgres","mysql","mongodb"]}).option("orm",{type:"string",describe:"ORM type",choices:["drizzle","prisma","none"]}).option("auth",{type:"boolean",describe:"Include authentication"}).option("frontend",{type:"array",string:!0,describe:"Frontend types",choices:["tanstack-router","react-router","tanstack-start","next","native","none"]}).option("addons",{type:"array",string:!0,describe:"Additional addons",choices:["pwa","tauri","starlight","biome","husky","turborepo","none"]}).option("examples",{type:"array",string:!0,describe:"Examples to include",choices:["todo","ai","none"]}).option("git",{type:"boolean",describe:"Initialize git repository"}).option("package-manager",{alias:"pm",type:"string",describe:"Package manager",choices:["npm","pnpm","bun"]}).option("install",{type:"boolean",describe:"Install dependencies"}).option("db-setup",{type:"string",describe:"Database setup",choices:["turso","neon","prisma-postgres","mongodb-atlas","none"]}).option("backend",{type:"string",describe:"Backend framework",choices:["hono","express","next","elysia"]}).option("runtime",{type:"string",describe:"Runtime",choices:["bun","node"]}).option("api",{type:"string",describe:"API type",choices:["trpc","orpc"]}).completion().recommendCommands().version(tr()).alias("version","v").help().alias("help","h").strict().wrap(null).parse(),a=t.projectDirectory;or();let n=Kn(t,a);Gn(z.magenta("Creating a new Better-T-Stack project")),!t.yes&&Object.keys(n).length>0&&(_.info(z.yellow("Using these pre-selected options:")),_.message(Re(n)),_.message(""));let o=t.yes?{...h,projectName:a??h.projectName,...n}:await Zt(n);t.yes&&(_.info(z.yellow("Using these default options:")),_.message(Re(o)),_.message("")),await Ft(o),_.success(z.blue(`You can reproduce this setup with the following command:
215
+ ${er(o)}`));let i=((Date.now()-e)/1e3).toFixed(2);Jn(z.magenta(`Project created successfully in ${z.bold(i)} seconds!`))}catch(r){r instanceof Error?(r.name==="YError"?Vn(z.red(`Invalid arguments: ${r.message}`)):(v.error(`An unexpected error occurred: ${r.message}`),v.error(r.stack)),process.exit(1)):(v.error("An unexpected error occurred."),console.error(r),process.exit(1))}}function Kn(e,r){let t={};if(e.database&&(t.database=e.database),e.orm&&(e.orm==="none"?t.orm="none":t.orm=e.orm),(t.database??e.database)==="mongodb"&&(t.orm??e.orm)==="drizzle"&&(v.fatal("MongoDB is only available with Prisma. Cannot use --database mongodb with --orm drizzle"),process.exit(1)),e.dbSetup){let s=e.dbSetup;s!=="none"?(t.dbSetup=s,s==="turso"?(e.database&&e.database!=="sqlite"&&(v.fatal(`Turso setup requires a SQLite database. Cannot use --db-setup turso with --database ${e.database}`),process.exit(1)),t.database="sqlite",e.orm==="prisma"&&(v.fatal("Turso setup is not compatible with Prisma. Cannot use --db-setup turso with --orm prisma"),process.exit(1)),t.orm="drizzle"):s==="prisma-postgres"?(e.database&&e.database!=="postgres"&&(v.fatal("Prisma PostgreSQL setup requires PostgreSQL database. Cannot use --db-setup prisma-postgres with a different database type."),process.exit(1)),t.database="postgres",e.orm&&e.orm!=="prisma"&&e.orm!=="none"&&(v.fatal("Prisma PostgreSQL setup requires Prisma ORM. Cannot use --db-setup prisma-postgres with a different ORM."),process.exit(1)),t.orm="prisma"):s==="mongodb-atlas"?(e.database&&e.database!=="mongodb"&&(v.fatal("MongoDB Atlas setup requires MongoDB database. Cannot use --db-setup mongodb-atlas with a different database type."),process.exit(1)),t.database="mongodb",t.orm="prisma"):s==="neon"&&(e.database&&e.database!=="postgres"&&(v.fatal("Neon PostgreSQL setup requires PostgreSQL database. Cannot use --db-setup neon with a different database type."),process.exit(1)),t.database="postgres")):t.dbSetup="none"}if((t.database??e.database)==="none"){e.auth===!0&&(v.fatal("Authentication requires a database. Cannot use --auth with --database none."),process.exit(1));let s=t.orm??e.orm;s&&s!=="none"&&(v.fatal(`Cannot use ORM with no database. Cannot use --orm ${s} with --database none.`),process.exit(1)),t.orm="none";let c=t.dbSetup??e.dbSetup;c&&c!=="none"&&(v.fatal(`Database setup requires a database. Cannot use --db-setup ${c} with --database none.`),process.exit(1)),t.dbSetup="none"}if(e.auth!==void 0&&(t.auth=e.auth),e.backend&&(t.backend=e.backend),e.runtime&&(t.runtime=e.runtime),e.frontend&&e.frontend.length>0)if(e.frontend.includes("none"))e.frontend.length>1&&(v.fatal("Cannot combine 'none' with other frontend options."),process.exit(1)),t.frontend=[];else{let s=e.frontend.filter(p=>p!=="none");s.filter(p=>p==="tanstack-router"||p==="react-router"||p==="tanstack-start"||p==="next").length>1&&(v.fatal("Cannot select multiple web frameworks. Choose only one of: tanstack-router, tanstack-start, react-router, next"),process.exit(1)),t.frontend=s}e.api&&(t.api=e.api);let n=t.frontend??e.frontend?.filter(s=>s!=="none")??(e.yes?h.frontend:void 0),o=n?.includes("native"),i=t.api??(e.yes?h.api:void 0);if(o&&i==="orpc"&&(v.fatal("oRPC API is not supported when using the 'native' frontend. Please use --api trpc or remove 'native' from --frontend."),process.exit(1)),o&&i!=="trpc"&&(!e.api||e.yes&&e.api!=="orpc")&&(t.api="trpc"),e.addons&&e.addons.length>0)if(e.addons.includes("none"))e.addons.length>1&&(v.fatal("Cannot combine 'none' with other addons."),process.exit(1)),t.addons=[];else{let s=e.addons.filter(y=>y!=="none"),c=["pwa","tauri"],p=s.some(y=>c.includes(y)),w=n?.some(y=>y==="tanstack-router"||y==="react-router");p&&!w&&(e.frontend?(v.fatal("PWA and Tauri addons require tanstack-router or react-router. Cannot use these addons with your frontend selection."),process.exit(1)):e.yes&&(v.fatal("PWA and Tauri addons require tanstack-router or react-router (default frontend incompatible)."),process.exit(1))),s.includes("husky")&&!s.includes("biome")&&s.push("biome"),t.addons=[...new Set(s)]}if(e.examples&&e.examples.length>0)if(e.examples.includes("none"))e.examples.length>1&&(v.fatal("Cannot combine 'none' with other examples."),process.exit(1)),t.examples=[];else{let s=e.examples.filter(w=>w!=="none"),c=t.backend??e.backend;s.includes("ai")&&c==="elysia"&&!(e.yes&&h.backend!=="elysia")&&(v.fatal("AI example is only compatible with Hono backend. Cannot use --examples ai with --backend elysia"),process.exit(1)),n?.some(w=>["tanstack-router","react-router","tanstack-start","next"].includes(w))||(e.frontend?(v.fatal("Examples require a web frontend (tanstack-router, react-router, tanstack-start, or next). Cannot use --examples with your frontend selection."),process.exit(1)):e.yes&&(v.fatal("Examples require a web frontend (tanstack-router, react-router, tanstack-start, or next) (default frontend incompatible)."),process.exit(1))),t.examples=s}return e.packageManager&&(t.packageManager=e.packageManager),e.git!==void 0&&(t.git=e.git),e.install!==void 0&&(t.install=e.install),r&&(t.projectName=r),t}Yn().catch(e=>{v.error("Aborting installation due to unexpected error..."),e instanceof Error?(v.error(e.message),console.error(e.stack)):(v.error("An unknown error has occurred. Please open an issue on GitHub with the below:"),console.error(e)),process.exit(1)});