alepha 0.15.1 → 0.15.3

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 (523) hide show
  1. package/README.md +68 -80
  2. package/dist/api/audits/index.d.ts +10 -33
  3. package/dist/api/audits/index.d.ts.map +1 -1
  4. package/dist/api/audits/index.js +10 -33
  5. package/dist/api/audits/index.js.map +1 -1
  6. package/dist/api/files/index.d.ts +10 -3
  7. package/dist/api/files/index.d.ts.map +1 -1
  8. package/dist/api/files/index.js +10 -3
  9. package/dist/api/files/index.js.map +1 -1
  10. package/dist/api/jobs/index.d.ts +162 -155
  11. package/dist/api/jobs/index.d.ts.map +1 -1
  12. package/dist/api/jobs/index.js +10 -3
  13. package/dist/api/jobs/index.js.map +1 -1
  14. package/dist/api/keys/index.d.ts +413 -0
  15. package/dist/api/keys/index.d.ts.map +1 -0
  16. package/dist/api/keys/index.js +476 -0
  17. package/dist/api/keys/index.js.map +1 -0
  18. package/dist/api/notifications/index.d.ts +10 -4
  19. package/dist/api/notifications/index.d.ts.map +1 -1
  20. package/dist/api/notifications/index.js +10 -4
  21. package/dist/api/notifications/index.js.map +1 -1
  22. package/dist/api/parameters/index.d.ts +43 -50
  23. package/dist/api/parameters/index.d.ts.map +1 -1
  24. package/dist/api/parameters/index.js +30 -37
  25. package/dist/api/parameters/index.js.map +1 -1
  26. package/dist/api/users/index.d.ts +1081 -760
  27. package/dist/api/users/index.d.ts.map +1 -1
  28. package/dist/api/users/index.js +2539 -218
  29. package/dist/api/users/index.js.map +1 -1
  30. package/dist/api/verifications/index.d.ts +138 -132
  31. package/dist/api/verifications/index.d.ts.map +1 -1
  32. package/dist/api/verifications/index.js +12 -4
  33. package/dist/api/verifications/index.js.map +1 -1
  34. package/dist/batch/index.d.ts +20 -40
  35. package/dist/batch/index.d.ts.map +1 -1
  36. package/dist/batch/index.js +31 -44
  37. package/dist/batch/index.js.map +1 -1
  38. package/dist/bucket/index.d.ts +440 -8
  39. package/dist/bucket/index.d.ts.map +1 -1
  40. package/dist/bucket/index.js +1861 -12
  41. package/dist/bucket/index.js.map +1 -1
  42. package/dist/cache/core/index.d.ts +179 -7
  43. package/dist/cache/core/index.d.ts.map +1 -1
  44. package/dist/cache/core/index.js +213 -7
  45. package/dist/cache/core/index.js.map +1 -1
  46. package/dist/cache/redis/index.d.ts +1 -0
  47. package/dist/cache/redis/index.d.ts.map +1 -1
  48. package/dist/cache/redis/index.js +4 -0
  49. package/dist/cache/redis/index.js.map +1 -1
  50. package/dist/cli/index.d.ts +638 -5645
  51. package/dist/cli/index.d.ts.map +1 -1
  52. package/dist/cli/index.js +2550 -368
  53. package/dist/cli/index.js.map +1 -1
  54. package/dist/command/index.d.ts +203 -45
  55. package/dist/command/index.d.ts.map +1 -1
  56. package/dist/command/index.js +2060 -71
  57. package/dist/command/index.js.map +1 -1
  58. package/dist/core/index.browser.js +70 -40
  59. package/dist/core/index.browser.js.map +1 -1
  60. package/dist/core/index.d.ts +34 -13
  61. package/dist/core/index.d.ts.map +1 -1
  62. package/dist/core/index.js +90 -40
  63. package/dist/core/index.js.map +1 -1
  64. package/dist/core/index.native.js +70 -40
  65. package/dist/core/index.native.js.map +1 -1
  66. package/dist/datetime/index.d.ts +15 -0
  67. package/dist/datetime/index.d.ts.map +1 -1
  68. package/dist/datetime/index.js +15 -0
  69. package/dist/datetime/index.js.map +1 -1
  70. package/dist/email/index.d.ts +323 -20
  71. package/dist/email/index.d.ts.map +1 -1
  72. package/dist/email/index.js +1857 -7
  73. package/dist/email/index.js.map +1 -1
  74. package/dist/fake/index.d.ts +90 -8
  75. package/dist/fake/index.d.ts.map +1 -1
  76. package/dist/fake/index.js +91 -20
  77. package/dist/fake/index.js.map +1 -1
  78. package/dist/lock/core/index.d.ts +11 -4
  79. package/dist/lock/core/index.d.ts.map +1 -1
  80. package/dist/lock/core/index.js +11 -4
  81. package/dist/lock/core/index.js.map +1 -1
  82. package/dist/logger/index.d.ts +17 -66
  83. package/dist/logger/index.d.ts.map +1 -1
  84. package/dist/logger/index.js +14 -63
  85. package/dist/logger/index.js.map +1 -1
  86. package/dist/mcp/index.d.ts +10 -30
  87. package/dist/mcp/index.d.ts.map +1 -1
  88. package/dist/mcp/index.js +12 -35
  89. package/dist/mcp/index.js.map +1 -1
  90. package/dist/orm/index.browser.js +3 -3
  91. package/dist/orm/index.browser.js.map +1 -1
  92. package/dist/orm/index.bun.js +39 -20
  93. package/dist/orm/index.bun.js.map +1 -1
  94. package/dist/orm/index.d.ts +517 -540
  95. package/dist/orm/index.d.ts.map +1 -1
  96. package/dist/orm/index.js +58 -71
  97. package/dist/orm/index.js.map +1 -1
  98. package/dist/queue/core/index.d.ts +18 -10
  99. package/dist/queue/core/index.d.ts.map +1 -1
  100. package/dist/queue/core/index.js +14 -6
  101. package/dist/queue/core/index.js.map +1 -1
  102. package/dist/react/auth/index.browser.js +108 -0
  103. package/dist/react/auth/index.browser.js.map +1 -0
  104. package/dist/react/auth/index.d.ts +100 -0
  105. package/dist/react/auth/index.d.ts.map +1 -0
  106. package/dist/react/auth/index.js +145 -0
  107. package/dist/react/auth/index.js.map +1 -0
  108. package/dist/react/core/index.d.ts +469 -0
  109. package/dist/react/core/index.d.ts.map +1 -0
  110. package/dist/react/core/index.js +464 -0
  111. package/dist/react/core/index.js.map +1 -0
  112. package/dist/react/form/index.d.ts +232 -0
  113. package/dist/react/form/index.d.ts.map +1 -0
  114. package/dist/react/form/index.js +432 -0
  115. package/dist/react/form/index.js.map +1 -0
  116. package/dist/react/head/index.browser.js +423 -0
  117. package/dist/react/head/index.browser.js.map +1 -0
  118. package/dist/react/head/index.d.ts +288 -0
  119. package/dist/react/head/index.d.ts.map +1 -0
  120. package/dist/react/head/index.js +465 -0
  121. package/dist/react/head/index.js.map +1 -0
  122. package/dist/react/i18n/index.d.ts +175 -0
  123. package/dist/react/i18n/index.d.ts.map +1 -0
  124. package/dist/react/i18n/index.js +224 -0
  125. package/dist/react/i18n/index.js.map +1 -0
  126. package/dist/react/router/index.browser.js +1974 -0
  127. package/dist/react/router/index.browser.js.map +1 -0
  128. package/dist/react/router/index.d.ts +1956 -0
  129. package/dist/react/router/index.d.ts.map +1 -0
  130. package/dist/react/router/index.js +4722 -0
  131. package/dist/react/router/index.js.map +1 -0
  132. package/dist/react/websocket/index.d.ts +117 -0
  133. package/dist/react/websocket/index.d.ts.map +1 -0
  134. package/dist/react/websocket/index.js +107 -0
  135. package/dist/react/websocket/index.js.map +1 -0
  136. package/dist/redis/index.bun.js +4 -0
  137. package/dist/redis/index.bun.js.map +1 -1
  138. package/dist/redis/index.d.ts +41 -44
  139. package/dist/redis/index.d.ts.map +1 -1
  140. package/dist/redis/index.js +16 -25
  141. package/dist/redis/index.js.map +1 -1
  142. package/dist/retry/index.d.ts +11 -2
  143. package/dist/retry/index.d.ts.map +1 -1
  144. package/dist/retry/index.js +11 -2
  145. package/dist/retry/index.js.map +1 -1
  146. package/dist/scheduler/index.d.ts +11 -2
  147. package/dist/scheduler/index.d.ts.map +1 -1
  148. package/dist/scheduler/index.js +11 -2
  149. package/dist/scheduler/index.js.map +1 -1
  150. package/dist/security/index.d.ts +140 -49
  151. package/dist/security/index.d.ts.map +1 -1
  152. package/dist/security/index.js +164 -32
  153. package/dist/security/index.js.map +1 -1
  154. package/dist/server/auth/index.d.ts +12 -7
  155. package/dist/server/auth/index.d.ts.map +1 -1
  156. package/dist/server/auth/index.js +12 -7
  157. package/dist/server/auth/index.js.map +1 -1
  158. package/dist/server/cache/index.d.ts +7 -22
  159. package/dist/server/cache/index.d.ts.map +1 -1
  160. package/dist/server/cache/index.js +7 -22
  161. package/dist/server/cache/index.js.map +1 -1
  162. package/dist/server/compress/index.d.ts +10 -2
  163. package/dist/server/compress/index.d.ts.map +1 -1
  164. package/dist/server/compress/index.js +10 -2
  165. package/dist/server/compress/index.js.map +1 -1
  166. package/dist/server/cookies/index.d.ts +40 -16
  167. package/dist/server/cookies/index.d.ts.map +1 -1
  168. package/dist/server/cookies/index.js +7 -5
  169. package/dist/server/cookies/index.js.map +1 -1
  170. package/dist/server/core/index.d.ts +124 -23
  171. package/dist/server/core/index.d.ts.map +1 -1
  172. package/dist/server/core/index.js +231 -14
  173. package/dist/server/core/index.js.map +1 -1
  174. package/dist/server/cors/index.d.ts +13 -23
  175. package/dist/server/cors/index.d.ts.map +1 -1
  176. package/dist/server/cors/index.js +7 -21
  177. package/dist/server/cors/index.js.map +1 -1
  178. package/dist/server/health/index.d.ts +8 -2
  179. package/dist/server/health/index.d.ts.map +1 -1
  180. package/dist/server/health/index.js +8 -2
  181. package/dist/server/health/index.js.map +1 -1
  182. package/dist/server/helmet/index.d.ts +11 -3
  183. package/dist/server/helmet/index.d.ts.map +1 -1
  184. package/dist/server/helmet/index.js +11 -3
  185. package/dist/server/helmet/index.js.map +1 -1
  186. package/dist/server/links/index.d.ts +11 -6
  187. package/dist/server/links/index.d.ts.map +1 -1
  188. package/dist/server/links/index.js +11 -6
  189. package/dist/server/links/index.js.map +1 -1
  190. package/dist/server/metrics/index.d.ts +10 -3
  191. package/dist/server/metrics/index.d.ts.map +1 -1
  192. package/dist/server/metrics/index.js +10 -3
  193. package/dist/server/metrics/index.js.map +1 -1
  194. package/dist/server/multipart/index.d.ts +9 -3
  195. package/dist/server/multipart/index.d.ts.map +1 -1
  196. package/dist/server/multipart/index.js +9 -3
  197. package/dist/server/multipart/index.js.map +1 -1
  198. package/dist/server/proxy/index.d.ts +8 -2
  199. package/dist/server/proxy/index.d.ts.map +1 -1
  200. package/dist/server/proxy/index.js +8 -2
  201. package/dist/server/proxy/index.js.map +1 -1
  202. package/dist/server/rate-limit/index.d.ts +30 -35
  203. package/dist/server/rate-limit/index.d.ts.map +1 -1
  204. package/dist/server/rate-limit/index.js +18 -55
  205. package/dist/server/rate-limit/index.js.map +1 -1
  206. package/dist/server/static/index.d.ts +137 -4
  207. package/dist/server/static/index.d.ts.map +1 -1
  208. package/dist/server/static/index.js +1853 -5
  209. package/dist/server/static/index.js.map +1 -1
  210. package/dist/server/swagger/index.d.ts +309 -6
  211. package/dist/server/swagger/index.d.ts.map +1 -1
  212. package/dist/server/swagger/index.js +1854 -6
  213. package/dist/server/swagger/index.js.map +1 -1
  214. package/dist/sms/index.d.ts +309 -7
  215. package/dist/sms/index.d.ts.map +1 -1
  216. package/dist/sms/index.js +1856 -7
  217. package/dist/sms/index.js.map +1 -1
  218. package/dist/system/index.browser.js +1218 -0
  219. package/dist/system/index.browser.js.map +1 -0
  220. package/dist/{file → system}/index.d.ts +343 -16
  221. package/dist/system/index.d.ts.map +1 -0
  222. package/dist/{file → system}/index.js +419 -22
  223. package/dist/system/index.js.map +1 -0
  224. package/dist/thread/index.d.ts +11 -2
  225. package/dist/thread/index.d.ts.map +1 -1
  226. package/dist/thread/index.js +11 -2
  227. package/dist/thread/index.js.map +1 -1
  228. package/dist/topic/core/index.d.ts +12 -5
  229. package/dist/topic/core/index.d.ts.map +1 -1
  230. package/dist/topic/core/index.js +12 -5
  231. package/dist/topic/core/index.js.map +1 -1
  232. package/dist/vite/index.d.ts +5 -6272
  233. package/dist/vite/index.d.ts.map +1 -1
  234. package/dist/vite/index.js +23 -10
  235. package/dist/vite/index.js.map +1 -1
  236. package/dist/websocket/index.d.ts +12 -8
  237. package/dist/websocket/index.d.ts.map +1 -1
  238. package/dist/websocket/index.js +12 -8
  239. package/dist/websocket/index.js.map +1 -1
  240. package/package.json +82 -11
  241. package/src/api/audits/index.ts +10 -33
  242. package/src/api/files/__tests__/$bucket.spec.ts +1 -1
  243. package/src/api/files/controllers/AdminFileStatsController.spec.ts +1 -1
  244. package/src/api/files/controllers/FileController.spec.ts +1 -1
  245. package/src/api/files/index.ts +10 -3
  246. package/src/api/files/jobs/FileJobs.spec.ts +1 -1
  247. package/src/api/files/services/FileService.spec.ts +1 -1
  248. package/src/api/jobs/index.ts +10 -3
  249. package/src/api/keys/controllers/AdminApiKeyController.ts +75 -0
  250. package/src/api/keys/controllers/ApiKeyController.ts +103 -0
  251. package/src/api/keys/entities/apiKeyEntity.ts +41 -0
  252. package/src/api/keys/index.ts +49 -0
  253. package/src/api/keys/schemas/adminApiKeyQuerySchema.ts +7 -0
  254. package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +17 -0
  255. package/src/api/keys/schemas/createApiKeyBodySchema.ts +7 -0
  256. package/src/api/keys/schemas/createApiKeyResponseSchema.ts +11 -0
  257. package/src/api/keys/schemas/listApiKeyResponseSchema.ts +15 -0
  258. package/src/api/keys/schemas/revokeApiKeyParamsSchema.ts +5 -0
  259. package/src/api/keys/schemas/revokeApiKeyResponseSchema.ts +5 -0
  260. package/src/api/keys/services/ApiKeyService.spec.ts +553 -0
  261. package/src/api/keys/services/ApiKeyService.ts +306 -0
  262. package/src/api/logs/TODO.md +55 -0
  263. package/src/api/notifications/index.ts +10 -4
  264. package/src/api/parameters/index.ts +9 -30
  265. package/src/api/parameters/primitives/$config.ts +12 -4
  266. package/src/api/parameters/services/ConfigStore.ts +9 -3
  267. package/src/api/users/__tests__/ApiKeys-integration.spec.ts +1035 -0
  268. package/src/api/users/__tests__/ApiKeys.spec.ts +401 -0
  269. package/src/api/users/index.ts +14 -3
  270. package/src/api/users/primitives/$realm.ts +33 -5
  271. package/src/api/users/providers/RealmProvider.ts +1 -12
  272. package/src/api/users/services/SessionService.ts +1 -1
  273. package/src/api/verifications/controllers/VerificationController.ts +2 -0
  274. package/src/api/verifications/index.ts +10 -4
  275. package/src/batch/index.ts +9 -36
  276. package/src/batch/primitives/$batch.ts +0 -8
  277. package/src/batch/providers/BatchProvider.ts +29 -2
  278. package/src/bucket/__tests__/shared.ts +1 -1
  279. package/src/bucket/index.ts +13 -6
  280. package/src/bucket/primitives/$bucket.ts +1 -1
  281. package/src/bucket/providers/LocalFileStorageProvider.ts +1 -1
  282. package/src/bucket/providers/MemoryFileStorageProvider.ts +1 -1
  283. package/src/cache/core/__tests__/shared.ts +30 -0
  284. package/src/cache/core/index.ts +11 -6
  285. package/src/cache/core/primitives/$cache.spec.ts +5 -0
  286. package/src/cache/core/providers/CacheProvider.ts +17 -0
  287. package/src/cache/core/providers/MemoryCacheProvider.ts +300 -1
  288. package/src/cache/redis/__tests__/cache-redis.spec.ts +5 -0
  289. package/src/cache/redis/providers/RedisCacheProvider.ts +9 -0
  290. package/src/cli/apps/AlephaCli.ts +1 -14
  291. package/src/cli/apps/AlephaPackageBuilderCli.ts +10 -1
  292. package/src/cli/atoms/buildOptions.ts +99 -9
  293. package/src/cli/commands/build.ts +150 -37
  294. package/src/cli/commands/db.ts +22 -18
  295. package/src/cli/commands/deploy.ts +1 -1
  296. package/src/cli/commands/dev.ts +1 -20
  297. package/src/cli/commands/gen/env.ts +5 -2
  298. package/src/cli/commands/gen/openapi.ts +5 -2
  299. package/src/cli/commands/init.spec.ts +588 -0
  300. package/src/cli/commands/init.ts +115 -58
  301. package/src/cli/commands/lint.ts +7 -1
  302. package/src/cli/commands/typecheck.ts +11 -0
  303. package/src/cli/providers/AppEntryProvider.ts +1 -1
  304. package/src/cli/providers/ViteBuildProvider.ts +8 -50
  305. package/src/cli/providers/ViteDevServerProvider.ts +35 -16
  306. package/src/cli/services/AlephaCliUtils.ts +52 -121
  307. package/src/cli/services/PackageManagerUtils.ts +129 -11
  308. package/src/cli/services/ProjectScaffolder.spec.ts +97 -0
  309. package/src/cli/services/ProjectScaffolder.ts +148 -81
  310. package/src/cli/services/ViteUtils.ts +82 -0
  311. package/src/cli/{assets/claudeMd.ts → templates/agentMd.ts} +37 -24
  312. package/src/cli/templates/apiAppSecurityTs.ts +11 -0
  313. package/src/cli/templates/apiIndexTs.ts +30 -0
  314. package/src/cli/templates/gitignore.ts +39 -0
  315. package/src/cli/{assets → templates}/mainCss.ts +11 -2
  316. package/src/cli/templates/mainServerTs.ts +33 -0
  317. package/src/cli/templates/webAppRouterTs.ts +74 -0
  318. package/src/cli/templates/webHelloComponentTsx.ts +30 -0
  319. package/src/command/helpers/Runner.spec.ts +139 -0
  320. package/src/command/helpers/Runner.ts +7 -22
  321. package/src/command/index.ts +12 -4
  322. package/src/command/providers/CliProvider.spec.ts +1392 -0
  323. package/src/command/providers/CliProvider.ts +320 -47
  324. package/src/core/Alepha.ts +34 -27
  325. package/src/core/__tests__/Alepha-start.spec.ts +4 -4
  326. package/src/core/helpers/jsonSchemaToTypeBox.spec.ts +771 -0
  327. package/src/core/helpers/jsonSchemaToTypeBox.ts +62 -10
  328. package/src/core/index.shared.ts +1 -0
  329. package/src/core/index.ts +20 -0
  330. package/src/core/providers/EventManager.spec.ts +0 -71
  331. package/src/core/providers/EventManager.ts +3 -15
  332. package/src/core/providers/Json.ts +2 -14
  333. package/src/datetime/index.ts +15 -0
  334. package/src/email/index.ts +10 -5
  335. package/src/email/providers/LocalEmailProvider.spec.ts +1 -1
  336. package/src/email/providers/LocalEmailProvider.ts +1 -1
  337. package/src/fake/__tests__/keyName.example.ts +1 -1
  338. package/src/fake/__tests__/keyName.spec.ts +5 -5
  339. package/src/fake/index.ts +9 -6
  340. package/src/fake/providers/FakeProvider.spec.ts +258 -40
  341. package/src/fake/providers/FakeProvider.ts +133 -19
  342. package/src/lock/core/index.ts +11 -4
  343. package/src/logger/index.ts +17 -66
  344. package/src/mcp/index.ts +10 -27
  345. package/src/mcp/transports/SseMcpTransport.ts +0 -11
  346. package/src/orm/__tests__/PostgresProvider.spec.ts +2 -2
  347. package/src/orm/index.browser.ts +2 -2
  348. package/src/orm/index.bun.ts +5 -3
  349. package/src/orm/index.ts +23 -53
  350. package/src/orm/providers/drivers/BunSqliteProvider.ts +5 -1
  351. package/src/orm/providers/drivers/CloudflareD1Provider.ts +57 -30
  352. package/src/orm/providers/drivers/DatabaseProvider.ts +9 -1
  353. package/src/orm/providers/drivers/NodeSqliteProvider.ts +4 -1
  354. package/src/orm/services/Repository.ts +7 -3
  355. package/src/queue/core/index.ts +14 -6
  356. package/src/react/auth/__tests__/$auth.spec.ts +202 -0
  357. package/src/react/auth/hooks/useAuth.ts +32 -0
  358. package/src/react/auth/index.browser.ts +13 -0
  359. package/src/react/auth/index.shared.ts +2 -0
  360. package/src/react/auth/index.ts +48 -0
  361. package/src/react/auth/providers/ReactAuthProvider.ts +16 -0
  362. package/src/react/auth/services/ReactAuth.ts +135 -0
  363. package/src/react/core/__tests__/Router.spec.tsx +169 -0
  364. package/src/react/core/components/ClientOnly.tsx +49 -0
  365. package/src/react/core/components/ErrorBoundary.tsx +73 -0
  366. package/src/react/core/contexts/AlephaContext.ts +7 -0
  367. package/src/react/core/contexts/AlephaProvider.tsx +42 -0
  368. package/src/react/core/hooks/useAction.browser.spec.tsx +569 -0
  369. package/src/react/core/hooks/useAction.ts +480 -0
  370. package/src/react/core/hooks/useAlepha.ts +26 -0
  371. package/src/react/core/hooks/useClient.ts +17 -0
  372. package/src/react/core/hooks/useEvents.ts +51 -0
  373. package/src/react/core/hooks/useInject.ts +12 -0
  374. package/src/react/core/hooks/useStore.ts +52 -0
  375. package/src/react/core/index.ts +90 -0
  376. package/src/react/form/components/FormState.tsx +17 -0
  377. package/src/react/form/errors/FormValidationError.ts +18 -0
  378. package/src/react/form/hooks/useForm.browser.spec.tsx +366 -0
  379. package/src/react/form/hooks/useForm.ts +47 -0
  380. package/src/react/form/hooks/useFormState.ts +130 -0
  381. package/src/react/form/index.ts +44 -0
  382. package/src/react/form/services/FormModel.ts +614 -0
  383. package/src/react/head/helpers/SeoExpander.spec.ts +203 -0
  384. package/src/react/head/helpers/SeoExpander.ts +142 -0
  385. package/src/react/head/hooks/useHead.spec.tsx +288 -0
  386. package/src/react/head/hooks/useHead.ts +62 -0
  387. package/src/react/head/index.browser.ts +26 -0
  388. package/src/react/head/index.ts +44 -0
  389. package/src/react/head/interfaces/Head.ts +105 -0
  390. package/src/react/head/primitives/$head.ts +25 -0
  391. package/src/react/head/providers/BrowserHeadProvider.browser.spec.ts +196 -0
  392. package/src/react/head/providers/BrowserHeadProvider.ts +212 -0
  393. package/src/react/head/providers/HeadProvider.ts +168 -0
  394. package/src/react/head/providers/ServerHeadProvider.ts +31 -0
  395. package/src/react/i18n/__tests__/integration.spec.tsx +239 -0
  396. package/src/react/i18n/components/Localize.spec.tsx +357 -0
  397. package/src/react/i18n/components/Localize.tsx +35 -0
  398. package/src/react/i18n/hooks/useI18n.browser.spec.tsx +438 -0
  399. package/src/react/i18n/hooks/useI18n.ts +18 -0
  400. package/src/react/i18n/index.ts +41 -0
  401. package/src/react/i18n/primitives/$dictionary.ts +69 -0
  402. package/src/react/i18n/providers/I18nProvider.spec.ts +389 -0
  403. package/src/react/i18n/providers/I18nProvider.ts +278 -0
  404. package/src/react/router/__tests__/page-head-browser.browser.spec.ts +95 -0
  405. package/src/react/router/__tests__/page-head.spec.ts +48 -0
  406. package/src/react/router/__tests__/seo-head.spec.ts +125 -0
  407. package/src/react/router/atoms/ssrManifestAtom.ts +58 -0
  408. package/src/react/router/components/ErrorViewer.tsx +872 -0
  409. package/src/react/router/components/Link.tsx +23 -0
  410. package/src/react/router/components/NestedView.tsx +223 -0
  411. package/src/react/router/components/NotFound.tsx +30 -0
  412. package/src/react/router/constants/PAGE_PRELOAD_KEY.ts +6 -0
  413. package/src/react/router/contexts/RouterLayerContext.ts +12 -0
  414. package/src/react/router/errors/Redirection.ts +28 -0
  415. package/src/react/router/hooks/useActive.ts +52 -0
  416. package/src/react/router/hooks/useQueryParams.ts +63 -0
  417. package/src/react/router/hooks/useRouter.ts +20 -0
  418. package/src/react/router/hooks/useRouterState.ts +11 -0
  419. package/src/react/router/index.browser.ts +45 -0
  420. package/src/react/router/index.shared.ts +19 -0
  421. package/src/react/router/index.ts +146 -0
  422. package/src/react/router/primitives/$page.browser.spec.tsx +851 -0
  423. package/src/react/router/primitives/$page.spec.tsx +676 -0
  424. package/src/react/router/primitives/$page.ts +489 -0
  425. package/src/react/router/providers/ReactBrowserProvider.ts +312 -0
  426. package/src/react/router/providers/ReactBrowserRendererProvider.ts +25 -0
  427. package/src/react/router/providers/ReactBrowserRouterProvider.ts +168 -0
  428. package/src/react/router/providers/ReactPageProvider.ts +726 -0
  429. package/src/react/router/providers/ReactPreloadProvider.spec.ts +142 -0
  430. package/src/react/router/providers/ReactPreloadProvider.ts +85 -0
  431. package/src/react/router/providers/ReactServerProvider.spec.tsx +316 -0
  432. package/src/react/router/providers/ReactServerProvider.ts +487 -0
  433. package/src/react/router/providers/ReactServerTemplateProvider.spec.ts +210 -0
  434. package/src/react/router/providers/ReactServerTemplateProvider.ts +542 -0
  435. package/src/react/router/providers/SSRManifestProvider.ts +334 -0
  436. package/src/react/router/services/ReactPageServerService.ts +48 -0
  437. package/src/react/router/services/ReactPageService.ts +27 -0
  438. package/src/react/router/services/ReactRouter.ts +262 -0
  439. package/src/react/websocket/hooks/useRoom.tsx +242 -0
  440. package/src/react/websocket/index.ts +7 -0
  441. package/src/redis/__tests__/redis.spec.ts +13 -0
  442. package/src/redis/index.ts +9 -25
  443. package/src/redis/providers/BunRedisProvider.ts +9 -0
  444. package/src/redis/providers/NodeRedisProvider.ts +8 -0
  445. package/src/redis/providers/RedisProvider.ts +16 -0
  446. package/src/retry/index.ts +11 -2
  447. package/src/router/index.ts +15 -0
  448. package/src/scheduler/index.ts +11 -2
  449. package/src/security/__tests__/BasicAuth.spec.ts +2 -0
  450. package/src/security/__tests__/ServerSecurityProvider.spec.ts +90 -5
  451. package/src/security/index.ts +15 -10
  452. package/src/security/interfaces/IssuerResolver.ts +27 -0
  453. package/src/security/primitives/$issuer.ts +55 -0
  454. package/src/security/providers/SecurityProvider.ts +179 -0
  455. package/src/security/providers/ServerBasicAuthProvider.ts +6 -2
  456. package/src/security/providers/ServerSecurityProvider.ts +63 -41
  457. package/src/server/auth/index.ts +12 -7
  458. package/src/server/cache/index.ts +7 -22
  459. package/src/server/compress/index.ts +10 -2
  460. package/src/server/cookies/index.ts +7 -5
  461. package/src/server/cookies/primitives/$cookie.ts +33 -11
  462. package/src/server/core/index.ts +16 -6
  463. package/src/server/core/interfaces/ServerRequest.ts +83 -1
  464. package/src/server/core/primitives/$action.spec.ts +1 -1
  465. package/src/server/core/primitives/$action.ts +8 -3
  466. package/src/server/core/providers/NodeHttpServerProvider.spec.ts +9 -3
  467. package/src/server/core/providers/NodeHttpServerProvider.ts +9 -3
  468. package/src/server/core/services/ServerRequestParser.spec.ts +520 -0
  469. package/src/server/core/services/ServerRequestParser.ts +306 -13
  470. package/src/server/cors/index.ts +7 -21
  471. package/src/server/cors/primitives/$cors.ts +6 -2
  472. package/src/server/health/index.ts +8 -2
  473. package/src/server/helmet/index.ts +11 -3
  474. package/src/server/links/index.ts +11 -6
  475. package/src/server/metrics/index.ts +10 -3
  476. package/src/server/multipart/index.ts +9 -3
  477. package/src/server/proxy/index.ts +8 -2
  478. package/src/server/rate-limit/index.ts +21 -25
  479. package/src/server/rate-limit/primitives/$rateLimit.ts +6 -2
  480. package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +38 -14
  481. package/src/server/rate-limit/providers/ServerRateLimitProvider.ts +22 -56
  482. package/src/server/static/index.ts +8 -2
  483. package/src/server/static/providers/ServerStaticProvider.ts +1 -1
  484. package/src/server/swagger/index.ts +9 -4
  485. package/src/server/swagger/providers/ServerSwaggerProvider.ts +1 -1
  486. package/src/sms/index.ts +9 -5
  487. package/src/sms/providers/LocalSmsProvider.spec.ts +1 -1
  488. package/src/sms/providers/LocalSmsProvider.ts +1 -1
  489. package/src/system/index.browser.ts +36 -0
  490. package/src/system/index.ts +62 -0
  491. package/src/system/index.workerd.ts +1 -0
  492. package/src/{file → system}/providers/FileSystemProvider.ts +24 -0
  493. package/src/{file → system}/providers/MemoryFileSystemProvider.ts +116 -3
  494. package/src/system/providers/MemoryShellProvider.ts +164 -0
  495. package/src/{file → system}/providers/NodeFileSystemProvider.spec.ts +2 -2
  496. package/src/{file → system}/providers/NodeFileSystemProvider.ts +47 -2
  497. package/src/system/providers/NodeShellProvider.ts +184 -0
  498. package/src/system/providers/ShellProvider.ts +74 -0
  499. package/src/{file → system}/services/FileDetector.spec.ts +2 -2
  500. package/src/thread/index.ts +11 -2
  501. package/src/topic/core/index.ts +12 -5
  502. package/src/vite/tasks/buildClient.ts +2 -7
  503. package/src/vite/tasks/buildServer.ts +19 -13
  504. package/src/vite/tasks/generateCloudflare.ts +10 -7
  505. package/src/vite/tasks/generateDocker.ts +4 -0
  506. package/src/websocket/index.ts +12 -8
  507. package/dist/file/index.d.ts.map +0 -1
  508. package/dist/file/index.js.map +0 -1
  509. package/src/cli/assets/apiIndexTs.ts +0 -16
  510. package/src/cli/assets/mainServerTs.ts +0 -24
  511. package/src/cli/assets/webAppRouterTs.ts +0 -16
  512. package/src/cli/assets/webHelloComponentTsx.ts +0 -20
  513. package/src/cli/providers/ViteTemplateProvider.ts +0 -27
  514. package/src/file/index.ts +0 -43
  515. /package/src/cli/{assets → templates}/apiHelloControllerTs.ts +0 -0
  516. /package/src/cli/{assets → templates}/biomeJson.ts +0 -0
  517. /package/src/cli/{assets → templates}/dummySpecTs.ts +0 -0
  518. /package/src/cli/{assets → templates}/editorconfig.ts +0 -0
  519. /package/src/cli/{assets → templates}/mainBrowserTs.ts +0 -0
  520. /package/src/cli/{assets → templates}/tsconfigJson.ts +0 -0
  521. /package/src/cli/{assets → templates}/webIndexTs.ts +0 -0
  522. /package/src/{file → system}/errors/FileError.ts +0 -0
  523. /package/src/{file → system}/services/FileDetector.ts +0 -0
@@ -1,9 +1,12 @@
1
- import { spawn } from "node:child_process";
2
- import { $inject, Alepha, AlephaError } from "alepha";
1
+ import { $inject, type Alepha } from "alepha";
3
2
  import { EnvUtils } from "alepha/command";
4
- import { FileSystemProvider } from "alepha/file";
5
3
  import { $logger } from "alepha/logger";
6
- import { AppEntryProvider } from "../providers/AppEntryProvider.ts";
4
+ import { FileSystemProvider, ShellProvider } from "alepha/system";
5
+ import {
6
+ type AppEntry,
7
+ AppEntryProvider,
8
+ } from "../providers/AppEntryProvider.ts";
9
+ import { ViteUtils } from "./ViteUtils.ts";
7
10
 
8
11
  /**
9
12
  * Core utility service for CLI commands.
@@ -19,6 +22,8 @@ export class AlephaCliUtils {
19
22
  protected readonly fs = $inject(FileSystemProvider);
20
23
  protected readonly envUtils = $inject(EnvUtils);
21
24
  protected readonly boot = $inject(AppEntryProvider);
25
+ protected readonly shell = $inject(ShellProvider);
26
+ protected readonly viteUtils = $inject(ViteUtils);
22
27
 
23
28
  // ===========================================
24
29
  // Command Execution
@@ -26,6 +31,11 @@ export class AlephaCliUtils {
26
31
 
27
32
  /**
28
33
  * Execute a command with inherited stdio.
34
+ *
35
+ * @param command - The command to execute
36
+ * @param options.root - Working directory
37
+ * @param options.env - Additional environment variables
38
+ * @param options.global - If true, run command directly without resolving from node_modules
29
39
  */
30
40
  public async exec(
31
41
  command: string,
@@ -35,71 +45,12 @@ export class AlephaCliUtils {
35
45
  global?: boolean;
36
46
  } = {},
37
47
  ): Promise<void> {
38
- const root = options.root ?? process.cwd();
39
- this.log.debug(`Executing command: ${command}`, { cwd: root });
40
-
41
- const runExec = async (app: string, args: string[]) => {
42
- const prog = spawn(app, args, {
43
- stdio: "inherit",
44
- cwd: root,
45
- env: {
46
- ...process.env,
47
- ...options.env,
48
- },
49
- });
50
-
51
- await new Promise<void>((resolve) =>
52
- prog.on("exit", () => {
53
- resolve();
54
- }),
55
- );
56
- };
57
-
58
- if (options.global) {
59
- const [app, ...args] = command.split(" ");
60
- await runExec(app, args);
61
- return;
62
- }
63
-
64
- const suffix = process.platform === "win32" ? ".cmd" : "";
65
- const [app, ...args] = command.split(" ");
66
-
67
- // find executable inside project node_modules
68
- let execPath = await this.checkFileExists(
69
- root,
70
- `node_modules/.bin/${app}${suffix}`,
71
- );
72
-
73
- // or, find executable inside alepha package node_modules (pnpm style)
74
- if (!execPath) {
75
- execPath = await this.checkFileExists(
76
- root,
77
- `node_modules/alepha/node_modules/.bin/${app}${suffix}`,
78
- );
79
- }
80
-
81
- // check if parent folder (monorepo) has the executable (check 3 times)
82
- if (!execPath) {
83
- let parentDir = this.fs.join(root, "..");
84
- for (let i = 0; i < 3; i++) {
85
- execPath = await this.checkFileExists(
86
- parentDir,
87
- `node_modules/.bin/${app}${suffix}`,
88
- );
89
- if (execPath) {
90
- break;
91
- }
92
- parentDir = this.fs.join(parentDir, "..");
93
- }
94
- }
95
-
96
- if (!execPath) {
97
- throw new AlephaError(
98
- `Could not find executable for command '${app}'. Make sure the package is installed.`,
99
- );
100
- }
101
-
102
- await runExec(execPath, args);
48
+ await this.shell.run(command, {
49
+ root: options.root,
50
+ env: options.env,
51
+ resolve: !options.global,
52
+ capture: false,
53
+ });
103
54
  }
104
55
 
105
56
  /**
@@ -122,55 +73,22 @@ export class AlephaCliUtils {
122
73
  return path;
123
74
  }
124
75
 
125
- /**
126
- * Load Alepha instance from a server entry file.
127
- */
128
76
  public async loadAlephaFromServerEntryFile(
129
- rootDir?: string,
130
- explicitEntry?: string,
131
- ): Promise<{
132
- alepha: Alepha;
133
- entry: string;
134
- }> {
135
- process.env.ALEPHA_CLI_IMPORT = "true";
136
-
137
- const root = rootDir ?? process.cwd();
138
- let entry: string;
139
-
140
- if (explicitEntry) {
141
- // Explicit entry provided
142
- entry = this.fs.join(root, explicitEntry);
143
- if (!(await this.fs.exists(entry))) {
144
- throw new AlephaError(
145
- `Explicit server entry file "${explicitEntry}" not found.`,
146
- );
147
- }
77
+ opts: {
78
+ mode: "production" | "development";
79
+ } & ({ entry: AppEntry } | { root: string }),
80
+ ): Promise<Alepha> {
81
+ let entry: AppEntry;
82
+ if ("root" in opts) {
83
+ entry = await this.boot.getAppEntry(opts.root);
148
84
  } else {
149
- // Auto-discover entry
150
- const appEntry = await this.boot.getAppEntry(root);
151
- entry = this.fs.join(root, appEntry.server);
152
- }
153
-
154
- delete (global as any).__alepha;
155
-
156
- const mod = await import(entry);
157
-
158
- this.log.debug(`Load entry: ${entry}`);
159
-
160
- // check if alepha is correctly exported
161
- if (mod.default instanceof Alepha) {
162
- return { alepha: mod.default, entry };
85
+ entry = opts.entry;
163
86
  }
164
87
 
165
- // else, try with global variable
166
- const g: any = global;
167
- if (g.__alepha) {
168
- return { alepha: g.__alepha, entry };
169
- }
170
-
171
- throw new AlephaError(
172
- `Could not find Alepha instance in entry file: ${entry}`,
173
- );
88
+ return await this.viteUtils.runAlepha({
89
+ entry,
90
+ mode: opts.mode,
91
+ });
174
92
  }
175
93
 
176
94
  // ===========================================
@@ -221,13 +139,26 @@ ${models.map((it: string) => `export const ${it} = models["${it}"];`).join("\n")
221
139
  return this.fs.exists(this.fs.join(root, path));
222
140
  }
223
141
 
224
- protected async checkFileExists(
225
- root: string,
226
- name: string,
227
- ): Promise<string | undefined> {
228
- const configPath = this.fs.join(root, name);
229
- if (await this.fs.exists(configPath)) {
230
- return configPath;
142
+ /**
143
+ * Check if a command is installed and available in the system PATH.
144
+ */
145
+ public isInstalledAsync(cmd: string): Promise<boolean> {
146
+ return this.shell.isInstalled(cmd);
147
+ }
148
+
149
+ /**
150
+ * Get the current git revision (commit SHA).
151
+ *
152
+ * @returns The short commit SHA or "unknown" if not in a git repo
153
+ */
154
+ public async getGitRevision(): Promise<string> {
155
+ try {
156
+ const result = await this.shell.run("git rev-parse --short HEAD", {
157
+ capture: true,
158
+ });
159
+ return result.trim();
160
+ } catch {
161
+ return "unknown";
231
162
  }
232
163
  }
233
164
  }
@@ -1,9 +1,37 @@
1
1
  import { $inject, Alepha } from "alepha";
2
2
  import type { RunnerMethod } from "alepha/command";
3
- import { FileSystemProvider } from "alepha/file";
4
3
  import { $logger } from "alepha/logger";
4
+ import alephaPackageJson from "alepha/package.json" with { type: "json" };
5
+ import { FileSystemProvider } from "alepha/system";
5
6
  import { version } from "../version.ts";
6
7
 
8
+ /**
9
+ * Context information about a workspace root.
10
+ * Used when initializing a package inside a monorepo.
11
+ */
12
+ export interface WorkspaceContext {
13
+ /**
14
+ * Whether we're inside a workspace package.
15
+ */
16
+ isPackage: boolean;
17
+ /**
18
+ * The workspace root directory (e.g., ../.. from packages/my-pkg).
19
+ */
20
+ workspaceRoot: string | null;
21
+ /**
22
+ * Package manager detected at workspace root.
23
+ */
24
+ packageManager: "yarn" | "pnpm" | "npm" | "bun" | null;
25
+ /**
26
+ * Config files present at workspace root.
27
+ */
28
+ config: {
29
+ biomeJson: boolean;
30
+ editorconfig: boolean;
31
+ tsconfigJson: boolean;
32
+ };
33
+ }
34
+
7
35
  /**
8
36
  * Utility service for package manager operations.
9
37
  *
@@ -23,12 +51,9 @@ export class PackageManagerUtils {
23
51
  */
24
52
  public async getPackageManager(
25
53
  root: string,
26
- flags?: { yarn?: boolean; pnpm?: boolean; npm?: boolean; bun?: boolean },
54
+ pm?: "yarn" | "pnpm" | "npm" | "bun",
27
55
  ): Promise<"yarn" | "pnpm" | "npm" | "bun"> {
28
- if (flags?.yarn) return "yarn";
29
- if (flags?.pnpm) return "pnpm";
30
- if (flags?.npm) return "npm";
31
- if (flags?.bun) return "bun";
56
+ if (pm) return pm;
32
57
  if (this.alepha.isBun()) return "bun";
33
58
  if (await this.fs.exists(this.fs.join(root, "bun.lock"))) return "bun";
34
59
  if (await this.fs.exists(this.fs.join(root, "yarn.lock"))) return "yarn";
@@ -37,6 +62,60 @@ export class PackageManagerUtils {
37
62
  return "npm";
38
63
  }
39
64
 
65
+ /**
66
+ * Detect workspace context when inside a monorepo package.
67
+ *
68
+ * Checks if we're inside a workspace package (e.g., packages/my-pkg or apps/my-app)
69
+ * by looking 2 levels up for workspace indicators like lockfiles and config files.
70
+ *
71
+ * @param root - The current package directory
72
+ * @returns Workspace context with root path, PM, and config presence
73
+ */
74
+ public async getWorkspaceContext(root: string): Promise<WorkspaceContext> {
75
+ // Workspace root is 2 levels up (e.g., packages/my-pkg → ..)
76
+ const workspaceRoot = this.fs.join(root, "..", "..");
77
+
78
+ // Check for lockfiles to detect PM
79
+ const [hasYarnLock, hasPnpmLock, hasNpmLock, hasBunLock] =
80
+ await Promise.all([
81
+ this.fs.exists(this.fs.join(workspaceRoot, "yarn.lock")),
82
+ this.fs.exists(this.fs.join(workspaceRoot, "pnpm-lock.yaml")),
83
+ this.fs.exists(this.fs.join(workspaceRoot, "package-lock.json")),
84
+ this.fs.exists(this.fs.join(workspaceRoot, "bun.lock")),
85
+ ]);
86
+
87
+ // Check for config files
88
+ const [hasBiome, hasEditorConfig, hasTsConfig, hasWorkspacePackageJson] =
89
+ await Promise.all([
90
+ this.fs.exists(this.fs.join(workspaceRoot, "biome.json")),
91
+ this.fs.exists(this.fs.join(workspaceRoot, ".editorconfig")),
92
+ this.fs.exists(this.fs.join(workspaceRoot, "tsconfig.json")),
93
+ this.fs.exists(this.fs.join(workspaceRoot, "package.json")),
94
+ ]);
95
+
96
+ // Determine if this looks like a workspace root
97
+ const hasLockfile = hasYarnLock || hasPnpmLock || hasNpmLock || hasBunLock;
98
+ const isPackage = hasLockfile && hasWorkspacePackageJson;
99
+
100
+ // Detect package manager from lockfile
101
+ let packageManager: "yarn" | "pnpm" | "npm" | "bun" | null = null;
102
+ if (hasYarnLock) packageManager = "yarn";
103
+ else if (hasPnpmLock) packageManager = "pnpm";
104
+ else if (hasBunLock) packageManager = "bun";
105
+ else if (hasNpmLock) packageManager = "npm";
106
+
107
+ return {
108
+ isPackage,
109
+ workspaceRoot: isPackage ? workspaceRoot : null,
110
+ packageManager,
111
+ config: {
112
+ biomeJson: hasBiome,
113
+ editorconfig: hasEditorConfig,
114
+ tsconfigJson: hasTsConfig,
115
+ },
116
+ };
117
+ }
118
+
40
119
  /**
41
120
  * Get the install command for a package.
42
121
  */
@@ -98,12 +177,17 @@ export class PackageManagerUtils {
98
177
 
99
178
  /**
100
179
  * Install a dependency if it's missing from the project.
180
+ * Optionally checks workspace root for the dependency in monorepo setups.
101
181
  */
102
182
  public async ensureDependency(
103
183
  root: string,
104
184
  packageName: string,
105
185
  options: {
106
186
  dev?: boolean;
187
+ /**
188
+ * Also check workspace root for the dependency (for monorepo setups).
189
+ */
190
+ checkWorkspace?: boolean;
107
191
  run?: RunnerMethod;
108
192
  exec?: (
109
193
  cmd: string,
@@ -111,13 +195,27 @@ export class PackageManagerUtils {
111
195
  ) => Promise<void>;
112
196
  } = {},
113
197
  ): Promise<void> {
114
- const { dev = true } = options;
198
+ const { dev = true, checkWorkspace = false } = options;
115
199
 
200
+ // Check current package
116
201
  if (await this.hasDependency(root, packageName)) {
117
202
  this.log.debug(`Dependency '${packageName}' is already installed`);
118
203
  return;
119
204
  }
120
205
 
206
+ // Check workspace root (for monorepo setups)
207
+ if (checkWorkspace) {
208
+ const workspace = await this.getWorkspaceContext(root);
209
+ if (workspace.workspaceRoot) {
210
+ if (await this.hasDependency(workspace.workspaceRoot, packageName)) {
211
+ this.log.debug(
212
+ `Dependency '${packageName}' is already installed in workspace root`,
213
+ );
214
+ return;
215
+ }
216
+ }
217
+ }
218
+
121
219
  const cmd = await this.getInstallCommand(root, packageName, dev);
122
220
 
123
221
  if (options.run) {
@@ -254,12 +352,22 @@ export class PackageManagerUtils {
254
352
  scripts: Record<string, string>;
255
353
  type: "module";
256
354
  } {
355
+ const alephaDeps = alephaPackageJson.devDependencies;
356
+
257
357
  const dependencies: Record<string, string> = {
258
358
  alepha: `^${version}`,
259
359
  };
260
360
 
261
361
  const devDependencies: Record<string, string> = {};
262
362
 
363
+ // Add biome/vitest only if not a workspace package (workspace root has them)
364
+ if (!modes.isPackage) {
365
+ devDependencies["@biomejs/biome"] = alephaDeps["@biomejs/biome"];
366
+ if (modes.test) {
367
+ devDependencies.vitest = alephaDeps.vitest;
368
+ }
369
+ }
370
+
263
371
  const scripts: Record<string, string> = {
264
372
  dev: "alepha dev",
265
373
  build: "alepha build",
@@ -268,16 +376,21 @@ export class PackageManagerUtils {
268
376
  verify: "alepha verify",
269
377
  };
270
378
 
379
+ if (modes.test) {
380
+ scripts.test = "vitest run";
381
+ }
382
+
271
383
  if (modes.ui) {
272
384
  dependencies["@alepha/ui"] = `^${version}`;
273
385
  modes.react = true;
274
386
  }
275
387
 
276
388
  if (modes.react) {
277
- dependencies["@alepha/react"] = `^${version}`;
278
- dependencies.react = "^19.2.0";
279
- dependencies["react-dom"] = "^19.2.0";
280
- devDependencies["@types/react"] = "^19.2.0";
389
+ dependencies.react = alephaDeps.react;
390
+ dependencies["react-dom"] = alephaDeps["react-dom"];
391
+ devDependencies["@vitejs/plugin-react"] =
392
+ alephaDeps["@vitejs/plugin-react"];
393
+ devDependencies["@types/react"] = alephaDeps["@types/react"];
281
394
  }
282
395
 
283
396
  return {
@@ -305,4 +418,9 @@ export interface DependencyModes {
305
418
  react?: boolean;
306
419
  ui?: boolean;
307
420
  expo?: boolean;
421
+ test?: boolean;
422
+ /**
423
+ * Skip biome/vitest when inside a workspace package (they're at root).
424
+ */
425
+ isPackage?: boolean;
308
426
  }
@@ -0,0 +1,97 @@
1
+ import { Alepha } from "alepha";
2
+ import {
3
+ FileSystemProvider,
4
+ MemoryFileSystemProvider,
5
+ MemoryShellProvider,
6
+ ShellProvider,
7
+ } from "alepha/system";
8
+ import { describe, expect, it } from "vitest";
9
+ import { ProjectScaffolder } from "./ProjectScaffolder.ts";
10
+
11
+ describe("ProjectScaffolder", () => {
12
+ const createTestEnv = () => {
13
+ const alepha = Alepha.create()
14
+ .with({ provide: FileSystemProvider, use: MemoryFileSystemProvider })
15
+ .with({ provide: ShellProvider, use: MemoryShellProvider });
16
+
17
+ const scaffolder = alepha.inject(ProjectScaffolder);
18
+
19
+ return { alepha, scaffolder };
20
+ };
21
+
22
+ // ─────────────────────────────────────────────────────────────────────────────
23
+ // getAppName
24
+ // ─────────────────────────────────────────────────────────────────────────────
25
+
26
+ describe("getAppName", () => {
27
+ it("should return lowercase directory name", () => {
28
+ const { scaffolder } = createTestEnv();
29
+
30
+ expect(scaffolder.getAppName("/project/MyApp")).toBe("myapp");
31
+ });
32
+
33
+ it("should remove dashes from directory name", () => {
34
+ const { scaffolder } = createTestEnv();
35
+
36
+ expect(scaffolder.getAppName("/project/my-cool-app")).toBe("mycoolapp");
37
+ });
38
+
39
+ it("should remove underscores from directory name", () => {
40
+ const { scaffolder } = createTestEnv();
41
+
42
+ expect(scaffolder.getAppName("/project/my_cool_app")).toBe("mycoolapp");
43
+ });
44
+
45
+ it("should remove spaces from directory name", () => {
46
+ const { scaffolder } = createTestEnv();
47
+
48
+ expect(scaffolder.getAppName("/project/my cool app")).toBe("mycoolapp");
49
+ });
50
+
51
+ it("should remove dots from directory name", () => {
52
+ const { scaffolder } = createTestEnv();
53
+
54
+ expect(scaffolder.getAppName("/project/my.cool.app")).toBe("mycoolapp");
55
+ });
56
+
57
+ it("should remove digits from directory name", () => {
58
+ const { scaffolder } = createTestEnv();
59
+
60
+ expect(scaffolder.getAppName("/project/app123")).toBe("app");
61
+ expect(scaffolder.getAppName("/project/my2app")).toBe("myapp");
62
+ expect(scaffolder.getAppName("/project/v2-app")).toBe("vapp");
63
+ });
64
+
65
+ it("should handle combination of special characters", () => {
66
+ const { scaffolder } = createTestEnv();
67
+
68
+ expect(scaffolder.getAppName("/project/my-cool_app.v2")).toBe(
69
+ "mycoolappv",
70
+ );
71
+ expect(scaffolder.getAppName("/project/test_app-2.0")).toBe("testapp");
72
+ });
73
+
74
+ it("should fallback to 'app' when all characters are removed", () => {
75
+ const { scaffolder } = createTestEnv();
76
+
77
+ expect(scaffolder.getAppName("/project/123")).toBe("app");
78
+ expect(scaffolder.getAppName("/project/---")).toBe("app");
79
+ expect(scaffolder.getAppName("/project/1.2.3")).toBe("app");
80
+ expect(scaffolder.getAppName("/project/_-._")).toBe("app");
81
+ });
82
+
83
+ it("should handle deeply nested paths", () => {
84
+ const { scaffolder } = createTestEnv();
85
+
86
+ expect(scaffolder.getAppName("/workspace/packages/apps/my-app")).toBe(
87
+ "myapp",
88
+ );
89
+ });
90
+
91
+ it("should handle root-level directories", () => {
92
+ const { scaffolder } = createTestEnv();
93
+
94
+ expect(scaffolder.getAppName("/myapp")).toBe("myapp");
95
+ });
96
+ });
97
+ });