create-nexwire 4.2.5 → 4.4.0

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 (399) hide show
  1. package/README.md +29 -12
  2. package/express/.env +1 -1
  3. package/express/package.json +1 -1
  4. package/express/src/config/database.ts +48 -29
  5. package/express/src/config/index.ts +83 -83
  6. package/express/src/config/openapi.ts +6 -24
  7. package/express/src/config/queue.ts +30 -30
  8. package/express/src/config/validate.ts +50 -40
  9. package/express/src/database/migrations/sqlite/0000_init.sql +47 -47
  10. package/express/src/database/migrations/sqlite/meta/0000_snapshot.json +1 -1
  11. package/express/src/database/migrations/sqlite/meta/_journal.json +1 -1
  12. package/express/src/framework/cache/cache.ts +40 -8
  13. package/express/src/framework/circuit-breaker/cb.ts +88 -60
  14. package/express/src/framework/database/connection.ts +52 -27
  15. package/express/src/framework/events/dispatcher.ts +61 -49
  16. package/express/src/framework/facade.ts +47 -3
  17. package/express/src/framework/http/app.ts +28 -22
  18. package/express/src/framework/http/logger.ts +37 -17
  19. package/express/src/framework/http/openapi.ts +9 -11
  20. package/express/src/framework/maker-cli/runtime/core.mjs +1 -2
  21. package/express/src/framework/modules/routes.ts +26 -21
  22. package/express/src/framework/notification/channels/broadcast.ts +15 -0
  23. package/express/src/framework/notification/channels/mail.ts +42 -0
  24. package/express/src/framework/notification/contracts.ts +29 -0
  25. package/express/src/framework/notification/index.ts +19 -94
  26. package/express/src/framework/notification/registry.ts +15 -0
  27. package/express/src/framework/providers/adapter.ts +27 -17
  28. package/express/src/framework/queue/queue.ts +43 -44
  29. package/express/src/framework/realtime/broadcast.ts +29 -5
  30. package/express/src/framework/realtime/socket.ts +149 -119
  31. package/express/src/framework/redis/client.ts +148 -151
  32. package/express/src/framework/runtime/server-adapter.ts +39 -34
  33. package/express/src/framework/scheduler/lock.ts +128 -116
  34. package/express/src/framework/server.ts +33 -49
  35. package/express/src/framework/session/session.ts +69 -14
  36. package/express/src/framework/storage/storage.ts +744 -785
  37. package/express/src/framework/support/mail.ts +15 -7
  38. package/express/src/middlewares/auth-middleware.ts +1 -2
  39. package/express/src/middlewares/role-middleware.ts +3 -13
  40. package/express/src/modules/auth/routes/index.ts +1 -2
  41. package/express/src/providers/notification.ts +4 -0
  42. package/express/src/resources/src/components/Switch.vue +60 -65
  43. package/express/src/resources/src/layouts/Layout/Header.vue +124 -105
  44. package/express/src/resources/src/pages/auth/forgetPassword.vue +23 -30
  45. package/express/src/resources/src/pages/auth/login.vue +25 -28
  46. package/express/src/resources/src/pages/auth/register.vue +35 -39
  47. package/express/src/resources/src/pages/auth/resetPassword.vue +29 -37
  48. package/express/src/resources/src/pages/auth/verifyEmail.vue +15 -19
  49. package/express/src/resources/src/plugins/gum.ts +519 -203
  50. package/express/src/resources/src/plugins/pulse.ts +157 -147
  51. package/express/src/resources/src/stores/auth.ts +9 -6
  52. package/express/src/resources/vite.config.ts +54 -43
  53. package/express/src/storage/database/nexwire.sqlite +0 -0
  54. package/express/src/storage/logs/app.log +0 -0
  55. package/express/src/storage/logs/fatal.log +0 -0
  56. package/express/src/types/global.d.ts +32 -26
  57. package/fastify/.dockerignore +14 -0
  58. package/fastify/.env +44 -0
  59. package/fastify/.env.example +42 -0
  60. package/fastify/.vscode/extensions.json +6 -0
  61. package/fastify/.vscode/settings.json +37 -0
  62. package/fastify/LICENSE +21 -0
  63. package/fastify/README.md +232 -0
  64. package/fastify/biome.json +99 -0
  65. package/fastify/drizzle.config.ts +25 -0
  66. package/fastify/gitignore-stub +31 -0
  67. package/fastify/package.json +130 -0
  68. package/fastify/public/.gitkeep +0 -0
  69. package/fastify/src/config/app.ts +41 -0
  70. package/fastify/src/config/auth.ts +12 -0
  71. package/fastify/src/config/cache.ts +16 -0
  72. package/fastify/src/config/cookie.ts +15 -0
  73. package/fastify/src/config/cors.ts +12 -0
  74. package/fastify/src/config/database.ts +48 -0
  75. package/fastify/src/config/index.ts +83 -0
  76. package/fastify/src/config/jwt.ts +19 -0
  77. package/fastify/src/config/logging.ts +13 -0
  78. package/fastify/src/config/mail.ts +24 -0
  79. package/fastify/src/config/openapi.ts +36 -0
  80. package/fastify/src/config/queue.ts +30 -0
  81. package/fastify/src/config/rateLimit.ts +17 -0
  82. package/fastify/src/config/realtime.ts +15 -0
  83. package/fastify/src/config/redis.ts +18 -0
  84. package/fastify/src/config/security.ts +44 -0
  85. package/fastify/src/config/session.ts +17 -0
  86. package/fastify/src/config/storage.ts +22 -0
  87. package/fastify/src/config/validate.ts +50 -0
  88. package/fastify/src/database/migrations/sqlite/0000_init.sql +48 -0
  89. package/fastify/src/database/migrations/sqlite/meta/0000_snapshot.json +324 -0
  90. package/fastify/src/database/migrations/sqlite/meta/_journal.json +13 -0
  91. package/fastify/src/database/schema.ts +2 -0
  92. package/fastify/src/env.ts +76 -0
  93. package/fastify/src/framework/cache/cache.ts +114 -0
  94. package/fastify/src/framework/circuit-breaker/cb.ts +88 -0
  95. package/fastify/src/framework/database/app-schema.ts +37 -0
  96. package/fastify/src/framework/database/connection.ts +223 -0
  97. package/fastify/src/framework/database/migrate-hooks.ts +87 -0
  98. package/fastify/src/framework/database/paginate.ts +226 -0
  99. package/fastify/src/framework/database/schema.ts +20 -0
  100. package/fastify/src/framework/database/seed.ts +152 -0
  101. package/fastify/src/framework/events/dispatcher.ts +61 -0
  102. package/fastify/src/framework/facade.ts +96 -0
  103. package/fastify/src/framework/http/app.ts +176 -0
  104. package/fastify/src/framework/http/cors.ts +13 -0
  105. package/fastify/src/framework/http/fastify.d.ts +13 -0
  106. package/fastify/src/framework/http/logger.ts +110 -0
  107. package/fastify/src/framework/http/metrics.ts +22 -0
  108. package/fastify/src/framework/http/openapi.ts +48 -0
  109. package/fastify/src/framework/http/ratelimiter.ts +47 -0
  110. package/fastify/src/framework/http/security.ts +25 -0
  111. package/fastify/src/framework/http/static.ts +83 -0
  112. package/fastify/src/framework/http/validation.ts +49 -0
  113. package/fastify/src/framework/kernel.ts +43 -0
  114. package/fastify/src/framework/maker-cli/db/core.mjs +291 -0
  115. package/fastify/src/framework/maker-cli/db/index.mjs +204 -0
  116. package/fastify/src/framework/maker-cli/deploy/core.mjs +1046 -0
  117. package/fastify/src/framework/maker-cli/deploy/index.mjs +91 -0
  118. package/fastify/src/framework/maker-cli/index.mjs +65 -0
  119. package/fastify/src/framework/maker-cli/middleware/core.mjs +41 -0
  120. package/fastify/src/framework/maker-cli/middleware/index.mjs +17 -0
  121. package/fastify/src/framework/maker-cli/module/core.mjs +1066 -0
  122. package/fastify/src/framework/maker-cli/module/index.mjs +211 -0
  123. package/fastify/src/framework/maker-cli/provider/core.mjs +49 -0
  124. package/fastify/src/framework/maker-cli/provider/index.mjs +12 -0
  125. package/fastify/src/framework/maker-cli/runtime/build-ui.mjs +16 -0
  126. package/fastify/src/framework/maker-cli/runtime/core.mjs +560 -0
  127. package/fastify/src/framework/maker-cli/runtime/index.mjs +120 -0
  128. package/fastify/src/framework/maker-cli/runtime/redis-commander-patch.cjs +20 -0
  129. package/fastify/src/framework/maker-cli/stubs/controller/openapi.ts.stub +74 -0
  130. package/fastify/src/framework/maker-cli/stubs/controller/plain.ts.stub +77 -0
  131. package/fastify/src/framework/maker-cli/stubs/controller/standalone.ts.stub +51 -0
  132. package/fastify/src/framework/maker-cli/stubs/deploy/Dockerfile.bun.stub +52 -0
  133. package/fastify/src/framework/maker-cli/stubs/deploy/Dockerfile.pnpm.stub +55 -0
  134. package/fastify/src/framework/maker-cli/stubs/deploy/Dockerfile.stub +51 -0
  135. package/fastify/src/framework/maker-cli/stubs/deploy/Dockerfile.yarn.stub +55 -0
  136. package/fastify/src/framework/maker-cli/stubs/deploy/README.stub +59 -0
  137. package/fastify/src/framework/maker-cli/stubs/deploy/compose/mysql.server.stub +45 -0
  138. package/fastify/src/framework/maker-cli/stubs/deploy/compose/postgres.server.stub +45 -0
  139. package/fastify/src/framework/maker-cli/stubs/deploy/compose/sqlite.stub +45 -0
  140. package/fastify/src/framework/maker-cli/stubs/deploy/env/mysql.server.stub +68 -0
  141. package/fastify/src/framework/maker-cli/stubs/deploy/env/postgres.server.stub +68 -0
  142. package/fastify/src/framework/maker-cli/stubs/deploy/env/sqlite.stub +67 -0
  143. package/fastify/src/framework/maker-cli/stubs/deploy/scripts/auto-migrate.sh.stub +41 -0
  144. package/fastify/src/framework/maker-cli/stubs/deploy/server/README.stub +78 -0
  145. package/fastify/src/framework/maker-cli/stubs/deploy/server/compose/noredis.stub +120 -0
  146. package/fastify/src/framework/maker-cli/stubs/deploy/server/compose/redis.dev.stub +133 -0
  147. package/fastify/src/framework/maker-cli/stubs/deploy/server/compose/redis.stub +131 -0
  148. package/fastify/src/framework/maker-cli/stubs/deploy/server/env/local.example.stub +11 -0
  149. package/fastify/src/framework/maker-cli/stubs/deploy/server/env/noredis.stub +25 -0
  150. package/fastify/src/framework/maker-cli/stubs/deploy/server/env/redis.stub +25 -0
  151. package/fastify/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/README.stub +16 -0
  152. package/fastify/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/app.example.com.stub +13 -0
  153. package/fastify/src/framework/maker-cli/stubs/deploy/server/pgadmin/servers.stub +14 -0
  154. package/fastify/src/framework/maker-cli/stubs/deploy/server/redis/redis.conf.stub +7 -0
  155. package/fastify/src/framework/maker-cli/stubs/deploy/supervisor/noredis.stub +54 -0
  156. package/fastify/src/framework/maker-cli/stubs/deploy/supervisor/redis.stub +70 -0
  157. package/fastify/src/framework/maker-cli/stubs/deploy/workflow/local.json.stub +25 -0
  158. package/fastify/src/framework/maker-cli/stubs/deploy/workflow/remote.json.stub +24 -0
  159. package/fastify/src/framework/maker-cli/stubs/facade/name.ts.stub +12 -0
  160. package/fastify/src/framework/maker-cli/stubs/helper/name.ts.stub +14 -0
  161. package/fastify/src/framework/maker-cli/stubs/job/name.ts.stub +25 -0
  162. package/fastify/src/framework/maker-cli/stubs/middleware/name.local.ts.stub +15 -0
  163. package/fastify/src/framework/maker-cli/stubs/middleware/name.ts.stub +15 -0
  164. package/fastify/src/framework/maker-cli/stubs/model/name.mysql.ts.stub +10 -0
  165. package/fastify/src/framework/maker-cli/stubs/model/name.postgresql.ts.stub +10 -0
  166. package/fastify/src/framework/maker-cli/stubs/model/name.sqlite.ts.stub +10 -0
  167. package/fastify/src/framework/maker-cli/stubs/notification/controller.ts.stub +79 -0
  168. package/fastify/src/framework/maker-cli/stubs/notification/job.ts.stub +11 -0
  169. package/fastify/src/framework/maker-cli/stubs/notification/model.ts.stub +29 -0
  170. package/fastify/src/framework/maker-cli/stubs/notification/provider.ts.stub +174 -0
  171. package/fastify/src/framework/maker-cli/stubs/notification/route.api.ts.stub +71 -0
  172. package/fastify/src/framework/maker-cli/stubs/notification/route.plain.ts.stub +15 -0
  173. package/fastify/src/framework/maker-cli/stubs/notification/schema.plain.ts.stub +26 -0
  174. package/fastify/src/framework/maker-cli/stubs/notification/schema.ts.stub +26 -0
  175. package/fastify/src/framework/maker-cli/stubs/provider/module-barrel.ts.stub +19 -0
  176. package/fastify/src/framework/maker-cli/stubs/provider/module.ts.stub +21 -0
  177. package/fastify/src/framework/maker-cli/stubs/provider/name.ts.stub +21 -0
  178. package/fastify/src/framework/maker-cli/stubs/route/api.ts.stub +101 -0
  179. package/fastify/src/framework/maker-cli/stubs/route/plain.ts.stub +23 -0
  180. package/fastify/src/framework/maker-cli/stubs/route/standalone.api.ts.stub +120 -0
  181. package/fastify/src/framework/maker-cli/stubs/route/standalone.plain.ts.stub +50 -0
  182. package/fastify/src/framework/maker-cli/stubs/schedule/name.ts.stub +36 -0
  183. package/fastify/src/framework/maker-cli/stubs/schema/name.plain.ts.stub +14 -0
  184. package/fastify/src/framework/maker-cli/stubs/schema/name.ts.stub +33 -0
  185. package/fastify/src/framework/maker-cli/stubs/seeder/name.ts.stub +18 -0
  186. package/fastify/src/framework/maker-cli/stubs/seeder/standalone.ts.stub +22 -0
  187. package/fastify/src/framework/maker-cli/stubs/service/name.plain.ts.stub +67 -0
  188. package/fastify/src/framework/maker-cli/stubs/service/name.ts.stub +65 -0
  189. package/fastify/src/framework/maker-cli/stubs/test/unit.ts.stub +22 -0
  190. package/fastify/src/framework/maker-cli/stubs/type/name.ts.stub +22 -0
  191. package/fastify/src/framework/maker-cli/utils/env-config.mjs +44 -0
  192. package/fastify/src/framework/maker-cli/utils/env-db.mjs +61 -0
  193. package/fastify/src/framework/maker-cli/utils/file-ops.mjs +30 -0
  194. package/fastify/src/framework/maker-cli/utils/flags.mjs +14 -0
  195. package/fastify/src/framework/maker-cli/utils/help.mjs +379 -0
  196. package/fastify/src/framework/maker-cli/utils/naming.mjs +119 -0
  197. package/fastify/src/framework/maker-cli/utils/process.mjs +52 -0
  198. package/fastify/src/framework/maker-cli/utils/project-commands.mjs +201 -0
  199. package/fastify/src/framework/modules/discover.ts +57 -0
  200. package/fastify/src/framework/modules/routes.ts +31 -0
  201. package/fastify/src/framework/notification/channels/broadcast.ts +15 -0
  202. package/fastify/src/framework/notification/channels/mail.ts +42 -0
  203. package/fastify/src/framework/notification/contracts.ts +29 -0
  204. package/fastify/src/framework/notification/index.ts +59 -0
  205. package/fastify/src/framework/notification/registry.ts +15 -0
  206. package/fastify/src/framework/providers/adapter.ts +149 -0
  207. package/fastify/src/framework/providers/contracts.ts +126 -0
  208. package/fastify/src/framework/providers/loader.ts +105 -0
  209. package/fastify/src/framework/providers/registry.ts +88 -0
  210. package/fastify/src/framework/queue/clear.ts +22 -0
  211. package/fastify/src/framework/queue/queue.ts +401 -0
  212. package/fastify/src/framework/queue/ui.ts +194 -0
  213. package/fastify/src/framework/queue/worker.ts +61 -0
  214. package/fastify/src/framework/realtime/broadcast.ts +70 -0
  215. package/fastify/src/framework/realtime/index.ts +2 -0
  216. package/fastify/src/framework/realtime/socket-cookie.ts +72 -0
  217. package/fastify/src/framework/realtime/socket.ts +149 -0
  218. package/fastify/src/framework/realtime/types.ts +6 -0
  219. package/fastify/src/framework/realtime/ui.ts +16 -0
  220. package/fastify/src/framework/redis/client.ts +148 -0
  221. package/fastify/src/framework/runtime/runtime.ts +23 -0
  222. package/fastify/src/framework/runtime/server-adapter.ts +33 -0
  223. package/fastify/src/framework/scheduler/lock.ts +128 -0
  224. package/fastify/src/framework/scheduler/run.ts +48 -0
  225. package/fastify/src/framework/scheduler/scheduler.ts +155 -0
  226. package/fastify/src/framework/server.ts +162 -0
  227. package/fastify/src/framework/session/session.ts +160 -0
  228. package/fastify/src/framework/storage/storage.ts +744 -0
  229. package/fastify/src/framework/support/cookie.ts +71 -0
  230. package/fastify/src/framework/support/jwt.ts +33 -0
  231. package/fastify/src/framework/support/lifecycle.ts +35 -0
  232. package/fastify/src/framework/support/logger.ts +148 -0
  233. package/fastify/src/framework/support/mail.ts +56 -0
  234. package/fastify/src/framework/support/password.ts +23 -0
  235. package/fastify/src/framework/support/status-codes.ts +75 -0
  236. package/fastify/src/framework/support/upload.ts +181 -0
  237. package/fastify/src/framework/support/url.ts +41 -0
  238. package/fastify/src/middlewares/auth-middleware.ts +134 -0
  239. package/fastify/src/middlewares/role-middleware.ts +19 -0
  240. package/fastify/src/modules/auth/__tests__/forgetpass.test.ts +200 -0
  241. package/fastify/src/modules/auth/__tests__/login.test.ts +171 -0
  242. package/fastify/src/modules/auth/__tests__/logout.test.ts +60 -0
  243. package/fastify/src/modules/auth/__tests__/logoutalldevices.test.ts +49 -0
  244. package/fastify/src/modules/auth/__tests__/me.test.ts +91 -0
  245. package/fastify/src/modules/auth/__tests__/refreshtoken.test.ts +305 -0
  246. package/fastify/src/modules/auth/__tests__/register.test.ts +291 -0
  247. package/fastify/src/modules/auth/__tests__/resetpass.test.ts +206 -0
  248. package/fastify/src/modules/auth/__tests__/verifyemail.test.ts +183 -0
  249. package/fastify/src/modules/auth/controllers/auth.ts +252 -0
  250. package/fastify/src/modules/auth/controllers/role.ts +35 -0
  251. package/fastify/src/modules/auth/database/models/role.ts +14 -0
  252. package/fastify/src/modules/auth/database/models/user.ts +46 -0
  253. package/fastify/src/modules/auth/database/seeders/role.ts +18 -0
  254. package/fastify/src/modules/auth/database/seeders/user.ts +35 -0
  255. package/fastify/src/modules/auth/facade.ts +12 -0
  256. package/fastify/src/modules/auth/helpers/auth.ts +115 -0
  257. package/fastify/src/modules/auth/jobs/forgetpass.ts +20 -0
  258. package/fastify/src/modules/auth/jobs/registeruser.ts +23 -0
  259. package/fastify/src/modules/auth/jobs/verifyemail.ts +18 -0
  260. package/fastify/src/modules/auth/routes/index.ts +185 -0
  261. package/fastify/src/modules/auth/routes/role.ts +56 -0
  262. package/fastify/src/modules/auth/schemas/auth.ts +116 -0
  263. package/fastify/src/modules/auth/services/forgetpassword.ts +66 -0
  264. package/fastify/src/modules/auth/services/login.ts +63 -0
  265. package/fastify/src/modules/auth/services/logout.ts +25 -0
  266. package/fastify/src/modules/auth/services/logoutalldevices.ts +19 -0
  267. package/fastify/src/modules/auth/services/me.ts +31 -0
  268. package/fastify/src/modules/auth/services/refreshtoken.ts +110 -0
  269. package/fastify/src/modules/auth/services/register.ts +141 -0
  270. package/fastify/src/modules/auth/services/resetpassword.ts +69 -0
  271. package/fastify/src/modules/auth/services/verifyemail.ts +77 -0
  272. package/fastify/src/modules/auth/types/auth.ts +31 -0
  273. package/fastify/src/providers/README.md +107 -0
  274. package/fastify/src/providers/notification.ts +4 -0
  275. package/fastify/src/resources/index.html +17 -0
  276. package/fastify/src/resources/src/App.vue +5 -0
  277. package/fastify/src/resources/src/assets/css/styles.css +14761 -0
  278. package/fastify/src/resources/src/assets/css/styles.css.map +1 -0
  279. package/fastify/src/resources/src/assets/fonts/public-sans/public-sans-latin-ext.woff2 +0 -0
  280. package/fastify/src/resources/src/assets/fonts/public-sans/public-sans-latin.woff2 +0 -0
  281. package/fastify/src/resources/src/assets/images/favicon/favicon.ico +0 -0
  282. package/fastify/src/resources/src/assets/images/logo.png +0 -0
  283. package/fastify/src/resources/src/assets/scss/custom.css +217 -0
  284. package/fastify/src/resources/src/assets/scss/custom.css.map +1 -0
  285. package/fastify/src/resources/src/assets/scss/custom.scss +1346 -0
  286. package/fastify/src/resources/src/components/Button.vue +32 -0
  287. package/fastify/src/resources/src/components/Checkbox.vue +32 -0
  288. package/fastify/src/resources/src/components/Datepicker.vue +106 -0
  289. package/fastify/src/resources/src/components/FeatureButton.vue +53 -0
  290. package/fastify/src/resources/src/components/FloatButton.vue +33 -0
  291. package/fastify/src/resources/src/components/Href.vue +32 -0
  292. package/fastify/src/resources/src/components/Input.vue +243 -0
  293. package/fastify/src/resources/src/components/InputGroup.vue +147 -0
  294. package/fastify/src/resources/src/components/InputPasswordToggle.vue +229 -0
  295. package/fastify/src/resources/src/components/Modal.vue +71 -0
  296. package/fastify/src/resources/src/components/Pagebar.vue +26 -0
  297. package/fastify/src/resources/src/components/Refresh.vue +19 -0
  298. package/fastify/src/resources/src/components/Select.vue +384 -0
  299. package/fastify/src/resources/src/components/Spinner.vue +42 -0
  300. package/fastify/src/resources/src/components/Switch.vue +60 -0
  301. package/fastify/src/resources/src/components/TextArea.vue +117 -0
  302. package/fastify/src/resources/src/components/Toast.vue +56 -0
  303. package/fastify/src/resources/src/components/datatable/DataTableSkeleton.vue +98 -0
  304. package/fastify/src/resources/src/components/datatable/Pagination.vue +147 -0
  305. package/fastify/src/resources/src/components/datatable/SelectOpption.vue +64 -0
  306. package/fastify/src/resources/src/components/datatable/index.vue +199 -0
  307. package/fastify/src/resources/src/composables/useAuth.ts +52 -0
  308. package/fastify/src/resources/src/helpers/assets.ts +51 -0
  309. package/fastify/src/resources/src/helpers/nformatter.ts +10 -0
  310. package/fastify/src/resources/src/helpers/utils.ts +75 -0
  311. package/fastify/src/resources/src/layouts/AuthLayout.vue +20 -0
  312. package/fastify/src/resources/src/layouts/Layout/Footer.vue +23 -0
  313. package/fastify/src/resources/src/layouts/Layout/Header.vue +124 -0
  314. package/fastify/src/resources/src/layouts/Layout/Sidebar.vue +137 -0
  315. package/fastify/src/resources/src/layouts/Layout/index.vue +87 -0
  316. package/fastify/src/resources/src/main.ts +28 -0
  317. package/fastify/src/resources/src/pages/auth/forgetPassword.vue +76 -0
  318. package/fastify/src/resources/src/pages/auth/login.vue +96 -0
  319. package/fastify/src/resources/src/pages/auth/register.vue +129 -0
  320. package/fastify/src/resources/src/pages/auth/resetPassword.vue +110 -0
  321. package/fastify/src/resources/src/pages/auth/verifyEmail.vue +64 -0
  322. package/fastify/src/resources/src/pages/dashboard/index.vue +66 -0
  323. package/fastify/src/resources/src/plugins/axios.ts +31 -0
  324. package/fastify/src/resources/src/plugins/browserDetect.ts +55 -0
  325. package/fastify/src/resources/src/plugins/dialog.ts +216 -0
  326. package/fastify/src/resources/src/plugins/gum.ts +683 -0
  327. package/fastify/src/resources/src/plugins/pulse.ts +157 -0
  328. package/fastify/src/resources/src/plugins/routeProgress.ts +87 -0
  329. package/fastify/src/resources/src/router/index.ts +85 -0
  330. package/fastify/src/resources/src/stores/admin-ui.ts +148 -0
  331. package/fastify/src/resources/src/stores/auth.ts +187 -0
  332. package/fastify/src/resources/tsconfig.json +19 -0
  333. package/fastify/src/resources/vite.config.ts +64 -0
  334. package/fastify/src/storage/app/private/.gitkeep +0 -0
  335. package/fastify/src/storage/app/public/.gitkeep +0 -0
  336. package/fastify/src/storage/app/tmp/generated/.gitkeep +0 -0
  337. package/fastify/src/storage/database/nexwire.sqlite +0 -0
  338. package/fastify/src/storage/logs/.gitkeep +0 -0
  339. package/fastify/src/storage/logs/app.log +0 -0
  340. package/fastify/src/storage/logs/fatal.log +0 -0
  341. package/fastify/src/storage/tmp/.gitkeep +0 -0
  342. package/fastify/src/storage/trash/modules/.gitkeep +0 -0
  343. package/fastify/src/types/global.d.ts +32 -0
  344. package/fastify/tsconfig.json +19 -0
  345. package/fastify/vitest.config.ts +38 -0
  346. package/hono/.env +1 -1
  347. package/hono/package.json +1 -1
  348. package/hono/src/config/database.ts +48 -29
  349. package/hono/src/config/index.ts +83 -83
  350. package/hono/src/config/openapi.ts +6 -24
  351. package/hono/src/config/queue.ts +30 -30
  352. package/hono/src/config/validate.ts +50 -40
  353. package/hono/src/database/migrations/sqlite/0000_init.sql +47 -47
  354. package/hono/src/database/migrations/sqlite/meta/0000_snapshot.json +1 -1
  355. package/hono/src/database/migrations/sqlite/meta/_journal.json +1 -1
  356. package/hono/src/framework/cache/cache.ts +40 -8
  357. package/hono/src/framework/circuit-breaker/cb.ts +88 -60
  358. package/hono/src/framework/database/connection.ts +52 -27
  359. package/hono/src/framework/events/dispatcher.ts +61 -49
  360. package/hono/src/framework/facade.ts +39 -1
  361. package/hono/src/framework/http/logger.ts +86 -81
  362. package/hono/src/framework/http/openapi.ts +7 -9
  363. package/hono/src/framework/maker-cli/runtime/core.mjs +1 -2
  364. package/hono/src/framework/notification/channels/broadcast.ts +15 -0
  365. package/hono/src/framework/notification/channels/mail.ts +42 -0
  366. package/hono/src/framework/notification/contracts.ts +29 -0
  367. package/hono/src/framework/notification/index.ts +19 -94
  368. package/hono/src/framework/notification/registry.ts +15 -0
  369. package/hono/src/framework/providers/adapter.ts +27 -17
  370. package/hono/src/framework/queue/queue.ts +43 -44
  371. package/hono/src/framework/realtime/broadcast.ts +29 -5
  372. package/hono/src/framework/realtime/socket.ts +217 -196
  373. package/hono/src/framework/redis/client.ts +148 -151
  374. package/hono/src/framework/scheduler/lock.ts +128 -116
  375. package/hono/src/framework/server.ts +27 -29
  376. package/hono/src/framework/session/session.ts +62 -14
  377. package/hono/src/framework/storage/storage.ts +744 -785
  378. package/hono/src/framework/support/mail.ts +56 -48
  379. package/hono/src/middlewares/auth-middleware.ts +1 -2
  380. package/hono/src/middlewares/role-middleware.ts +3 -13
  381. package/hono/src/modules/auth/routes/index.ts +1 -2
  382. package/hono/src/providers/notification.ts +4 -0
  383. package/hono/src/resources/src/components/Switch.vue +60 -65
  384. package/hono/src/resources/src/layouts/Layout/Header.vue +124 -105
  385. package/hono/src/resources/src/pages/auth/forgetPassword.vue +23 -29
  386. package/hono/src/resources/src/pages/auth/login.vue +26 -29
  387. package/hono/src/resources/src/pages/auth/register.vue +36 -40
  388. package/hono/src/resources/src/pages/auth/resetPassword.vue +29 -37
  389. package/hono/src/resources/src/pages/auth/verifyEmail.vue +15 -19
  390. package/hono/src/resources/src/plugins/gum.ts +519 -203
  391. package/hono/src/resources/src/plugins/pulse.ts +157 -147
  392. package/hono/src/resources/src/stores/auth.ts +9 -6
  393. package/hono/src/resources/vite.config.ts +54 -43
  394. package/hono/src/storage/database/nexwire.sqlite +0 -0
  395. package/hono/src/storage/logs/app.log +0 -0
  396. package/hono/src/storage/logs/fatal.log +0 -0
  397. package/hono/src/types/global.d.ts +32 -26
  398. package/package.json +4 -3
  399. package/src/index.js +143 -15
@@ -0,0 +1,48 @@
1
+ import { initDatabase } from "@/framework/database/connection.js";
2
+ import { bootQueueJobs, stopQueueRuntime } from "@/framework/queue/queue.js";
3
+ import { closeRedis, initRedis } from "@/framework/redis/client.js";
4
+ import { startScheduler, stopScheduler } from "@/framework/scheduler/scheduler.js";
5
+ import { registerShutdownSignals, type ShutdownSignal } from "@/framework/support/lifecycle.js";
6
+ import { logger } from "@/framework/support/logger.js";
7
+
8
+ export interface SchedulerHandle {
9
+ count: number;
10
+ shutdown: (signal: ShutdownSignal) => Promise<void>;
11
+ }
12
+
13
+ /**
14
+ * Why: Starts the scheduler and wires DB/Redis/queue shutdown.
15
+ * When: CLI `schedule:work` command or E2E test bootstrap.
16
+ * Where: Scheduler entrypoint.
17
+ * How: Inits DB/Redis, boots queue jobs, starts scheduler, registers signals.
18
+ * When called as the main module, also prints the startup banner.
19
+ */
20
+ export async function startSchedulerRuntime(): Promise<SchedulerHandle> {
21
+ await initDatabase();
22
+ await initRedis();
23
+ await bootQueueJobs();
24
+ const count = await startScheduler();
25
+ console.log(`Scheduler started [${count} schedule(s)]`);
26
+
27
+ let shuttingDown = false;
28
+
29
+ async function shutdown(signal: ShutdownSignal) {
30
+ if (shuttingDown) return;
31
+ shuttingDown = true;
32
+
33
+ logger.info("Scheduler shutdown signal received", { signal });
34
+ await Promise.allSettled([Promise.resolve(stopScheduler()), stopQueueRuntime()]);
35
+ await closeRedis();
36
+
37
+ process.exit(0);
38
+ }
39
+
40
+ registerShutdownSignals(shutdown);
41
+
42
+ return { count, shutdown };
43
+ }
44
+
45
+ const isMain = process.argv[1]?.endsWith("run.ts") || process.argv[1]?.endsWith("run.js");
46
+ if (isMain) {
47
+ await startSchedulerRuntime();
48
+ }
@@ -0,0 +1,155 @@
1
+ import { Cron } from "croner";
2
+ import { discoverModuleFiles, importFile } from "@/framework/modules/discover.js";
3
+ import { getQueue } from "@/framework/queue/queue.js";
4
+ import { runWithLock } from "@/framework/scheduler/lock.js";
5
+
6
+ type Schedule = {
7
+ name: string;
8
+ expression: string;
9
+ handler?: () => void | Promise<void>;
10
+ /** Queue mode: on each tick dispatches `job` to the given queue for its worker to process. */
11
+ queue?: string;
12
+ /** Queue mode: job name enqueued on each tick (defaults to `name`). */
13
+ job?: string;
14
+ /** Queue mode: static data passed to every enqueued job. */
15
+ data?: any;
16
+ timezone?: string;
17
+ /** Queue mode: also dispatch one job immediately at scheduler boot. */
18
+ immediately?: boolean;
19
+ runOnInit?: boolean;
20
+ enabled?: boolean;
21
+ ttlMs?: number;
22
+ };
23
+
24
+ const schedules: Schedule[] = [];
25
+ const tasks: Cron[] = [];
26
+
27
+ const PAD = 60;
28
+
29
+ function pad(str: string, len: number, char = " ") {
30
+ return str.length >= len ? str : str + char.repeat(len - str.length);
31
+ }
32
+
33
+ function printHeader() {
34
+ console.log("");
35
+ console.log("Running Scheduled Commands");
36
+ console.log(`${"=".repeat(PAD)}`);
37
+ }
38
+
39
+ function printScheduleResult(name: string, startMs: number, success: boolean, _message?: string) {
40
+ const elapsed = ((Date.now() - startMs) / 1000).toFixed(2);
41
+ const now = new Date().toLocaleString("en-GB", { hour12: true });
42
+ const dots = ".".repeat(Math.max(1, PAD - name.length - 8));
43
+ const status = success ? `${elapsed}s` : `FAIL`;
44
+ console.log(` ${name} ${dots} ${status}`);
45
+ }
46
+
47
+ /**
48
+ * Why: Registers a cron schedule definition at runtime.
49
+ * When: Module console/schedule files are imported.
50
+ * Where: Scheduler-related module files.
51
+ * How: Pushes normalized schedule config into in-memory registry. Handler
52
+ * schedules run an in-process callback on each tick; queue-mode schedules
53
+ * dispatch a job to their queue on each tick. `schedule:work` is the sole
54
+ * trigger — queue workers never fire schedules on their own.
55
+ */
56
+ export function defineSchedule(schedule: Schedule) {
57
+ const normalized = { enabled: true, runOnInit: false, ttlMs: 120_000, ...schedule };
58
+ schedules.push(normalized);
59
+
60
+ if (normalized.queue) {
61
+ // nothing to pre-register: schedule:work dispatches on each tick
62
+ } else if (!normalized.handler) {
63
+ console.warn(`Schedule "${normalized.name}" has no handler and no queue; nothing will run`);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Why: Loads module schedule files so schedules are registered.
69
+ * When: Scheduler boot process starts.
70
+ * Where: Scheduler worker startup.
71
+ * How: Discovers schedules/console files and imports them.
72
+ */
73
+ export async function bootSchedules() {
74
+ const files = await discoverModuleFiles("**/{schedules,console}/*.{ts,js}");
75
+ for (const file of files) await importFile(file);
76
+ return files.length;
77
+ }
78
+
79
+ function handlerRun(schedule: Schedule) {
80
+ return async () => {
81
+ await runWithLock(
82
+ schedule.name,
83
+ async () => {
84
+ const startMs = Date.now();
85
+ try {
86
+ await schedule.handler!();
87
+ printScheduleResult(schedule.name, startMs, true);
88
+ } catch (err: any) {
89
+ printScheduleResult(schedule.name, startMs, false, err?.message || String(err));
90
+ }
91
+ },
92
+ { ttlMs: schedule.ttlMs }
93
+ );
94
+ };
95
+ }
96
+
97
+ function queueDispatchRun(schedule: Schedule) {
98
+ return async () => {
99
+ await runWithLock(
100
+ schedule.name,
101
+ async () => {
102
+ const startMs = Date.now();
103
+ try {
104
+ const queue = getQueue(schedule.queue);
105
+ if (!queue) throw new Error(`Queue "${schedule.queue}" is unavailable`);
106
+ await queue.add(schedule.job ?? schedule.name, schedule.data ?? {});
107
+ printScheduleResult(schedule.name, startMs, true);
108
+ } catch (err: any) {
109
+ printScheduleResult(schedule.name, startMs, false, err?.message || String(err));
110
+ }
111
+ },
112
+ { ttlMs: schedule.ttlMs }
113
+ );
114
+ };
115
+ }
116
+
117
+ /**
118
+ * Why: Starts cron tasks for all enabled schedules.
119
+ * When: Scheduler worker process boots.
120
+ * Where: `schedule:work` runtime.
121
+ * How: Creates a croner task per enabled schedule — handler schedules run the
122
+ * callback in-process, queue-mode schedules dispatch a job to their queue
123
+ * on each tick (the target worker processes it). Boots once for
124
+ * `runOnInit` handlers and `immediately` queue schedules.
125
+ */
126
+ export async function startScheduler() {
127
+ await bootSchedules();
128
+
129
+ for (const schedule of schedules) {
130
+ if (!schedule.enabled) continue;
131
+ const run = schedule.handler ? handlerRun(schedule) : queueDispatchRun(schedule);
132
+ tasks.push(new Cron(schedule.expression, { timezone: schedule.timezone, name: schedule.name }, run));
133
+ }
134
+
135
+ printHeader();
136
+
137
+ for (const schedule of schedules) {
138
+ if (!schedule.enabled) continue;
139
+ if (schedule.handler && schedule.runOnInit) await handlerRun(schedule)();
140
+ if (schedule.queue && schedule.immediately) await queueDispatchRun(schedule)();
141
+ }
142
+
143
+ return schedules.length;
144
+ }
145
+
146
+ /**
147
+ * Why: Stops and destroys active cron tasks.
148
+ * When: Scheduler shutdown.
149
+ * Where: Process lifecycle handlers.
150
+ * How: Iterates task registry and invokes stop on each croner job.
151
+ */
152
+ export async function stopScheduler() {
153
+ await Promise.all(tasks.map((task) => task.stop()));
154
+ tasks.length = 0;
155
+ }
@@ -0,0 +1,162 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import chalk from "chalk";
4
+ import { appConfig, mailConfig, realtimeConfig, redisConfig } from "@/config/index.js";
5
+ import { createKernel } from "@/framework/kernel.js";
6
+ import { stopQueueRuntime } from "@/framework/queue/queue.js";
7
+ import { stopQueueDashboard } from "@/framework/queue/ui.js";
8
+ import { broadcast, closeRealtime, socketServer, WS_PATH } from "@/framework/realtime/index.js";
9
+ import { setupSocketAdminUI } from "@/framework/realtime/ui.js";
10
+ import { closeRedis, redisClientIfReady, redisError, redisReady } from "@/framework/redis/client.js";
11
+ import { type HttpServerHandle, startHttpServer } from "@/framework/runtime/server-adapter.js";
12
+ import { parseCsvOrFallback, registerShutdownSignals, type ShutdownSignal } from "@/framework/support/lifecycle.js";
13
+ import { logger } from "@/framework/support/logger.js";
14
+
15
+ const redisBackedServices = "cache, session, queue, events, Queue Dashboard";
16
+
17
+ function serverUrl(server: HttpServerHandle, pathname = "") {
18
+ const address = server.address();
19
+ const port = typeof address === "object" && address ? address.port : appConfig.port;
20
+ try {
21
+ const currentUrl = new URL(appConfig.url);
22
+ currentUrl.port = String(port);
23
+ if (currentUrl.hostname === "0.0.0.0" || currentUrl.hostname === "::") {
24
+ currentUrl.hostname = "localhost";
25
+ }
26
+ return `${currentUrl.toString().replace(/\/$/, "")}${pathname}`;
27
+ } catch {
28
+ return `http://localhost:${port}${pathname}`;
29
+ }
30
+ }
31
+
32
+ export interface ServerHandle {
33
+ app: Awaited<ReturnType<typeof createKernel>>["app"];
34
+ bullBoard: Awaited<ReturnType<typeof createKernel>>["bullBoard"];
35
+ server: HttpServerHandle;
36
+ realtime: any; // Type for Fastify is simpler
37
+ broadcastSubClient: ReturnType<typeof redisClientIfReady> | null;
38
+ shutdown: (signal: ShutdownSignal) => Promise<void>;
39
+ closeHttpServer: () => Promise<void>;
40
+ }
41
+
42
+ export async function startServer(): Promise<ServerHandle> {
43
+ const { app, bullBoard } = await createKernel();
44
+
45
+ // 1. Start the server (this internally attaches Socket.IO for Fastify)
46
+ const server = await startHttpServer(app, appConfig.port);
47
+
48
+ // 2. Grab the existing Socket.IO instance
49
+ const io = socketServer();
50
+ const realtime = io ? { io } : null;
51
+ const socketAdmin = setupSocketAdminUI(io);
52
+
53
+ let shuttingDown = false;
54
+ let broadcastSubClient: ReturnType<typeof redisClientIfReady> | null = null;
55
+
56
+ async function closeHttpServer() {
57
+ await server.close();
58
+ }
59
+
60
+ async function shutdown(signal: ShutdownSignal) {
61
+ if (shuttingDown) return;
62
+ shuttingDown = true;
63
+
64
+ logger.info("Shutdown signal received", { signal });
65
+ if (broadcastSubClient) {
66
+ try {
67
+ await broadcastSubClient.quit();
68
+ } catch {
69
+ broadcastSubClient.disconnect();
70
+ }
71
+ broadcastSubClient = null;
72
+ }
73
+
74
+ // closeRealtime is handled by server.close() adapter
75
+ await Promise.allSettled([stopQueueRuntime(), closeHttpServer()]);
76
+ stopQueueDashboard();
77
+ await closeRedis();
78
+
79
+ process.exit(0);
80
+ }
81
+
82
+ registerShutdownSignals(shutdown);
83
+
84
+ if (redisConfig.enabled && realtime) {
85
+ const redis = redisClientIfReady();
86
+ if (redis) {
87
+ broadcastSubClient = redis.duplicate();
88
+ await broadcastSubClient.connect();
89
+ const channel = `${redisConfig.prefix}:broadcast`;
90
+ await broadcastSubClient.subscribe(channel);
91
+ broadcastSubClient.on("message", (_channel: string, message: string) => {
92
+ try {
93
+ const { event, payload, options } = JSON.parse(message);
94
+ if (event) broadcast(event, payload, options);
95
+ } catch (error) {
96
+ logger.error("Broadcast relay error", { error });
97
+ }
98
+ });
99
+ }
100
+ }
101
+
102
+ const views = new Set(parseCsvOrFallback(process.env.NEXWIRE_DEV_VIEWS, []).map((view) => view.toLowerCase()));
103
+
104
+ if (appConfig.openApiEnabled) {
105
+ console.log(`API Docs: ${serverUrl(server, "/api-docs")}`);
106
+ }
107
+
108
+ if (appConfig.uiEnabled) {
109
+ console.log(`UI: ${process.env.NEXWIRE_FRONTEND_URL}`);
110
+ } else {
111
+ console.log(chalk.gray("UI: .env -> UI=false (API-only mode)"));
112
+ }
113
+
114
+ if (redisConfig.enabled && bullBoard.enabled) {
115
+ console.log(`Queue: ${serverUrl(server, bullBoard.basePath)}`);
116
+ }
117
+
118
+ if (views.has("maildev")) {
119
+ console.log(`MailDev: http://localhost:${mailConfig.maildev.webPort} (SMTP ${mailConfig.maildev.smtpPort})`);
120
+ }
121
+
122
+ if (views.has("studio")) {
123
+ console.log("Drizzle: https://local.drizzle.studio");
124
+ }
125
+
126
+ const wsUrl = serverUrl(server, WS_PATH).replace(/^http/, "ws");
127
+ if (!realtimeConfig.enabled) {
128
+ console.log(chalk.gray("Realtime (Socket.IO) disabled"));
129
+ } else if (realtime) {
130
+ if (socketAdmin.enabled) {
131
+ console.log(`Realtime: https://admin.socket.io | ${wsUrl}`);
132
+ } else {
133
+ console.log(`Realtime: ${wsUrl}`);
134
+ }
135
+ } else {
136
+ console.log(chalk.yellow("Realtime (Socket.IO) unavailable"));
137
+ }
138
+
139
+ if (redisConfig.enabled && views.has("redis")) {
140
+ console.log(`Redis UI: http://localhost:${redisConfig.commanderPort}`);
141
+ }
142
+
143
+ if (!redisConfig.enabled) {
144
+ console.log(chalk.cyan(`Redis: .env -> REDIS=false (disabled ${redisBackedServices})`));
145
+ } else if (redisReady()) {
146
+ console.log(chalk.green(`Redis connected: ${redisConfig.url}`));
147
+ console.log(chalk.green(`Redis-backed services enabled: ${redisBackedServices}`));
148
+ } else {
149
+ console.log(chalk.yellow(`Redis unavailable: ${redisError() || "not connected"}`));
150
+ console.log(chalk.yellow(`Redis-backed services unavailable: ${redisBackedServices}`));
151
+ }
152
+
153
+ console.log(`${appConfig.name} API running on ${serverUrl(server)}`);
154
+
155
+ return { app, bullBoard, server, realtime, broadcastSubClient, shutdown, closeHttpServer };
156
+ }
157
+
158
+ const currentFile = fileURLToPath(import.meta.url);
159
+ const isMain = process.argv[1] && path.resolve(process.argv[1]) === path.resolve(currentFile);
160
+ if (isMain) {
161
+ await startServer();
162
+ }
@@ -0,0 +1,160 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import type { FastifyReply, FastifyRequest } from "fastify";
3
+ import { appConfig, redisConfig, sessionConfig } from "@/config/index.js";
4
+ import { createCircuitBreaker, isCircuitBreakerError } from "@/framework/circuit-breaker/cb.js";
5
+ import { redisClientIfReady } from "@/framework/redis/client.js";
6
+
7
+ // Initialize the breaker for Session operations
8
+ const sessionBreaker = createCircuitBreaker({
9
+ name: "Redis Session",
10
+ failureThreshold: 3,
11
+ resetTimeout: 30000
12
+ });
13
+
14
+ function originOf(url?: string) {
15
+ if (!url) return "";
16
+ try {
17
+ return new URL(url).origin;
18
+ } catch {
19
+ return "";
20
+ }
21
+ }
22
+
23
+ function needsCrossSiteCookie() {
24
+ const appOrigin = originOf(appConfig.url);
25
+ const frontendOrigin = originOf(appConfig.frontendUrl);
26
+ return Boolean(appOrigin && frontendOrigin && appOrigin !== frontendOrigin);
27
+ }
28
+
29
+ function sessionKey(id: string) {
30
+ return `${sessionConfig.keyPrefix}:${id}`;
31
+ }
32
+
33
+ /**
34
+ * Global hook that ensures every request has a session cookie.
35
+ *
36
+ * Runs in an onRequest hook, after `@fastify/cookie` has parsed the header, so
37
+ * `request.cookies` is available. The session id is exposed on the request for
38
+ * downstream handlers, mirroring Express's `res.locals.sessionId`.
39
+ */
40
+ export async function sessionMiddleware(request: FastifyRequest, reply: FastifyReply) {
41
+ let sessionId = request.cookies?.[sessionConfig.cookieName];
42
+
43
+ if (!sessionId) {
44
+ sessionId = randomUUID();
45
+ const crossSiteCookie = needsCrossSiteCookie();
46
+ reply.setCookie(sessionConfig.cookieName, sessionId, {
47
+ httpOnly: true,
48
+ sameSite: crossSiteCookie ? "none" : "lax",
49
+ secure: crossSiteCookie,
50
+ path: "/",
51
+ // @fastify/cookie expects maxAge in seconds.
52
+ maxAge: sessionConfig.ttlSeconds
53
+ });
54
+ }
55
+
56
+ request.sessionId = sessionId;
57
+
58
+ // Refresh is safely wrapped in the breaker internally
59
+ await session.refresh(sessionId);
60
+ }
61
+
62
+ /** Redis-backed server-side session store. */
63
+ export const session = {
64
+ async start(data: Record<string, unknown> = {}) {
65
+ const client = redisClientIfReady();
66
+ if (!client) return "";
67
+
68
+ try {
69
+ return await sessionBreaker.exec(async () => {
70
+ const id = randomUUID();
71
+ await client.set(sessionKey(id), JSON.stringify(data), "EX", sessionConfig.ttlSeconds);
72
+ return id;
73
+ });
74
+ } catch (error) {
75
+ if (isCircuitBreakerError(error)) return "";
76
+ return "";
77
+ }
78
+ },
79
+
80
+ async all<T = Record<string, unknown>>(id: string): Promise<T | null> {
81
+ const client = redisClientIfReady();
82
+ if (!client) return null;
83
+
84
+ try {
85
+ return await sessionBreaker.exec(async () => {
86
+ const data = await client.get(sessionKey(id));
87
+ return data ? (JSON.parse(data) as T) : null;
88
+ });
89
+ } catch (error) {
90
+ if (isCircuitBreakerError(error)) return null;
91
+ return null;
92
+ }
93
+ },
94
+
95
+ async get<T>(id: string, key: string): Promise<T | null> {
96
+ const data = await session.all<Record<string, T>>(id);
97
+ return data?.[key] ?? null;
98
+ },
99
+
100
+ async set(id: string, key: string, value: unknown) {
101
+ const client = redisClientIfReady();
102
+ if (!client) return false;
103
+
104
+ try {
105
+ return await sessionBreaker.exec(async () => {
106
+ // Read through the client directly rather than `session.all()`. Calling
107
+ // another breaker-wrapped method from inside `exec` deadlocks the
108
+ // half-open probe: the inner call sees the outer probe in flight and
109
+ // rejects, so a `set` could never be the call that closes the breaker.
110
+ const raw = await client.get(sessionKey(id));
111
+ const data = raw ? (JSON.parse(raw) as Record<string, unknown>) : {};
112
+ data[key] = value;
113
+ await client.set(sessionKey(id), JSON.stringify(data), "EX", sessionConfig.ttlSeconds);
114
+ return true;
115
+ });
116
+ } catch (error) {
117
+ if (isCircuitBreakerError(error)) return false;
118
+ return false;
119
+ }
120
+ },
121
+
122
+ /** @deprecated Use set() instead. */
123
+ async put(id: string, key: string, value: unknown) {
124
+ return this.set(id, key, value);
125
+ },
126
+
127
+ async refresh(id: string) {
128
+ const client = redisClientIfReady();
129
+ if (!client) return false;
130
+
131
+ try {
132
+ return await sessionBreaker.exec(async () => {
133
+ await client.expire(sessionKey(id), sessionConfig.ttlSeconds);
134
+ return true;
135
+ });
136
+ } catch (error) {
137
+ if (isCircuitBreakerError(error)) return false;
138
+ return false;
139
+ }
140
+ },
141
+
142
+ async destroy(id: string) {
143
+ const client = redisClientIfReady();
144
+ if (!client) return false;
145
+
146
+ try {
147
+ return await sessionBreaker.exec(async () => {
148
+ await client.del(sessionKey(id));
149
+ return true;
150
+ });
151
+ } catch (error) {
152
+ if (isCircuitBreakerError(error)) return false;
153
+ return false;
154
+ }
155
+ },
156
+
157
+ isAvailable() {
158
+ return redisConfig.enabled && redisClientIfReady() !== null && sessionBreaker.getState() !== "open";
159
+ }
160
+ };