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
@@ -1,48 +1,48 @@
1
- CREATE TABLE `roles` (
2
- `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
3
- `name` text NOT NULL,
4
- `created_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL,
5
- `updated_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL
6
- );
7
- --> statement-breakpoint
8
- CREATE UNIQUE INDEX `roles_name_unique` ON `roles` (`name`);--> statement-breakpoint
9
- CREATE TABLE `email_verification_tokens` (
10
- `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
11
- `email` text NOT NULL,
12
- `token` text NOT NULL,
13
- `expires_at` integer NOT NULL,
14
- `created_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL
15
- );
16
- --> statement-breakpoint
17
- CREATE TABLE `password_reset_tokens` (
18
- `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
19
- `email` text NOT NULL,
20
- `token` text NOT NULL,
21
- `expires_at` integer NOT NULL,
22
- `created_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL
23
- );
24
- --> statement-breakpoint
25
- CREATE TABLE `refresh_tokens` (
26
- `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
27
- `user_id` integer,
28
- `jti` text NOT NULL,
29
- `revoked` integer DEFAULT false,
30
- `expires_at` integer NOT NULL,
31
- `created_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL,
32
- FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE cascade ON DELETE set null
33
- );
34
- --> statement-breakpoint
35
- CREATE UNIQUE INDEX `refresh_tokens_jti_unique` ON `refresh_tokens` (`jti`);--> statement-breakpoint
36
- CREATE TABLE `users` (
37
- `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
38
- `name` text NOT NULL,
39
- `email` text NOT NULL,
40
- `password` text NOT NULL,
41
- `role_id` integer,
42
- `email_verified_at` integer,
43
- `created_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL,
44
- `updated_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL,
45
- FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON UPDATE cascade ON DELETE set null
46
- );
47
- --> statement-breakpoint
1
+ CREATE TABLE `roles` (
2
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
3
+ `name` text NOT NULL,
4
+ `created_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL,
5
+ `updated_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL
6
+ );
7
+ --> statement-breakpoint
8
+ CREATE UNIQUE INDEX `roles_name_unique` ON `roles` (`name`);--> statement-breakpoint
9
+ CREATE TABLE `email_verification_tokens` (
10
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
11
+ `email` text NOT NULL,
12
+ `token` text NOT NULL,
13
+ `expires_at` integer NOT NULL,
14
+ `created_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL
15
+ );
16
+ --> statement-breakpoint
17
+ CREATE TABLE `password_reset_tokens` (
18
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
19
+ `email` text NOT NULL,
20
+ `token` text NOT NULL,
21
+ `expires_at` integer NOT NULL,
22
+ `created_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL
23
+ );
24
+ --> statement-breakpoint
25
+ CREATE TABLE `refresh_tokens` (
26
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
27
+ `user_id` integer,
28
+ `jti` text NOT NULL,
29
+ `revoked` integer DEFAULT false,
30
+ `expires_at` integer NOT NULL,
31
+ `created_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL,
32
+ FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE cascade ON DELETE set null
33
+ );
34
+ --> statement-breakpoint
35
+ CREATE UNIQUE INDEX `refresh_tokens_jti_unique` ON `refresh_tokens` (`jti`);--> statement-breakpoint
36
+ CREATE TABLE `users` (
37
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
38
+ `name` text NOT NULL,
39
+ `email` text NOT NULL,
40
+ `password` text NOT NULL,
41
+ `role_id` integer,
42
+ `email_verified_at` integer,
43
+ `created_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL,
44
+ `updated_at` integer DEFAULT (cast((julianday('now') - 2440587.5)*86400000 as integer)) NOT NULL,
45
+ FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON UPDATE cascade ON DELETE set null
46
+ );
47
+ --> statement-breakpoint
48
48
  CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "6",
3
3
  "dialect": "sqlite",
4
- "id": "f0fe475e-8a3e-4c5c-9b5e-9ec41ddfde71",
4
+ "id": "af502348-be37-45c6-84e4-df4db9f31bfb",
5
5
  "prevId": "00000000-0000-0000-0000-000000000000",
6
6
  "tables": {
7
7
  "roles": {
@@ -5,7 +5,7 @@
5
5
  {
6
6
  "idx": 0,
7
7
  "version": "6",
8
- "when": 1792936160057,
8
+ "when": 1793719238470,
9
9
  "tag": "0000_init",
10
10
  "breakpoints": true
11
11
  }
@@ -1,10 +1,18 @@
1
1
  import { cacheConfig, redisConfig } from "@/config/index.js";
2
+ import { createCircuitBreaker, isCircuitBreakerError } from "@/framework/circuit-breaker/cb.js";
2
3
  import { redisClientIfReady } from "@/framework/redis/client.js";
3
4
 
4
5
  function cacheKey(key: string) {
5
6
  return `${cacheConfig.keyPrefix}:${key}`;
6
7
  }
7
8
 
9
+ // Initialize the circuit breaker specifically for Cache operations
10
+ const cacheBreaker = createCircuitBreaker({
11
+ name: "Redis Cache",
12
+ failureThreshold: 3,
13
+ resetTimeout: 30000
14
+ });
15
+
8
16
  /**
9
17
  * Why: Provides Redis-backed cache helpers with graceful fallback behavior.
10
18
  * When: Controllers/jobs need temporary computed data caching.
@@ -20,18 +28,35 @@ export const cache = {
20
28
  */
21
29
  async get<T>(key: string, fallback: T | null = null) {
22
30
  const client = redisClientIfReady();
31
+ // If the client isn't connected at all, fail fast to fallback
23
32
  if (!client) return fallback;
24
33
 
25
- const value = await client.get(cacheKey(key));
26
- return value ? (JSON.parse(value) as T) : fallback;
34
+ try {
35
+ return await cacheBreaker.exec(async () => {
36
+ const value = await client.get(cacheKey(key));
37
+ return value ? (JSON.parse(value) as T) : fallback;
38
+ });
39
+ } catch (error) {
40
+ // If the circuit is open, or a Redis error occurs, return the fallback safely
41
+ if (isCircuitBreakerError(error)) return fallback;
42
+ return fallback;
43
+ }
27
44
  },
28
45
 
29
46
  async set(key: string, value: unknown, ttl = cacheConfig.ttlSeconds) {
30
47
  const client = redisClientIfReady();
31
48
  if (!client) return false;
32
49
 
33
- await client.set(cacheKey(key), JSON.stringify(value), "EX", ttl);
34
- return true;
50
+ try {
51
+ return await cacheBreaker.exec(async () => {
52
+ await client.set(cacheKey(key), JSON.stringify(value), "EX", ttl);
53
+ return true;
54
+ });
55
+ } catch (error) {
56
+ // If the circuit is open, or a Redis error occurs, silently fail
57
+ if (isCircuitBreakerError(error)) return false;
58
+ return false;
59
+ }
35
60
  },
36
61
 
37
62
  /**
@@ -51,8 +76,15 @@ export const cache = {
51
76
  const client = redisClientIfReady();
52
77
  if (!client) return false;
53
78
 
54
- await client.del(cacheKey(key));
55
- return true;
79
+ try {
80
+ return await cacheBreaker.exec(async () => {
81
+ await client.del(cacheKey(key));
82
+ return true;
83
+ });
84
+ } catch (error) {
85
+ if (isCircuitBreakerError(error)) return false;
86
+ return false;
87
+ }
56
88
  },
57
89
 
58
90
  /**
@@ -66,7 +98,7 @@ export const cache = {
66
98
  if (cached !== null) return cached;
67
99
 
68
100
  const fresh = await callback();
69
- await this.put(key, fresh, ttl);
101
+ await this.set(key, fresh, ttl);
70
102
  return fresh;
71
103
  },
72
104
 
@@ -77,6 +109,6 @@ export const cache = {
77
109
  * How: Confirms REDIS flag and ready Redis client instance.
78
110
  */
79
111
  isAvailable() {
80
- return redisConfig.enabled && redisClientIfReady() !== null;
112
+ return redisConfig.enabled && redisClientIfReady() !== null && cacheBreaker.getState() !== "open";
81
113
  }
82
114
  };
@@ -1,60 +1,88 @@
1
- export class CircuitBreaker {
2
- private state: "closed" | "open" | "half-open" = "closed";
3
- private failureCount = 0;
4
- private readonly failureThreshold = 3;
5
- private readonly resetTimeout = 30000;
6
- private lastFailureTime = 0;
7
- private successCount = 0;
8
- private readonly successThreshold = 1;
9
-
10
- async exec<T>(fn: () => Promise<T>): Promise<T> {
11
- if (this.state === "open") {
12
- if (Date.now() - this.lastFailureTime >= this.resetTimeout) {
13
- this.state = "half-open";
14
- this.successCount = 0;
15
- } else {
16
- throw new Error("Circuit breaker is open");
17
- }
18
- }
19
- try {
20
- const result = await fn();
21
- this.onSuccess();
22
- return result;
23
- } catch (error) {
24
- this.onFailure();
25
- throw error;
26
- }
27
- }
28
-
29
- getState(): "closed" | "open" | "half-open" {
30
- return this.state;
31
- }
32
-
33
- onSuccess(): void {
34
- if (this.state === "half-open") {
35
- this.successCount++;
36
- if (this.successCount >= this.successThreshold) {
37
- this.reset();
38
- }
39
- }
40
- this.failureCount = 0;
41
- }
42
-
43
- onFailure(): void {
44
- this.failureCount++;
45
- if (this.failureCount >= this.failureThreshold || this.state === "half-open") {
46
- this.trip();
47
- }
48
- }
49
-
50
- trip(): void {
51
- this.state = "open";
52
- this.lastFailureTime = Date.now();
53
- }
54
-
55
- reset(): void {
56
- this.state = "closed";
57
- this.failureCount = 0;
58
- this.successCount = 0;
59
- }
60
- }
1
+ // Factory for the error
2
+ export function createCircuitBreakerError(serviceName: string) {
3
+ const error = new Error(`Circuit breaker is open for ${serviceName}. Service is temporarily unavailable.`);
4
+ // Attach a custom property to identify it
5
+ Object.assign(error, { name: "CircuitBreakerOpenError", isCircuitBreakerError: true });
6
+ return error;
7
+ }
8
+
9
+ // Functional Type Guard
10
+ export function isCircuitBreakerError(error: unknown): error is Error {
11
+ return error instanceof Error && (error as any).isCircuitBreakerError === true;
12
+ }
13
+
14
+ export interface CircuitBreakerOptions {
15
+ name?: string;
16
+ failureThreshold?: number;
17
+ resetTimeout?: number;
18
+ successThreshold?: number;
19
+ }
20
+
21
+ export function createCircuitBreaker({
22
+ name = "Unknown Service",
23
+ failureThreshold = 3,
24
+ resetTimeout = 30000,
25
+ successThreshold = 1
26
+ }: CircuitBreakerOptions = {}) {
27
+ let state: "closed" | "open" | "half-open" = "closed";
28
+ let failureCount = 0;
29
+ let successCount = 0;
30
+ let lastFailureTime = 0;
31
+ let isHalfOpenTestRunning = false;
32
+
33
+ function trip() {
34
+ state = "open";
35
+ lastFailureTime = Date.now();
36
+ }
37
+
38
+ function reset() {
39
+ state = "closed";
40
+ failureCount = 0;
41
+ successCount = 0;
42
+ }
43
+
44
+ return {
45
+ async exec<T>(fn: () => Promise<T>): Promise<T> {
46
+ if (state === "open") {
47
+ if (Date.now() - lastFailureTime >= resetTimeout) {
48
+ state = "half-open";
49
+ successCount = 0;
50
+ isHalfOpenTestRunning = false;
51
+ } else {
52
+ throw createCircuitBreakerError(name);
53
+ }
54
+ }
55
+
56
+ if (state === "half-open") {
57
+ if (isHalfOpenTestRunning) {
58
+ throw createCircuitBreakerError(name);
59
+ }
60
+ isHalfOpenTestRunning = true;
61
+ }
62
+
63
+ try {
64
+ const result = await fn();
65
+ if (state === "half-open") {
66
+ successCount++;
67
+ if (successCount >= successThreshold) reset();
68
+ }
69
+ failureCount = 0;
70
+ return result;
71
+ } catch (error) {
72
+ failureCount++;
73
+ if (failureCount >= failureThreshold || state === "half-open") {
74
+ trip();
75
+ }
76
+ throw error;
77
+ } finally {
78
+ if (state === "half-open") isHalfOpenTestRunning = false;
79
+ }
80
+ },
81
+
82
+ getState() {
83
+ return state;
84
+ }
85
+ };
86
+ }
87
+
88
+ export type CircuitBreaker = ReturnType<typeof createCircuitBreaker>;
@@ -1,6 +1,6 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { databaseConfig } from "@/config/index.js";
3
+ import { databaseConfig, detectDialectFrom } from "@/config/index.js";
4
4
  import { loadAppSchema } from "@/framework/database/app-schema.js";
5
5
 
6
6
  export type Dialect = "sqlite" | "mysql" | "postgresql";
@@ -20,10 +20,7 @@ async function optionalImport<T = any>(name: string): Promise<T> {
20
20
  * How: Checks DATABASE_URL prefix and maps to sqlite/mysql/postgresql.
21
21
  */
22
22
  export function detectDialect(): Dialect {
23
- const url = databaseConfig.url.toLowerCase();
24
- if (url.startsWith("mysql")) return "mysql";
25
- if (url.startsWith("postgres")) return "postgresql";
26
- return "sqlite";
23
+ return detectDialectFrom(databaseConfig.url);
27
24
  }
28
25
 
29
26
  /**
@@ -36,9 +33,9 @@ export async function initDatabase() {
36
33
  if (databaseInstance) return databaseInstance;
37
34
 
38
35
  dialect = detectDialect();
39
-
40
36
  const schema = await loadAppSchema();
41
37
 
38
+ // --- SQLite (libsql) ---
42
39
  if (dialect === "sqlite") {
43
40
  let drizzleSqlite: any;
44
41
  let createClient: any;
@@ -51,13 +48,24 @@ export async function initDatabase() {
51
48
  throw new Error("Missing sqlite dependencies. Install with: bun add drizzle-orm @libsql/client");
52
49
  }
53
50
 
54
- const file = path.resolve(process.cwd(), databaseConfig.url.replace(/^sqlite:/, ""));
55
- await fs.mkdir(path.dirname(file), { recursive: true });
56
- pool = createClient({ url: `file:${file.replace(/\\/g, "/")}` });
51
+ // databaseConfig.url is guaranteed to be "file:..."
52
+ const url = databaseConfig.url;
53
+
54
+ // Ensure the directory exists (skip for :memory: or absolute URLs)
55
+ if (!url.includes(":memory:")) {
56
+ const rawPath = url.replace(/^file:/i, "");
57
+ if (!rawPath.startsWith("//")) {
58
+ const file = path.resolve(process.cwd(), rawPath);
59
+ await fs.mkdir(path.dirname(file), { recursive: true });
60
+ }
61
+ }
62
+
63
+ pool = createClient({ url });
57
64
  databaseInstance = drizzleSqlite(pool, { schema });
58
65
  return databaseInstance;
59
66
  }
60
67
 
68
+ // --- MySQL ---
61
69
  if (dialect === "mysql") {
62
70
  let drizzleMysql: any;
63
71
  let mysql: any;
@@ -67,11 +75,19 @@ export async function initDatabase() {
67
75
  throw new Error("Missing mysql dependencies. Install with: bun add drizzle-orm mysql2");
68
76
  }
69
77
 
70
- pool = mysql.createPool({ uri: databaseConfig.url, connectionLimit: 10, enableKeepAlive: true });
78
+ pool = mysql.createPool({
79
+ uri: databaseConfig.url,
80
+ connectionLimit: databaseConfig.pool.max,
81
+ connectTimeout: databaseConfig.pool.connectTimeout,
82
+ enableKeepAlive: databaseConfig.pool.keepAlive,
83
+ ...(databaseConfig.ssl ? { ssl: {} } : {})
84
+ });
85
+
71
86
  databaseInstance = drizzleMysql(pool, { schema, mode: "default" });
72
87
  return databaseInstance;
73
88
  }
74
89
 
90
+ // --- PostgreSQL ---
75
91
  let drizzlePg: any;
76
92
  let postgres: any;
77
93
  try {
@@ -83,7 +99,14 @@ export async function initDatabase() {
83
99
  throw new Error("Missing postgres dependencies. Install with: bun add drizzle-orm postgres");
84
100
  }
85
101
 
86
- pool = postgres(databaseConfig.url);
102
+ pool = postgres(databaseConfig.url, {
103
+ max: databaseConfig.pool.max,
104
+ idle_timeout: Math.floor(databaseConfig.pool.idleTimeout / 1000),
105
+ connect_timeout: Math.floor(databaseConfig.pool.connectTimeout / 1000),
106
+ prepare: databaseConfig.prepare,
107
+ ...(databaseConfig.ssl ? { ssl: "require" as const } : {})
108
+ });
109
+
87
110
  databaseInstance = drizzlePg(pool, { schema });
88
111
  return databaseInstance;
89
112
  }
@@ -121,23 +144,20 @@ export async function closeDatabase() {
121
144
 
122
145
  const activeDialect = databaseDialect();
123
146
 
124
- if (activeDialect === "sqlite") {
125
- pool.close?.();
126
- pool = undefined;
127
- databaseInstance = undefined;
128
- return;
129
- }
130
-
131
- if (activeDialect === "mysql") {
132
- await pool.end();
147
+ try {
148
+ if (activeDialect === "sqlite") {
149
+ await pool.close?.();
150
+ } else if (activeDialect === "mysql") {
151
+ await pool.end();
152
+ } else {
153
+ await pool.end();
154
+ }
155
+ } catch (error) {
156
+ console.error("Error closing database pool:", error);
157
+ } finally {
133
158
  pool = undefined;
134
159
  databaseInstance = undefined;
135
- return;
136
160
  }
137
-
138
- await pool.end();
139
- pool = undefined;
140
- databaseInstance = undefined;
141
161
  }
142
162
 
143
163
  /**
@@ -146,7 +166,7 @@ export async function closeDatabase() {
146
166
  * Where: Locking, schema, and shutdown helpers.
147
167
  * How: Uses initialized dialect or falls back to detection.
148
168
  */
149
- export function databaseDialect() {
169
+ export function databaseDialect(): Dialect {
150
170
  return dialect || detectDialect();
151
171
  }
152
172
 
@@ -185,12 +205,17 @@ export const db = new Proxy(
185
205
  {
186
206
  get(_target, property) {
187
207
  const instance = database();
208
+
188
209
  if (property === "execute") {
189
210
  return async (query: unknown, params?: unknown) => {
190
- const raw = instance.execute ? await instance.execute(query, params) : await instance.all(query);
211
+ if (!instance.execute) {
212
+ throw new Error("The current driver does not support raw execute.");
213
+ }
214
+ const raw = await instance.execute(query, params);
191
215
  return normalizeExecuteResult(raw);
192
216
  };
193
217
  }
218
+
194
219
  const value = instance[property as keyof typeof instance];
195
220
  return typeof value === "function" ? value.bind(instance) : value;
196
221
  }
@@ -1,49 +1,61 @@
1
- import { queueJob } from "@/framework/queue/queue.js";
2
- import { type BroadcastOptions, broadcast } from "@/framework/realtime/broadcast.js";
3
-
4
- type CommandHandler = (payload: any) => Promise<any>;
5
-
6
- const commandHandlers = new Map<string, CommandHandler>();
7
-
8
- /**
9
- * Why: Registers in-memory command handler for synchronous dispatch.
10
- * When: Module startup files register command handlers.
11
- * Where: Job/command style module code.
12
- * How: Stores handler in a process-level map by command name.
13
- */
14
- export function command(name: string, handler: CommandHandler) {
15
- commandHandlers.set(name, handler);
16
- }
17
-
18
- /**
19
- * Why: Executes command immediately or queues it for async processing.
20
- * When: Application logic needs command pattern behavior.
21
- * Where: Controllers, jobs, and service layers.
22
- * How: Runs local handler unless async requested; otherwise enqueues.
23
- */
24
- export async function dispatchCommand(name: string, payload: any, options: { async?: boolean; queue?: string } = {}) {
25
- if (!options.async) {
26
- const handler = commandHandlers.get(name);
27
- if (handler) return await handler(payload);
28
- }
29
-
30
- return await queueJob(name, payload, { queue: options.queue || "default" });
31
- }
32
-
33
- /**
34
- * Why: Dispatches domain events with optional queueing and websocket fan-out.
35
- * When: Domain actions need side effects or realtime notifications.
36
- * Where: Controllers/jobs across modules.
37
- * How: Broadcasts via Socket.IO and optionally enqueues job.
38
- */
39
- export async function dispatchEvent(name: string, payload: any, options: { queue?: boolean | string; broadcast?: BroadcastOptions } = {}) {
40
- if (options.broadcast) {
41
- broadcast(name, payload, options.broadcast);
42
- }
43
-
44
- if (options.queue) {
45
- return await queueJob(name, payload, {
46
- queue: typeof options.queue === "string" ? options.queue : "default"
47
- });
48
- }
49
- }
1
+ import { queueJob } from "@/framework/queue/queue.js";
2
+ import { type BroadcastOptions, broadcast } from "@/framework/realtime/broadcast.js";
3
+ import { logger } from "@/framework/support/logger.js";
4
+
5
+ type CommandHandler = (payload: any) => Promise<any>;
6
+
7
+ const commandHandlers = new Map<string, CommandHandler>();
8
+
9
+ /**
10
+ * Why: Registers in-memory command handler for synchronous dispatch.
11
+ * When: Module startup files register command handlers.
12
+ * Where: Job/command style module code.
13
+ * How: Stores handler in a process-level map by command name.
14
+ */
15
+ export function command(name: string, handler: CommandHandler) {
16
+ commandHandlers.set(name, handler);
17
+ }
18
+
19
+ /**
20
+ * Why: Executes command immediately or queues it for async processing.
21
+ * When: Application logic needs command pattern behavior.
22
+ * Where: Controllers, jobs, and service layers.
23
+ * How: Runs local handler unless async requested; otherwise enqueues.
24
+ */
25
+ export async function dispatchCommand(name: string, payload: any, options: { async?: boolean; queue?: string } = {}) {
26
+ if (!options.async) {
27
+ const handler = commandHandlers.get(name);
28
+ if (handler) return await handler(payload);
29
+ }
30
+
31
+ return await queueJob(name, payload, { queue: options.queue || "default" });
32
+ }
33
+
34
+ /**
35
+ * Why: Dispatches domain events with optional queueing and websocket fan-out.
36
+ * When: Domain actions need side effects or realtime notifications.
37
+ * Where: Controllers/jobs across modules.
38
+ * How: Broadcasts via Socket.IO and optionally enqueues job.
39
+ */
40
+ export async function dispatchEvent(name: string, payload: any, options: { queue?: boolean | string; broadcast?: BroadcastOptions } = {}) {
41
+ // 1. Handle Broadcast safely
42
+ if (options.broadcast) {
43
+ try {
44
+ // Await the broadcast so the circuit breaker and redis publish complete safely
45
+ await broadcast(name, payload, options.broadcast);
46
+ } catch (error) {
47
+ logger.error(`Failed to broadcast event: ${name}`, { error });
48
+ }
49
+ }
50
+
51
+ // 2. Handle Queue safely
52
+ if (options.queue) {
53
+ try {
54
+ return await queueJob(name, payload, {
55
+ queue: typeof options.queue === "string" ? options.queue : "default"
56
+ });
57
+ } catch (error) {
58
+ logger.error(`Failed to queue event: ${name}`, { error });
59
+ }
60
+ }
61
+ }