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
@@ -5,17 +5,44 @@
5
5
  * How: Re-exports stable, reusable helpers while hiding setup internals.
6
6
  */
7
7
 
8
+ // ==========================================
9
+ // 1. External & Core Utilities
10
+ // ==========================================
8
11
  export { createRoute, z } from "@hono/zod-openapi";
9
12
  export * as lodash from "lodash-es";
10
13
  export * as HttpStatusCodes from "stoker/http-status-codes";
11
14
  export { jsonContent } from "stoker/openapi/helpers";
15
+ // ==========================================
16
+ // 6. Cache & Session
17
+ // ==========================================
12
18
  export { cache } from "@/framework/cache/cache.js";
19
+ // ==========================================
20
+ // 2. Database
21
+ // ==========================================
13
22
  export { database, db } from "@/framework/database/connection.js";
14
23
  export { type PaginatedResult, paginate, paginateModel, paginateQuery, paginateTable } from "@/framework/database/paginate.js";
24
+ // ==========================================
25
+ // 4. Events & Queue
26
+ // ==========================================
15
27
  export { command, dispatchCommand, dispatchEvent } from "@/framework/events/dispatcher.js";
28
+ // ==========================================
29
+ // 3. HTTP & Routing
30
+ // ==========================================
31
+ export { loginLimiter } from "@/framework/http/ratelimiter.js";
16
32
  export { createRouter, group } from "@/framework/http/router.js";
17
33
  export { validate } from "@/framework/http/validation.js";
34
+ export { broadcastChannel } from "@/framework/notification/channels/broadcast.js";
35
+ export { mailChannel } from "@/framework/notification/channels/mail.js";
36
+ export type { NotificationChannel, NotificationOptions } from "@/framework/notification/contracts.js";
37
+ // ==========================================
38
+ // 10. Notification Engine (Delivery Channels)
39
+ // ==========================================
18
40
  export { notify } from "@/framework/notification/index.js";
41
+ export { registerChannel } from "@/framework/notification/registry.js";
42
+ // ==========================================
43
+ // 9. Providers (Storage/Auth)
44
+ // ==========================================
45
+ export { resolveAuthProvider, resolveNotificationProvider } from "@/framework/providers/adapter.js";
19
46
  export type {
20
47
  AuthProvider,
21
48
  AuthProviderRefreshToken,
@@ -29,7 +56,6 @@ export type {
29
56
  NotificationProvider,
30
57
  NotificationRecord
31
58
  } from "@/framework/providers/contracts.js";
32
- export { resolveAuthProvider, resolveNotificationProvider } from "@/framework/providers/adapter.js";
33
59
  export { loadProviders } from "@/framework/providers/loader.js";
34
60
  export {
35
61
  clearAuthProvider,
@@ -47,12 +73,24 @@ export {
47
73
  registerProvider
48
74
  } from "@/framework/providers/registry.js";
49
75
  export { queue, queueJob, shouldQueue } from "@/framework/queue/queue.js";
76
+ // ==========================================
77
+ // 5. Realtime
78
+ // ==========================================
50
79
  export { broadcast } from "@/framework/realtime/index.js";
51
80
  export { defineSchedule } from "@/framework/scheduler/scheduler.js";
52
81
  export { session } from "@/framework/session/session.js";
82
+ // ==========================================
83
+ // 7. Storage & Mail
84
+ // ==========================================
53
85
  export { storage } from "@/framework/storage/storage.js";
86
+ // ==========================================
87
+ // 8. Security & Auth
88
+ // ==========================================
54
89
  export { cookie } from "@/framework/support/cookie.js";
55
90
  export { jwt } from "@/framework/support/jwt.js";
91
+ // ==========================================
92
+ // 11. Utilities
93
+ // ==========================================
56
94
  export { logger } from "@/framework/support/logger.js";
57
95
  export { mail } from "@/framework/support/mail.js";
58
96
  export { password } from "@/framework/support/password.js";
@@ -1,81 +1,86 @@
1
- import type { Context, Next } from "hono";
2
- import { loggingConfig } from "@/config/index.js";
3
- import { logger } from "@/framework/support/logger.js";
4
-
5
- function ip(c: Context) {
6
- return c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for") || c.req.header("x-real-ip") || null;
7
- }
8
-
9
- function shouldSkipHttpLog(pathname: string) {
10
- return pathname.startsWith("/queues");
11
- }
12
-
13
- /**
14
- * Why: Logs each HTTP request with latency and request metadata.
15
- * When: Applied globally to app routes.
16
- * Where: HTTP middleware stack.
17
- * How: Captures start time, assigns request id, logs after downstream response.
18
- */
19
- export async function loggerMiddleware(c: Context, next: Next) {
20
- const start = Date.now();
21
- const requestId = crypto.randomUUID();
22
-
23
- c.set("requestId", requestId);
24
- await next();
25
-
26
- if (!loggingConfig.httpRequests || shouldSkipHttpLog(c.req.path)) {
27
- return;
28
- }
29
-
30
- logger.info("HTTP Request", {
31
- requestId,
32
- method: c.req.method,
33
- path: c.req.path,
34
- url: c.req.url,
35
- status: c.res.status,
36
- duration_ms: Date.now() - start,
37
- ip: ip(c),
38
- userAgent: c.req.header("user-agent") || null
39
- });
40
- }
41
-
42
- /**
43
- * Why: Standard 404 handler with structured log context.
44
- * When: No route matches request path.
45
- * Where: App notFound handler registration.
46
- * How: Emits warning log and returns JSON 404 payload.
47
- */
48
- export function notFound(c: Context) {
49
- logger.warn("404 Not Found", {
50
- requestId: c.get("requestId") || null,
51
- method: c.req.method,
52
- path: c.req.path,
53
- url: c.req.url,
54
- ip: ip(c),
55
- userAgent: c.req.header("user-agent") || null
56
- });
57
-
58
- return c.json({ message: "Not Found" }, 404);
59
- }
60
-
61
- /**
62
- * Why: Centralized unhandled error responder and logger.
63
- * When: Route/middleware throws uncaught error.
64
- * Where: App onError handler registration.
65
- * How: Logs stack + request context and returns status/message JSON.
66
- */
67
- export function onError(error: any, c: Context) {
68
- logger.error("Unhandled Application Error", {
69
- requestId: c.get("requestId") || null,
70
- name: error?.name || "Error",
71
- message: error?.message,
72
- stack: error?.stack,
73
- method: c.req.method,
74
- path: c.req.path,
75
- url: c.req.url,
76
- ip: ip(c),
77
- userAgent: c.req.header("user-agent") || null
78
- });
79
-
80
- return c.json({ message: error?.message || "Internal Server Error" }, error?.status || 500);
81
- }
1
+ import type { Context, Next } from "hono";
2
+ import { loggingConfig } from "@/config/index.js";
3
+ import { logger } from "@/framework/support/logger.js";
4
+
5
+ function ip(c: Context) {
6
+ return c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for") || c.req.header("x-real-ip") || null;
7
+ }
8
+
9
+ // Probe endpoints and the queue dashboard are infrastructure traffic, not
10
+ // application requests. Skip them on every engine so the access log stays
11
+ // useful (the dev CLI polls /health while it boots).
12
+ const PROBE_PATHS = new Set(["/health", "/ready", "/live"]);
13
+
14
+ function shouldSkipHttpLog(pathname: string) {
15
+ return PROBE_PATHS.has(pathname) || pathname.startsWith("/queues");
16
+ }
17
+
18
+ /**
19
+ * Why: Logs each HTTP request with latency and request metadata.
20
+ * When: Applied globally to app routes.
21
+ * Where: HTTP middleware stack.
22
+ * How: Captures start time, assigns request id, logs after downstream response.
23
+ */
24
+ export async function loggerMiddleware(c: Context, next: Next) {
25
+ const start = Date.now();
26
+ const requestId = crypto.randomUUID();
27
+
28
+ c.set("requestId", requestId);
29
+ await next();
30
+
31
+ if (!loggingConfig.httpRequests || shouldSkipHttpLog(c.req.path)) {
32
+ return;
33
+ }
34
+
35
+ logger.info("HTTP Request", {
36
+ requestId,
37
+ method: c.req.method,
38
+ path: c.req.path,
39
+ url: c.req.url,
40
+ status: c.res.status,
41
+ duration_ms: Date.now() - start,
42
+ ip: ip(c),
43
+ userAgent: c.req.header("user-agent") || null
44
+ });
45
+ }
46
+
47
+ /**
48
+ * Why: Standard 404 handler with structured log context.
49
+ * When: No route matches request path.
50
+ * Where: App notFound handler registration.
51
+ * How: Emits warning log and returns JSON 404 payload.
52
+ */
53
+ export function notFound(c: Context) {
54
+ logger.warn("404 Not Found", {
55
+ requestId: c.get("requestId") || null,
56
+ method: c.req.method,
57
+ path: c.req.path,
58
+ url: c.req.url,
59
+ ip: ip(c),
60
+ userAgent: c.req.header("user-agent") || null
61
+ });
62
+
63
+ return c.json({ message: "Not Found" }, 404);
64
+ }
65
+
66
+ /**
67
+ * Why: Centralized unhandled error responder and logger.
68
+ * When: Route/middleware throws uncaught error.
69
+ * Where: App onError handler registration.
70
+ * How: Logs stack + request context and returns status/message JSON.
71
+ */
72
+ export function onError(error: any, c: Context) {
73
+ logger.error("Unhandled Application Error", {
74
+ requestId: c.get("requestId") || null,
75
+ name: error?.name || "Error",
76
+ message: error?.message,
77
+ stack: error?.stack,
78
+ method: c.req.method,
79
+ path: c.req.path,
80
+ url: c.req.url,
81
+ ip: ip(c),
82
+ userAgent: c.req.header("user-agent") || null
83
+ });
84
+
85
+ return c.json({ message: error?.message || "Internal Server Error" }, error?.status || 500);
86
+ }
@@ -11,6 +11,8 @@ import type { NexwireRouter } from "@/framework/http/router.js";
11
11
  * How: Exposes `/doc` spec and `/api-docs` Scalar viewer.
12
12
  */
13
13
  export function configureOpenApi(app: NexwireRouter) {
14
+ const { specUrl, docsPath, favicon, ...scalarOptions } = openApiConfig.scalar;
15
+
14
16
  app.doc("/doc", {
15
17
  openapi: openApiConfig.version,
16
18
  info: {
@@ -20,23 +22,19 @@ export function configureOpenApi(app: NexwireRouter) {
20
22
  }
21
23
  });
22
24
 
23
- if (openApiConfig.scalar.favicon) {
25
+ if (favicon) {
24
26
  app.get("/favicon.ico", (c) => {
25
- const faviconPath = path.join(process.cwd(), openApiConfig.scalar.favicon);
27
+ const faviconPath = path.join(process.cwd(), favicon);
26
28
  if (!fs.existsSync(faviconPath)) return c.notFound();
27
29
  return c.body(fs.readFileSync(faviconPath), 200, { "content-type": "image/x-icon" });
28
30
  });
29
31
  }
30
32
 
31
33
  app.get(
32
- openApiConfig.scalar.docsPath,
34
+ docsPath, // Use the destructured path
33
35
  Scalar({
34
- url: openApiConfig.scalar.specUrl,
35
- layout: openApiConfig.scalar.layout,
36
- theme: openApiConfig.scalar.theme,
37
- pageTitle: openApiConfig.scalar.pageTitle,
38
- defaultHttpClient: openApiConfig.scalar.defaultHttpClient,
39
- defaultOpenAllTags: openApiConfig.scalar.defaultOpenAllTags
36
+ url: specUrl, // Use the destructured URL
37
+ ...scalarOptions // Pass EVERYTHING else automatically!
40
38
  })
41
39
  );
42
40
  }
@@ -120,7 +120,7 @@ function serveRedisUnavailablePage(port, endpoint) {
120
120
  </html>
121
121
  `;
122
122
 
123
- return new Promise((resolve, reject) => {
123
+ return new Promise((_resolve, reject) => {
124
124
  const server = http.createServer((_req, res) => {
125
125
  res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
126
126
  res.end(body);
@@ -558,4 +558,3 @@ export async function clearViteCache() {
558
558
 
559
559
  console.log("Vite cache cleared.");
560
560
  }
561
-
@@ -0,0 +1,15 @@
1
+ import { dispatchEvent } from "@/framework/events/dispatcher.js";
2
+ import type { NotificationChannel } from "@/framework/notification/contracts.js";
3
+
4
+ export const broadcastChannel: NotificationChannel = {
5
+ name: "broadcast",
6
+ async send(target, notification, options) {
7
+ if (!options.broadcast) return false;
8
+
9
+ await dispatchEvent("notification.created", notification, {
10
+ broadcast: { users: [target.id] }
11
+ });
12
+
13
+ return true;
14
+ }
15
+ };
@@ -0,0 +1,42 @@
1
+ import { dispatchEvent } from "@/framework/events/dispatcher.js";
2
+ import type { NotificationChannel } from "@/framework/notification/contracts.js";
3
+ import { resolveAuthProvider } from "@/framework/providers/adapter.js";
4
+ import { redisClientIfReady } from "@/framework/redis/client.js";
5
+ import { mail } from "@/framework/support/mail.js";
6
+
7
+ function escapeHtml(str: string) {
8
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
9
+ }
10
+
11
+ export const mailChannel: NotificationChannel = {
12
+ name: "mail",
13
+ async send(target, notification, options) {
14
+ if (!options.mail) return false;
15
+
16
+ let to = options.mail.to || null;
17
+ if (!to) {
18
+ try {
19
+ const provider = await resolveAuthProvider();
20
+ if (provider?.getUserContact) {
21
+ const contact = await provider.getUserContact(target.id);
22
+ if (contact?.email) to = contact.email as string;
23
+ }
24
+ } catch {}
25
+ }
26
+
27
+ if (!to) return false;
28
+
29
+ const subject = options.mail.subject || notification.title;
30
+ const html =
31
+ options.mail.html ||
32
+ `<h2>${escapeHtml(notification.title)}</h2>${notification.body ? `<p>${escapeHtml(notification.body)}</p>` : ""}`;
33
+
34
+ if (redisClientIfReady()) {
35
+ await dispatchEvent("notification:mail", { to, subject, html }, { queue: "mail" });
36
+ } else {
37
+ await mail.sendMail({ to, subject, html });
38
+ }
39
+
40
+ return true;
41
+ }
42
+ };
@@ -0,0 +1,29 @@
1
+ import type { NotifiableTarget, NotificationRecord } from "@/framework/providers/contracts.js";
2
+
3
+ export type NotificationTarget = number | string | NotifiableTarget;
4
+ export type NormalizedTarget = { type: string; id: number | string };
5
+
6
+ export type NotificationOptions = {
7
+ type?: string;
8
+ title: string;
9
+ body?: string;
10
+ link?: string;
11
+ data?: Record<string, unknown>;
12
+
13
+ // Built-in Channels
14
+ broadcast?: boolean;
15
+ mail?: {
16
+ to?: string;
17
+ subject?: string;
18
+ html?: string;
19
+ };
20
+
21
+ // Extensible: Add any custom channel options here (e.g., sms, push, discord)
22
+ sms?: { to?: string; message?: string };
23
+ push?: { token?: string; payload?: any };
24
+ };
25
+
26
+ export interface NotificationChannel {
27
+ name: string;
28
+ send(target: NormalizedTarget, notification: NotificationRecord, options: NotificationOptions): Promise<boolean>;
29
+ }
@@ -1,39 +1,12 @@
1
- import { dispatchEvent } from "@/framework/events/dispatcher.js";
2
- import { resolveAuthProvider, resolveNotificationProvider } from "@/framework/providers/adapter.js";
3
- import type { NotifiableTarget, NotificationRecord } from "@/framework/providers/contracts.js";
4
- import { redisClientIfReady } from "@/framework/redis/client.js";
5
- import { mail } from "@/framework/support/mail.js";
1
+ import type { NormalizedTarget, NotificationOptions, NotificationTarget } from "@/framework/notification/contracts.js";
2
+ import { getChannels } from "@/framework/notification/registry.js";
3
+ import { resolveNotificationProvider } from "@/framework/providers/adapter.js";
4
+ import type { NotificationRecord } from "@/framework/providers/contracts.js";
6
5
 
7
6
  let missingProviderWarned = false;
8
7
 
9
- /** A numeric id (default auth), a string id (UUID/ULID), or an explicit target. */
10
- export type NotificationTarget = number | string | NotifiableTarget;
11
-
12
- /** Extra JSON metadata attached to the notification (e.g. entity IDs, links). */
13
- export type NotificationOptions = {
14
- /** Notification category key (default: "info") */
15
- type?: string;
16
- /** Notification title */
17
- title: string;
18
- /** Notification body text */
19
- body?: string;
20
- /** Optional click-through URL */
21
- link?: string;
22
- /** Arbitrary JSON payload stored in `data` column */
23
- data?: Record<string, unknown>;
24
- /** Whether to broadcast the notification to the user's socket in realtime */
25
- broadcast?: boolean;
26
- /** Email delivery options */
27
- mail?: {
28
- /** Explicit recipient. Skips the auth provider contact lookup. */
29
- to?: string;
30
- subject?: string;
31
- html?: string;
32
- };
33
- };
34
-
35
8
  /** Turn the public target argument into the polymorphic owner pair. */
36
- function normalizeTarget(target: NotificationTarget): Required<Pick<NotifiableTarget, "id">> & { type: string } {
9
+ function normalizeTarget(target: NotificationTarget): NormalizedTarget {
37
10
  if (target !== null && typeof target === "object") {
38
11
  return {
39
12
  type: String(target.type || "user").trim() || "user",
@@ -44,13 +17,10 @@ function normalizeTarget(target: NotificationTarget): Required<Pick<NotifiableTa
44
17
  }
45
18
 
46
19
  /**
47
- * Why: Persists a notification through the registered provider.
48
- * When: A feature wants to record something for a user (or another notifiable).
20
+ * Why: Persists a notification to the database and triggers all active channels.
21
+ * When: A feature wants to record something for a user.
49
22
  * Where: Application code, through the framework facade.
50
- * How: The provider owns storage; broadcasting and email stay here so a custom
51
- * store cannot silently disable them. A missing provider is reported once
52
- * and returns `null` instead of throwing, matching the framework's
53
- * "optional module" behaviour.
23
+ * How: The provider owns database storage. The channels handle delivery (mail, sms, ws).
54
24
  */
55
25
  export async function notify(target: NotificationTarget, options: NotificationOptions): Promise<NotificationRecord | null> {
56
26
  const provider = await resolveNotificationProvider();
@@ -65,6 +35,8 @@ export async function notify(target: NotificationTarget, options: NotificationOp
65
35
  }
66
36
 
67
37
  const normalizedTarget = normalizeTarget(target);
38
+
39
+ // 1. Save to Database via the Provider
68
40
  const normalized = await provider.create(normalizedTarget, {
69
41
  type: options.type,
70
42
  title: options.title,
@@ -73,62 +45,15 @@ export async function notify(target: NotificationTarget, options: NotificationOp
73
45
  data: options.data ?? null
74
46
  });
75
47
 
76
- if (options.broadcast) {
77
- await dispatchEvent("notification.created", normalized, {
78
- broadcast: { users: [normalizedTarget.id] }
79
- });
80
- }
81
-
82
- if (options.mail) {
83
- await sendMailChannel(normalizedTarget, normalized, options);
84
- }
48
+ // 2. Dispatch to all registered channels in parallel
49
+ const channels = getChannels();
50
+ await Promise.allSettled(
51
+ channels.map((channel) =>
52
+ channel.send(normalizedTarget, normalized, options).catch((err) => {
53
+ console.error(`[notification] Channel ${channel.name} failed:`, err);
54
+ })
55
+ )
56
+ );
85
57
 
86
58
  return normalized;
87
59
  }
88
-
89
- /** Deliver an email notification, either queued (if Redis is available) or direct. */
90
- async function sendMailChannel(
91
- target: { type: string; id: number | string },
92
- notification: NotificationRecord,
93
- options: NotificationOptions
94
- ) {
95
- let to: string | null = options.mail?.to || null;
96
-
97
- if (!to) {
98
- try {
99
- const provider = await resolveAuthProvider();
100
- if (provider?.getUserContact) {
101
- const contact = await provider.getUserContact(target.id);
102
- if (contact?.email) to = contact.email as string;
103
- }
104
- } catch {}
105
- }
106
-
107
- if (!to) return;
108
-
109
- const subject = options.mail?.subject || notification.title;
110
- const html = options.mail?.html || defaultMailHtml(notification.title, notification.body);
111
-
112
- if (redisClientIfReady()) {
113
- await dispatchEvent(
114
- "notification:mail",
115
- {
116
- to,
117
- subject,
118
- html
119
- },
120
- { queue: "mail" }
121
- );
122
- } else {
123
- await mail.sendMail({ to, subject, html });
124
- }
125
- }
126
-
127
- /** Generate a basic HTML email body from title and body text. */
128
- function defaultMailHtml(title: string, body: string | null) {
129
- return `<h2>${escapeHtml(title)}</h2>${body ? `<p>${escapeHtml(body)}</p>` : ""}`;
130
- }
131
-
132
- function escapeHtml(str: string) {
133
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
134
- }
@@ -0,0 +1,15 @@
1
+ import type { NotificationChannel } from "@/framework/notification/contracts.js";
2
+
3
+ const channels = new Map<string, NotificationChannel>();
4
+
5
+ export function registerChannel(channel: NotificationChannel) {
6
+ channels.set(channel.name, channel);
7
+ }
8
+
9
+ export function getChannels(): NotificationChannel[] {
10
+ return Array.from(channels.values());
11
+ }
12
+
13
+ export function clearChannels() {
14
+ channels.clear();
15
+ }
@@ -18,6 +18,7 @@ async function loadDefaultProvider(): Promise<AuthProvider | null> {
18
18
  if (defaultProvider) return defaultProvider;
19
19
  if (defaultLoadAttempted) return null;
20
20
  defaultLoadAttempted = true;
21
+
21
22
  try {
22
23
  const userMod = await import("@/modules/auth/database/models/user.js").catch(() => null);
23
24
  if (!userMod?.users || !userMod?.refreshTokens) return null;
@@ -25,22 +26,28 @@ async function loadDefaultProvider(): Promise<AuthProvider | null> {
25
26
  const users = userMod.users;
26
27
  const refreshTokens = userMod.refreshTokens;
27
28
 
28
- defaultProvider = {
29
- async getUserById(id: number | string) {
30
- try {
31
- const user = await (db.query.users.findFirst as any)?.({
32
- where: eq(users.id, id as any),
33
- with: { role: true }
34
- });
35
- if (user) return user;
36
- } catch {}
37
- try {
38
- const rows = await db.select().from(users).where(eq(users.id, id as any));
39
- return rows?.[0] ?? null;
40
- } catch {
41
- return null;
42
- }
43
- },
29
+ // Define the core logic as standalone functions to avoid `this` context issues
30
+ const getUserById = async (id: number | string) => {
31
+ try {
32
+ const user = await (db.query.users.findFirst as any)?.({
33
+ where: eq(users.id, id as any),
34
+ with: { role: true }
35
+ });
36
+ if (user) return user;
37
+ } catch {}
38
+ try {
39
+ const rows = await db
40
+ .select()
41
+ .from(users)
42
+ .where(eq(users.id, id as any));
43
+ return rows?.[0] ?? null;
44
+ } catch {
45
+ return null;
46
+ }
47
+ };
48
+
49
+ const provider: AuthProvider = {
50
+ getUserById,
44
51
  async findRefreshToken(jti: string) {
45
52
  try {
46
53
  const token = await (db.query.refreshTokens.findFirst as any)?.({
@@ -89,7 +96,8 @@ async function loadDefaultProvider(): Promise<AuthProvider | null> {
89
96
  },
90
97
  async getUserContact(userId: number | string) {
91
98
  try {
92
- const user = await this.getUserById(userId);
99
+ // Use the standalone function instead of `this.getUserById`
100
+ const user = await getUserById(userId);
93
101
  if (!user) return null;
94
102
  return {
95
103
  email: user.email ?? null,
@@ -101,6 +109,8 @@ async function loadDefaultProvider(): Promise<AuthProvider | null> {
101
109
  }
102
110
  }
103
111
  };
112
+
113
+ defaultProvider = provider;
104
114
  return defaultProvider;
105
115
  } catch {
106
116
  return null;