alepha 0.20.1 → 0.20.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 (393) hide show
  1. package/README.md +0 -1
  2. package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
  3. package/assets/swagger-ui/swagger-ui.css +1 -1
  4. package/dist/api/audits/index.browser.js +49 -0
  5. package/dist/api/audits/index.browser.js.map +1 -1
  6. package/dist/api/audits/index.d.ts.map +1 -1
  7. package/dist/api/audits/index.js +49 -0
  8. package/dist/api/audits/index.js.map +1 -1
  9. package/dist/api/files/index.d.ts.map +1 -1
  10. package/dist/api/files/index.js +2 -1
  11. package/dist/api/files/index.js.map +1 -1
  12. package/dist/api/jobs/index.browser.js +64 -148
  13. package/dist/api/jobs/index.browser.js.map +1 -1
  14. package/dist/api/jobs/index.d.ts +339 -600
  15. package/dist/api/jobs/index.d.ts.map +1 -1
  16. package/dist/api/jobs/index.js +605 -1012
  17. package/dist/api/jobs/index.js.map +1 -1
  18. package/dist/api/keys/index.js.map +1 -1
  19. package/dist/api/notifications/index.d.ts +79 -27
  20. package/dist/api/notifications/index.d.ts.map +1 -1
  21. package/dist/api/notifications/index.js +90 -23
  22. package/dist/api/notifications/index.js.map +1 -1
  23. package/dist/api/organizations/index.d.ts.map +1 -1
  24. package/dist/api/parameters/index.browser.js +37 -0
  25. package/dist/api/parameters/index.browser.js.map +1 -1
  26. package/dist/api/parameters/index.d.ts +4 -65
  27. package/dist/api/parameters/index.d.ts.map +1 -1
  28. package/dist/api/parameters/index.js +37 -0
  29. package/dist/api/parameters/index.js.map +1 -1
  30. package/dist/api/payments/index.d.ts +2 -1
  31. package/dist/api/payments/index.d.ts.map +1 -1
  32. package/dist/api/payments/index.js +4 -2
  33. package/dist/api/payments/index.js.map +1 -1
  34. package/dist/api/users/index.d.ts +225 -5199
  35. package/dist/api/users/index.d.ts.map +1 -1
  36. package/dist/api/users/index.js +15 -11
  37. package/dist/api/users/index.js.map +1 -1
  38. package/dist/api/verifications/index.d.ts.map +1 -1
  39. package/dist/api/verifications/index.js +4 -2
  40. package/dist/api/verifications/index.js.map +1 -1
  41. package/dist/bucket/index.js +5 -1
  42. package/dist/bucket/index.js.map +1 -1
  43. package/dist/bucket/index.workerd.js +5 -1
  44. package/dist/bucket/index.workerd.js.map +1 -1
  45. package/dist/cache/core/index.js.map +1 -1
  46. package/dist/cache/core/index.workerd.js.map +1 -1
  47. package/dist/captcha/index.js.map +1 -1
  48. package/dist/cli/core/index.d.ts +225 -11681
  49. package/dist/cli/core/index.d.ts.map +1 -1
  50. package/dist/cli/core/index.js +732 -257
  51. package/dist/cli/core/index.js.map +1 -1
  52. package/dist/cli/devtools/index.js +7 -1
  53. package/dist/cli/devtools/index.js.map +1 -1
  54. package/dist/cli/platform/index.d.ts +65 -63
  55. package/dist/cli/platform/index.d.ts.map +1 -1
  56. package/dist/cli/platform/index.js +140 -27
  57. package/dist/cli/platform/index.js.map +1 -1
  58. package/dist/cli/vendor/index.js +15 -0
  59. package/dist/cli/vendor/index.js.map +1 -1
  60. package/dist/command/index.d.ts +1 -1
  61. package/dist/command/index.js +1 -1
  62. package/dist/command/index.js.map +1 -1
  63. package/dist/core/index.browser.js +6 -0
  64. package/dist/core/index.browser.js.map +1 -1
  65. package/dist/core/index.d.ts +8 -8
  66. package/dist/core/index.d.ts.map +1 -1
  67. package/dist/core/index.js +6 -0
  68. package/dist/core/index.js.map +1 -1
  69. package/dist/core/index.native.js +6 -0
  70. package/dist/core/index.native.js.map +1 -1
  71. package/dist/core/index.workerd.js +6 -0
  72. package/dist/core/index.workerd.js.map +1 -1
  73. package/dist/crypto/index.js.map +1 -1
  74. package/dist/datetime/index.js.map +1 -1
  75. package/dist/email/core/index.js.map +1 -1
  76. package/dist/email/smtp/index.js +2 -10522
  77. package/dist/email/smtp/index.js.map +1 -1
  78. package/dist/fake/index.d.ts +4 -8085
  79. package/dist/fake/index.d.ts.map +1 -1
  80. package/dist/fake/index.js +3 -33554
  81. package/dist/fake/index.js.map +1 -1
  82. package/dist/lock/core/index.js.map +1 -1
  83. package/dist/lock/redis/index.js.map +1 -1
  84. package/dist/logger/index.js +32 -1
  85. package/dist/logger/index.js.map +1 -1
  86. package/dist/mcp/index.js +5 -1
  87. package/dist/mcp/index.js.map +1 -1
  88. package/dist/orm/core/index.browser.js +1 -361
  89. package/dist/orm/core/index.browser.js.map +1 -1
  90. package/dist/orm/core/index.bun.js +14 -406
  91. package/dist/orm/core/index.bun.js.map +1 -1
  92. package/dist/orm/core/index.d.ts +96 -5117
  93. package/dist/orm/core/index.d.ts.map +1 -1
  94. package/dist/orm/core/index.js +23 -419
  95. package/dist/orm/core/index.js.map +1 -1
  96. package/dist/orm/postgres/index.bun.js +17 -20
  97. package/dist/orm/postgres/index.bun.js.map +1 -1
  98. package/dist/orm/postgres/index.d.ts +2 -613
  99. package/dist/orm/postgres/index.d.ts.map +1 -1
  100. package/dist/orm/postgres/index.js +17 -20
  101. package/dist/orm/postgres/index.js.map +1 -1
  102. package/dist/react/core/index.js.map +1 -1
  103. package/dist/react/form/index.d.ts +60 -1
  104. package/dist/react/form/index.d.ts.map +1 -1
  105. package/dist/react/form/index.js +86 -1
  106. package/dist/react/form/index.js.map +1 -1
  107. package/dist/react/head/index.browser.js +16 -1
  108. package/dist/react/head/index.browser.js.map +1 -1
  109. package/dist/react/head/index.d.ts +6 -0
  110. package/dist/react/head/index.d.ts.map +1 -1
  111. package/dist/react/head/index.js +16 -1
  112. package/dist/react/head/index.js.map +1 -1
  113. package/dist/react/i18n/index.js.map +1 -1
  114. package/dist/react/intro/index.js +22 -17
  115. package/dist/react/intro/index.js.map +1 -1
  116. package/dist/react/router/index.browser.js +78 -12
  117. package/dist/react/router/index.browser.js.map +1 -1
  118. package/dist/react/router/index.d.ts +57 -13
  119. package/dist/react/router/index.d.ts.map +1 -1
  120. package/dist/react/router/index.js +102 -14
  121. package/dist/react/router/index.js.map +1 -1
  122. package/dist/react/testing/index.d.ts +1 -411
  123. package/dist/react/testing/index.d.ts.map +1 -1
  124. package/dist/react/testing/index.js +13 -12293
  125. package/dist/react/testing/index.js.map +1 -1
  126. package/dist/react/ui/index.d.ts +124 -0
  127. package/dist/react/ui/index.d.ts.map +1 -0
  128. package/dist/react/ui/index.js +209 -0
  129. package/dist/react/ui/index.js.map +1 -0
  130. package/dist/react/websocket/index.js.map +1 -1
  131. package/dist/redis/index.js.map +1 -1
  132. package/dist/router/index.d.ts +13 -13
  133. package/dist/router/index.d.ts.map +1 -1
  134. package/dist/router/index.js +45 -32
  135. package/dist/router/index.js.map +1 -1
  136. package/dist/scheduler/index.d.ts +1 -83
  137. package/dist/scheduler/index.d.ts.map +1 -1
  138. package/dist/scheduler/index.js +2 -391
  139. package/dist/scheduler/index.js.map +1 -1
  140. package/dist/scheduler/index.workerd.js +2 -391
  141. package/dist/scheduler/index.workerd.js.map +1 -1
  142. package/dist/security/index.browser.js.map +1 -1
  143. package/dist/security/index.d.ts +2 -325
  144. package/dist/security/index.d.ts.map +1 -1
  145. package/dist/security/index.js +3 -1362
  146. package/dist/security/index.js.map +1 -1
  147. package/dist/server/auth/index.d.ts +1 -1054
  148. package/dist/server/auth/index.d.ts.map +1 -1
  149. package/dist/server/auth/index.js +16 -1224
  150. package/dist/server/auth/index.js.map +1 -1
  151. package/dist/server/cookies/index.js.map +1 -1
  152. package/dist/server/core/index.browser.js.map +1 -1
  153. package/dist/server/core/index.d.ts +1 -4
  154. package/dist/server/core/index.d.ts.map +1 -1
  155. package/dist/server/core/index.js +19 -4
  156. package/dist/server/core/index.js.map +1 -1
  157. package/dist/server/links/index.browser.js.map +1 -1
  158. package/dist/server/links/index.js.map +1 -1
  159. package/dist/server/metrics/index.d.ts +1 -514
  160. package/dist/server/metrics/index.d.ts.map +1 -1
  161. package/dist/server/metrics/index.js +4 -4356
  162. package/dist/server/metrics/index.js.map +1 -1
  163. package/dist/server/rate-limit/index.js.map +1 -1
  164. package/dist/server/static/index.js.map +1 -1
  165. package/dist/server/swagger/index.js +1 -1
  166. package/dist/server/swagger/index.js.map +1 -1
  167. package/dist/sms/index.js.map +1 -1
  168. package/dist/system/index.browser.js.map +1 -1
  169. package/dist/system/index.d.ts.map +1 -1
  170. package/dist/system/index.js +1 -0
  171. package/dist/system/index.js.map +1 -1
  172. package/dist/system/index.workerd.js.map +1 -1
  173. package/dist/topic/core/index.js +1 -1
  174. package/dist/topic/core/index.js.map +1 -1
  175. package/dist/websocket/index.browser.js +21 -0
  176. package/dist/websocket/index.browser.js.map +1 -1
  177. package/dist/websocket/index.js +21 -0
  178. package/dist/websocket/index.js.map +1 -1
  179. package/package.json +23 -37
  180. package/src/api/files/__tests__/FileController.spec.ts +1 -1
  181. package/src/api/files/jobs/FileJobs.ts +2 -1
  182. package/src/api/jobs/__tests__/$job.spec.ts +320 -2867
  183. package/src/api/jobs/controllers/AdminJobController.ts +29 -138
  184. package/src/api/jobs/entities/jobExecutionEntity.ts +27 -19
  185. package/src/api/jobs/index.browser.ts +5 -7
  186. package/src/api/jobs/index.ts +23 -51
  187. package/src/api/jobs/primitives/$job.ts +66 -58
  188. package/src/api/jobs/providers/JobProvider.ts +561 -566
  189. package/src/api/jobs/providers/JobQueueProvider.ts +18 -19
  190. package/src/api/jobs/schemas/jobConfigAtom.ts +20 -23
  191. package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +3 -27
  192. package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +5 -7
  193. package/src/api/jobs/schemas/jobRegistrationSchema.ts +7 -4
  194. package/src/api/jobs/schemas/triggerJobSchema.ts +0 -1
  195. package/src/api/jobs/services/JobService.ts +90 -483
  196. package/src/api/notifications/controllers/AdminNotificationController.ts +19 -12
  197. package/src/api/notifications/index.ts +7 -4
  198. package/src/api/notifications/jobs/NotificationJobs.ts +83 -12
  199. package/src/api/payments/services/PaymentService.ts +4 -2
  200. package/src/api/users/__tests__/UserJobs.spec.ts +10 -49
  201. package/src/api/users/audits/UserAudits.ts +3 -1
  202. package/src/api/users/buckets/UserBuckets.ts +2 -1
  203. package/src/api/users/index.ts +1 -4
  204. package/src/api/users/jobs/UserJobs.ts +5 -4
  205. package/src/api/users/schemas/userQuerySchema.ts +0 -1
  206. package/src/api/users/services/UserService.ts +1 -5
  207. package/src/api/verifications/__tests__/CodeVerification.spec.ts +14 -0
  208. package/src/api/verifications/__tests__/LinkVerification.spec.ts +14 -0
  209. package/src/api/verifications/jobs/VerificationJobs.ts +2 -1
  210. package/src/api/verifications/services/VerificationService.ts +1 -0
  211. package/src/cli/core/__tests__/init.spec.ts +209 -1
  212. package/src/cli/core/commands/init.ts +9 -9
  213. package/src/cli/core/services/PackageManagerUtils.ts +22 -12
  214. package/src/cli/core/services/ProjectScaffolder.ts +300 -70
  215. package/src/cli/core/tasks/BuildDockerTask.ts +9 -10
  216. package/src/cli/core/tasks/BuildServerTask.ts +8 -0
  217. package/src/cli/core/templates/agentMd.ts +2 -8
  218. package/src/cli/core/templates/apiIndexTs.ts +22 -14
  219. package/src/cli/core/templates/componentsJsonTs.ts +39 -0
  220. package/src/cli/core/templates/mainCss.ts +2 -36
  221. package/src/cli/core/templates/saasAdminLayoutTsx.ts +77 -0
  222. package/src/cli/core/templates/saasAdminPagesTsx.ts +26 -0
  223. package/src/cli/core/templates/saasAuthLayoutTsx.ts +20 -0
  224. package/src/cli/core/templates/saasAuthPagesTsx.ts +62 -0
  225. package/src/cli/core/templates/saasRealmProviderTs.ts +46 -0
  226. package/src/cli/core/templates/vitestConfigTs.ts +17 -0
  227. package/src/cli/core/templates/webAppRouterTs.ts +102 -82
  228. package/src/cli/core/templates/webIndexTs.ts +23 -1
  229. package/src/cli/platform/__tests__/CloudflareAdapter.spec.ts +22 -71
  230. package/src/cli/platform/__tests__/SecretsCommand.spec.ts +2 -0
  231. package/src/cli/platform/adapters/CloudflareAdapter.ts +12 -11
  232. package/src/cli/platform/atoms/platformOptions.ts +9 -0
  233. package/src/cli/platform/schemas/cloudflare.ts +3 -2
  234. package/src/cli/platform/services/CloudflareApi.ts +164 -25
  235. package/src/cli/platform/services/WranglerApi.ts +0 -17
  236. package/src/command/providers/CliProvider.ts +1 -1
  237. package/src/core/Alepha.ts +9 -0
  238. package/src/core/interfaces/Service.ts +3 -1
  239. package/src/core/providers/TypeProvider.ts +1 -1
  240. package/src/logger/services/Logger.ts +1 -1
  241. package/src/mcp/__tests__/$resource.spec.ts +1 -1
  242. package/src/mcp/__tests__/$tool.spec.ts +1 -1
  243. package/src/mcp/__tests__/McpServerProvider.spec.ts +1 -1
  244. package/src/orm/__tests__/$repository-tests.ts +1 -0
  245. package/src/orm/__tests__/orm-next-tests.ts +2 -67
  246. package/src/orm/__tests__/orm-next.spec.ts +0 -21
  247. package/src/orm/core/index.shared.ts +0 -2
  248. package/src/orm/core/index.ts +1 -2
  249. package/src/orm/core/primitives/$repository.ts +3 -6
  250. package/src/orm/core/providers/drivers/DatabaseProvider.ts +0 -5
  251. package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +11 -13
  252. package/src/orm/core/services/ModelBuilder.ts +1 -13
  253. package/src/orm/core/services/Repository.ts +1 -42
  254. package/src/orm/core/services/SqliteModelBuilder.ts +2 -33
  255. package/src/orm/postgres/services/PostgresModelBuilder.ts +10 -45
  256. package/src/react/form/index.ts +2 -0
  257. package/src/react/form/services/parseField.ts +163 -0
  258. package/src/react/form/services/prettyName.ts +19 -0
  259. package/src/react/head/providers/BrowserHeadProvider.ts +31 -10
  260. package/src/react/intro/components/GettingStartedAuthSlide.tsx +11 -4
  261. package/src/react/router/__tests__/ReactBrowserProvider.browser.spec.ts +213 -2
  262. package/src/react/router/primitives/$page.ts +35 -12
  263. package/src/react/router/providers/ReactBrowserProvider.ts +73 -0
  264. package/src/react/router/providers/ReactBrowserRouterProvider.ts +1 -1
  265. package/src/react/router/providers/ReactPreloadProvider.ts +1 -1
  266. package/src/react/router/providers/ReactServerProvider.ts +1 -0
  267. package/src/react/ui/atoms/uiAtom.ts +28 -0
  268. package/src/react/ui/components/ColorScheme.tsx +36 -0
  269. package/src/react/ui/hooks/useColorMode.ts +49 -0
  270. package/src/react/ui/hooks/useSidebarState.ts +26 -0
  271. package/src/react/ui/hooks/useTheme.ts +22 -0
  272. package/src/react/ui/index.ts +35 -0
  273. package/src/react/ui/services/UiPersistence.ts +41 -0
  274. package/src/router/TemplatedPathParser.ts +50 -51
  275. package/src/router/__tests__/RouterProvider.spec.ts +62 -0
  276. package/src/router/__tests__/TemplatedPathParser.spec.ts +18 -0
  277. package/src/router/providers/RouterProvider.ts +10 -5
  278. package/src/scheduler/providers/CronProvider.ts +1 -1
  279. package/src/security/primitives/$basicAuth.ts +1 -1
  280. package/src/server/auth/providers/ServerAuthProvider.ts +5 -1
  281. package/src/server/core/interfaces/ServerRequest.ts +1 -0
  282. package/src/server/core/providers/ServerProvider.ts +1 -1
  283. package/src/server/core/providers/ServerRouterProvider.ts +2 -2
  284. package/src/server/core/services/HttpClient.ts +1 -1
  285. package/src/server/swagger/providers/ServerSwaggerProvider.ts +1 -1
  286. package/src/system/providers/NodeShellProvider.ts +1 -0
  287. package/src/topic/core/providers/TopicProvider.ts +1 -1
  288. package/dist/api/invitations/index.d.ts +0 -790
  289. package/dist/api/invitations/index.d.ts.map +0 -1
  290. package/dist/api/invitations/index.js +0 -662
  291. package/dist/api/invitations/index.js.map +0 -1
  292. package/dist/api/issues/index.d.ts +0 -810
  293. package/dist/api/issues/index.d.ts.map +0 -1
  294. package/dist/api/issues/index.js +0 -444
  295. package/dist/api/issues/index.js.map +0 -1
  296. package/dist/api/subscriptions/index.d.ts +0 -1692
  297. package/dist/api/subscriptions/index.d.ts.map +0 -1
  298. package/dist/api/subscriptions/index.js +0 -1867
  299. package/dist/api/subscriptions/index.js.map +0 -1
  300. package/dist/api/workflows/index.browser.js +0 -246
  301. package/dist/api/workflows/index.browser.js.map +0 -1
  302. package/dist/api/workflows/index.d.ts +0 -1618
  303. package/dist/api/workflows/index.d.ts.map +0 -1
  304. package/dist/api/workflows/index.js +0 -1495
  305. package/dist/api/workflows/index.js.map +0 -1
  306. package/dist/react/testing/chunk-DBEY4PJZ.js +0 -16
  307. package/src/api/invitations/__tests__/InvitationService.spec.ts +0 -439
  308. package/src/api/invitations/controllers/AdminInvitationController.ts +0 -86
  309. package/src/api/invitations/controllers/InvitationController.ts +0 -84
  310. package/src/api/invitations/entities/invitations.ts +0 -33
  311. package/src/api/invitations/index.ts +0 -58
  312. package/src/api/invitations/jobs/InvitationJobs.ts +0 -37
  313. package/src/api/invitations/providers/InvitationProvider.ts +0 -45
  314. package/src/api/invitations/schemas/createInvitationSchema.ts +0 -12
  315. package/src/api/invitations/schemas/invitationConfigAtom.ts +0 -20
  316. package/src/api/invitations/schemas/invitationQuerySchema.ts +0 -15
  317. package/src/api/invitations/schemas/invitationResourceSchema.ts +0 -6
  318. package/src/api/invitations/schemas/invitationWithResourceInfoSchema.ts +0 -22
  319. package/src/api/invitations/schemas/myInvitationsQuerySchema.ts +0 -10
  320. package/src/api/invitations/services/InvitationService.ts +0 -556
  321. package/src/api/issues/__tests__/IssueService.spec.ts +0 -263
  322. package/src/api/issues/controllers/AdminIssueController.ts +0 -149
  323. package/src/api/issues/controllers/IssueController.ts +0 -44
  324. package/src/api/issues/entities/issues.ts +0 -49
  325. package/src/api/issues/index.ts +0 -50
  326. package/src/api/issues/schemas/createIssueSchema.ts +0 -13
  327. package/src/api/issues/schemas/issueConfigAtom.ts +0 -13
  328. package/src/api/issues/schemas/issueQuerySchema.ts +0 -18
  329. package/src/api/issues/schemas/issueResourceSchema.ts +0 -6
  330. package/src/api/issues/schemas/myIssueQuerySchema.ts +0 -10
  331. package/src/api/issues/schemas/updateIssueSchema.ts +0 -13
  332. package/src/api/issues/services/IssueService.ts +0 -264
  333. package/src/api/jobs/__tests__/$job-middleware.spec.ts +0 -126
  334. package/src/api/jobs/__tests__/JobService.spec.ts +0 -31
  335. package/src/api/jobs/entities/jobExecutionLogEntity.ts +0 -13
  336. package/src/api/jobs/schemas/jobActivitySchema.ts +0 -15
  337. package/src/api/jobs/schemas/jobCronInfoSchema.ts +0 -22
  338. package/src/api/jobs/schemas/jobExecutionDetailResourceSchema.ts +0 -20
  339. package/src/api/jobs/schemas/jobFailureSchema.ts +0 -9
  340. package/src/api/jobs/schemas/jobQueueDepthSchema.ts +0 -14
  341. package/src/api/jobs/schemas/jobStatsSchema.ts +0 -14
  342. package/src/api/jobs/services/JobService-tests.ts +0 -157
  343. package/src/api/subscriptions/__tests__/BillingService.spec.ts +0 -218
  344. package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +0 -278
  345. package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +0 -212
  346. package/src/api/subscriptions/controllers/SubscriptionController.ts +0 -189
  347. package/src/api/subscriptions/entities/subscriptionEvents.ts +0 -54
  348. package/src/api/subscriptions/entities/subscriptions.ts +0 -68
  349. package/src/api/subscriptions/index.ts +0 -133
  350. package/src/api/subscriptions/jobs/SubscriptionJobs.ts +0 -382
  351. package/src/api/subscriptions/middleware/$requireLimit.ts +0 -50
  352. package/src/api/subscriptions/middleware/$requirePlan.ts +0 -49
  353. package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +0 -110
  354. package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +0 -8
  355. package/src/api/subscriptions/schemas/changePlanSchema.ts +0 -9
  356. package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +0 -11
  357. package/src/api/subscriptions/schemas/entitlementsSchema.ts +0 -21
  358. package/src/api/subscriptions/schemas/mrrSchema.ts +0 -13
  359. package/src/api/subscriptions/schemas/planDefinitionSchema.ts +0 -71
  360. package/src/api/subscriptions/schemas/planResourceSchema.ts +0 -25
  361. package/src/api/subscriptions/schemas/subscriptionEventResourceSchema.ts +0 -8
  362. package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +0 -19
  363. package/src/api/subscriptions/schemas/subscriptionResourceSchema.ts +0 -6
  364. package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +0 -32
  365. package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +0 -23
  366. package/src/api/subscriptions/services/BillingService.ts +0 -437
  367. package/src/api/subscriptions/services/SubscriptionConfig.ts +0 -56
  368. package/src/api/subscriptions/services/SubscriptionService.ts +0 -867
  369. package/src/api/subscriptions/services/UsageService.ts +0 -118
  370. package/src/api/workflows/__tests__/$workflow.spec.ts +0 -616
  371. package/src/api/workflows/controllers/AdminWorkflowController.ts +0 -191
  372. package/src/api/workflows/entities/workflowExecutions.ts +0 -74
  373. package/src/api/workflows/entities/workflowStepExecutions.ts +0 -74
  374. package/src/api/workflows/entities/workflowStepLogs.ts +0 -13
  375. package/src/api/workflows/index.browser.ts +0 -22
  376. package/src/api/workflows/index.ts +0 -115
  377. package/src/api/workflows/jobs/WorkflowJobs.ts +0 -77
  378. package/src/api/workflows/primitives/$workflow.ts +0 -202
  379. package/src/api/workflows/providers/WorkflowProvider.ts +0 -1284
  380. package/src/api/workflows/schemas/workflowActivitySchema.ts +0 -15
  381. package/src/api/workflows/schemas/workflowConfigAtom.ts +0 -51
  382. package/src/api/workflows/schemas/workflowExecutionDetailSchema.ts +0 -18
  383. package/src/api/workflows/schemas/workflowExecutionQuerySchema.ts +0 -26
  384. package/src/api/workflows/schemas/workflowExecutionResourceSchema.ts +0 -30
  385. package/src/api/workflows/schemas/workflowRegistrationSchema.ts +0 -26
  386. package/src/api/workflows/schemas/workflowStatsSchema.ts +0 -16
  387. package/src/api/workflows/schemas/workflowStepExecutionResourceSchema.ts +0 -15
  388. package/src/api/workflows/services/WorkflowService.ts +0 -382
  389. package/src/cli/core/templates/apiAppSecurityTs.ts +0 -43
  390. package/src/cli/core/templates/webAdminDashboardTsx.ts +0 -17
  391. package/src/orm/core/__tests__/parseQueryString.spec.ts +0 -196
  392. package/src/orm/core/helpers/parseQueryString.ts +0 -502
  393. package/src/orm/core/primitives/$view.ts +0 -88
@@ -0,0 +1,124 @@
1
+ import * as _$alepha from "alepha";
2
+ import { Static } from "alepha";
3
+ import * as _$alepha_react_head0 from "alepha/react/head";
4
+ import * as _$alepha_server_cookies0 from "alepha/server/cookies";
5
+ import * as _$typebox from "typebox";
6
+
7
+ //#region ../../src/react/ui/atoms/uiAtom.d.ts
8
+ /**
9
+ * Persisted UI state — color mode, theme palette, sidebar collapsed state, etc.
10
+ *
11
+ * The atom is bound to a single `alepha-ui` cookie via {@link UiPersistence},
12
+ * so values survive page reloads and are available during SSR.
13
+ */
14
+ declare const uiAtom: _$alepha.Atom<_$alepha.TObject<{
15
+ /** Color mode preference. `"system"` follows the OS-level setting. */mode: _$alepha.TUnsafe<"light" | "dark" | "system">; /** Theme palette name. UI consumers map this to a CSS class on the root. */
16
+ theme: _$alepha.TString; /** Sidebar UI state. */
17
+ sidebar: _$alepha.TObject<{
18
+ collapsed: _$alepha.TBoolean;
19
+ }>;
20
+ }>, "alepha.react.ui">;
21
+ type UiState = Static<typeof uiAtom.schema>;
22
+ //#endregion
23
+ //#region ../../src/react/ui/components/ColorScheme.d.ts
24
+ /**
25
+ * Applies `class="dark"` and an optional theme palette class
26
+ * (`theme-<name>`) to the document root, syncing whenever the underlying
27
+ * atom mutates.
28
+ *
29
+ * Mount once near the root of your tree (typically inside the layout).
30
+ *
31
+ * @example
32
+ * <ColorScheme />
33
+ */
34
+ declare function ColorScheme(): null;
35
+ //#endregion
36
+ //#region ../../src/react/ui/hooks/useColorMode.d.ts
37
+ type ColorMode = "light" | "dark" | "system";
38
+ type ResolvedColorMode = "light" | "dark";
39
+ /**
40
+ * Read and update the user's color-mode preference. `"system"` resolves to
41
+ * the OS preference and updates live as the OS toggles between light/dark.
42
+ *
43
+ * @example
44
+ * const { mode, setMode, resolved } = useColorMode();
45
+ * setMode("dark");
46
+ * document.documentElement.classList.toggle("dark", resolved === "dark");
47
+ */
48
+ declare const useColorMode: () => {
49
+ mode: ColorMode;
50
+ resolved: ResolvedColorMode;
51
+ setMode: (next: ColorMode) => void;
52
+ };
53
+ //#endregion
54
+ //#region ../../src/react/ui/hooks/useSidebarState.d.ts
55
+ /**
56
+ * Read and update the sidebar collapsed state. The value is persisted via the
57
+ * `alepha-ui` cookie so it survives reloads and is available during SSR — no
58
+ * flash of expanded-then-collapsed when the user prefers a collapsed shell.
59
+ *
60
+ * @example
61
+ * const { collapsed, setCollapsed, toggle } = useSidebarState();
62
+ */
63
+ declare const useSidebarState: () => {
64
+ collapsed: boolean;
65
+ setCollapsed: (next: boolean) => void;
66
+ toggle: () => void;
67
+ };
68
+ //#endregion
69
+ //#region ../../src/react/ui/hooks/useTheme.d.ts
70
+ /**
71
+ * Read and update the active theme palette name. UI consumers typically map
72
+ * the value to a class on the document root (e.g. `theme-claude`).
73
+ *
74
+ * @example
75
+ * const { theme, setTheme } = useTheme();
76
+ * setTheme("claude");
77
+ */
78
+ declare const useTheme: () => {
79
+ theme: string;
80
+ setTheme: (next: string) => void;
81
+ };
82
+ //#endregion
83
+ //#region ../../src/react/ui/services/UiPersistence.d.ts
84
+ /**
85
+ * Binds the {@link uiAtom} to an `alepha-ui` cookie + injects an inline
86
+ * boot script into the SSR head to prevent FOUC on first paint.
87
+ *
88
+ * Reading flow: on app boot the cookie is parsed and pushed into the atom
89
+ * (via the `key` option on `$cookie`). Writing flow: every time the atom
90
+ * mutates, the cookie is rewritten — a single `useStore(uiAtom)` call is
91
+ * enough to persist UI preferences across reloads.
92
+ *
93
+ * Persists for 365 days; SameSite=lax so it travels on top-level navigation
94
+ * but not on cross-origin requests.
95
+ */
96
+ declare class UiPersistence {
97
+ ui: _$alepha_server_cookies0.AbstractCookiePrimitive<_$typebox.TObject<{
98
+ mode: _$typebox.TUnsafe<"light" | "dark" | "system">;
99
+ theme: _$typebox.TString;
100
+ sidebar: _$typebox.TObject<{
101
+ collapsed: _$typebox.TBoolean;
102
+ }>;
103
+ }>>;
104
+ head: _$alepha_react_head0.HeadPrimitive;
105
+ }
106
+ //#endregion
107
+ //#region ../../src/react/ui/index.d.ts
108
+ declare module "alepha" {
109
+ interface State {
110
+ "alepha.react.ui": UiState;
111
+ }
112
+ }
113
+ /**
114
+ * Persisted UI state: color mode, theme palette, sidebar collapsed state.
115
+ *
116
+ * Backed by an `alepha-ui` cookie so preferences survive reloads and are
117
+ * available during SSR (no flash of wrong theme).
118
+ *
119
+ * @module alepha.react.ui
120
+ */
121
+ declare const AlephaReactUi: _$alepha.Service<_$alepha.Module>;
122
+ //#endregion
123
+ export { AlephaReactUi, ColorMode, ColorScheme, ResolvedColorMode, UiPersistence, UiState, uiAtom, useColorMode, useSidebarState, useTheme };
124
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/react/ui/atoms/uiAtom.ts","../../../src/react/ui/components/ColorScheme.tsx","../../../src/react/ui/hooks/useColorMode.ts","../../../src/react/ui/hooks/useSidebarState.ts","../../../src/react/ui/hooks/useTheme.ts","../../../src/react/ui/services/UiPersistence.ts","../../../src/react/ui/index.ts"],"mappings":";;;;;;;;;;;;;cAQa,MAAA,EAAM,QAAA,CAAA,IAAA,UAAA,OAAA;EAiBjB,4EAAA,QAAA,CAAA,OAAA,+BAAA;;;;;;KAEU,OAAA,GAAU,MAAA,QAAc,MAAA,CAAO,MAAA;;;;;;;;;;AAnB3C;;;iBCMgB,WAAA,CAAA;;;KCVJ,SAAA;AAAA,KACA,iBAAA;;;;;;AFGZ;;;;cEQa,YAAA;;;kBAQO,SAAA;AAAA;;;;;;;;;;AFhBpB;cGGa,eAAA;;;;;;;;;;;;;;AHHb;cIGa,QAAA;;;;;;;;;;;;;AJHb;;;;;cKoBa,aAAA;EACX,EAAA,EAAE,wBAAA,CAAA,uBAAA,WAAA,OAAA;UADsB,SAAA,CAAA,OAAA;;;;;;EASxB,IAAA,EARE,oBAAA,CAQE,aAAA;AAAA;;;;YCrBa,KAAA;IACf,iBAAA,EAAmB,OAAA;EAAA;AAAA;;;;;;;;;cAcV,aAAA,EAAa,QAAA,CAAA,OAAA,CAGxB,QAAA,CAHwB,MAAA"}
@@ -0,0 +1,209 @@
1
+ import { $atom, $module, t } from "alepha";
2
+ import { $head } from "alepha/react/head";
3
+ import { $cookie } from "alepha/server/cookies";
4
+ import { useEffect, useState } from "react";
5
+ import { useStore } from "alepha/react";
6
+ //#region ../../src/react/ui/atoms/uiAtom.ts
7
+ /**
8
+ * Persisted UI state — color mode, theme palette, sidebar collapsed state, etc.
9
+ *
10
+ * The atom is bound to a single `alepha-ui` cookie via {@link UiPersistence},
11
+ * so values survive page reloads and are available during SSR.
12
+ */
13
+ const uiAtom = $atom({
14
+ name: "alepha.react.ui",
15
+ schema: t.object({
16
+ /** Color mode preference. `"system"` follows the OS-level setting. */
17
+ mode: t.enum([
18
+ "light",
19
+ "dark",
20
+ "system"
21
+ ]),
22
+ /** Theme palette name. UI consumers map this to a CSS class on the root. */
23
+ theme: t.string(),
24
+ /** Sidebar UI state. */
25
+ sidebar: t.object({ collapsed: t.boolean() })
26
+ }),
27
+ default: {
28
+ mode: "system",
29
+ theme: "default",
30
+ sidebar: { collapsed: false }
31
+ }
32
+ });
33
+ //#endregion
34
+ //#region ../../src/react/ui/services/UiPersistence.ts
35
+ /**
36
+ * Inline `<script>` rendered by SSR into the document `<head>`. Runs
37
+ * synchronously before any CSS or React hydration: reads the `alepha-ui`
38
+ * cookie, resolves `mode === "system"` via `prefers-color-scheme`, and
39
+ * applies `class="dark"` (and optional `theme-<name>`) on `<html>`.
40
+ *
41
+ * This is what kills the flash-of-wrong-theme (FOUC) you'd otherwise get
42
+ * with React-effect-based theming. Failures are swallowed silently — at
43
+ * worst the page paints in light mode for one frame.
44
+ */
45
+ const colorSchemeBoot = `(function(){try{var m=document.cookie.match(/(?:^|;\\s*)alepha-ui=([^;]+)/);var s=m?JSON.parse(decodeURIComponent(m[1])):{};var mode=s.mode||"system";var dark=mode==="dark"||(mode==="system"&&window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches);var r=document.documentElement;if(dark)r.classList.add("dark");if(s.theme&&s.theme!=="default")r.classList.add("theme-"+s.theme);}catch(e){}})();`;
46
+ /**
47
+ * Binds the {@link uiAtom} to an `alepha-ui` cookie + injects an inline
48
+ * boot script into the SSR head to prevent FOUC on first paint.
49
+ *
50
+ * Reading flow: on app boot the cookie is parsed and pushed into the atom
51
+ * (via the `key` option on `$cookie`). Writing flow: every time the atom
52
+ * mutates, the cookie is rewritten — a single `useStore(uiAtom)` call is
53
+ * enough to persist UI preferences across reloads.
54
+ *
55
+ * Persists for 365 days; SameSite=lax so it travels on top-level navigation
56
+ * but not on cross-origin requests.
57
+ */
58
+ var UiPersistence = class {
59
+ ui = $cookie({
60
+ name: "alepha-ui",
61
+ key: uiAtom.key,
62
+ schema: uiAtom.schema,
63
+ ttl: [365, "days"],
64
+ sameSite: "lax"
65
+ });
66
+ head = $head({ script: [{ content: colorSchemeBoot }] });
67
+ };
68
+ //#endregion
69
+ //#region ../../src/react/ui/hooks/useColorMode.ts
70
+ /**
71
+ * Read and update the user's color-mode preference. `"system"` resolves to
72
+ * the OS preference and updates live as the OS toggles between light/dark.
73
+ *
74
+ * @example
75
+ * const { mode, setMode, resolved } = useColorMode();
76
+ * setMode("dark");
77
+ * document.documentElement.classList.toggle("dark", resolved === "dark");
78
+ */
79
+ const useColorMode = () => {
80
+ const [state, set] = useStore(uiAtom);
81
+ const mode = state?.mode ?? "system";
82
+ return {
83
+ mode,
84
+ resolved: useResolvedColorMode(mode),
85
+ setMode: (next) => {
86
+ set({
87
+ ...state ?? uiAtom.options.default,
88
+ mode: next
89
+ });
90
+ }
91
+ };
92
+ };
93
+ const useResolvedColorMode = (mode) => {
94
+ const [systemDark, setSystemDark] = useState(() => {
95
+ if (typeof window === "undefined") return false;
96
+ return window.matchMedia?.("(prefers-color-scheme: dark)").matches ?? false;
97
+ });
98
+ useEffect(() => {
99
+ if (typeof window === "undefined") return;
100
+ const mq = window.matchMedia?.("(prefers-color-scheme: dark)");
101
+ if (!mq) return;
102
+ const onChange = (ev) => setSystemDark(ev.matches);
103
+ mq.addEventListener("change", onChange);
104
+ return () => mq.removeEventListener("change", onChange);
105
+ }, []);
106
+ if (mode === "dark") return "dark";
107
+ if (mode === "light") return "light";
108
+ return systemDark ? "dark" : "light";
109
+ };
110
+ //#endregion
111
+ //#region ../../src/react/ui/hooks/useTheme.ts
112
+ /**
113
+ * Read and update the active theme palette name. UI consumers typically map
114
+ * the value to a class on the document root (e.g. `theme-claude`).
115
+ *
116
+ * @example
117
+ * const { theme, setTheme } = useTheme();
118
+ * setTheme("claude");
119
+ */
120
+ const useTheme = () => {
121
+ const [state, set] = useStore(uiAtom);
122
+ return {
123
+ theme: state?.theme ?? "default",
124
+ setTheme: (next) => {
125
+ set({
126
+ ...state ?? uiAtom.options.default,
127
+ theme: next
128
+ });
129
+ }
130
+ };
131
+ };
132
+ //#endregion
133
+ //#region ../../src/react/ui/components/ColorScheme.tsx
134
+ /**
135
+ * Applies `class="dark"` and an optional theme palette class
136
+ * (`theme-<name>`) to the document root, syncing whenever the underlying
137
+ * atom mutates.
138
+ *
139
+ * Mount once near the root of your tree (typically inside the layout).
140
+ *
141
+ * @example
142
+ * <ColorScheme />
143
+ */
144
+ function ColorScheme() {
145
+ const { resolved } = useColorMode();
146
+ const { theme } = useTheme();
147
+ useEffect(() => {
148
+ if (typeof document === "undefined") return;
149
+ document.documentElement.classList.toggle("dark", resolved === "dark");
150
+ }, [resolved]);
151
+ useEffect(() => {
152
+ if (typeof document === "undefined") return;
153
+ const root = document.documentElement;
154
+ const previous = [];
155
+ root.classList.forEach((cls) => {
156
+ if (cls.startsWith("theme-")) previous.push(cls);
157
+ });
158
+ for (const cls of previous) root.classList.remove(cls);
159
+ if (theme && theme !== "default") root.classList.add(`theme-${theme}`);
160
+ }, [theme]);
161
+ return null;
162
+ }
163
+ //#endregion
164
+ //#region ../../src/react/ui/hooks/useSidebarState.ts
165
+ /**
166
+ * Read and update the sidebar collapsed state. The value is persisted via the
167
+ * `alepha-ui` cookie so it survives reloads and is available during SSR — no
168
+ * flash of expanded-then-collapsed when the user prefers a collapsed shell.
169
+ *
170
+ * @example
171
+ * const { collapsed, setCollapsed, toggle } = useSidebarState();
172
+ */
173
+ const useSidebarState = () => {
174
+ const [state, set] = useStore(uiAtom);
175
+ const collapsed = state?.sidebar.collapsed ?? false;
176
+ const setCollapsed = (next) => {
177
+ const base = state ?? uiAtom.options.default;
178
+ set({
179
+ ...base,
180
+ sidebar: {
181
+ ...base.sidebar,
182
+ collapsed: next
183
+ }
184
+ });
185
+ };
186
+ return {
187
+ collapsed,
188
+ setCollapsed,
189
+ toggle: () => setCollapsed(!collapsed)
190
+ };
191
+ };
192
+ //#endregion
193
+ //#region ../../src/react/ui/index.ts
194
+ /**
195
+ * Persisted UI state: color mode, theme palette, sidebar collapsed state.
196
+ *
197
+ * Backed by an `alepha-ui` cookie so preferences survive reloads and are
198
+ * available during SSR (no flash of wrong theme).
199
+ *
200
+ * @module alepha.react.ui
201
+ */
202
+ const AlephaReactUi = $module({
203
+ name: "alepha.react.ui",
204
+ services: [UiPersistence]
205
+ });
206
+ //#endregion
207
+ export { AlephaReactUi, ColorScheme, UiPersistence, uiAtom, useColorMode, useSidebarState, useTheme };
208
+
209
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/react/ui/atoms/uiAtom.ts","../../../src/react/ui/services/UiPersistence.ts","../../../src/react/ui/hooks/useColorMode.ts","../../../src/react/ui/hooks/useTheme.ts","../../../src/react/ui/components/ColorScheme.tsx","../../../src/react/ui/hooks/useSidebarState.ts","../../../src/react/ui/index.ts"],"sourcesContent":["import { $atom, type Static, t } from \"alepha\";\n\n/**\n * Persisted UI state — color mode, theme palette, sidebar collapsed state, etc.\n *\n * The atom is bound to a single `alepha-ui` cookie via {@link UiPersistence},\n * so values survive page reloads and are available during SSR.\n */\nexport const uiAtom = $atom({\n name: \"alepha.react.ui\",\n schema: t.object({\n /** Color mode preference. `\"system\"` follows the OS-level setting. */\n mode: t.enum([\"light\", \"dark\", \"system\"]),\n /** Theme palette name. UI consumers map this to a CSS class on the root. */\n theme: t.string(),\n /** Sidebar UI state. */\n sidebar: t.object({\n collapsed: t.boolean(),\n }),\n }),\n default: {\n mode: \"system\",\n theme: \"default\",\n sidebar: { collapsed: false },\n },\n});\n\nexport type UiState = Static<typeof uiAtom.schema>;\n","import { $head } from \"alepha/react/head\";\nimport { $cookie } from \"alepha/server/cookies\";\nimport { uiAtom } from \"../atoms/uiAtom.ts\";\n\n/**\n * Inline `<script>` rendered by SSR into the document `<head>`. Runs\n * synchronously before any CSS or React hydration: reads the `alepha-ui`\n * cookie, resolves `mode === \"system\"` via `prefers-color-scheme`, and\n * applies `class=\"dark\"` (and optional `theme-<name>`) on `<html>`.\n *\n * This is what kills the flash-of-wrong-theme (FOUC) you'd otherwise get\n * with React-effect-based theming. Failures are swallowed silently — at\n * worst the page paints in light mode for one frame.\n */\nconst colorSchemeBoot = `(function(){try{var m=document.cookie.match(/(?:^|;\\\\s*)alepha-ui=([^;]+)/);var s=m?JSON.parse(decodeURIComponent(m[1])):{};var mode=s.mode||\"system\";var dark=mode===\"dark\"||(mode===\"system\"&&window.matchMedia&&window.matchMedia(\"(prefers-color-scheme: dark)\").matches);var r=document.documentElement;if(dark)r.classList.add(\"dark\");if(s.theme&&s.theme!==\"default\")r.classList.add(\"theme-\"+s.theme);}catch(e){}})();`;\n\n/**\n * Binds the {@link uiAtom} to an `alepha-ui` cookie + injects an inline\n * boot script into the SSR head to prevent FOUC on first paint.\n *\n * Reading flow: on app boot the cookie is parsed and pushed into the atom\n * (via the `key` option on `$cookie`). Writing flow: every time the atom\n * mutates, the cookie is rewritten — a single `useStore(uiAtom)` call is\n * enough to persist UI preferences across reloads.\n *\n * Persists for 365 days; SameSite=lax so it travels on top-level navigation\n * but not on cross-origin requests.\n */\nexport class UiPersistence {\n ui = $cookie({\n name: \"alepha-ui\",\n key: uiAtom.key,\n schema: uiAtom.schema,\n ttl: [365, \"days\"],\n sameSite: \"lax\",\n });\n\n head = $head({\n script: [{ content: colorSchemeBoot }],\n });\n}\n","import { useStore } from \"alepha/react\";\nimport { useEffect, useState } from \"react\";\nimport { uiAtom } from \"../atoms/uiAtom.ts\";\n\nexport type ColorMode = \"light\" | \"dark\" | \"system\";\nexport type ResolvedColorMode = \"light\" | \"dark\";\n\n/**\n * Read and update the user's color-mode preference. `\"system\"` resolves to\n * the OS preference and updates live as the OS toggles between light/dark.\n *\n * @example\n * const { mode, setMode, resolved } = useColorMode();\n * setMode(\"dark\");\n * document.documentElement.classList.toggle(\"dark\", resolved === \"dark\");\n */\nexport const useColorMode = () => {\n const [state, set] = useStore(uiAtom);\n const mode = (state?.mode ?? \"system\") as ColorMode;\n const resolved = useResolvedColorMode(mode);\n\n return {\n mode,\n resolved,\n setMode: (next: ColorMode) => {\n set({ ...(state ?? uiAtom.options.default!), mode: next });\n },\n };\n};\n\nconst useResolvedColorMode = (mode: ColorMode): ResolvedColorMode => {\n const [systemDark, setSystemDark] = useState<boolean>(() => {\n if (typeof window === \"undefined\") return false;\n return window.matchMedia?.(\"(prefers-color-scheme: dark)\").matches ?? false;\n });\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const mq = window.matchMedia?.(\"(prefers-color-scheme: dark)\");\n if (!mq) return;\n const onChange = (ev: MediaQueryListEvent) => setSystemDark(ev.matches);\n mq.addEventListener(\"change\", onChange);\n return () => mq.removeEventListener(\"change\", onChange);\n }, []);\n\n if (mode === \"dark\") return \"dark\";\n if (mode === \"light\") return \"light\";\n return systemDark ? \"dark\" : \"light\";\n};\n","import { useStore } from \"alepha/react\";\nimport { uiAtom } from \"../atoms/uiAtom.ts\";\n\n/**\n * Read and update the active theme palette name. UI consumers typically map\n * the value to a class on the document root (e.g. `theme-claude`).\n *\n * @example\n * const { theme, setTheme } = useTheme();\n * setTheme(\"claude\");\n */\nexport const useTheme = () => {\n const [state, set] = useStore(uiAtom);\n const theme = state?.theme ?? \"default\";\n\n return {\n theme,\n setTheme: (next: string) => {\n set({ ...(state ?? uiAtom.options.default!), theme: next });\n },\n };\n};\n","import { useEffect } from \"react\";\nimport { useColorMode } from \"../hooks/useColorMode.ts\";\nimport { useTheme } from \"../hooks/useTheme.ts\";\n\n/**\n * Applies `class=\"dark\"` and an optional theme palette class\n * (`theme-<name>`) to the document root, syncing whenever the underlying\n * atom mutates.\n *\n * Mount once near the root of your tree (typically inside the layout).\n *\n * @example\n * <ColorScheme />\n */\nexport function ColorScheme() {\n const { resolved } = useColorMode();\n const { theme } = useTheme();\n\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n document.documentElement.classList.toggle(\"dark\", resolved === \"dark\");\n }, [resolved]);\n\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n const root = document.documentElement;\n const previous: string[] = [];\n root.classList.forEach((cls) => {\n if (cls.startsWith(\"theme-\")) previous.push(cls);\n });\n for (const cls of previous) root.classList.remove(cls);\n if (theme && theme !== \"default\") root.classList.add(`theme-${theme}`);\n }, [theme]);\n\n return null;\n}\n","import { useStore } from \"alepha/react\";\nimport { uiAtom } from \"../atoms/uiAtom.ts\";\n\n/**\n * Read and update the sidebar collapsed state. The value is persisted via the\n * `alepha-ui` cookie so it survives reloads and is available during SSR — no\n * flash of expanded-then-collapsed when the user prefers a collapsed shell.\n *\n * @example\n * const { collapsed, setCollapsed, toggle } = useSidebarState();\n */\nexport const useSidebarState = () => {\n const [state, set] = useStore(uiAtom);\n const collapsed = state?.sidebar.collapsed ?? false;\n\n const setCollapsed = (next: boolean) => {\n const base = state ?? uiAtom.options.default!;\n set({ ...base, sidebar: { ...base.sidebar, collapsed: next } });\n };\n\n return {\n collapsed,\n setCollapsed,\n toggle: () => setCollapsed(!collapsed),\n };\n};\n","import { $module } from \"alepha\";\nimport type { UiState } from \"./atoms/uiAtom.ts\";\nimport { UiPersistence } from \"./services/UiPersistence.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./atoms/uiAtom.ts\";\nexport * from \"./components/ColorScheme.tsx\";\nexport * from \"./hooks/useColorMode.ts\";\nexport * from \"./hooks/useSidebarState.ts\";\nexport * from \"./hooks/useTheme.ts\";\nexport * from \"./services/UiPersistence.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n export interface State {\n \"alepha.react.ui\": UiState;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Persisted UI state: color mode, theme palette, sidebar collapsed state.\n *\n * Backed by an `alepha-ui` cookie so preferences survive reloads and are\n * available during SSR (no flash of wrong theme).\n *\n * @module alepha.react.ui\n */\nexport const AlephaReactUi = $module({\n name: \"alepha.react.ui\",\n services: [UiPersistence],\n});\n"],"mappings":";;;;;;;;;;;;AAQA,MAAa,SAAS,MAAM;CAC1B,MAAM;CACN,QAAQ,EAAE,OAAO;;EAEf,MAAM,EAAE,KAAK;GAAC;GAAS;GAAQ;GAAS,CAAC;;EAEzC,OAAO,EAAE,QAAQ;;EAEjB,SAAS,EAAE,OAAO,EAChB,WAAW,EAAE,SAAS,EACvB,CAAC;EACH,CAAC;CACF,SAAS;EACP,MAAM;EACN,OAAO;EACP,SAAS,EAAE,WAAW,OAAO;EAC9B;CACF,CAAC;;;;;;;;;;;;;ACXF,MAAM,kBAAkB;;;;;;;;;;;;;AAcxB,IAAa,gBAAb,MAA2B;CACzB,KAAK,QAAQ;EACX,MAAM;EACN,KAAK,OAAO;EACZ,QAAQ,OAAO;EACf,KAAK,CAAC,KAAK,OAAO;EAClB,UAAU;EACX,CAAC;CAEF,OAAO,MAAM,EACX,QAAQ,CAAC,EAAE,SAAS,iBAAiB,CAAC,EACvC,CAAC;;;;;;;;;;;;;ACvBJ,MAAa,qBAAqB;CAChC,MAAM,CAAC,OAAO,OAAO,SAAS,OAAO;CACrC,MAAM,OAAQ,OAAO,QAAQ;AAG7B,QAAO;EACL;EACA,UAJe,qBAAqB,KAI5B;EACR,UAAU,SAAoB;AAC5B,OAAI;IAAE,GAAI,SAAS,OAAO,QAAQ;IAAW,MAAM;IAAM,CAAC;;EAE7D;;AAGH,MAAM,wBAAwB,SAAuC;CACnE,MAAM,CAAC,YAAY,iBAAiB,eAAwB;AAC1D,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,SAAO,OAAO,aAAa,+BAA+B,CAAC,WAAW;GACtE;AAEF,iBAAgB;AACd,MAAI,OAAO,WAAW,YAAa;EACnC,MAAM,KAAK,OAAO,aAAa,+BAA+B;AAC9D,MAAI,CAAC,GAAI;EACT,MAAM,YAAY,OAA4B,cAAc,GAAG,QAAQ;AACvE,KAAG,iBAAiB,UAAU,SAAS;AACvC,eAAa,GAAG,oBAAoB,UAAU,SAAS;IACtD,EAAE,CAAC;AAEN,KAAI,SAAS,OAAQ,QAAO;AAC5B,KAAI,SAAS,QAAS,QAAO;AAC7B,QAAO,aAAa,SAAS;;;;;;;;;;;;ACpC/B,MAAa,iBAAiB;CAC5B,MAAM,CAAC,OAAO,OAAO,SAAS,OAAO;AAGrC,QAAO;EACL,OAHY,OAAO,SAAS;EAI5B,WAAW,SAAiB;AAC1B,OAAI;IAAE,GAAI,SAAS,OAAO,QAAQ;IAAW,OAAO;IAAM,CAAC;;EAE9D;;;;;;;;;;;;;;ACNH,SAAgB,cAAc;CAC5B,MAAM,EAAE,aAAa,cAAc;CACnC,MAAM,EAAE,UAAU,UAAU;AAE5B,iBAAgB;AACd,MAAI,OAAO,aAAa,YAAa;AACrC,WAAS,gBAAgB,UAAU,OAAO,QAAQ,aAAa,OAAO;IACrE,CAAC,SAAS,CAAC;AAEd,iBAAgB;AACd,MAAI,OAAO,aAAa,YAAa;EACrC,MAAM,OAAO,SAAS;EACtB,MAAM,WAAqB,EAAE;AAC7B,OAAK,UAAU,SAAS,QAAQ;AAC9B,OAAI,IAAI,WAAW,SAAS,CAAE,UAAS,KAAK,IAAI;IAChD;AACF,OAAK,MAAM,OAAO,SAAU,MAAK,UAAU,OAAO,IAAI;AACtD,MAAI,SAAS,UAAU,UAAW,MAAK,UAAU,IAAI,SAAS,QAAQ;IACrE,CAAC,MAAM,CAAC;AAEX,QAAO;;;;;;;;;;;;ACvBT,MAAa,wBAAwB;CACnC,MAAM,CAAC,OAAO,OAAO,SAAS,OAAO;CACrC,MAAM,YAAY,OAAO,QAAQ,aAAa;CAE9C,MAAM,gBAAgB,SAAkB;EACtC,MAAM,OAAO,SAAS,OAAO,QAAQ;AACrC,MAAI;GAAE,GAAG;GAAM,SAAS;IAAE,GAAG,KAAK;IAAS,WAAW;IAAM;GAAE,CAAC;;AAGjE,QAAO;EACL;EACA;EACA,cAAc,aAAa,CAAC,UAAU;EACvC;;;;;;;;;;;;ACOH,MAAa,gBAAgB,QAAQ;CACnC,MAAM;CACN,UAAU,CAAC,cAAc;CAC1B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/react/websocket/hooks/useRoom.tsx"],"sourcesContent":["import type { Static } from \"alepha\";\nimport { useAlepha, useInject } from \"alepha/react\";\nimport type { ChannelPrimitive, TWSObject } from \"alepha/websocket\";\nimport { WebSocketClient } from \"alepha/websocket\";\nimport { useEffect, useRef, useState } from \"react\";\n\n/**\n * UseRoom options\n */\nexport interface UseRoomOptions<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> {\n /**\n * Room ID to connect to\n */\n roomId: string;\n\n /**\n * Channel primitive defining the schemas\n */\n channel: ChannelPrimitive<TClient, TServer>;\n\n /**\n * Handler for incoming messages from the server\n */\n handler: (message: Static<TClient>) => void;\n\n /**\n * Optional WebSocket URL override\n * Defaults to auto-detected URL based on window.location\n */\n url?: string;\n\n /**\n * Enable automatic reconnection on disconnect\n * @default true\n */\n autoReconnect?: boolean;\n\n /**\n * Reconnection interval in milliseconds\n * @default 3000\n */\n reconnectInterval?: number;\n\n /**\n * Maximum reconnection attempts (-1 for infinite)\n * @default 10\n */\n maxReconnectAttempts?: number;\n\n /**\n * Called when connection is established\n */\n onConnect?: () => void;\n\n /**\n * Called when connection is closed\n */\n onDisconnect?: () => void;\n\n /**\n * Called on connection error\n */\n onError?: (error: Error) => void;\n}\n\n/**\n * UseRoom return value\n */\nexport interface UseRoomReturn<TServer extends TWSObject> {\n /**\n * Send a message to the server\n */\n send: (message: Static<TServer>) => Promise<void>;\n\n /**\n * Whether the connection is established\n */\n isConnected: boolean;\n\n /**\n * Whether the connection is in progress\n */\n isConnecting: boolean;\n\n /**\n * Whether there was an error\n */\n isError: boolean;\n\n /**\n * The error object if any\n */\n error?: Error;\n\n /**\n * Manually reconnect\n */\n reconnect: () => void;\n\n /**\n * Manually disconnect\n */\n disconnect: () => void;\n}\n\n/**\n * React hook for WebSocket room communication\n *\n * Provides automatic connection management, reconnection, and type-safe messaging\n * for WebSocket rooms using the injected WebSocketClient service.\n *\n * Multiple useRoom hooks on the same channel will share a single WebSocket connection.\n *\n * @example\n * ```tsx\n * const chat = useRoom({\n * roomId: \"room-123\",\n * channel: chatChannel,\n * handler: (message) => {\n * if (message.type === \"append\") {\n * setMessages(prev => [...prev, message]);\n * }\n * }\n * }, [roomId]);\n *\n * const sendMessage = async () => {\n * await chat.send({\n * content: \"Hello, world!\"\n * });\n * };\n * ```\n */\nexport const useRoom = <TClient extends TWSObject, TServer extends TWSObject>(\n options: UseRoomOptions<TClient, TServer>,\n deps: unknown[],\n): UseRoomReturn<TServer> => {\n const webSocketClient = useInject(WebSocketClient);\n const unsubscribeRef = useRef<(() => void) | null>(null);\n\n const [isConnected, setIsConnected] = useState(false);\n const [isConnecting, setIsConnecting] = useState(false);\n const [isError, setIsError] = useState(false);\n const [error, setError] = useState<Error | undefined>(undefined);\n\n const {\n roomId,\n channel,\n handler,\n url,\n autoReconnect,\n reconnectInterval,\n maxReconnectAttempts,\n onConnect,\n onDisconnect,\n onError,\n } = options;\n\n // Keep handler ref stable to avoid stale closures\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n useEffect(() => {\n // Subscribe to room — use ref so handler is always current\n const unsubscribe = webSocketClient.subscribe(\n roomId,\n channel,\n (msg) => handlerRef.current(msg),\n {\n url,\n autoReconnect,\n reconnectInterval,\n maxReconnectAttempts,\n onConnect: () => {\n setIsConnected(true);\n setIsConnecting(false);\n setIsError(false);\n setError(undefined);\n onConnect?.();\n },\n onDisconnect: () => {\n setIsConnected(false);\n setIsConnecting(false);\n onDisconnect?.();\n },\n onError: (err) => {\n setIsError(true);\n setError(err);\n setIsConnecting(false);\n onError?.(err);\n },\n },\n );\n\n unsubscribeRef.current = unsubscribe;\n\n // Get initial state from connection\n const connection = webSocketClient.getConnection(channel);\n if (connection) {\n setIsConnected(connection.isConnected);\n setIsConnecting(connection.isConnecting);\n setIsError(connection.isError);\n setError(connection.error);\n }\n\n // Cleanup on unmount or deps change\n return () => {\n unsubscribe();\n unsubscribeRef.current = null;\n };\n }, deps);\n\n const alepha = useAlepha();\n\n if (!alepha.isBrowser()) {\n return {\n send: async (_message: Static<TServer>) => {\n // No-op on server\n },\n isConnected: false,\n isConnecting: false,\n isError: false,\n error: undefined,\n reconnect: () => {\n // No-op on server\n },\n disconnect: () => {\n // No-op on server\n },\n };\n }\n\n return {\n send: async (message: Static<TServer>) => {\n await webSocketClient.send(roomId, channel, message);\n },\n isConnected,\n isConnecting,\n isError,\n error,\n reconnect: () => {\n const connection = webSocketClient.getConnection(channel);\n connection?.reconnect();\n },\n disconnect: () => {\n unsubscribeRef.current?.();\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuIA,MAAa,WACX,SACA,SAC2B;CAC3B,MAAM,kBAAkB,UAAU,gBAAgB;CAClD,MAAM,iBAAiB,OAA4B,KAAK;CAExD,MAAM,CAAC,aAAa,kBAAkB,SAAS,MAAM;CACrD,MAAM,CAAC,cAAc,mBAAmB,SAAS,MAAM;CACvD,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;CAC7C,MAAM,CAAC,OAAO,YAAY,SAA4B,KAAA,EAAU;CAEhE,MAAM,EACJ,QACA,SACA,SACA,KACA,eACA,mBACA,sBACA,WACA,cACA,YACE;CAGJ,MAAM,aAAa,OAAO,QAAQ;AAClC,YAAW,UAAU;AAErB,iBAAgB;EAEd,MAAM,cAAc,gBAAgB,UAClC,QACA,UACC,QAAQ,WAAW,QAAQ,IAAI,EAChC;GACE;GACA;GACA;GACA;GACA,iBAAiB;AACf,mBAAe,KAAK;AACpB,oBAAgB,MAAM;AACtB,eAAW,MAAM;AACjB,aAAS,KAAA,EAAU;AACnB,iBAAa;;GAEf,oBAAoB;AAClB,mBAAe,MAAM;AACrB,oBAAgB,MAAM;AACtB,oBAAgB;;GAElB,UAAU,QAAQ;AAChB,eAAW,KAAK;AAChB,aAAS,IAAI;AACb,oBAAgB,MAAM;AACtB,cAAU,IAAI;;GAEjB,CACF;AAED,iBAAe,UAAU;EAGzB,MAAM,aAAa,gBAAgB,cAAc,QAAQ;AACzD,MAAI,YAAY;AACd,kBAAe,WAAW,YAAY;AACtC,mBAAgB,WAAW,aAAa;AACxC,cAAW,WAAW,QAAQ;AAC9B,YAAS,WAAW,MAAM;;AAI5B,eAAa;AACX,gBAAa;AACb,kBAAe,UAAU;;IAE1B,KAAK;AAIR,KAAI,CAFW,WAAW,CAEd,WAAW,CACrB,QAAO;EACL,MAAM,OAAO,aAA8B;EAG3C,aAAa;EACb,cAAc;EACd,SAAS;EACT,OAAO,KAAA;EACP,iBAAiB;EAGjB,kBAAkB;EAGnB;AAGH,QAAO;EACL,MAAM,OAAO,YAA6B;AACxC,SAAM,gBAAgB,KAAK,QAAQ,SAAS,QAAQ;;EAEtD;EACA;EACA;EACA;EACA,iBAAiB;AACI,mBAAgB,cAAc,QAAQ,EAC7C,WAAW;;EAEzB,kBAAkB;AAChB,kBAAe,WAAW;;EAE7B"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/react/websocket/hooks/useRoom.tsx"],"sourcesContent":["import type { Static } from \"alepha\";\nimport { useAlepha, useInject } from \"alepha/react\";\nimport type { ChannelPrimitive, TWSObject } from \"alepha/websocket\";\nimport { WebSocketClient } from \"alepha/websocket\";\nimport { useEffect, useRef, useState } from \"react\";\n\n/**\n * UseRoom options\n */\nexport interface UseRoomOptions<\n TClient extends TWSObject,\n TServer extends TWSObject,\n> {\n /**\n * Room ID to connect to\n */\n roomId: string;\n\n /**\n * Channel primitive defining the schemas\n */\n channel: ChannelPrimitive<TClient, TServer>;\n\n /**\n * Handler for incoming messages from the server\n */\n handler: (message: Static<TClient>) => void;\n\n /**\n * Optional WebSocket URL override\n * Defaults to auto-detected URL based on window.location\n */\n url?: string;\n\n /**\n * Enable automatic reconnection on disconnect\n * @default true\n */\n autoReconnect?: boolean;\n\n /**\n * Reconnection interval in milliseconds\n * @default 3000\n */\n reconnectInterval?: number;\n\n /**\n * Maximum reconnection attempts (-1 for infinite)\n * @default 10\n */\n maxReconnectAttempts?: number;\n\n /**\n * Called when connection is established\n */\n onConnect?: () => void;\n\n /**\n * Called when connection is closed\n */\n onDisconnect?: () => void;\n\n /**\n * Called on connection error\n */\n onError?: (error: Error) => void;\n}\n\n/**\n * UseRoom return value\n */\nexport interface UseRoomReturn<TServer extends TWSObject> {\n /**\n * Send a message to the server\n */\n send: (message: Static<TServer>) => Promise<void>;\n\n /**\n * Whether the connection is established\n */\n isConnected: boolean;\n\n /**\n * Whether the connection is in progress\n */\n isConnecting: boolean;\n\n /**\n * Whether there was an error\n */\n isError: boolean;\n\n /**\n * The error object if any\n */\n error?: Error;\n\n /**\n * Manually reconnect\n */\n reconnect: () => void;\n\n /**\n * Manually disconnect\n */\n disconnect: () => void;\n}\n\n/**\n * React hook for WebSocket room communication\n *\n * Provides automatic connection management, reconnection, and type-safe messaging\n * for WebSocket rooms using the injected WebSocketClient service.\n *\n * Multiple useRoom hooks on the same channel will share a single WebSocket connection.\n *\n * @example\n * ```tsx\n * const chat = useRoom({\n * roomId: \"room-123\",\n * channel: chatChannel,\n * handler: (message) => {\n * if (message.type === \"append\") {\n * setMessages(prev => [...prev, message]);\n * }\n * }\n * }, [roomId]);\n *\n * const sendMessage = async () => {\n * await chat.send({\n * content: \"Hello, world!\"\n * });\n * };\n * ```\n */\nexport const useRoom = <TClient extends TWSObject, TServer extends TWSObject>(\n options: UseRoomOptions<TClient, TServer>,\n deps: unknown[],\n): UseRoomReturn<TServer> => {\n const webSocketClient = useInject(WebSocketClient);\n const unsubscribeRef = useRef<(() => void) | null>(null);\n\n const [isConnected, setIsConnected] = useState(false);\n const [isConnecting, setIsConnecting] = useState(false);\n const [isError, setIsError] = useState(false);\n const [error, setError] = useState<Error | undefined>(undefined);\n\n const {\n roomId,\n channel,\n handler,\n url,\n autoReconnect,\n reconnectInterval,\n maxReconnectAttempts,\n onConnect,\n onDisconnect,\n onError,\n } = options;\n\n // Keep handler ref stable to avoid stale closures\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n\n useEffect(() => {\n // Subscribe to room — use ref so handler is always current\n const unsubscribe = webSocketClient.subscribe(\n roomId,\n channel,\n (msg) => handlerRef.current(msg),\n {\n url,\n autoReconnect,\n reconnectInterval,\n maxReconnectAttempts,\n onConnect: () => {\n setIsConnected(true);\n setIsConnecting(false);\n setIsError(false);\n setError(undefined);\n onConnect?.();\n },\n onDisconnect: () => {\n setIsConnected(false);\n setIsConnecting(false);\n onDisconnect?.();\n },\n onError: (err) => {\n setIsError(true);\n setError(err);\n setIsConnecting(false);\n onError?.(err);\n },\n },\n );\n\n unsubscribeRef.current = unsubscribe;\n\n // Get initial state from connection\n const connection = webSocketClient.getConnection(channel);\n if (connection) {\n setIsConnected(connection.isConnected);\n setIsConnecting(connection.isConnecting);\n setIsError(connection.isError);\n setError(connection.error);\n }\n\n // Cleanup on unmount or deps change\n return () => {\n unsubscribe();\n unsubscribeRef.current = null;\n };\n }, deps);\n\n const alepha = useAlepha();\n\n if (!alepha.isBrowser()) {\n return {\n send: async (_message: Static<TServer>) => {\n // No-op on server\n },\n isConnected: false,\n isConnecting: false,\n isError: false,\n error: undefined,\n reconnect: () => {\n // No-op on server\n },\n disconnect: () => {\n // No-op on server\n },\n };\n }\n\n return {\n send: async (message: Static<TServer>) => {\n await webSocketClient.send(roomId, channel, message);\n },\n isConnected,\n isConnecting,\n isError,\n error,\n reconnect: () => {\n const connection = webSocketClient.getConnection(channel);\n connection?.reconnect();\n },\n disconnect: () => {\n unsubscribeRef.current?.();\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuIA,MAAa,WACX,SACA,SAC2B;CAC3B,MAAM,kBAAkB,UAAU,gBAAgB;CAClD,MAAM,iBAAiB,OAA4B,KAAK;CAExD,MAAM,CAAC,aAAa,kBAAkB,SAAS,MAAM;CACrD,MAAM,CAAC,cAAc,mBAAmB,SAAS,MAAM;CACvD,MAAM,CAAC,SAAS,cAAc,SAAS,MAAM;CAC7C,MAAM,CAAC,OAAO,YAAY,SAA4B,KAAA,EAAU;CAEhE,MAAM,EACJ,QACA,SACA,SACA,KACA,eACA,mBACA,sBACA,WACA,cACA,YACE;CAGJ,MAAM,aAAa,OAAO,QAAQ;AAClC,YAAW,UAAU;AAErB,iBAAgB;EAEd,MAAM,cAAc,gBAAgB,UAClC,QACA,UACC,QAAQ,WAAW,QAAQ,IAAI,EAChC;GACE;GACA;GACA;GACA;GACA,iBAAiB;AACf,mBAAe,KAAK;AACpB,oBAAgB,MAAM;AACtB,eAAW,MAAM;AACjB,aAAS,KAAA,EAAU;AACnB,iBAAa;;GAEf,oBAAoB;AAClB,mBAAe,MAAM;AACrB,oBAAgB,MAAM;AACtB,oBAAgB;;GAElB,UAAU,QAAQ;AAChB,eAAW,KAAK;AAChB,aAAS,IAAI;AACb,oBAAgB,MAAM;AACtB,cAAU,IAAI;;GAEjB,CACF;AAED,iBAAe,UAAU;EAGzB,MAAM,aAAa,gBAAgB,cAAc,QAAQ;AACzD,MAAI,YAAY;AACd,kBAAe,WAAW,YAAY;AACtC,mBAAgB,WAAW,aAAa;AACxC,cAAW,WAAW,QAAQ;AAC9B,YAAS,WAAW,MAAM;;AAI5B,eAAa;AACX,gBAAa;AACb,kBAAe,UAAU;;IAE1B,KAAK;AAIR,KAAI,CAFW,WAEJ,CAAC,WAAW,CACrB,QAAO;EACL,MAAM,OAAO,aAA8B;EAG3C,aAAa;EACb,cAAc;EACd,SAAS;EACT,OAAO,KAAA;EACP,iBAAiB;EAGjB,kBAAkB;EAGnB;AAGH,QAAO;EACL,MAAM,OAAO,YAA6B;AACxC,SAAM,gBAAgB,KAAK,QAAQ,SAAS,QAAQ;;EAEtD;EACA;EACA;EACA;EACA,iBAAiB;AACI,mBAAgB,cAAc,QACvC,EAAE,WAAW;;EAEzB,kBAAkB;AAChB,kBAAe,WAAW;;EAE7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["envSchema"],"sources":["../../src/redis/providers/RedisProvider.ts","../../src/redis/providers/BunRedisProvider.ts","../../src/redis/providers/RedisSubscriberProvider.ts","../../src/redis/providers/BunRedisSubscriberProvider.ts","../../src/redis/providers/NodeRedisProvider.ts","../../src/redis/providers/NodeRedisSubscriberProvider.ts","../../src/redis/index.ts"],"sourcesContent":["/**\n * Abstract Redis provider interface.\n *\n * This abstract class defines the common interface for Redis operations.\n * Implementations include:\n * - {@link NodeRedisProvider} - Uses `@redis/client` for Node.js runtime\n * - {@link BunRedisProvider} - Uses Bun's native `RedisClient` for Bun runtime\n *\n * @example\n * ```ts\n * // Inject the abstract provider - runtime selects the implementation\n * const redis = alepha.inject(RedisProvider);\n *\n * // Use common operations\n * await redis.set(\"key\", \"value\");\n * const value = await redis.get(\"key\");\n * ```\n */\nexport abstract class RedisProvider {\n /**\n * Whether the Redis client is ready to accept commands.\n */\n public abstract readonly isReady: boolean;\n\n /**\n * Connect to the Redis server.\n */\n public abstract connect(): Promise<void>;\n\n /**\n * Close the connection to the Redis server.\n */\n public abstract close(): Promise<void>;\n\n /**\n * Get the value of a key.\n *\n * @param key The key to get.\n * @returns The value as a Buffer, or undefined if the key does not exist.\n */\n public abstract get(key: string): Promise<Buffer | undefined>;\n\n /**\n * Set the value of a key.\n *\n * @param key The key to set.\n * @param value The value to set (Buffer or string).\n * @param options Optional set options (EX, PX, NX, XX, etc.).\n * @returns The value as a Buffer.\n */\n public abstract set(\n key: string,\n value: Buffer | string,\n options?: RedisSetOptions,\n ): Promise<Buffer>;\n\n /**\n * Check if a key exists.\n *\n * @param key The key to check.\n * @returns True if the key exists.\n */\n public abstract has(key: string): Promise<boolean>;\n\n /**\n * Get all keys matching a pattern.\n *\n * @param pattern The glob-style pattern to match.\n * @returns Array of matching key names.\n */\n public abstract keys(pattern: string): Promise<string[]>;\n\n /**\n * Delete one or more keys.\n *\n * @param keys The keys to delete.\n */\n public abstract del(keys: string[]): Promise<void>;\n\n // ---------------------------------------------------------\n // Queue operations (for alepha/queue-redis)\n // ---------------------------------------------------------\n\n /**\n * Push a value to the left (head) of a list.\n *\n * @param key The list key.\n * @param value The value to push.\n */\n public abstract lpush(key: string, value: string): Promise<void>;\n\n /**\n * Pop a value from the right (tail) of a list.\n *\n * @param key The list key.\n * @returns The value, or undefined if the list is empty.\n */\n public abstract rpop(key: string): Promise<string | undefined>;\n\n // ---------------------------------------------------------\n // Pub/Sub operations (for alepha/topic-redis)\n // ---------------------------------------------------------\n\n /**\n * Publish a message to a channel.\n *\n * @param channel The channel name.\n * @param message The message to publish.\n */\n public abstract publish(channel: string, message: string): Promise<void>;\n\n // ---------------------------------------------------------\n // Counter operations\n // ---------------------------------------------------------\n\n /**\n * Increment the integer value of a key by the given amount.\n *\n * If the key does not exist, it is set to 0 before performing the operation.\n * This operation is atomic.\n *\n * @param key The key to increment.\n * @param amount The amount to increment by.\n * @returns The new value after incrementing.\n */\n public abstract incr(key: string, amount: number): Promise<number>;\n}\n\n/**\n * Common Redis SET command options.\n * Compatible with @redis/client SetOptions format.\n */\nexport interface RedisSetOptions {\n /**\n * Set the specified expire time, in seconds.\n */\n EX?: number;\n /**\n * Set the specified expire time, in milliseconds.\n */\n PX?: number;\n /**\n * Set the specified Unix time at which the key will expire, in seconds.\n */\n EXAT?: number;\n /**\n * Set the specified Unix time at which the key will expire, in milliseconds.\n */\n PXAT?: number;\n /**\n * Only set the key if it does not already exist.\n */\n NX?: boolean;\n /**\n * Only set the key if it already exists.\n */\n XX?: boolean;\n /**\n * Retain the time to live associated with the key.\n */\n KEEPTTL?: boolean;\n /**\n * Return the old string stored at key, or nil if key did not exist.\n */\n GET?: boolean;\n /**\n * Alternative expiration format (compatible with @redis/client).\n */\n expiration?: {\n type: \"EX\" | \"PX\" | \"EXAT\" | \"PXAT\" | \"KEEPTTL\";\n value: number;\n };\n /**\n * Alternative condition format (compatible with @redis/client).\n */\n condition?: \"NX\" | \"XX\";\n}\n","import {\n $env,\n $hook,\n $inject,\n Alepha,\n AlephaError,\n type Static,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { RedisProvider, type RedisSetOptions } from \"./RedisProvider.ts\";\n\nconst envSchema = t.object({\n REDIS_URL: t.text({\n default: \"redis://localhost:6379\",\n description: \"Redis connection URL\",\n }),\n});\n\ndeclare module \"alepha\" {\n interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\n/**\n * Bun Redis client provider using Bun's native Redis client.\n *\n * This provider uses Bun's built-in `RedisClient` class for Redis connections,\n * which provides excellent performance (7.9x faster than ioredis) on the Bun runtime.\n *\n * @example\n * ```ts\n * // Set REDIS_URL environment variable (default: redis://localhost:6379)\n * // REDIS_URL=redis://:password@myredis.example.com:6379\n *\n * // Or configure programmatically\n * alepha.with({\n * provide: RedisProvider,\n * use: BunRedisProvider,\n * });\n * ```\n */\nexport class BunRedisProvider extends RedisProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly env = $env(envSchema);\n protected client?: Bun.RedisClient;\n\n public get publisher(): Bun.RedisClient {\n if (!this.client?.connected) {\n throw new AlephaError(\"Redis client is not ready\");\n }\n\n return this.client;\n }\n\n public override get isReady(): boolean {\n return this.client?.connected ?? false;\n }\n\n protected readonly start = $hook({\n on: \"start\",\n handler: () => this.connect(),\n });\n\n protected readonly stop = $hook({\n on: \"stop\",\n handler: () => this.close(),\n });\n\n /**\n * Connect to the Redis server.\n */\n public override async connect(): Promise<void> {\n // Check if we're running in Bun\n if (!this.alepha.isBun()) {\n throw new AlephaError(\n \"BunRedisProvider requires the Bun runtime. Use NodeRedisProvider for Node.js.\",\n );\n }\n\n this.log.debug(\"Connecting...\");\n\n this.client = new Bun.RedisClient(this.getUrl(), {\n autoReconnect: true,\n enableAutoPipelining: true,\n });\n\n this.client.onconnect = () => {\n this.log.trace(\"Redis connected\");\n };\n\n this.client.onclose = (error) => {\n if (this.alepha.isStarted() && error) {\n this.log.error(\"Redis connection closed\", error);\n }\n };\n\n await this.client.connect();\n\n this.log.info(\"Connection OK\");\n }\n\n /**\n * Close the connection to the Redis server.\n */\n public override async close(): Promise<void> {\n if (this.client) {\n this.log.debug(\"Closing connection...\");\n this.client.close();\n this.client = undefined;\n this.log.info(\"Connection closed\");\n }\n }\n\n /**\n * Create a duplicate connection for pub/sub or other isolated operations.\n */\n public async duplicate(): Promise<Bun.RedisClient> {\n if (typeof Bun === \"undefined\") {\n throw new AlephaError(\"BunRedisProvider requires the Bun runtime.\");\n }\n\n const client = new Bun.RedisClient(this.getUrl(), {\n autoReconnect: true,\n enableAutoPipelining: true,\n });\n\n client.onclose = (error) => {\n if (this.alepha.isStarted() && error) {\n this.log.error(\"Redis duplicate connection closed\", error);\n }\n };\n\n await client.connect();\n\n return client;\n }\n\n public override async get(key: string): Promise<Buffer | undefined> {\n this.log.trace(`Getting key ${key}`);\n const resp = await this.publisher.getBuffer(key);\n\n if (resp === null) {\n return undefined;\n }\n\n return Buffer.from(resp);\n }\n\n public override async set(\n key: string,\n value: Buffer | string,\n options?: RedisSetOptions,\n ): Promise<Buffer> {\n const buf = Buffer.isBuffer(value) ? value : Buffer.from(value, \"utf-8\");\n\n // Build SET command arguments\n const args: string[] = [key, buf.toString(\"binary\")];\n\n // Handle expiration object format (from alepha/cache-redis, alepha/lock-redis)\n if (options?.expiration) {\n if (options.expiration.type === \"KEEPTTL\") {\n args.push(\"KEEPTTL\");\n } else {\n args.push(options.expiration.type, String(options.expiration.value));\n }\n }\n\n // Handle direct expiration properties\n if (options?.EX !== undefined) {\n args.push(\"EX\", String(options.EX));\n }\n if (options?.PX !== undefined) {\n args.push(\"PX\", String(options.PX));\n }\n if (options?.EXAT !== undefined) {\n args.push(\"EXAT\", String(options.EXAT));\n }\n if (options?.PXAT !== undefined) {\n args.push(\"PXAT\", String(options.PXAT));\n }\n if (options?.KEEPTTL) {\n args.push(\"KEEPTTL\");\n }\n\n // Handle condition object format\n if (options?.condition === \"NX\") {\n args.push(\"NX\");\n } else if (options?.condition === \"XX\") {\n args.push(\"XX\");\n }\n\n // Handle direct condition properties\n if (options?.NX) {\n args.push(\"NX\");\n }\n if (options?.XX) {\n args.push(\"XX\");\n }\n if (options?.GET) {\n args.push(\"GET\");\n }\n\n if (args.length === 2) {\n // Simple set without options\n await this.publisher.set(key, buf);\n } else {\n // Set with options via raw command\n await this.publisher.send(\"SET\", args);\n }\n\n return buf;\n }\n\n public override async has(key: string): Promise<boolean> {\n return this.publisher.exists(key);\n }\n\n public override async keys(pattern: string): Promise<string[]> {\n const keys = await this.publisher.send(\"KEYS\", [pattern]);\n if (!Array.isArray(keys)) {\n return [];\n }\n return keys.map((key) =>\n key instanceof Uint8Array ? Buffer.from(key).toString() : String(key),\n );\n }\n\n public override async del(keys: string[]): Promise<void> {\n if (keys.length === 0) {\n return;\n }\n\n await this.publisher.send(\"DEL\", keys);\n }\n\n // ---------------------------------------------------------\n // Queue operations\n // ---------------------------------------------------------\n\n public override async lpush(key: string, value: string): Promise<void> {\n await this.publisher.send(\"LPUSH\", [key, value]);\n }\n\n public override async rpop(key: string): Promise<string | undefined> {\n const value = await this.publisher.send(\"RPOP\", [key]);\n if (value == null) {\n return undefined;\n }\n if (value instanceof Uint8Array) {\n return Buffer.from(value).toString();\n }\n return String(value);\n }\n\n // ---------------------------------------------------------\n // Pub/Sub operations\n // ---------------------------------------------------------\n\n public override async publish(\n channel: string,\n message: string,\n ): Promise<void> {\n await this.publisher.publish(channel, message);\n }\n\n // ---------------------------------------------------------\n // Counter operations\n // ---------------------------------------------------------\n\n public override async incr(key: string, amount: number): Promise<number> {\n const result = await this.publisher.send(\"INCRBY\", [key, String(amount)]);\n return Number(result);\n }\n\n /**\n * Get the Redis connection URL.\n */\n protected getUrl(): string {\n return this.env.REDIS_URL;\n }\n}\n","/**\n * Abstract Redis subscriber provider interface.\n *\n * This abstract class defines the common interface for Redis pub/sub subscriptions.\n * Implementations include:\n * - {@link NodeRedisSubscriberProvider} - Uses `@redis/client` for Node.js runtime\n * - {@link BunRedisSubscriberProvider} - Uses Bun's native `RedisClient` for Bun runtime\n *\n * Redis requires separate connections for pub/sub operations, so this provider\n * creates a dedicated connection for subscriptions.\n *\n * @example\n * ```ts\n * // Inject the abstract provider - runtime selects the implementation\n * const subscriber = alepha.inject(RedisSubscriberProvider);\n *\n * // Subscribe to a channel\n * await subscriber.subscribe(\"my-channel\", (message, channel) => {\n * console.log(`Received: ${message} on ${channel}`);\n * });\n * ```\n */\nexport abstract class RedisSubscriberProvider {\n /**\n * Whether the Redis subscriber client is ready to accept commands.\n */\n public abstract readonly isReady: boolean;\n\n /**\n * Connect to the Redis server for subscriptions.\n */\n public abstract connect(): Promise<void>;\n\n /**\n * Close the subscriber connection.\n */\n public abstract close(): Promise<void>;\n\n /**\n * Subscribe to a channel.\n *\n * @param channel The channel name.\n * @param callback The callback to invoke when a message is received.\n */\n public abstract subscribe(\n channel: string,\n callback: SubscribeCallback,\n ): Promise<void>;\n\n /**\n * Unsubscribe from a channel.\n *\n * @param channel The channel name.\n * @param callback Optional specific callback to remove.\n */\n public abstract unsubscribe(\n channel: string,\n callback?: SubscribeCallback,\n ): Promise<void>;\n}\n\n/**\n * Callback for subscription messages.\n */\nexport type SubscribeCallback = (message: string, channel: string) => void;\n","import { $hook, $inject, Alepha, AlephaError } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { BunRedisProvider } from \"./BunRedisProvider.ts\";\nimport {\n RedisSubscriberProvider,\n type SubscribeCallback,\n} from \"./RedisSubscriberProvider.ts\";\n\n/**\n * Bun Redis subscriber provider for pub/sub operations.\n *\n * This provider creates a dedicated Redis connection for subscriptions,\n * as Redis requires separate connections for pub/sub operations.\n *\n * @example\n * ```ts\n * const subscriber = alepha.inject(RedisSubscriberProvider);\n * await subscriber.subscribe(\"channel\", (message, channel) => {\n * console.log(`Received: ${message} on ${channel}`);\n * });\n * ```\n */\nexport class BunRedisSubscriberProvider extends RedisSubscriberProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly redisProvider = $inject(BunRedisProvider);\n protected client?: Bun.RedisClient;\n\n public get subscriber(): Bun.RedisClient {\n if (!this.client?.connected) {\n throw new AlephaError(\"Redis subscriber client is not ready\");\n }\n\n return this.client;\n }\n\n public override get isReady(): boolean {\n return this.client?.connected ?? false;\n }\n\n protected readonly start = $hook({\n on: \"start\",\n handler: () => this.connect(),\n });\n\n protected readonly stop = $hook({\n on: \"stop\",\n handler: () => this.close(),\n });\n\n /**\n * Connect to the Redis server for subscriptions.\n */\n public override async connect(): Promise<void> {\n this.log.debug(\"Connecting subscriber...\");\n this.client = await this.redisProvider.duplicate();\n this.log.info(\"Subscriber connection OK\");\n }\n\n /**\n * Close the subscriber connection.\n */\n public override async close(): Promise<void> {\n if (this.client) {\n this.log.debug(\"Closing subscriber connection...\");\n this.client.close();\n this.client = undefined;\n this.log.info(\"Subscriber connection closed\");\n }\n }\n\n public override async subscribe(\n channel: string,\n callback: SubscribeCallback,\n ): Promise<void> {\n await this.subscriber.subscribe(channel, (message, ch) => {\n // Bun's callback provides Buffer or string, normalize to string\n const msg =\n typeof message === \"object\" && message !== null\n ? Buffer.from(message as Uint8Array).toString()\n : String(message);\n callback(msg, ch);\n });\n }\n\n public override async unsubscribe(\n channel: string,\n _callback?: SubscribeCallback,\n ): Promise<void> {\n // Bun's unsubscribe doesn't support callback filtering\n await this.subscriber.unsubscribe(channel);\n }\n}\n","import {\n createClient,\n RESP_TYPES,\n type RedisClientType,\n type SetOptions,\n} from \"@redis/client\";\nimport {\n $env,\n $hook,\n $inject,\n Alepha,\n AlephaError,\n type Static,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { RedisProvider, type RedisSetOptions } from \"./RedisProvider.ts\";\n\nconst envSchema = t.object({\n REDIS_URL: t.text({\n default: \"redis://localhost:6379\",\n description: \"Redis connection URL\",\n }),\n});\n\ndeclare module \"alepha\" {\n interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\nexport type NodeRedisClient = RedisClientType<\n {},\n {},\n {},\n 3,\n { 36: BufferConstructor }\n>;\nexport type NodeRedisClientOptions = Parameters<typeof createClient>[0];\n\n/**\n * Node.js Redis client provider using `@redis/client`.\n *\n * This provider uses the official Redis client for Node.js runtime.\n *\n * @example\n * ```ts\n * // Set REDIS_URL environment variable (default: redis://localhost:6379)\n * // REDIS_URL=redis://:password@myredis.example.com:6379\n *\n * // Or configure programmatically\n * alepha.with({\n * provide: RedisProvider,\n * use: NodeRedisProvider,\n * });\n * ```\n */\nexport class NodeRedisProvider extends RedisProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly env = $env(envSchema);\n protected readonly client = this.createClient();\n\n public get publisher(): NodeRedisClient {\n if (!this.client.isReady) {\n throw new AlephaError(\"Redis client is not ready\");\n }\n\n return this.client;\n }\n\n public override get isReady(): boolean {\n return this.client.isReady;\n }\n\n protected readonly start = $hook({\n on: \"start\",\n handler: () => this.connect(),\n });\n\n protected readonly stop = $hook({\n on: \"stop\",\n handler: () => this.close(),\n });\n\n /**\n * Connect to the Redis server.\n */\n public override async connect(): Promise<void> {\n this.log.debug(\"Connecting...\");\n await this.client.connect();\n this.log.info(\"Connection OK\");\n }\n\n /**\n * Close the connection to the Redis server.\n */\n public override async close(): Promise<void> {\n this.log.debug(\"Closing connection...\");\n await this.client.close();\n this.log.info(\"Connection closed\");\n }\n\n public duplicate(options?: Partial<NodeRedisClientOptions>): NodeRedisClient {\n return this.client\n .duplicate({\n ...options,\n RESP: 3,\n })\n .withTypeMapping({\n [RESP_TYPES.BLOB_STRING]: Buffer,\n });\n }\n\n public override async get(key: string): Promise<Buffer | undefined> {\n this.log.trace(`Getting key ${key}`);\n const resp = await this.publisher.get(key);\n\n if (resp === null) {\n return undefined;\n }\n\n return Buffer.from(resp);\n }\n\n public override async set(\n key: string,\n value: Buffer | string,\n options?: RedisSetOptions,\n ): Promise<Buffer> {\n const buf = Buffer.isBuffer(value) ? value : Buffer.from(value, \"utf-8\");\n\n // Convert RedisSetOptions to @redis/client SetOptions\n const setOptions: SetOptions = {};\n\n // Handle expiration object format (from alepha/cache-redis, alepha/lock-redis)\n if (options?.expiration) {\n if (options.expiration.type === \"KEEPTTL\") {\n setOptions.KEEPTTL = true;\n } else {\n setOptions[options.expiration.type] = options.expiration.value;\n }\n }\n\n // Handle direct expiration properties\n if (options?.EX !== undefined) {\n setOptions.EX = options.EX;\n }\n if (options?.PX !== undefined) {\n setOptions.PX = options.PX;\n }\n if (options?.EXAT !== undefined) {\n setOptions.EXAT = options.EXAT;\n }\n if (options?.PXAT !== undefined) {\n setOptions.PXAT = options.PXAT;\n }\n if (options?.KEEPTTL) {\n setOptions.KEEPTTL = true;\n }\n\n // Handle condition object format\n if (options?.condition === \"NX\") {\n setOptions.NX = true;\n } else if (options?.condition === \"XX\") {\n setOptions.XX = true;\n }\n\n // Handle direct condition properties\n if (options?.NX) {\n setOptions.NX = true;\n }\n if (options?.XX) {\n setOptions.XX = true;\n }\n if (options?.GET) {\n setOptions.GET = true;\n }\n\n const resp = await this.publisher.set(\n key,\n buf,\n Object.keys(setOptions).length > 0 ? setOptions : undefined,\n );\n\n if (resp === \"OK\" || !resp) {\n return buf;\n }\n\n return Buffer.from(resp);\n }\n\n public override async has(key: string): Promise<boolean> {\n const resp = await this.publisher.exists(key);\n return resp > 0;\n }\n\n public override async keys(pattern: string): Promise<string[]> {\n const keys = await this.publisher.keys(pattern);\n return keys.map((key) => key.toString());\n }\n\n public override async del(keys: string[]): Promise<void> {\n if (keys.length === 0) {\n return;\n }\n\n await this.publisher.del(keys);\n }\n\n // ---------------------------------------------------------\n // Queue operations\n // ---------------------------------------------------------\n\n public override async lpush(key: string, value: string): Promise<void> {\n await this.publisher.LPUSH(key, value);\n }\n\n public override async rpop(key: string): Promise<string | undefined> {\n const value = await this.publisher.RPOP(key);\n if (value == null) {\n return undefined;\n }\n return String(value);\n }\n\n // ---------------------------------------------------------\n // Pub/Sub operations\n // ---------------------------------------------------------\n\n public override async publish(\n channel: string,\n message: string,\n ): Promise<void> {\n await this.publisher.publish(channel, message);\n }\n\n // ---------------------------------------------------------\n // Counter operations\n // ---------------------------------------------------------\n\n public override async incr(key: string, amount: number): Promise<number> {\n return this.publisher.INCRBY(key, amount);\n }\n\n /**\n * Get the Redis connection URL.\n */\n protected getUrl(): string {\n return this.env.REDIS_URL;\n }\n\n /**\n * Redis client factory method.\n */\n protected createClient(): NodeRedisClient {\n const client = createClient({\n url: this.getUrl(),\n RESP: 3,\n }).withTypeMapping({\n [RESP_TYPES.BLOB_STRING]: Buffer,\n });\n\n client.on(\"error\", (error) => {\n if (this.alepha.isStarted()) {\n this.log.error(error);\n }\n });\n\n return client;\n }\n}\n","import { $hook, $inject, Alepha, AlephaError } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport {\n type NodeRedisClient,\n NodeRedisProvider,\n} from \"./NodeRedisProvider.ts\";\nimport {\n RedisSubscriberProvider,\n type SubscribeCallback,\n} from \"./RedisSubscriberProvider.ts\";\n\n/**\n * Node.js Redis subscriber provider using `@redis/client`.\n *\n * This provider creates a dedicated Redis connection for subscriptions,\n * as Redis requires separate connections for pub/sub operations.\n *\n * @example\n * ```ts\n * const subscriber = alepha.inject(RedisSubscriberProvider);\n * await subscriber.subscribe(\"channel\", (message, channel) => {\n * console.log(`Received: ${message} on ${channel}`);\n * });\n * ```\n */\nexport class NodeRedisSubscriberProvider extends RedisSubscriberProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly redisProvider = $inject(NodeRedisProvider);\n protected readonly client: NodeRedisClient = this.createClient();\n\n public get subscriber(): NodeRedisClient {\n if (!this.client.isReady) {\n throw new AlephaError(\"Redis subscriber client is not ready\");\n }\n\n return this.client;\n }\n\n public override get isReady(): boolean {\n return this.client.isReady;\n }\n\n protected readonly start = $hook({\n on: \"start\",\n handler: () => this.connect(),\n });\n\n protected readonly stop = $hook({\n on: \"stop\",\n handler: () => this.close(),\n });\n\n public override async connect(): Promise<void> {\n this.log.debug(\"Connecting subscriber...\");\n await this.client.connect();\n this.log.info(\"Subscriber connection OK\");\n }\n\n public override async close(): Promise<void> {\n if (!this.client.isReady) {\n this.log.debug(\"Subscriber client not ready, skipping close\");\n return;\n }\n this.log.debug(\"Closing subscriber connection...\");\n await this.client.close();\n this.log.info(\"Subscriber connection closed\");\n }\n\n public override async subscribe(\n channel: string,\n callback: SubscribeCallback,\n ): Promise<void> {\n await this.subscriber.subscribe(channel, callback);\n }\n\n public override async unsubscribe(\n channel: string,\n callback?: SubscribeCallback,\n ): Promise<void> {\n await this.subscriber.unsubscribe(channel, callback);\n }\n\n /**\n * Redis subscriber client factory method.\n */\n protected createClient(): NodeRedisClient {\n const client = this.redisProvider.duplicate();\n\n client.on(\"error\", (error) => {\n if (this.alepha.isStarted()) {\n this.log.error(error);\n }\n });\n\n return client;\n }\n}\n","import { $module, type Alepha } from \"alepha\";\nimport { BunRedisProvider } from \"./providers/BunRedisProvider.ts\";\nimport { BunRedisSubscriberProvider } from \"./providers/BunRedisSubscriberProvider.ts\";\nimport { NodeRedisProvider } from \"./providers/NodeRedisProvider.ts\";\nimport { NodeRedisSubscriberProvider } from \"./providers/NodeRedisSubscriberProvider.ts\";\nimport { RedisProvider } from \"./providers/RedisProvider.ts\";\nimport { RedisSubscriberProvider } from \"./providers/RedisSubscriberProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./providers/BunRedisProvider.ts\";\nexport * from \"./providers/BunRedisSubscriberProvider.ts\";\nexport * from \"./providers/NodeRedisProvider.ts\";\nexport * from \"./providers/NodeRedisSubscriberProvider.ts\";\nexport * from \"./providers/RedisProvider.ts\";\nexport * from \"./providers/RedisSubscriberProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Redis client wrapper.\n *\n * **Features:**\n * - Connection pooling\n * - Automatic reconnection\n * - Command pipelining\n * - Pub/sub support\n *\n * @module alepha.redis\n */\nexport const AlephaRedis = $module({\n name: \"alepha.redis\",\n services: [RedisProvider, RedisSubscriberProvider],\n variants: [\n NodeRedisProvider,\n NodeRedisSubscriberProvider,\n BunRedisProvider,\n BunRedisSubscriberProvider,\n ],\n register: (alepha: Alepha) => {\n if (alepha.isBun()) {\n alepha\n .with({\n provide: RedisProvider,\n use: BunRedisProvider,\n })\n .with({\n provide: RedisSubscriberProvider,\n use: BunRedisSubscriberProvider,\n });\n } else {\n alepha\n .with({\n provide: RedisProvider,\n use: NodeRedisProvider,\n })\n .with({\n provide: RedisSubscriberProvider,\n use: NodeRedisSubscriberProvider,\n });\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAkBA,IAAsB,gBAAtB,MAAoC;;;ACNpC,MAAMA,cAAY,EAAE,OAAO,EACzB,WAAW,EAAE,KAAK;CAChB,SAAS;CACT,aAAa;CACd,CAAC,EACH,CAAC;;;;;;;;;;;;;;;;;;;AAwBF,IAAa,mBAAb,cAAsC,cAAc;CAClD,MAAyB,SAAS;CAClC,SAA4B,QAAQ,OAAO;CAC3C,MAAyB,KAAKA,YAAU;CACxC;CAEA,IAAW,YAA6B;AACtC,MAAI,CAAC,KAAK,QAAQ,UAChB,OAAM,IAAI,YAAY,4BAA4B;AAGpD,SAAO,KAAK;;CAGd,IAAoB,UAAmB;AACrC,SAAO,KAAK,QAAQ,aAAa;;CAGnC,QAA2B,MAAM;EAC/B,IAAI;EACJ,eAAe,KAAK,SAAS;EAC9B,CAAC;CAEF,OAA0B,MAAM;EAC9B,IAAI;EACJ,eAAe,KAAK,OAAO;EAC5B,CAAC;;;;CAKF,MAAsB,UAAyB;AAE7C,MAAI,CAAC,KAAK,OAAO,OAAO,CACtB,OAAM,IAAI,YACR,gFACD;AAGH,OAAK,IAAI,MAAM,gBAAgB;AAE/B,OAAK,SAAS,IAAI,IAAI,YAAY,KAAK,QAAQ,EAAE;GAC/C,eAAe;GACf,sBAAsB;GACvB,CAAC;AAEF,OAAK,OAAO,kBAAkB;AAC5B,QAAK,IAAI,MAAM,kBAAkB;;AAGnC,OAAK,OAAO,WAAW,UAAU;AAC/B,OAAI,KAAK,OAAO,WAAW,IAAI,MAC7B,MAAK,IAAI,MAAM,2BAA2B,MAAM;;AAIpD,QAAM,KAAK,OAAO,SAAS;AAE3B,OAAK,IAAI,KAAK,gBAAgB;;;;;CAMhC,MAAsB,QAAuB;AAC3C,MAAI,KAAK,QAAQ;AACf,QAAK,IAAI,MAAM,wBAAwB;AACvC,QAAK,OAAO,OAAO;AACnB,QAAK,SAAS,KAAA;AACd,QAAK,IAAI,KAAK,oBAAoB;;;;;;CAOtC,MAAa,YAAsC;AACjD,MAAI,OAAO,QAAQ,YACjB,OAAM,IAAI,YAAY,6CAA6C;EAGrE,MAAM,SAAS,IAAI,IAAI,YAAY,KAAK,QAAQ,EAAE;GAChD,eAAe;GACf,sBAAsB;GACvB,CAAC;AAEF,SAAO,WAAW,UAAU;AAC1B,OAAI,KAAK,OAAO,WAAW,IAAI,MAC7B,MAAK,IAAI,MAAM,qCAAqC,MAAM;;AAI9D,QAAM,OAAO,SAAS;AAEtB,SAAO;;CAGT,MAAsB,IAAI,KAA0C;AAClE,OAAK,IAAI,MAAM,eAAe,MAAM;EACpC,MAAM,OAAO,MAAM,KAAK,UAAU,UAAU,IAAI;AAEhD,MAAI,SAAS,KACX;AAGF,SAAO,OAAO,KAAK,KAAK;;CAG1B,MAAsB,IACpB,KACA,OACA,SACiB;EACjB,MAAM,MAAM,OAAO,SAAS,MAAM,GAAG,QAAQ,OAAO,KAAK,OAAO,QAAQ;EAGxE,MAAM,OAAiB,CAAC,KAAK,IAAI,SAAS,SAAS,CAAC;AAGpD,MAAI,SAAS,WACX,KAAI,QAAQ,WAAW,SAAS,UAC9B,MAAK,KAAK,UAAU;MAEpB,MAAK,KAAK,QAAQ,WAAW,MAAM,OAAO,QAAQ,WAAW,MAAM,CAAC;AAKxE,MAAI,SAAS,OAAO,KAAA,EAClB,MAAK,KAAK,MAAM,OAAO,QAAQ,GAAG,CAAC;AAErC,MAAI,SAAS,OAAO,KAAA,EAClB,MAAK,KAAK,MAAM,OAAO,QAAQ,GAAG,CAAC;AAErC,MAAI,SAAS,SAAS,KAAA,EACpB,MAAK,KAAK,QAAQ,OAAO,QAAQ,KAAK,CAAC;AAEzC,MAAI,SAAS,SAAS,KAAA,EACpB,MAAK,KAAK,QAAQ,OAAO,QAAQ,KAAK,CAAC;AAEzC,MAAI,SAAS,QACX,MAAK,KAAK,UAAU;AAItB,MAAI,SAAS,cAAc,KACzB,MAAK,KAAK,KAAK;WACN,SAAS,cAAc,KAChC,MAAK,KAAK,KAAK;AAIjB,MAAI,SAAS,GACX,MAAK,KAAK,KAAK;AAEjB,MAAI,SAAS,GACX,MAAK,KAAK,KAAK;AAEjB,MAAI,SAAS,IACX,MAAK,KAAK,MAAM;AAGlB,MAAI,KAAK,WAAW,EAElB,OAAM,KAAK,UAAU,IAAI,KAAK,IAAI;MAGlC,OAAM,KAAK,UAAU,KAAK,OAAO,KAAK;AAGxC,SAAO;;CAGT,MAAsB,IAAI,KAA+B;AACvD,SAAO,KAAK,UAAU,OAAO,IAAI;;CAGnC,MAAsB,KAAK,SAAoC;EAC7D,MAAM,OAAO,MAAM,KAAK,UAAU,KAAK,QAAQ,CAAC,QAAQ,CAAC;AACzD,MAAI,CAAC,MAAM,QAAQ,KAAK,CACtB,QAAO,EAAE;AAEX,SAAO,KAAK,KAAK,QACf,eAAe,aAAa,OAAO,KAAK,IAAI,CAAC,UAAU,GAAG,OAAO,IAAI,CACtE;;CAGH,MAAsB,IAAI,MAA+B;AACvD,MAAI,KAAK,WAAW,EAClB;AAGF,QAAM,KAAK,UAAU,KAAK,OAAO,KAAK;;CAOxC,MAAsB,MAAM,KAAa,OAA8B;AACrE,QAAM,KAAK,UAAU,KAAK,SAAS,CAAC,KAAK,MAAM,CAAC;;CAGlD,MAAsB,KAAK,KAA0C;EACnE,MAAM,QAAQ,MAAM,KAAK,UAAU,KAAK,QAAQ,CAAC,IAAI,CAAC;AACtD,MAAI,SAAS,KACX;AAEF,MAAI,iBAAiB,WACnB,QAAO,OAAO,KAAK,MAAM,CAAC,UAAU;AAEtC,SAAO,OAAO,MAAM;;CAOtB,MAAsB,QACpB,SACA,SACe;AACf,QAAM,KAAK,UAAU,QAAQ,SAAS,QAAQ;;CAOhD,MAAsB,KAAK,KAAa,QAAiC;EACvE,MAAM,SAAS,MAAM,KAAK,UAAU,KAAK,UAAU,CAAC,KAAK,OAAO,OAAO,CAAC,CAAC;AACzE,SAAO,OAAO,OAAO;;;;;CAMvB,SAA2B;AACzB,SAAO,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjQpB,IAAsB,0BAAtB,MAA8C;;;;;;;;;;;;;;;;;ACA9C,IAAa,6BAAb,cAAgD,wBAAwB;CACtE,MAAyB,SAAS;CAClC,SAA4B,QAAQ,OAAO;CAC3C,gBAAmC,QAAQ,iBAAiB;CAC5D;CAEA,IAAW,aAA8B;AACvC,MAAI,CAAC,KAAK,QAAQ,UAChB,OAAM,IAAI,YAAY,uCAAuC;AAG/D,SAAO,KAAK;;CAGd,IAAoB,UAAmB;AACrC,SAAO,KAAK,QAAQ,aAAa;;CAGnC,QAA2B,MAAM;EAC/B,IAAI;EACJ,eAAe,KAAK,SAAS;EAC9B,CAAC;CAEF,OAA0B,MAAM;EAC9B,IAAI;EACJ,eAAe,KAAK,OAAO;EAC5B,CAAC;;;;CAKF,MAAsB,UAAyB;AAC7C,OAAK,IAAI,MAAM,2BAA2B;AAC1C,OAAK,SAAS,MAAM,KAAK,cAAc,WAAW;AAClD,OAAK,IAAI,KAAK,2BAA2B;;;;;CAM3C,MAAsB,QAAuB;AAC3C,MAAI,KAAK,QAAQ;AACf,QAAK,IAAI,MAAM,mCAAmC;AAClD,QAAK,OAAO,OAAO;AACnB,QAAK,SAAS,KAAA;AACd,QAAK,IAAI,KAAK,+BAA+B;;;CAIjD,MAAsB,UACpB,SACA,UACe;AACf,QAAM,KAAK,WAAW,UAAU,UAAU,SAAS,OAAO;AAMxD,YAHE,OAAO,YAAY,YAAY,YAAY,OACvC,OAAO,KAAK,QAAsB,CAAC,UAAU,GAC7C,OAAO,QAAQ,EACP,GAAG;IACjB;;CAGJ,MAAsB,YACpB,SACA,WACe;AAEf,QAAM,KAAK,WAAW,YAAY,QAAQ;;;;;ACxE9C,MAAM,YAAY,EAAE,OAAO,EACzB,WAAW,EAAE,KAAK;CAChB,SAAS;CACT,aAAa;CACd,CAAC,EACH,CAAC;;;;;;;;;;;;;;;;;;AAgCF,IAAa,oBAAb,cAAuC,cAAc;CACnD,MAAyB,SAAS;CAClC,SAA4B,QAAQ,OAAO;CAC3C,MAAyB,KAAK,UAAU;CACxC,SAA4B,KAAK,cAAc;CAE/C,IAAW,YAA6B;AACtC,MAAI,CAAC,KAAK,OAAO,QACf,OAAM,IAAI,YAAY,4BAA4B;AAGpD,SAAO,KAAK;;CAGd,IAAoB,UAAmB;AACrC,SAAO,KAAK,OAAO;;CAGrB,QAA2B,MAAM;EAC/B,IAAI;EACJ,eAAe,KAAK,SAAS;EAC9B,CAAC;CAEF,OAA0B,MAAM;EAC9B,IAAI;EACJ,eAAe,KAAK,OAAO;EAC5B,CAAC;;;;CAKF,MAAsB,UAAyB;AAC7C,OAAK,IAAI,MAAM,gBAAgB;AAC/B,QAAM,KAAK,OAAO,SAAS;AAC3B,OAAK,IAAI,KAAK,gBAAgB;;;;;CAMhC,MAAsB,QAAuB;AAC3C,OAAK,IAAI,MAAM,wBAAwB;AACvC,QAAM,KAAK,OAAO,OAAO;AACzB,OAAK,IAAI,KAAK,oBAAoB;;CAGpC,UAAiB,SAA4D;AAC3E,SAAO,KAAK,OACT,UAAU;GACT,GAAG;GACH,MAAM;GACP,CAAC,CACD,gBAAgB,GACd,WAAW,cAAc,QAC3B,CAAC;;CAGN,MAAsB,IAAI,KAA0C;AAClE,OAAK,IAAI,MAAM,eAAe,MAAM;EACpC,MAAM,OAAO,MAAM,KAAK,UAAU,IAAI,IAAI;AAE1C,MAAI,SAAS,KACX;AAGF,SAAO,OAAO,KAAK,KAAK;;CAG1B,MAAsB,IACpB,KACA,OACA,SACiB;EACjB,MAAM,MAAM,OAAO,SAAS,MAAM,GAAG,QAAQ,OAAO,KAAK,OAAO,QAAQ;EAGxE,MAAM,aAAyB,EAAE;AAGjC,MAAI,SAAS,WACX,KAAI,QAAQ,WAAW,SAAS,UAC9B,YAAW,UAAU;MAErB,YAAW,QAAQ,WAAW,QAAQ,QAAQ,WAAW;AAK7D,MAAI,SAAS,OAAO,KAAA,EAClB,YAAW,KAAK,QAAQ;AAE1B,MAAI,SAAS,OAAO,KAAA,EAClB,YAAW,KAAK,QAAQ;AAE1B,MAAI,SAAS,SAAS,KAAA,EACpB,YAAW,OAAO,QAAQ;AAE5B,MAAI,SAAS,SAAS,KAAA,EACpB,YAAW,OAAO,QAAQ;AAE5B,MAAI,SAAS,QACX,YAAW,UAAU;AAIvB,MAAI,SAAS,cAAc,KACzB,YAAW,KAAK;WACP,SAAS,cAAc,KAChC,YAAW,KAAK;AAIlB,MAAI,SAAS,GACX,YAAW,KAAK;AAElB,MAAI,SAAS,GACX,YAAW,KAAK;AAElB,MAAI,SAAS,IACX,YAAW,MAAM;EAGnB,MAAM,OAAO,MAAM,KAAK,UAAU,IAChC,KACA,KACA,OAAO,KAAK,WAAW,CAAC,SAAS,IAAI,aAAa,KAAA,EACnD;AAED,MAAI,SAAS,QAAQ,CAAC,KACpB,QAAO;AAGT,SAAO,OAAO,KAAK,KAAK;;CAG1B,MAAsB,IAAI,KAA+B;AAEvD,SADa,MAAM,KAAK,UAAU,OAAO,IAAI,GAC/B;;CAGhB,MAAsB,KAAK,SAAoC;AAE7D,UADa,MAAM,KAAK,UAAU,KAAK,QAAQ,EACnC,KAAK,QAAQ,IAAI,UAAU,CAAC;;CAG1C,MAAsB,IAAI,MAA+B;AACvD,MAAI,KAAK,WAAW,EAClB;AAGF,QAAM,KAAK,UAAU,IAAI,KAAK;;CAOhC,MAAsB,MAAM,KAAa,OAA8B;AACrE,QAAM,KAAK,UAAU,MAAM,KAAK,MAAM;;CAGxC,MAAsB,KAAK,KAA0C;EACnE,MAAM,QAAQ,MAAM,KAAK,UAAU,KAAK,IAAI;AAC5C,MAAI,SAAS,KACX;AAEF,SAAO,OAAO,MAAM;;CAOtB,MAAsB,QACpB,SACA,SACe;AACf,QAAM,KAAK,UAAU,QAAQ,SAAS,QAAQ;;CAOhD,MAAsB,KAAK,KAAa,QAAiC;AACvE,SAAO,KAAK,UAAU,OAAO,KAAK,OAAO;;;;;CAM3C,SAA2B;AACzB,SAAO,KAAK,IAAI;;;;;CAMlB,eAA0C;EACxC,MAAM,SAAS,aAAa;GAC1B,KAAK,KAAK,QAAQ;GAClB,MAAM;GACP,CAAC,CAAC,gBAAgB,GAChB,WAAW,cAAc,QAC3B,CAAC;AAEF,SAAO,GAAG,UAAU,UAAU;AAC5B,OAAI,KAAK,OAAO,WAAW,CACzB,MAAK,IAAI,MAAM,MAAM;IAEvB;AAEF,SAAO;;;;;;;;;;;;;;;;;;;AClPX,IAAa,8BAAb,cAAiD,wBAAwB;CACvE,MAAyB,SAAS;CAClC,SAA4B,QAAQ,OAAO;CAC3C,gBAAmC,QAAQ,kBAAkB;CAC7D,SAA6C,KAAK,cAAc;CAEhE,IAAW,aAA8B;AACvC,MAAI,CAAC,KAAK,OAAO,QACf,OAAM,IAAI,YAAY,uCAAuC;AAG/D,SAAO,KAAK;;CAGd,IAAoB,UAAmB;AACrC,SAAO,KAAK,OAAO;;CAGrB,QAA2B,MAAM;EAC/B,IAAI;EACJ,eAAe,KAAK,SAAS;EAC9B,CAAC;CAEF,OAA0B,MAAM;EAC9B,IAAI;EACJ,eAAe,KAAK,OAAO;EAC5B,CAAC;CAEF,MAAsB,UAAyB;AAC7C,OAAK,IAAI,MAAM,2BAA2B;AAC1C,QAAM,KAAK,OAAO,SAAS;AAC3B,OAAK,IAAI,KAAK,2BAA2B;;CAG3C,MAAsB,QAAuB;AAC3C,MAAI,CAAC,KAAK,OAAO,SAAS;AACxB,QAAK,IAAI,MAAM,8CAA8C;AAC7D;;AAEF,OAAK,IAAI,MAAM,mCAAmC;AAClD,QAAM,KAAK,OAAO,OAAO;AACzB,OAAK,IAAI,KAAK,+BAA+B;;CAG/C,MAAsB,UACpB,SACA,UACe;AACf,QAAM,KAAK,WAAW,UAAU,SAAS,SAAS;;CAGpD,MAAsB,YACpB,SACA,UACe;AACf,QAAM,KAAK,WAAW,YAAY,SAAS,SAAS;;;;;CAMtD,eAA0C;EACxC,MAAM,SAAS,KAAK,cAAc,WAAW;AAE7C,SAAO,GAAG,UAAU,UAAU;AAC5B,OAAI,KAAK,OAAO,WAAW,CACzB,MAAK,IAAI,MAAM,MAAM;IAEvB;AAEF,SAAO;;;;;;;;;;;;;;;;ACjEX,MAAa,cAAc,QAAQ;CACjC,MAAM;CACN,UAAU,CAAC,eAAe,wBAAwB;CAClD,UAAU;EACR;EACA;EACA;EACA;EACD;CACD,WAAW,WAAmB;AAC5B,MAAI,OAAO,OAAO,CAChB,QACG,KAAK;GACJ,SAAS;GACT,KAAK;GACN,CAAC,CACD,KAAK;GACJ,SAAS;GACT,KAAK;GACN,CAAC;MAEJ,QACG,KAAK;GACJ,SAAS;GACT,KAAK;GACN,CAAC,CACD,KAAK;GACJ,SAAS;GACT,KAAK;GACN,CAAC;;CAGT,CAAC"}
1
+ {"version":3,"file":"index.js","names":["envSchema"],"sources":["../../src/redis/providers/RedisProvider.ts","../../src/redis/providers/BunRedisProvider.ts","../../src/redis/providers/RedisSubscriberProvider.ts","../../src/redis/providers/BunRedisSubscriberProvider.ts","../../src/redis/providers/NodeRedisProvider.ts","../../src/redis/providers/NodeRedisSubscriberProvider.ts","../../src/redis/index.ts"],"sourcesContent":["/**\n * Abstract Redis provider interface.\n *\n * This abstract class defines the common interface for Redis operations.\n * Implementations include:\n * - {@link NodeRedisProvider} - Uses `@redis/client` for Node.js runtime\n * - {@link BunRedisProvider} - Uses Bun's native `RedisClient` for Bun runtime\n *\n * @example\n * ```ts\n * // Inject the abstract provider - runtime selects the implementation\n * const redis = alepha.inject(RedisProvider);\n *\n * // Use common operations\n * await redis.set(\"key\", \"value\");\n * const value = await redis.get(\"key\");\n * ```\n */\nexport abstract class RedisProvider {\n /**\n * Whether the Redis client is ready to accept commands.\n */\n public abstract readonly isReady: boolean;\n\n /**\n * Connect to the Redis server.\n */\n public abstract connect(): Promise<void>;\n\n /**\n * Close the connection to the Redis server.\n */\n public abstract close(): Promise<void>;\n\n /**\n * Get the value of a key.\n *\n * @param key The key to get.\n * @returns The value as a Buffer, or undefined if the key does not exist.\n */\n public abstract get(key: string): Promise<Buffer | undefined>;\n\n /**\n * Set the value of a key.\n *\n * @param key The key to set.\n * @param value The value to set (Buffer or string).\n * @param options Optional set options (EX, PX, NX, XX, etc.).\n * @returns The value as a Buffer.\n */\n public abstract set(\n key: string,\n value: Buffer | string,\n options?: RedisSetOptions,\n ): Promise<Buffer>;\n\n /**\n * Check if a key exists.\n *\n * @param key The key to check.\n * @returns True if the key exists.\n */\n public abstract has(key: string): Promise<boolean>;\n\n /**\n * Get all keys matching a pattern.\n *\n * @param pattern The glob-style pattern to match.\n * @returns Array of matching key names.\n */\n public abstract keys(pattern: string): Promise<string[]>;\n\n /**\n * Delete one or more keys.\n *\n * @param keys The keys to delete.\n */\n public abstract del(keys: string[]): Promise<void>;\n\n // ---------------------------------------------------------\n // Queue operations (for alepha/queue-redis)\n // ---------------------------------------------------------\n\n /**\n * Push a value to the left (head) of a list.\n *\n * @param key The list key.\n * @param value The value to push.\n */\n public abstract lpush(key: string, value: string): Promise<void>;\n\n /**\n * Pop a value from the right (tail) of a list.\n *\n * @param key The list key.\n * @returns The value, or undefined if the list is empty.\n */\n public abstract rpop(key: string): Promise<string | undefined>;\n\n // ---------------------------------------------------------\n // Pub/Sub operations (for alepha/topic-redis)\n // ---------------------------------------------------------\n\n /**\n * Publish a message to a channel.\n *\n * @param channel The channel name.\n * @param message The message to publish.\n */\n public abstract publish(channel: string, message: string): Promise<void>;\n\n // ---------------------------------------------------------\n // Counter operations\n // ---------------------------------------------------------\n\n /**\n * Increment the integer value of a key by the given amount.\n *\n * If the key does not exist, it is set to 0 before performing the operation.\n * This operation is atomic.\n *\n * @param key The key to increment.\n * @param amount The amount to increment by.\n * @returns The new value after incrementing.\n */\n public abstract incr(key: string, amount: number): Promise<number>;\n}\n\n/**\n * Common Redis SET command options.\n * Compatible with @redis/client SetOptions format.\n */\nexport interface RedisSetOptions {\n /**\n * Set the specified expire time, in seconds.\n */\n EX?: number;\n /**\n * Set the specified expire time, in milliseconds.\n */\n PX?: number;\n /**\n * Set the specified Unix time at which the key will expire, in seconds.\n */\n EXAT?: number;\n /**\n * Set the specified Unix time at which the key will expire, in milliseconds.\n */\n PXAT?: number;\n /**\n * Only set the key if it does not already exist.\n */\n NX?: boolean;\n /**\n * Only set the key if it already exists.\n */\n XX?: boolean;\n /**\n * Retain the time to live associated with the key.\n */\n KEEPTTL?: boolean;\n /**\n * Return the old string stored at key, or nil if key did not exist.\n */\n GET?: boolean;\n /**\n * Alternative expiration format (compatible with @redis/client).\n */\n expiration?: {\n type: \"EX\" | \"PX\" | \"EXAT\" | \"PXAT\" | \"KEEPTTL\";\n value: number;\n };\n /**\n * Alternative condition format (compatible with @redis/client).\n */\n condition?: \"NX\" | \"XX\";\n}\n","import {\n $env,\n $hook,\n $inject,\n Alepha,\n AlephaError,\n type Static,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { RedisProvider, type RedisSetOptions } from \"./RedisProvider.ts\";\n\nconst envSchema = t.object({\n REDIS_URL: t.text({\n default: \"redis://localhost:6379\",\n description: \"Redis connection URL\",\n }),\n});\n\ndeclare module \"alepha\" {\n interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\n/**\n * Bun Redis client provider using Bun's native Redis client.\n *\n * This provider uses Bun's built-in `RedisClient` class for Redis connections,\n * which provides excellent performance (7.9x faster than ioredis) on the Bun runtime.\n *\n * @example\n * ```ts\n * // Set REDIS_URL environment variable (default: redis://localhost:6379)\n * // REDIS_URL=redis://:password@myredis.example.com:6379\n *\n * // Or configure programmatically\n * alepha.with({\n * provide: RedisProvider,\n * use: BunRedisProvider,\n * });\n * ```\n */\nexport class BunRedisProvider extends RedisProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly env = $env(envSchema);\n protected client?: Bun.RedisClient;\n\n public get publisher(): Bun.RedisClient {\n if (!this.client?.connected) {\n throw new AlephaError(\"Redis client is not ready\");\n }\n\n return this.client;\n }\n\n public override get isReady(): boolean {\n return this.client?.connected ?? false;\n }\n\n protected readonly start = $hook({\n on: \"start\",\n handler: () => this.connect(),\n });\n\n protected readonly stop = $hook({\n on: \"stop\",\n handler: () => this.close(),\n });\n\n /**\n * Connect to the Redis server.\n */\n public override async connect(): Promise<void> {\n // Check if we're running in Bun\n if (!this.alepha.isBun()) {\n throw new AlephaError(\n \"BunRedisProvider requires the Bun runtime. Use NodeRedisProvider for Node.js.\",\n );\n }\n\n this.log.debug(\"Connecting...\");\n\n this.client = new Bun.RedisClient(this.getUrl(), {\n autoReconnect: true,\n enableAutoPipelining: true,\n });\n\n this.client.onconnect = () => {\n this.log.trace(\"Redis connected\");\n };\n\n this.client.onclose = (error) => {\n if (this.alepha.isStarted() && error) {\n this.log.error(\"Redis connection closed\", error);\n }\n };\n\n await this.client.connect();\n\n this.log.info(\"Connection OK\");\n }\n\n /**\n * Close the connection to the Redis server.\n */\n public override async close(): Promise<void> {\n if (this.client) {\n this.log.debug(\"Closing connection...\");\n this.client.close();\n this.client = undefined;\n this.log.info(\"Connection closed\");\n }\n }\n\n /**\n * Create a duplicate connection for pub/sub or other isolated operations.\n */\n public async duplicate(): Promise<Bun.RedisClient> {\n if (typeof Bun === \"undefined\") {\n throw new AlephaError(\"BunRedisProvider requires the Bun runtime.\");\n }\n\n const client = new Bun.RedisClient(this.getUrl(), {\n autoReconnect: true,\n enableAutoPipelining: true,\n });\n\n client.onclose = (error) => {\n if (this.alepha.isStarted() && error) {\n this.log.error(\"Redis duplicate connection closed\", error);\n }\n };\n\n await client.connect();\n\n return client;\n }\n\n public override async get(key: string): Promise<Buffer | undefined> {\n this.log.trace(`Getting key ${key}`);\n const resp = await this.publisher.getBuffer(key);\n\n if (resp === null) {\n return undefined;\n }\n\n return Buffer.from(resp);\n }\n\n public override async set(\n key: string,\n value: Buffer | string,\n options?: RedisSetOptions,\n ): Promise<Buffer> {\n const buf = Buffer.isBuffer(value) ? value : Buffer.from(value, \"utf-8\");\n\n // Build SET command arguments\n const args: string[] = [key, buf.toString(\"binary\")];\n\n // Handle expiration object format (from alepha/cache-redis, alepha/lock-redis)\n if (options?.expiration) {\n if (options.expiration.type === \"KEEPTTL\") {\n args.push(\"KEEPTTL\");\n } else {\n args.push(options.expiration.type, String(options.expiration.value));\n }\n }\n\n // Handle direct expiration properties\n if (options?.EX !== undefined) {\n args.push(\"EX\", String(options.EX));\n }\n if (options?.PX !== undefined) {\n args.push(\"PX\", String(options.PX));\n }\n if (options?.EXAT !== undefined) {\n args.push(\"EXAT\", String(options.EXAT));\n }\n if (options?.PXAT !== undefined) {\n args.push(\"PXAT\", String(options.PXAT));\n }\n if (options?.KEEPTTL) {\n args.push(\"KEEPTTL\");\n }\n\n // Handle condition object format\n if (options?.condition === \"NX\") {\n args.push(\"NX\");\n } else if (options?.condition === \"XX\") {\n args.push(\"XX\");\n }\n\n // Handle direct condition properties\n if (options?.NX) {\n args.push(\"NX\");\n }\n if (options?.XX) {\n args.push(\"XX\");\n }\n if (options?.GET) {\n args.push(\"GET\");\n }\n\n if (args.length === 2) {\n // Simple set without options\n await this.publisher.set(key, buf);\n } else {\n // Set with options via raw command\n await this.publisher.send(\"SET\", args);\n }\n\n return buf;\n }\n\n public override async has(key: string): Promise<boolean> {\n return this.publisher.exists(key);\n }\n\n public override async keys(pattern: string): Promise<string[]> {\n const keys = await this.publisher.send(\"KEYS\", [pattern]);\n if (!Array.isArray(keys)) {\n return [];\n }\n return keys.map((key) =>\n key instanceof Uint8Array ? Buffer.from(key).toString() : String(key),\n );\n }\n\n public override async del(keys: string[]): Promise<void> {\n if (keys.length === 0) {\n return;\n }\n\n await this.publisher.send(\"DEL\", keys);\n }\n\n // ---------------------------------------------------------\n // Queue operations\n // ---------------------------------------------------------\n\n public override async lpush(key: string, value: string): Promise<void> {\n await this.publisher.send(\"LPUSH\", [key, value]);\n }\n\n public override async rpop(key: string): Promise<string | undefined> {\n const value = await this.publisher.send(\"RPOP\", [key]);\n if (value == null) {\n return undefined;\n }\n if (value instanceof Uint8Array) {\n return Buffer.from(value).toString();\n }\n return String(value);\n }\n\n // ---------------------------------------------------------\n // Pub/Sub operations\n // ---------------------------------------------------------\n\n public override async publish(\n channel: string,\n message: string,\n ): Promise<void> {\n await this.publisher.publish(channel, message);\n }\n\n // ---------------------------------------------------------\n // Counter operations\n // ---------------------------------------------------------\n\n public override async incr(key: string, amount: number): Promise<number> {\n const result = await this.publisher.send(\"INCRBY\", [key, String(amount)]);\n return Number(result);\n }\n\n /**\n * Get the Redis connection URL.\n */\n protected getUrl(): string {\n return this.env.REDIS_URL;\n }\n}\n","/**\n * Abstract Redis subscriber provider interface.\n *\n * This abstract class defines the common interface for Redis pub/sub subscriptions.\n * Implementations include:\n * - {@link NodeRedisSubscriberProvider} - Uses `@redis/client` for Node.js runtime\n * - {@link BunRedisSubscriberProvider} - Uses Bun's native `RedisClient` for Bun runtime\n *\n * Redis requires separate connections for pub/sub operations, so this provider\n * creates a dedicated connection for subscriptions.\n *\n * @example\n * ```ts\n * // Inject the abstract provider - runtime selects the implementation\n * const subscriber = alepha.inject(RedisSubscriberProvider);\n *\n * // Subscribe to a channel\n * await subscriber.subscribe(\"my-channel\", (message, channel) => {\n * console.log(`Received: ${message} on ${channel}`);\n * });\n * ```\n */\nexport abstract class RedisSubscriberProvider {\n /**\n * Whether the Redis subscriber client is ready to accept commands.\n */\n public abstract readonly isReady: boolean;\n\n /**\n * Connect to the Redis server for subscriptions.\n */\n public abstract connect(): Promise<void>;\n\n /**\n * Close the subscriber connection.\n */\n public abstract close(): Promise<void>;\n\n /**\n * Subscribe to a channel.\n *\n * @param channel The channel name.\n * @param callback The callback to invoke when a message is received.\n */\n public abstract subscribe(\n channel: string,\n callback: SubscribeCallback,\n ): Promise<void>;\n\n /**\n * Unsubscribe from a channel.\n *\n * @param channel The channel name.\n * @param callback Optional specific callback to remove.\n */\n public abstract unsubscribe(\n channel: string,\n callback?: SubscribeCallback,\n ): Promise<void>;\n}\n\n/**\n * Callback for subscription messages.\n */\nexport type SubscribeCallback = (message: string, channel: string) => void;\n","import { $hook, $inject, Alepha, AlephaError } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { BunRedisProvider } from \"./BunRedisProvider.ts\";\nimport {\n RedisSubscriberProvider,\n type SubscribeCallback,\n} from \"./RedisSubscriberProvider.ts\";\n\n/**\n * Bun Redis subscriber provider for pub/sub operations.\n *\n * This provider creates a dedicated Redis connection for subscriptions,\n * as Redis requires separate connections for pub/sub operations.\n *\n * @example\n * ```ts\n * const subscriber = alepha.inject(RedisSubscriberProvider);\n * await subscriber.subscribe(\"channel\", (message, channel) => {\n * console.log(`Received: ${message} on ${channel}`);\n * });\n * ```\n */\nexport class BunRedisSubscriberProvider extends RedisSubscriberProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly redisProvider = $inject(BunRedisProvider);\n protected client?: Bun.RedisClient;\n\n public get subscriber(): Bun.RedisClient {\n if (!this.client?.connected) {\n throw new AlephaError(\"Redis subscriber client is not ready\");\n }\n\n return this.client;\n }\n\n public override get isReady(): boolean {\n return this.client?.connected ?? false;\n }\n\n protected readonly start = $hook({\n on: \"start\",\n handler: () => this.connect(),\n });\n\n protected readonly stop = $hook({\n on: \"stop\",\n handler: () => this.close(),\n });\n\n /**\n * Connect to the Redis server for subscriptions.\n */\n public override async connect(): Promise<void> {\n this.log.debug(\"Connecting subscriber...\");\n this.client = await this.redisProvider.duplicate();\n this.log.info(\"Subscriber connection OK\");\n }\n\n /**\n * Close the subscriber connection.\n */\n public override async close(): Promise<void> {\n if (this.client) {\n this.log.debug(\"Closing subscriber connection...\");\n this.client.close();\n this.client = undefined;\n this.log.info(\"Subscriber connection closed\");\n }\n }\n\n public override async subscribe(\n channel: string,\n callback: SubscribeCallback,\n ): Promise<void> {\n await this.subscriber.subscribe(channel, (message, ch) => {\n // Bun's callback provides Buffer or string, normalize to string\n const msg =\n typeof message === \"object\" && message !== null\n ? Buffer.from(message as Uint8Array).toString()\n : String(message);\n callback(msg, ch);\n });\n }\n\n public override async unsubscribe(\n channel: string,\n _callback?: SubscribeCallback,\n ): Promise<void> {\n // Bun's unsubscribe doesn't support callback filtering\n await this.subscriber.unsubscribe(channel);\n }\n}\n","import {\n createClient,\n RESP_TYPES,\n type RedisClientType,\n type SetOptions,\n} from \"@redis/client\";\nimport {\n $env,\n $hook,\n $inject,\n Alepha,\n AlephaError,\n type Static,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { RedisProvider, type RedisSetOptions } from \"./RedisProvider.ts\";\n\nconst envSchema = t.object({\n REDIS_URL: t.text({\n default: \"redis://localhost:6379\",\n description: \"Redis connection URL\",\n }),\n});\n\ndeclare module \"alepha\" {\n interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\nexport type NodeRedisClient = RedisClientType<\n {},\n {},\n {},\n 3,\n { 36: BufferConstructor }\n>;\nexport type NodeRedisClientOptions = Parameters<typeof createClient>[0];\n\n/**\n * Node.js Redis client provider using `@redis/client`.\n *\n * This provider uses the official Redis client for Node.js runtime.\n *\n * @example\n * ```ts\n * // Set REDIS_URL environment variable (default: redis://localhost:6379)\n * // REDIS_URL=redis://:password@myredis.example.com:6379\n *\n * // Or configure programmatically\n * alepha.with({\n * provide: RedisProvider,\n * use: NodeRedisProvider,\n * });\n * ```\n */\nexport class NodeRedisProvider extends RedisProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly env = $env(envSchema);\n protected readonly client = this.createClient();\n\n public get publisher(): NodeRedisClient {\n if (!this.client.isReady) {\n throw new AlephaError(\"Redis client is not ready\");\n }\n\n return this.client;\n }\n\n public override get isReady(): boolean {\n return this.client.isReady;\n }\n\n protected readonly start = $hook({\n on: \"start\",\n handler: () => this.connect(),\n });\n\n protected readonly stop = $hook({\n on: \"stop\",\n handler: () => this.close(),\n });\n\n /**\n * Connect to the Redis server.\n */\n public override async connect(): Promise<void> {\n this.log.debug(\"Connecting...\");\n await this.client.connect();\n this.log.info(\"Connection OK\");\n }\n\n /**\n * Close the connection to the Redis server.\n */\n public override async close(): Promise<void> {\n this.log.debug(\"Closing connection...\");\n await this.client.close();\n this.log.info(\"Connection closed\");\n }\n\n public duplicate(options?: Partial<NodeRedisClientOptions>): NodeRedisClient {\n return this.client\n .duplicate({\n ...options,\n RESP: 3,\n })\n .withTypeMapping({\n [RESP_TYPES.BLOB_STRING]: Buffer,\n });\n }\n\n public override async get(key: string): Promise<Buffer | undefined> {\n this.log.trace(`Getting key ${key}`);\n const resp = await this.publisher.get(key);\n\n if (resp === null) {\n return undefined;\n }\n\n return Buffer.from(resp);\n }\n\n public override async set(\n key: string,\n value: Buffer | string,\n options?: RedisSetOptions,\n ): Promise<Buffer> {\n const buf = Buffer.isBuffer(value) ? value : Buffer.from(value, \"utf-8\");\n\n // Convert RedisSetOptions to @redis/client SetOptions\n const setOptions: SetOptions = {};\n\n // Handle expiration object format (from alepha/cache-redis, alepha/lock-redis)\n if (options?.expiration) {\n if (options.expiration.type === \"KEEPTTL\") {\n setOptions.KEEPTTL = true;\n } else {\n setOptions[options.expiration.type] = options.expiration.value;\n }\n }\n\n // Handle direct expiration properties\n if (options?.EX !== undefined) {\n setOptions.EX = options.EX;\n }\n if (options?.PX !== undefined) {\n setOptions.PX = options.PX;\n }\n if (options?.EXAT !== undefined) {\n setOptions.EXAT = options.EXAT;\n }\n if (options?.PXAT !== undefined) {\n setOptions.PXAT = options.PXAT;\n }\n if (options?.KEEPTTL) {\n setOptions.KEEPTTL = true;\n }\n\n // Handle condition object format\n if (options?.condition === \"NX\") {\n setOptions.NX = true;\n } else if (options?.condition === \"XX\") {\n setOptions.XX = true;\n }\n\n // Handle direct condition properties\n if (options?.NX) {\n setOptions.NX = true;\n }\n if (options?.XX) {\n setOptions.XX = true;\n }\n if (options?.GET) {\n setOptions.GET = true;\n }\n\n const resp = await this.publisher.set(\n key,\n buf,\n Object.keys(setOptions).length > 0 ? setOptions : undefined,\n );\n\n if (resp === \"OK\" || !resp) {\n return buf;\n }\n\n return Buffer.from(resp);\n }\n\n public override async has(key: string): Promise<boolean> {\n const resp = await this.publisher.exists(key);\n return resp > 0;\n }\n\n public override async keys(pattern: string): Promise<string[]> {\n const keys = await this.publisher.keys(pattern);\n return keys.map((key) => key.toString());\n }\n\n public override async del(keys: string[]): Promise<void> {\n if (keys.length === 0) {\n return;\n }\n\n await this.publisher.del(keys);\n }\n\n // ---------------------------------------------------------\n // Queue operations\n // ---------------------------------------------------------\n\n public override async lpush(key: string, value: string): Promise<void> {\n await this.publisher.LPUSH(key, value);\n }\n\n public override async rpop(key: string): Promise<string | undefined> {\n const value = await this.publisher.RPOP(key);\n if (value == null) {\n return undefined;\n }\n return String(value);\n }\n\n // ---------------------------------------------------------\n // Pub/Sub operations\n // ---------------------------------------------------------\n\n public override async publish(\n channel: string,\n message: string,\n ): Promise<void> {\n await this.publisher.publish(channel, message);\n }\n\n // ---------------------------------------------------------\n // Counter operations\n // ---------------------------------------------------------\n\n public override async incr(key: string, amount: number): Promise<number> {\n return this.publisher.INCRBY(key, amount);\n }\n\n /**\n * Get the Redis connection URL.\n */\n protected getUrl(): string {\n return this.env.REDIS_URL;\n }\n\n /**\n * Redis client factory method.\n */\n protected createClient(): NodeRedisClient {\n const client = createClient({\n url: this.getUrl(),\n RESP: 3,\n }).withTypeMapping({\n [RESP_TYPES.BLOB_STRING]: Buffer,\n });\n\n client.on(\"error\", (error) => {\n if (this.alepha.isStarted()) {\n this.log.error(error);\n }\n });\n\n return client;\n }\n}\n","import { $hook, $inject, Alepha, AlephaError } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport {\n type NodeRedisClient,\n NodeRedisProvider,\n} from \"./NodeRedisProvider.ts\";\nimport {\n RedisSubscriberProvider,\n type SubscribeCallback,\n} from \"./RedisSubscriberProvider.ts\";\n\n/**\n * Node.js Redis subscriber provider using `@redis/client`.\n *\n * This provider creates a dedicated Redis connection for subscriptions,\n * as Redis requires separate connections for pub/sub operations.\n *\n * @example\n * ```ts\n * const subscriber = alepha.inject(RedisSubscriberProvider);\n * await subscriber.subscribe(\"channel\", (message, channel) => {\n * console.log(`Received: ${message} on ${channel}`);\n * });\n * ```\n */\nexport class NodeRedisSubscriberProvider extends RedisSubscriberProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly redisProvider = $inject(NodeRedisProvider);\n protected readonly client: NodeRedisClient = this.createClient();\n\n public get subscriber(): NodeRedisClient {\n if (!this.client.isReady) {\n throw new AlephaError(\"Redis subscriber client is not ready\");\n }\n\n return this.client;\n }\n\n public override get isReady(): boolean {\n return this.client.isReady;\n }\n\n protected readonly start = $hook({\n on: \"start\",\n handler: () => this.connect(),\n });\n\n protected readonly stop = $hook({\n on: \"stop\",\n handler: () => this.close(),\n });\n\n public override async connect(): Promise<void> {\n this.log.debug(\"Connecting subscriber...\");\n await this.client.connect();\n this.log.info(\"Subscriber connection OK\");\n }\n\n public override async close(): Promise<void> {\n if (!this.client.isReady) {\n this.log.debug(\"Subscriber client not ready, skipping close\");\n return;\n }\n this.log.debug(\"Closing subscriber connection...\");\n await this.client.close();\n this.log.info(\"Subscriber connection closed\");\n }\n\n public override async subscribe(\n channel: string,\n callback: SubscribeCallback,\n ): Promise<void> {\n await this.subscriber.subscribe(channel, callback);\n }\n\n public override async unsubscribe(\n channel: string,\n callback?: SubscribeCallback,\n ): Promise<void> {\n await this.subscriber.unsubscribe(channel, callback);\n }\n\n /**\n * Redis subscriber client factory method.\n */\n protected createClient(): NodeRedisClient {\n const client = this.redisProvider.duplicate();\n\n client.on(\"error\", (error) => {\n if (this.alepha.isStarted()) {\n this.log.error(error);\n }\n });\n\n return client;\n }\n}\n","import { $module, type Alepha } from \"alepha\";\nimport { BunRedisProvider } from \"./providers/BunRedisProvider.ts\";\nimport { BunRedisSubscriberProvider } from \"./providers/BunRedisSubscriberProvider.ts\";\nimport { NodeRedisProvider } from \"./providers/NodeRedisProvider.ts\";\nimport { NodeRedisSubscriberProvider } from \"./providers/NodeRedisSubscriberProvider.ts\";\nimport { RedisProvider } from \"./providers/RedisProvider.ts\";\nimport { RedisSubscriberProvider } from \"./providers/RedisSubscriberProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./providers/BunRedisProvider.ts\";\nexport * from \"./providers/BunRedisSubscriberProvider.ts\";\nexport * from \"./providers/NodeRedisProvider.ts\";\nexport * from \"./providers/NodeRedisSubscriberProvider.ts\";\nexport * from \"./providers/RedisProvider.ts\";\nexport * from \"./providers/RedisSubscriberProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Redis client wrapper.\n *\n * **Features:**\n * - Connection pooling\n * - Automatic reconnection\n * - Command pipelining\n * - Pub/sub support\n *\n * @module alepha.redis\n */\nexport const AlephaRedis = $module({\n name: \"alepha.redis\",\n services: [RedisProvider, RedisSubscriberProvider],\n variants: [\n NodeRedisProvider,\n NodeRedisSubscriberProvider,\n BunRedisProvider,\n BunRedisSubscriberProvider,\n ],\n register: (alepha: Alepha) => {\n if (alepha.isBun()) {\n alepha\n .with({\n provide: RedisProvider,\n use: BunRedisProvider,\n })\n .with({\n provide: RedisSubscriberProvider,\n use: BunRedisSubscriberProvider,\n });\n } else {\n alepha\n .with({\n provide: RedisProvider,\n use: NodeRedisProvider,\n })\n .with({\n provide: RedisSubscriberProvider,\n use: NodeRedisSubscriberProvider,\n });\n }\n },\n});\n"],"mappings":"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"}