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
@@ -0,0 +1,256 @@
1
+ import { Alepha, t } from "alepha";
2
+ import { describe, expect, it } from "vitest";
3
+ import { DbEntityNotFoundError } from "../errors/DbEntityNotFoundError.ts";
4
+ import { $entity, $repository } from "../index.ts";
5
+ import { pg } from "../providers/DatabaseTypeProvider.ts";
6
+
7
+ // Test entity
8
+ const userEntity = $entity({
9
+ name: "users",
10
+ schema: t.object({
11
+ id: pg.primaryKey(),
12
+ name: t.string(),
13
+ email: t.email(),
14
+ active: t.boolean(),
15
+ }),
16
+ });
17
+
18
+ const postEntity = $entity({
19
+ name: "posts",
20
+ schema: t.object({
21
+ id: pg.primaryKey(),
22
+ userId: t.integer(),
23
+ title: t.string(),
24
+ content: t.text(),
25
+ }),
26
+ });
27
+
28
+ class TestApp {
29
+ users = $repository(userEntity);
30
+ posts = $repository(postEntity);
31
+ }
32
+
33
+ /**
34
+ * Shared test function that runs on both PostgreSQL and SQLite
35
+ */
36
+ const testDeleteReturning = async (alepha: Alepha) => {
37
+ const app = alepha.inject(TestApp);
38
+ await alepha.start();
39
+
40
+ // Test 1: deleteById returns the deleted ID
41
+ const user1 = await app.users.create({
42
+ name: "Alice",
43
+ email: "alice@example.com",
44
+ active: true,
45
+ });
46
+
47
+ const deletedIds = await app.users.deleteById(user1.id);
48
+ expect(deletedIds).toHaveLength(1);
49
+ expect(deletedIds[0]).toBe(user1.id);
50
+
51
+ // Verify the user is deleted
52
+ await expect(app.users.findById(user1.id)).rejects.toThrow(
53
+ DbEntityNotFoundError,
54
+ );
55
+
56
+ // Test 2: deleteById throws error when entity not found
57
+ await expect(app.users.deleteById(999999)).rejects.toThrow(
58
+ DbEntityNotFoundError,
59
+ );
60
+
61
+ // Test 3: deleteMany returns array of deleted IDs
62
+ const users = await Promise.all([
63
+ app.users.create({ name: "Bob", email: "bob@example.com", active: true }),
64
+ app.users.create({
65
+ name: "Charlie",
66
+ email: "charlie@example.com",
67
+ active: false,
68
+ }),
69
+ app.users.create({
70
+ name: "David",
71
+ email: "david@example.com",
72
+ active: true,
73
+ }),
74
+ ]);
75
+
76
+ const activeUserIds = users
77
+ .filter((u) => u.active)
78
+ .map((u) => u.id)
79
+ .sort((a, b) => a - b);
80
+
81
+ const deletedActiveIds = await app.users.deleteMany({
82
+ active: { eq: true },
83
+ });
84
+
85
+ expect(deletedActiveIds).toHaveLength(2);
86
+ expect(deletedActiveIds.sort((a, b) => Number(a) - Number(b))).toEqual(
87
+ activeUserIds,
88
+ );
89
+
90
+ // Verify only inactive user remains
91
+ const remaining = await app.users.findMany({});
92
+ expect(remaining).toHaveLength(1);
93
+ expect(remaining[0].name).toBe("Charlie");
94
+
95
+ // Test 4: deleteOne returns array with single ID
96
+ const deletedOneIds = await app.users.deleteOne({
97
+ email: { eq: "charlie@example.com" },
98
+ });
99
+ expect(deletedOneIds).toHaveLength(1);
100
+ expect(deletedOneIds[0]).toBe(users[1].id);
101
+
102
+ // Test 5: clear returns all deleted IDs
103
+ const moreUsers = await Promise.all([
104
+ app.users.create({ name: "Eve", email: "eve@example.com", active: true }),
105
+ app.users.create({
106
+ name: "Frank",
107
+ email: "frank@example.com",
108
+ active: false,
109
+ }),
110
+ app.users.create({
111
+ name: "Grace",
112
+ email: "grace@example.com",
113
+ active: true,
114
+ }),
115
+ ]);
116
+
117
+ const allIds = moreUsers.map((u) => u.id).sort((a, b) => a - b);
118
+ const clearedIds = await app.users.clear();
119
+
120
+ expect(clearedIds).toHaveLength(3);
121
+ expect(clearedIds.sort((a, b) => Number(a) - Number(b))).toEqual(allIds);
122
+
123
+ // Verify table is empty
124
+ expect(await app.users.count()).toBe(0);
125
+
126
+ // Test 6: destroy returns the deleted ID
127
+ const user = await app.users.create({
128
+ name: "Helen",
129
+ email: "helen@example.com",
130
+ active: true,
131
+ });
132
+
133
+ const destroyedIds = await app.users.destroy(user);
134
+ expect(destroyedIds).toHaveLength(1);
135
+ expect(destroyedIds[0]).toBe(user.id);
136
+
137
+ // Test 7: deleteMany with no matches returns empty array
138
+ const emptyResult = await app.users.deleteMany({
139
+ name: { eq: "NonExistent" },
140
+ });
141
+ expect(emptyResult).toHaveLength(0);
142
+
143
+ // Test 8: Test with composite operations
144
+ const posts = await Promise.all([
145
+ app.posts.create({
146
+ userId: 1,
147
+ title: "Post 1",
148
+ content: "Content 1",
149
+ }),
150
+ app.posts.create({
151
+ userId: 1,
152
+ title: "Post 2",
153
+ content: "Content 2",
154
+ }),
155
+ app.posts.create({
156
+ userId: 2,
157
+ title: "Post 3",
158
+ content: "Content 3",
159
+ }),
160
+ ]);
161
+
162
+ const deletedPostIds = await app.posts.deleteMany({
163
+ userId: { eq: 1 },
164
+ });
165
+
166
+ expect(deletedPostIds).toHaveLength(2);
167
+ const sortedDeletedIds = deletedPostIds.sort((a, b) => Number(a) - Number(b));
168
+ const expectedIds = [posts[0].id, posts[1].id].sort((a, b) => a - b);
169
+ expect(sortedDeletedIds).toEqual(expectedIds);
170
+
171
+ // Clean up
172
+ await app.posts.clear({ force: true });
173
+ await app.users.clear({ force: true });
174
+ };
175
+
176
+ describe("Delete methods with returning IDs", () => {
177
+ it("should return deleted IDs in PostgreSQL", async () => {
178
+ await testDeleteReturning(Alepha.create());
179
+ });
180
+
181
+ it("should return deleted IDs in SQLite", async () => {
182
+ await testDeleteReturning(
183
+ Alepha.create({
184
+ env: {
185
+ DATABASE_URL: "sqlite://:memory:",
186
+ },
187
+ }),
188
+ );
189
+ });
190
+
191
+ it("should handle soft delete with returning IDs", async () => {
192
+ // Test entity with soft delete
193
+ const softEntity = $entity({
194
+ name: "soft_delete_items",
195
+ schema: t.object({
196
+ id: pg.primaryKey(),
197
+ name: t.string(),
198
+ deletedAt: pg.deletedAt(),
199
+ }),
200
+ });
201
+
202
+ class SoftDeleteApp {
203
+ items = $repository(softEntity);
204
+ }
205
+
206
+ const alepha = Alepha.create();
207
+ const app = alepha.inject(SoftDeleteApp);
208
+ await alepha.start();
209
+
210
+ // Create test items
211
+ const item1 = await app.items.create({ name: "Item 1" });
212
+ const item2 = await app.items.create({ name: "Item 2" });
213
+ const item3 = await app.items.create({ name: "Item 3" });
214
+
215
+ // Test soft delete by ID - this should trigger soft delete
216
+ const softDeletedId = await app.items.deleteById(item1.id);
217
+ expect(softDeletedId).toHaveLength(1);
218
+ expect(softDeletedId[0]).toBe(item1.id);
219
+
220
+ // Item should still exist but be soft deleted
221
+ const allAfterSoftDelete = await app.items.findMany({}, { force: true });
222
+ expect(allAfterSoftDelete).toHaveLength(3);
223
+
224
+ const activeAfterSoftDelete = await app.items.findMany({});
225
+ expect(activeAfterSoftDelete).toHaveLength(2);
226
+ expect(activeAfterSoftDelete.map((i) => i.name).sort()).toEqual([
227
+ "Item 2",
228
+ "Item 3",
229
+ ]);
230
+
231
+ // Test soft delete multiple items
232
+ const softDeletedIds = await app.items.deleteMany({
233
+ name: { inArray: ["Item 2", "Item 3"] },
234
+ });
235
+
236
+ expect(softDeletedIds).toHaveLength(2);
237
+ const sortedIds = softDeletedIds.sort((a, b) => Number(a) - Number(b));
238
+ const expectedIds = [item2.id, item3.id].sort((a, b) => a - b);
239
+ expect(sortedIds).toEqual(expectedIds);
240
+
241
+ // All items should be soft deleted now
242
+ const allItems = await app.items.findMany({}, { force: true });
243
+ expect(allItems).toHaveLength(3);
244
+
245
+ const activeItems = await app.items.findMany({});
246
+ expect(activeItems).toHaveLength(0);
247
+
248
+ // Force delete returns IDs
249
+ const forceDeletedIds = await app.items.clear({ force: true });
250
+ expect(forceDeletedIds).toHaveLength(3);
251
+
252
+ // Table should be empty now
253
+ const finalItems = await app.items.findMany({}, { force: true });
254
+ expect(finalItems).toHaveLength(0);
255
+ });
256
+ });
@@ -0,0 +1,80 @@
1
+ import { Alepha, t } from "alepha";
2
+ import { DateTimeProvider } from "alepha/datetime";
3
+ import { describe, it } from "vitest";
4
+ import { $entity, $repository, DbEntityNotFoundError, pg } from "../index.ts";
5
+
6
+ describe("deletedAt", () => {
7
+ const entity = $entity({
8
+ name: "test_entity",
9
+ schema: t.object({
10
+ id: pg.primaryKey(),
11
+ deletedAt: pg.deletedAt(),
12
+ name: t.optional(t.text()),
13
+ }),
14
+ });
15
+
16
+ class App {
17
+ repository = $repository(entity);
18
+ }
19
+
20
+ const setup = async () => {
21
+ const alepha = Alepha.create();
22
+ const app = alepha.inject(App);
23
+ await alepha.start();
24
+ const now = alepha.inject(DateTimeProvider).pause();
25
+ return {
26
+ repository: app.repository,
27
+ now: now.toISOString(),
28
+ };
29
+ };
30
+
31
+ it("should update instead of delete", async ({ expect }) => {
32
+ const { repository, now } = await setup();
33
+
34
+ await repository.createMany([{}, {}]);
35
+ const entities = await repository.findMany();
36
+ expect(entities.length).toEqual(2);
37
+ expect(await repository.count()).toEqual(2);
38
+
39
+ await repository.deleteById(entities[0].id);
40
+ expect(await repository.count()).toEqual(1);
41
+ expect(await repository.findMany()).toEqual([{ id: entities[1].id }]);
42
+
43
+ expect(await repository.count({}, { force: true })).toEqual(2);
44
+ expect(await repository.findMany({}, { force: true })).toEqual([
45
+ { id: entities[1].id },
46
+ { id: entities[0].id, deletedAt: now },
47
+ ]);
48
+ });
49
+
50
+ it("should not update if deletedAt is already set", async ({ expect }) => {
51
+ const { repository, now } = await setup();
52
+ await repository.createMany([{}, {}]);
53
+ const entities = await repository.findMany();
54
+ const it = entities[0];
55
+ await repository.destroy(it);
56
+ it.name = "Toby";
57
+ await expect(() => repository.save(it)).rejects.toThrow(
58
+ DbEntityNotFoundError,
59
+ );
60
+ await repository.save(it, { force: true });
61
+ expect(await repository.findById(it.id, { force: true })).toEqual({
62
+ id: it.id,
63
+ deletedAt: now,
64
+ name: "Toby",
65
+ });
66
+ });
67
+
68
+ it("should force delete", async ({ expect }) => {
69
+ const { repository } = await setup();
70
+ await repository.createMany([{}, {}]);
71
+ const entities = await repository.findMany();
72
+ const it = entities[0];
73
+ await repository.destroy(it);
74
+ expect(await repository.count()).toEqual(1);
75
+ expect(await repository.count({}, { force: true })).toEqual(2);
76
+ await repository.destroy(it, { force: true });
77
+ expect(await repository.count()).toEqual(1);
78
+ expect(await repository.count({}, { force: true })).toEqual(1);
79
+ });
80
+ });
@@ -0,0 +1,315 @@
1
+ import { Alepha, t } from "alepha";
2
+ import { describe, expect, it } from "vitest";
3
+ import { $entity, $repository, DrizzleKitProvider, pg } from "../index.ts";
4
+
5
+ // Test 1: Basic enum using t.enum (should map to TEXT column)
6
+ const textEnumEntity = $entity({
7
+ name: "text_enum_test",
8
+ schema: t.object({
9
+ id: pg.primaryKey(),
10
+ status: t.enum(["pending", "active", "archived"]),
11
+ role: t.enum(["user", "admin", "moderator"]),
12
+ }),
13
+ });
14
+
15
+ // Test 2: Basic enum using pg.enum (should create real PG ENUM type)
16
+ const pgEnumEntity = $entity({
17
+ name: "pg_enum_test",
18
+ schema: t.object({
19
+ id: pg.primaryKey(),
20
+ status: pg.enum(["draft", "published", "deleted"]),
21
+ priority: pg.enum(["low", "medium", "high"]),
22
+ }),
23
+ });
24
+
25
+ // Test 3: Mixed t.enum and pg.enum in the same table
26
+ const mixedEnumEntity = $entity({
27
+ name: "mixed_enum_test",
28
+ schema: t.object({
29
+ id: pg.primaryKey(),
30
+ textStatus: t.enum(["open", "closed"]),
31
+ pgStatus: pg.enum(["new", "in_progress", "done"]),
32
+ }),
33
+ });
34
+
35
+ // Test 4: Shared enum with custom name across two tables
36
+ const sharedEnumEntity1 = $entity({
37
+ name: "shared_enum_test_1",
38
+ schema: t.object({
39
+ id: pg.primaryKey(),
40
+ status: pg.enum(["enabled", "disabled"], { name: "shared_status_enum" }),
41
+ }),
42
+ });
43
+
44
+ const sharedEnumEntity2 = $entity({
45
+ name: "shared_enum_test_2",
46
+ schema: t.object({
47
+ id: pg.primaryKey(),
48
+ status: pg.enum(["enabled", "disabled"], { name: "shared_status_enum" }),
49
+ }),
50
+ });
51
+
52
+ // Test 5: Conflicting enum - same name but different values (should throw error)
53
+ const conflictEnumEntity1 = $entity({
54
+ name: "conflict_enum_test_1",
55
+ schema: t.object({
56
+ id: pg.primaryKey(),
57
+ status: pg.enum(["a", "b", "c"], { name: "conflict_status_enum" }),
58
+ }),
59
+ });
60
+
61
+ const conflictEnumEntity2 = $entity({
62
+ name: "conflict_enum_test_2",
63
+ schema: t.object({
64
+ id: pg.primaryKey(),
65
+ status: pg.enum(["a", "b", "d"], { name: "conflict_status_enum" }), // Different value!
66
+ }),
67
+ });
68
+
69
+ describe("enums - t.enum (TEXT column)", () => {
70
+ it("should create TEXT columns for t.enum fields", async () => {
71
+ const alepha = Alepha.create();
72
+
73
+ class App {
74
+ repository = $repository(textEnumEntity);
75
+ }
76
+
77
+ const app = alepha.inject(App);
78
+ const drizzleKit = alepha.inject(DrizzleKitProvider);
79
+
80
+ await alepha.start();
81
+
82
+ // Check generated SQL
83
+ const { statements: sql } = await drizzleKit.generateMigration(
84
+ app.repository.provider,
85
+ );
86
+
87
+ expect(sql).toContainEqual(expect.stringContaining("CREATE TABLE"));
88
+ expect(sql).toContainEqual(expect.stringContaining("text_enum_test"));
89
+ // t.enum should map to TEXT, not a real ENUM type
90
+ expect(sql.some((s) => s.includes('"status" text'))).toBe(true);
91
+ expect(sql.some((s) => s.includes('"role" text'))).toBe(true);
92
+ });
93
+
94
+ it("should allow inserting and querying with t.enum values", async () => {
95
+ const alepha = Alepha.create();
96
+
97
+ class App {
98
+ repository = $repository(textEnumEntity);
99
+ }
100
+
101
+ const app = alepha.inject(App);
102
+ await alepha.start();
103
+
104
+ const created = await app.repository.create({
105
+ status: "pending",
106
+ role: "user",
107
+ });
108
+
109
+ expect(created.status).toBe("pending");
110
+ expect(created.role).toBe("user");
111
+ expect(created.id).toBeDefined();
112
+
113
+ const found = await app.repository.findOne({ where: { id: created.id } });
114
+ expect(found?.status).toBe("pending");
115
+ expect(found?.role).toBe("user");
116
+ });
117
+ });
118
+
119
+ describe("enums - pg.enum (real PG ENUM type)", () => {
120
+ it("should create real PostgreSQL ENUM types for pg.enum fields", async () => {
121
+ const alepha = Alepha.create();
122
+
123
+ class App {
124
+ repository = $repository(pgEnumEntity);
125
+ }
126
+
127
+ const app = alepha.inject(App);
128
+ const drizzleKit = alepha.inject(DrizzleKitProvider);
129
+
130
+ await alepha.start();
131
+
132
+ // Check generated SQL
133
+ const { statements: sql } = await drizzleKit.generateMigration(
134
+ app.repository.provider,
135
+ );
136
+
137
+ expect(sql).toContainEqual(expect.stringContaining("CREATE TABLE"));
138
+ expect(sql).toContainEqual(expect.stringContaining("pg_enum_test"));
139
+ // pg.enum should create real ENUM types
140
+ expect(
141
+ sql.some((s) => s.includes("CREATE TYPE") || s.includes("DO $$ BEGIN")),
142
+ ).toBe(true);
143
+ });
144
+
145
+ it("should allow inserting and querying with pg.enum values", async () => {
146
+ const alepha = Alepha.create();
147
+
148
+ class App {
149
+ repository = $repository(pgEnumEntity);
150
+ }
151
+
152
+ const app = alepha.inject(App);
153
+ await alepha.start();
154
+
155
+ const created = await app.repository.create({
156
+ status: "draft",
157
+ priority: "high",
158
+ });
159
+
160
+ expect(created.status).toBe("draft");
161
+ expect(created.priority).toBe("high");
162
+ expect(created.id).toBeDefined();
163
+
164
+ const found = await app.repository.findOne({ where: { id: created.id } });
165
+ expect(found?.status).toBe("draft");
166
+ expect(found?.priority).toBe("high");
167
+ });
168
+ });
169
+
170
+ describe("enums - mixed t.enum and pg.enum in same table", () => {
171
+ it("should handle both TEXT and PG ENUM types in the same table", async () => {
172
+ const alepha = Alepha.create();
173
+
174
+ class App {
175
+ repository = $repository(mixedEnumEntity);
176
+ }
177
+
178
+ const app = alepha.inject(App);
179
+ const drizzleKit = alepha.inject(DrizzleKitProvider);
180
+
181
+ await alepha.start();
182
+
183
+ // Check generated SQL
184
+ const { statements: sql } = await drizzleKit.generateMigration(
185
+ app.repository.provider,
186
+ );
187
+
188
+ expect(sql).toContainEqual(expect.stringContaining("CREATE TABLE"));
189
+ expect(sql).toContainEqual(expect.stringContaining("mixed_enum_test"));
190
+ // textStatus should be TEXT
191
+ expect(
192
+ sql.some(
193
+ (s) =>
194
+ s.includes('"text_status" text') || s.includes('"textStatus" text'),
195
+ ),
196
+ ).toBe(true);
197
+ // pgStatus should create an ENUM type
198
+ expect(
199
+ sql.some((s) => s.includes("CREATE TYPE") || s.includes("DO $$ BEGIN")),
200
+ ).toBe(true);
201
+ });
202
+
203
+ it("should allow inserting and querying with mixed enum values", async () => {
204
+ const alepha = Alepha.create();
205
+
206
+ class App {
207
+ repository = $repository(mixedEnumEntity);
208
+ }
209
+
210
+ const app = alepha.inject(App);
211
+ await alepha.start();
212
+
213
+ const created = await app.repository.create({
214
+ textStatus: "open",
215
+ pgStatus: "new",
216
+ });
217
+
218
+ expect(created.textStatus).toBe("open");
219
+ expect(created.pgStatus).toBe("new");
220
+ expect(created.id).toBeDefined();
221
+
222
+ const found = await app.repository.findOne({ where: { id: created.id } });
223
+ expect(found?.textStatus).toBe("open");
224
+ expect(found?.pgStatus).toBe("new");
225
+ });
226
+ });
227
+
228
+ describe("enums - shared enum with custom name across tables", () => {
229
+ it("should reuse the same PG ENUM type across multiple tables", async () => {
230
+ const alepha = Alepha.create();
231
+
232
+ class App {
233
+ repository1 = $repository(sharedEnumEntity1);
234
+ repository2 = $repository(sharedEnumEntity2);
235
+ }
236
+
237
+ const app = alepha.inject(App);
238
+ const drizzleKit = alepha.inject(DrizzleKitProvider);
239
+
240
+ await alepha.start();
241
+
242
+ // Check generated SQL
243
+ const { statements: sql } = await drizzleKit.generateMigration(
244
+ app.repository1.provider,
245
+ );
246
+
247
+ // Count how many times the shared_status_enum is created
248
+ // It should only be created once, even though it's used in two tables
249
+ const enumCreations = sql.filter(
250
+ (s) =>
251
+ s.includes("shared_status_enum") &&
252
+ (s.includes("CREATE TYPE") || s.includes("DO $$ BEGIN")),
253
+ );
254
+
255
+ // Should only create the enum type once
256
+ expect(enumCreations.length).toBeLessThanOrEqual(1);
257
+
258
+ // Both tables should exist
259
+ expect(sql.some((s) => s.includes("shared_enum_test_1"))).toBe(true);
260
+ expect(sql.some((s) => s.includes("shared_enum_test_2"))).toBe(true);
261
+ });
262
+
263
+ it("should allow both tables to use the shared enum values", async () => {
264
+ const alepha = Alepha.create();
265
+
266
+ class App {
267
+ repository1 = $repository(sharedEnumEntity1);
268
+ repository2 = $repository(sharedEnumEntity2);
269
+ }
270
+
271
+ const app = alepha.inject(App);
272
+ await alepha.start();
273
+
274
+ const created1 = await app.repository1.create({
275
+ status: "enabled",
276
+ });
277
+
278
+ const created2 = await app.repository2.create({
279
+ status: "disabled",
280
+ });
281
+
282
+ expect(created1.status).toBe("enabled");
283
+ expect(created2.status).toBe("disabled");
284
+
285
+ const found1 = await app.repository1.findOne({
286
+ where: { id: created1.id },
287
+ });
288
+ const found2 = await app.repository2.findOne({
289
+ where: { id: created2.id },
290
+ });
291
+
292
+ expect(found1?.status).toBe("enabled");
293
+ expect(found2?.status).toBe("disabled");
294
+ });
295
+ });
296
+
297
+ describe("enums - conflict detection with different values", () => {
298
+ it("should throw error when same enum name has different values", async () => {
299
+ const alepha = Alepha.create();
300
+
301
+ const load = async () => {
302
+ return alepha.with(() => ({
303
+ r1: $repository(conflictEnumEntity1),
304
+ r2: $repository(conflictEnumEntity2),
305
+ }));
306
+ };
307
+
308
+ expect(() =>
309
+ alepha.with(() => ({
310
+ r1: $repository(conflictEnumEntity1),
311
+ r2: $repository(conflictEnumEntity2),
312
+ })),
313
+ ).toThrow(/Enum name conflict/i);
314
+ });
315
+ });