create-nexwire 4.2.5 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (399) hide show
  1. package/README.md +29 -12
  2. package/express/.env +1 -1
  3. package/express/package.json +1 -1
  4. package/express/src/config/database.ts +48 -29
  5. package/express/src/config/index.ts +83 -83
  6. package/express/src/config/openapi.ts +6 -24
  7. package/express/src/config/queue.ts +30 -30
  8. package/express/src/config/validate.ts +50 -40
  9. package/express/src/database/migrations/sqlite/0000_init.sql +47 -47
  10. package/express/src/database/migrations/sqlite/meta/0000_snapshot.json +1 -1
  11. package/express/src/database/migrations/sqlite/meta/_journal.json +1 -1
  12. package/express/src/framework/cache/cache.ts +40 -8
  13. package/express/src/framework/circuit-breaker/cb.ts +88 -60
  14. package/express/src/framework/database/connection.ts +52 -27
  15. package/express/src/framework/events/dispatcher.ts +61 -49
  16. package/express/src/framework/facade.ts +47 -3
  17. package/express/src/framework/http/app.ts +28 -22
  18. package/express/src/framework/http/logger.ts +37 -17
  19. package/express/src/framework/http/openapi.ts +9 -11
  20. package/express/src/framework/maker-cli/runtime/core.mjs +1 -2
  21. package/express/src/framework/modules/routes.ts +26 -21
  22. package/express/src/framework/notification/channels/broadcast.ts +15 -0
  23. package/express/src/framework/notification/channels/mail.ts +42 -0
  24. package/express/src/framework/notification/contracts.ts +29 -0
  25. package/express/src/framework/notification/index.ts +19 -94
  26. package/express/src/framework/notification/registry.ts +15 -0
  27. package/express/src/framework/providers/adapter.ts +27 -17
  28. package/express/src/framework/queue/queue.ts +43 -44
  29. package/express/src/framework/realtime/broadcast.ts +29 -5
  30. package/express/src/framework/realtime/socket.ts +149 -119
  31. package/express/src/framework/redis/client.ts +148 -151
  32. package/express/src/framework/runtime/server-adapter.ts +39 -34
  33. package/express/src/framework/scheduler/lock.ts +128 -116
  34. package/express/src/framework/server.ts +33 -49
  35. package/express/src/framework/session/session.ts +69 -14
  36. package/express/src/framework/storage/storage.ts +744 -785
  37. package/express/src/framework/support/mail.ts +15 -7
  38. package/express/src/middlewares/auth-middleware.ts +1 -2
  39. package/express/src/middlewares/role-middleware.ts +3 -13
  40. package/express/src/modules/auth/routes/index.ts +1 -2
  41. package/express/src/providers/notification.ts +4 -0
  42. package/express/src/resources/src/components/Switch.vue +60 -65
  43. package/express/src/resources/src/layouts/Layout/Header.vue +124 -105
  44. package/express/src/resources/src/pages/auth/forgetPassword.vue +23 -30
  45. package/express/src/resources/src/pages/auth/login.vue +25 -28
  46. package/express/src/resources/src/pages/auth/register.vue +35 -39
  47. package/express/src/resources/src/pages/auth/resetPassword.vue +29 -37
  48. package/express/src/resources/src/pages/auth/verifyEmail.vue +15 -19
  49. package/express/src/resources/src/plugins/gum.ts +519 -203
  50. package/express/src/resources/src/plugins/pulse.ts +157 -147
  51. package/express/src/resources/src/stores/auth.ts +9 -6
  52. package/express/src/resources/vite.config.ts +54 -43
  53. package/express/src/storage/database/nexwire.sqlite +0 -0
  54. package/express/src/storage/logs/app.log +0 -0
  55. package/express/src/storage/logs/fatal.log +0 -0
  56. package/express/src/types/global.d.ts +32 -26
  57. package/fastify/.dockerignore +14 -0
  58. package/fastify/.env +44 -0
  59. package/fastify/.env.example +42 -0
  60. package/fastify/.vscode/extensions.json +6 -0
  61. package/fastify/.vscode/settings.json +37 -0
  62. package/fastify/LICENSE +21 -0
  63. package/fastify/README.md +232 -0
  64. package/fastify/biome.json +99 -0
  65. package/fastify/drizzle.config.ts +25 -0
  66. package/fastify/gitignore-stub +31 -0
  67. package/fastify/package.json +130 -0
  68. package/fastify/public/.gitkeep +0 -0
  69. package/fastify/src/config/app.ts +41 -0
  70. package/fastify/src/config/auth.ts +12 -0
  71. package/fastify/src/config/cache.ts +16 -0
  72. package/fastify/src/config/cookie.ts +15 -0
  73. package/fastify/src/config/cors.ts +12 -0
  74. package/fastify/src/config/database.ts +48 -0
  75. package/fastify/src/config/index.ts +83 -0
  76. package/fastify/src/config/jwt.ts +19 -0
  77. package/fastify/src/config/logging.ts +13 -0
  78. package/fastify/src/config/mail.ts +24 -0
  79. package/fastify/src/config/openapi.ts +36 -0
  80. package/fastify/src/config/queue.ts +30 -0
  81. package/fastify/src/config/rateLimit.ts +17 -0
  82. package/fastify/src/config/realtime.ts +15 -0
  83. package/fastify/src/config/redis.ts +18 -0
  84. package/fastify/src/config/security.ts +44 -0
  85. package/fastify/src/config/session.ts +17 -0
  86. package/fastify/src/config/storage.ts +22 -0
  87. package/fastify/src/config/validate.ts +50 -0
  88. package/fastify/src/database/migrations/sqlite/0000_init.sql +48 -0
  89. package/fastify/src/database/migrations/sqlite/meta/0000_snapshot.json +324 -0
  90. package/fastify/src/database/migrations/sqlite/meta/_journal.json +13 -0
  91. package/fastify/src/database/schema.ts +2 -0
  92. package/fastify/src/env.ts +76 -0
  93. package/fastify/src/framework/cache/cache.ts +114 -0
  94. package/fastify/src/framework/circuit-breaker/cb.ts +88 -0
  95. package/fastify/src/framework/database/app-schema.ts +37 -0
  96. package/fastify/src/framework/database/connection.ts +223 -0
  97. package/fastify/src/framework/database/migrate-hooks.ts +87 -0
  98. package/fastify/src/framework/database/paginate.ts +226 -0
  99. package/fastify/src/framework/database/schema.ts +20 -0
  100. package/fastify/src/framework/database/seed.ts +152 -0
  101. package/fastify/src/framework/events/dispatcher.ts +61 -0
  102. package/fastify/src/framework/facade.ts +96 -0
  103. package/fastify/src/framework/http/app.ts +176 -0
  104. package/fastify/src/framework/http/cors.ts +13 -0
  105. package/fastify/src/framework/http/fastify.d.ts +13 -0
  106. package/fastify/src/framework/http/logger.ts +110 -0
  107. package/fastify/src/framework/http/metrics.ts +22 -0
  108. package/fastify/src/framework/http/openapi.ts +48 -0
  109. package/fastify/src/framework/http/ratelimiter.ts +47 -0
  110. package/fastify/src/framework/http/security.ts +25 -0
  111. package/fastify/src/framework/http/static.ts +83 -0
  112. package/fastify/src/framework/http/validation.ts +49 -0
  113. package/fastify/src/framework/kernel.ts +43 -0
  114. package/fastify/src/framework/maker-cli/db/core.mjs +291 -0
  115. package/fastify/src/framework/maker-cli/db/index.mjs +204 -0
  116. package/fastify/src/framework/maker-cli/deploy/core.mjs +1046 -0
  117. package/fastify/src/framework/maker-cli/deploy/index.mjs +91 -0
  118. package/fastify/src/framework/maker-cli/index.mjs +65 -0
  119. package/fastify/src/framework/maker-cli/middleware/core.mjs +41 -0
  120. package/fastify/src/framework/maker-cli/middleware/index.mjs +17 -0
  121. package/fastify/src/framework/maker-cli/module/core.mjs +1066 -0
  122. package/fastify/src/framework/maker-cli/module/index.mjs +211 -0
  123. package/fastify/src/framework/maker-cli/provider/core.mjs +49 -0
  124. package/fastify/src/framework/maker-cli/provider/index.mjs +12 -0
  125. package/fastify/src/framework/maker-cli/runtime/build-ui.mjs +16 -0
  126. package/fastify/src/framework/maker-cli/runtime/core.mjs +560 -0
  127. package/fastify/src/framework/maker-cli/runtime/index.mjs +120 -0
  128. package/fastify/src/framework/maker-cli/runtime/redis-commander-patch.cjs +20 -0
  129. package/fastify/src/framework/maker-cli/stubs/controller/openapi.ts.stub +74 -0
  130. package/fastify/src/framework/maker-cli/stubs/controller/plain.ts.stub +77 -0
  131. package/fastify/src/framework/maker-cli/stubs/controller/standalone.ts.stub +51 -0
  132. package/fastify/src/framework/maker-cli/stubs/deploy/Dockerfile.bun.stub +52 -0
  133. package/fastify/src/framework/maker-cli/stubs/deploy/Dockerfile.pnpm.stub +55 -0
  134. package/fastify/src/framework/maker-cli/stubs/deploy/Dockerfile.stub +51 -0
  135. package/fastify/src/framework/maker-cli/stubs/deploy/Dockerfile.yarn.stub +55 -0
  136. package/fastify/src/framework/maker-cli/stubs/deploy/README.stub +59 -0
  137. package/fastify/src/framework/maker-cli/stubs/deploy/compose/mysql.server.stub +45 -0
  138. package/fastify/src/framework/maker-cli/stubs/deploy/compose/postgres.server.stub +45 -0
  139. package/fastify/src/framework/maker-cli/stubs/deploy/compose/sqlite.stub +45 -0
  140. package/fastify/src/framework/maker-cli/stubs/deploy/env/mysql.server.stub +68 -0
  141. package/fastify/src/framework/maker-cli/stubs/deploy/env/postgres.server.stub +68 -0
  142. package/fastify/src/framework/maker-cli/stubs/deploy/env/sqlite.stub +67 -0
  143. package/fastify/src/framework/maker-cli/stubs/deploy/scripts/auto-migrate.sh.stub +41 -0
  144. package/fastify/src/framework/maker-cli/stubs/deploy/server/README.stub +78 -0
  145. package/fastify/src/framework/maker-cli/stubs/deploy/server/compose/noredis.stub +120 -0
  146. package/fastify/src/framework/maker-cli/stubs/deploy/server/compose/redis.dev.stub +133 -0
  147. package/fastify/src/framework/maker-cli/stubs/deploy/server/compose/redis.stub +131 -0
  148. package/fastify/src/framework/maker-cli/stubs/deploy/server/env/local.example.stub +11 -0
  149. package/fastify/src/framework/maker-cli/stubs/deploy/server/env/noredis.stub +25 -0
  150. package/fastify/src/framework/maker-cli/stubs/deploy/server/env/redis.stub +25 -0
  151. package/fastify/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/README.stub +16 -0
  152. package/fastify/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/app.example.com.stub +13 -0
  153. package/fastify/src/framework/maker-cli/stubs/deploy/server/pgadmin/servers.stub +14 -0
  154. package/fastify/src/framework/maker-cli/stubs/deploy/server/redis/redis.conf.stub +7 -0
  155. package/fastify/src/framework/maker-cli/stubs/deploy/supervisor/noredis.stub +54 -0
  156. package/fastify/src/framework/maker-cli/stubs/deploy/supervisor/redis.stub +70 -0
  157. package/fastify/src/framework/maker-cli/stubs/deploy/workflow/local.json.stub +25 -0
  158. package/fastify/src/framework/maker-cli/stubs/deploy/workflow/remote.json.stub +24 -0
  159. package/fastify/src/framework/maker-cli/stubs/facade/name.ts.stub +12 -0
  160. package/fastify/src/framework/maker-cli/stubs/helper/name.ts.stub +14 -0
  161. package/fastify/src/framework/maker-cli/stubs/job/name.ts.stub +25 -0
  162. package/fastify/src/framework/maker-cli/stubs/middleware/name.local.ts.stub +15 -0
  163. package/fastify/src/framework/maker-cli/stubs/middleware/name.ts.stub +15 -0
  164. package/fastify/src/framework/maker-cli/stubs/model/name.mysql.ts.stub +10 -0
  165. package/fastify/src/framework/maker-cli/stubs/model/name.postgresql.ts.stub +10 -0
  166. package/fastify/src/framework/maker-cli/stubs/model/name.sqlite.ts.stub +10 -0
  167. package/fastify/src/framework/maker-cli/stubs/notification/controller.ts.stub +79 -0
  168. package/fastify/src/framework/maker-cli/stubs/notification/job.ts.stub +11 -0
  169. package/fastify/src/framework/maker-cli/stubs/notification/model.ts.stub +29 -0
  170. package/fastify/src/framework/maker-cli/stubs/notification/provider.ts.stub +174 -0
  171. package/fastify/src/framework/maker-cli/stubs/notification/route.api.ts.stub +71 -0
  172. package/fastify/src/framework/maker-cli/stubs/notification/route.plain.ts.stub +15 -0
  173. package/fastify/src/framework/maker-cli/stubs/notification/schema.plain.ts.stub +26 -0
  174. package/fastify/src/framework/maker-cli/stubs/notification/schema.ts.stub +26 -0
  175. package/fastify/src/framework/maker-cli/stubs/provider/module-barrel.ts.stub +19 -0
  176. package/fastify/src/framework/maker-cli/stubs/provider/module.ts.stub +21 -0
  177. package/fastify/src/framework/maker-cli/stubs/provider/name.ts.stub +21 -0
  178. package/fastify/src/framework/maker-cli/stubs/route/api.ts.stub +101 -0
  179. package/fastify/src/framework/maker-cli/stubs/route/plain.ts.stub +23 -0
  180. package/fastify/src/framework/maker-cli/stubs/route/standalone.api.ts.stub +120 -0
  181. package/fastify/src/framework/maker-cli/stubs/route/standalone.plain.ts.stub +50 -0
  182. package/fastify/src/framework/maker-cli/stubs/schedule/name.ts.stub +36 -0
  183. package/fastify/src/framework/maker-cli/stubs/schema/name.plain.ts.stub +14 -0
  184. package/fastify/src/framework/maker-cli/stubs/schema/name.ts.stub +33 -0
  185. package/fastify/src/framework/maker-cli/stubs/seeder/name.ts.stub +18 -0
  186. package/fastify/src/framework/maker-cli/stubs/seeder/standalone.ts.stub +22 -0
  187. package/fastify/src/framework/maker-cli/stubs/service/name.plain.ts.stub +67 -0
  188. package/fastify/src/framework/maker-cli/stubs/service/name.ts.stub +65 -0
  189. package/fastify/src/framework/maker-cli/stubs/test/unit.ts.stub +22 -0
  190. package/fastify/src/framework/maker-cli/stubs/type/name.ts.stub +22 -0
  191. package/fastify/src/framework/maker-cli/utils/env-config.mjs +44 -0
  192. package/fastify/src/framework/maker-cli/utils/env-db.mjs +61 -0
  193. package/fastify/src/framework/maker-cli/utils/file-ops.mjs +30 -0
  194. package/fastify/src/framework/maker-cli/utils/flags.mjs +14 -0
  195. package/fastify/src/framework/maker-cli/utils/help.mjs +379 -0
  196. package/fastify/src/framework/maker-cli/utils/naming.mjs +119 -0
  197. package/fastify/src/framework/maker-cli/utils/process.mjs +52 -0
  198. package/fastify/src/framework/maker-cli/utils/project-commands.mjs +201 -0
  199. package/fastify/src/framework/modules/discover.ts +57 -0
  200. package/fastify/src/framework/modules/routes.ts +31 -0
  201. package/fastify/src/framework/notification/channels/broadcast.ts +15 -0
  202. package/fastify/src/framework/notification/channels/mail.ts +42 -0
  203. package/fastify/src/framework/notification/contracts.ts +29 -0
  204. package/fastify/src/framework/notification/index.ts +59 -0
  205. package/fastify/src/framework/notification/registry.ts +15 -0
  206. package/fastify/src/framework/providers/adapter.ts +149 -0
  207. package/fastify/src/framework/providers/contracts.ts +126 -0
  208. package/fastify/src/framework/providers/loader.ts +105 -0
  209. package/fastify/src/framework/providers/registry.ts +88 -0
  210. package/fastify/src/framework/queue/clear.ts +22 -0
  211. package/fastify/src/framework/queue/queue.ts +401 -0
  212. package/fastify/src/framework/queue/ui.ts +194 -0
  213. package/fastify/src/framework/queue/worker.ts +61 -0
  214. package/fastify/src/framework/realtime/broadcast.ts +70 -0
  215. package/fastify/src/framework/realtime/index.ts +2 -0
  216. package/fastify/src/framework/realtime/socket-cookie.ts +72 -0
  217. package/fastify/src/framework/realtime/socket.ts +149 -0
  218. package/fastify/src/framework/realtime/types.ts +6 -0
  219. package/fastify/src/framework/realtime/ui.ts +16 -0
  220. package/fastify/src/framework/redis/client.ts +148 -0
  221. package/fastify/src/framework/runtime/runtime.ts +23 -0
  222. package/fastify/src/framework/runtime/server-adapter.ts +33 -0
  223. package/fastify/src/framework/scheduler/lock.ts +128 -0
  224. package/fastify/src/framework/scheduler/run.ts +48 -0
  225. package/fastify/src/framework/scheduler/scheduler.ts +155 -0
  226. package/fastify/src/framework/server.ts +162 -0
  227. package/fastify/src/framework/session/session.ts +160 -0
  228. package/fastify/src/framework/storage/storage.ts +744 -0
  229. package/fastify/src/framework/support/cookie.ts +71 -0
  230. package/fastify/src/framework/support/jwt.ts +33 -0
  231. package/fastify/src/framework/support/lifecycle.ts +35 -0
  232. package/fastify/src/framework/support/logger.ts +148 -0
  233. package/fastify/src/framework/support/mail.ts +56 -0
  234. package/fastify/src/framework/support/password.ts +23 -0
  235. package/fastify/src/framework/support/status-codes.ts +75 -0
  236. package/fastify/src/framework/support/upload.ts +181 -0
  237. package/fastify/src/framework/support/url.ts +41 -0
  238. package/fastify/src/middlewares/auth-middleware.ts +134 -0
  239. package/fastify/src/middlewares/role-middleware.ts +19 -0
  240. package/fastify/src/modules/auth/__tests__/forgetpass.test.ts +200 -0
  241. package/fastify/src/modules/auth/__tests__/login.test.ts +171 -0
  242. package/fastify/src/modules/auth/__tests__/logout.test.ts +60 -0
  243. package/fastify/src/modules/auth/__tests__/logoutalldevices.test.ts +49 -0
  244. package/fastify/src/modules/auth/__tests__/me.test.ts +91 -0
  245. package/fastify/src/modules/auth/__tests__/refreshtoken.test.ts +305 -0
  246. package/fastify/src/modules/auth/__tests__/register.test.ts +291 -0
  247. package/fastify/src/modules/auth/__tests__/resetpass.test.ts +206 -0
  248. package/fastify/src/modules/auth/__tests__/verifyemail.test.ts +183 -0
  249. package/fastify/src/modules/auth/controllers/auth.ts +252 -0
  250. package/fastify/src/modules/auth/controllers/role.ts +35 -0
  251. package/fastify/src/modules/auth/database/models/role.ts +14 -0
  252. package/fastify/src/modules/auth/database/models/user.ts +46 -0
  253. package/fastify/src/modules/auth/database/seeders/role.ts +18 -0
  254. package/fastify/src/modules/auth/database/seeders/user.ts +35 -0
  255. package/fastify/src/modules/auth/facade.ts +12 -0
  256. package/fastify/src/modules/auth/helpers/auth.ts +115 -0
  257. package/fastify/src/modules/auth/jobs/forgetpass.ts +20 -0
  258. package/fastify/src/modules/auth/jobs/registeruser.ts +23 -0
  259. package/fastify/src/modules/auth/jobs/verifyemail.ts +18 -0
  260. package/fastify/src/modules/auth/routes/index.ts +185 -0
  261. package/fastify/src/modules/auth/routes/role.ts +56 -0
  262. package/fastify/src/modules/auth/schemas/auth.ts +116 -0
  263. package/fastify/src/modules/auth/services/forgetpassword.ts +66 -0
  264. package/fastify/src/modules/auth/services/login.ts +63 -0
  265. package/fastify/src/modules/auth/services/logout.ts +25 -0
  266. package/fastify/src/modules/auth/services/logoutalldevices.ts +19 -0
  267. package/fastify/src/modules/auth/services/me.ts +31 -0
  268. package/fastify/src/modules/auth/services/refreshtoken.ts +110 -0
  269. package/fastify/src/modules/auth/services/register.ts +141 -0
  270. package/fastify/src/modules/auth/services/resetpassword.ts +69 -0
  271. package/fastify/src/modules/auth/services/verifyemail.ts +77 -0
  272. package/fastify/src/modules/auth/types/auth.ts +31 -0
  273. package/fastify/src/providers/README.md +107 -0
  274. package/fastify/src/providers/notification.ts +4 -0
  275. package/fastify/src/resources/index.html +17 -0
  276. package/fastify/src/resources/src/App.vue +5 -0
  277. package/fastify/src/resources/src/assets/css/styles.css +14761 -0
  278. package/fastify/src/resources/src/assets/css/styles.css.map +1 -0
  279. package/fastify/src/resources/src/assets/fonts/public-sans/public-sans-latin-ext.woff2 +0 -0
  280. package/fastify/src/resources/src/assets/fonts/public-sans/public-sans-latin.woff2 +0 -0
  281. package/fastify/src/resources/src/assets/images/favicon/favicon.ico +0 -0
  282. package/fastify/src/resources/src/assets/images/logo.png +0 -0
  283. package/fastify/src/resources/src/assets/scss/custom.css +217 -0
  284. package/fastify/src/resources/src/assets/scss/custom.css.map +1 -0
  285. package/fastify/src/resources/src/assets/scss/custom.scss +1346 -0
  286. package/fastify/src/resources/src/components/Button.vue +32 -0
  287. package/fastify/src/resources/src/components/Checkbox.vue +32 -0
  288. package/fastify/src/resources/src/components/Datepicker.vue +106 -0
  289. package/fastify/src/resources/src/components/FeatureButton.vue +53 -0
  290. package/fastify/src/resources/src/components/FloatButton.vue +33 -0
  291. package/fastify/src/resources/src/components/Href.vue +32 -0
  292. package/fastify/src/resources/src/components/Input.vue +243 -0
  293. package/fastify/src/resources/src/components/InputGroup.vue +147 -0
  294. package/fastify/src/resources/src/components/InputPasswordToggle.vue +229 -0
  295. package/fastify/src/resources/src/components/Modal.vue +71 -0
  296. package/fastify/src/resources/src/components/Pagebar.vue +26 -0
  297. package/fastify/src/resources/src/components/Refresh.vue +19 -0
  298. package/fastify/src/resources/src/components/Select.vue +384 -0
  299. package/fastify/src/resources/src/components/Spinner.vue +42 -0
  300. package/fastify/src/resources/src/components/Switch.vue +60 -0
  301. package/fastify/src/resources/src/components/TextArea.vue +117 -0
  302. package/fastify/src/resources/src/components/Toast.vue +56 -0
  303. package/fastify/src/resources/src/components/datatable/DataTableSkeleton.vue +98 -0
  304. package/fastify/src/resources/src/components/datatable/Pagination.vue +147 -0
  305. package/fastify/src/resources/src/components/datatable/SelectOpption.vue +64 -0
  306. package/fastify/src/resources/src/components/datatable/index.vue +199 -0
  307. package/fastify/src/resources/src/composables/useAuth.ts +52 -0
  308. package/fastify/src/resources/src/helpers/assets.ts +51 -0
  309. package/fastify/src/resources/src/helpers/nformatter.ts +10 -0
  310. package/fastify/src/resources/src/helpers/utils.ts +75 -0
  311. package/fastify/src/resources/src/layouts/AuthLayout.vue +20 -0
  312. package/fastify/src/resources/src/layouts/Layout/Footer.vue +23 -0
  313. package/fastify/src/resources/src/layouts/Layout/Header.vue +124 -0
  314. package/fastify/src/resources/src/layouts/Layout/Sidebar.vue +137 -0
  315. package/fastify/src/resources/src/layouts/Layout/index.vue +87 -0
  316. package/fastify/src/resources/src/main.ts +28 -0
  317. package/fastify/src/resources/src/pages/auth/forgetPassword.vue +76 -0
  318. package/fastify/src/resources/src/pages/auth/login.vue +96 -0
  319. package/fastify/src/resources/src/pages/auth/register.vue +129 -0
  320. package/fastify/src/resources/src/pages/auth/resetPassword.vue +110 -0
  321. package/fastify/src/resources/src/pages/auth/verifyEmail.vue +64 -0
  322. package/fastify/src/resources/src/pages/dashboard/index.vue +66 -0
  323. package/fastify/src/resources/src/plugins/axios.ts +31 -0
  324. package/fastify/src/resources/src/plugins/browserDetect.ts +55 -0
  325. package/fastify/src/resources/src/plugins/dialog.ts +216 -0
  326. package/fastify/src/resources/src/plugins/gum.ts +683 -0
  327. package/fastify/src/resources/src/plugins/pulse.ts +157 -0
  328. package/fastify/src/resources/src/plugins/routeProgress.ts +87 -0
  329. package/fastify/src/resources/src/router/index.ts +85 -0
  330. package/fastify/src/resources/src/stores/admin-ui.ts +148 -0
  331. package/fastify/src/resources/src/stores/auth.ts +187 -0
  332. package/fastify/src/resources/tsconfig.json +19 -0
  333. package/fastify/src/resources/vite.config.ts +64 -0
  334. package/fastify/src/storage/app/private/.gitkeep +0 -0
  335. package/fastify/src/storage/app/public/.gitkeep +0 -0
  336. package/fastify/src/storage/app/tmp/generated/.gitkeep +0 -0
  337. package/fastify/src/storage/database/nexwire.sqlite +0 -0
  338. package/fastify/src/storage/logs/.gitkeep +0 -0
  339. package/fastify/src/storage/logs/app.log +0 -0
  340. package/fastify/src/storage/logs/fatal.log +0 -0
  341. package/fastify/src/storage/tmp/.gitkeep +0 -0
  342. package/fastify/src/storage/trash/modules/.gitkeep +0 -0
  343. package/fastify/src/types/global.d.ts +32 -0
  344. package/fastify/tsconfig.json +19 -0
  345. package/fastify/vitest.config.ts +38 -0
  346. package/hono/.env +1 -1
  347. package/hono/package.json +1 -1
  348. package/hono/src/config/database.ts +48 -29
  349. package/hono/src/config/index.ts +83 -83
  350. package/hono/src/config/openapi.ts +6 -24
  351. package/hono/src/config/queue.ts +30 -30
  352. package/hono/src/config/validate.ts +50 -40
  353. package/hono/src/database/migrations/sqlite/0000_init.sql +47 -47
  354. package/hono/src/database/migrations/sqlite/meta/0000_snapshot.json +1 -1
  355. package/hono/src/database/migrations/sqlite/meta/_journal.json +1 -1
  356. package/hono/src/framework/cache/cache.ts +40 -8
  357. package/hono/src/framework/circuit-breaker/cb.ts +88 -60
  358. package/hono/src/framework/database/connection.ts +52 -27
  359. package/hono/src/framework/events/dispatcher.ts +61 -49
  360. package/hono/src/framework/facade.ts +39 -1
  361. package/hono/src/framework/http/logger.ts +86 -81
  362. package/hono/src/framework/http/openapi.ts +7 -9
  363. package/hono/src/framework/maker-cli/runtime/core.mjs +1 -2
  364. package/hono/src/framework/notification/channels/broadcast.ts +15 -0
  365. package/hono/src/framework/notification/channels/mail.ts +42 -0
  366. package/hono/src/framework/notification/contracts.ts +29 -0
  367. package/hono/src/framework/notification/index.ts +19 -94
  368. package/hono/src/framework/notification/registry.ts +15 -0
  369. package/hono/src/framework/providers/adapter.ts +27 -17
  370. package/hono/src/framework/queue/queue.ts +43 -44
  371. package/hono/src/framework/realtime/broadcast.ts +29 -5
  372. package/hono/src/framework/realtime/socket.ts +217 -196
  373. package/hono/src/framework/redis/client.ts +148 -151
  374. package/hono/src/framework/scheduler/lock.ts +128 -116
  375. package/hono/src/framework/server.ts +27 -29
  376. package/hono/src/framework/session/session.ts +62 -14
  377. package/hono/src/framework/storage/storage.ts +744 -785
  378. package/hono/src/framework/support/mail.ts +56 -48
  379. package/hono/src/middlewares/auth-middleware.ts +1 -2
  380. package/hono/src/middlewares/role-middleware.ts +3 -13
  381. package/hono/src/modules/auth/routes/index.ts +1 -2
  382. package/hono/src/providers/notification.ts +4 -0
  383. package/hono/src/resources/src/components/Switch.vue +60 -65
  384. package/hono/src/resources/src/layouts/Layout/Header.vue +124 -105
  385. package/hono/src/resources/src/pages/auth/forgetPassword.vue +23 -29
  386. package/hono/src/resources/src/pages/auth/login.vue +26 -29
  387. package/hono/src/resources/src/pages/auth/register.vue +36 -40
  388. package/hono/src/resources/src/pages/auth/resetPassword.vue +29 -37
  389. package/hono/src/resources/src/pages/auth/verifyEmail.vue +15 -19
  390. package/hono/src/resources/src/plugins/gum.ts +519 -203
  391. package/hono/src/resources/src/plugins/pulse.ts +157 -147
  392. package/hono/src/resources/src/stores/auth.ts +9 -6
  393. package/hono/src/resources/vite.config.ts +54 -43
  394. package/hono/src/storage/database/nexwire.sqlite +0 -0
  395. package/hono/src/storage/logs/app.log +0 -0
  396. package/hono/src/storage/logs/fatal.log +0 -0
  397. package/hono/src/types/global.d.ts +32 -26
  398. package/package.json +4 -3
  399. package/src/index.js +143 -15
@@ -0,0 +1,201 @@
1
+ import fs from "node:fs";
2
+ import fsPromises from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { writeFileAlways, writeFileIfMissing } from "./file-ops.mjs";
6
+ import { PROJECT_COMMAND_FLAG } from "./help.mjs";
7
+
8
+ /**
9
+ * Where a project keeps its own maker commands.
10
+ *
11
+ * Deliberately outside `src/`. Anything under `src/framework/` is copied into
12
+ * the published package by `scripts/sync-template.mjs`, so a developer edit
13
+ * there would be overwritten on the next framework update - and `src/modules/`
14
+ * is swept by the route, job and seeder globs. The project root is the one
15
+ * place nothing else owns.
16
+ *
17
+ * Two names are read: commands.mjs (plain JavaScript, loaded by plain node)
18
+ * and commands.ts (TypeScript, loaded through tsx). The .mjs is the incumbent
19
+ * and wins if a project keeps both.
20
+ */
21
+ export const PROJECT_COMMANDS_PATH = "maker/commands.mjs";
22
+ export const PROJECT_COMMANDS_TS_PATH = "maker/commands.ts";
23
+
24
+ /** Process-global so a re-evaluated module cannot register tsx twice. */
25
+ const TSX_REGISTERED = "__nexwireMakerTsxRegistered";
26
+
27
+ const PROJECT_COMMANDS_TEMPLATE = `/**
28
+ * Your project's maker commands.
29
+ *
30
+ * This file is yours. Nothing in nexwire writes to it, and no framework update
31
+ * will touch it. Whatever you export here is registered on the maker CLI
32
+ * alongside the built-in commands:
33
+ *
34
+ * maker example:hello run your command
35
+ * maker --help every command, yours included
36
+ *
37
+ * \`program\` is the same commander object the built-in commands are built with,
38
+ * so \`.command()\`, \`.description()\`, \`.option()\` and \`.action()\` behave exactly
39
+ * as they do in nexwire's own commands.
40
+ *
41
+ * Three things worth knowing:
42
+ *
43
+ * - A name that collides with a framework command is ignored, and you are told
44
+ * which one. Rename yours; the built-in stays.
45
+ * - An error in this file is reported, never swallowed. If your commands stop
46
+ * appearing, the fault is here rather than in your command code.
47
+ * - This file runs as plain JavaScript under plain Node, so it cannot import
48
+ * your TypeScript source or use your tsconfig path alias. If a command
49
+ * needs either, name this file maker/commands.ts instead and delete this
50
+ * one - nexwire loads that file through tsx, with your tsconfig applied.
51
+ * For editor type support, create maker/tsconfig.json as shown in the docs.
52
+ *
53
+ * Replace or delete the example below once you have a command of your own.
54
+ */
55
+
56
+ export default function register(program) {
57
+ program
58
+ .command("example:hello <name>")
59
+ .description("Example command - replace or delete this")
60
+ .option("--loud", "Shout the greeting")
61
+ .action((name, options) => {
62
+ const greeting = \`Hello, \${name}!\`;
63
+ console.log(options.loud ? greeting.toUpperCase() : greeting);
64
+ });
65
+ }
66
+ `;
67
+
68
+ /**
69
+ * Why: Plain node cannot import TypeScript, so maker/commands.ts needs tsx
70
+ * registered before it is imported. Registered at most once per process
71
+ * and never unregistered: two overlapping registrations corrupt the
72
+ * loader, and commands routinely import more TypeScript at action time,
73
+ * long after this function returns. The flag lives on globalThis because
74
+ * this module can be evaluated more than once in one process (vitest's
75
+ * per-file isolation) while the loader hooks are process-wide.
76
+ * When: Only when the project's file is TypeScript - maker/commands.mjs never
77
+ * pays for tsx being installed.
78
+ * Where: utils/project-commands.mjs.
79
+ */
80
+ async function registerTsLoader(rel) {
81
+ if (globalThis[TSX_REGISTERED]) return;
82
+
83
+ try {
84
+ const { register } = await import("tsx/esm/api");
85
+ register();
86
+ } catch (error) {
87
+ throw new Error(
88
+ `${rel} needs tsx to load TypeScript, but it could not be registered: ${error?.message || error}. tsx ships as a devDependency of every nexwire project - run npm install, or rename the file to ${PROJECT_COMMANDS_PATH}.`,
89
+ { cause: error }
90
+ );
91
+ }
92
+
93
+ globalThis[TSX_REGISTERED] = true;
94
+ }
95
+
96
+ /**
97
+ * Why: Registers the commands a project defined for itself.
98
+ * When: Every maker invocation, right after the framework's own registrars.
99
+ * Where: Maker CLI entry flow, from utils/project-commands.mjs.
100
+ * How: Imports maker/commands.mjs - or maker/commands.ts, loaded through tsx,
101
+ * which resolves the project's tsconfig path aliases - resolved from
102
+ * process.cwd(), not from import.meta.dirname, which points inside
103
+ * node_modules and would find the framework's own directory instead of the
104
+ * project. If a project keeps both files the .mjs wins and the .ts file is
105
+ * skipped with a warning naming it, so neither file is ever silently dead:
106
+ * a project that already runs must not be re-registered by a file that
107
+ * appeared later, and a file that is skipped must say so. Absent is silent
108
+ * and free; broken is loud, because a developer's commands silently not
109
+ * existing is a far worse experience than an error message. A name that
110
+ * collides with a framework command is refused by commander itself, which
111
+ * is the right outcome: the built-in wins and the project cannot shadow a
112
+ * command it did not write. That refusal is re-thrown here with the file
113
+ * name attached, because commander's own message does not say which file
114
+ * asked for the name.
115
+ */
116
+ export async function registerProjectCommands(program, rawArgs, cwd = process.cwd()) {
117
+ const mjsFile = path.resolve(cwd, PROJECT_COMMANDS_PATH);
118
+ const tsFile = path.resolve(cwd, PROJECT_COMMANDS_TS_PATH);
119
+ const hasMjs = fs.existsSync(mjsFile);
120
+ const hasTs = fs.existsSync(tsFile);
121
+
122
+ if (!hasMjs && !hasTs) {
123
+ return { loaded: false, file: mjsFile, added: [] };
124
+ }
125
+
126
+ const isTs = !hasMjs && hasTs;
127
+ const file = isTs ? tsFile : mjsFile;
128
+ const rel = isTs ? PROJECT_COMMANDS_TS_PATH : PROJECT_COMMANDS_PATH;
129
+
130
+ if (hasMjs && hasTs) {
131
+ console.warn(
132
+ `${PROJECT_COMMANDS_TS_PATH} is ignored because ${PROJECT_COMMANDS_PATH} exists. Keep one - delete the file you are not using.`
133
+ );
134
+ }
135
+
136
+ // Not wrapped in a bare try/catch on purpose. A file that exists but fails to
137
+ // load has to say so, or the developer goes looking for a bug in their own
138
+ // command that is actually in this loader. The catches below only attach the
139
+ // file name, because an error from inside the project file otherwise reads as
140
+ // if it came from the framework.
141
+ if (isTs) {
142
+ await registerTsLoader(rel);
143
+ }
144
+
145
+ let module;
146
+ try {
147
+ module = await import(pathToFileURL(file).href);
148
+ } catch (error) {
149
+ throw new Error(`Could not load ${rel}: ${error?.message || error}`, { cause: error });
150
+ }
151
+
152
+ const register = module.default ?? module.register;
153
+
154
+ if (typeof register !== "function") {
155
+ throw new TypeError(
156
+ `${rel} must export a default function (program, args) => void. Found: ${typeof register}.`
157
+ );
158
+ }
159
+
160
+ const before = new Set(program.commands);
161
+
162
+ try {
163
+ await register(program, rawArgs);
164
+ } catch (error) {
165
+ throw new Error(`Could not register commands from ${rel}: ${error?.message || error}`, {
166
+ cause: error
167
+ });
168
+ }
169
+
170
+ const added = [];
171
+
172
+ for (const command of program.commands) {
173
+ if (before.has(command)) continue;
174
+ // Tagged so `maker --help` files these under "Your commands" beside
175
+ // `maker:init`, rather than in the section for unclassified commands.
176
+ command[PROJECT_COMMAND_FLAG] = true;
177
+ added.push(command.name());
178
+ }
179
+
180
+ return { loaded: true, file, added };
181
+ }
182
+
183
+ /**
184
+ * Why: Creates maker/commands.mjs so a project can add its own commands.
185
+ * When: A developer runs `maker maker:init`.
186
+ * Where: utils/project-commands.mjs.
187
+ * How: Writes the template with the same no-clobber default as every other
188
+ * generator, so an existing file is left alone unless --force is given.
189
+ */
190
+ export async function initProjectCommands(cwd = process.cwd(), { force = false } = {}) {
191
+ const file = path.resolve(cwd, PROJECT_COMMANDS_PATH);
192
+
193
+ if (force) {
194
+ await writeFileAlways(file, PROJECT_COMMANDS_TEMPLATE);
195
+ return { file, created: false, overwritten: true };
196
+ }
197
+
198
+ await fsPromises.mkdir(path.dirname(file), { recursive: true });
199
+ const created = await writeFileIfMissing(file, PROJECT_COMMANDS_TEMPLATE);
200
+ return { file, created, overwritten: false };
201
+ }
@@ -0,0 +1,57 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { glob } from "glob";
5
+
6
+ function resolveModulesPath() {
7
+ const cwd = process.cwd();
8
+ const srcModules = path.resolve(cwd, "src/modules");
9
+ const distModules = path.resolve(cwd, "dist/src/modules");
10
+ const entry = String(process.argv[1] || "");
11
+ const runningDist = /[\\/]dist[\\/]/.test(entry);
12
+
13
+ if (runningDist && fs.existsSync(distModules)) return distModules;
14
+ return srcModules;
15
+ }
16
+
17
+ export const modulesPath = resolveModulesPath();
18
+
19
+ /**
20
+ * Why: Finds module files by glob from active src/dist modules path.
21
+ * When: Framework needs module routes/jobs/seeders/schedules discovery.
22
+ * Where: Route registrar, queue boot, scheduler boot, seeding.
23
+ * How: Runs glob with absolute paths and stable sorting.
24
+ */
25
+ export async function discoverModuleFiles(pattern: string) {
26
+ const files = await glob(pattern, {
27
+ cwd: modulesPath,
28
+ absolute: true,
29
+ nodir: true,
30
+ windowsPathsNoEscape: true
31
+ });
32
+
33
+ return files.sort();
34
+ }
35
+
36
+ /**
37
+ * Why: Derives the module name from an absolute discovered file path.
38
+ * When: Mounting route prefixes and grouping module assets.
39
+ * Where: Route registration logic.
40
+ * How: Strips the artifact folder (e.g. `routes/`), keeping any panel segment so
41
+ * `admin/post/routes/index.ts` resolves to `admin/post` rather than `admin`.
42
+ * Returns POSIX separators because the result is used as a URL prefix.
43
+ */
44
+ export function moduleNameFromPath(filePath: string) {
45
+ const relative = path.relative(modulesPath, filePath);
46
+ return path.dirname(path.dirname(relative)).split(path.sep).join("/");
47
+ }
48
+
49
+ /**
50
+ * Why: Dynamically imports a discovered module file.
51
+ * When: Bootstrapping pluggable module artifacts.
52
+ * Where: Discovery consumers across framework.
53
+ * How: Converts file path to file URL and imports it.
54
+ */
55
+ export async function importFile(filePath: string) {
56
+ return await import(pathToFileURL(filePath).href);
57
+ }
@@ -0,0 +1,31 @@
1
+ import type { FastifyInstance } from "fastify";
2
+ import { discoverModuleFiles, importFile, moduleNameFromPath } from "@/framework/modules/discover.js";
3
+
4
+ /**
5
+ * Why: Discovers and mounts every module route plugin.
6
+ * When: Kernel boot, after the HTTP app exists.
7
+ * Where: Framework startup.
8
+ * How: Each `modules/<name>/routes/*.ts` default export is a Fastify plugin,
9
+ * registered under `/api/<module-name>`.
10
+ */
11
+ export async function registerModuleRoutes(app: FastifyInstance) {
12
+ const files = await discoverModuleFiles("**/routes/*.{ts,js}");
13
+
14
+ for (const file of files) {
15
+ const route = await importFile(file);
16
+
17
+ if (!route.default) {
18
+ throw new Error(`Route file ${file} has no default export`);
19
+ }
20
+
21
+ // Optional Guard: Ensure it's a Fastify plugin function
22
+ if (typeof route.default !== "function") {
23
+ throw new Error(`Route file ${file} must export a Fastify plugin as default`);
24
+ }
25
+
26
+ const prefix = `/api/${moduleNameFromPath(file)}`;
27
+ await app.register(route.default, { prefix });
28
+ }
29
+
30
+ return files.length;
31
+ }
@@ -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
+ }
@@ -0,0 +1,59 @@
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";
5
+
6
+ let missingProviderWarned = false;
7
+
8
+ /** Turn the public target argument into the polymorphic owner pair. */
9
+ function normalizeTarget(target: NotificationTarget): NormalizedTarget {
10
+ if (target !== null && typeof target === "object") {
11
+ return {
12
+ type: String(target.type || "user").trim() || "user",
13
+ id: target.id
14
+ };
15
+ }
16
+ return { type: "user", id: target as number | string };
17
+ }
18
+
19
+ /**
20
+ * Why: Persists a notification to the database and triggers all active channels.
21
+ * When: A feature wants to record something for a user.
22
+ * Where: Application code, through the framework facade.
23
+ * How: The provider owns database storage. The channels handle delivery (mail, sms, ws).
24
+ */
25
+ export async function notify(target: NotificationTarget, options: NotificationOptions): Promise<NotificationRecord | null> {
26
+ const provider = await resolveNotificationProvider();
27
+ if (!provider) {
28
+ if (!missingProviderWarned) {
29
+ missingProviderWarned = true;
30
+ console.warn(
31
+ '[notification] skipped: no notification provider is registered. Run "bun maker module:make-notification notification" then "bun maker module:migrate notification", or register a provider in src/providers/.'
32
+ );
33
+ }
34
+ return null;
35
+ }
36
+
37
+ const normalizedTarget = normalizeTarget(target);
38
+
39
+ // 1. Save to Database via the Provider
40
+ const normalized = await provider.create(normalizedTarget, {
41
+ type: options.type,
42
+ title: options.title,
43
+ body: options.body ?? null,
44
+ link: options.link ?? null,
45
+ data: options.data ?? null
46
+ });
47
+
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
+ );
57
+
58
+ return normalized;
59
+ }
@@ -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
+ }
@@ -0,0 +1,149 @@
1
+ import { eq } from "drizzle-orm";
2
+ import { db } from "@/framework/database/connection.js";
3
+ import type { AuthProvider, NotificationProvider } from "./contracts.js";
4
+ import { loadProviders } from "./loader.js";
5
+ import { getAuthProvider, getNotificationProvider } from "./registry.js";
6
+
7
+ let defaultProvider: AuthProvider | null = null;
8
+ let defaultLoadAttempted = false;
9
+
10
+ /**
11
+ * Why: Builds the built-in auth provider from the default auth module.
12
+ * When: No custom provider was registered by the application.
13
+ * Where: Auth provider adapter.
14
+ * How: Lazily imports the default user/refresh-token models. When the default
15
+ * auth module was deleted or replaced, no provider is produced.
16
+ */
17
+ async function loadDefaultProvider(): Promise<AuthProvider | null> {
18
+ if (defaultProvider) return defaultProvider;
19
+ if (defaultLoadAttempted) return null;
20
+ defaultLoadAttempted = true;
21
+
22
+ try {
23
+ const userMod = await import("@/modules/auth/database/models/user.js").catch(() => null);
24
+ if (!userMod?.users || !userMod?.refreshTokens) return null;
25
+
26
+ const users = userMod.users;
27
+ const refreshTokens = userMod.refreshTokens;
28
+
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,
51
+ async findRefreshToken(jti: string) {
52
+ try {
53
+ const token = await (db.query.refreshTokens.findFirst as any)?.({
54
+ where: eq(refreshTokens.jti, jti)
55
+ });
56
+ if (token) return token;
57
+ } catch {}
58
+ try {
59
+ const rows = await db.select().from(refreshTokens).where(eq(refreshTokens.jti, jti));
60
+ return rows?.[0] ?? null;
61
+ } catch {
62
+ return null;
63
+ }
64
+ },
65
+ async deleteRefreshToken(tokenId: number | string) {
66
+ try {
67
+ await db.delete(refreshTokens).where(eq(refreshTokens.id, tokenId as any));
68
+ } catch {}
69
+ },
70
+ async revokeRefreshToken(tokenId: number | string) {
71
+ try {
72
+ await db.delete(refreshTokens).where(eq(refreshTokens.id, tokenId as any));
73
+ } catch {}
74
+ },
75
+ async getAuthContext(user: any, payload?: any) {
76
+ try {
77
+ if (user?.role && typeof user.role === "object") {
78
+ return {
79
+ ...(payload || {}),
80
+ id: user.id,
81
+ email: user.email,
82
+ roleId: user.role?.id ?? null,
83
+ role: user.role?.name ?? null,
84
+ ...user
85
+ };
86
+ }
87
+ } catch {}
88
+ return {
89
+ ...(payload || {}),
90
+ id: user.id,
91
+ email: user.email,
92
+ roleId: user.roleId ?? null,
93
+ role: user.role ?? null,
94
+ ...user
95
+ };
96
+ },
97
+ async getUserContact(userId: number | string) {
98
+ try {
99
+ // Use the standalone function instead of `this.getUserById`
100
+ const user = await getUserById(userId);
101
+ if (!user) return null;
102
+ return {
103
+ email: user.email ?? null,
104
+ name: user.name ?? user.fullName ?? user.username ?? null,
105
+ phone: user.phone ?? user.phoneNumber ?? null
106
+ };
107
+ } catch {
108
+ return null;
109
+ }
110
+ }
111
+ };
112
+
113
+ defaultProvider = provider;
114
+ return defaultProvider;
115
+ } catch {
116
+ return null;
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Why: Resolves the auth provider the framework should use.
122
+ * When: The auth middleware or the notification mailer needs user data.
123
+ * Where: Auth provider adapter.
124
+ * How: Application providers are loaded first, so a file in `src/providers/`
125
+ * wins. Otherwise the built-in provider from the default auth module is
126
+ * used. When neither exists the framework degrades gracefully.
127
+ */
128
+ export async function resolveAuthProvider(): Promise<AuthProvider | null> {
129
+ await loadProviders();
130
+ const registered = getAuthProvider();
131
+ if (registered) return registered;
132
+ const def = await loadDefaultProvider();
133
+ if (def) return def;
134
+ return null;
135
+ }
136
+
137
+ /**
138
+ * Why: Resolves the notification storage provider.
139
+ * When: `notify()` persists a notification; the HTTP handlers read it back.
140
+ * Where: Notification runtime and the generated notification controller.
141
+ * How: Provider files are loaded first, so a project can replace the store from
142
+ * `src/providers/` or a module provider folder. The notification module is
143
+ * opt-in, so an absent provider is a normal state: callers warn once
144
+ * (runtime) or answer 503 (HTTP) instead of throwing.
145
+ */
146
+ export async function resolveNotificationProvider(): Promise<NotificationProvider | null> {
147
+ await loadProviders();
148
+ return getNotificationProvider();
149
+ }