create-stackr 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +642 -0
  3. package/bin/cli.js +12 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +113 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/config/dependencies.d.ts +82 -0
  9. package/dist/config/dependencies.d.ts.map +1 -0
  10. package/dist/config/dependencies.js +82 -0
  11. package/dist/config/dependencies.js.map +1 -0
  12. package/dist/config/presets.d.ts +3 -0
  13. package/dist/config/presets.d.ts.map +1 -0
  14. package/dist/config/presets.js +174 -0
  15. package/dist/config/presets.js.map +1 -0
  16. package/dist/generators/index.d.ts +40 -0
  17. package/dist/generators/index.d.ts.map +1 -0
  18. package/dist/generators/index.js +130 -0
  19. package/dist/generators/index.js.map +1 -0
  20. package/dist/generators/onboarding.d.ts +8 -0
  21. package/dist/generators/onboarding.d.ts.map +1 -0
  22. package/dist/generators/onboarding.js +141 -0
  23. package/dist/generators/onboarding.js.map +1 -0
  24. package/dist/index.d.ts +3 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +65 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/prompts/features.d.ts +14 -0
  29. package/dist/prompts/features.d.ts.map +1 -0
  30. package/dist/prompts/features.js +96 -0
  31. package/dist/prompts/features.js.map +1 -0
  32. package/dist/prompts/index.d.ts +3 -0
  33. package/dist/prompts/index.d.ts.map +1 -0
  34. package/dist/prompts/index.js +93 -0
  35. package/dist/prompts/index.js.map +1 -0
  36. package/dist/prompts/onboarding.d.ts +6 -0
  37. package/dist/prompts/onboarding.d.ts.map +1 -0
  38. package/dist/prompts/onboarding.js +37 -0
  39. package/dist/prompts/onboarding.js.map +1 -0
  40. package/dist/prompts/orm.d.ts +3 -0
  41. package/dist/prompts/orm.d.ts.map +1 -0
  42. package/dist/prompts/orm.js +23 -0
  43. package/dist/prompts/orm.js.map +1 -0
  44. package/dist/prompts/packageManager.d.ts +2 -0
  45. package/dist/prompts/packageManager.d.ts.map +1 -0
  46. package/dist/prompts/packageManager.js +18 -0
  47. package/dist/prompts/packageManager.js.map +1 -0
  48. package/dist/prompts/platform.d.ts +3 -0
  49. package/dist/prompts/platform.d.ts.map +1 -0
  50. package/dist/prompts/platform.js +21 -0
  51. package/dist/prompts/platform.js.map +1 -0
  52. package/dist/prompts/preset.d.ts +4 -0
  53. package/dist/prompts/preset.d.ts.map +1 -0
  54. package/dist/prompts/preset.js +165 -0
  55. package/dist/prompts/preset.js.map +1 -0
  56. package/dist/prompts/project.d.ts +2 -0
  57. package/dist/prompts/project.d.ts.map +1 -0
  58. package/dist/prompts/project.js +27 -0
  59. package/dist/prompts/project.js.map +1 -0
  60. package/dist/prompts/sdks.d.ts +2 -0
  61. package/dist/prompts/sdks.d.ts.map +1 -0
  62. package/dist/prompts/sdks.js +46 -0
  63. package/dist/prompts/sdks.js.map +1 -0
  64. package/dist/types/index.d.ts +77 -0
  65. package/dist/types/index.d.ts.map +1 -0
  66. package/dist/types/index.js +25 -0
  67. package/dist/types/index.js.map +1 -0
  68. package/dist/utils/cleanup.d.ts +5 -0
  69. package/dist/utils/cleanup.d.ts.map +1 -0
  70. package/dist/utils/cleanup.js +38 -0
  71. package/dist/utils/cleanup.js.map +1 -0
  72. package/dist/utils/copy.d.ts +10 -0
  73. package/dist/utils/copy.d.ts.map +1 -0
  74. package/dist/utils/copy.js +53 -0
  75. package/dist/utils/copy.js.map +1 -0
  76. package/dist/utils/errors.d.ts +33 -0
  77. package/dist/utils/errors.d.ts.map +1 -0
  78. package/dist/utils/errors.js +136 -0
  79. package/dist/utils/errors.js.map +1 -0
  80. package/dist/utils/git.d.ts +5 -0
  81. package/dist/utils/git.d.ts.map +1 -0
  82. package/dist/utils/git.js +33 -0
  83. package/dist/utils/git.js.map +1 -0
  84. package/dist/utils/logger.d.ts +9 -0
  85. package/dist/utils/logger.d.ts.map +1 -0
  86. package/dist/utils/logger.js +22 -0
  87. package/dist/utils/logger.js.map +1 -0
  88. package/dist/utils/package.d.ts +16 -0
  89. package/dist/utils/package.d.ts.map +1 -0
  90. package/dist/utils/package.js +86 -0
  91. package/dist/utils/package.js.map +1 -0
  92. package/dist/utils/system-validation.d.ts +9 -0
  93. package/dist/utils/system-validation.d.ts.map +1 -0
  94. package/dist/utils/system-validation.js +31 -0
  95. package/dist/utils/system-validation.js.map +1 -0
  96. package/dist/utils/template.d.ts +20 -0
  97. package/dist/utils/template.d.ts.map +1 -0
  98. package/dist/utils/template.js +234 -0
  99. package/dist/utils/template.js.map +1 -0
  100. package/dist/utils/validation.d.ts +8 -0
  101. package/dist/utils/validation.d.ts.map +1 -0
  102. package/dist/utils/validation.js +94 -0
  103. package/dist/utils/validation.js.map +1 -0
  104. package/package.json +96 -0
  105. package/templates/base/backend/.dockerignore.ejs +62 -0
  106. package/templates/base/backend/.env.example.ejs +116 -0
  107. package/templates/base/backend/Dockerfile.ejs +142 -0
  108. package/templates/base/backend/controllers/event-queue/index.ts +20 -0
  109. package/templates/base/backend/controllers/event-queue/workers/user.ts +39 -0
  110. package/templates/base/backend/controllers/rest-api/index.ts +48 -0
  111. package/templates/base/backend/controllers/rest-api/plugins/auth.ts +152 -0
  112. package/templates/base/backend/controllers/rest-api/plugins/config.ts +64 -0
  113. package/templates/base/backend/controllers/rest-api/plugins/error-handler.ts +118 -0
  114. package/templates/base/backend/controllers/rest-api/routes/auth.ts.ejs +180 -0
  115. package/templates/base/backend/controllers/rest-api/routes/device-sessions.ts +197 -0
  116. package/templates/base/backend/controllers/rest-api/routes/oauth-web.ts.ejs +375 -0
  117. package/templates/base/backend/controllers/rest-api/server.ts.ejs +87 -0
  118. package/templates/base/backend/domain/device-session/repository.drizzle.ts +209 -0
  119. package/templates/base/backend/domain/device-session/repository.prisma.ts +248 -0
  120. package/templates/base/backend/domain/device-session/schema.ts +72 -0
  121. package/templates/base/backend/domain/session/repository.drizzle.ts +72 -0
  122. package/templates/base/backend/domain/session/repository.prisma.ts +72 -0
  123. package/templates/base/backend/domain/session/schema.ts +29 -0
  124. package/templates/base/backend/domain/user/repository.drizzle.ts +127 -0
  125. package/templates/base/backend/domain/user/repository.prisma.ts +115 -0
  126. package/templates/base/backend/domain/user/schema.ts +14 -0
  127. package/templates/base/backend/drizzle/schema.drizzle.ts +111 -0
  128. package/templates/base/backend/drizzle.config.drizzle.ts +13 -0
  129. package/templates/base/backend/lib/auth.drizzle.ts.ejs +104 -0
  130. package/templates/base/backend/lib/auth.prisma.ts.ejs +97 -0
  131. package/templates/base/backend/lib/constants.ts.ejs +29 -0
  132. package/templates/base/backend/package.json.ejs +50 -0
  133. package/templates/base/backend/prisma/schema.prisma.ejs +102 -0
  134. package/templates/base/backend/prisma.config.prisma.ts +12 -0
  135. package/templates/base/backend/tsconfig.json +39 -0
  136. package/templates/base/backend/utils/db.drizzle.ts +41 -0
  137. package/templates/base/backend/utils/db.prisma.ts +51 -0
  138. package/templates/base/backend/utils/email.ts.ejs +35 -0
  139. package/templates/base/backend/utils/errors.ts +348 -0
  140. package/templates/base/backend/utils/redis.ts.ejs +279 -0
  141. package/templates/base/mobile/.env.example.ejs +35 -0
  142. package/templates/base/mobile/.gitignore.ejs +167 -0
  143. package/templates/base/mobile/app/+not-found.tsx +85 -0
  144. package/templates/base/mobile/app/_layout.tsx.ejs +71 -0
  145. package/templates/base/mobile/app.json.ejs +88 -0
  146. package/templates/base/mobile/assets/images/adaptive-icon.png +0 -0
  147. package/templates/base/mobile/assets/images/favicon.png +0 -0
  148. package/templates/base/mobile/assets/images/icon.png +0 -0
  149. package/templates/base/mobile/assets/images/onboarding_page_1.png +0 -0
  150. package/templates/base/mobile/assets/images/onboarding_page_2.png +0 -0
  151. package/templates/base/mobile/assets/images/onboarding_page_3.png +0 -0
  152. package/templates/base/mobile/assets/images/paywall_image.png +0 -0
  153. package/templates/base/mobile/assets/images/splash.png +0 -0
  154. package/templates/base/mobile/eas.json.ejs +49 -0
  155. package/templates/base/mobile/metro.config.js +9 -0
  156. package/templates/base/mobile/package.json.ejs +53 -0
  157. package/templates/base/mobile/src/components/ui/Button.tsx +131 -0
  158. package/templates/base/mobile/src/components/ui/Card.tsx +68 -0
  159. package/templates/base/mobile/src/components/ui/IconSymbol.tsx +90 -0
  160. package/templates/base/mobile/src/components/ui/Input.tsx +142 -0
  161. package/templates/base/mobile/src/components/ui/LoadingSpinner.tsx +98 -0
  162. package/templates/base/mobile/src/components/ui/OnboardingLayout.tsx +356 -0
  163. package/templates/base/mobile/src/components/ui/PaywallLayout.tsx +311 -0
  164. package/templates/base/mobile/src/components/ui/Skeleton.tsx +58 -0
  165. package/templates/base/mobile/src/components/ui/index.ts +6 -0
  166. package/templates/base/mobile/src/constants/Theme.ts +163 -0
  167. package/templates/base/mobile/src/context/ThemeContext.tsx +157 -0
  168. package/templates/base/mobile/src/lib/auth-client.ts.ejs +51 -0
  169. package/templates/base/mobile/src/services/api.ts.ejs +71 -0
  170. package/templates/base/mobile/src/services/errorService.ts +179 -0
  171. package/templates/base/mobile/src/services/sdkInitializer.ts.ejs +36 -0
  172. package/templates/base/mobile/src/store/index.ts.ejs +18 -0
  173. package/templates/base/mobile/src/store/ui.store.ts +100 -0
  174. package/templates/base/mobile/src/utils/formatters.ts +105 -0
  175. package/templates/base/mobile/src/utils/logger.ts +73 -0
  176. package/templates/base/mobile/src/utils/responsive.ts +234 -0
  177. package/templates/base/mobile/tsconfig.json +32 -0
  178. package/templates/base/web/.env.example.ejs +26 -0
  179. package/templates/base/web/components.json +22 -0
  180. package/templates/base/web/eslint.config.mjs +18 -0
  181. package/templates/base/web/next.config.ts +7 -0
  182. package/templates/base/web/package.json.ejs +35 -0
  183. package/templates/base/web/postcss.config.mjs +7 -0
  184. package/templates/base/web/public/.gitkeep +0 -0
  185. package/templates/base/web/public/file.svg +1 -0
  186. package/templates/base/web/public/globe.svg +1 -0
  187. package/templates/base/web/public/next.svg +1 -0
  188. package/templates/base/web/public/vercel.svg +1 -0
  189. package/templates/base/web/public/window.svg +1 -0
  190. package/templates/base/web/src/app/favicon.ico +0 -0
  191. package/templates/base/web/src/app/globals.css +152 -0
  192. package/templates/base/web/src/app/layout.tsx.ejs +54 -0
  193. package/templates/base/web/src/app/page.tsx.ejs +92 -0
  194. package/templates/base/web/src/components/auth/auth-hydrator.tsx.ejs +19 -0
  195. package/templates/base/web/src/components/auth/protected-route.tsx.ejs +109 -0
  196. package/templates/base/web/src/components/providers/device-session-setup.tsx.ejs +56 -0
  197. package/templates/base/web/src/components/providers/theme-provider.tsx +17 -0
  198. package/templates/base/web/src/components/theme-toggle.tsx +34 -0
  199. package/templates/base/web/src/components/ui/button.tsx +62 -0
  200. package/templates/base/web/src/components/ui/card.tsx +92 -0
  201. package/templates/base/web/src/components/ui/input.tsx +21 -0
  202. package/templates/base/web/src/components/ui/label.tsx +24 -0
  203. package/templates/base/web/src/components/ui/skeleton.tsx +13 -0
  204. package/templates/base/web/src/components/ui/spinner.tsx +20 -0
  205. package/templates/base/web/src/hooks/use-device-session.ts.ejs +40 -0
  206. package/templates/base/web/src/hooks/use-session.ts.ejs +56 -0
  207. package/templates/base/web/src/lib/auth/actions.ts.ejs +334 -0
  208. package/templates/base/web/src/lib/auth/config.ts.ejs +65 -0
  209. package/templates/base/web/src/lib/auth/cookies.ts.ejs +74 -0
  210. package/templates/base/web/src/lib/auth/index.ts.ejs +40 -0
  211. package/templates/base/web/src/lib/auth/oauth.ts.ejs +72 -0
  212. package/templates/base/web/src/lib/auth/pkce.ts.ejs +48 -0
  213. package/templates/base/web/src/lib/auth/sessions.ts.ejs +135 -0
  214. package/templates/base/web/src/lib/auth/user-agent.ts.ejs +47 -0
  215. package/templates/base/web/src/lib/device/actions.ts.ejs +148 -0
  216. package/templates/base/web/src/lib/device/id.ts.ejs +74 -0
  217. package/templates/base/web/src/lib/utils.ts +6 -0
  218. package/templates/base/web/src/proxy.ts.ejs +66 -0
  219. package/templates/base/web/src/store/auth.store.ts.ejs +89 -0
  220. package/templates/base/web/src/store/deviceSession.store.ts.ejs +141 -0
  221. package/templates/base/web/tsconfig.json +34 -0
  222. package/templates/features/mobile/auth/app/(auth)/_layout.tsx +16 -0
  223. package/templates/features/mobile/auth/app/(auth)/login.tsx +86 -0
  224. package/templates/features/mobile/auth/app/(auth)/register.tsx +86 -0
  225. package/templates/features/mobile/auth/components/auth/LoginForm.tsx.ejs +349 -0
  226. package/templates/features/mobile/auth/components/auth/RegisterForm.tsx.ejs +407 -0
  227. package/templates/features/mobile/auth/components/auth/index.ts +2 -0
  228. package/templates/features/mobile/auth/hooks/index.ts.ejs +1 -0
  229. package/templates/features/mobile/auth/hooks/useAuth.ts.ejs +367 -0
  230. package/templates/features/mobile/auth/services/deviceSession.ts +370 -0
  231. package/templates/features/mobile/auth/store/deviceSession.store.ts +326 -0
  232. package/templates/features/mobile/onboarding/app/(onboarding)/_layout.tsx.ejs +11 -0
  233. package/templates/features/mobile/onboarding/app/(onboarding)/page-1.tsx.ejs +52 -0
  234. package/templates/features/mobile/onboarding/app/(onboarding)/page-2.tsx.ejs +52 -0
  235. package/templates/features/mobile/onboarding/app/(onboarding)/page-3.tsx.ejs +60 -0
  236. package/templates/features/mobile/paywall/app/paywall.tsx +550 -0
  237. package/templates/features/mobile/tabs/app/(tabs)/_layout.tsx +26 -0
  238. package/templates/features/mobile/tabs/app/(tabs)/index.tsx +565 -0
  239. package/templates/features/web/.gitkeep +0 -0
  240. package/templates/features/web/auth/app/(app)/dashboard/dashboard-client.tsx.ejs +166 -0
  241. package/templates/features/web/auth/app/(app)/dashboard/page.tsx.ejs +24 -0
  242. package/templates/features/web/auth/app/(app)/layout.tsx.ejs +43 -0
  243. package/templates/features/web/auth/app/(app)/settings/sessions/page.tsx.ejs +29 -0
  244. package/templates/features/web/auth/app/(app)/settings/sessions/sessions-client.tsx.ejs +77 -0
  245. package/templates/features/web/auth/app/(auth)/forgot-password/page.tsx.ejs +127 -0
  246. package/templates/features/web/auth/app/(auth)/layout.tsx.ejs +32 -0
  247. package/templates/features/web/auth/app/(auth)/login/page.tsx.ejs +35 -0
  248. package/templates/features/web/auth/app/(auth)/register/page.tsx.ejs +19 -0
  249. package/templates/features/web/auth/app/(auth)/reset-password/page.tsx.ejs +40 -0
  250. package/templates/features/web/auth/app/(auth)/verify-email/page.tsx.ejs +198 -0
  251. package/templates/features/web/auth/app/auth/callback/route.ts.ejs +152 -0
  252. package/templates/features/web/auth/components/auth/login-form.tsx.ejs +100 -0
  253. package/templates/features/web/auth/components/auth/oauth-buttons.tsx.ejs +126 -0
  254. package/templates/features/web/auth/components/auth/password-reset-form.tsx.ejs +103 -0
  255. package/templates/features/web/auth/components/auth/register-form.tsx.ejs +139 -0
  256. package/templates/features/web/auth/components/settings/session-card.tsx.ejs +132 -0
  257. package/templates/integrations/mobile/adjust/services/adjustService.ts.ejs +163 -0
  258. package/templates/integrations/mobile/adjust/store/adjust.store.ts +243 -0
  259. package/templates/integrations/mobile/att/services/attService.ts +84 -0
  260. package/templates/integrations/mobile/att/services/trackingPermissions.ts +208 -0
  261. package/templates/integrations/mobile/att/store/att.store.ts +162 -0
  262. package/templates/integrations/mobile/revenuecat/services/revenuecatService.ts.ejs +174 -0
  263. package/templates/integrations/mobile/revenuecat/store/revenuecat.store.ts +286 -0
  264. package/templates/integrations/mobile/scate/services/scateService.ts.ejs +85 -0
  265. package/templates/integrations/mobile/scate/store/scate.store.ts +125 -0
  266. package/templates/integrations/web/.gitkeep +0 -0
  267. package/templates/shared/.env.example.ejs +21 -0
  268. package/templates/shared/.gitignore.ejs +145 -0
  269. package/templates/shared/README.md.ejs +134 -0
  270. package/templates/shared/docker-compose.prod.yml.ejs +120 -0
  271. package/templates/shared/docker-compose.yml.ejs +129 -0
  272. package/templates/shared/scripts/docker-dev.sh.ejs +395 -0
  273. package/templates/shared/scripts/docker-prod.sh.ejs +542 -0
  274. package/templates/shared/scripts/setup.sh.ejs +979 -0
@@ -0,0 +1,8 @@
1
+ import type { ProjectConfig } from '../types/index.js';
2
+ /**
3
+ * Generate dynamic onboarding pages based on configuration
4
+ * Note: Templates already have pages 1-3, so we only generate pages 4-5 if needed
5
+ * Onboarding is a mobile-only feature
6
+ */
7
+ export declare function generateOnboardingPages(config: ProjectConfig, targetDir: string): Promise<void>;
8
+ //# sourceMappingURL=onboarding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/generators/onboarding.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAwCf"}
@@ -0,0 +1,141 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ /**
4
+ * Generate dynamic onboarding pages based on configuration
5
+ * Note: Templates already have pages 1-3, so we only generate pages 4-5 if needed
6
+ * Onboarding is a mobile-only feature
7
+ */
8
+ export async function generateOnboardingPages(config, targetDir) {
9
+ // Onboarding is mobile-only - skip if mobile platform not selected
10
+ if (!config.platforms.includes('mobile')) {
11
+ return;
12
+ }
13
+ if (!config.features.onboarding.enabled) {
14
+ return;
15
+ }
16
+ const { pages, skipButton, showPaywall } = config.features.onboarding;
17
+ // Templates already include pages 1-3
18
+ // Only generate additional pages if needed (4-5)
19
+ if (pages <= 3) {
20
+ return;
21
+ }
22
+ const onboardingDir = path.join(targetDir, 'mobile/app/(onboarding)');
23
+ await fs.ensureDir(onboardingDir);
24
+ // Generate pages 4-5
25
+ for (let i = 4; i <= pages; i++) {
26
+ const isLastPage = i === pages;
27
+ const pageContent = generatePageContent({
28
+ pageNumber: i,
29
+ totalPages: pages,
30
+ isFirstPage: false,
31
+ isLastPage,
32
+ skipButton,
33
+ showPaywall: showPaywall && isLastPage,
34
+ hasPaywall: config.integrations.revenueCat.enabled,
35
+ });
36
+ await fs.writeFile(path.join(onboardingDir, `page-${i}.tsx`), pageContent);
37
+ }
38
+ // Update _layout.tsx to include all pages
39
+ await updateOnboardingLayout(pages, onboardingDir);
40
+ }
41
+ function generatePageContent(options) {
42
+ const { pageNumber, totalPages, isLastPage, skipButton, showPaywall } = options;
43
+ const nextAction = isLastPage
44
+ ? showPaywall
45
+ ? "router.replace('/paywall');"
46
+ : "router.replace('/(tabs)');"
47
+ : `router.push('/(onboarding)/page-${pageNumber + 1}');`;
48
+ return `import { View, Text, StyleSheet } from 'react-native';
49
+ import { useRouter } from 'expo-router';
50
+ import { Button } from '@/components/ui/Button';
51
+ import { OnboardingLayout } from '@/components/ui/OnboardingLayout';
52
+
53
+ export default function OnboardingPage${pageNumber}() {
54
+ const router = useRouter();
55
+
56
+ const handleNext = () => {
57
+ ${nextAction}
58
+ };
59
+
60
+ ${skipButton
61
+ ? `const handleSkip = () => {
62
+ router.replace('/(tabs)');
63
+ };`
64
+ : ''}
65
+
66
+ return (
67
+ <OnboardingLayout
68
+ currentPage={${pageNumber}}
69
+ totalPages={${totalPages}}
70
+ ${skipButton ? 'onSkip={handleSkip}' : ''}
71
+ >
72
+ <View style={styles.container}>
73
+ <Text style={styles.title}>Welcome to Your App</Text>
74
+ <Text style={styles.description}>
75
+ This is onboarding page ${pageNumber} of ${totalPages}. Customize this content to guide your users.
76
+ </Text>
77
+
78
+ <Button onPress={handleNext} style={styles.button}>
79
+ ${isLastPage ? 'Get Started' : 'Next'}
80
+ </Button>
81
+ </View>
82
+ </OnboardingLayout>
83
+ );
84
+ }
85
+
86
+ const styles = StyleSheet.create({
87
+ container: {
88
+ flex: 1,
89
+ justifyContent: 'center',
90
+ alignItems: 'center',
91
+ padding: 20,
92
+ },
93
+ title: {
94
+ fontSize: 28,
95
+ fontWeight: 'bold',
96
+ marginBottom: 16,
97
+ textAlign: 'center',
98
+ },
99
+ description: {
100
+ fontSize: 16,
101
+ color: '#666',
102
+ textAlign: 'center',
103
+ marginBottom: 32,
104
+ paddingHorizontal: 20,
105
+ },
106
+ button: {
107
+ minWidth: 200,
108
+ },
109
+ });
110
+ `;
111
+ }
112
+ async function updateOnboardingLayout(totalPages, onboardingDir) {
113
+ const layoutPath = path.join(onboardingDir, '_layout.tsx');
114
+ // Check if layout exists
115
+ if (!(await fs.pathExists(layoutPath))) {
116
+ // Create new layout
117
+ const layoutContent = generateOnboardingLayout(totalPages);
118
+ await fs.writeFile(layoutPath, layoutContent);
119
+ }
120
+ else {
121
+ // Update existing layout to include all pages
122
+ const layoutContent = generateOnboardingLayout(totalPages);
123
+ await fs.writeFile(layoutPath, layoutContent);
124
+ }
125
+ }
126
+ function generateOnboardingLayout(totalPages) {
127
+ const screenImports = Array.from({ length: totalPages }, (_, i) => i + 1)
128
+ .map((i) => ` <Stack.Screen name="page-${i}" />`)
129
+ .join('\n');
130
+ return `import { Stack } from 'expo-router';
131
+
132
+ export default function OnboardingLayout() {
133
+ return (
134
+ <Stack screenOptions={{ headerShown: false }}>
135
+ ${screenImports}
136
+ </Stack>
137
+ );
138
+ }
139
+ `;
140
+ }
141
+ //# sourceMappingURL=onboarding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.js","sourceRoot":"","sources":["../../src/generators/onboarding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import chalk from 'chalk';
4
+ import boxen from 'boxen';
5
+ import { runCLI } from './cli.js';
6
+ import { displayError } from './utils/errors.js';
7
+ import { validateNodeVersion } from './utils/system-validation.js';
8
+ import { readFileSync } from 'fs';
9
+ import { fileURLToPath } from 'url';
10
+ import { dirname, join } from 'path';
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = dirname(__filename);
13
+ const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
14
+ // Validate Node.js version before proceeding
15
+ try {
16
+ validateNodeVersion();
17
+ }
18
+ catch (error) {
19
+ displayError(error);
20
+ process.exit(1);
21
+ }
22
+ // Welcome banner
23
+ function displayWelcome() {
24
+ console.log(boxen(chalk.bold.cyan('Welcome to create-fullstack-app!\n\n') +
25
+ chalk.white('Create a production-ready full-stack mobile app\n') +
26
+ chalk.white('with backend infrastructure in minutes.'), {
27
+ padding: 1,
28
+ margin: 1,
29
+ borderStyle: 'round',
30
+ borderColor: 'cyan',
31
+ }));
32
+ }
33
+ // Configure CLI
34
+ program
35
+ .name('create-fullstack-app')
36
+ .description('Create a production-ready full-stack mobile app')
37
+ .version(packageJson.version)
38
+ .argument('[project-name]', 'Name of the project')
39
+ .option('-t, --template <preset>', 'Use a preset template (minimal, full-featured, analytics-focused)')
40
+ .option('--defaults', 'Use default configuration without prompts')
41
+ .option('--verbose', 'Show detailed output')
42
+ .action(async (projectName, options) => {
43
+ try {
44
+ displayWelcome();
45
+ await runCLI(projectName, options);
46
+ }
47
+ catch (error) {
48
+ displayError(error);
49
+ process.exit(1);
50
+ }
51
+ });
52
+ // Add help text
53
+ program.addHelpText('after', `
54
+
55
+ Examples:
56
+ $ npx create-fullstack-app my-app
57
+ $ npx create-fullstack-app my-app --template minimal
58
+ $ npx create-fullstack-app my-app --defaults
59
+
60
+ For more information, visit:
61
+ https://docs.create-fullstack-app.dev
62
+ `);
63
+ // Parse arguments
64
+ program.parse();
65
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAErC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAC1D,CAAC;AAEF,6CAA6C;AAC7C,IAAI,CAAC;IACH,mBAAmB,EAAE,CAAC;AACxB,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,YAAY,CAAC,KAAc,CAAC,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,iBAAiB;AACjB,SAAS,cAAc;IACrB,OAAO,CAAC,GAAG,CACT,KAAK,CACH,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,sCAAsC,CAAC;QACrD,KAAK,CAAC,KAAK,CAAC,mDAAmD,CAAC;QAChE,KAAK,CAAC,KAAK,CAAC,yCAAyC,CAAC,EACxD;QACE,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,CAAC;QACT,WAAW,EAAE,OAAO;QACpB,WAAW,EAAE,MAAM;KACpB,CACF,CACF,CAAC;AACJ,CAAC;AAED,gBAAgB;AAChB,OAAO;KACJ,IAAI,CAAC,sBAAsB,CAAC;KAC5B,WAAW,CAAC,iDAAiD,CAAC;KAC9D,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,CAAC;KACjD,MAAM,CACL,yBAAyB,EACzB,mEAAmE,CACpE;KACA,MAAM,CAAC,YAAY,EAAE,2CAA2C,CAAC;KACjE,MAAM,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC3C,MAAM,CAAC,KAAK,EAAE,WAA+B,EAAE,OAAY,EAAE,EAAE;IAC9D,IAAI,CAAC;QACH,cAAc,EAAE,CAAC;QACjB,MAAM,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,YAAY,CAAC,KAAc,CAAC,CAAC;QAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,gBAAgB;AAChB,OAAO,CAAC,WAAW,CACjB,OAAO,EACP;;;;;;;;;CASD,CACA,CAAC;AAEF,kBAAkB;AAClB,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface AuthenticationConfig {
2
+ enabled: boolean;
3
+ providers: {
4
+ emailPassword: boolean;
5
+ google: boolean;
6
+ apple: boolean;
7
+ github: boolean;
8
+ };
9
+ emailVerification: boolean;
10
+ passwordReset: boolean;
11
+ twoFactor: boolean;
12
+ }
13
+ export declare function promptFeatures(): Promise<any>;
14
+ //# sourceMappingURL=features.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../../src/prompts/features.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE;QACT,aAAa,EAAE,OAAO,CAAC;QACvB,MAAM,EAAE,OAAO,CAAC;QAChB,KAAK,EAAE,OAAO,CAAC;QACf,MAAM,EAAE,OAAO,CAAC;KACjB,CAAC;IACF,iBAAiB,EAAE,OAAO,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,CAkGnD"}
@@ -0,0 +1,96 @@
1
+ import inquirer from 'inquirer';
2
+ export async function promptFeatures() {
3
+ // First, ask about basic features
4
+ const basicFeatures = await inquirer.prompt([
5
+ {
6
+ type: 'checkbox',
7
+ name: 'features',
8
+ message: 'Select features to include:',
9
+ choices: [
10
+ {
11
+ name: 'Onboarding Flow - Multi-step user onboarding',
12
+ value: 'onboarding',
13
+ checked: true,
14
+ },
15
+ {
16
+ name: 'Authentication - User authentication with BetterAuth',
17
+ value: 'authentication',
18
+ checked: true,
19
+ },
20
+ {
21
+ name: 'Subscription Paywall - RevenueCat integration',
22
+ value: 'paywall',
23
+ checked: false,
24
+ },
25
+ {
26
+ name: 'Session Management - Anonymous device session tracking',
27
+ value: 'sessionManagement',
28
+ checked: true,
29
+ },
30
+ ],
31
+ },
32
+ ]);
33
+ const hasAuth = basicFeatures.features.includes('authentication');
34
+ // Default auth config (used when auth is disabled)
35
+ let authConfig = {
36
+ enabled: false,
37
+ providers: {
38
+ emailPassword: true,
39
+ google: false,
40
+ apple: false,
41
+ github: false,
42
+ },
43
+ emailVerification: false,
44
+ passwordReset: false,
45
+ twoFactor: false,
46
+ };
47
+ // If auth is enabled, ask about OAuth providers and features
48
+ if (hasAuth) {
49
+ const authDetails = await inquirer.prompt([
50
+ {
51
+ type: 'checkbox',
52
+ name: 'providers',
53
+ message: 'Select OAuth providers to enable:',
54
+ choices: [
55
+ { name: 'Google', value: 'google', checked: false },
56
+ { name: 'Apple', value: 'apple', checked: false },
57
+ { name: 'GitHub', value: 'github', checked: false },
58
+ ],
59
+ },
60
+ {
61
+ type: 'checkbox',
62
+ name: 'authFeatures',
63
+ message: 'Select additional auth features:',
64
+ choices: [
65
+ { name: 'Email Verification', value: 'emailVerification', checked: false },
66
+ { name: 'Password Reset', value: 'passwordReset', checked: true },
67
+ { name: 'Two-Factor Authentication (TOTP)', value: 'twoFactor', checked: false },
68
+ ],
69
+ },
70
+ ]);
71
+ authConfig = {
72
+ enabled: true,
73
+ providers: {
74
+ emailPassword: true,
75
+ google: authDetails.providers.includes('google'),
76
+ apple: authDetails.providers.includes('apple'),
77
+ github: authDetails.providers.includes('github'),
78
+ },
79
+ emailVerification: authDetails.authFeatures.includes('emailVerification'),
80
+ passwordReset: authDetails.authFeatures.includes('passwordReset'),
81
+ twoFactor: authDetails.authFeatures.includes('twoFactor'),
82
+ };
83
+ }
84
+ return {
85
+ onboarding: {
86
+ enabled: basicFeatures.features.includes('onboarding'),
87
+ pages: 3, // Will be configured later if enabled
88
+ skipButton: false,
89
+ showPaywall: false,
90
+ },
91
+ authentication: authConfig,
92
+ paywall: basicFeatures.features.includes('paywall'),
93
+ sessionManagement: basicFeatures.features.includes('sessionManagement'),
94
+ };
95
+ }
96
+ //# sourceMappingURL=features.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.js","sourceRoot":"","sources":["../../src/prompts/features.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectConfig, CLIOptions } from '../types/index.js';
2
+ export declare function collectConfiguration(projectName: string | undefined, options: CLIOptions): Promise<ProjectConfig>;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGnE,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,aAAa,CAAC,CA+CxB"}
@@ -0,0 +1,93 @@
1
+ import { promptProjectName } from './project.js';
2
+ import { selectPreset, customizePreset } from './preset.js';
3
+ import { promptFeatures } from './features.js';
4
+ import { promptSDKs } from './sdks.js';
5
+ import { promptOnboarding } from './onboarding.js';
6
+ import { promptPackageManager } from './packageManager.js';
7
+ import { promptORM } from './orm.js';
8
+ import { promptPlatforms } from './platform.js';
9
+ import { PRESETS } from '../config/presets.js';
10
+ import { deriveAppScheme } from '../types/index.js';
11
+ export async function collectConfiguration(projectName, options) {
12
+ // 1. Get project name
13
+ const name = await promptProjectName(projectName);
14
+ // 2. If --template flag is provided, load that preset
15
+ if (options.template) {
16
+ const config = await loadPresetByName(options.template);
17
+ const packageManager = await promptPackageManager();
18
+ return {
19
+ ...config,
20
+ projectName: name,
21
+ appScheme: deriveAppScheme(name),
22
+ packageManager,
23
+ };
24
+ }
25
+ // 3. If --defaults flag, use minimal preset
26
+ if (options.defaults) {
27
+ const config = await loadPresetByName('minimal');
28
+ return {
29
+ ...config,
30
+ projectName: name,
31
+ appScheme: deriveAppScheme(name),
32
+ packageManager: 'npm',
33
+ };
34
+ }
35
+ // 4. Interactive mode: Select preset or custom
36
+ let config = await selectPreset();
37
+ // 5. If custom selected, collect full configuration
38
+ if (!config) {
39
+ config = await collectCustomConfiguration();
40
+ }
41
+ else {
42
+ // Ask if user wants to customize the preset
43
+ config = await customizePreset(config);
44
+ }
45
+ // 6. Get package manager
46
+ const packageManager = await promptPackageManager();
47
+ return {
48
+ ...config,
49
+ projectName: name,
50
+ appScheme: deriveAppScheme(name),
51
+ packageManager,
52
+ };
53
+ }
54
+ async function collectCustomConfiguration() {
55
+ // Platform selection FIRST (foundational choice)
56
+ const platforms = await promptPlatforms();
57
+ // ORM selection (foundational choice)
58
+ const orm = await promptORM();
59
+ // Collect features
60
+ const features = await promptFeatures();
61
+ // Collect SDK integrations
62
+ const integrations = await promptSDKs();
63
+ // If onboarding enabled, collect onboarding config
64
+ if (features.onboarding.enabled) {
65
+ const onboardingConfig = await promptOnboarding(integrations.revenueCat.enabled);
66
+ features.onboarding = { ...features.onboarding, ...onboardingConfig };
67
+ }
68
+ // Auto-enable ATT if Adjust is enabled
69
+ if (integrations.adjust.enabled) {
70
+ integrations.att.enabled = true;
71
+ }
72
+ return {
73
+ platforms,
74
+ features,
75
+ integrations,
76
+ backend: {
77
+ database: 'postgresql',
78
+ orm,
79
+ eventQueue: true,
80
+ docker: true,
81
+ },
82
+ preset: 'custom',
83
+ customized: false,
84
+ };
85
+ }
86
+ async function loadPresetByName(presetName) {
87
+ const preset = PRESETS.find((p) => p.name.toLowerCase() === presetName.toLowerCase());
88
+ if (!preset) {
89
+ throw new Error(`Unknown preset: ${presetName}. Available: minimal, full-featured, analytics-focused`);
90
+ }
91
+ return preset.config;
92
+ }
93
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function promptOnboarding(hasRevenueCat: boolean): Promise<{
2
+ pages: number;
3
+ skipButton: boolean;
4
+ showPaywall: boolean;
5
+ }>;
6
+ //# sourceMappingURL=onboarding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.d.ts","sourceRoot":"","sources":["../../src/prompts/onboarding.ts"],"names":[],"mappings":"AAEA,wBAAsB,gBAAgB,CACpC,aAAa,EAAE,OAAO,GACrB,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC,CAmCvE"}
@@ -0,0 +1,37 @@
1
+ import inquirer from 'inquirer';
2
+ export async function promptOnboarding(hasRevenueCat) {
3
+ // @ts-expect-error - inquirer types are too strict for our use case
4
+ const answers = await inquirer.prompt([
5
+ {
6
+ type: 'number',
7
+ name: 'pages',
8
+ message: 'How many onboarding pages?',
9
+ default: 3,
10
+ validate: (input) => {
11
+ if (input < 1 || input > 5) {
12
+ return 'Please enter a number between 1 and 5';
13
+ }
14
+ return true;
15
+ },
16
+ },
17
+ {
18
+ type: 'confirm',
19
+ name: 'skipButton',
20
+ message: 'Include skip button?',
21
+ default: true,
22
+ },
23
+ {
24
+ type: 'confirm',
25
+ name: 'showPaywall',
26
+ message: 'Show paywall after onboarding?',
27
+ default: false,
28
+ when: () => hasRevenueCat,
29
+ },
30
+ ]);
31
+ return {
32
+ pages: answers.pages,
33
+ skipButton: answers.skipButton,
34
+ showPaywall: answers.showPaywall || false,
35
+ };
36
+ }
37
+ //# sourceMappingURL=onboarding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding.js","sourceRoot":"","sources":["../../src/prompts/onboarding.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAEhC,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,aAAsB;IAEtB,oEAAoE;IACpE,MAAM,OAAO,GAAQ,MAAM,QAAQ,CAAC,MAAM,CAAC;QACzC;YACE,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,4BAA4B;YACrC,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE;gBAC1B,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;oBAC3B,OAAO,uCAAuC,CAAC;gBACjD,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;SACF;QACD;YACE,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,sBAAsB;YAC/B,OAAO,EAAE,IAAI;SACd;QACD;YACE,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,gCAAgC;YACzC,OAAO,EAAE,KAAK;YACd,IAAI,EAAE,GAAG,EAAE,CAAC,aAAa;SAC1B;KACF,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,KAAK;KAC1C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ORMChoice } from '../types/index.js';
2
+ export declare function promptORM(): Promise<ORMChoice>;
3
+ //# sourceMappingURL=orm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orm.d.ts","sourceRoot":"","sources":["../../src/prompts/orm.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,wBAAsB,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC,CAqBpD"}
@@ -0,0 +1,23 @@
1
+ import inquirer from 'inquirer';
2
+ export async function promptORM() {
3
+ const { orm } = await inquirer.prompt([
4
+ {
5
+ type: 'list',
6
+ name: 'orm',
7
+ message: 'Select your ORM:',
8
+ choices: [
9
+ {
10
+ name: 'Prisma - Type-safe ORM with auto-generated client',
11
+ value: 'prisma',
12
+ },
13
+ {
14
+ name: 'Drizzle - Lightweight, SQL-first TypeScript ORM',
15
+ value: 'drizzle',
16
+ },
17
+ ],
18
+ default: 'prisma',
19
+ },
20
+ ]);
21
+ return orm;
22
+ }
23
+ //# sourceMappingURL=orm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orm.js","sourceRoot":"","sources":["../../src/prompts/orm.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAGhC,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QACpC;YACE,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,mDAAmD;oBACzD,KAAK,EAAE,QAAQ;iBAChB;gBACD;oBACE,IAAI,EAAE,iDAAiD;oBACvD,KAAK,EAAE,SAAS;iBACjB;aACF;YACD,OAAO,EAAE,QAAQ;SAClB;KACF,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function promptPackageManager(): Promise<'npm' | 'yarn' | 'bun'>;
2
+ //# sourceMappingURL=packageManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packageManager.d.ts","sourceRoot":"","sources":["../../src/prompts/packageManager.ts"],"names":[],"mappings":"AAEA,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC,CAgB5E"}
@@ -0,0 +1,18 @@
1
+ import inquirer from 'inquirer';
2
+ export async function promptPackageManager() {
3
+ const { packageManager } = await inquirer.prompt([
4
+ {
5
+ type: 'list',
6
+ name: 'packageManager',
7
+ message: 'Which package manager do you want to use?',
8
+ choices: [
9
+ { name: 'npm', value: 'npm' },
10
+ { name: 'yarn', value: 'yarn' },
11
+ { name: 'bun', value: 'bun' },
12
+ ],
13
+ default: 'npm',
14
+ },
15
+ ]);
16
+ return packageManager;
17
+ }
18
+ //# sourceMappingURL=packageManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packageManager.js","sourceRoot":"","sources":["../../src/prompts/packageManager.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAEhC,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QAC/C;YACE,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,2CAA2C;YACpD,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;gBAC7B,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;gBAC/B,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE;aAC9B;YACD,OAAO,EAAE,KAAK;SACf;KACF,CAAC,CAAC;IAEH,OAAO,cAAc,CAAC;AACxB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Platform } from '../types/index.js';
2
+ export declare function promptPlatforms(): Promise<Platform[]>;
3
+ //# sourceMappingURL=platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/prompts/platform.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,wBAAsB,eAAe,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAoB3D"}
@@ -0,0 +1,21 @@
1
+ import inquirer from 'inquirer';
2
+ export async function promptPlatforms() {
3
+ const { platforms } = await inquirer.prompt([
4
+ {
5
+ type: 'checkbox',
6
+ name: 'platforms',
7
+ message: 'Which platforms do you want to generate?',
8
+ choices: [
9
+ { name: 'Mobile (Expo/React Native)', value: 'mobile', checked: true },
10
+ { name: 'Web (Next.js)', value: 'web', checked: true },
11
+ ],
12
+ },
13
+ ]);
14
+ // Ensure at least one platform is selected
15
+ if (platforms.length === 0) {
16
+ console.log('At least one platform is required. Defaulting to both platforms.');
17
+ return ['mobile', 'web'];
18
+ }
19
+ return platforms;
20
+ }
21
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/prompts/platform.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAGhC,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QAC1C;YACE,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,0CAA0C;YACnD,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,4BAA4B,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE;gBACtE,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE;aACvD;SACF;KACF,CAAC,CAAC;IAEH,2CAA2C;IAC3C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;QAChF,OAAO,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { ProjectConfig } from '../types/index.js';
2
+ export declare function selectPreset(): Promise<Omit<ProjectConfig, 'projectName' | 'packageManager' | 'appScheme'> | null>;
3
+ export declare function customizePreset(config: Omit<ProjectConfig, 'projectName' | 'packageManager' | 'appScheme'>): Promise<Omit<ProjectConfig, 'projectName' | 'packageManager' | 'appScheme'>>;
4
+ //# sourceMappingURL=preset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/prompts/preset.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,wBAAsB,YAAY,IAAI,OAAO,CAC3C,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,gBAAgB,GAAG,WAAW,CAAC,GAAG,IAAI,CAC3E,CAoCA;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,gBAAgB,GAAG,WAAW,CAAC,GAC1E,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,GAAG,gBAAgB,GAAG,WAAW,CAAC,CAAC,CAwH9E"}