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,129 @@
1
+ <template>
2
+ <div class="container position-absolute start-50 top-50 translate-middle">
3
+ <div class="auth col-12 col-sm-9 col-md-7 col-lg-5 col-xl-4 mx-auto py-5">
4
+ <div class="card card-body border-0">
5
+ <div class="d-block mb-2 text-center">
6
+ <img src="@/assets/images/logo.png" alt="nexwire" style="max-height: 60px;">
7
+ </div>
8
+ <h4 class="text-center">Create Account</h4>
9
+ <p v-if="message" class="text-center alert py-1 mt-2" :class="isError ? 'alert-danger text-danger' : 'alert-success text-success'">
10
+ {{ message }}
11
+ </p>
12
+ <form @submit.prevent="onSubmit">
13
+ <div class="mb-4">
14
+ <Input
15
+ id="name"
16
+ v-model="form.data.name"
17
+ type="text"
18
+ label="name"
19
+ placeholder="Enter your name..."
20
+ :err="form.errors.name"
21
+ focus
22
+ must
23
+ />
24
+ </div>
25
+ <div class="mb-4">
26
+ <Input
27
+ id="email"
28
+ v-model="form.data.email"
29
+ type="email"
30
+ label="email"
31
+ placeholder="Enter your email..."
32
+ :err="form.errors.email"
33
+ must
34
+ />
35
+ </div>
36
+ <div class="mb-4">
37
+ <InputPasswordToggle
38
+ id="password"
39
+ v-model="form.data.password"
40
+ label="password"
41
+ placeholder="Create a password..."
42
+ :err="form.errors.password"
43
+ must
44
+ />
45
+ </div>
46
+ <div class="mb-4">
47
+ <InputPasswordToggle
48
+ id="password_confirmation"
49
+ v-model="form.data.password_confirmation"
50
+ label="confirm password"
51
+ placeholder="Confirm your password..."
52
+ :err="form.errors.password_confirmation"
53
+ must
54
+ />
55
+ </div>
56
+ <Button type="submit" class="btn btn-primary w-100" label="Create Account" icon="bi bi-person-plus" :disabled="processing" />
57
+ </form>
58
+ <div class="text-center mt-3">
59
+ <span class="text-muted">Already have an account?</span>
60
+ <router-link to="/login" class="ms-1 text-decoration-none">Login</router-link>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ </template>
66
+
67
+ <script setup lang="ts">
68
+ import { useHead } from "@unhead/vue";
69
+ import { ref } from "vue";
70
+ import { useRouter } from "vue-router";
71
+ import Button from "@/components/Button.vue";
72
+ import Input from "@/components/Input.vue";
73
+ import InputPasswordToggle from "@/components/InputPasswordToggle.vue";
74
+ import { useGum } from "@/plugins/gum";
75
+ import { type RegisterPayload, useAuthStore } from "@/stores/auth";
76
+
77
+ useHead({ title: "Register" });
78
+
79
+ const router = useRouter();
80
+ const auth = useAuthStore();
81
+
82
+ const gum = useGum({
83
+ name: "",
84
+ email: "",
85
+ password: "",
86
+ password_confirmation: ""
87
+ });
88
+
89
+ const form = gum.form;
90
+ const processing = form.processing;
91
+ const message = ref("");
92
+ const isError = ref(false);
93
+
94
+ const onSubmit = async () => {
95
+ message.value = "";
96
+ isError.value = false;
97
+
98
+ if (form.data.password !== form.data.password_confirmation) {
99
+ isError.value = true;
100
+ message.value = "Password confirmation does not match";
101
+ return;
102
+ }
103
+
104
+ await form.postWith({
105
+ fetcher: (body) => auth.register(body as RegisterPayload),
106
+ transform: (data) => ({
107
+ name: String(data.name || "").trim(),
108
+ email: String(data.email || "").trim(),
109
+ password: data.password,
110
+ password_confirmation: data.password_confirmation
111
+ }),
112
+ onSuccess: async () => {
113
+ if (auth.isAuthenticated) {
114
+ await router.push("/");
115
+ return;
116
+ }
117
+
118
+ message.value = "Registration successful. Please verify your email.";
119
+ form.reset();
120
+ },
121
+ onError: (_errors, error) => {
122
+ isError.value = true;
123
+ message.value = error instanceof Error ? error.message : "Unable to register right now";
124
+ }
125
+ });
126
+ };
127
+ </script>
128
+
129
+ <style lang="scss" scoped></style>
@@ -0,0 +1,110 @@
1
+ <template>
2
+ <div class="container position-absolute start-50 top-50 translate-middle">
3
+ <div class="auth col-12 col-sm-9 col-md-7 col-lg-5 col-xl-4 mx-auto py-5">
4
+ <div class="card card-body border-0">
5
+ <div class="d-block mb-2 text-center">
6
+ <img src="@/assets/images/logo.png" alt="nexwire" style="max-height: 60px;">
7
+ </div>
8
+ <h4 class="text-center">Reset Password</h4>
9
+ <p v-if="message" class="text-center alert py-1 mt-2" :class="isError ? 'alert-danger text-danger' : 'alert-success text-success'">
10
+ {{ message }}
11
+ </p>
12
+ <form id="formAuthentication" :class="{ 'pe-none opacity-50': !isLinkValid }" @submit.prevent="onSubmit">
13
+ <div class="mb-4">
14
+ <input-password-toggle
15
+ id="password"
16
+ v-model="form.data.password"
17
+ label="new password"
18
+ placeholder="Enter your password..."
19
+ :err="form.errors.password"
20
+ must
21
+ />
22
+ </div>
23
+ <div class="mb-4">
24
+ <input-password-toggle
25
+ id="password_confirmation"
26
+ v-model="form.data.password_confirmation"
27
+ label="confirm password"
28
+ placeholder="Confirm new password..."
29
+ :err="form.errors.password_confirmation"
30
+ must
31
+ />
32
+ </div>
33
+ <Button type="submit" label="Reset Password" class="btn btn-primary w-100" icon="bi bi-key ms-2" :disabled="processing" />
34
+ </form>
35
+ <div class="text-center mt-2">
36
+ <router-link to="/login">
37
+ <i class="bx bx-chevron-left scaleX-n1-rtl me-1"></i>
38
+ <span>Back to login</span>
39
+ </router-link>
40
+ </div>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ </template>
45
+
46
+ <script setup lang="ts">
47
+ import { useHead } from "@unhead/vue";
48
+ import { ref } from "vue";
49
+ import { useRoute, useRouter } from "vue-router";
50
+ import Button from "@/components/Button.vue";
51
+ import InputPasswordToggle from "@/components/InputPasswordToggle.vue";
52
+ import { useGum } from "@/plugins/gum";
53
+ import { type ResetPayload, useAuthStore } from "@/stores/auth";
54
+
55
+ useHead({ title: "Reset Password" });
56
+
57
+ const route = useRoute();
58
+ const router = useRouter();
59
+ const auth = useAuthStore();
60
+
61
+ const email = String(route.query.email || "");
62
+ const token = String(route.query.token || "");
63
+
64
+ const gum = useGum({
65
+ email,
66
+ token,
67
+ password: "",
68
+ password_confirmation: ""
69
+ });
70
+
71
+ const form = gum.form;
72
+ const processing = form.processing;
73
+ const isLinkValid = !!(token && email);
74
+ const message = ref(isLinkValid ? "Set your new password" : "Invalid reset link. Please request a new one.");
75
+ const isError = ref(!isLinkValid);
76
+
77
+ const onSubmit = async () => {
78
+ if (!isLinkValid) return;
79
+
80
+ message.value = "";
81
+ isError.value = false;
82
+
83
+ if (form.data.password !== form.data.password_confirmation) {
84
+ isError.value = true;
85
+ message.value = "Password confirmation does not match";
86
+ return;
87
+ }
88
+
89
+ await form.postWith({
90
+ fetcher: (body) => auth.resetPassword(body as ResetPayload),
91
+ transform: (data) => ({
92
+ email: String(data.email || "").trim(),
93
+ token: String(data.token || "").trim(),
94
+ password: data.password,
95
+ password_confirmation: data.password_confirmation
96
+ }),
97
+ onSuccess: (res) => {
98
+ isError.value = false;
99
+ message.value = String(res.data || "Password reset successfully");
100
+ void router.push("/login");
101
+ },
102
+ onError: (_errors, error) => {
103
+ isError.value = true;
104
+ message.value = error instanceof Error ? error.message : "Failed to reset password";
105
+ }
106
+ });
107
+ };
108
+ </script>
109
+
110
+ <style lang="scss" scoped></style>
@@ -0,0 +1,64 @@
1
+ <template>
2
+ <div class="container position-absolute start-50 top-50 translate-middle">
3
+ <div class="auth col-12 col-sm-9 col-md-7 col-lg-5 col-xl-4 mx-auto py-5">
4
+ <div class="card card-body border-0">
5
+ <div class="d-block mb-2 text-center">
6
+ <img src="@/assets/images/logo.png" alt="nexwire" style="max-height: 60px;">
7
+ </div>
8
+ <h4 class="text-center">Email Verification</h4>
9
+ <p v-if="message" class="text-center alert py-2 mt-2" :class="isError ? 'alert-danger text-danger' : 'alert-success text-success'">
10
+ {{ message }}
11
+ </p>
12
+ <div class="text-center mt-2">
13
+ <router-link to="/login">
14
+ <span>Back to login</span>
15
+ </router-link>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import { useHead } from "@unhead/vue";
24
+ import { ref } from "vue";
25
+ import { useRoute } from "vue-router";
26
+ import { useGum } from "@/plugins/gum";
27
+ import { useAuthStore } from "@/stores/auth";
28
+
29
+ useHead({ title: "Verify Email" });
30
+
31
+ const route = useRoute();
32
+ const auth = useAuthStore();
33
+
34
+ const email = String(route.query.email || "").trim();
35
+ const token = String(route.query.token || "").trim();
36
+ const message = ref("Verifying your email...");
37
+ const isError = ref(false);
38
+
39
+ const gum = useGum();
40
+
41
+ const verify = async () => {
42
+ if (!email || !token) {
43
+ isError.value = true;
44
+ message.value = "Invalid verification link. Please request a new one.";
45
+ return;
46
+ }
47
+
48
+ await gum.postWith({
49
+ fetcher: () => auth.verifyEmail({ email, token }),
50
+ onSuccess: (res) => {
51
+ isError.value = false;
52
+ message.value = String(res.data || "Email verified successfully. You can now login.");
53
+ },
54
+ onError: (_errors, error) => {
55
+ isError.value = true;
56
+ message.value = error instanceof Error ? error.message : "Failed to verify email";
57
+ }
58
+ });
59
+ };
60
+
61
+ void verify();
62
+ </script>
63
+
64
+ <style lang="scss" scoped></style>
@@ -0,0 +1,66 @@
1
+ <template>
2
+ <Pagebar title="Dashboard" />
3
+
4
+ <div class="dashboard-placeholder">
5
+ <div class="row g-2 mb-2">
6
+ <div class="col-12 col-md-4">
7
+ <div class="placeholder-card"></div>
8
+ </div>
9
+ <div class="col-12 col-md-4">
10
+ <div class="placeholder-card"></div>
11
+ </div>
12
+ <div class="col-12 col-md-4">
13
+ <div class="placeholder-card"></div>
14
+ </div>
15
+ </div>
16
+
17
+ <div class="placeholder-panel"></div>
18
+ </div>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import { useHead } from "@unhead/vue";
23
+ import { onMounted, onUnmounted } from "vue";
24
+ import Pagebar from "@/components/Pagebar.vue";
25
+ import { useAuth } from "@/composables/useAuth";
26
+ import { pulse } from "@/plugins/pulse";
27
+
28
+ useHead({ title: "Dashboard" });
29
+
30
+ const { user } = useAuth();
31
+
32
+ onMounted(() => {
33
+ const ch = pulse.channel("user");
34
+ ch.listen("user.changed", () => alert("me"));
35
+ onUnmounted(() => ch.stopListening("user.changed"));
36
+ });
37
+
38
+ // const hardRefresh = () => window.location.reload();
39
+ </script>
40
+
41
+ <style scoped>
42
+ .placeholder-card,
43
+ .placeholder-panel {
44
+ border: 1px solid var(--app-border);
45
+ border-radius: 0.3rem;
46
+ background: var(--app-surface);
47
+ }
48
+
49
+ .placeholder-card {
50
+ min-height: 220px;
51
+ }
52
+
53
+ .placeholder-panel {
54
+ min-height: 520px;
55
+ }
56
+
57
+ @media (max-width: 768px) {
58
+ .placeholder-card {
59
+ min-height: 160px;
60
+ }
61
+
62
+ .placeholder-panel {
63
+ min-height: 360px;
64
+ }
65
+ }
66
+ </style>
@@ -0,0 +1,31 @@
1
+ import axios from "axios";
2
+
3
+ if (import.meta.env.VITE_API_URL) {
4
+ axios.defaults.baseURL = import.meta.env.VITE_API_URL;
5
+ }
6
+
7
+ axios.defaults.withCredentials = true;
8
+ axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
9
+ axios.defaults.headers.common.Accept = "application/json";
10
+
11
+ axios.interceptors.response.use(
12
+ (response) => response,
13
+ (error) => {
14
+ const status = error?.response?.status;
15
+ const isAuthPage =
16
+ window.location.pathname === "/register" ||
17
+ window.location.pathname === "/login" ||
18
+ window.location.pathname === "/forget-password" ||
19
+ window.location.pathname === "/reset-password" ||
20
+ window.location.pathname === "/verify-email";
21
+
22
+ if (status === 401 && !isAuthPage) {
23
+ const redirect = encodeURIComponent(window.location.pathname + window.location.search + window.location.hash);
24
+ window.location.href = `/login?redirect=${redirect}`;
25
+ }
26
+
27
+ return Promise.reject(error);
28
+ }
29
+ );
30
+
31
+ export default axios;
@@ -0,0 +1,55 @@
1
+ import type { App, ComputedRef } from "vue";
2
+ import { computed } from "vue";
3
+
4
+ export type BrowserDetectResult = {
5
+ userAgent: string;
6
+ isFirefox: ComputedRef<boolean>;
7
+ isChrome: ComputedRef<boolean>;
8
+ isSafari: ComputedRef<boolean>;
9
+ isEdge: ComputedRef<boolean>;
10
+ isOpera: ComputedRef<boolean>;
11
+ isBrave: ComputedRef<boolean>;
12
+ isAndroid: ComputedRef<boolean>;
13
+ isIOS: ComputedRef<boolean>;
14
+ isWindows: ComputedRef<boolean>;
15
+ isMac: ComputedRef<boolean>;
16
+ };
17
+
18
+ const userAgent = typeof navigator !== "undefined" ? navigator.userAgent.toLowerCase() : "";
19
+
20
+ const isFirefoxRaw = userAgent.includes("firefox");
21
+ const isEdgeRaw = userAgent.includes("edg");
22
+ const isOperaRaw = userAgent.includes("opr") || userAgent.includes("opera");
23
+ const isBraveRaw = userAgent.includes("brave");
24
+ const isChromeRaw = userAgent.includes("chrome") && !isEdgeRaw && !isOperaRaw && !isBraveRaw;
25
+ const isAndroidRaw = userAgent.includes("android");
26
+ const isSafariRaw = userAgent.includes("safari") && !isChromeRaw && !isAndroidRaw;
27
+ const isIOSRaw = /iphone|ipad|ipod/.test(userAgent);
28
+ const isWindowsRaw = userAgent.includes("windows");
29
+ const isMacRaw = userAgent.includes("macintosh");
30
+
31
+ export const browserDetect: BrowserDetectResult = {
32
+ userAgent,
33
+ isFirefox: computed(() => isFirefoxRaw),
34
+ isChrome: computed(() => isChromeRaw),
35
+ isSafari: computed(() => isSafariRaw),
36
+ isEdge: computed(() => isEdgeRaw),
37
+ isOpera: computed(() => isOperaRaw),
38
+ isBrave: computed(() => isBraveRaw),
39
+ isAndroid: computed(() => isAndroidRaw),
40
+ isIOS: computed(() => isIOSRaw),
41
+ isWindows: computed(() => isWindowsRaw),
42
+ isMac: computed(() => isMacRaw)
43
+ };
44
+
45
+ export const BrowserDetectPlugin = {
46
+ install(app: App) {
47
+ app.config.globalProperties.$browserDetect = browserDetect;
48
+ }
49
+ };
50
+
51
+ declare module "vue" {
52
+ interface ComponentCustomProperties {
53
+ $browserDetect: BrowserDetectResult;
54
+ }
55
+ }
@@ -0,0 +1,216 @@
1
+ import type { App } from "vue";
2
+
3
+ type PromptOptions = {
4
+ limit?: number;
5
+ placeholder?: string;
6
+ defaultValue?: string;
7
+ };
8
+
9
+ type DialogClient = {
10
+ alert: (text?: string) => void;
11
+ confirm: (text?: string, callback?: (ok: boolean) => void) => void;
12
+ prompt: (text?: string, options?: PromptOptions, callback?: (result: { ok: boolean; value: string }) => void) => void;
13
+ };
14
+
15
+ function hostNode() {
16
+ return document.querySelector("#modal-show") || document.body;
17
+ }
18
+
19
+ function siteLabel() {
20
+ return `${location.protocol}//${location.hostname}`;
21
+ }
22
+
23
+ function buildShell(content: string) {
24
+ const root = document.createElement("div");
25
+ root.className = "position-fixed w-100 h-100 top-0 start-0";
26
+ root.style.background = "var(--app-backdrop)";
27
+ root.style.color = "var(--app-text)";
28
+ root.style.zIndex = "100000";
29
+ root.innerHTML = content;
30
+ return root;
31
+ }
32
+
33
+ function closeShell(shell: HTMLElement) {
34
+ shell.remove();
35
+ }
36
+
37
+ function bindKeys(shell: HTMLElement, onOk: () => void, onCancel: () => void) {
38
+ shell.addEventListener(
39
+ "keydown",
40
+ (e) => {
41
+ if (!shell.isConnected) return;
42
+ const tag = (e.target as HTMLElement)?.tagName;
43
+ const isInput = tag === "TEXTAREA" || tag === "INPUT";
44
+
45
+ if (e.key === "Escape") {
46
+ e.preventDefault();
47
+ e.stopPropagation();
48
+ onCancel();
49
+ return;
50
+ }
51
+
52
+ if (e.key === "Enter" && !isInput) {
53
+ e.preventDefault();
54
+ e.stopPropagation();
55
+ onOk();
56
+ }
57
+ },
58
+ true
59
+ );
60
+ }
61
+
62
+ export const dialog: DialogClient = {
63
+ alert(text = "") {
64
+ const shell = buildShell(`
65
+ <div class='card position-absolute top-50 start-50 translate-middle border' style='width:300px'>
66
+ <div class='card-header d-flex justify-content-between align-items-center px-2 py-1 border-0'>
67
+ <span class='d-flex align-items-center'>
68
+ <i class="bi bi-exclamation-circle"></i> <span class='ms-2'>${siteLabel()}</span>
69
+ </span>
70
+ <button class='btn btn-sm p-0' type='button' data-dialog='close'>
71
+ <i class='bi bi-x fs-3'></i>
72
+ </button>
73
+ </div>
74
+ <div class='card-body overflow-x-hidden overflow-y-scroll p-2 text-center' style='max-height:200px'>
75
+ ${text}
76
+ </div>
77
+ <div class='card-footer d-flex justify-content-end align-items-center px-2 py-1 border-0'>
78
+ <button type='button' class='btn btn-primary btn-sm' data-dialog='ok'>OK</button>
79
+ </div>
80
+ </div>
81
+ `);
82
+
83
+ shell.addEventListener("click", (event) => {
84
+ event.stopPropagation();
85
+ const target = event.target as HTMLElement;
86
+ const action = target.closest("[data-dialog]")?.getAttribute("data-dialog");
87
+ if (action === "ok" || action === "close") closeShell(shell);
88
+ });
89
+
90
+ bindKeys(
91
+ shell,
92
+ () => closeShell(shell),
93
+ () => closeShell(shell)
94
+ );
95
+ hostNode().appendChild(shell);
96
+ (shell.querySelector("[data-dialog='ok']") as HTMLElement)?.focus();
97
+ },
98
+
99
+ confirm(text = "", callback?: (ok: boolean) => void) {
100
+ const shell = buildShell(`
101
+ <div class='card position-absolute top-50 start-50 translate-middle border' style='width:300px'>
102
+ <div class='card-header d-flex justify-content-between align-items-center px-2 py-1 border-0'>
103
+ <span class='d-flex align-items-center'>
104
+ <i class="bi bi-globe"></i> <span class='ms-2'>${siteLabel()}</span>
105
+ </span>
106
+ <button class='btn btn-sm p-0' type='button' data-dialog='cancel'>
107
+ <i class='bi bi-x fs-3'></i>
108
+ </button>
109
+ </div>
110
+ <div class='card-body overflow-x-hidden overflow-y-scroll p-2 text-center' style='max-height:200px'>
111
+ ${text}
112
+ </div>
113
+ <div class='card-footer d-flex justify-content-end align-items-center px-2 py-1 border-0'>
114
+ <button type='button' class='btn btn-primary btn-sm' data-dialog='ok'>OK</button>
115
+ <button type='button' class='btn btn-secondary btn-sm ms-1' data-dialog='cancel'>Cancel</button>
116
+ </div>
117
+ </div>
118
+ `);
119
+
120
+ shell.addEventListener("click", (event) => {
121
+ event.stopPropagation();
122
+ const target = event.target as HTMLElement;
123
+ const action = target.closest("[data-dialog]")?.getAttribute("data-dialog");
124
+ if (action === "ok") {
125
+ closeShell(shell);
126
+ callback?.(true);
127
+ }
128
+ if (action === "cancel") {
129
+ closeShell(shell);
130
+ callback?.(false);
131
+ }
132
+ });
133
+
134
+ bindKeys(
135
+ shell,
136
+ () => {
137
+ closeShell(shell);
138
+ callback?.(true);
139
+ },
140
+ () => {
141
+ closeShell(shell);
142
+ callback?.(false);
143
+ }
144
+ );
145
+ hostNode().appendChild(shell);
146
+ (shell.querySelector("[data-dialog='ok']") as HTMLElement)?.focus();
147
+ },
148
+
149
+ prompt(text = "", options: PromptOptions = {}, callback?: (result: { ok: boolean; value: string }) => void) {
150
+ const { limit = 0, placeholder = "Remarks...", defaultValue = "" } = options;
151
+
152
+ const shell = buildShell(`
153
+ <div class='card position-absolute top-50 start-50 translate-middle border' style='width:300px'>
154
+ <div class='card-header d-flex justify-content-between align-items-center px-2 py-1 border-0'>
155
+ <span class='d-flex align-items-center'>
156
+ <i class="bi bi-globe"></i> <span class='ms-2'>${siteLabel()}</span>
157
+ </span>
158
+ <button class='btn btn-sm p-0' type='button' data-dialog='cancel'>
159
+ <i class='bi bi-x fs-3'></i>
160
+ </button>
161
+ </div>
162
+ <div class='card-body overflow-x-hidden overflow-y-scroll p-2 position-relative'>
163
+ ${text} <sup style='font-size: 10px'>${limit} char</sup>
164
+ <textarea class='form-control' rows='4' placeholder='${placeholder}' data-dialog='input' ${limit > 0 ? `maxlength='${limit}'` : ""}>${defaultValue}</textarea>
165
+ </div>
166
+ <div class='card-footer d-flex justify-content-end align-items-center px-2 py-1 border-0'>
167
+ <button type='button' class='btn btn-primary btn-sm' data-dialog='ok'>OK</button>
168
+ <button type='button' class='btn btn-secondary btn-sm ms-1' data-dialog='cancel'>Cancel</button>
169
+ </div>
170
+ </div>
171
+ `);
172
+
173
+ const input = shell.querySelector("textarea[data-dialog='input']") as HTMLTextAreaElement | null;
174
+
175
+ shell.addEventListener("click", (event) => {
176
+ event.stopPropagation();
177
+ const target = event.target as HTMLElement;
178
+ const action = target.closest("[data-dialog]")?.getAttribute("data-dialog");
179
+
180
+ if (action === "ok") {
181
+ closeShell(shell);
182
+ callback?.({ ok: true, value: input?.value || "" });
183
+ }
184
+ if (action === "cancel") {
185
+ closeShell(shell);
186
+ callback?.({ ok: false, value: "" });
187
+ }
188
+ });
189
+
190
+ bindKeys(
191
+ shell,
192
+ () => {
193
+ closeShell(shell);
194
+ callback?.({ ok: true, value: input?.value || "" });
195
+ },
196
+ () => {
197
+ closeShell(shell);
198
+ callback?.({ ok: false, value: "" });
199
+ }
200
+ );
201
+ hostNode().appendChild(shell);
202
+ (shell.querySelector("textarea[data-dialog='input']") as HTMLElement)?.focus();
203
+ }
204
+ };
205
+
206
+ export const DialogPlugin = {
207
+ install(app: App) {
208
+ app.config.globalProperties.$dialog = dialog;
209
+ }
210
+ };
211
+
212
+ declare module "vue" {
213
+ interface ComponentCustomProperties {
214
+ $dialog: DialogClient;
215
+ }
216
+ }