create-mantiq 0.7.0 → 0.7.2

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 (220) hide show
  1. package/package.json +2 -1
  2. package/skeleton/.env.example +64 -0
  3. package/skeleton/README.md +46 -0
  4. package/skeleton/app/Console/Commands/.gitkeep +0 -0
  5. package/skeleton/app/Enums/UserStatus.ts +7 -0
  6. package/skeleton/app/Http/Controllers/HomeController.ts +78 -0
  7. package/skeleton/app/Http/Middleware/.gitkeep +0 -0
  8. package/skeleton/app/Models/User.ts +7 -0
  9. package/skeleton/app/Providers/AppServiceProvider.ts +25 -0
  10. package/skeleton/app/Providers/DatabaseServiceProvider.ts +17 -0
  11. package/skeleton/bootstrap/.gitkeep +0 -0
  12. package/skeleton/config/ai.ts +51 -0
  13. package/skeleton/config/app.ts +108 -0
  14. package/skeleton/config/auth.ts +51 -0
  15. package/skeleton/config/broadcasting.ts +93 -0
  16. package/skeleton/config/cache.ts +61 -0
  17. package/skeleton/config/cors.ts +77 -0
  18. package/skeleton/config/database.ts +120 -0
  19. package/skeleton/config/filesystem.ts +58 -0
  20. package/skeleton/config/hashing.ts +47 -0
  21. package/skeleton/config/heartbeat.ts +112 -0
  22. package/skeleton/config/logging.ts +58 -0
  23. package/skeleton/config/mail.ts +93 -0
  24. package/skeleton/config/notify.ts +141 -0
  25. package/skeleton/config/queue.ts +59 -0
  26. package/skeleton/config/search.ts +96 -0
  27. package/skeleton/config/services.ts +110 -0
  28. package/skeleton/config/session.ts +84 -0
  29. package/skeleton/config/vite.ts +33 -0
  30. package/skeleton/database/factories/.gitkeep +0 -0
  31. package/skeleton/database/migrations/001_create_users_table.ts +19 -0
  32. package/skeleton/database/migrations/002_create_personal_access_tokens_table.ts +22 -0
  33. package/skeleton/database/seeders/DatabaseSeeder.ts +7 -0
  34. package/skeleton/index.ts +20 -0
  35. package/skeleton/mantiq.ts +8 -0
  36. package/skeleton/package.json +34 -0
  37. package/skeleton/public/.gitkeep +0 -0
  38. package/skeleton/routes/api.ts +8 -0
  39. package/skeleton/routes/channels.ts +23 -0
  40. package/skeleton/routes/console.ts +24 -0
  41. package/skeleton/routes/web.ts +6 -0
  42. package/skeleton/storage/cache/.gitkeep +0 -0
  43. package/skeleton/storage/framework/.gitkeep +0 -0
  44. package/skeleton/tests/feature/api.test.ts +14 -0
  45. package/skeleton/tests/feature/home.test.ts +17 -0
  46. package/skeleton/tests/unit/example.test.ts +11 -0
  47. package/skeleton/tsconfig.json +27 -0
  48. package/src/index.ts +289 -25
  49. package/src/templates.ts +141 -945
  50. package/src/terminal.ts +64 -0
  51. package/stubs/api-only/routes/api.ts.stub +24 -0
  52. package/stubs/api-only/tests/feature/token-auth.test.ts.stub +69 -0
  53. package/stubs/auth/api/app/Http/Controllers/ApiAuthController.ts.stub +57 -0
  54. package/stubs/auth/api/routes/api.ts.stub +24 -0
  55. package/stubs/auth/api/tests/feature/token-auth.test.ts.stub +69 -0
  56. package/stubs/auth/shared/app/Http/Requests/LoginRequest.ts.stub +10 -0
  57. package/stubs/auth/shared/app/Http/Requests/RegisterRequest.ts.stub +11 -0
  58. package/stubs/auth/web/app/Http/Controllers/AuthController.ts.stub +43 -0
  59. package/stubs/auth/web/app/Http/Controllers/PageController.ts.stub +66 -0
  60. package/stubs/auth/web/routes/web.ts.stub +25 -0
  61. package/stubs/auth/web/svelte/src/App.svelte.stub +77 -0
  62. package/stubs/auth/web/svelte/src/pages.ts.stub +17 -0
  63. package/stubs/auth/web/tests/feature/auth.test.ts.stub +69 -0
  64. package/stubs/auth/web/vue/src/App.vue.stub +74 -0
  65. package/stubs/auth/web/vue/src/pages.ts.stub +17 -0
  66. package/stubs/manifest.json +630 -2
  67. package/stubs/noauth/app/Http/Controllers/PageController.ts.stub +41 -0
  68. package/stubs/noauth/app/Models/User.ts.stub +5 -0
  69. package/stubs/noauth/database/migrations/001_create_users_table.ts.stub +17 -0
  70. package/stubs/noauth/routes/api.ts.stub +16 -0
  71. package/stubs/noauth/routes/web.ts.stub +15 -0
  72. package/stubs/noauth/svelte/src/App.svelte.stub +68 -0
  73. package/stubs/noauth/svelte/src/pages.ts.stub +7 -0
  74. package/stubs/noauth/vue/src/App.vue.stub +62 -0
  75. package/stubs/noauth/vue/src/pages.ts.stub +7 -0
  76. package/stubs/react/src/App.tsx.stub +4 -2
  77. package/stubs/react/src/components/layout/search-dialog.tsx.stub +2 -2
  78. package/stubs/react/src/components/layout/sidebar-data.ts.stub +2 -2
  79. package/stubs/react/src/lib/api.ts.stub +30 -6
  80. package/stubs/react/src/pages/Login.tsx.stub +3 -3
  81. package/stubs/react/src/pages/users/dialogs.tsx.stub +7 -26
  82. package/stubs/react/vite.config.ts.stub +26 -3
  83. package/stubs/shared/app/Http/Controllers/ApiAuthController.ts.stub +57 -0
  84. package/stubs/shared/app/Http/Controllers/AuthController.ts.stub +14 -38
  85. package/stubs/shared/app/Http/Controllers/PageController.ts.stub +3 -3
  86. package/stubs/shared/app/Http/Controllers/UserController.ts.stub +61 -0
  87. package/stubs/shared/app/Http/Requests/LoginRequest.ts.stub +10 -0
  88. package/stubs/shared/app/Http/Requests/RegisterRequest.ts.stub +11 -0
  89. package/stubs/shared/app/Http/Requests/StoreUserRequest.ts.stub +11 -0
  90. package/stubs/shared/app/Http/Requests/UpdateUserRequest.ts.stub +11 -0
  91. package/stubs/shared/config/app.ts.stub +36 -0
  92. package/stubs/shared/config/vite.ts.stub +8 -0
  93. package/stubs/shared/database/factories/UserFactory.ts.stub +4 -6
  94. package/stubs/shared/routes/api.ts.stub +12 -102
  95. package/stubs/shared/routes/web.ts.stub +5 -3
  96. package/stubs/shared/tests/feature/auth.test.ts.stub +69 -0
  97. package/stubs/shared/tests/feature/users.test.ts.stub +90 -0
  98. package/stubs/svelte/src/App.svelte.stub +1 -1
  99. package/stubs/svelte/src/lib/api.ts.stub +30 -6
  100. package/stubs/svelte/src/main.ts.stub +3 -1
  101. package/stubs/svelte/src/pages/Login.svelte.stub +3 -3
  102. package/stubs/svelte/vite.config.ts.stub +20 -1
  103. package/stubs/tailwind-only/react/src/components/layout/app-sidebar.tsx.stub +68 -0
  104. package/stubs/tailwind-only/react/src/components/layout/authenticated-layout.tsx.stub +57 -0
  105. package/stubs/tailwind-only/react/src/components/layout/header.tsx.stub +52 -0
  106. package/stubs/tailwind-only/react/src/components/layout/main.tsx.stub +21 -0
  107. package/stubs/tailwind-only/react/src/components/layout/nav-group.tsx.stub +185 -0
  108. package/stubs/tailwind-only/react/src/components/layout/nav-user.tsx.stub +106 -0
  109. package/stubs/tailwind-only/react/src/components/layout/sidebar-data.ts.stub +58 -0
  110. package/stubs/tailwind-only/react/src/components/layout/theme-toggle.tsx.stub +36 -0
  111. package/stubs/tailwind-only/react/src/components/layout/top-nav.tsx.stub +72 -0
  112. package/stubs/tailwind-only/react/src/lib/utils.ts.stub +6 -0
  113. package/stubs/tailwind-only/react/src/pages/Dashboard.tsx.stub +205 -0
  114. package/stubs/tailwind-only/react/src/pages/Login.tsx.stub +122 -0
  115. package/stubs/tailwind-only/react/src/pages/Register.tsx.stub +137 -0
  116. package/stubs/tailwind-only/react/src/pages/Users.tsx.stub +426 -0
  117. package/stubs/tailwind-only/react/src/pages/account/layout.tsx.stub +64 -0
  118. package/stubs/tailwind-only/react/src/pages/account/preferences.tsx.stub +80 -0
  119. package/stubs/tailwind-only/react/src/pages/account/profile.tsx.stub +67 -0
  120. package/stubs/tailwind-only/react/src/pages/account/security.tsx.stub +91 -0
  121. package/stubs/tailwind-only/react/src/style.css.stub +14 -0
  122. package/stubs/tailwind-only/svelte/src/lib/components/layout/app-sidebar.svelte.stub +104 -0
  123. package/stubs/tailwind-only/svelte/src/lib/components/layout/authenticated-layout.svelte.stub +51 -0
  124. package/stubs/tailwind-only/svelte/src/lib/components/layout/header.svelte.stub +66 -0
  125. package/stubs/tailwind-only/svelte/src/lib/components/layout/main.svelte.stub +26 -0
  126. package/stubs/tailwind-only/svelte/src/lib/components/layout/nav-group.svelte.stub +131 -0
  127. package/stubs/tailwind-only/svelte/src/lib/components/layout/nav-user.svelte.stub +104 -0
  128. package/stubs/tailwind-only/svelte/src/lib/components/layout/sidebar-data.ts.stub +57 -0
  129. package/stubs/tailwind-only/svelte/src/lib/components/layout/theme-toggle.svelte.stub +28 -0
  130. package/stubs/tailwind-only/svelte/src/lib/components/layout/top-nav.svelte.stub +99 -0
  131. package/stubs/tailwind-only/svelte/src/lib/utils.ts.stub +6 -0
  132. package/stubs/tailwind-only/svelte/src/pages/Dashboard.svelte.stub +192 -0
  133. package/stubs/tailwind-only/svelte/src/pages/Login.svelte.stub +120 -0
  134. package/stubs/tailwind-only/svelte/src/pages/Register.svelte.stub +134 -0
  135. package/stubs/tailwind-only/svelte/src/pages/Users.svelte.stub +293 -0
  136. package/stubs/tailwind-only/svelte/src/pages/account/Layout.svelte.stub +61 -0
  137. package/stubs/tailwind-only/svelte/src/pages/account/Preferences.svelte.stub +81 -0
  138. package/stubs/tailwind-only/svelte/src/pages/account/Profile.svelte.stub +76 -0
  139. package/stubs/tailwind-only/svelte/src/pages/account/Security.svelte.stub +140 -0
  140. package/stubs/tailwind-only/svelte/src/style.css.stub +127 -0
  141. package/stubs/tailwind-only/vue/src/components/layout/AppSidebar.vue.stub +60 -0
  142. package/stubs/tailwind-only/vue/src/components/layout/AuthenticatedLayout.vue.stub +73 -0
  143. package/stubs/tailwind-only/vue/src/components/layout/Header.vue.stub +54 -0
  144. package/stubs/tailwind-only/vue/src/components/layout/Main.vue.stub +22 -0
  145. package/stubs/tailwind-only/vue/src/components/layout/NavGroup.vue.stub +107 -0
  146. package/stubs/tailwind-only/vue/src/components/layout/NavUser.vue.stub +104 -0
  147. package/stubs/tailwind-only/vue/src/components/layout/ThemeToggle.vue.stub +28 -0
  148. package/stubs/tailwind-only/vue/src/components/layout/TopNav.vue.stub +86 -0
  149. package/stubs/tailwind-only/vue/src/components/layout/sidebar-data.ts.stub +57 -0
  150. package/stubs/tailwind-only/vue/src/lib/utils.ts.stub +7 -0
  151. package/stubs/tailwind-only/vue/src/pages/Dashboard.vue.stub +195 -0
  152. package/stubs/tailwind-only/vue/src/pages/Login.vue.stub +121 -0
  153. package/stubs/tailwind-only/vue/src/pages/Register.vue.stub +137 -0
  154. package/stubs/tailwind-only/vue/src/pages/Users.vue.stub +401 -0
  155. package/stubs/tailwind-only/vue/src/pages/account/Layout.vue.stub +56 -0
  156. package/stubs/tailwind-only/vue/src/pages/account/Preferences.vue.stub +81 -0
  157. package/stubs/tailwind-only/vue/src/pages/account/Profile.vue.stub +69 -0
  158. package/stubs/tailwind-only/vue/src/pages/account/Security.vue.stub +85 -0
  159. package/stubs/tailwind-only/vue/src/style.css.stub +26 -0
  160. package/stubs/themes/corporate/react/src/components/layout/app-sidebar.tsx.stub +74 -0
  161. package/stubs/themes/corporate/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
  162. package/stubs/themes/corporate/react/src/pages/Dashboard.tsx.stub +310 -0
  163. package/stubs/themes/corporate/react/src/pages/Login.tsx.stub +122 -0
  164. package/stubs/themes/corporate/react/src/pages/Register.tsx.stub +144 -0
  165. package/stubs/themes/corporate/react/src/style.css.stub +135 -0
  166. package/stubs/themes/corporate/svelte/src/pages/Dashboard.svelte.stub +271 -0
  167. package/stubs/themes/corporate/svelte/src/pages/Login.svelte.stub +117 -0
  168. package/stubs/themes/corporate/svelte/src/pages/Register.svelte.stub +138 -0
  169. package/stubs/themes/corporate/svelte/src/style.css.stub +134 -0
  170. package/stubs/themes/corporate/vue/src/pages/Dashboard.vue.stub +325 -0
  171. package/stubs/themes/corporate/vue/src/pages/Login.vue.stub +118 -0
  172. package/stubs/themes/corporate/vue/src/pages/Register.vue.stub +139 -0
  173. package/stubs/themes/corporate/vue/src/style.css.stub +134 -0
  174. package/stubs/themes/minimal/react/src/components/layout/app-sidebar.tsx.stub +68 -0
  175. package/stubs/themes/minimal/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
  176. package/stubs/themes/minimal/react/src/pages/Dashboard.tsx.stub +166 -0
  177. package/stubs/themes/minimal/react/src/pages/Login.tsx.stub +95 -0
  178. package/stubs/themes/minimal/react/src/pages/Register.tsx.stub +73 -0
  179. package/stubs/themes/minimal/react/src/style.css.stub +142 -0
  180. package/stubs/themes/minimal/svelte/src/pages/Dashboard.svelte.stub +149 -0
  181. package/stubs/themes/minimal/svelte/src/pages/Login.svelte.stub +90 -0
  182. package/stubs/themes/minimal/svelte/src/pages/Register.svelte.stub +70 -0
  183. package/stubs/themes/minimal/svelte/src/style.css.stub +142 -0
  184. package/stubs/themes/minimal/vue/src/pages/Dashboard.vue.stub +163 -0
  185. package/stubs/themes/minimal/vue/src/pages/Login.vue.stub +91 -0
  186. package/stubs/themes/minimal/vue/src/pages/Register.vue.stub +73 -0
  187. package/stubs/themes/minimal/vue/src/style.css.stub +142 -0
  188. package/stubs/themes/starter/react/src/components/layout/app-sidebar.tsx.stub +74 -0
  189. package/stubs/themes/starter/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
  190. package/stubs/themes/starter/react/src/pages/Dashboard.tsx.stub +236 -0
  191. package/stubs/themes/starter/react/src/pages/Login.tsx.stub +131 -0
  192. package/stubs/themes/starter/react/src/pages/Register.tsx.stub +145 -0
  193. package/stubs/themes/starter/react/src/style.css.stub +141 -0
  194. package/stubs/themes/starter/svelte/src/pages/Dashboard.svelte.stub +212 -0
  195. package/stubs/themes/starter/svelte/src/pages/Login.svelte.stub +126 -0
  196. package/stubs/themes/starter/svelte/src/pages/Register.svelte.stub +139 -0
  197. package/stubs/themes/starter/svelte/src/style.css.stub +141 -0
  198. package/stubs/themes/starter/vue/src/pages/Dashboard.vue.stub +228 -0
  199. package/stubs/themes/starter/vue/src/pages/Login.vue.stub +127 -0
  200. package/stubs/themes/starter/vue/src/pages/Register.vue.stub +140 -0
  201. package/stubs/themes/starter/vue/src/style.css.stub +141 -0
  202. package/stubs/themes/workspace/react/src/components/layout/app-sidebar.tsx.stub +97 -0
  203. package/stubs/themes/workspace/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
  204. package/stubs/themes/workspace/react/src/pages/Dashboard.tsx.stub +304 -0
  205. package/stubs/themes/workspace/react/src/pages/Login.tsx.stub +131 -0
  206. package/stubs/themes/workspace/react/src/pages/Register.tsx.stub +82 -0
  207. package/stubs/themes/workspace/react/src/style.css.stub +138 -0
  208. package/stubs/themes/workspace/svelte/src/pages/Dashboard.svelte.stub +215 -0
  209. package/stubs/themes/workspace/svelte/src/pages/Login.svelte.stub +124 -0
  210. package/stubs/themes/workspace/svelte/src/pages/Register.svelte.stub +76 -0
  211. package/stubs/themes/workspace/svelte/src/style.css.stub +134 -0
  212. package/stubs/themes/workspace/vue/src/pages/Dashboard.vue.stub +220 -0
  213. package/stubs/themes/workspace/vue/src/pages/Login.vue.stub +128 -0
  214. package/stubs/themes/workspace/vue/src/pages/Register.vue.stub +80 -0
  215. package/stubs/themes/workspace/vue/src/style.css.stub +134 -0
  216. package/stubs/vue/src/App.vue.stub +2 -1
  217. package/stubs/vue/src/lib/api.ts.stub +30 -6
  218. package/stubs/vue/src/main.ts.stub +3 -1
  219. package/stubs/vue/src/pages/Login.vue.stub +3 -3
  220. package/stubs/vue/vite.config.ts.stub +20 -1
package/src/templates.ts CHANGED
@@ -1,985 +1,181 @@
1
+ export type Theme = 'default' | 'minimal' | 'workspace' | 'corporate' | 'starter'
2
+
1
3
  export interface TemplateContext {
2
4
  name: string
3
5
  appKey: string
4
- kit?: 'react' | 'vue' | 'svelte'
5
- ui?: 'shadcn' | 'none'
6
- }
7
-
6
+ kit?: 'react' | 'vue' | 'svelte' | undefined
7
+ ui: 'shadcn' | 'tailwind'
8
+ theme: Theme
9
+ auth: 'builtin' | 'none'
10
+ optionalPackages: string[]
11
+ }
12
+
13
+ /**
14
+ * Returns ONLY the files that need dynamic generation or kit-specific overrides.
15
+ * The base skeleton is copied as-is from the skeleton/ directory.
16
+ *
17
+ * Dynamic files:
18
+ * - package.json (project name, deps vary by kit)
19
+ * - .env / .env.example (APP_KEY generated)
20
+ *
21
+ * Kit overrides (when a framework is selected):
22
+ * - package.json gets additional deps (react, vue, svelte, vite, tailwind, etc.)
23
+ */
8
24
  export function getTemplates(ctx: TemplateContext): Record<string, string> {
9
- const templates: Record<string, string> = {
10
- // ── Root files ──────────────────────────────────────────────────────────
11
-
12
- 'package.json': JSON.stringify({
13
- name: ctx.name,
14
- version: '0.0.1',
15
- private: true,
16
- type: 'module',
17
- scripts: {
18
- dev: 'bun run --watch index.ts',
19
- start: 'bun run index.ts',
20
- mantiq: 'bun run mantiq.ts',
21
- },
22
- dependencies: {
23
- '@mantiq/auth': '^0.2.0',
24
- '@mantiq/cli': '^0.1.6',
25
- '@mantiq/core': '^0.2.0',
26
- '@mantiq/database': '^0.1.4',
27
- '@mantiq/events': '^0.1.2',
28
- '@mantiq/filesystem': '^0.1.2',
29
- '@mantiq/heartbeat': '^0.3.0',
30
- '@mantiq/helpers': '^0.1.2',
31
- '@mantiq/logging': '^0.1.2',
32
- '@mantiq/queue': '^0.1.2',
33
- '@mantiq/realtime': '^0.1.2',
34
- '@mantiq/validation': '^0.1.2',
35
- '@mantiq/mail': '^0.2.0',
36
- '@mantiq/notify': '^0.1.0',
37
- '@mantiq/search': '^0.1.0',
38
- '@mantiq/health': '^0.1.0',
39
- },
40
- devDependencies: {
41
- 'bun-types': 'latest',
42
- 'typescript': '^5.7.0',
43
- },
44
- }, null, 2) + '\n',
45
-
46
- 'tsconfig.json': JSON.stringify({
47
- compilerOptions: {
48
- target: 'ESNext',
49
- module: 'ESNext',
50
- moduleResolution: 'bundler',
51
- lib: ['ESNext'],
52
- types: ['bun-types'],
53
- strict: true,
54
- noImplicitAny: true,
55
- strictNullChecks: true,
56
- noUncheckedIndexedAccess: true,
57
- noImplicitOverride: true,
58
- allowImportingTsExtensions: true,
59
- noEmit: true,
60
- skipLibCheck: true,
61
- },
62
- include: ['./**/*'],
63
- exclude: ['node_modules'],
64
- }, null, 2) + '\n',
65
-
66
- '.env': `APP_NAME=${ctx.name}
67
- APP_ENV=local
68
- APP_DEBUG=true
69
- APP_URL=http://localhost:3000
70
- APP_PORT=3000
71
- APP_KEY=${ctx.appKey}
72
-
73
- DB_CONNECTION=sqlite
74
- DB_DATABASE=database/database.sqlite
75
-
76
- LOG_CHANNEL=stack
77
- QUEUE_CONNECTION=sync
78
- MAIL_MAILER=log
79
- `,
80
-
81
- '.env.example': `APP_NAME=${ctx.name}
82
- APP_ENV=local
83
- APP_DEBUG=true
84
- APP_URL=http://localhost:3000
85
- APP_PORT=3000
86
- APP_KEY=
87
-
88
- DB_CONNECTION=sqlite
89
- DB_DATABASE=database/database.sqlite
90
-
91
- LOG_CHANNEL=stack
92
- QUEUE_CONNECTION=sync
93
- `,
94
-
95
- '.gitignore': `node_modules/
96
- dist/
97
- *.sqlite
98
- *.sqlite-journal
99
- *.sqlite-wal
100
- *.sqlite-shm
101
- .env
102
- .DS_Store
103
- tsconfig.tsbuildinfo
104
- storage/logs/
105
- storage/app/
106
- storage/heartbeat/
107
- `,
108
-
109
- // ── Entry points ────────────────────────────────────────────────────────
110
-
111
- 'index.ts': `import { Application, CoreServiceProvider, HttpKernel, RouterImpl, CorsMiddleware, StartSession, EncryptCookies, VerifyCsrfToken } from '@mantiq/core'
112
- import { AuthServiceProvider, Authenticate, RedirectIfAuthenticated, CheckAbilities, CheckForAnyAbility } from '@mantiq/auth'
113
- import { FilesystemServiceProvider } from '@mantiq/filesystem'
114
- import { LoggingServiceProvider } from '@mantiq/logging'
115
- import { EventServiceProvider } from '@mantiq/events'
116
- import { QueueServiceProvider } from '@mantiq/queue'
117
- import { ValidationServiceProvider } from '@mantiq/validation'
118
- import { HeartbeatServiceProvider, HeartbeatMiddleware } from '@mantiq/heartbeat'
119
- import { RealtimeServiceProvider } from '@mantiq/realtime'
120
- import { MailServiceProvider } from '@mantiq/mail'
121
- import { NotificationServiceProvider } from '@mantiq/notify'
122
- import { SearchServiceProvider } from '@mantiq/search'
123
- import { DatabaseServiceProvider } from './app/Providers/DatabaseServiceProvider.ts'
124
-
125
- // ── Load .env ─────────────────────────────────────────────────────────────────
126
- const envFile = Bun.file(import.meta.dir + '/.env')
127
- if (await envFile.exists()) {
128
- const text = await envFile.text()
129
- for (const line of text.split('\\n')) {
130
- const trimmed = line.trim()
131
- if (!trimmed || trimmed.startsWith('#')) continue
132
- const eqIdx = trimmed.indexOf('=')
133
- if (eqIdx === -1) continue
134
- const key = trimmed.slice(0, eqIdx).trim()
135
- const value = trimmed.slice(eqIdx + 1).trim()
136
- if (key && !(key in process.env)) process.env[key] = value
137
- }
138
- }
139
-
140
- // ── Bootstrap ─────────────────────────────────────────────────────────────────
141
- const app = await Application.create(import.meta.dir, 'config')
142
-
143
- await app.registerProviders([
144
- CoreServiceProvider,
145
- DatabaseServiceProvider,
146
- AuthServiceProvider,
147
- FilesystemServiceProvider,
148
- LoggingServiceProvider,
149
- EventServiceProvider,
150
- QueueServiceProvider,
151
- ValidationServiceProvider,
152
- HeartbeatServiceProvider,
153
- RealtimeServiceProvider,
154
- MailServiceProvider,
155
- NotificationServiceProvider,
156
- SearchServiceProvider,
157
- ])
158
- await app.bootProviders()
159
-
160
- // ── Kernel setup ──────────────────────────────────────────────────────────────
161
- const kernel = app.make(HttpKernel)
162
- const router = app.make(RouterImpl)
163
-
164
- // Register middleware aliases
165
- kernel.registerMiddleware('cors', CorsMiddleware)
166
- kernel.registerMiddleware('encrypt.cookies', EncryptCookies)
167
- kernel.registerMiddleware('session', StartSession)
168
- kernel.registerMiddleware('csrf', VerifyCsrfToken)
169
- kernel.registerMiddleware('auth', Authenticate)
170
- kernel.registerMiddleware('guest', RedirectIfAuthenticated)
171
- kernel.registerMiddleware('heartbeat', HeartbeatMiddleware)
172
- kernel.registerMiddleware('abilities', CheckAbilities)
173
- kernel.registerMiddleware('ability', CheckForAnyAbility)
174
-
175
- // Global middleware
176
- kernel.setGlobalMiddleware(['cors', 'encrypt.cookies', 'session', 'heartbeat'])
177
-
178
- // ── Routes ────────────────────────────────────────────────────────────────────
179
- import webRoutes from './routes/web.ts'
180
- import apiRoutes from './routes/api.ts'
181
-
182
- webRoutes(router)
183
- apiRoutes(router)
184
-
185
- // ── Export for CLI ────────────────────────────────────────────────────────────
186
- export default app
187
-
188
- // ── Start ─────────────────────────────────────────────────────────────────────
189
- if (import.meta.main) {
190
- await kernel.start()
191
- }
192
- `,
193
-
194
- 'mantiq.ts': `#!/usr/bin/env bun
195
- await import('./index.ts')
196
-
197
- import { Kernel } from '@mantiq/cli'
198
- import {
199
- AboutCommand,
200
- MigrateCommand,
201
- MigrateRollbackCommand,
202
- MigrateResetCommand,
203
- MigrateFreshCommand,
204
- MigrateStatusCommand,
205
- SeedCommand,
206
- MakeCommandCommand,
207
- MakeControllerCommand,
208
- MakeEventCommand,
209
- MakeExceptionCommand,
210
- MakeFactoryCommand,
211
- MakeListenerCommand,
212
- MakeMiddlewareCommand,
213
- MakeMigrationCommand,
214
- MakeModelCommand,
215
- MakeObserverCommand,
216
- MakeProviderCommand,
217
- MakeRequestCommand,
218
- MakeRuleCommand,
219
- MakeSeederCommand,
220
- MakeTestCommand,
221
- ServeCommand,
222
- RouteListCommand,
223
- TinkerCommand,
224
- } from '@mantiq/cli'
225
- import {
226
- QueueWorkCommand,
227
- QueueRetryCommand,
228
- QueueFailedCommand,
229
- QueueFlushCommand,
230
- MakeJobCommand,
231
- ScheduleRunCommand,
232
- } from '@mantiq/queue'
233
- import { InstallCommand as HeartbeatInstallCommand } from '@mantiq/heartbeat'
234
- import { MakeMailCommand } from '@mantiq/mail'
235
- import { MakeNotificationCommand } from '@mantiq/notify'
236
-
237
- const kernel = new Kernel()
238
-
239
- kernel.registerAll([
240
- // Database
241
- new MigrateCommand(),
242
- new MigrateRollbackCommand(),
243
- new MigrateResetCommand(),
244
- new MigrateFreshCommand(),
245
- new MigrateStatusCommand(),
246
- new SeedCommand(),
247
-
248
- // Code generators
249
- new MakeCommandCommand(),
250
- new MakeControllerCommand(),
251
- new MakeEventCommand(),
252
- new MakeExceptionCommand(),
253
- new MakeFactoryCommand(),
254
- new MakeJobCommand(),
255
- new MakeListenerCommand(),
256
- new MakeMiddlewareCommand(),
257
- new MakeMigrationCommand(),
258
- new MakeModelCommand(),
259
- new MakeObserverCommand(),
260
- new MakeProviderCommand(),
261
- new MakeRequestCommand(),
262
- new MakeRuleCommand(),
263
- new MakeSeederCommand(),
264
- new MakeTestCommand(),
265
- new MakeMailCommand(),
266
- new MakeNotificationCommand(),
267
-
268
- // Queue
269
- new QueueWorkCommand(),
270
- new QueueRetryCommand(),
271
- new QueueFailedCommand(),
272
- new QueueFlushCommand(),
273
- new ScheduleRunCommand(),
274
-
275
- // Utilities
276
- new AboutCommand(),
277
- new ServeCommand(),
278
- new RouteListCommand(),
279
- new TinkerCommand(),
280
-
281
- // Heartbeat
282
- new HeartbeatInstallCommand(),
283
- ])
284
-
285
- const code = await kernel.run()
286
- process.exit(code)
287
- `,
288
-
289
- // ── Config ──────────────────────────────────────────────────────────────
290
-
291
- 'config/app.ts': `import { env } from '@mantiq/core'
292
-
293
- export default {
294
- name: env('APP_NAME', 'MantiqJS'),
295
- env: env('APP_ENV', 'production'),
296
- debug: env('APP_DEBUG', false),
297
- key: env('APP_KEY', ''),
298
- url: env('APP_URL', 'http://localhost:3000'),
299
- port: Number(env('APP_PORT', '3000')),
300
- basePath: import.meta.dir + '/..',
301
- }
302
- `,
303
-
304
- 'config/database.ts': `import { env } from '@mantiq/core'
305
-
306
- export default {
307
- default: env('DB_CONNECTION', 'sqlite'),
308
-
309
- connections: {
310
- sqlite: {
311
- driver: 'sqlite' as const,
312
- database: env('DB_DATABASE', import.meta.dir + '/../database/database.sqlite'),
313
- },
314
- },
315
- }
316
- `,
317
-
318
- 'config/auth.ts': `import { User } from '../app/Models/User.ts'
319
-
320
- export default {
321
- defaults: {
322
- guard: 'web',
323
- },
324
-
325
- guards: {
326
- web: { driver: 'session', provider: 'users' },
327
- api: { driver: 'token', provider: 'users' },
328
- },
329
-
330
- providers: {
331
- users: { driver: 'database', model: User },
332
- },
333
- }
334
- `,
335
-
336
- 'config/filesystem.ts': `import { env } from '@mantiq/core'
337
-
338
- export default {
339
- default: env('FILESYSTEM_DISK', 'local'),
340
-
341
- disks: {
342
- local: {
343
- driver: 'local' as const,
344
- root: import.meta.dir + '/../storage/app',
345
- },
346
- public: {
347
- driver: 'local' as const,
348
- root: import.meta.dir + '/../storage/app/public',
349
- visibility: 'public' as const,
350
- },
351
- },
352
- }
353
- `,
354
-
355
- 'config/logging.ts': `import { env } from '@mantiq/core'
356
-
357
- export default {
358
- default: env('LOG_CHANNEL', 'stack'),
359
-
360
- channels: {
361
- stack: {
362
- driver: 'stack' as const,
363
- channels: ['console', 'daily'],
364
- },
365
- console: {
366
- driver: 'console' as const,
367
- level: 'debug' as const,
368
- },
369
- daily: {
370
- driver: 'daily' as const,
371
- path: 'storage/logs/mantiq.log',
372
- level: 'debug' as const,
373
- days: 14,
374
- },
375
- file: {
376
- driver: 'file' as const,
377
- path: 'storage/logs/mantiq.log',
378
- level: 'debug' as const,
379
- },
380
- },
381
- }
382
- `,
383
-
384
- 'config/queue.ts': `import { env } from '@mantiq/core'
385
-
386
- export default {
387
- default: env('QUEUE_CONNECTION', 'sync'),
388
-
389
- connections: {
390
- sync: {
391
- driver: 'sync' as const,
392
- },
393
- sqlite: {
394
- driver: 'sqlite' as const,
395
- database: import.meta.dir + '/../database/queue.sqlite',
396
- table: 'jobs',
397
- retryAfter: 60,
398
- },
399
- },
400
-
401
- failed: {
402
- driver: 'sqlite' as const,
403
- database: import.meta.dir + '/../database/queue.sqlite',
404
- table: 'failed_jobs',
405
- },
406
- }
407
- `,
408
-
409
- 'config/mail.ts': `import { env } from '@mantiq/core'
410
-
411
- export default {
412
- default: env('MAIL_MAILER', 'log'),
413
-
414
- from: {
415
- address: env('MAIL_FROM_ADDRESS', 'hello@example.com'),
416
- name: env('MAIL_FROM_NAME', '${ctx.name}'),
417
- },
418
-
419
- mailers: {
420
- smtp: {
421
- driver: 'smtp' as const,
422
- host: env('MAIL_HOST', 'localhost'),
423
- port: Number(env('MAIL_PORT', '587')),
424
- username: env('MAIL_USERNAME', ''),
425
- password: env('MAIL_PASSWORD', ''),
426
- encryption: env('MAIL_ENCRYPTION', 'starttls') as 'tls' | 'starttls' | 'none',
427
- },
428
-
429
- resend: {
430
- driver: 'resend' as const,
431
- apiKey: env('RESEND_API_KEY', ''),
432
- },
433
-
434
- sendgrid: {
435
- driver: 'sendgrid' as const,
436
- apiKey: env('SENDGRID_API_KEY', ''),
437
- },
438
-
439
- mailgun: {
440
- driver: 'mailgun' as const,
441
- apiKey: env('MAILGUN_API_KEY', ''),
442
- domain: env('MAILGUN_DOMAIN', ''),
443
- },
444
-
445
- postmark: {
446
- driver: 'postmark' as const,
447
- serverToken: env('POSTMARK_TOKEN', ''),
448
- },
449
-
450
- ses: {
451
- driver: 'ses' as const,
452
- region: env('AWS_REGION', 'us-east-1'),
453
- accessKeyId: env('AWS_ACCESS_KEY_ID', ''),
454
- secretAccessKey: env('AWS_SECRET_ACCESS_KEY', ''),
455
- },
456
-
457
- log: { driver: 'log' as const },
458
- array: { driver: 'array' as const },
459
- },
460
- }
461
- `,
462
-
463
- 'config/notify.ts': `export default {
464
- channels: {},
465
- }
466
- `,
467
-
468
- 'config/search.ts': `export default {
469
- default: 'collection',
470
- prefix: '',
471
- queue: false,
472
- softDelete: false,
473
-
474
- engines: {
475
- collection: {
476
- driver: 'collection' as const,
477
- },
478
- database: {
479
- driver: 'database' as const,
480
- },
481
- // algolia: {
482
- // driver: 'algolia' as const,
483
- // applicationId: env('ALGOLIA_APP_ID', ''),
484
- // apiKey: env('ALGOLIA_SECRET', ''),
485
- // },
486
- // meilisearch: {
487
- // driver: 'meilisearch' as const,
488
- // host: env('MEILISEARCH_HOST', 'http://127.0.0.1:7700'),
489
- // apiKey: env('MEILISEARCH_KEY', ''),
490
- // },
491
- },
492
- }
493
- `,
494
-
495
- 'config/heartbeat.ts': `export default {
496
- enabled: true,
497
-
498
- storage: {
499
- driver: 'sqlite' as const,
500
- path: 'storage/heartbeat/heartbeat.sqlite',
501
- retention: 86400, // 24 hours
502
- pruneInterval: 300, // 5 minutes
503
- },
504
-
505
- queue: {
506
- connection: 'sync',
507
- queue: 'heartbeat',
508
- batchSize: 50,
509
- flushInterval: 1000,
510
- },
511
-
512
- watchers: {
513
- request: { enabled: true, slow_threshold: 1000, ignore: [] },
514
- query: { enabled: true, slow_threshold: 100, detect_n_plus_one: true },
515
- exception: { enabled: true, ignore: [] },
516
- cache: { enabled: true },
517
- job: { enabled: true },
518
- event: { enabled: true, ignore: [] },
519
- model: { enabled: true },
520
- log: { enabled: true, level: 'debug' },
521
- schedule: { enabled: true },
522
- },
523
-
524
- tracing: {
525
- enabled: true,
526
- propagate: true,
527
- },
528
-
529
- sampling: {
530
- rate: 1.0,
531
- always_sample_errors: true,
532
- },
533
-
534
- dashboard: {
535
- enabled: true,
536
- path: '/_heartbeat',
537
- middleware: [],
538
- },
539
- }
540
- `,
541
-
542
- // ── Storage ─────────────────────────────────────────────────────────────
543
-
544
- 'storage/app/.gitkeep': '',
545
- 'storage/logs/.gitkeep': '',
546
-
547
- // ── Routes ──────────────────────────────────────────────────────────────
548
-
549
- 'routes/web.ts': `import type { Router } from '@mantiq/core'
550
- import { HomeController } from '../app/Http/Controllers/HomeController.ts'
551
-
552
- export default function (router: Router) {
553
- router.get('/', [HomeController, 'index'])
554
- }
555
- `,
556
-
557
- 'routes/api.ts': `import type { Router } from '@mantiq/core'
558
- import { MantiqResponse } from '@mantiq/core'
559
-
560
- export default function (router: Router) {
561
- router.get('/api/ping', () => {
562
- return MantiqResponse.json({ status: 'ok', timestamp: new Date().toISOString() })
563
- })
564
- }
565
- `,
566
-
567
- // ── App ─────────────────────────────────────────────────────────────────
568
-
569
- 'app/Http/Controllers/HomeController.ts': `import type { MantiqRequest } from '@mantiq/core'
570
- import { config } from '@mantiq/core'
571
-
572
- export class HomeController {
573
- async index(_request: MantiqRequest): Promise<Response> {
574
- const appName = config('app.name') ?? 'MantiqJS'
575
- const appEnv = config('app.env') ?? 'production'
576
- const debug = config('app.debug') ? 'Enabled' : 'Disabled'
577
- const bunVersion = typeof Bun !== 'undefined' ? Bun.version : 'unknown'
578
-
579
- let mantiqVersion = '0.0.0'
580
- try {
581
- const pkg = await Bun.file(require.resolve('@mantiq/core/package.json')).json()
582
- mantiqVersion = pkg.version
583
- } catch { /* fallback */ }
584
-
585
- const html = \`<!DOCTYPE html>
586
- <html lang="en">
587
- <head>
588
- <meta charset="UTF-8">
589
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
590
- <title>\${appName}</title>
591
- <style>
592
- *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
593
- body{
594
- font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
595
- background:#0a0a0b;color:#fafafa;min-height:100vh;
596
- display:flex;align-items:center;justify-content:center;
597
- -webkit-font-smoothing:antialiased;
598
- }
599
- .c{width:100%;max-width:460px;padding:32px;animation:up .5s ease}
600
- @keyframes up{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}
601
- .w{font-size:28px;font-weight:600;letter-spacing:-0.04em;color:#fafafa}
602
- .w .d{color:#10b981}
603
- .v{font-family:'SF Mono',ui-monospace,monospace;font-size:12px;color:#52525b;margin-top:6px}
604
- hr{border:none;border-top:1px solid #1e1e1e;margin:24px 0}
605
- .g{display:grid;grid-template-columns:1fr 1fr;gap:8px}
606
- .l{
607
- background:#111113;border:1px solid #1e1e1e;border-radius:8px;
608
- padding:14px 16px;text-decoration:none;color:#a1a1aa;font-size:13px;
609
- display:flex;align-items:center;justify-content:space-between;
610
- transition:border-color .15s,color .15s;
611
- }
612
- .l:hover{border-color:#27272a;color:#34d399}
613
- .l .a{color:#52525b;font-size:11px;transition:color .15s}
614
- .l:hover .a{color:#34d399}
615
- .e{
616
- margin-top:24px;font-family:'SF Mono',ui-monospace,monospace;
617
- font-size:11px;color:#3f3f46;line-height:2;
618
- }
619
- .e span{color:#52525b}
620
- </style>
621
- </head>
622
- <body>
623
- <div class="c">
624
- <div class="w"><span class="d">.</span>mantiq</div>
625
- <div class="v">v\${mantiqVersion} — \${appName}</div>
626
- <hr>
627
- <div class="g">
628
- <a class="l" href="/_heartbeat">Heartbeat<span class="a">&rarr;</span></a>
629
- <a class="l" href="/api/ping">API Ping<span class="a">&rarr;</span></a>
630
- <a class="l" href="https://github.com/mantiqjs/mantiq" target="_blank" rel="noopener">GitHub<span class="a">&nearr;</span></a>
631
- <a class="l" href="https://www.npmjs.com/org/mantiq" target="_blank" rel="noopener">npm<span class="a">&nearr;</span></a>
632
- </div>
633
- <div class="e">
634
- <span>Runtime</span> Bun \${bunVersion}<br>
635
- <span>Environment</span> \${appEnv}<br>
636
- <span>Debug</span> \${debug}
637
- </div>
638
- </div>
639
- </body>
640
- </html>\`
641
-
642
- return new Response(html, {
643
- headers: { 'Content-Type': 'text/html; charset=utf-8' },
644
- })
25
+ const templates: Record<string, string> = {}
26
+
27
+ // ── package.json (always dynamic — name + deps) ────────────────────────
28
+ const baseDeps: Record<string, string> = {
29
+ ...(ctx.auth !== 'none' ? { '@mantiq/auth': '^0.7.0' } : {}),
30
+ '@mantiq/cli': '^0.7.0',
31
+ '@mantiq/core': '^0.7.0',
32
+ '@mantiq/database': '^0.7.0',
33
+ '@mantiq/events': '^0.7.0',
34
+ '@mantiq/filesystem': '^0.7.0',
35
+ '@mantiq/heartbeat': '^0.7.0',
36
+ '@mantiq/helpers': '^0.7.0',
37
+ '@mantiq/logging': '^0.7.0',
38
+ '@mantiq/queue': '^0.7.0',
39
+ '@mantiq/realtime': '^0.7.0',
40
+ '@mantiq/validation': '^0.7.0',
41
+ '@mantiq/mail': '^0.7.0',
42
+ '@mantiq/notify': '^0.7.0',
43
+ '@mantiq/search': '^0.7.0',
44
+ '@mantiq/health': '^0.7.0',
45
+ ...(ctx.optionalPackages.includes('ai') ? { '@mantiq/ai': '^0.7.0' } : {}),
46
+ ...(ctx.optionalPackages.includes('studio') ? { '@mantiq/studio': '^0.7.0' } : {}),
645
47
  }
646
- }
647
- `,
648
-
649
- 'app/Http/Middleware/.gitkeep': '',
650
-
651
- 'app/Models/User.ts': `import { Model } from '@mantiq/database'
652
- import type { Authenticatable } from '@mantiq/auth'
653
-
654
- export class User extends Model implements Authenticatable {
655
- static override table = 'users'
656
- static override fillable = ['name', 'email', 'password']
657
- static override guarded = ['id']
658
- static override hidden = ['password', 'remember_token']
659
- static override timestamps = true
660
-
661
- getAuthIdentifierName(): string { return 'id' }
662
- getAuthIdentifier(): number { return this.getAttribute('id') as number }
663
- getAuthPasswordName(): string { return 'password' }
664
- getAuthPassword(): string { return this.getAttribute('password') as string }
665
- getRememberToken(): string | null { return (this.getAttribute('remember_token') as string) ?? null }
666
- setRememberToken(token: string | null): void { this.setAttribute('remember_token', token) }
667
- getRememberTokenName(): string { return 'remember_token' }
668
- }
669
- `,
670
48
 
671
- 'app/Models/PersonalAccessToken.ts': `import { PersonalAccessToken as BaseToken } from '@mantiq/auth'
672
-
673
- // Re-export the built-in PersonalAccessToken.
674
- // Extend this class if you need to add custom logic.
675
- export class PersonalAccessToken extends BaseToken {}
676
- `,
677
-
678
- 'app/Providers/DatabaseServiceProvider.ts': `import { ServiceProvider, config } from '@mantiq/core'
679
- import { DatabaseManager, setupModels, setManager, Migrator } from '@mantiq/database'
680
- import { applyHasApiTokens, PersonalAccessToken } from '@mantiq/auth'
681
- import { User } from '../Models/User.ts'
682
-
683
- export class DatabaseServiceProvider extends ServiceProvider {
684
- override register(): void {
685
- this.app.singleton(DatabaseManager, () => {
686
- const dbConfig = config('database')
687
- const manager = new DatabaseManager(dbConfig)
688
-
689
- setManager(manager)
690
- setupModels(manager)
691
-
692
- return manager
693
- })
49
+ const baseDevDeps: Record<string, string> = {
50
+ '@mantiq/testing': '^0.7.0',
51
+ 'bun-types': 'latest',
52
+ 'typescript': '^5.7.0',
694
53
  }
695
54
 
696
- override async boot(): Promise<void> {
697
- // Resolve the manager (triggers creation via the singleton factory)
698
- const manager = this.app.make(DatabaseManager)
699
-
700
- // Set up PersonalAccessToken connection and apply HasApiTokens mixin
701
- PersonalAccessToken.setConnection(manager.connection())
702
- applyHasApiTokens(User)
55
+ const scripts: Record<string, string> = {
56
+ dev: 'bun run --watch index.ts',
57
+ start: 'bun run index.ts',
58
+ mantiq: 'bun run mantiq.ts',
59
+ test: 'bun test tests/',
703
60
  }
704
- }
705
- `,
706
-
707
- // ── Database ────────────────────────────────────────────────────────────
708
-
709
- 'database/migrations/001_create_users_table.ts': `import { Migration } from '@mantiq/database'
710
- import type { SchemaBuilder } from '@mantiq/database'
711
61
 
712
- export default class CreateUsersTable extends Migration {
713
- override async up(schema: SchemaBuilder) {
714
- await schema.create('users', (t) => {
715
- t.id()
716
- t.string('name', 100)
717
- t.string('email', 150).unique()
718
- t.string('password', 255)
719
- t.string('remember_token', 100).nullable()
720
- t.timestamps()
62
+ if (ctx.kit) {
63
+ // Kit-specific additions
64
+ const frameworkDevDeps: Record<string, string> = ctx.kit === 'react'
65
+ ? { 'react': '^19.0.0', 'react-dom': '^19.0.0', '@vitejs/plugin-react': '^6.0.0', '@types/react': '^19.0.0', '@types/react-dom': '^19.0.0' }
66
+ : ctx.kit === 'vue'
67
+ ? { 'vue': '^3.5.0', '@vitejs/plugin-vue': '^6.0.0' }
68
+ : { 'svelte': '^5.0.0', '@sveltejs/vite-plugin-svelte': '^7.0.0' }
69
+
70
+ const shadcnOnly = ctx.ui === 'shadcn'
71
+
72
+ const uiDeps: Record<string, string> = ctx.kit === 'react'
73
+ ? {
74
+ 'clsx': '^2.1.0', 'tailwind-merge': '^2.6.0',
75
+ ...(shadcnOnly ? { 'class-variance-authority': '^0.7.1', 'lucide-react': '^0.577.0', 'radix-ui': '^1.4.0' } : {}),
76
+ }
77
+ : ctx.kit === 'vue'
78
+ ? {
79
+ 'clsx': '^2.1.0', 'tailwind-merge': '^3.5.0',
80
+ ...(shadcnOnly ? { 'class-variance-authority': '^0.7.1', 'lucide-vue-next': '^0.577.0', 'reka-ui': '^2.9.0' } : {}),
81
+ 'tw-animate-css': '^1.4.0', '@tanstack/vue-table': '^8.0.0',
82
+ }
83
+ : {
84
+ 'clsx': '^2.1.0', 'tailwind-merge': '^2.6.0',
85
+ ...(shadcnOnly ? { 'tailwind-variants': '^3.2.0', 'lucide-svelte': '^0.577.0', '@lucide/svelte': '^0.577.0', 'bits-ui': '^2.16.0' } : {}),
86
+ }
87
+
88
+ Object.assign(baseDeps, {
89
+ '@mantiq/vite': '^0.7.0',
90
+ ...uiDeps,
721
91
  })
722
- }
723
92
 
724
- override async down(schema: SchemaBuilder) {
725
- await schema.dropIfExists('users')
726
- }
727
- }
728
- `,
729
-
730
- 'database/migrations/002_create_personal_access_tokens_table.ts': `import { Migration } from '@mantiq/database'
731
- import type { SchemaBuilder } from '@mantiq/database'
732
-
733
- export default class CreatePersonalAccessTokensTable extends Migration {
734
- override async up(schema: SchemaBuilder) {
735
- await schema.create('personal_access_tokens', (t) => {
736
- t.id()
737
- t.string('tokenable_type')
738
- t.unsignedBigInteger('tokenable_id')
739
- t.string('name')
740
- t.string('token', 64).unique()
741
- t.json('abilities').nullable()
742
- t.timestamp('last_used_at').nullable()
743
- t.timestamp('expires_at').nullable()
744
- t.timestamps()
93
+ Object.assign(baseDevDeps, {
94
+ 'vite': '^8.0.0',
95
+ 'tailwindcss': '^4.0.0',
96
+ '@tailwindcss/vite': '^4.0.0',
97
+ ...frameworkDevDeps,
745
98
  })
746
- }
747
-
748
- override async down(schema: SchemaBuilder) {
749
- await schema.dropIfExists('personal_access_tokens')
750
- }
751
- }
752
- `,
753
-
754
- 'database/seeders/DatabaseSeeder.ts': `import { Seeder } from '@mantiq/database'
755
99
 
756
- export default class DatabaseSeeder extends Seeder {
757
- override async run() {
758
- // await this.call(UserSeeder)
100
+ scripts.dev = 'bun run dev:backend & bun run dev:frontend & wait'
101
+ scripts['dev:backend'] = 'bun run --watch index.ts'
102
+ scripts['dev:frontend'] = 'bunx vite --clearScreen false'
103
+ scripts.build = `vite build && vite build --ssr ${ctx.kit === 'react' ? 'src/ssr.tsx' : 'src/ssr.ts'} --outDir bootstrap/ssr`
759
104
  }
760
- }
761
- `,
762
-
763
- 'database/factories/.gitkeep': '',
764
-
765
- 'public/.gitkeep': '',
766
- }
767
-
768
- // Apply starter kit overrides
769
- if (ctx.kit) {
770
- applyKitOverrides(templates, ctx)
771
- }
772
-
773
- return templates
774
- }
775
-
776
- // ── Starter Kit Overrides ────────────────────────────────────────────────────
777
-
778
- function applyKitOverrides(templates: Record<string, string>, ctx: TemplateContext): void {
779
- const kit = ctx.kit!
780
-
781
- // ── package.json ────────────────────────────────────────────────────────
782
- const frameworkDevDeps: Record<string, string> = kit === 'react'
783
- ? { 'react': '^19.0.0', 'react-dom': '^19.0.0', '@vitejs/plugin-react': '^4.0.0', '@types/react': '^19.0.0', '@types/react-dom': '^19.0.0' }
784
- : kit === 'vue'
785
- ? { 'vue': '^3.5.0', '@vitejs/plugin-vue': '^5.0.0' }
786
- : { 'svelte': '^5.0.0', '@sveltejs/vite-plugin-svelte': '^5.0.0' }
787
-
788
- // UI library deps (shadcn + icons) — must match what the stubs actually import
789
- const uiDeps: Record<string, string> = kit === 'react'
790
- ? { 'clsx': '^2.1.0', 'tailwind-merge': '^2.6.0', 'class-variance-authority': '^0.7.1', 'lucide-react': '^0.577.0', 'radix-ui': '^1.4.0' }
791
- : kit === 'vue'
792
- ? { 'clsx': '^2.1.0', 'tailwind-merge': '^3.5.0', 'class-variance-authority': '^0.7.1', 'lucide-vue-next': '^0.577.0', 'reka-ui': '^2.9.0', 'tw-animate-css': '^1.4.0', '@tanstack/vue-table': '^8.0.0' }
793
- : { 'clsx': '^2.1.0', 'tailwind-merge': '^2.6.0', 'tailwind-variants': '^3.2.0', 'lucide-svelte': '^0.577.0', '@lucide/svelte': '^0.577.0', 'bits-ui': '^2.16.0' }
794
105
 
795
106
  templates['package.json'] = JSON.stringify({
796
107
  name: ctx.name,
797
108
  version: '0.0.1',
798
109
  private: true,
799
110
  type: 'module',
800
- scripts: {
801
- dev: 'bun run --watch index.ts',
802
- start: 'bun run index.ts',
803
- mantiq: 'bun run mantiq.ts',
804
- build: `vite build && vite build --ssr ${kit === 'react' ? 'src/ssr.tsx' : 'src/ssr.ts'} --outDir bootstrap/ssr`,
805
- setup: 'bun install && bun mantiq migrate && bun mantiq seed && bun run build',
806
- postinstall: 'rm -rf node_modules/@mantiq/*/node_modules/@mantiq 2>/dev/null; true',
807
- },
808
- dependencies: {
809
- '@mantiq/auth': '^0.2.0',
810
- '@mantiq/cli': '^0.1.6',
811
- '@mantiq/core': '^0.2.0',
812
- '@mantiq/database': '^0.1.4',
813
- '@mantiq/events': '^0.1.2',
814
- '@mantiq/filesystem': '^0.1.2',
815
- '@mantiq/heartbeat': '^0.3.0',
816
- '@mantiq/helpers': '^0.1.2',
817
- '@mantiq/logging': '^0.1.2',
818
- '@mantiq/queue': '^0.1.2',
819
- '@mantiq/realtime': '^0.1.2',
820
- '@mantiq/validation': '^0.1.2',
821
- '@mantiq/mail': '^0.2.0',
822
- '@mantiq/notify': '^0.1.0',
823
- '@mantiq/search': '^0.1.0',
824
- '@mantiq/health': '^0.1.0',
825
- '@mantiq/vite': '^0.1.3',
826
- ...uiDeps,
827
- },
828
- devDependencies: {
829
- 'bun-types': 'latest',
830
- 'typescript': '^5.7.0',
831
- 'vite': '^6.0.0',
832
- 'tailwindcss': '^4.0.0',
833
- '@tailwindcss/vite': '^4.0.0',
834
- ...frameworkDevDeps,
835
- },
111
+ scripts,
112
+ dependencies: baseDeps,
113
+ devDependencies: baseDevDeps,
836
114
  }, null, 2) + '\n'
837
115
 
838
- // ── .env ────────────────────────────────────────────────────────────────
839
- templates['.env'] = `APP_NAME=${ctx.name}
116
+ // ── .env (dynamic — APP_KEY generated) ─────────────────────────────────
117
+ const envBody = (appKey: string) => `# Application
118
+ APP_NAME=${ctx.name}
840
119
  APP_ENV=local
841
120
  APP_DEBUG=true
121
+ APP_KEY=${appKey}
842
122
  APP_URL=http://localhost:3000
843
123
  APP_PORT=3000
844
- APP_KEY=${ctx.appKey}
845
124
 
125
+ # Database
846
126
  DB_CONNECTION=sqlite
847
127
  DB_DATABASE=database/database.sqlite
848
-
849
- LOG_CHANNEL=stack
128
+ # DB_HOST=127.0.0.1
129
+ # DB_PORT=5432
130
+ # DB_USERNAME=postgres
131
+ # DB_PASSWORD=
132
+
133
+ # Session
134
+ SESSION_DRIVER=memory
135
+ SESSION_LIFETIME=120
136
+ SESSION_COOKIE=mantiq_session
137
+
138
+ # Cache
139
+ CACHE_STORE=memory
140
+ # REDIS_HOST=127.0.0.1
141
+ # REDIS_PORT=6379
142
+ # REDIS_PASSWORD=
143
+
144
+ # Queue
850
145
  QUEUE_CONNECTION=sync
851
146
 
852
- VITE_DEV_SERVER_URL=http://localhost:5173
853
- `
854
-
855
- templates['.env.example'] = `APP_NAME=${ctx.name}
856
- APP_ENV=local
857
- APP_DEBUG=true
858
- APP_URL=http://localhost:3000
859
- APP_PORT=3000
860
- APP_KEY=
861
-
862
- DB_CONNECTION=sqlite
863
- DB_DATABASE=database/database.sqlite
864
-
147
+ # Mail
148
+ MAIL_MAILER=log
149
+ MAIL_FROM_ADDRESS=hello@example.com
150
+ MAIL_FROM_NAME=\${APP_NAME}
151
+ # MAIL_HOST=localhost
152
+ # MAIL_PORT=587
153
+ # MAIL_USERNAME=
154
+ # MAIL_PASSWORD=
155
+
156
+ # Logging
865
157
  LOG_CHANNEL=stack
866
- QUEUE_CONNECTION=sync
867
158
 
868
- VITE_DEV_SERVER_URL=http://localhost:5173
869
- `
870
-
871
- // ── .gitignore ──────────────────────────────────────────────────────────
872
- templates['.gitignore'] = `node_modules/
873
- dist/
874
- *.sqlite
875
- *.sqlite-journal
876
- *.sqlite-wal
877
- *.sqlite-shm
878
- .env
879
- .DS_Store
880
- tsconfig.tsbuildinfo
881
- storage/logs/
882
- storage/app/
883
- storage/heartbeat/
884
- public/build/
885
- public/hot
886
- bootstrap/
887
- `
159
+ # Hashing
160
+ HASH_DRIVER=bcrypt
161
+ BCRYPT_ROUNDS=10
888
162
 
889
- // ── index.ts ────────────────────────────────────────────────────────────
890
- templates['index.ts'] = `import { Application, CoreServiceProvider, HttpKernel, RouterImpl, CorsMiddleware, StartSession, EncryptCookies, VerifyCsrfToken } from '@mantiq/core'
891
- import { ViteServiceProvider, ServeStaticFiles } from '@mantiq/vite'
892
- import { AuthServiceProvider, Authenticate, RedirectIfAuthenticated, CheckAbilities, CheckForAnyAbility } from '@mantiq/auth'
893
- import { FilesystemServiceProvider } from '@mantiq/filesystem'
894
- import { LoggingServiceProvider } from '@mantiq/logging'
895
- import { EventServiceProvider } from '@mantiq/events'
896
- import { QueueServiceProvider } from '@mantiq/queue'
897
- import { ValidationServiceProvider } from '@mantiq/validation'
898
- import { HeartbeatServiceProvider, HeartbeatMiddleware } from '@mantiq/heartbeat'
899
- import { RealtimeServiceProvider } from '@mantiq/realtime'
900
- import { MailServiceProvider } from '@mantiq/mail'
901
- import { NotificationServiceProvider } from '@mantiq/notify'
902
- import { SearchServiceProvider } from '@mantiq/search'
903
- import { DatabaseServiceProvider } from './app/Providers/DatabaseServiceProvider.ts'
904
-
905
- // ── Load .env ─────────────────────────────────────────────────────────────────
906
- const envFile = Bun.file(import.meta.dir + '/.env')
907
- if (await envFile.exists()) {
908
- const text = await envFile.text()
909
- for (const line of text.split('\\n')) {
910
- const trimmed = line.trim()
911
- if (!trimmed || trimmed.startsWith('#')) continue
912
- const eqIdx = trimmed.indexOf('=')
913
- if (eqIdx === -1) continue
914
- const key = trimmed.slice(0, eqIdx).trim()
915
- const value = trimmed.slice(eqIdx + 1).trim()
916
- if (key && !(key in process.env)) process.env[key] = value
917
- }
918
- }
163
+ # Broadcasting
164
+ BROADCAST_DRIVER=bun
919
165
 
920
- // ── Bootstrap ─────────────────────────────────────────────────────────────────
921
- const app = await Application.create(import.meta.dir, 'config')
166
+ # Filesystem
167
+ FILESYSTEM_DISK=local
922
168
 
923
- await app.registerProviders([
924
- CoreServiceProvider,
925
- DatabaseServiceProvider,
926
- AuthServiceProvider,
927
- ViteServiceProvider,
928
- FilesystemServiceProvider,
929
- LoggingServiceProvider,
930
- EventServiceProvider,
931
- QueueServiceProvider,
932
- ValidationServiceProvider,
933
- HeartbeatServiceProvider,
934
- RealtimeServiceProvider,
935
- MailServiceProvider,
936
- NotificationServiceProvider,
937
- SearchServiceProvider,
938
- ])
939
- await app.bootProviders()
940
-
941
- // ── Seed default data (only when running the server directly) ────────────────
942
- if (import.meta.main) {
943
- try {
944
- const UserSeeder = (await import('./database/seeders/UserSeeder.ts')).default
945
- await new UserSeeder().run()
946
- } catch {
947
- // Table may not exist yet — run: bun mantiq migrate
948
- }
949
- }
950
-
951
- // ── Kernel setup ──────────────────────────────────────────────────────────────
952
- const kernel = app.make(HttpKernel)
953
- const router = app.make(RouterImpl)
954
-
955
- // Register middleware aliases
956
- kernel.registerMiddleware('cors', CorsMiddleware)
957
- kernel.registerMiddleware('static', ServeStaticFiles)
958
- kernel.registerMiddleware('encrypt.cookies', EncryptCookies)
959
- kernel.registerMiddleware('session', StartSession)
960
- kernel.registerMiddleware('csrf', VerifyCsrfToken)
961
- kernel.registerMiddleware('auth', Authenticate)
962
- kernel.registerMiddleware('guest', RedirectIfAuthenticated)
963
- kernel.registerMiddleware('heartbeat', HeartbeatMiddleware)
964
- kernel.registerMiddleware('abilities', CheckAbilities)
965
- kernel.registerMiddleware('ability', CheckForAnyAbility)
966
-
967
- // Global middleware
968
- kernel.setGlobalMiddleware(['static', 'cors', 'encrypt.cookies', 'session', 'heartbeat'])
969
-
970
- // ── Routes ────────────────────────────────────────────────────────────────────
971
- import webRoutes from './routes/web.ts'
972
- import apiRoutes from './routes/api.ts'
973
-
974
- webRoutes(router)
975
- apiRoutes(router)
169
+ # Search
170
+ # ALGOLIA_APP_ID=
171
+ # ALGOLIA_SECRET=
172
+ # MEILISEARCH_HOST=http://127.0.0.1:7700
173
+ # MEILISEARCH_KEY=
174
+ ${ctx.kit ? '\n# Vite\nVITE_DEV_SERVER_URL=http://localhost:5173' : ''}
175
+ `
976
176
 
977
- // ── Export for CLI ────────────────────────────────────────────────────────────
978
- export default app
177
+ templates['.env'] = envBody(ctx.appKey)
178
+ templates['.env.example'] = envBody('')
979
179
 
980
- // ── Start ─────────────────────────────────────────────────────────────────────
981
- if (import.meta.main) {
982
- await kernel.start()
983
- }
984
- `
180
+ return templates
985
181
  }