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
@@ -10,6 +10,7 @@ import {
10
10
  type Static,
11
11
  type TObject,
12
12
  type TSchema,
13
+ type TUnion,
13
14
  TypeBoxError,
14
15
  t,
15
16
  } from "alepha";
@@ -77,7 +78,37 @@ declare module "alepha" {
77
78
 
78
79
  // ---------------------------------------------------------------------------------------------------------------------
79
80
 
81
+ /**
82
+ * CLI provider for parsing and executing commands.
83
+ *
84
+ * Handles:
85
+ * - Command resolution (simple, nested, colon-notation)
86
+ * - Flag and argument parsing
87
+ * - Environment variable validation
88
+ * - Help generation
89
+ * - Pre/post command hooks
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * // Define a command
94
+ * class MyCommands {
95
+ * build = $command({
96
+ * name: "build",
97
+ * description: "Build the project",
98
+ * flags: t.object({ watch: t.optional(t.boolean()) }),
99
+ * handler: async ({ flags }) => { ... }
100
+ * });
101
+ * }
102
+ *
103
+ * // CLI automatically discovers and executes commands
104
+ * const alepha = Alepha.create().with(MyCommands);
105
+ * ```
106
+ */
80
107
  export class CliProvider {
108
+ // ─────────────────────────────────────────────────────────────────────────────
109
+ // Dependencies
110
+ // ─────────────────────────────────────────────────────────────────────────────
111
+
81
112
  protected readonly env = $env(envSchema);
82
113
  protected readonly alepha = $inject(Alepha);
83
114
  protected readonly log = $logger();
@@ -85,9 +116,12 @@ export class CliProvider {
85
116
  protected readonly runner = $inject(Runner);
86
117
  protected readonly asker = $inject(Asker);
87
118
  protected readonly envUtils = $inject(EnvUtils);
88
-
89
119
  protected readonly options = $use(cliOptions);
90
120
 
121
+ // ─────────────────────────────────────────────────────────────────────────────
122
+ // Configuration
123
+ // ─────────────────────────────────────────────────────────────────────────────
124
+
91
125
  protected get name(): string {
92
126
  return this.options.name || this.env.CLI_NAME;
93
127
  }
@@ -103,6 +137,9 @@ export class CliProvider {
103
137
  );
104
138
  }
105
139
 
140
+ /**
141
+ * Global flags available to all commands.
142
+ */
106
143
  protected readonly globalFlags = {
107
144
  help: {
108
145
  aliases: ["h", "help"],
@@ -111,6 +148,14 @@ export class CliProvider {
111
148
  },
112
149
  };
113
150
 
151
+ // ─────────────────────────────────────────────────────────────────────────────
152
+ // Lifecycle
153
+ // ─────────────────────────────────────────────────────────────────────────────
154
+
155
+ /**
156
+ * Main entry point - resolves and executes the command from process.argv.
157
+ * This is the production execution path with full lifecycle support.
158
+ */
114
159
  protected readonly onReady = $hook({
115
160
  on: "ready",
116
161
  handler: async () => {
@@ -119,7 +164,7 @@ export class CliProvider {
119
164
  // Extract positional arguments (potential command path)
120
165
  const positionalArgs = argv.filter((arg) => !arg.startsWith("-"));
121
166
 
122
- // Resolve command using the new resolution logic
167
+ // Resolve command using space-separated or colon-notation
123
168
  const { command, consumedArgs } = this.resolveCommand(positionalArgs);
124
169
 
125
170
  const globalFlags = this.parseFlags(
@@ -128,6 +173,7 @@ export class CliProvider {
128
173
  key,
129
174
  ...value,
130
175
  })),
176
+ { strict: false }, // Don't throw for command-specific flags
131
177
  );
132
178
 
133
179
  if (globalFlags.help) {
@@ -166,7 +212,15 @@ export class CliProvider {
166
212
  });
167
213
 
168
214
  /**
169
- * Execute a command with the given argv.
215
+ * Execute a command with full lifecycle support.
216
+ *
217
+ * This is the production execution path that includes:
218
+ * - Mode-based .env file loading
219
+ * - Pre/post command hooks
220
+ * - Runner session for pretty CLI output
221
+ * - Alepha context wrapper for proper scoping
222
+ *
223
+ * @see run() for a lightweight test-only alternative
170
224
  */
171
225
  protected async executeCommand(
172
226
  command: CommandPrimitive<TObject>,
@@ -186,7 +240,9 @@ export class CliProvider {
186
240
  await this.loadModeEnv(root, modeValue);
187
241
  }
188
242
 
189
- const commandFlags = this.parseCommandFlags(argv, command.flags);
243
+ const commandFlags = this.parseCommandFlags(argv, command.flags, {
244
+ modeEnabled: !!command.options.mode,
245
+ });
190
246
  const commandArgs = this.parseCommandArgs(
191
247
  argv,
192
248
  command.options.args,
@@ -244,7 +300,7 @@ export class CliProvider {
244
300
  }
245
301
 
246
302
  /**
247
- * Remove consumed command path arguments from argv.
303
+ * Remove consumed command path arguments from argv (keeps flags and remaining args).
248
304
  */
249
305
  protected removeConsumedArgs(
250
306
  argv: string[],
@@ -327,33 +383,113 @@ export class CliProvider {
327
383
  return { command: currentCommand, consumedArgs };
328
384
  }
329
385
 
386
+ // ─────────────────────────────────────────────────────────────────────────────
387
+ // Public API
388
+ // ─────────────────────────────────────────────────────────────────────────────
389
+
390
+ /**
391
+ * Get all registered commands in the application.
392
+ */
330
393
  public get commands(): CommandPrimitive<any>[] {
331
394
  return this.alepha.primitives($command);
332
395
  }
333
396
 
397
+ /**
398
+ * Execute a command handler with given arguments.
399
+ *
400
+ * This is a **lightweight test helper** that directly invokes the command handler
401
+ * without the full production lifecycle. It intentionally skips:
402
+ * - Pre/post command hooks
403
+ * - Runner session (pretty CLI output)
404
+ * - Alepha context wrapper
405
+ * - .env.{mode} file loading
406
+ *
407
+ * For production execution, the `onReady` hook uses `executeCommand()` which
408
+ * provides the full lifecycle. Merging them would either make this method too
409
+ * heavy for simple testing or require many optional parameters to toggle behaviors.
410
+ *
411
+ * @example
412
+ * ```typescript
413
+ * // In tests
414
+ * const cli = alepha.inject(CliProvider);
415
+ * const cmd = alepha.inject(InitCommand);
416
+ *
417
+ * await cli.run(cmd.init, "--agent --pm=yarn");
418
+ * await cli.run(cmd.init, { argv: "--agent", root: "/project" });
419
+ * ```
420
+ */
421
+ public async run<T extends TObject, A extends TSchema>(
422
+ command: CommandPrimitive<T, A>,
423
+ options:
424
+ | string
425
+ | string[]
426
+ | { argv?: string | string[]; root?: string } = {},
427
+ ): Promise<void> {
428
+ const opts =
429
+ typeof options === "string" || Array.isArray(options)
430
+ ? { argv: options }
431
+ : options;
432
+ const args =
433
+ typeof opts.argv === "string"
434
+ ? opts.argv.split(" ").filter(Boolean)
435
+ : (opts.argv ?? []);
436
+ const root = opts.root ?? process.cwd();
437
+
438
+ const commandFlags = this.parseCommandFlags(args, command.flags, {
439
+ modeEnabled: !!command.options.mode,
440
+ });
441
+ const commandArgs = this.parseCommandArgs(
442
+ args,
443
+ command.options.args,
444
+ true,
445
+ command.flags,
446
+ );
447
+ const commandEnv = this.parseCommandEnv(command.env, command.name);
448
+
449
+ let modeValue: string | undefined;
450
+ if (command.options.mode) {
451
+ modeValue = this.parseModeFlag(args);
452
+ if (modeValue === undefined && typeof command.options.mode === "string") {
453
+ modeValue = command.options.mode;
454
+ }
455
+ }
456
+
457
+ await command.options.handler({
458
+ flags: commandFlags,
459
+ args: commandArgs,
460
+ env: commandEnv,
461
+ run: this.runner.run,
462
+ ask: this.asker.ask,
463
+ fs,
464
+ glob,
465
+ root,
466
+ help: () => this.printHelp(command),
467
+ mode: modeValue,
468
+ } as CommandHandlerArgs<T, A>);
469
+ }
470
+
471
+ // ─────────────────────────────────────────────────────────────────────────────
472
+ // Command Resolution
473
+ // ─────────────────────────────────────────────────────────────────────────────
474
+
475
+ /** Find a command by name or alias */
334
476
  protected findCommand(name: string): CommandPrimitive<TObject> | undefined {
335
477
  return this.commands.findLast(
336
478
  (command) => command.name === name || command.aliases.includes(name),
337
479
  );
338
480
  }
339
481
 
340
- /**
341
- * Find all pre-hooks for a command.
342
- */
482
+ /** Find all pre-hooks for a command (commands named `pre{commandName}`) */
343
483
  protected findPreHooks(commandName: string): CommandPrimitive<TObject>[] {
344
484
  return this.commands.filter((cmd) => cmd.name === `pre${commandName}`);
345
485
  }
346
486
 
347
- /**
348
- * Find all post-hooks for a command.
349
- */
487
+ /** Find all post-hooks for a command (commands named `post{commandName}`) */
350
488
  protected findPostHooks(commandName: string): CommandPrimitive<TObject>[] {
351
489
  return this.commands.filter((cmd) => cmd.name === `post${commandName}`);
352
490
  }
353
491
 
354
- /**
355
- * Get global flags (help only, root command flags are NOT global).
356
- */
492
+ /** Get global flags (help only, root command flags are NOT global) */
357
493
  protected getAllGlobalFlags(): Record<
358
494
  string,
359
495
  { aliases: string[]; description?: string; schema: TSchema }
@@ -361,10 +497,17 @@ export class CliProvider {
361
497
  return { ...this.globalFlags };
362
498
  }
363
499
 
500
+ // ─────────────────────────────────────────────────────────────────────────────
501
+ // Parsing (Flags, Args, Env)
502
+ // ─────────────────────────────────────────────────────────────────────────────
503
+
504
+ /** Parse command flags from argv using the command's flag schema */
364
505
  protected parseCommandFlags(
365
506
  argv: string[],
366
507
  schema: TObject,
508
+ options: { modeEnabled?: boolean } = {},
367
509
  ): Record<string, any> {
510
+ const { modeEnabled = false } = options;
368
511
  const flagDefs = Object.entries(schema.properties).map(([key, value]) => ({
369
512
  key,
370
513
  aliases: [
@@ -377,8 +520,21 @@ export class CliProvider {
377
520
  schema: value,
378
521
  }));
379
522
 
523
+ // Add mode flags if mode is enabled (they're parsed elsewhere by parseModeFlag)
524
+ if (modeEnabled) {
525
+ flagDefs.push({
526
+ key: "__mode__",
527
+ aliases: ["mode", "m"],
528
+ description: undefined,
529
+ schema: t.string(),
530
+ });
531
+ }
532
+
380
533
  const parsed = this.parseFlags(argv, flagDefs);
381
534
 
535
+ // Remove the mode flag from parsed result (it's handled separately)
536
+ delete parsed.__mode__;
537
+
382
538
  // apply manually defaults for optional properties that have defaults
383
539
  for (const [key, value] of Object.entries(schema.properties)) {
384
540
  if (!(key in parsed) && t.schema.isOptional(value)) {
@@ -401,6 +557,7 @@ export class CliProvider {
401
557
  }
402
558
  }
403
559
 
560
+ /** Parse and validate environment variables using the command's env schema */
404
561
  protected parseCommandEnv(
405
562
  schema: TObject,
406
563
  commandName: string,
@@ -442,9 +599,7 @@ export class CliProvider {
442
599
  }
443
600
  }
444
601
 
445
- /**
446
- * Parse --mode or -m flag from argv.
447
- */
602
+ /** Parse --mode or -m flag from argv for environment file loading */
448
603
  protected parseModeFlag(argv: string[]): string | undefined {
449
604
  for (let i = 0; i < argv.length; i++) {
450
605
  const arg = argv[i];
@@ -467,9 +622,7 @@ export class CliProvider {
467
622
  return undefined;
468
623
  }
469
624
 
470
- /**
471
- * Load environment files based on mode.
472
- */
625
+ /** Load .env and .env.{mode} files into process.env */
473
626
  protected async loadModeEnv(
474
627
  root: string,
475
628
  mode: string | undefined,
@@ -482,10 +635,13 @@ export class CliProvider {
482
635
  await this.envUtils.loadEnv(root, envFiles);
483
636
  }
484
637
 
638
+ /** Low-level flag parser - extracts flag values from argv based on definitions */
485
639
  protected parseFlags(
486
640
  argv: string[],
487
641
  flagDefs: { key: string; aliases: string[]; schema: TSchema }[],
642
+ options: { strict?: boolean } = {},
488
643
  ): Record<string, any> {
644
+ const { strict = true } = options;
489
645
  const result: Record<string, any> = {};
490
646
 
491
647
  for (let i = 0; i < argv.length; i++) {
@@ -496,10 +652,31 @@ export class CliProvider {
496
652
  let value = valueParts.join("=");
497
653
 
498
654
  const def = flagDefs.find((d) => d.aliases.includes(rawKey));
499
- if (!def) continue;
655
+ if (!def) {
656
+ if (strict) {
657
+ throw new CommandError(`Unknown flag: --${rawKey}`);
658
+ }
659
+ continue;
660
+ }
661
+
662
+ // Check if schema is a union containing boolean (allows flag without value)
663
+ const isUnionWithBoolean =
664
+ t.schema.isUnion(def.schema) &&
665
+ (def.schema as TUnion).anyOf.some((s) => t.schema.isBoolean(s));
500
666
 
501
667
  if (t.schema.isBoolean(def.schema)) {
502
668
  result[def.key] = true;
669
+ } else if (isUnionWithBoolean && !value) {
670
+ // Union with boolean: --flag without value → true
671
+ const nextArg = argv[i + 1];
672
+ if (nextArg && !nextArg.startsWith("-")) {
673
+ // Has a value after space: --flag value
674
+ result[def.key] = nextArg;
675
+ i++; // consume next arg
676
+ } else {
677
+ // No value: --flag → true
678
+ result[def.key] = true;
679
+ }
503
680
  } else if (value) {
504
681
  // Value provided via --flag=value syntax
505
682
  try {
@@ -534,9 +711,7 @@ export class CliProvider {
534
711
  return result;
535
712
  }
536
713
 
537
- /**
538
- * Get indices of argv elements that are consumed by flags (including space-separated values).
539
- */
714
+ /** Get indices of argv elements consumed by flags (for separating args from flags) */
540
715
  protected getFlagConsumedIndices(
541
716
  argv: string[],
542
717
  flagDefs: { key: string; aliases: string[]; schema: TSchema }[],
@@ -555,8 +730,24 @@ export class CliProvider {
555
730
  const def = flagDefs.find((d) => d.aliases.includes(rawKey));
556
731
  if (!def) continue;
557
732
 
733
+ // Check if schema is a union containing boolean
734
+ const isUnionWithBoolean =
735
+ t.schema.isUnion(def.schema) &&
736
+ (def.schema as TUnion).anyOf.some((s) => t.schema.isBoolean(s));
737
+
558
738
  // If not a boolean flag and no = value, the next arg is consumed as the value
559
- if (!t.schema.isBoolean(def.schema) && !hasEqualValue) {
739
+ // Exception: union with boolean can work without a value
740
+ if (
741
+ !t.schema.isBoolean(def.schema) &&
742
+ !isUnionWithBoolean &&
743
+ !hasEqualValue
744
+ ) {
745
+ const nextArg = argv[i + 1];
746
+ if (nextArg && !nextArg.startsWith("-")) {
747
+ consumed.add(i + 1);
748
+ }
749
+ } else if (isUnionWithBoolean && !hasEqualValue) {
750
+ // Union with boolean: check if next arg looks like a value (not a flag)
560
751
  const nextArg = argv[i + 1];
561
752
  if (nextArg && !nextArg.startsWith("-")) {
562
753
  consumed.add(i + 1);
@@ -638,6 +829,7 @@ export class CliProvider {
638
829
  }
639
830
  }
640
831
 
832
+ /** Convert a string argument value to the appropriate type based on schema */
641
833
  protected parseArgumentValue(value: string, schema: TSchema): any {
642
834
  if (t.schema.isString(schema)) {
643
835
  return value;
@@ -665,6 +857,11 @@ export class CliProvider {
665
857
  return value;
666
858
  }
667
859
 
860
+ // ─────────────────────────────────────────────────────────────────────────────
861
+ // Help Generation
862
+ // ─────────────────────────────────────────────────────────────────────────────
863
+
864
+ /** Generate usage string for command arguments (e.g., "<path>" or "[path]") */
668
865
  protected generateArgsUsage(schema?: TSchema): string {
669
866
  if (!schema) {
670
867
  return "";
@@ -694,6 +891,7 @@ export class CliProvider {
694
891
  return ` <${key}${typeName}>`;
695
892
  }
696
893
 
894
+ /** Get display type name for a schema (e.g., ": number", ": boolean") */
697
895
  protected getTypeName(schema: TSchema): string {
698
896
  if (!schema) return "";
699
897
 
@@ -706,6 +904,12 @@ export class CliProvider {
706
904
  return "";
707
905
  }
708
906
 
907
+ /**
908
+ * Print help for a specific command or general CLI help.
909
+ *
910
+ * @param command - If provided, shows help for this specific command.
911
+ * If omitted, shows general CLI help with all commands.
912
+ */
709
913
  public printHelp(command?: CommandPrimitive<any>): void {
710
914
  const cliName = this.name || "cli";
711
915
  const c = this.color;
@@ -757,7 +961,11 @@ export class CliProvider {
757
961
  ...Object.entries(command.flags.properties).map(([key, value]) => ({
758
962
  key,
759
963
  schema: value,
760
- aliases: (value as any).alias ?? [key],
964
+ aliases: [
965
+ key,
966
+ ...((value as any).aliases ??
967
+ ((value as any).alias ? [(value as any).alias] : [])),
968
+ ],
761
969
  description: (value as any).description,
762
970
  })),
763
971
  // Add --mode flag if command has mode option enabled
@@ -770,6 +978,7 @@ export class CliProvider {
770
978
  typeof command.options.mode === "string"
771
979
  ? `Environment mode - loads .env.{mode} (default: ${command.options.mode})`
772
980
  : "Environment mode (e.g., production, staging) - loads .env.{mode}",
981
+ schema: t.string() as TSchema,
773
982
  },
774
983
  ]
775
984
  : []),
@@ -780,13 +989,20 @@ export class CliProvider {
780
989
  ];
781
990
 
782
991
  const maxFlagLength = this.getMaxFlagLength(flags);
783
- for (const { aliases, description } of flags) {
784
- const flagStr = (Array.isArray(aliases) ? aliases : [aliases])
992
+ for (const flag of flags) {
993
+ const { aliases, description } = flag;
994
+ const schema = "schema" in flag ? (flag.schema as TSchema) : undefined;
995
+ // Sort aliases by length (shorter first: -t before --target)
996
+ const sortedAliases = (Array.isArray(aliases) ? aliases : [aliases])
997
+ .slice()
998
+ .sort((a, b) => a.length - b.length);
999
+ const flagStr = sortedAliases
785
1000
  .map((a: string) => (a.length === 1 ? `-${a}` : `--${a}`))
786
1001
  .join(", ");
787
1002
  const coloredFlag = c.set("GREY_LIGHT", flagStr);
788
1003
  const padding = " ".repeat(Math.max(0, maxFlagLength - flagStr.length));
789
- this.log.info(` ${coloredFlag}${padding} ${description ?? ""}`);
1004
+ const formattedDesc = this.formatFlagDescription(description, schema);
1005
+ this.log.info(` ${coloredFlag}${padding} ${formattedDesc}`);
790
1006
  }
791
1007
 
792
1008
  // Show environment variables if defined
@@ -853,6 +1069,7 @@ export class CliProvider {
853
1069
  []),
854
1070
  ],
855
1071
  description: (value as any).description,
1072
+ schema: value as TSchema,
856
1073
  }))
857
1074
  : [];
858
1075
 
@@ -861,21 +1078,20 @@ export class CliProvider {
861
1078
  ...Object.values(this.getAllGlobalFlags()),
862
1079
  ];
863
1080
  const maxFlagLength = this.getMaxFlagLength(globalFlags);
864
- for (const { aliases, description } of globalFlags) {
1081
+ for (const { aliases, description, schema } of globalFlags) {
865
1082
  const flagStr = aliases
866
1083
  .map((a) => (a.length === 1 ? `-${a}` : `--${a}`))
867
1084
  .join(", ");
868
1085
  const coloredFlag = c.set("GREY_LIGHT", flagStr);
869
1086
  const padding = " ".repeat(Math.max(0, maxFlagLength - flagStr.length));
870
- this.log.info(` ${coloredFlag}${padding} ${description ?? ""}`);
1087
+ const formattedDesc = this.formatFlagDescription(description, schema);
1088
+ this.log.info(` ${coloredFlag}${padding} ${formattedDesc}`);
871
1089
  }
872
1090
  }
873
1091
  this.log.info(""); // Newline
874
1092
  }
875
1093
 
876
- /**
877
- * Generate colored args usage string for help display.
878
- */
1094
+ /** Generate colored usage string for command arguments (for help display) */
879
1095
  protected generateColoredArgsUsage(schema?: TSchema): string {
880
1096
  if (!schema) {
881
1097
  return "";
@@ -907,9 +1123,7 @@ export class CliProvider {
907
1123
  return ` ${c.set("CYAN", `<${key}${typeName}>`)}`;
908
1124
  }
909
1125
 
910
- /**
911
- * Get the full command path (e.g., "deploy vercel" for a child command).
912
- */
1126
+ /** Get the full command path (e.g., "deploy vercel" for a nested command) */
913
1127
  protected getCommandPath(command: CommandPrimitive<any>): string {
914
1128
  const path: string[] = [command.name];
915
1129
  let current = command;
@@ -925,9 +1139,7 @@ export class CliProvider {
925
1139
  return path.join(" ");
926
1140
  }
927
1141
 
928
- /**
929
- * Find the parent command of a given command.
930
- */
1142
+ /** Find the parent command of a nested command */
931
1143
  protected findParentCommand(
932
1144
  command: CommandPrimitive<any>,
933
1145
  ): CommandPrimitive<any> | undefined {
@@ -939,9 +1151,7 @@ export class CliProvider {
939
1151
  return undefined;
940
1152
  }
941
1153
 
942
- /**
943
- * Get top-level commands (commands that are not children of other commands).
944
- */
1154
+ /** Get top-level commands (commands that are not children of other commands) */
945
1155
  protected getTopLevelCommands(): CommandPrimitive<any>[] {
946
1156
  const allChildren = new Set<CommandPrimitive<any>>();
947
1157
 
@@ -956,9 +1166,7 @@ export class CliProvider {
956
1166
  return this.commands.filter((cmd) => !allChildren.has(cmd));
957
1167
  }
958
1168
 
959
- /**
960
- * Get max length for child command display.
961
- */
1169
+ /** Calculate max display length for child commands (for help alignment) */
962
1170
  protected getMaxChildCmdLength(children: CommandPrimitive<any>[]): number {
963
1171
  return Math.max(
964
1172
  ...children
@@ -972,6 +1180,7 @@ export class CliProvider {
972
1180
  );
973
1181
  }
974
1182
 
1183
+ /** Calculate max display length for commands (for help alignment) */
975
1184
  protected getMaxCmdLength(commands: CommandPrimitive[]): number {
976
1185
  return Math.max(
977
1186
  ...commands
@@ -986,7 +1195,8 @@ export class CliProvider {
986
1195
  );
987
1196
  }
988
1197
 
989
- private getMaxFlagLength(flags: { aliases: string[] }[]): number {
1198
+ /** Calculate max display length for flags (for help alignment) */
1199
+ protected getMaxFlagLength(flags: { aliases: string[] }[]): number {
990
1200
  return Math.max(
991
1201
  ...flags.map((f) => {
992
1202
  const aliases = Array.isArray(f.aliases) ? f.aliases : [f.aliases];
@@ -996,4 +1206,67 @@ export class CliProvider {
996
1206
  }),
997
1207
  );
998
1208
  }
1209
+
1210
+ /**
1211
+ * Extract enum values from a schema if it represents an enum.
1212
+ * Returns undefined if the schema is not an enum.
1213
+ */
1214
+ protected getEnumValues(schema: TSchema): string[] | undefined {
1215
+ if (!schema) return undefined;
1216
+
1217
+ // Check if schema has an enum property (t.enum creates schemas with this)
1218
+ if (
1219
+ "enum" in schema &&
1220
+ Array.isArray(schema.enum) &&
1221
+ schema.enum.every((v) => typeof v === "string")
1222
+ ) {
1223
+ return schema.enum as string[];
1224
+ }
1225
+
1226
+ // Also check for union of string literals (alternative enum representation)
1227
+ if (t.schema.isUnion(schema)) {
1228
+ const union = schema as TUnion;
1229
+ const values: string[] = [];
1230
+
1231
+ for (const variant of union.anyOf) {
1232
+ // Check if the variant is a string literal (has const property)
1233
+ if (
1234
+ t.schema.isString(variant) &&
1235
+ "const" in variant &&
1236
+ typeof variant.const === "string"
1237
+ ) {
1238
+ values.push(variant.const);
1239
+ } else {
1240
+ // Not all variants are string literals, not a simple enum
1241
+ return undefined;
1242
+ }
1243
+ }
1244
+
1245
+ return values.length > 0 ? values : undefined;
1246
+ }
1247
+
1248
+ return undefined;
1249
+ }
1250
+
1251
+ /**
1252
+ * Format flag description with enum values if applicable.
1253
+ */
1254
+ protected formatFlagDescription(
1255
+ description: string | undefined,
1256
+ schema: TSchema | undefined,
1257
+ ): string {
1258
+ const baseDesc = description ?? "";
1259
+
1260
+ if (!schema) return baseDesc;
1261
+
1262
+ const enumValues = this.getEnumValues(schema);
1263
+ if (enumValues && enumValues.length > 0) {
1264
+ const valuesStr = enumValues.join(", ");
1265
+ const c = this.color;
1266
+ const enumHint = c.set("GREY_DARK", `[${valuesStr}]`);
1267
+ return baseDesc ? `${baseDesc} ${enumHint}` : enumHint;
1268
+ }
1269
+
1270
+ return baseDesc;
1271
+ }
999
1272
  }