alepha 0.14.2 β†’ 0.14.4

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 (405) hide show
  1. package/README.md +1 -1
  2. package/dist/api/audits/index.browser.js +5 -5
  3. package/dist/api/audits/index.browser.js.map +1 -1
  4. package/dist/api/audits/index.d.ts +706 -785
  5. package/dist/api/audits/index.d.ts.map +1 -1
  6. package/dist/api/audits/index.js +13 -13
  7. package/dist/api/audits/index.js.map +1 -1
  8. package/dist/api/files/index.browser.js +5 -5
  9. package/dist/api/files/index.browser.js.map +1 -1
  10. package/dist/api/files/index.d.ts +58 -137
  11. package/dist/api/files/index.d.ts.map +1 -1
  12. package/dist/api/files/index.js +71 -71
  13. package/dist/api/files/index.js.map +1 -1
  14. package/dist/api/jobs/index.browser.js +5 -5
  15. package/dist/api/jobs/index.browser.js.map +1 -1
  16. package/dist/api/jobs/index.d.ts +29 -108
  17. package/dist/api/jobs/index.d.ts.map +1 -1
  18. package/dist/api/jobs/index.js +10 -10
  19. package/dist/api/jobs/index.js.map +1 -1
  20. package/dist/api/notifications/index.browser.js +10 -10
  21. package/dist/api/notifications/index.browser.js.map +1 -1
  22. package/dist/api/notifications/index.d.ts +504 -171
  23. package/dist/api/notifications/index.d.ts.map +1 -1
  24. package/dist/api/notifications/index.js +12 -12
  25. package/dist/api/notifications/index.js.map +1 -1
  26. package/dist/api/parameters/index.browser.js +163 -10
  27. package/dist/api/parameters/index.browser.js.map +1 -1
  28. package/dist/api/parameters/index.d.ts +277 -351
  29. package/dist/api/parameters/index.d.ts.map +1 -1
  30. package/dist/api/parameters/index.js +196 -91
  31. package/dist/api/parameters/index.js.map +1 -1
  32. package/dist/api/users/index.browser.js +19 -19
  33. package/dist/api/users/index.browser.js.map +1 -1
  34. package/dist/api/users/index.d.ts +787 -852
  35. package/dist/api/users/index.d.ts.map +1 -1
  36. package/dist/api/users/index.js +827 -596
  37. package/dist/api/users/index.js.map +1 -1
  38. package/dist/api/verifications/index.browser.js +6 -6
  39. package/dist/api/verifications/index.browser.js.map +1 -1
  40. package/dist/api/verifications/index.d.ts +128 -128
  41. package/dist/api/verifications/index.d.ts.map +1 -1
  42. package/dist/api/verifications/index.js +6 -6
  43. package/dist/api/verifications/index.js.map +1 -1
  44. package/dist/bin/index.d.ts +1 -2
  45. package/dist/bin/index.js +0 -1
  46. package/dist/bin/index.js.map +1 -1
  47. package/dist/cli/index.d.ts +252 -131
  48. package/dist/cli/index.d.ts.map +1 -1
  49. package/dist/cli/index.js +595 -395
  50. package/dist/cli/index.js.map +1 -1
  51. package/dist/command/index.d.ts +46 -11
  52. package/dist/command/index.d.ts.map +1 -1
  53. package/dist/command/index.js +99 -19
  54. package/dist/command/index.js.map +1 -1
  55. package/dist/core/index.browser.js +40 -22
  56. package/dist/core/index.browser.js.map +1 -1
  57. package/dist/core/index.d.ts +45 -1
  58. package/dist/core/index.d.ts.map +1 -1
  59. package/dist/core/index.js +40 -22
  60. package/dist/core/index.js.map +1 -1
  61. package/dist/core/index.native.js +40 -22
  62. package/dist/core/index.native.js.map +1 -1
  63. package/dist/fake/index.js +195 -168
  64. package/dist/fake/index.js.map +1 -1
  65. package/dist/file/index.d.ts +8 -0
  66. package/dist/file/index.d.ts.map +1 -1
  67. package/dist/file/index.js +3 -0
  68. package/dist/file/index.js.map +1 -1
  69. package/dist/logger/index.d.ts +1 -1
  70. package/dist/logger/index.d.ts.map +1 -1
  71. package/dist/logger/index.js +12 -2
  72. package/dist/logger/index.js.map +1 -1
  73. package/dist/mcp/index.js +1 -1
  74. package/dist/mcp/index.js.map +1 -1
  75. package/dist/orm/index.d.ts +59 -195
  76. package/dist/orm/index.d.ts.map +1 -1
  77. package/dist/orm/index.js +201 -430
  78. package/dist/orm/index.js.map +1 -1
  79. package/dist/security/index.d.ts +1 -1
  80. package/dist/security/index.d.ts.map +1 -1
  81. package/dist/security/index.js +1 -1
  82. package/dist/security/index.js.map +1 -1
  83. package/dist/server/auth/index.d.ts +171 -155
  84. package/dist/server/auth/index.d.ts.map +1 -1
  85. package/dist/server/auth/index.js +0 -1
  86. package/dist/server/auth/index.js.map +1 -1
  87. package/dist/server/cache/index.d.ts +12 -0
  88. package/dist/server/cache/index.d.ts.map +1 -1
  89. package/dist/server/cache/index.js +55 -2
  90. package/dist/server/cache/index.js.map +1 -1
  91. package/dist/server/compress/index.d.ts +6 -0
  92. package/dist/server/compress/index.d.ts.map +1 -1
  93. package/dist/server/compress/index.js +38 -1
  94. package/dist/server/compress/index.js.map +1 -1
  95. package/dist/server/core/index.browser.js +2 -2
  96. package/dist/server/core/index.browser.js.map +1 -1
  97. package/dist/server/core/index.d.ts +10 -10
  98. package/dist/server/core/index.d.ts.map +1 -1
  99. package/dist/server/core/index.js +7 -4
  100. package/dist/server/core/index.js.map +1 -1
  101. package/dist/server/links/index.browser.js +22 -6
  102. package/dist/server/links/index.browser.js.map +1 -1
  103. package/dist/server/links/index.d.ts +46 -44
  104. package/dist/server/links/index.d.ts.map +1 -1
  105. package/dist/server/links/index.js +24 -41
  106. package/dist/server/links/index.js.map +1 -1
  107. package/dist/server/static/index.d.ts.map +1 -1
  108. package/dist/server/static/index.js +4 -0
  109. package/dist/server/static/index.js.map +1 -1
  110. package/dist/server/swagger/index.d.ts +2 -1
  111. package/dist/server/swagger/index.d.ts.map +1 -1
  112. package/dist/server/swagger/index.js +9 -5
  113. package/dist/server/swagger/index.js.map +1 -1
  114. package/dist/vite/index.d.ts +101 -106
  115. package/dist/vite/index.d.ts.map +1 -1
  116. package/dist/vite/index.js +574 -503
  117. package/dist/vite/index.js.map +1 -1
  118. package/dist/websocket/index.d.ts +7 -7
  119. package/package.json +7 -7
  120. package/src/api/audits/controllers/{AuditController.ts β†’ AdminAuditController.ts} +5 -6
  121. package/src/api/audits/entities/audits.ts +5 -5
  122. package/src/api/audits/index.browser.ts +1 -1
  123. package/src/api/audits/index.ts +3 -3
  124. package/src/api/audits/primitives/$audit.spec.ts +276 -0
  125. package/src/api/audits/services/AuditService.spec.ts +495 -0
  126. package/src/api/files/__tests__/$bucket.spec.ts +91 -0
  127. package/src/api/files/controllers/AdminFileStatsController.spec.ts +166 -0
  128. package/src/api/files/controllers/{StorageStatsController.ts β†’ AdminFileStatsController.ts} +2 -2
  129. package/src/api/files/controllers/FileController.spec.ts +558 -0
  130. package/src/api/files/controllers/FileController.ts +4 -5
  131. package/src/api/files/entities/files.ts +5 -5
  132. package/src/api/files/index.browser.ts +1 -1
  133. package/src/api/files/index.ts +4 -4
  134. package/src/api/files/jobs/FileJobs.spec.ts +52 -0
  135. package/src/api/files/services/FileService.spec.ts +109 -0
  136. package/src/api/jobs/__tests__/JobController.spec.ts +343 -0
  137. package/src/api/jobs/controllers/{JobController.ts β†’ AdminJobController.ts} +2 -2
  138. package/src/api/jobs/entities/jobExecutions.ts +5 -5
  139. package/src/api/jobs/index.ts +3 -3
  140. package/src/api/jobs/primitives/$job.spec.ts +476 -0
  141. package/src/api/notifications/controllers/{NotificationController.ts β†’ AdminNotificationController.ts} +4 -5
  142. package/src/api/notifications/entities/notifications.ts +5 -5
  143. package/src/api/notifications/index.browser.ts +1 -1
  144. package/src/api/notifications/index.ts +4 -4
  145. package/src/api/parameters/controllers/{ConfigController.ts β†’ AdminConfigController.ts} +46 -107
  146. package/src/api/parameters/entities/parameters.ts +7 -17
  147. package/src/api/parameters/index.ts +3 -3
  148. package/src/api/parameters/primitives/$config.spec.ts +356 -0
  149. package/src/api/parameters/schemas/activateConfigBodySchema.ts +12 -0
  150. package/src/api/parameters/schemas/checkScheduledResponseSchema.ts +8 -0
  151. package/src/api/parameters/schemas/configCurrentResponseSchema.ts +13 -0
  152. package/src/api/parameters/schemas/configHistoryResponseSchema.ts +9 -0
  153. package/src/api/parameters/schemas/configNameParamSchema.ts +10 -0
  154. package/src/api/parameters/schemas/configNamesResponseSchema.ts +8 -0
  155. package/src/api/parameters/schemas/configTreeNodeSchema.ts +13 -0
  156. package/src/api/parameters/schemas/configVersionParamSchema.ts +9 -0
  157. package/src/api/parameters/schemas/configVersionResponseSchema.ts +9 -0
  158. package/src/api/parameters/schemas/configsByStatusResponseSchema.ts +9 -0
  159. package/src/api/parameters/schemas/createConfigVersionBodySchema.ts +24 -0
  160. package/src/api/parameters/schemas/index.ts +15 -0
  161. package/src/api/parameters/schemas/parameterResponseSchema.ts +26 -0
  162. package/src/api/parameters/schemas/parameterStatusSchema.ts +13 -0
  163. package/src/api/parameters/schemas/rollbackConfigBodySchema.ts +15 -0
  164. package/src/api/parameters/schemas/statusParamSchema.ts +9 -0
  165. package/src/api/users/__tests__/EmailVerification.spec.ts +369 -0
  166. package/src/api/users/__tests__/PasswordReset.spec.ts +550 -0
  167. package/src/api/users/controllers/AdminIdentityController.spec.ts +365 -0
  168. package/src/api/users/controllers/{IdentityController.ts β†’ AdminIdentityController.ts} +3 -4
  169. package/src/api/users/controllers/AdminSessionController.spec.ts +274 -0
  170. package/src/api/users/controllers/{SessionController.ts β†’ AdminSessionController.ts} +3 -4
  171. package/src/api/users/controllers/AdminUserController.spec.ts +372 -0
  172. package/src/api/users/controllers/AdminUserController.ts +116 -0
  173. package/src/api/users/controllers/UserController.ts +4 -107
  174. package/src/api/users/controllers/UserRealmController.ts +3 -0
  175. package/src/api/users/entities/identities.ts +6 -6
  176. package/src/api/users/entities/sessions.ts +6 -6
  177. package/src/api/users/entities/users.ts +9 -9
  178. package/src/api/users/index.ts +9 -6
  179. package/src/api/users/primitives/$userRealm.ts +13 -8
  180. package/src/api/users/services/CredentialService.spec.ts +509 -0
  181. package/src/api/users/services/CredentialService.ts +46 -0
  182. package/src/api/users/services/IdentityService.ts +15 -0
  183. package/src/api/users/services/RegistrationService.spec.ts +630 -0
  184. package/src/api/users/services/RegistrationService.ts +18 -0
  185. package/src/api/users/services/SessionService.spec.ts +301 -0
  186. package/src/api/users/services/SessionService.ts +110 -1
  187. package/src/api/users/services/UserService.ts +67 -2
  188. package/src/api/verifications/__tests__/CodeVerification.spec.ts +318 -0
  189. package/src/api/verifications/__tests__/LinkVerification.spec.ts +279 -0
  190. package/src/api/verifications/entities/verifications.ts +6 -6
  191. package/src/api/verifications/jobs/VerificationJobs.spec.ts +50 -0
  192. package/src/batch/__tests__/startup-buffering.spec.ts +458 -0
  193. package/src/batch/primitives/$batch.spec.ts +766 -0
  194. package/src/batch/providers/BatchProvider.spec.ts +786 -0
  195. package/src/bin/index.ts +0 -1
  196. package/src/bucket/__tests__/shared.ts +194 -0
  197. package/src/bucket/primitives/$bucket.spec.ts +104 -0
  198. package/src/bucket/providers/FileStorageProvider.spec.ts +13 -0
  199. package/src/bucket/providers/LocalFileStorageProvider.spec.ts +77 -0
  200. package/src/bucket/providers/MemoryFileStorageProvider.spec.ts +82 -0
  201. package/src/cache/core/__tests__/shared.ts +377 -0
  202. package/src/cache/core/primitives/$cache.spec.ts +111 -0
  203. package/src/cache/redis/__tests__/cache-redis.spec.ts +70 -0
  204. package/src/cli/apps/AlephaCli.ts +25 -6
  205. package/src/cli/atoms/buildOptions.ts +88 -0
  206. package/src/cli/commands/build.ts +32 -69
  207. package/src/cli/commands/db.ts +0 -4
  208. package/src/cli/commands/dev.ts +34 -10
  209. package/src/cli/commands/gen/changelog.spec.ts +315 -0
  210. package/src/cli/commands/{changelog.ts β†’ gen/changelog.ts} +9 -9
  211. package/src/cli/commands/gen/env.ts +53 -0
  212. package/src/cli/commands/gen/openapi.ts +71 -0
  213. package/src/cli/commands/gen/resource.ts +15 -0
  214. package/src/cli/commands/gen.ts +24 -0
  215. package/src/cli/commands/init.ts +2 -1
  216. package/src/cli/commands/root.ts +12 -3
  217. package/src/cli/commands/test.ts +0 -1
  218. package/src/cli/commands/typecheck.ts +5 -0
  219. package/src/cli/commands/verify.ts +1 -1
  220. package/src/cli/defineConfig.ts +49 -7
  221. package/src/cli/index.ts +2 -2
  222. package/src/cli/services/AlephaCliUtils.ts +105 -55
  223. package/src/cli/services/GitMessageParser.ts +1 -1
  224. package/src/command/helpers/Asker.spec.ts +127 -0
  225. package/src/command/helpers/Runner.spec.ts +126 -0
  226. package/src/command/helpers/Runner.ts +1 -1
  227. package/src/command/primitives/$command.spec.ts +1588 -0
  228. package/src/command/primitives/$command.ts +0 -6
  229. package/src/command/providers/CliProvider.ts +75 -27
  230. package/src/core/Alepha.ts +87 -0
  231. package/src/core/__tests__/Alepha-emit.spec.ts +22 -0
  232. package/src/core/__tests__/Alepha-graph.spec.ts +93 -0
  233. package/src/core/__tests__/Alepha-has.spec.ts +41 -0
  234. package/src/core/__tests__/Alepha-inject.spec.ts +93 -0
  235. package/src/core/__tests__/Alepha-register.spec.ts +81 -0
  236. package/src/core/__tests__/Alepha-start.spec.ts +176 -0
  237. package/src/core/__tests__/Alepha-with.spec.ts +14 -0
  238. package/src/core/__tests__/TypeBox-usecases.spec.ts +35 -0
  239. package/src/core/__tests__/TypeBoxLocale.spec.ts +15 -0
  240. package/src/core/__tests__/descriptor.spec.ts +34 -0
  241. package/src/core/__tests__/fixtures/A.ts +5 -0
  242. package/src/core/__tests__/pagination.spec.ts +77 -0
  243. package/src/core/helpers/jsonSchemaToTypeBox.ts +2 -2
  244. package/src/core/primitives/$atom.spec.ts +43 -0
  245. package/src/core/primitives/$hook.spec.ts +130 -0
  246. package/src/core/primitives/$inject.spec.ts +175 -0
  247. package/src/core/primitives/$module.spec.ts +115 -0
  248. package/src/core/providers/CodecManager.spec.ts +740 -0
  249. package/src/core/providers/EventManager.spec.ts +762 -0
  250. package/src/core/providers/EventManager.ts +4 -0
  251. package/src/core/providers/StateManager.spec.ts +365 -0
  252. package/src/core/providers/TypeProvider.spec.ts +1607 -0
  253. package/src/core/providers/TypeProvider.ts +20 -26
  254. package/src/datetime/primitives/$interval.spec.ts +103 -0
  255. package/src/datetime/providers/DateTimeProvider.spec.ts +86 -0
  256. package/src/email/primitives/$email.spec.ts +175 -0
  257. package/src/email/providers/LocalEmailProvider.spec.ts +341 -0
  258. package/src/fake/__tests__/keyName.example.ts +40 -0
  259. package/src/fake/__tests__/keyName.spec.ts +152 -0
  260. package/src/fake/__tests__/module.example.ts +32 -0
  261. package/src/fake/providers/FakeProvider.spec.ts +438 -0
  262. package/src/file/providers/FileSystemProvider.ts +8 -0
  263. package/src/file/providers/NodeFileSystemProvider.spec.ts +418 -0
  264. package/src/file/providers/NodeFileSystemProvider.ts +5 -0
  265. package/src/file/services/FileDetector.spec.ts +591 -0
  266. package/src/lock/core/__tests__/shared.ts +190 -0
  267. package/src/lock/core/providers/MemoryLockProvider.spec.ts +25 -0
  268. package/src/lock/redis/providers/RedisLockProvider.spec.ts +25 -0
  269. package/src/logger/__tests__/SimpleFormatterProvider.spec.ts +109 -0
  270. package/src/logger/index.ts +15 -3
  271. package/src/logger/primitives/$logger.spec.ts +108 -0
  272. package/src/logger/services/Logger.spec.ts +295 -0
  273. package/src/mcp/__tests__/errors.spec.ts +175 -0
  274. package/src/mcp/__tests__/integration.spec.ts +450 -0
  275. package/src/mcp/helpers/jsonrpc.spec.ts +380 -0
  276. package/src/mcp/primitives/$prompt.spec.ts +468 -0
  277. package/src/mcp/primitives/$resource.spec.ts +390 -0
  278. package/src/mcp/primitives/$tool.spec.ts +406 -0
  279. package/src/mcp/providers/McpServerProvider.spec.ts +797 -0
  280. package/src/mcp/transports/StdioMcpTransport.ts +1 -1
  281. package/src/orm/__tests__/$repository-crud.spec.ts +276 -0
  282. package/src/orm/__tests__/$repository-hooks.spec.ts +325 -0
  283. package/src/orm/__tests__/$repository-orderBy.spec.ts +128 -0
  284. package/src/orm/__tests__/$repository-pagination-sort.spec.ts +149 -0
  285. package/src/orm/__tests__/$repository-save.spec.ts +37 -0
  286. package/src/orm/__tests__/ModelBuilder-integration.spec.ts +490 -0
  287. package/src/orm/__tests__/ModelBuilder-types.spec.ts +186 -0
  288. package/src/orm/__tests__/PostgresProvider.spec.ts +46 -0
  289. package/src/orm/__tests__/delete-returning.spec.ts +256 -0
  290. package/src/orm/__tests__/deletedAt.spec.ts +80 -0
  291. package/src/orm/__tests__/enums.spec.ts +315 -0
  292. package/src/orm/__tests__/execute.spec.ts +72 -0
  293. package/src/orm/__tests__/fixtures/bigEntitySchema.ts +65 -0
  294. package/src/orm/__tests__/fixtures/userEntitySchema.ts +27 -0
  295. package/src/orm/__tests__/joins.spec.ts +1114 -0
  296. package/src/orm/__tests__/page.spec.ts +287 -0
  297. package/src/orm/__tests__/primaryKey.spec.ts +87 -0
  298. package/src/orm/__tests__/query-date-encoding.spec.ts +402 -0
  299. package/src/orm/__tests__/ref-auto-onDelete.spec.ts +156 -0
  300. package/src/orm/__tests__/references.spec.ts +102 -0
  301. package/src/orm/__tests__/security.spec.ts +710 -0
  302. package/src/orm/__tests__/sqlite.spec.ts +111 -0
  303. package/src/orm/__tests__/string-operators.spec.ts +429 -0
  304. package/src/orm/__tests__/timestamps.spec.ts +388 -0
  305. package/src/orm/__tests__/validation.spec.ts +183 -0
  306. package/src/orm/__tests__/version.spec.ts +64 -0
  307. package/src/orm/helpers/parseQueryString.spec.ts +196 -0
  308. package/src/orm/index.ts +2 -8
  309. package/src/orm/primitives/$repository.spec.ts +137 -0
  310. package/src/orm/primitives/$sequence.spec.ts +29 -0
  311. package/src/orm/primitives/$transaction.spec.ts +82 -0
  312. package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -3
  313. package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
  314. package/src/orm/providers/drivers/CloudflareD1Provider.ts +1 -1
  315. package/src/orm/providers/drivers/DatabaseProvider.ts +1 -1
  316. package/src/orm/providers/drivers/NodePostgresProvider.ts +3 -3
  317. package/src/orm/providers/drivers/NodeSqliteProvider.ts +1 -1
  318. package/src/orm/providers/drivers/PglitePostgresProvider.ts +2 -2
  319. package/src/orm/services/ModelBuilder.spec.ts +575 -0
  320. package/src/orm/services/Repository.spec.ts +137 -0
  321. package/src/queue/core/__tests__/shared.ts +143 -0
  322. package/src/queue/core/providers/MemoryQueueProvider.spec.ts +23 -0
  323. package/src/queue/core/providers/WorkerProvider.spec.ts +394 -0
  324. package/src/queue/redis/providers/RedisQueueProvider.spec.ts +23 -0
  325. package/src/redis/__tests__/redis.spec.ts +58 -0
  326. package/src/retry/primitives/$retry.spec.ts +234 -0
  327. package/src/retry/providers/RetryProvider.spec.ts +438 -0
  328. package/src/router/__tests__/match.spec.ts +252 -0
  329. package/src/router/providers/RouterProvider.spec.ts +197 -0
  330. package/src/scheduler/__tests__/$scheduler-cron.spec.ts +25 -0
  331. package/src/scheduler/__tests__/$scheduler-interval.spec.ts +25 -0
  332. package/src/scheduler/__tests__/shared.ts +77 -0
  333. package/src/security/__tests__/bug-1-wildcard-after-start.spec.ts +229 -0
  334. package/src/security/__tests__/bug-2-password-validation.spec.ts +245 -0
  335. package/src/security/__tests__/bug-3-regex-vulnerability.spec.ts +407 -0
  336. package/src/security/__tests__/bug-4-oauth2-validation.spec.ts +439 -0
  337. package/src/security/__tests__/multi-layer-permissions.spec.ts +522 -0
  338. package/src/security/primitives/$permission.spec.ts +30 -0
  339. package/src/security/primitives/$permission.ts +2 -2
  340. package/src/security/primitives/$realm.spec.ts +101 -0
  341. package/src/security/primitives/$role.spec.ts +52 -0
  342. package/src/security/primitives/$serviceAccount.spec.ts +61 -0
  343. package/src/security/providers/SecurityProvider.spec.ts +350 -0
  344. package/src/server/auth/providers/ServerAuthProvider.ts +0 -2
  345. package/src/server/cache/providers/ServerCacheProvider.spec.ts +1125 -0
  346. package/src/server/cache/providers/ServerCacheProvider.ts +94 -9
  347. package/src/server/compress/providers/ServerCompressProvider.spec.ts +31 -0
  348. package/src/server/compress/providers/ServerCompressProvider.ts +63 -2
  349. package/src/server/cookies/providers/ServerCookiesProvider.spec.ts +253 -0
  350. package/src/server/core/__tests__/ServerRouterProvider-getRoutes.spec.ts +334 -0
  351. package/src/server/core/__tests__/ServerRouterProvider-requestId.spec.ts +129 -0
  352. package/src/server/core/helpers/ServerReply.ts +2 -2
  353. package/src/server/core/primitives/$action.spec.ts +191 -0
  354. package/src/server/core/primitives/$route.spec.ts +65 -0
  355. package/src/server/core/providers/ServerBodyParserProvider.spec.ts +93 -0
  356. package/src/server/core/providers/ServerLoggerProvider.spec.ts +100 -0
  357. package/src/server/core/providers/ServerProvider.ts +14 -2
  358. package/src/server/core/services/HttpClient.spec.ts +123 -0
  359. package/src/server/core/services/UserAgentParser.spec.ts +111 -0
  360. package/src/server/cors/providers/ServerCorsProvider.spec.ts +481 -0
  361. package/src/server/health/providers/ServerHealthProvider.spec.ts +22 -0
  362. package/src/server/helmet/providers/ServerHelmetProvider.spec.ts +105 -0
  363. package/src/server/links/__tests__/$action.spec.ts +238 -0
  364. package/src/server/links/__tests__/fixtures/CrudApp.ts +122 -0
  365. package/src/server/links/__tests__/requestId.spec.ts +120 -0
  366. package/src/server/links/primitives/$remote.spec.ts +228 -0
  367. package/src/server/links/providers/LinkProvider.spec.ts +54 -0
  368. package/src/server/links/providers/LinkProvider.ts +49 -3
  369. package/src/server/links/providers/ServerLinksProvider.ts +1 -53
  370. package/src/server/links/schemas/apiLinksResponseSchema.ts +7 -0
  371. package/src/server/metrics/providers/ServerMetricsProvider.spec.ts +25 -0
  372. package/src/server/multipart/providers/ServerMultipartProvider.spec.ts +528 -0
  373. package/src/server/proxy/primitives/$proxy.spec.ts +87 -0
  374. package/src/server/rate-limit/__tests__/ActionRateLimit.spec.ts +211 -0
  375. package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +344 -0
  376. package/src/server/security/__tests__/BasicAuth.spec.ts +684 -0
  377. package/src/server/security/__tests__/ServerSecurityProvider-realm.spec.ts +388 -0
  378. package/src/server/security/providers/ServerSecurityProvider.spec.ts +123 -0
  379. package/src/server/static/primitives/$serve.spec.ts +193 -0
  380. package/src/server/static/providers/ServerStaticProvider.ts +10 -0
  381. package/src/server/swagger/__tests__/ui.spec.ts +52 -0
  382. package/src/server/swagger/primitives/$swagger.spec.ts +193 -0
  383. package/src/server/swagger/providers/ServerSwaggerProvider.ts +19 -12
  384. package/src/sms/primitives/$sms.spec.ts +165 -0
  385. package/src/sms/providers/LocalSmsProvider.spec.ts +224 -0
  386. package/src/sms/providers/MemorySmsProvider.spec.ts +193 -0
  387. package/src/thread/primitives/$thread.spec.ts +186 -0
  388. package/src/topic/core/__tests__/shared.ts +144 -0
  389. package/src/topic/core/providers/MemoryTopicProvider.spec.ts +23 -0
  390. package/src/topic/redis/providers/RedisTopicProvider.spec.ts +23 -0
  391. package/src/vite/helpers/importViteReact.ts +13 -0
  392. package/src/vite/index.ts +1 -21
  393. package/src/vite/plugins/viteAlephaDev.ts +32 -5
  394. package/src/vite/plugins/viteAlephaSsrPreload.ts +222 -0
  395. package/src/vite/tasks/buildClient.ts +11 -0
  396. package/src/vite/tasks/buildServer.ts +47 -3
  397. package/src/vite/tasks/devServer.ts +69 -0
  398. package/src/vite/tasks/index.ts +2 -1
  399. package/src/vite/tasks/runAlepha.ts +7 -1
  400. package/src/websocket/__tests__/$websocket-new.spec.ts +195 -0
  401. package/src/websocket/primitives/$channel.spec.ts +30 -0
  402. package/src/cli/assets/viteConfigTs.ts +0 -14
  403. package/src/cli/commands/run.ts +0 -24
  404. package/src/vite/plugins/viteAlepha.ts +0 -37
  405. package/src/vite/plugins/viteAlephaBuild.ts +0 -281
@@ -105,12 +105,6 @@ export interface CommandPrimitiveOptions<
105
105
  */
106
106
  args?: A;
107
107
 
108
- /**
109
- * If false, skip summary message at the end of the command execution.
110
- * Summary will display only if ({ run }) method calls were made.
111
- */
112
- summary?: boolean;
113
-
114
108
  /**
115
109
  * Marks this command as the root command.
116
110
  * Equivalent to setting name to an empty string "".
@@ -14,6 +14,7 @@ import {
14
14
  t,
15
15
  } from "alepha";
16
16
  import { $logger } from "alepha/logger";
17
+ import { ConsoleColorProvider } from "../../logger/providers/ConsoleColorProvider.ts";
17
18
  import { CommandError } from "../errors/CommandError.ts";
18
19
  import { Asker } from "../helpers/Asker.ts";
19
20
  import { EnvUtils } from "../helpers/EnvUtils.ts";
@@ -80,6 +81,7 @@ export class CliProvider {
80
81
  protected readonly env = $env(envSchema);
81
82
  protected readonly alepha = $inject(Alepha);
82
83
  protected readonly log = $logger();
84
+ protected readonly color = $inject(ConsoleColorProvider);
83
85
  protected readonly runner = $inject(Runner);
84
86
  protected readonly asker = $inject(Asker);
85
87
  protected readonly envUtils = $inject(EnvUtils);
@@ -235,9 +237,7 @@ export class CliProvider {
235
237
  await hook.options.handler(args as CommandHandlerArgs<TObject>);
236
238
  }
237
239
 
238
- if (command.options.summary !== false) {
239
- runner.summary();
240
- }
240
+ runner.end();
241
241
 
242
242
  this.log.debug(`Command '${command.name}' executed successfully.`);
243
243
  });
@@ -708,17 +708,19 @@ export class CliProvider {
708
708
 
709
709
  public printHelp(command?: CommandPrimitive<any>): void {
710
710
  const cliName = this.name || "cli";
711
+ const c = this.color;
711
712
  this.log.info(""); // Newline
712
713
 
713
714
  if (command?.name) {
714
715
  // Command-specific help
715
716
  const hasChildren = command.hasChildren;
716
717
  const argsUsage = hasChildren
717
- ? " <command>"
718
- : this.generateArgsUsage(command.options.args);
718
+ ? ` ${c.set("CYAN", "<command>")}`
719
+ : this.generateColoredArgsUsage(command.options.args);
719
720
  const commandPath = this.getCommandPath(command);
720
- const usage = `${cliName} ${commandPath}${argsUsage}`.trim();
721
- this.log.info(`Usage: \`${usage}\``);
721
+ const usage =
722
+ `${c.set("GREY_LIGHT", cliName)} ${c.set("CYAN", commandPath)}${argsUsage}`.trim();
723
+ this.log.info(`${c.set("WHITE_BOLD", "Usage:")} ${usage}`);
722
724
 
723
725
  if (command.options.description) {
724
726
  this.log.info(``);
@@ -728,7 +730,7 @@ export class CliProvider {
728
730
  // Show subcommands if this is a parent command
729
731
  if (hasChildren) {
730
732
  this.log.info("");
731
- this.log.info("Commands:");
733
+ this.log.info(c.set("WHITE_BOLD", "Commands:"));
732
734
  const maxSubCmdLength = this.getMaxChildCmdLength(command.children);
733
735
 
734
736
  for (const child of command.children) {
@@ -738,14 +740,18 @@ export class CliProvider {
738
740
  const childArgsUsage = this.generateArgsUsage(child.options.args);
739
741
  const cmdStr = [child.name, ...child.aliases].join(", ");
740
742
  const fullCmdStr = `${cmdStr}${childArgsUsage}`;
743
+ const coloredCmd = `${c.set("GREY_LIGHT", cliName)} ${c.set("CYAN", command.name)} ${c.set("CYAN", fullCmdStr)}`;
744
+ const padding = " ".repeat(
745
+ Math.max(0, maxSubCmdLength - fullCmdStr.length),
746
+ );
741
747
  this.log.info(
742
- ` ${cliName} ${command.name} ${fullCmdStr.padEnd(maxSubCmdLength)} # ${child.options.description ?? ""}`,
748
+ ` ${coloredCmd}${padding} ${child.options.description ?? ""}`,
743
749
  );
744
750
  }
745
751
  }
746
752
 
747
753
  this.log.info("");
748
- this.log.info("Flags:");
754
+ this.log.info(c.set("WHITE_BOLD", "Flags:"));
749
755
 
750
756
  const flags = [
751
757
  ...Object.entries(command.flags.properties).map(([key, value]) => ({
@@ -778,23 +784,27 @@ export class CliProvider {
778
784
  const flagStr = (Array.isArray(aliases) ? aliases : [aliases])
779
785
  .map((a: string) => (a.length === 1 ? `-${a}` : `--${a}`))
780
786
  .join(", ");
781
- this.log.info(
782
- ` ${flagStr.padEnd(maxFlagLength)} # ${description ?? ""}`,
783
- );
787
+ const coloredFlag = c.set("GREY_LIGHT", flagStr);
788
+ const padding = " ".repeat(Math.max(0, maxFlagLength - flagStr.length));
789
+ this.log.info(` ${coloredFlag}${padding} ${description ?? ""}`);
784
790
  }
785
791
 
786
792
  // Show environment variables if defined
787
793
  const envVars = Object.entries(command.env.properties);
788
794
  if (envVars.length > 0) {
789
795
  this.log.info("");
790
- this.log.info("Env:");
796
+ this.log.info(c.set("WHITE_BOLD", "Env:"));
791
797
  const maxEnvLength = Math.max(...envVars.map(([key]) => key.length));
792
798
  for (const [key, schema] of envVars) {
793
799
  const isOptional = t.schema.isOptional(schema as TSchema);
794
800
  const description = (schema as any).description ?? "";
795
- const optionalStr = isOptional ? " (optional)" : "";
801
+ const optionalStr = isOptional
802
+ ? c.set("GREY_DARK", " (optional)")
803
+ : c.set("RED", " (required)");
804
+ const coloredKey = c.set("CYAN", key);
805
+ const padding = " ".repeat(Math.max(0, maxEnvLength - key.length));
796
806
  this.log.info(
797
- ` ${key.padEnd(maxEnvLength)} # ${description}${optionalStr}`,
807
+ ` ${coloredKey}${padding} ${description}${optionalStr}`,
798
808
  );
799
809
  }
800
810
  }
@@ -802,30 +812,34 @@ export class CliProvider {
802
812
  // general help
803
813
  this.log.info(this.description || "Available commands:");
804
814
  this.log.info("");
805
- this.log.info("Commands:");
815
+ this.log.info(c.set("WHITE_BOLD", "Commands:"));
806
816
 
807
817
  // Get top-level commands (commands that are not children of other commands)
808
818
  const topLevelCommands = this.getTopLevelCommands();
809
819
  const maxCmdLength = this.getMaxCmdLength(topLevelCommands);
810
820
 
811
- for (const command of topLevelCommands) {
821
+ for (const cmd of topLevelCommands) {
812
822
  // skip root command and hooks in list
813
- if (command.name === "" || command.options.hide) {
823
+ if (cmd.name === "" || cmd.options.hide) {
814
824
  continue;
815
825
  }
816
826
 
817
- const cmdStr = [command.name, ...command.aliases].join(", ");
818
- const argsUsage = command.hasChildren
827
+ const cmdStr = [cmd.name, ...cmd.aliases].join(", ");
828
+ const argsUsage = cmd.hasChildren
819
829
  ? " <command>"
820
- : this.generateArgsUsage(command.options.args);
830
+ : this.generateArgsUsage(cmd.options.args);
821
831
  const fullCmdStr = `${cmdStr}${argsUsage}`;
832
+ const coloredCmd = `${c.set("GREY_LIGHT", cliName)} ${c.set("CYAN", fullCmdStr)}`;
833
+ const padding = " ".repeat(
834
+ Math.max(0, maxCmdLength - fullCmdStr.length),
835
+ );
822
836
  this.log.info(
823
- ` ${cliName} ${fullCmdStr.padEnd(maxCmdLength)} # ${command.options.description ?? ""}`,
837
+ ` ${coloredCmd}${padding} ${cmd.options.description ?? ""}`,
824
838
  );
825
839
  }
826
840
 
827
841
  this.log.info("");
828
- this.log.info("Flags:");
842
+ this.log.info(c.set("WHITE_BOLD", "Flags:"));
829
843
 
830
844
  // In general help, also show root command flags
831
845
  const rootCommand = this.commands.find((cmd) => cmd.name === "");
@@ -851,14 +865,48 @@ export class CliProvider {
851
865
  const flagStr = aliases
852
866
  .map((a) => (a.length === 1 ? `-${a}` : `--${a}`))
853
867
  .join(", ");
854
- this.log.info(
855
- ` ${flagStr.padEnd(maxFlagLength)} # ${description ?? ""}`,
856
- );
868
+ const coloredFlag = c.set("GREY_LIGHT", flagStr);
869
+ const padding = " ".repeat(Math.max(0, maxFlagLength - flagStr.length));
870
+ this.log.info(` ${coloredFlag}${padding} ${description ?? ""}`);
857
871
  }
858
872
  }
859
873
  this.log.info(""); // Newline
860
874
  }
861
875
 
876
+ /**
877
+ * Generate colored args usage string for help display.
878
+ */
879
+ protected generateColoredArgsUsage(schema?: TSchema): string {
880
+ if (!schema) {
881
+ return "";
882
+ }
883
+
884
+ const c = this.color;
885
+
886
+ if (t.schema.isOptional(schema)) {
887
+ const typeName = this.getTypeName(schema);
888
+ const key = "title" in schema ? (schema as any).title : "arg1";
889
+ return ` ${c.set("GREY_DARK", `[${key}${typeName}]`)}`;
890
+ }
891
+
892
+ if (t.schema.isTuple(schema) && schema.items) {
893
+ const items = schema.items;
894
+ const args = items.map((item, index) => {
895
+ const argName = `arg${index + 1}`;
896
+ const typeName = this.getTypeName(item);
897
+ if (t.schema.isOptional(item)) {
898
+ return c.set("GREY_DARK", `[${argName}${typeName}]`);
899
+ }
900
+ return c.set("CYAN", `<${argName}${typeName}>`);
901
+ });
902
+ return ` ${args.join(" ")}`;
903
+ }
904
+
905
+ const typeName = this.getTypeName(schema);
906
+ const key = "title" in schema ? (schema as any).title : "arg1";
907
+ return ` ${c.set("CYAN", `<${key}${typeName}>`)}`;
908
+ }
909
+
862
910
  /**
863
911
  * Get the full command path (e.g., "deploy vercel" for a child command).
864
912
  */
@@ -165,6 +165,13 @@ export class Alepha {
165
165
  ...state.env,
166
166
  ...process.env,
167
167
  };
168
+
169
+ // remove empty env variables
170
+ for (const key in state.env) {
171
+ if (state.env[key] === "") {
172
+ delete (state.env as any)[key];
173
+ }
174
+ }
168
175
  }
169
176
 
170
177
  // force production mode when building with vite
@@ -482,9 +489,17 @@ export class Alepha {
482
489
 
483
490
  const target = this.store.get("alepha.target");
484
491
  if (target) {
492
+ this.modules = [];
485
493
  this.registry = new Map();
486
494
  this.primitiveRegistry = new Map();
495
+ this.pendingInstantiations = [];
496
+ this.substitutions = new Map();
497
+ this.events.clear();
498
+ delete (target as any)[MODULE];
487
499
  this.with(target);
500
+ for (const [key] of this.substitutions.entries()) {
501
+ this.inject(key);
502
+ }
488
503
  }
489
504
 
490
505
  this.locked = true;
@@ -868,6 +883,15 @@ export class Alepha {
868
883
  > = {};
869
884
 
870
885
  for (const [provide, { parents }] of this.registry.entries()) {
886
+ if (provide.name === "") {
887
+ // ignore anonymous classes
888
+ continue;
889
+ }
890
+
891
+ if (Module.is(provide)) {
892
+ continue;
893
+ }
894
+
871
895
  graph[provide.name] = {
872
896
  from: parents.filter((it) => !!it).map((it) => it.name),
873
897
  };
@@ -891,6 +915,27 @@ export class Alepha {
891
915
  return graph;
892
916
  }
893
917
 
918
+ public dump(): AlephaDump {
919
+ const env: Record<string, AlephaDumpEnvVariable> = {};
920
+ for (const [schema] of this.cacheEnv.entries()) {
921
+ const ref = schema as any;
922
+ for (const [key, value] of Object.entries(ref.properties)) {
923
+ const prop = value as any;
924
+ env[key] = {
925
+ description: prop.description,
926
+ default: prop.default,
927
+ required: ref.required?.includes(key) ?? undefined,
928
+ enum: prop.enum ? ([...prop.enum] as Array<string>) : undefined,
929
+ };
930
+ }
931
+ }
932
+
933
+ return {
934
+ env,
935
+ providers: this.graph(),
936
+ };
937
+ }
938
+
894
939
  public services<T extends object>(base: Service<T>): Array<T> {
895
940
  const list: Array<T> = [];
896
941
  for (const [key, value] of this.registry.entries()) {
@@ -995,6 +1040,20 @@ export interface Hook<T extends keyof Hooks = any> {
995
1040
 
996
1041
  // ---------------------------------------------------------------------------------------------------------------------
997
1042
 
1043
+ export interface AlephaDump {
1044
+ env: Record<string, AlephaDumpEnvVariable>;
1045
+ providers: Record<string, { from: string[]; as?: string[]; module?: string }>;
1046
+ }
1047
+
1048
+ export interface AlephaDumpEnvVariable {
1049
+ description: string;
1050
+ default?: string;
1051
+ required?: boolean;
1052
+ enum?: Array<string>;
1053
+ }
1054
+
1055
+ // ---------------------------------------------------------------------------------------------------------------------
1056
+
998
1057
  /**
999
1058
  * This is how we store services in the Alepha container.
1000
1059
  */
@@ -1049,6 +1108,34 @@ export interface State {
1049
1108
 
1050
1109
  /**
1051
1110
  * If defined, the Alepha container will only register this service and its dependencies.
1111
+ *
1112
+ * @example
1113
+ * ```ts
1114
+ * class MigrateCmd {
1115
+ * db = $inject(DatabaseProvider);
1116
+ * alepha = $inject(Alepha);
1117
+ * env = $env(
1118
+ * t.object({
1119
+ * MIGRATE: t.optional(t.boolean()),
1120
+ * }),
1121
+ * );
1122
+ *
1123
+ * constructor() {
1124
+ * if (this.env.MIGRATE) {
1125
+ * this.alepha.set("alepha.target", MigrateCmd);
1126
+ * }
1127
+ * }
1128
+ *
1129
+ * ready = $hook({
1130
+ * on: "ready",
1131
+ * handler: async () => {
1132
+ * if (this.env.MIGRATE) {
1133
+ * await this.db.migrate();
1134
+ * }
1135
+ * },
1136
+ * });
1137
+ * }
1138
+ * ```
1052
1139
  */
1053
1140
  "alepha.target"?: Service;
1054
1141
 
@@ -0,0 +1,22 @@
1
+ import { Alepha } from "alepha";
2
+ import { describe, it } from "vitest";
3
+
4
+ describe("alepha.events.emit", () => {
5
+ it("should handle errors with catch option", async ({ expect }) => {
6
+ const alepha = Alepha.create();
7
+
8
+ alepha.events.on("echo", () => {
9
+ throw new Error("Error in echo");
10
+ });
11
+
12
+ await alepha.start();
13
+
14
+ await expect(() => alepha.events.emit("echo", {})).rejects.toThrowError(
15
+ "Error in echo",
16
+ );
17
+
18
+ expect(await alepha.events.emit("echo", {}, { catch: true })).toEqual(
19
+ undefined,
20
+ );
21
+ });
22
+ });
@@ -0,0 +1,93 @@
1
+ import { $inject, Alepha } from "alepha";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ describe("Alepha#graph", () => {
5
+ it("should generate dependency graph", async () => {
6
+ class A {
7
+ value = "a";
8
+ }
9
+
10
+ class B {
11
+ a = $inject(A);
12
+ }
13
+
14
+ class C {
15
+ a = $inject(A);
16
+ }
17
+
18
+ class M {
19
+ b = $inject(B);
20
+ c = $inject(C);
21
+ }
22
+
23
+ class A3X {
24
+ value = "a3bis";
25
+ }
26
+
27
+ class A3 {
28
+ deps = $inject(A3X);
29
+ value = "a2";
30
+ }
31
+
32
+ class X {
33
+ value = "x";
34
+ }
35
+
36
+ class X2 {
37
+ value = "x2";
38
+ }
39
+
40
+ const a = Alepha.create();
41
+
42
+ a.with({
43
+ provide: A,
44
+ use: A3,
45
+ });
46
+
47
+ a.with({
48
+ provide: X,
49
+ use: X2,
50
+ });
51
+
52
+ a.with(M);
53
+
54
+ await a.start();
55
+
56
+ expect(a.graph()).toEqual({
57
+ B: { from: ["M"] },
58
+ C: { from: ["M"] },
59
+ M: { from: ["Alepha"] },
60
+ A3X: { from: ["A3"] },
61
+ A3: { from: ["B", "C", "Alepha"], as: ["A"] },
62
+ X2: { from: ["Alepha"], as: ["X"] },
63
+ AlsProvider: {
64
+ from: ["StateManager", "Alepha"],
65
+ module: "alepha.core",
66
+ },
67
+ EventManager: {
68
+ from: ["StateManager", "Alepha"],
69
+ module: "alepha.core",
70
+ },
71
+ StateManager: {
72
+ from: ["Alepha"],
73
+ module: "alepha.core",
74
+ },
75
+ Json: {
76
+ from: ["JsonSchemaCodec"],
77
+ module: "alepha.core",
78
+ },
79
+ JsonSchemaCodec: {
80
+ from: ["StateManager", "CodecManager"],
81
+ module: "alepha.core",
82
+ },
83
+ CodecManager: {
84
+ from: ["Alepha"],
85
+ module: "alepha.core",
86
+ },
87
+ SchemaValidator: {
88
+ from: ["CodecManager"],
89
+ module: "alepha.core",
90
+ },
91
+ });
92
+ });
93
+ });
@@ -0,0 +1,41 @@
1
+ import { $inject, Alepha } from "alepha";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ class A {}
5
+
6
+ class B {}
7
+
8
+ class C {
9
+ a = $inject(A);
10
+ }
11
+
12
+ class D {
13
+ alepha = $inject(Alepha);
14
+ constructor() {
15
+ if (this.alepha.has(A)) {
16
+ this.alepha.with(B);
17
+ }
18
+ }
19
+ }
20
+
21
+ describe("Alepha#has", () => {
22
+ it("should check if service is registered", () => {
23
+ const container = new Alepha();
24
+ expect(container.has(A)).toBe(false);
25
+ expect(container.has(B)).toBe(false);
26
+ expect(container.has(C)).toBe(false);
27
+ container.with(C);
28
+ expect(container.has(A)).toBe(true);
29
+ expect(container.has(B)).toBe(false);
30
+ expect(container.has(C)).toBe(true);
31
+ });
32
+
33
+ it("should check service dependencies", () => {
34
+ const container = new Alepha().with(D);
35
+ expect(container.has(D)).toBe(true);
36
+ expect(container.has(B)).toBe(false);
37
+ const container2 = new Alepha().with(D).with(A);
38
+ expect(container2.has(D)).toBe(true);
39
+ expect(container2.has(B)).toBe(false);
40
+ });
41
+ });
@@ -0,0 +1,93 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { Alepha } from "alepha";
3
+ import { describe, expect, it } from "vitest";
4
+
5
+ describe("Alepha#inject", () => {
6
+ it("should handle transient lifetime", ({ expect }) => {
7
+ class Logger {
8
+ id = randomUUID();
9
+ }
10
+
11
+ const alepha = new Alepha();
12
+
13
+ expect(alepha.inject(Logger, { lifetime: "transient" }).id).not.toBe(
14
+ alepha.inject(Logger, { lifetime: "transient" }).id,
15
+ );
16
+
17
+ const log = alepha.inject(Logger);
18
+
19
+ expect(log.id).toBe(alepha.inject(Logger).id);
20
+
21
+ expect(alepha.inject(Logger, { lifetime: "transient" }).id).not.toBe(
22
+ log.id,
23
+ );
24
+ });
25
+
26
+ it("should handle transient lifetime with substitution", ({ expect }) => {
27
+ class BaseLogger {
28
+ print(msg: string): string {
29
+ return msg;
30
+ }
31
+ }
32
+
33
+ class EmojiLogger extends BaseLogger {
34
+ print(msg: string): string {
35
+ return `${msg}😊`;
36
+ }
37
+ }
38
+
39
+ const alepha = new Alepha().with({
40
+ provide: BaseLogger,
41
+ use: EmojiLogger,
42
+ });
43
+
44
+ const log = alepha.inject(BaseLogger, { lifetime: "transient" });
45
+
46
+ expect(log).toBeInstanceOf(EmojiLogger);
47
+ expect(log.print("Hello")).toBe("Hello😊");
48
+
49
+ expect(alepha.has(BaseLogger)).toBe(true);
50
+
51
+ // no trace of EmojiLogger in Alepha
52
+ expect(alepha.has(EmojiLogger)).toBe(false);
53
+ expect(alepha.has(BaseLogger, { inSubstitutions: false })).toBe(false);
54
+ });
55
+
56
+ it("should handle scoped lifetime", ({ expect }) => {
57
+ class Request {
58
+ id = randomUUID();
59
+ }
60
+
61
+ const alepha = new Alepha();
62
+
63
+ const base = alepha.inject(Request, { lifetime: "scoped" });
64
+
65
+ expect(alepha.inject(Request, { lifetime: "scoped" }).id).toBe(base.id);
66
+
67
+ alepha.context.run(() => {
68
+ expect(alepha.inject(Request, { lifetime: "scoped" }).id).not.toBe(
69
+ base.id,
70
+ );
71
+ expect(alepha.inject(Request, { lifetime: "scoped" }).id).toBe(
72
+ alepha.inject(Request, { lifetime: "scoped" }).id,
73
+ );
74
+ });
75
+ });
76
+
77
+ it("should pass constructor args correctly", () => {
78
+ class Logger {
79
+ constructor(public a: string) {}
80
+ }
81
+
82
+ const alepha = new Alepha();
83
+
84
+ expect(alepha.inject(Logger, { args: ["a"] }).a).toBe("a");
85
+ expect(alepha.inject(Logger).a).toBe("a");
86
+ });
87
+
88
+ it("should inject Alepha instance itself", () => {
89
+ const alepha = new Alepha();
90
+
91
+ expect(alepha.inject(Alepha)).toBe(alepha);
92
+ });
93
+ });
@@ -0,0 +1,81 @@
1
+ import { $inject, Alepha, TooLateSubstitutionError } from "alepha";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ describe("Alepha#with", () => {
5
+ it("should allow substitution", () => {
6
+ class A {
7
+ value = "a";
8
+ }
9
+
10
+ class M {
11
+ a = $inject(A);
12
+ }
13
+
14
+ expect(
15
+ Alepha.create()
16
+ .with({
17
+ provide: A,
18
+ use: class extends A {
19
+ value = "z";
20
+ },
21
+ })
22
+ .inject(M).a.value,
23
+ ).toBe("z");
24
+ });
25
+
26
+ class A {
27
+ a = "a";
28
+ }
29
+
30
+ class B {
31
+ a = "b";
32
+ }
33
+
34
+ class C {
35
+ a = "c";
36
+ }
37
+
38
+ class M {
39
+ a = $inject(A);
40
+ }
41
+
42
+ it("should allow optional substitution", () => {
43
+ const T1 = Alepha.create().with(M);
44
+ expect(T1.inject(M).a.a).toBe("a");
45
+
46
+ const T2 = Alepha.create().with({
47
+ provide: A,
48
+ use: B,
49
+ });
50
+ expect(T2.inject(M).a.a).toBe("b");
51
+
52
+ const T3 = Alepha.create();
53
+ T3.with({
54
+ provide: A,
55
+ use: C,
56
+ optional: true,
57
+ });
58
+ expect(T3.inject(M).a.a).toBe("c");
59
+
60
+ const T4 = Alepha.create();
61
+ T4.with(M);
62
+ T4.with({
63
+ provide: A,
64
+ use: C,
65
+ optional: true,
66
+ });
67
+ expect(T1.inject(M).a.a).toBe("a");
68
+ });
69
+
70
+ it("should reject substitution of already registered service", () => {
71
+ const T5 = Alepha.create();
72
+ T5.with(M);
73
+ expect(() =>
74
+ T5.with({
75
+ provide: A,
76
+ use: C,
77
+ optional: false, // should throw, because the default is already set
78
+ }),
79
+ ).toThrow(TooLateSubstitutionError);
80
+ });
81
+ });