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,234 @@
1
+ import ejs from 'ejs';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { dirname } from 'path';
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+ // Get template directory path
9
+ export const TEMPLATE_DIR = path.join(__dirname, '../../templates');
10
+ /**
11
+ * Render an EJS template with configuration
12
+ */
13
+ export async function renderTemplate(templatePath, config) {
14
+ const fullPath = path.join(TEMPLATE_DIR, templatePath);
15
+ if (!(await fs.pathExists(fullPath))) {
16
+ throw new Error(`Template not found: ${templatePath}`);
17
+ }
18
+ const content = await fs.readFile(fullPath, 'utf-8');
19
+ return ejs.render(content, config);
20
+ }
21
+ /**
22
+ * Check if a file should be included based on configuration
23
+ */
24
+ export function shouldIncludeFile(filePath, config) {
25
+ // Skip .gitkeep files - they are only for version control
26
+ if (filePath.endsWith('.gitkeep')) {
27
+ return false;
28
+ }
29
+ // ==========================================================================
30
+ // Platform-based filtering (consistent architecture)
31
+ // ==========================================================================
32
+ // All platform-specific content lives under /mobile/ or /web/ subdirectories:
33
+ // - base/mobile/, features/mobile/, integrations/mobile/ → mobile platform
34
+ // - base/web/, features/web/, integrations/web/ → web platform
35
+ // - base/backend/, shared/ → always included (platform-agnostic)
36
+ // Exclude mobile-specific content when mobile platform not selected
37
+ if (filePath.includes('/mobile/') && !config.platforms.includes('mobile')) {
38
+ return false;
39
+ }
40
+ // Exclude web-specific content when web platform not selected
41
+ if (filePath.includes('/web/') && !config.platforms.includes('web')) {
42
+ return false;
43
+ }
44
+ // Check if file is in a conditional directory
45
+ if (filePath.includes('features/mobile/onboarding') && !config.features.onboarding.enabled) {
46
+ return false;
47
+ }
48
+ // Auth check updated for new structure (mobile)
49
+ if (filePath.includes('features/mobile/auth') && !config.features.authentication.enabled) {
50
+ return false;
51
+ }
52
+ // Web auth check (mirrors mobile auth check)
53
+ if (filePath.includes('features/web/auth') && !config.features.authentication.enabled) {
54
+ return false;
55
+ }
56
+ // Email verification screens
57
+ if (filePath.includes('verify-email') && !config.features.authentication.emailVerification) {
58
+ return false;
59
+ }
60
+ // Password reset screens
61
+ if ((filePath.includes('forgot-password') || filePath.includes('reset-password')) &&
62
+ !config.features.authentication.passwordReset) {
63
+ return false;
64
+ }
65
+ // Two-factor screens (future scope)
66
+ if (filePath.includes('two-factor') && !config.features.authentication.twoFactor) {
67
+ return false;
68
+ }
69
+ if (filePath.includes('features/mobile/paywall') && !config.features.paywall) {
70
+ return false;
71
+ }
72
+ // Note: Tabs templates are always included (not conditional)
73
+ if (filePath.includes('integrations/mobile/revenuecat') && !config.integrations.revenueCat.enabled) {
74
+ return false;
75
+ }
76
+ if (filePath.includes('integrations/mobile/adjust') && !config.integrations.adjust.enabled) {
77
+ return false;
78
+ }
79
+ if (filePath.includes('integrations/mobile/scate') && !config.integrations.scate.enabled) {
80
+ return false;
81
+ }
82
+ if (filePath.includes('integrations/mobile/att') && !config.integrations.att.enabled) {
83
+ return false;
84
+ }
85
+ // Only include SDK initializer if at least one SDK integration is enabled
86
+ if (filePath.includes('services/sdkInitializer')) {
87
+ const hasAnySdk = config.integrations.revenueCat.enabled ||
88
+ config.integrations.adjust.enabled ||
89
+ config.integrations.scate.enabled;
90
+ return hasAnySdk;
91
+ }
92
+ // Backend conditional files
93
+ if (filePath.includes('controllers/event-queue') && !config.backend.eventQueue) {
94
+ return false;
95
+ }
96
+ // Email service - only include when email verification or password reset is enabled
97
+ if (filePath.includes('utils/email') &&
98
+ !config.features.authentication.emailVerification &&
99
+ !config.features.authentication.passwordReset) {
100
+ return false;
101
+ }
102
+ // ORM-specific file filtering
103
+ const orm = config.backend.orm;
104
+ // Prisma-specific: filter entire prisma/ directory and .prisma.ts suffix files
105
+ if (orm !== 'prisma') {
106
+ // Matches: prisma/schema.prisma.ejs, prisma/generated/*, prisma/migrations/*, etc.
107
+ if (filePath.includes('/prisma/')) {
108
+ return false;
109
+ }
110
+ // Matches: db.prisma.ts, auth.prisma.ts.ejs, prisma.config.prisma.ts, etc.
111
+ if (filePath.includes('.prisma.ts')) {
112
+ return false;
113
+ }
114
+ }
115
+ // Drizzle-specific: filter entire drizzle/ directory and .drizzle.ts suffix files
116
+ if (orm !== 'drizzle') {
117
+ // Matches: drizzle/schema.drizzle.ts, drizzle/migrations/*, etc.
118
+ if (filePath.includes('/drizzle/')) {
119
+ return false;
120
+ }
121
+ // Matches: db.drizzle.ts, auth.drizzle.ts.ejs, drizzle.config.drizzle.ts, etc.
122
+ if (filePath.includes('.drizzle.ts')) {
123
+ return false;
124
+ }
125
+ }
126
+ return true;
127
+ }
128
+ /**
129
+ * Check if a file is an EJS template
130
+ */
131
+ export function isTemplate(filePath) {
132
+ return filePath.endsWith('.ejs');
133
+ }
134
+ /**
135
+ * Get destination path for a template file
136
+ * Removes .ejs extension and maps template path to project path
137
+ */
138
+ export function getDestinationPath(templatePath, targetDir) {
139
+ let relativePath = templatePath;
140
+ // Remove templates/ prefix
141
+ if (relativePath.startsWith('templates/')) {
142
+ relativePath = relativePath.substring('templates/'.length);
143
+ }
144
+ // ==========================================================================
145
+ // Platform base paths
146
+ // ==========================================================================
147
+ // base/mobile/* → mobile/*
148
+ if (relativePath.startsWith('base/mobile/')) {
149
+ relativePath = relativePath.substring('base/'.length);
150
+ }
151
+ // base/backend/* → backend/*
152
+ else if (relativePath.startsWith('base/backend/')) {
153
+ relativePath = relativePath.substring('base/'.length);
154
+ }
155
+ // base/web/* → web/*
156
+ else if (relativePath.startsWith('base/web/')) {
157
+ relativePath = relativePath.substring('base/'.length);
158
+ }
159
+ // ==========================================================================
160
+ // Mobile features and integrations (now under /mobile/ subdirectory)
161
+ // ==========================================================================
162
+ // features/mobile/*/app/* → mobile/app/*
163
+ else if (relativePath.startsWith('features/mobile/')) {
164
+ const featurePath = relativePath.substring('features/mobile/'.length);
165
+ const restOfPath = featurePath.substring(featurePath.indexOf('/') + 1);
166
+ if (restOfPath.startsWith('app/') || restOfPath === 'app') {
167
+ relativePath = `mobile/${restOfPath}`;
168
+ }
169
+ else if (['services', 'store', 'hooks', 'components'].some(dir => restOfPath.startsWith(dir + '/') || restOfPath === dir)) {
170
+ relativePath = `mobile/src/${restOfPath}`;
171
+ }
172
+ else {
173
+ relativePath = `mobile/${restOfPath}`;
174
+ }
175
+ }
176
+ // integrations/mobile/*/services/* → mobile/src/services/*
177
+ else if (relativePath.startsWith('integrations/mobile/')) {
178
+ const integrationPath = relativePath.substring('integrations/mobile/'.length);
179
+ const restOfPath = integrationPath.substring(integrationPath.indexOf('/') + 1);
180
+ if (restOfPath.startsWith('services/') || restOfPath.startsWith('store/')) {
181
+ relativePath = `mobile/src/${restOfPath}`;
182
+ }
183
+ else {
184
+ relativePath = `mobile/${restOfPath}`;
185
+ }
186
+ }
187
+ // ==========================================================================
188
+ // Web features and integrations (future - placeholder for consistency)
189
+ // ==========================================================================
190
+ // features/web/*/app/* → web/src/app/*
191
+ else if (relativePath.startsWith('features/web/')) {
192
+ const featurePath = relativePath.substring('features/web/'.length);
193
+ const restOfPath = featurePath.substring(featurePath.indexOf('/') + 1);
194
+ // Map to web directory structure (Next.js App Router)
195
+ if (restOfPath.startsWith('app/') || restOfPath === 'app') {
196
+ relativePath = `web/src/${restOfPath}`;
197
+ }
198
+ else if (['components', 'lib', 'hooks'].some(dir => restOfPath.startsWith(dir + '/') || restOfPath === dir)) {
199
+ relativePath = `web/src/${restOfPath}`;
200
+ }
201
+ else {
202
+ relativePath = `web/${restOfPath}`;
203
+ }
204
+ }
205
+ // integrations/web/* → web/src/*
206
+ else if (relativePath.startsWith('integrations/web/')) {
207
+ const integrationPath = relativePath.substring('integrations/web/'.length);
208
+ const restOfPath = integrationPath.substring(integrationPath.indexOf('/') + 1);
209
+ relativePath = `web/src/${restOfPath}`;
210
+ }
211
+ // ==========================================================================
212
+ // Shared templates (platform-agnostic)
213
+ // ==========================================================================
214
+ // shared/* → *
215
+ else if (relativePath.startsWith('shared/')) {
216
+ relativePath = relativePath.substring('shared/'.length);
217
+ }
218
+ // Remove ORM suffix from file names (.prisma.ts → .ts, .drizzle.ts → .ts)
219
+ // This handles:
220
+ // - db.prisma.ts → db.ts
221
+ // - db.drizzle.ts → db.ts
222
+ // - auth.prisma.ts.ejs → auth.ts.ejs (then .ejs removed later)
223
+ // - prisma.config.prisma.ts → prisma.config.ts
224
+ // - drizzle.config.drizzle.ts → drizzle.config.ts
225
+ // - drizzle/schema.drizzle.ts → drizzle/schema.ts
226
+ relativePath = relativePath.replace(/\.prisma\.ts/, '.ts');
227
+ relativePath = relativePath.replace(/\.drizzle\.ts/, '.ts');
228
+ // Remove .ejs extension
229
+ if (relativePath.endsWith('.ejs')) {
230
+ relativePath = relativePath.substring(0, relativePath.length - 4);
231
+ }
232
+ return path.join(targetDir, relativePath);
233
+ }
234
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/utils/template.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { ProjectConfig } from '../types/index.js';
2
+ export interface ValidationResult {
3
+ valid: boolean;
4
+ error?: string;
5
+ }
6
+ export declare function validateProjectName(name: string): ValidationResult;
7
+ export declare function validateConfiguration(config: ProjectConfig): ValidationResult;
8
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAsClE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,CAiE7E"}
@@ -0,0 +1,94 @@
1
+ import validateNpmPackageName from 'validate-npm-package-name';
2
+ export function validateProjectName(name) {
3
+ // Check if empty
4
+ if (!name || name.trim().length === 0) {
5
+ return {
6
+ valid: false,
7
+ error: 'Project name cannot be empty',
8
+ };
9
+ }
10
+ // Check npm package name validity
11
+ const npmValidation = validateNpmPackageName(name);
12
+ if (!npmValidation.validForNewPackages) {
13
+ const errors = [
14
+ ...(npmValidation.errors || []),
15
+ ...(npmValidation.warnings || []),
16
+ ];
17
+ return {
18
+ valid: false,
19
+ error: errors.join(', '),
20
+ };
21
+ }
22
+ // Additional checks
23
+ if (name.length > 214) {
24
+ return {
25
+ valid: false,
26
+ error: 'Project name must be less than 214 characters',
27
+ };
28
+ }
29
+ if (!/^[a-z0-9-]+$/.test(name)) {
30
+ return {
31
+ valid: false,
32
+ error: 'Project name must contain only lowercase letters, numbers, and hyphens',
33
+ };
34
+ }
35
+ return { valid: true };
36
+ }
37
+ export function validateConfiguration(config) {
38
+ // Validate project name
39
+ const nameValidation = validateProjectName(config.projectName);
40
+ if (!nameValidation.valid) {
41
+ return nameValidation;
42
+ }
43
+ // Validate platforms
44
+ if (!config.platforms || config.platforms.length === 0) {
45
+ return {
46
+ valid: false,
47
+ error: 'At least one platform must be selected',
48
+ };
49
+ }
50
+ const validPlatforms = ['mobile', 'web'];
51
+ for (const platform of config.platforms) {
52
+ if (!validPlatforms.includes(platform)) {
53
+ return {
54
+ valid: false,
55
+ error: `Invalid platform: ${platform}. Must be one of: ${validPlatforms.join(', ')}`,
56
+ };
57
+ }
58
+ }
59
+ // Validate package manager
60
+ const validPackageManagers = ['npm', 'yarn', 'bun'];
61
+ if (!validPackageManagers.includes(config.packageManager)) {
62
+ return {
63
+ valid: false,
64
+ error: 'Package manager must be one of: npm, yarn, bun',
65
+ };
66
+ }
67
+ // Validate paywall requires RevenueCat
68
+ if (config.features.paywall && !config.integrations.revenueCat.enabled) {
69
+ return {
70
+ valid: false,
71
+ error: 'Paywall feature requires RevenueCat integration',
72
+ };
73
+ }
74
+ // Validate onboarding pages
75
+ if (config.features.onboarding.enabled) {
76
+ const pages = config.features.onboarding.pages;
77
+ if (pages < 1 || pages > 5) {
78
+ return {
79
+ valid: false,
80
+ error: 'Onboarding pages must be between 1 and 5',
81
+ };
82
+ }
83
+ }
84
+ // Validate onboarding paywall requires RevenueCat
85
+ if (config.features.onboarding.showPaywall &&
86
+ !config.integrations.revenueCat.enabled) {
87
+ return {
88
+ valid: false,
89
+ error: 'Onboarding paywall requires RevenueCat integration',
90
+ };
91
+ }
92
+ return { valid: true };
93
+ }
94
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "create-stackr",
3
+ "version": "0.2.0",
4
+ "description": "Create production-ready full-stack mobile apps with React Native (Expo) and Node.js backend",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-stackr": "./bin/cli.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "dist",
12
+ "templates",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "scripts": {
17
+ "dev": "tsx src/index.ts",
18
+ "build": "tsc",
19
+ "test": "vitest run",
20
+ "test:watch": "VITEST_WATCH=1 vitest",
21
+ "test:coverage": "vitest run --coverage",
22
+ "test:unit": "vitest run tests/unit",
23
+ "test:integration": "vitest run tests/integration",
24
+ "test:e2e": "vitest run tests/e2e --exclude tests/e2e/build-verification.test.ts",
25
+ "test:e2e:all": "vitest run tests/e2e",
26
+ "test:build": "vitest run tests/e2e/build-verification.test.ts",
27
+ "test:ui": "vitest --ui",
28
+ "lint": "eslint src tests",
29
+ "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
30
+ "typecheck": "tsc --noEmit",
31
+ "prepublishOnly": "bun run build"
32
+ },
33
+ "keywords": [
34
+ "react-native",
35
+ "expo",
36
+ "fullstack",
37
+ "mobile",
38
+ "backend",
39
+ "cli",
40
+ "generator",
41
+ "scaffold",
42
+ "boilerplate",
43
+ "fastify",
44
+ "prisma",
45
+ "revenuecat",
46
+ "adjust",
47
+ "scate",
48
+ "typescript",
49
+ "nodejs",
50
+ "postgresql",
51
+ "docker"
52
+ ],
53
+ "author": "itharea",
54
+ "repository": {
55
+ "type": "git",
56
+ "url": "https://github.com/itharea/create-stackr"
57
+ },
58
+ "bugs": {
59
+ "url": "https://github.com/itharea/create-stackr/issues"
60
+ },
61
+ "homepage": "https://github.com/itharea/create-stackr#readme",
62
+ "engines": {
63
+ "node": ">=18.0.0"
64
+ },
65
+ "packageManager": "bun@1.3.3",
66
+ "license": "MIT",
67
+ "dependencies": {
68
+ "boxen": "^8.0.0",
69
+ "chalk": "^5.0.0",
70
+ "commander": "^12.0.0",
71
+ "ejs": "^3.1.10",
72
+ "execa": "^9.0.0",
73
+ "fs-extra": "^11.3.2",
74
+ "globby": "^16.0.0",
75
+ "inquirer": "^10.0.0",
76
+ "ora": "^8.0.0",
77
+ "validate-npm-package-name": "^5.0.0"
78
+ },
79
+ "devDependencies": {
80
+ "@eslint/js": "^9.0.0",
81
+ "@types/ejs": "^3.1.5",
82
+ "@types/fs-extra": "^11.0.4",
83
+ "@types/inquirer": "^9.0.0",
84
+ "@types/node": "^22.0.0",
85
+ "@types/validate-npm-package-name": "^4.0.2",
86
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
87
+ "@typescript-eslint/parser": "^8.0.0",
88
+ "@vitest/coverage-v8": "^2.0.0",
89
+ "eslint": "^9.0.0",
90
+ "memfs": "^4.51.0",
91
+ "prettier": "^3.0.0",
92
+ "tsx": "^4.19.2",
93
+ "typescript": "^5.7.2",
94
+ "vitest": "^2.0.0"
95
+ }
96
+ }
@@ -0,0 +1,62 @@
1
+ # Dependencies - will be installed in container
2
+ node_modules
3
+ .pnp
4
+ .pnp.js
5
+
6
+ # Testing
7
+ coverage
8
+
9
+ # Build output
10
+ dist
11
+ build
12
+
13
+ # Development
14
+ .env.local
15
+ .env.development.local
16
+ .env.test.local
17
+ .env.production.local
18
+
19
+ # IDE
20
+ .vscode
21
+ .idea
22
+ *.swp
23
+ *.swo
24
+ *~
25
+
26
+ # OS
27
+ .DS_Store
28
+ Thumbs.db
29
+
30
+ # Logs
31
+ npm-debug.log*
32
+ yarn-debug.log*
33
+ yarn-error.log*
34
+ lerna-debug.log*
35
+ .pnpm-debug.log*
36
+
37
+ # Git
38
+ .git
39
+ .gitignore
40
+
41
+ # Docker
42
+ Dockerfile
43
+ Dockerfile.*
44
+ .dockerignore
45
+ docker-compose*.yml
46
+
47
+ # CI/CD
48
+ .github
49
+ .gitlab-ci.yml
50
+
51
+ # Documentation
52
+ *.md
53
+ !README.md
54
+
55
+ # Exclude lock files for package managers not being used
56
+ <% if (packageManager !== 'bun') { %>bun.lockb<% } %>
57
+ <% if (packageManager !== 'npm') { %>package-lock.json<% } %>
58
+ <% if (packageManager !== 'yarn') { %>yarn.lock
59
+ .yarn
60
+ .yarnrc.yml<% } %>
61
+ <% if (packageManager !== 'pnpm') { %>pnpm-lock.yaml
62
+ .pnpm-store<% } %>
@@ -0,0 +1,116 @@
1
+ # =============================================================================
2
+ # Backend Environment Configuration
3
+ # =============================================================================
4
+ # Copy this file to .env and update with your actual values
5
+ # Never commit .env to version control!
6
+ # =============================================================================
7
+
8
+ # Environment
9
+ NODE_ENV=development
10
+ LOG_LEVEL=info
11
+
12
+ # Server Configuration
13
+ API_HOST=0.0.0.0
14
+ API_PORT=8080
15
+
16
+ # Database Configuration
17
+ # PostgreSQL connection string
18
+ # Format: postgresql://username:password@host:port/database?schema=public
19
+ DATABASE_URL="postgresql://username:password@localhost:5432/<%= projectName.toLowerCase().replace(/[^a-z0-9]/g, '_') %>_db?schema=public"
20
+
21
+ # =============================================================================
22
+ # BetterAuth Configuration
23
+ # =============================================================================
24
+ # IMPORTANT: Change this in production! Use a secure random string.
25
+ # Generate with: openssl rand -base64 32
26
+ BETTER_AUTH_SECRET=your-super-secret-auth-key-change-this-in-production
27
+ BETTER_AUTH_URL=http://localhost:8080
28
+
29
+ # Trusted Origins for BetterAuth (includes mobile deep link scheme and web)
30
+ # Comma-separated list of trusted origins for OAuth callbacks
31
+ TRUSTED_ORIGINS=http://localhost:3000,http://localhost:8081,<%= appScheme %>://
32
+ # Web App URL (for OAuth callbacks)
33
+ WEB_APP_URL=http://localhost:3000
34
+ <% if (features.authentication.providers.google) { %>
35
+ # =============================================================================
36
+ # Google OAuth Configuration
37
+ # =============================================================================
38
+ # Get credentials at: https://console.cloud.google.com/
39
+ # Create OAuth 2.0 credentials for Web, iOS, and Android
40
+ #
41
+ # Web Client ID - Used for ID token audience verification on backend
42
+ GOOGLE_WEB_CLIENT_ID=YOUR_GOOGLE_WEB_CLIENT_ID
43
+ # Client Secret - For backend token exchange
44
+ GOOGLE_CLIENT_SECRET=YOUR_GOOGLE_CLIENT_SECRET
45
+ # Note: iOS and Android client IDs are configured in mobile/app.json
46
+ <% } %>
47
+ <% if (features.authentication.providers.apple) { %>
48
+ # =============================================================================
49
+ # Apple Sign In Configuration
50
+ # =============================================================================
51
+ # Get credentials at: https://developer.apple.com/
52
+ #
53
+ # Service ID - For web OAuth flow
54
+ APPLE_SERVICE_ID=YOUR_APPLE_SERVICE_ID
55
+ # Bundle ID - For native iOS ID token verification (must match your app)
56
+ APPLE_BUNDLE_ID=com.yourcompany.yourapp
57
+ # Client Secret - JWT signed with your Apple private key (expires every 180 days)
58
+ APPLE_CLIENT_SECRET=YOUR_APPLE_CLIENT_SECRET
59
+ <% } %>
60
+ <% if (features.authentication.providers.github) { %>
61
+ # =============================================================================
62
+ # GitHub OAuth Configuration
63
+ # =============================================================================
64
+ # Get credentials at: https://github.com/settings/developers
65
+ GITHUB_CLIENT_ID=YOUR_GITHUB_CLIENT_ID
66
+ GITHUB_CLIENT_SECRET=YOUR_GITHUB_CLIENT_SECRET
67
+ <% } %>
68
+
69
+ # Redis Configuration
70
+ # Used for caching<% if (backend.eventQueue) { %> and BullMQ job queue<% } %>
71
+ REDIS_HOST=localhost
72
+ REDIS_PORT=6379
73
+ REDIS_PASSWORD=your-redis-password
74
+ REDIS_DB=0
75
+ <% if (backend.eventQueue) { %>
76
+ # BullMQ Configuration (Event Queue)
77
+ # Queue settings for background job processing
78
+ BULLMQ_QUEUE_NAME=<%= projectName.toLowerCase().replace(/[^a-z0-9]/g, '_') %>_queue
79
+ BULLMQ_MAX_RETRIES=3
80
+ BULLMQ_BACKOFF_DELAY=5000
81
+ <% } %>
82
+ # CORS Configuration
83
+ # Comma-separated list of allowed origins for Fastify CORS
84
+ # Includes mobile dev server and web app
85
+ ALLOWED_ORIGINS=http://localhost:3000,http://localhost:8081,https://yourdomain.com
86
+
87
+ # Rate Limiting
88
+ RATE_LIMIT_WINDOW_MS=900000
89
+ RATE_LIMIT_MAX_REQUESTS=100
90
+ <% if (features.authentication.emailVerification || features.authentication.passwordReset) { %>
91
+ # =============================================================================
92
+ # Email Configuration (Required for email verification/password reset)
93
+ # =============================================================================
94
+ SMTP_HOST=smtp.gmail.com
95
+ SMTP_PORT=587
96
+ SMTP_USER=your-email@gmail.com
97
+ SMTP_PASS=your-app-password
98
+ EMAIL_FROM=noreply@<%= projectName.toLowerCase().replace(/[^a-z0-9]/g, '') %>.com
99
+ <% } else { %>
100
+ # Email Configuration (Optional)
101
+ # SMTP_HOST=smtp.gmail.com
102
+ # SMTP_PORT=587
103
+ # SMTP_USER=your-email@gmail.com
104
+ # SMTP_PASS=your-app-password
105
+ # EMAIL_FROM=noreply@<%= projectName.toLowerCase().replace(/[^a-z0-9]/g, '') %>.com
106
+ <% } %>
107
+
108
+ # Third-party Services (Optional)
109
+ # AWS_ACCESS_KEY_ID=
110
+ # AWS_SECRET_ACCESS_KEY=
111
+ # AWS_REGION=us-east-1
112
+ # S3_BUCKET_NAME=
113
+
114
+ # Monitoring & Logging (Optional)
115
+ # SENTRY_DSN=
116
+ # SENTRY_ENVIRONMENT=development