create-nexwire 4.0.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 (488) hide show
  1. package/README.md +233 -0
  2. package/express/.dockerignore +14 -0
  3. package/express/.env +44 -0
  4. package/express/.env.example +42 -0
  5. package/express/.vscode/settings.json +26 -0
  6. package/express/LICENSE +21 -0
  7. package/express/README.md +211 -0
  8. package/express/biome.json +66 -0
  9. package/express/drizzle.config.ts +25 -0
  10. package/express/gitignore-stub +24 -0
  11. package/express/package.json +108 -0
  12. package/express/public/.gitkeep +0 -0
  13. package/express/src/config/app.ts +41 -0
  14. package/express/src/config/auth.ts +12 -0
  15. package/express/src/config/cache.ts +16 -0
  16. package/express/src/config/cookie.ts +15 -0
  17. package/express/src/config/cors.ts +12 -0
  18. package/express/src/config/database.ts +29 -0
  19. package/express/src/config/index.ts +83 -0
  20. package/express/src/config/jwt.ts +19 -0
  21. package/express/src/config/logging.ts +13 -0
  22. package/express/src/config/mail.ts +24 -0
  23. package/express/src/config/openapi.ts +54 -0
  24. package/express/src/config/queue.ts +30 -0
  25. package/express/src/config/rateLimit.ts +17 -0
  26. package/express/src/config/realtime.ts +15 -0
  27. package/express/src/config/redis.ts +18 -0
  28. package/express/src/config/security.ts +44 -0
  29. package/express/src/config/session.ts +17 -0
  30. package/express/src/config/storage.ts +22 -0
  31. package/express/src/config/validate.ts +40 -0
  32. package/express/src/database/migrations/sqlite/0000_init.sql +61 -0
  33. package/express/src/database/migrations/sqlite/meta/0000_snapshot.json +412 -0
  34. package/express/src/database/migrations/sqlite/meta/_journal.json +13 -0
  35. package/express/src/database/schema.ts +3 -0
  36. package/express/src/env.ts +76 -0
  37. package/express/src/framework/cache/cache.ts +81 -0
  38. package/express/src/framework/circuit-breaker/cb.ts +60 -0
  39. package/express/src/framework/database/connection.ts +196 -0
  40. package/express/src/framework/database/migrate-hooks.ts +87 -0
  41. package/express/src/framework/database/paginate.ts +227 -0
  42. package/express/src/framework/database/schema.ts +20 -0
  43. package/express/src/framework/database/seed.ts +139 -0
  44. package/express/src/framework/events/dispatcher.ts +49 -0
  45. package/express/src/framework/facade.ts +48 -0
  46. package/express/src/framework/http/app.ts +107 -0
  47. package/express/src/framework/http/cors.ts +7 -0
  48. package/express/src/framework/http/logger.ts +69 -0
  49. package/express/src/framework/http/metrics.ts +22 -0
  50. package/express/src/framework/http/openapi.ts +54 -0
  51. package/express/src/framework/http/ratelimiter.ts +16 -0
  52. package/express/src/framework/http/router.ts +178 -0
  53. package/express/src/framework/http/security.ts +23 -0
  54. package/express/src/framework/http/static.ts +23 -0
  55. package/express/src/framework/http/validation.ts +18 -0
  56. package/express/src/framework/kernel.ts +52 -0
  57. package/express/src/framework/maker-cli/db/core.mjs +288 -0
  58. package/express/src/framework/maker-cli/db/index.mjs +204 -0
  59. package/express/src/framework/maker-cli/deploy/core.mjs +1047 -0
  60. package/express/src/framework/maker-cli/deploy/index.mjs +91 -0
  61. package/express/src/framework/maker-cli/index.mjs +53 -0
  62. package/express/src/framework/maker-cli/middleware/core.mjs +47 -0
  63. package/express/src/framework/maker-cli/middleware/index.mjs +17 -0
  64. package/express/src/framework/maker-cli/module/core.mjs +684 -0
  65. package/express/src/framework/maker-cli/module/index.mjs +140 -0
  66. package/express/src/framework/maker-cli/runtime/build-ui.mjs +16 -0
  67. package/express/src/framework/maker-cli/runtime/core.mjs +543 -0
  68. package/express/src/framework/maker-cli/runtime/index.mjs +104 -0
  69. package/express/src/framework/maker-cli/runtime/redis-commander-patch.cjs +20 -0
  70. package/express/src/framework/maker-cli/stubs/controller/openapi.ts.stub +47 -0
  71. package/express/src/framework/maker-cli/stubs/controller/openapi.with-model.ts.stub +48 -0
  72. package/express/src/framework/maker-cli/stubs/controller/plain.ts.stub +54 -0
  73. package/express/src/framework/maker-cli/stubs/controller/schema.plain.ts.stub +14 -0
  74. package/express/src/framework/maker-cli/stubs/controller/schema.ts.stub +33 -0
  75. package/express/src/framework/maker-cli/stubs/deploy/Dockerfile.bun.stub +52 -0
  76. package/express/src/framework/maker-cli/stubs/deploy/Dockerfile.pnpm.stub +55 -0
  77. package/express/src/framework/maker-cli/stubs/deploy/Dockerfile.stub +51 -0
  78. package/express/src/framework/maker-cli/stubs/deploy/Dockerfile.yarn.stub +55 -0
  79. package/express/src/framework/maker-cli/stubs/deploy/README.stub +59 -0
  80. package/express/src/framework/maker-cli/stubs/deploy/compose/mysql.server.stub +45 -0
  81. package/express/src/framework/maker-cli/stubs/deploy/compose/postgres.server.stub +45 -0
  82. package/express/src/framework/maker-cli/stubs/deploy/compose/sqlite.stub +45 -0
  83. package/express/src/framework/maker-cli/stubs/deploy/env/mysql.server.stub +68 -0
  84. package/express/src/framework/maker-cli/stubs/deploy/env/postgres.server.stub +68 -0
  85. package/express/src/framework/maker-cli/stubs/deploy/env/sqlite.stub +67 -0
  86. package/express/src/framework/maker-cli/stubs/deploy/scripts/auto-migrate.sh.stub +41 -0
  87. package/express/src/framework/maker-cli/stubs/deploy/server/README.stub +78 -0
  88. package/express/src/framework/maker-cli/stubs/deploy/server/compose/noredis.stub +120 -0
  89. package/express/src/framework/maker-cli/stubs/deploy/server/compose/redis.dev.stub +133 -0
  90. package/express/src/framework/maker-cli/stubs/deploy/server/compose/redis.stub +131 -0
  91. package/express/src/framework/maker-cli/stubs/deploy/server/env/local.example.stub +11 -0
  92. package/express/src/framework/maker-cli/stubs/deploy/server/env/noredis.stub +25 -0
  93. package/express/src/framework/maker-cli/stubs/deploy/server/env/redis.stub +25 -0
  94. package/express/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/README.stub +16 -0
  95. package/express/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/app.example.com.stub +13 -0
  96. package/express/src/framework/maker-cli/stubs/deploy/server/pgadmin/servers.stub +14 -0
  97. package/express/src/framework/maker-cli/stubs/deploy/server/redis/redis.conf.stub +7 -0
  98. package/express/src/framework/maker-cli/stubs/deploy/supervisor/noredis.stub +54 -0
  99. package/express/src/framework/maker-cli/stubs/deploy/supervisor/redis.stub +70 -0
  100. package/express/src/framework/maker-cli/stubs/deploy/workflow/local.json.stub +25 -0
  101. package/express/src/framework/maker-cli/stubs/deploy/workflow/remote.json.stub +24 -0
  102. package/express/src/framework/maker-cli/stubs/example/console.ts.stub +34 -0
  103. package/express/src/framework/maker-cli/stubs/example/controller.ts.stub +418 -0
  104. package/express/src/framework/maker-cli/stubs/example/job.ts.stub +75 -0
  105. package/express/src/framework/maker-cli/stubs/example/route.api.ts.stub +207 -0
  106. package/express/src/framework/maker-cli/stubs/example/route.plain.ts.stub +18 -0
  107. package/express/src/framework/maker-cli/stubs/example/schema.plain.ts.stub +42 -0
  108. package/express/src/framework/maker-cli/stubs/example/schema.ts.stub +42 -0
  109. package/express/src/framework/maker-cli/stubs/job/name.ts.stub +25 -0
  110. package/express/src/framework/maker-cli/stubs/middleware/name.ts.stub +14 -0
  111. package/express/src/framework/maker-cli/stubs/model/name.mysql.ts.stub +9 -0
  112. package/express/src/framework/maker-cli/stubs/model/name.postgresql.ts.stub +9 -0
  113. package/express/src/framework/maker-cli/stubs/model/name.sqlite.ts.stub +9 -0
  114. package/express/src/framework/maker-cli/stubs/notification/controller.ts.stub +77 -0
  115. package/express/src/framework/maker-cli/stubs/notification/job.ts.stub +13 -0
  116. package/express/src/framework/maker-cli/stubs/notification/route.api.ts.stub +50 -0
  117. package/express/src/framework/maker-cli/stubs/notification/route.plain.ts.stub +12 -0
  118. package/express/src/framework/maker-cli/stubs/notification/schema.plain.ts.stub +26 -0
  119. package/express/src/framework/maker-cli/stubs/notification/schema.ts.stub +26 -0
  120. package/express/src/framework/maker-cli/stubs/route/api.ts.stub +80 -0
  121. package/express/src/framework/maker-cli/stubs/route/plain.ts.stub +11 -0
  122. package/express/src/framework/maker-cli/stubs/schedule/name.ts.stub +36 -0
  123. package/express/src/framework/maker-cli/stubs/seeder/name.ts.stub +20 -0
  124. package/express/src/framework/maker-cli/stubs/test/unit.ts.stub +22 -0
  125. package/express/src/framework/maker-cli/utils/env-config.mjs +44 -0
  126. package/express/src/framework/maker-cli/utils/env-db.mjs +61 -0
  127. package/express/src/framework/maker-cli/utils/file-ops.mjs +30 -0
  128. package/express/src/framework/maker-cli/utils/flags.mjs +14 -0
  129. package/express/src/framework/maker-cli/utils/help.mjs +50 -0
  130. package/express/src/framework/maker-cli/utils/naming.mjs +13 -0
  131. package/express/src/framework/maker-cli/utils/process.mjs +52 -0
  132. package/express/src/framework/modules/discover.ts +54 -0
  133. package/express/src/framework/modules/routes.ts +21 -0
  134. package/express/src/framework/notification/index.ts +116 -0
  135. package/express/src/framework/queue/clear.ts +22 -0
  136. package/express/src/framework/queue/queue.ts +342 -0
  137. package/express/src/framework/queue/ui.ts +187 -0
  138. package/express/src/framework/queue/worker.ts +61 -0
  139. package/express/src/framework/realtime/broadcast.ts +46 -0
  140. package/express/src/framework/realtime/index.ts +2 -0
  141. package/express/src/framework/realtime/socket-cookie.ts +71 -0
  142. package/express/src/framework/realtime/socket.ts +119 -0
  143. package/express/src/framework/realtime/types.ts +6 -0
  144. package/express/src/framework/realtime/ui.ts +16 -0
  145. package/express/src/framework/redis/client.ts +151 -0
  146. package/express/src/framework/runtime/runtime.ts +23 -0
  147. package/express/src/framework/runtime/server-adapter.ts +34 -0
  148. package/express/src/framework/scheduler/lock.ts +116 -0
  149. package/express/src/framework/scheduler/run.ts +48 -0
  150. package/express/src/framework/scheduler/scheduler.ts +155 -0
  151. package/express/src/framework/server.ts +177 -0
  152. package/express/src/framework/session/session.ts +98 -0
  153. package/express/src/framework/storage/storage.ts +785 -0
  154. package/express/src/framework/support/cookie.ts +62 -0
  155. package/express/src/framework/support/jwt.ts +33 -0
  156. package/express/src/framework/support/lifecycle.ts +35 -0
  157. package/express/src/framework/support/logger.ts +148 -0
  158. package/express/src/framework/support/mail.ts +48 -0
  159. package/express/src/framework/support/password.ts +23 -0
  160. package/express/src/framework/support/upload.ts +160 -0
  161. package/express/src/framework/support/url.ts +41 -0
  162. package/express/src/middlewares/auth-middleware.ts +98 -0
  163. package/express/src/middlewares/role-middleware.ts +25 -0
  164. package/express/src/modules/auth/controllers/auth.controller.ts +358 -0
  165. package/express/src/modules/auth/controllers/auth.helpers.ts +104 -0
  166. package/express/src/modules/auth/controllers/auth.schema.ts +102 -0
  167. package/express/src/modules/auth/controllers/role.controller.ts +15 -0
  168. package/express/src/modules/auth/database/models/notifications.ts +24 -0
  169. package/express/src/modules/auth/database/models/role.ts +14 -0
  170. package/express/src/modules/auth/database/models/user.ts +46 -0
  171. package/express/src/modules/auth/database/seeders/role.ts +18 -0
  172. package/express/src/modules/auth/database/seeders/user.ts +35 -0
  173. package/express/src/modules/auth/jobs/forgetpass.ts +20 -0
  174. package/express/src/modules/auth/jobs/registeruser.ts +23 -0
  175. package/express/src/modules/auth/jobs/verifyemail.ts +18 -0
  176. package/express/src/modules/auth/routes/api.ts +150 -0
  177. package/express/src/modules/auth/routes/role.ts +33 -0
  178. package/express/src/resources/index.html +17 -0
  179. package/express/src/resources/src/App.vue +5 -0
  180. package/express/src/resources/src/assets/css/styles.css +14761 -0
  181. package/express/src/resources/src/assets/css/styles.css.map +1 -0
  182. package/express/src/resources/src/assets/fonts/public-sans/public-sans-latin-ext.woff2 +0 -0
  183. package/express/src/resources/src/assets/fonts/public-sans/public-sans-latin.woff2 +0 -0
  184. package/express/src/resources/src/assets/images/favicon/favicon.ico +0 -0
  185. package/express/src/resources/src/assets/images/logo.png +0 -0
  186. package/express/src/resources/src/assets/scss/custom.css +217 -0
  187. package/express/src/resources/src/assets/scss/custom.css.map +1 -0
  188. package/express/src/resources/src/assets/scss/custom.scss +1346 -0
  189. package/express/src/resources/src/components/Button.vue +32 -0
  190. package/express/src/resources/src/components/Checkbox.vue +29 -0
  191. package/express/src/resources/src/components/Datepicker.vue +106 -0
  192. package/express/src/resources/src/components/FeatureButton.vue +53 -0
  193. package/express/src/resources/src/components/FloatButton.vue +33 -0
  194. package/express/src/resources/src/components/Href.vue +32 -0
  195. package/express/src/resources/src/components/Input.vue +223 -0
  196. package/express/src/resources/src/components/InputGroup.vue +145 -0
  197. package/express/src/resources/src/components/InputPasswordToggle.vue +213 -0
  198. package/express/src/resources/src/components/Modal.vue +55 -0
  199. package/express/src/resources/src/components/Pagebar.vue +26 -0
  200. package/express/src/resources/src/components/Select.vue +384 -0
  201. package/express/src/resources/src/components/Spinner.vue +42 -0
  202. package/express/src/resources/src/components/Switch.vue +65 -0
  203. package/express/src/resources/src/components/TextArea.vue +117 -0
  204. package/express/src/resources/src/components/Toast.vue +56 -0
  205. package/express/src/resources/src/components/datatable/DataTableSkeleton.vue +98 -0
  206. package/express/src/resources/src/components/datatable/Pagination.vue +147 -0
  207. package/express/src/resources/src/components/datatable/SelectOpption.vue +64 -0
  208. package/express/src/resources/src/components/datatable/index.vue +199 -0
  209. package/express/src/resources/src/composables/useAuth.ts +52 -0
  210. package/express/src/resources/src/helpers/nformatter.ts +10 -0
  211. package/express/src/resources/src/helpers/utils.ts +75 -0
  212. package/express/src/resources/src/layouts/AuthLayout.vue +20 -0
  213. package/express/src/resources/src/layouts/Layout/Footer.vue +23 -0
  214. package/express/src/resources/src/layouts/Layout/Header.vue +105 -0
  215. package/express/src/resources/src/layouts/Layout/Sidebar.vue +137 -0
  216. package/express/src/resources/src/layouts/Layout/index.vue +87 -0
  217. package/express/src/resources/src/main.ts +26 -0
  218. package/express/src/resources/src/pages/auth/forgetPassword.vue +82 -0
  219. package/express/src/resources/src/pages/auth/login.vue +99 -0
  220. package/express/src/resources/src/pages/auth/register.vue +133 -0
  221. package/express/src/resources/src/pages/auth/resetPassword.vue +118 -0
  222. package/express/src/resources/src/pages/auth/verifyEmail.vue +68 -0
  223. package/express/src/resources/src/pages/dashboard/index.vue +66 -0
  224. package/express/src/resources/src/plugins/axios.ts +31 -0
  225. package/express/src/resources/src/plugins/browserDetect.ts +55 -0
  226. package/express/src/resources/src/plugins/dialog.ts +216 -0
  227. package/express/src/resources/src/plugins/gum.ts +367 -0
  228. package/express/src/resources/src/plugins/pulse.ts +147 -0
  229. package/express/src/resources/src/plugins/routeProgress.ts +87 -0
  230. package/express/src/resources/src/router/index.ts +85 -0
  231. package/express/src/resources/src/stores/admin-ui.ts +148 -0
  232. package/express/src/resources/src/stores/auth.ts +164 -0
  233. package/express/src/resources/tsconfig.json +19 -0
  234. package/express/src/resources/vite.config.ts +46 -0
  235. package/express/src/storage/app/private/.gitkeep +0 -0
  236. package/express/src/storage/app/public/.gitkeep +0 -0
  237. package/express/src/storage/app/tmp/generated/.gitkeep +0 -0
  238. package/express/src/storage/database/nexwire.sqlite +0 -0
  239. package/express/src/storage/logs/.gitkeep +0 -0
  240. package/express/src/storage/tmp/.gitkeep +0 -0
  241. package/express/src/storage/trash/modules/.gitkeep +0 -0
  242. package/express/src/types/global.d.ts +26 -0
  243. package/express/tsconfig.json +19 -0
  244. package/express/vitest.config.ts +23 -0
  245. package/hono/.dockerignore +14 -0
  246. package/hono/.env +44 -0
  247. package/hono/.env.example +42 -0
  248. package/hono/.vscode/settings.json +26 -0
  249. package/hono/LICENSE +21 -0
  250. package/hono/README.md +211 -0
  251. package/hono/biome.json +76 -0
  252. package/hono/drizzle.config.ts +25 -0
  253. package/hono/gitignore-stub +24 -0
  254. package/hono/package.json +99 -0
  255. package/hono/public/.gitkeep +0 -0
  256. package/hono/src/config/app.ts +41 -0
  257. package/hono/src/config/auth.ts +12 -0
  258. package/hono/src/config/cache.ts +16 -0
  259. package/hono/src/config/cookie.ts +15 -0
  260. package/hono/src/config/cors.ts +12 -0
  261. package/hono/src/config/database.ts +29 -0
  262. package/hono/src/config/index.ts +83 -0
  263. package/hono/src/config/jwt.ts +19 -0
  264. package/hono/src/config/logging.ts +13 -0
  265. package/hono/src/config/mail.ts +24 -0
  266. package/hono/src/config/openapi.ts +54 -0
  267. package/hono/src/config/queue.ts +30 -0
  268. package/hono/src/config/rateLimit.ts +17 -0
  269. package/hono/src/config/realtime.ts +15 -0
  270. package/hono/src/config/redis.ts +18 -0
  271. package/hono/src/config/security.ts +44 -0
  272. package/hono/src/config/session.ts +17 -0
  273. package/hono/src/config/storage.ts +22 -0
  274. package/hono/src/config/validate.ts +40 -0
  275. package/hono/src/database/migrations/sqlite/0000_init.sql +61 -0
  276. package/hono/src/database/migrations/sqlite/meta/0000_snapshot.json +412 -0
  277. package/hono/src/database/migrations/sqlite/meta/_journal.json +13 -0
  278. package/hono/src/database/schema.ts +3 -0
  279. package/hono/src/env.ts +76 -0
  280. package/hono/src/framework/cache/cache.ts +81 -0
  281. package/hono/src/framework/circuit-breaker/cb.ts +60 -0
  282. package/hono/src/framework/database/connection.ts +196 -0
  283. package/hono/src/framework/database/migrate-hooks.ts +87 -0
  284. package/hono/src/framework/database/paginate.ts +253 -0
  285. package/hono/src/framework/database/schema.ts +20 -0
  286. package/hono/src/framework/database/seed.ts +139 -0
  287. package/hono/src/framework/events/dispatcher.ts +49 -0
  288. package/hono/src/framework/facade.ts +29 -0
  289. package/hono/src/framework/http/app.ts +109 -0
  290. package/hono/src/framework/http/cors.ts +19 -0
  291. package/hono/src/framework/http/logger.ts +81 -0
  292. package/hono/src/framework/http/metrics.ts +22 -0
  293. package/hono/src/framework/http/openapi.ts +42 -0
  294. package/hono/src/framework/http/ratelimiter.ts +172 -0
  295. package/hono/src/framework/http/router.ts +76 -0
  296. package/hono/src/framework/http/security.ts +23 -0
  297. package/hono/src/framework/http/static.ts +70 -0
  298. package/hono/src/framework/http/validation.ts +21 -0
  299. package/hono/src/framework/kernel.ts +48 -0
  300. package/hono/src/framework/maker-cli/db/core.mjs +288 -0
  301. package/hono/src/framework/maker-cli/db/index.mjs +204 -0
  302. package/hono/src/framework/maker-cli/deploy/core.mjs +1038 -0
  303. package/hono/src/framework/maker-cli/deploy/index.mjs +91 -0
  304. package/hono/src/framework/maker-cli/index.mjs +53 -0
  305. package/hono/src/framework/maker-cli/middleware/core.mjs +47 -0
  306. package/hono/src/framework/maker-cli/middleware/index.mjs +12 -0
  307. package/hono/src/framework/maker-cli/module/core.mjs +684 -0
  308. package/hono/src/framework/maker-cli/module/index.mjs +140 -0
  309. package/hono/src/framework/maker-cli/runtime/build-ui.mjs +17 -0
  310. package/hono/src/framework/maker-cli/runtime/core.mjs +543 -0
  311. package/hono/src/framework/maker-cli/runtime/index.mjs +104 -0
  312. package/hono/src/framework/maker-cli/runtime/redis-commander-patch.cjs +20 -0
  313. package/hono/src/framework/maker-cli/stubs/controller/openapi.ts.stub +57 -0
  314. package/hono/src/framework/maker-cli/stubs/controller/openapi.with-model.ts.stub +58 -0
  315. package/hono/src/framework/maker-cli/stubs/controller/plain.ts.stub +59 -0
  316. package/hono/src/framework/maker-cli/stubs/controller/schema.plain.ts.stub +14 -0
  317. package/hono/src/framework/maker-cli/stubs/controller/schema.ts.stub +33 -0
  318. package/hono/src/framework/maker-cli/stubs/deploy/Dockerfile.bun.stub +52 -0
  319. package/hono/src/framework/maker-cli/stubs/deploy/Dockerfile.pnpm.stub +55 -0
  320. package/hono/src/framework/maker-cli/stubs/deploy/Dockerfile.stub +51 -0
  321. package/hono/src/framework/maker-cli/stubs/deploy/Dockerfile.yarn.stub +55 -0
  322. package/hono/src/framework/maker-cli/stubs/deploy/README.stub +59 -0
  323. package/hono/src/framework/maker-cli/stubs/deploy/compose/mysql.server.stub +45 -0
  324. package/hono/src/framework/maker-cli/stubs/deploy/compose/postgres.server.stub +45 -0
  325. package/hono/src/framework/maker-cli/stubs/deploy/compose/sqlite.stub +45 -0
  326. package/hono/src/framework/maker-cli/stubs/deploy/env/mysql.server.stub +68 -0
  327. package/hono/src/framework/maker-cli/stubs/deploy/env/postgres.server.stub +68 -0
  328. package/hono/src/framework/maker-cli/stubs/deploy/env/sqlite.stub +67 -0
  329. package/hono/src/framework/maker-cli/stubs/deploy/scripts/auto-migrate.sh.stub +41 -0
  330. package/hono/src/framework/maker-cli/stubs/deploy/server/README.stub +78 -0
  331. package/hono/src/framework/maker-cli/stubs/deploy/server/compose/noredis.stub +120 -0
  332. package/hono/src/framework/maker-cli/stubs/deploy/server/compose/redis.dev.stub +133 -0
  333. package/hono/src/framework/maker-cli/stubs/deploy/server/compose/redis.stub +131 -0
  334. package/hono/src/framework/maker-cli/stubs/deploy/server/env/local.example.stub +11 -0
  335. package/hono/src/framework/maker-cli/stubs/deploy/server/env/noredis.stub +25 -0
  336. package/hono/src/framework/maker-cli/stubs/deploy/server/env/redis.stub +25 -0
  337. package/hono/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/README.stub +16 -0
  338. package/hono/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/app.example.com.stub +13 -0
  339. package/hono/src/framework/maker-cli/stubs/deploy/server/pgadmin/servers.stub +14 -0
  340. package/hono/src/framework/maker-cli/stubs/deploy/server/redis/redis.conf.stub +7 -0
  341. package/hono/src/framework/maker-cli/stubs/deploy/supervisor/noredis.stub +54 -0
  342. package/hono/src/framework/maker-cli/stubs/deploy/supervisor/redis.stub +70 -0
  343. package/hono/src/framework/maker-cli/stubs/deploy/workflow/local.json.stub +25 -0
  344. package/hono/src/framework/maker-cli/stubs/deploy/workflow/remote.json.stub +24 -0
  345. package/hono/src/framework/maker-cli/stubs/example/console.ts.stub +34 -0
  346. package/hono/src/framework/maker-cli/stubs/example/controller.ts.stub +505 -0
  347. package/hono/src/framework/maker-cli/stubs/example/job.ts.stub +75 -0
  348. package/hono/src/framework/maker-cli/stubs/example/route.api.ts.stub +207 -0
  349. package/hono/src/framework/maker-cli/stubs/example/route.plain.ts.stub +18 -0
  350. package/hono/src/framework/maker-cli/stubs/example/schema.plain.ts.stub +42 -0
  351. package/hono/src/framework/maker-cli/stubs/example/schema.ts.stub +42 -0
  352. package/hono/src/framework/maker-cli/stubs/job/name.ts.stub +25 -0
  353. package/hono/src/framework/maker-cli/stubs/middleware/name.ts.stub +14 -0
  354. package/hono/src/framework/maker-cli/stubs/model/name.mysql.ts.stub +9 -0
  355. package/hono/src/framework/maker-cli/stubs/model/name.postgresql.ts.stub +9 -0
  356. package/hono/src/framework/maker-cli/stubs/model/name.sqlite.ts.stub +9 -0
  357. package/hono/src/framework/maker-cli/stubs/notification/controller.ts.stub +86 -0
  358. package/hono/src/framework/maker-cli/stubs/notification/job.ts.stub +13 -0
  359. package/hono/src/framework/maker-cli/stubs/notification/route.api.ts.stub +50 -0
  360. package/hono/src/framework/maker-cli/stubs/notification/route.plain.ts.stub +12 -0
  361. package/hono/src/framework/maker-cli/stubs/notification/schema.plain.ts.stub +26 -0
  362. package/hono/src/framework/maker-cli/stubs/notification/schema.ts.stub +26 -0
  363. package/hono/src/framework/maker-cli/stubs/route/api.ts.stub +80 -0
  364. package/hono/src/framework/maker-cli/stubs/route/plain.ts.stub +11 -0
  365. package/hono/src/framework/maker-cli/stubs/schedule/name.ts.stub +36 -0
  366. package/hono/src/framework/maker-cli/stubs/seeder/name.ts.stub +20 -0
  367. package/hono/src/framework/maker-cli/stubs/test/unit.ts.stub +22 -0
  368. package/hono/src/framework/maker-cli/utils/env-config.mjs +44 -0
  369. package/hono/src/framework/maker-cli/utils/env-db.mjs +61 -0
  370. package/hono/src/framework/maker-cli/utils/file-ops.mjs +30 -0
  371. package/hono/src/framework/maker-cli/utils/flags.mjs +14 -0
  372. package/hono/src/framework/maker-cli/utils/help.mjs +50 -0
  373. package/hono/src/framework/maker-cli/utils/naming.mjs +13 -0
  374. package/hono/src/framework/maker-cli/utils/process.mjs +52 -0
  375. package/hono/src/framework/modules/discover.ts +54 -0
  376. package/hono/src/framework/modules/routes.ts +24 -0
  377. package/hono/src/framework/notification/index.ts +116 -0
  378. package/hono/src/framework/queue/clear.ts +22 -0
  379. package/hono/src/framework/queue/queue.ts +342 -0
  380. package/hono/src/framework/queue/ui.ts +214 -0
  381. package/hono/src/framework/queue/worker.ts +61 -0
  382. package/hono/src/framework/realtime/broadcast.ts +46 -0
  383. package/hono/src/framework/realtime/index.ts +2 -0
  384. package/hono/src/framework/realtime/socket-cookie.ts +68 -0
  385. package/hono/src/framework/realtime/socket.ts +196 -0
  386. package/hono/src/framework/realtime/types.ts +6 -0
  387. package/hono/src/framework/realtime/ui.ts +16 -0
  388. package/hono/src/framework/redis/client.ts +151 -0
  389. package/hono/src/framework/runtime/runtime.ts +23 -0
  390. package/hono/src/framework/runtime/server-adapter.ts +94 -0
  391. package/hono/src/framework/scheduler/lock.ts +116 -0
  392. package/hono/src/framework/scheduler/run.ts +48 -0
  393. package/hono/src/framework/scheduler/scheduler.ts +155 -0
  394. package/hono/src/framework/server.ts +183 -0
  395. package/hono/src/framework/session/session.ts +116 -0
  396. package/hono/src/framework/storage/storage.ts +785 -0
  397. package/hono/src/framework/support/cookie.ts +99 -0
  398. package/hono/src/framework/support/jwt.ts +45 -0
  399. package/hono/src/framework/support/lifecycle.ts +35 -0
  400. package/hono/src/framework/support/logger.ts +148 -0
  401. package/hono/src/framework/support/mail.ts +48 -0
  402. package/hono/src/framework/support/password.ts +23 -0
  403. package/hono/src/framework/support/url.ts +41 -0
  404. package/hono/src/middlewares/auth-middleware.ts +98 -0
  405. package/hono/src/middlewares/role-middleware.ts +25 -0
  406. package/hono/src/modules/auth/controllers/auth.controller.ts +413 -0
  407. package/hono/src/modules/auth/controllers/auth.helpers.ts +128 -0
  408. package/hono/src/modules/auth/controllers/auth.schema.ts +102 -0
  409. package/hono/src/modules/auth/controllers/role.controller.ts +25 -0
  410. package/hono/src/modules/auth/database/models/notifications.ts +24 -0
  411. package/hono/src/modules/auth/database/models/role.ts +14 -0
  412. package/hono/src/modules/auth/database/models/user.ts +46 -0
  413. package/hono/src/modules/auth/database/seeders/role.ts +18 -0
  414. package/hono/src/modules/auth/database/seeders/user.ts +35 -0
  415. package/hono/src/modules/auth/jobs/forgetpass.ts +20 -0
  416. package/hono/src/modules/auth/jobs/registeruser.ts +23 -0
  417. package/hono/src/modules/auth/jobs/verifyemail.ts +18 -0
  418. package/hono/src/modules/auth/routes/api.ts +150 -0
  419. package/hono/src/modules/auth/routes/role.ts +33 -0
  420. package/hono/src/resources/index.html +17 -0
  421. package/hono/src/resources/src/App.vue +5 -0
  422. package/hono/src/resources/src/assets/css/styles.css +14913 -0
  423. package/hono/src/resources/src/assets/css/styles.css.map +1 -0
  424. package/hono/src/resources/src/assets/fonts/public-sans/public-sans-latin-ext.woff2 +0 -0
  425. package/hono/src/resources/src/assets/fonts/public-sans/public-sans-latin.woff2 +0 -0
  426. package/hono/src/resources/src/assets/images/favicon/favicon.ico +0 -0
  427. package/hono/src/resources/src/assets/images/logo.png +0 -0
  428. package/hono/src/resources/src/assets/scss/custom.css +217 -0
  429. package/hono/src/resources/src/assets/scss/custom.css.map +1 -0
  430. package/hono/src/resources/src/assets/scss/custom.scss +1346 -0
  431. package/hono/src/resources/src/components/Button.vue +32 -0
  432. package/hono/src/resources/src/components/Checkbox.vue +29 -0
  433. package/hono/src/resources/src/components/Datepicker.vue +106 -0
  434. package/hono/src/resources/src/components/FeatureButton.vue +53 -0
  435. package/hono/src/resources/src/components/FloatButton.vue +33 -0
  436. package/hono/src/resources/src/components/Href.vue +32 -0
  437. package/hono/src/resources/src/components/Input.vue +234 -0
  438. package/hono/src/resources/src/components/InputGroup.vue +149 -0
  439. package/hono/src/resources/src/components/InputPasswordToggle.vue +222 -0
  440. package/hono/src/resources/src/components/Modal.vue +55 -0
  441. package/hono/src/resources/src/components/Pagebar.vue +26 -0
  442. package/hono/src/resources/src/components/Select.vue +415 -0
  443. package/hono/src/resources/src/components/Spinner.vue +42 -0
  444. package/hono/src/resources/src/components/Switch.vue +65 -0
  445. package/hono/src/resources/src/components/TextArea.vue +121 -0
  446. package/hono/src/resources/src/components/Toast.vue +56 -0
  447. package/hono/src/resources/src/components/datatable/DataTableSkeleton.vue +98 -0
  448. package/hono/src/resources/src/components/datatable/Pagination.vue +147 -0
  449. package/hono/src/resources/src/components/datatable/SelectOpption.vue +64 -0
  450. package/hono/src/resources/src/components/datatable/index.vue +199 -0
  451. package/hono/src/resources/src/composables/useAuth.ts +52 -0
  452. package/hono/src/resources/src/helpers/nformatter.ts +10 -0
  453. package/hono/src/resources/src/helpers/utils.ts +75 -0
  454. package/hono/src/resources/src/layouts/AuthLayout.vue +20 -0
  455. package/hono/src/resources/src/layouts/Layout/Footer.vue +23 -0
  456. package/hono/src/resources/src/layouts/Layout/Header.vue +105 -0
  457. package/hono/src/resources/src/layouts/Layout/Sidebar.vue +137 -0
  458. package/hono/src/resources/src/layouts/Layout/index.vue +87 -0
  459. package/hono/src/resources/src/main.ts +26 -0
  460. package/hono/src/resources/src/pages/auth/forgetPassword.vue +82 -0
  461. package/hono/src/resources/src/pages/auth/login.vue +99 -0
  462. package/hono/src/resources/src/pages/auth/register.vue +133 -0
  463. package/hono/src/resources/src/pages/auth/resetPassword.vue +118 -0
  464. package/hono/src/resources/src/pages/auth/verifyEmail.vue +68 -0
  465. package/hono/src/resources/src/pages/dashboard/index.vue +66 -0
  466. package/hono/src/resources/src/plugins/axios.ts +31 -0
  467. package/hono/src/resources/src/plugins/browserDetect.ts +55 -0
  468. package/hono/src/resources/src/plugins/dialog.ts +216 -0
  469. package/hono/src/resources/src/plugins/gum.ts +367 -0
  470. package/hono/src/resources/src/plugins/pulse.ts +147 -0
  471. package/hono/src/resources/src/plugins/routeProgress.ts +87 -0
  472. package/hono/src/resources/src/router/index.ts +85 -0
  473. package/hono/src/resources/src/stores/admin-ui.ts +148 -0
  474. package/hono/src/resources/src/stores/auth.ts +164 -0
  475. package/hono/src/resources/tsconfig.json +19 -0
  476. package/hono/src/resources/vite.config.ts +46 -0
  477. package/hono/src/storage/app/private/.gitkeep +0 -0
  478. package/hono/src/storage/app/public/.gitkeep +0 -0
  479. package/hono/src/storage/app/tmp/generated/.gitkeep +0 -0
  480. package/hono/src/storage/database/nexwire.sqlite +0 -0
  481. package/hono/src/storage/logs/.gitkeep +0 -0
  482. package/hono/src/storage/tmp/.gitkeep +0 -0
  483. package/hono/src/storage/trash/modules/.gitkeep +0 -0
  484. package/hono/src/types/global.d.ts +26 -0
  485. package/hono/tsconfig.json +20 -0
  486. package/hono/vitest.config.ts +23 -0
  487. package/package.json +238 -0
  488. package/src/index.js +204 -0
@@ -0,0 +1,213 @@
1
+ <template>
2
+ <div :class="topclass">
3
+ <div class="position-relative">
4
+ <label :for="inputId" class="d-flex align-items-center" :class="{ 'd-none': !inputLabel }">
5
+ <div class="position-relative">
6
+ <span class="text-capitalize mb-1" v-html="inputLabel"></span>
7
+ <span
8
+ class="position-absolute text-danger rounded-circle bg-danger must"
9
+ :class="{ 'd-none': !props.must }"></span>
10
+ </div>
11
+ <div
12
+ class="text-end ms-auto text-primary align-self-center"
13
+ :class="{ 'd-none': !props.hood }"
14
+ style="font-size: 12px; margin-top: 0.15rem"
15
+ v-html="hoodHtml"></div>
16
+ </label>
17
+
18
+ <div class="input-group mb-3">
19
+ <input
20
+ ref="inputRef"
21
+ class="form-control border-0"
22
+ :type="showPassword ? 'text' : 'password'"
23
+ :value="props.modelValue"
24
+ :maxlength="maxLengthAttr"
25
+ :readonly="props.readonly"
26
+ v-bind="$attrs"
27
+ @input="updateModel" />
28
+ <button
29
+ class="input-group-text p-0 border-0 border-start border-1 position-relative z-1"
30
+ type="button"
31
+ @click="togglePassword">
32
+ <i
33
+ class="py-2 px-3"
34
+ :class="showPassword ? 'bi bi-eye' : 'bi bi-eye-slash'"
35
+ style="font-size: 15px"></i>
36
+ </button>
37
+ </div>
38
+ <!-- <input class="form-control" v-model="model" :maxlength="max" v-bind="$attrs"> vue3.3 (2nd way)/3.4 -->
39
+ <div
40
+ class="position-absolute bottom-0 end-0 pe-1 text-secondary max"
41
+ :class="{ 'd-none': !max }">
42
+ {{ maxCounter }}
43
+ </div>
44
+ </div>
45
+ <div
46
+ :id="`${inputId}Help`"
47
+ class="form-text mt-1 text-danger"
48
+ :class="{ 'd-none': !props.err }">
49
+ {{ props.err }}
50
+ </div>
51
+ </div>
52
+ </template>
53
+
54
+ <script setup lang="ts">
55
+ import { computed, nextTick, onMounted, ref, useAttrs } from "vue";
56
+ import { browserDetect } from "@/plugins/browserDetect";
57
+
58
+ defineOptions({ name: "InputPasswordToggle", inheritAttrs: false });
59
+ const { isFirefox } = browserDetect;
60
+
61
+ const $attrs = useAttrs();
62
+ const inputRef = ref<HTMLInputElement | null>(null);
63
+ type InputPasswordCategory = "number" | "decimal" | "mobile" | "tax-period" | "bin" | "challan-number" | string;
64
+
65
+ interface InputPasswordProps {
66
+ focus?: boolean;
67
+ must?: boolean;
68
+ err?: string | boolean;
69
+ modelValue?: string | number;
70
+ category?: InputPasswordCategory;
71
+ hood?: string | boolean | number;
72
+ readonly?: boolean;
73
+ }
74
+
75
+ const props = withDefaults(defineProps<InputPasswordProps>(), {
76
+ err: false,
77
+ modelValue: ""
78
+ });
79
+
80
+ const topclass = computed(() => ($attrs.topclass as string | undefined) || "mb-3");
81
+ const inputId = computed(() => ($attrs.id as string | undefined) || "");
82
+ const inputLabel = computed(() => ($attrs.label as string | undefined) || "");
83
+ const inputType = computed(() => ($attrs.type as string | undefined) || "text");
84
+
85
+ const max = computed<number | null>(() => {
86
+ const raw = $attrs.maxlength as string | number | undefined;
87
+ return raw != null ? Number(raw) : null;
88
+ });
89
+ const maxLengthAttr = computed<number | undefined>(() => max.value ?? undefined);
90
+
91
+ const hoodHtml = computed(() => (props.hood === false || props.hood == null ? "" : String(props.hood)));
92
+
93
+ const maxCounter = computed(() => {
94
+ if (max.value == null) {
95
+ return "";
96
+ }
97
+
98
+ if (!isFirefox && inputType.value === "month") {
99
+ return "";
100
+ }
101
+
102
+ return max.value - String(props.modelValue).length;
103
+ });
104
+
105
+ const emit = defineEmits<(event: "update:modelValue", value: string | number) => void>();
106
+ const updateModel = (e: Event) => {
107
+ const target = e.target as HTMLInputElement;
108
+
109
+ if (props.category === "number") {
110
+ emit("update:modelValue", (target.value = target.value.replace(/[^\d]/gi, "")));
111
+ } else if (props.category === "decimal") {
112
+ let val = target.value.replace(/[^\d.]/g, "");
113
+ const parts = val.split(".");
114
+ val = parts[0];
115
+ if (parts.length > 1) {
116
+ val += `.${parts.slice(1).join("")}`;
117
+ }
118
+ emit("update:modelValue", (target.value = val));
119
+ } else if (props.category === "mobile") {
120
+ let digits = target.value.replace(/[^\d]/g, ""); // only digits
121
+ let val = digits;
122
+ if (target.value.includes("+")) {
123
+ val = `+${digits}`;
124
+ }
125
+ emit("update:modelValue", (target.value = val));
126
+ } else if (props.category === "tax-period") {
127
+ let val = target.value.replace(/[^\d-]/g, ""); // Only numbers and hyphen
128
+ val = val.replace(/-/g, ""); // Remove all hyphens
129
+ val = val.slice(0, 6); // Only 6 digits (YYYYMM)
130
+
131
+ if (val.length > 4) {
132
+ let year = val.slice(0, 4);
133
+ let month = val.slice(4, 6);
134
+
135
+ // Only correct if both month digits entered
136
+ if (month.length === 2) {
137
+ let m = parseInt(month, 10);
138
+ // Clamp month between 1 and 12
139
+ if (m < 1) m = 1;
140
+ if (m > 12) m = 12;
141
+ // Always pad to 2 digits
142
+ month = m.toString().padStart(2, "0");
143
+ }
144
+
145
+ val = `${year}-${month}`;
146
+ }
147
+
148
+ emit("update:modelValue", (target.value = val));
149
+ } else if (props.category === "bin") {
150
+ let digits = target.value.replace(/[^\d]/g, "");
151
+ digits = digits.slice(0, 14);
152
+ let formatted = digits;
153
+ if (digits.length > 9) {
154
+ formatted = `${digits.slice(0, 9)}-${digits.slice(9, 14)}`;
155
+ }
156
+ emit("update:modelValue", (target.value = formatted));
157
+ } else if (props.category === "challan-number") {
158
+ let digits = target.value.replace(/[^\d]/g, "");
159
+ digits = digits.slice(0, 16);
160
+ let formatted = digits;
161
+ if (digits.length > 4) {
162
+ formatted = `${digits.slice(0, 4)}-${digits.slice(4, 16)}`;
163
+ }
164
+ emit("update:modelValue", (target.value = formatted));
165
+ } else {
166
+ emit("update:modelValue", target.value);
167
+ }
168
+ };
169
+
170
+ const showPassword = ref(false);
171
+ const togglePassword = () => (showPassword.value = !showPassword.value);
172
+
173
+ onMounted(() => {
174
+ const shouldFocus = props.focus !== false && props.focus !== undefined;
175
+ if (!shouldFocus) return;
176
+
177
+ nextTick(() => inputRef.value?.focus());
178
+ });
179
+ </script>
180
+
181
+ <style lang="scss" scoped>
182
+ input {
183
+ border-color: #cccccc;
184
+
185
+ &:read-only {
186
+ background-color: #f8f8f8;
187
+ }
188
+
189
+ &::placeholder {
190
+ color: #bfbfbf;
191
+ }
192
+ }
193
+
194
+ button:focus-visible {
195
+ border: none;
196
+ box-shadow: none;
197
+ }
198
+
199
+ .form-text {
200
+ font-size: 0.75rem;
201
+ }
202
+
203
+ .must {
204
+ width: 4px;
205
+ height: 4px;
206
+ margin-left: 2px;
207
+ margin-top: 5px;
208
+ }
209
+
210
+ .max {
211
+ font-size: 0.6rem;
212
+ }
213
+ </style>
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <Teleport to="#modal-show">
3
+ <div :id="props.id" ref="modal" class="modal fade" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
4
+ :aria-labelledby="`${props.id}Label`">
5
+ <div :class="`modal-dialog modal-dialog-centered modal-dialog-scrollable modal-${props.size}`">
6
+ <div class="modal-content border">
7
+ <div class="modal-header">
8
+ <div class="d-flex w-100 justify-content-between align-items-center">
9
+ <h5 id="modalScrollableTitle" class="modal-title me-3">{{ props.title }}</h5>
10
+ <button ref="closeButton" type="button" class="btn-close shadow-none" data-bs-dismiss="modal"
11
+ aria-label="Close"></button>
12
+ <slot name="modal-header-extra"></slot>
13
+ </div>
14
+ </div>
15
+ <div class="modal-body">
16
+ <slot name="modalbody"></slot>
17
+ </div>
18
+ <div class="modal-footer py-2">
19
+ <slot name="modalfooter"></slot>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ </Teleport>
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ import { ref } from "vue";
29
+
30
+ type ModalSize = "sm" | "md" | "lg" | "xl" | string;
31
+
32
+ interface ModalProps {
33
+ id: string;
34
+ title?: string;
35
+ size?: ModalSize;
36
+ }
37
+
38
+ defineOptions({ name: "Modal", inheritAttrs: false });
39
+
40
+ const props = withDefaults(defineProps<ModalProps>(), {
41
+ title: "",
42
+ size: "md"
43
+ });
44
+
45
+ const modal = ref<HTMLElement | null>(null);
46
+ const closeButton = ref<HTMLButtonElement | null>(null);
47
+
48
+ const close = () => {
49
+ closeButton.value?.click();
50
+ };
51
+
52
+ defineExpose({ close });
53
+ </script>
54
+
55
+ <style lang="scss" scoped></style>
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <Teleport v-if="target" :to="target">
3
+ <p v-if="props.title && !$slots.default" class="m-0 fs-4">{{ props.title }}</p>
4
+ </Teleport>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import { onMounted, ref, useSlots } from "vue";
9
+
10
+ defineOptions({ name: "PageBar", inheritAttrs: false });
11
+
12
+ interface PageBarProps {
13
+ title?: string;
14
+ }
15
+
16
+ const props = defineProps<PageBarProps>();
17
+ const slots = useSlots();
18
+
19
+ const target = ref<HTMLElement | null>(null);
20
+
21
+ onMounted(() => {
22
+ target.value = document.getElementById("pagebar");
23
+ });
24
+ </script>
25
+
26
+ <style lang="scss" scoped></style>
@@ -0,0 +1,384 @@
1
+ <script setup lang="ts">
2
+ import axios from "axios";
3
+ import { debounce } from "lodash-es";
4
+ import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, useAttrs, watch } from "vue";
5
+ import "vue-select/dist/vue-select.css";
6
+ import vSelect from "vue-select";
7
+ import { empty } from "../helpers/utils";
8
+
9
+ defineOptions({ name: "Select", inheritAttrs: false });
10
+
11
+ type AnyRecord = Record<string, unknown>;
12
+ type SelectValue = string | number | boolean | AnyRecord | null;
13
+ type OptionHook = ((value: unknown) => void | Promise<void>) | null;
14
+
15
+ interface FetchPack {
16
+ url?: string | null;
17
+ data?: string | null;
18
+ params?: AnyRecord;
19
+ mapFn?: (x: AnyRecord) => AnyRecord;
20
+ option?: ((value: unknown) => void | Promise<void>) | Array<(value: unknown) => void | Promise<void>>;
21
+ reset?: boolean;
22
+ reload?: boolean;
23
+ }
24
+
25
+ interface SelectProps {
26
+ fetched?: (payload: Record<string, any>) => any;
27
+ must?: boolean;
28
+ err?: string | boolean;
29
+ hood?: string | boolean;
30
+ defaultValue?: SelectValue;
31
+ resetKey?: string | number | boolean | AnyRecord | null;
32
+ }
33
+
34
+ const $attrs = useAttrs();
35
+ const props = withDefaults(defineProps<SelectProps>(), {
36
+ defaultValue: null,
37
+ resetKey: null
38
+ });
39
+
40
+ // vue3.4 way
41
+ const emit = defineEmits<{
42
+ (event: "fetched"): void;
43
+ (event: "clear"): void;
44
+ }>();
45
+ const model = defineModel<SelectValue | SelectValue[]>();
46
+
47
+ const skipNextSearch = ref(false); // suppress search right after clear
48
+
49
+ let observer = ref<IntersectionObserver | null>(null);
50
+ let load = ref<HTMLElement | null>(null);
51
+
52
+ // store callbacks coming from fetchedDropdown(pack)
53
+ const hooks = ref<{ option: OptionHook | OptionHook[] }>({ option: null }); // function | function[] | null
54
+
55
+ // remember last fetch config and search so the child can refetch/append by itself
56
+ const lastPack = ref<FetchPack | null>(null); // { url, data, params, mapFn }
57
+ const lastSearch = ref(""); // current search term
58
+ const lastSearchRows = ref<AnyRecord[]>([]); // results of the last search, to pin on top after clearing
59
+
60
+ const hasNextPage = computed(() => {
61
+ const total = Number((fieldData.value as { total?: number }).total ?? 0);
62
+ return field.all.length < total;
63
+ });
64
+
65
+ // ask parent for a pack and run our internal fetcher
66
+ const callParentFetched = async (search: string, opts: Partial<FetchPack> = {}) => {
67
+ const maybePack = await props.fetched?.({ search, ...opts });
68
+ if (maybePack && typeof maybePack === "object") {
69
+ await fetchedDropdown(search, { ...maybePack, ...opts });
70
+ }
71
+ };
72
+
73
+ const onClear = () => {
74
+ resetMe(); // clear options + selected value
75
+ skipNextSearch.value = true; // suppress the immediate empty search
76
+ emit("clear"); // notify parent that clear button was clicked
77
+ };
78
+
79
+ const onOpen = async () => {
80
+ // if empty, load page 1 via parent fetcher (no boolean flags)
81
+ if (!field.all.length) {
82
+ if (lastPack.value) {
83
+ await fetchedDropdown("", { ...lastPack.value, reset: true });
84
+ } else {
85
+ // await props.fetched?.('');
86
+ await callParentFetched("", { reset: true });
87
+ }
88
+ }
89
+
90
+ await nextTick();
91
+ if (load.value && hasNextPage.value) {
92
+ observer.value?.observe(load.value);
93
+ }
94
+ };
95
+
96
+ const onClose = async () => {
97
+ observer.value?.disconnect();
98
+ };
99
+
100
+ const onModelUpdate = async (val: unknown) => {
101
+ const optHooks = Array.isArray(hooks.value.option) ? hooks.value.option : hooks.value.option ? [hooks.value.option] : [];
102
+
103
+ // When user clicks × or backspaces everything, v-select sets model to null.
104
+ if (val == null || val === "") {
105
+ for (const f of optHooks) {
106
+ if (typeof f === "function") {
107
+ await Promise.resolve(f(null));
108
+ }
109
+ }
110
+ emit("clear");
111
+ return;
112
+ }
113
+
114
+ field.val = val as SelectValue;
115
+
116
+ for (const f of optHooks) {
117
+ if (typeof f === "function") {
118
+ await Promise.resolve(f(val));
119
+ }
120
+ }
121
+ };
122
+
123
+ const inputSearch = debounce(async (search: string, loading: (value: boolean) => void) => {
124
+ if (skipNextSearch.value && !search?.trim().length) {
125
+ skipNextSearch.value = false; // consume the flag
126
+ return;
127
+ }
128
+
129
+ if (search?.trim().length) {
130
+ loading(true);
131
+ if (lastPack.value) {
132
+ await fetchedDropdown(search, { ...lastPack.value, reset: true }).finally(() => loading(false));
133
+ } else {
134
+ await callParentFetched(search, { reset: true }).finally(() => loading(false));
135
+ }
136
+ } else {
137
+ // user erased the query manually: refetch the full list, then pin the last search results on top
138
+ field.page = 0;
139
+ if (lastPack.value) {
140
+ await fetchedDropdown("", { ...lastPack.value, reset: true });
141
+ } else {
142
+ await callParentFetched("");
143
+ }
144
+ pinLastSearchRows();
145
+ await nextTick();
146
+ if (load.value && hasNextPage.value) observer.value?.observe(load.value);
147
+ }
148
+ }, 400);
149
+
150
+ const infiniteScroll = async ([{ isIntersecting, target }]: IntersectionObserverEntry[]) => {
151
+ if (!isIntersecting) return;
152
+
153
+ const ul = target instanceof HTMLElement && target.offsetParent instanceof HTMLElement ? target.offsetParent : null;
154
+ const scrollTop = ul?.scrollTop ?? 0;
155
+
156
+ if (lastPack.value) {
157
+ await fetchedDropdown(lastSearch.value, { ...lastPack.value }); // next page of current mode
158
+ } else {
159
+ await callParentFetched(lastSearch.value || "");
160
+ }
161
+
162
+ await nextTick();
163
+
164
+ if (ul) ul.scrollTop = scrollTop;
165
+ };
166
+
167
+ onMounted(async () => {
168
+ observer.value = new IntersectionObserver(infiniteScroll);
169
+
170
+ // set default value if provided
171
+ if (props.defaultValue) {
172
+ await nextTick();
173
+ field.val = props.defaultValue;
174
+ model.value = props.defaultValue;
175
+ }
176
+ });
177
+
178
+ onBeforeUnmount(() => {
179
+ observer.value?.disconnect();
180
+ observer.value = null;
181
+ });
182
+
183
+ // prototype and it will call from parent
184
+ const field = reactive<{ all: AnyRecord[]; val: SelectValue; page: number; size: number }>({
185
+ all: [],
186
+ val: "",
187
+ page: 0,
188
+ size: 10
189
+ });
190
+ const fieldData = ref<AnyRecord>({});
191
+
192
+ const resetMe = () => {
193
+ field.all = [];
194
+ field.page = 0;
195
+ field.val = "";
196
+ };
197
+
198
+ const reloadMe = () => {
199
+ field.all = [];
200
+ field.page = 0;
201
+ };
202
+
203
+ const fetchedDropdown = async (search: string, pack: FetchPack | null = null) => {
204
+ const url = pack?.url ?? null;
205
+ const data = pack?.data ?? null;
206
+ const params = pack?.params ?? {};
207
+ const mapFn = pack?.mapFn ?? ((x: AnyRecord) => x);
208
+ const reset = !!pack?.reset;
209
+ const reload = !!pack?.reload;
210
+
211
+ // make option sticky: only overwrite if caller provided it
212
+ if ("option" in (pack ?? {})) {
213
+ const pOpt = pack?.option;
214
+ hooks.value.option = Array.isArray(pOpt) ? pOpt.filter((fn) => typeof fn === "function") : typeof pOpt === "function" ? [pOpt] : [];
215
+ }
216
+
217
+ // remember essentials so the child can refetch/append on its own
218
+ lastPack.value = { url, data, params, mapFn };
219
+ lastSearch.value = search ?? "";
220
+
221
+ // if pass and true -> reset, reload , search
222
+ (reset && resetMe()) || (reload && reloadMe()) || (!empty(search) && !reset && !reload && reloadMe());
223
+
224
+ // after reset/reload/search
225
+ field.page++;
226
+ const param = { page: field.page, size: field.size, search: search };
227
+
228
+ // log once (don't call axios twice)
229
+ // console.log('GET', pack.url, { params: pack.params ? { ...pack.params, ...param } : param });
230
+
231
+ if (!url || !data) {
232
+ return;
233
+ }
234
+
235
+ let key: any;
236
+ try {
237
+ key = await axios.get(url, { params: params ? { ...params, ...param } : param });
238
+ } catch {
239
+ return; // failed to fetch (e.g. cascade with missing parent)
240
+ }
241
+ const payload = key.data[data as string] as AnyRecord;
242
+
243
+ fieldData.value = payload;
244
+ const rows = Array.isArray((payload as { data?: unknown }).data) ? (payload as { data: AnyRecord[] }).data : [];
245
+
246
+ const options = rows.map((dt) => (dt == null ? null : mapFn(dt))).filter((opt): opt is AnyRecord => opt != null);
247
+
248
+ // remember the last fresh search results so they can be pinned on top after clearing the search
249
+ if (search?.trim().length && reset) {
250
+ lastSearchRows.value = options.map((opt) => ({ ...opt }));
251
+ }
252
+
253
+ // console.log('Fetched', payload?.data);
254
+ options.forEach((opt) => {
255
+ const key = opt?.id ?? opt?.title ?? JSON.stringify(opt); // build a comparison key: prefer id, then title, then full object
256
+
257
+ if (
258
+ !field.all.some(
259
+ (o) =>
260
+ o != null &&
261
+ ((o as { id?: unknown; title?: unknown }).id ?? (o as { id?: unknown; title?: unknown }).title ?? JSON.stringify(o)) === key
262
+ )
263
+ ) {
264
+ field.all = [...field.all, opt];
265
+ }
266
+ });
267
+ };
268
+
269
+ const optionKey = (o: AnyRecord) =>
270
+ (o as { id?: unknown; title?: unknown }).id ?? (o as { id?: unknown; title?: unknown }).title ?? JSON.stringify(o);
271
+
272
+ // after a refetch, move the last search results to the top of the list
273
+ const pinLastSearchRows = () => {
274
+ if (!lastSearchRows.value.length) return;
275
+ const pinKeys = new Set(lastSearchRows.value.map(optionKey));
276
+ const rest = field.all.filter((o) => !pinKeys.has(optionKey(o)));
277
+ field.all = [...lastSearchRows.value, ...rest];
278
+ };
279
+
280
+ /**
281
+ * This function created for
282
+ * functionally reset or reload
283
+ * from without component
284
+ * like fn.value.reload({reset:true/reload:true/both});
285
+ * it is exposed, so we can call from with
286
+ * template ref
287
+ */
288
+ const reload = async () => {
289
+ resetMe(); // clear field.all, page, val
290
+ await callParentFetched("", { reset: true }); // ask parent to fetch first page again
291
+ };
292
+
293
+ /**
294
+ * if backend send proper object or null
295
+ * then watch function not get any axios
296
+ * error else axios can send error
297
+ */
298
+ watch(
299
+ () => props.resetKey,
300
+ async (newVal, oldVal) => {
301
+ if (oldVal === undefined) return;
302
+
303
+ const optHooks = Array.isArray(hooks.value.option) ? hooks.value.option : hooks.value.option ? [hooks.value.option] : [];
304
+
305
+ model.value = "";
306
+
307
+ // Notify hooks that selection is gone
308
+ for (const fn of optHooks) {
309
+ if (typeof fn === "function") {
310
+ await Promise.resolve(fn(null));
311
+ }
312
+ }
313
+
314
+ skipNextSearch.value = true; // avoid instant empty-search call
315
+ if (newVal == null) {
316
+ lastPack.value = null;
317
+ return;
318
+ } // parent cleared, don't fetch with null key
319
+ await callParentFetched("", { reload: true });
320
+ pinLastSearchRows();
321
+ skipNextSearch.value = false; // allow subsequent empty-searches (backspace-to-empty)
322
+ }
323
+ );
324
+
325
+ defineExpose({ field, fieldData, fetchedDropdown, reload });
326
+
327
+ const parentClass = computed(() => ($attrs.parentclass as string | undefined) || "mb-2");
328
+
329
+ const inputTitle = computed(() => ($attrs.title as string | undefined) || "");
330
+ const hoodHtml = computed(() => (props.hood === false || props.hood == null ? "" : String(props.hood)));
331
+ </script>
332
+
333
+ <template>
334
+ <div :class="parentClass">
335
+ <label
336
+ class="text-capitalize d-flex align-items-center mb-1"
337
+ :class="{ 'd-none': !inputTitle }">
338
+ <div class="position-relative">
339
+ <span class="text-capitalize" v-html="inputTitle"></span>
340
+ <span
341
+ class="position-absolute text-danger rounded-circle bg-danger must"
342
+ :class="{ 'd-none': !props.must }"></span>
343
+ </div>
344
+ <div
345
+ class="text-uppercase w-100 text-end text-primary fw-semibold"
346
+ :class="{ 'd-none': !props.hood }"
347
+ style="font-size: 12px; margin-top: 0.15rem"
348
+ v-html="hoodHtml"></div>
349
+ </label>
350
+ <v-select
351
+ v-model="model"
352
+ label="title"
353
+ :filterable="false"
354
+ :options="field.all"
355
+ v-bind="$attrs"
356
+ @open="onOpen"
357
+ @update:model-value="onModelUpdate"
358
+ @close="onClose"
359
+ @search="inputSearch"
360
+ @clear="onClear">
361
+ <template #list-footer>
362
+ <li v-show="hasNextPage" ref="load" class="loader">More...</li>
363
+ </template>
364
+ </v-select>
365
+ <div class="form-text text-danger" :class="{ 'd-none': !props.err }" style="font-size: 0.8rem">
366
+ {{ props.err }}
367
+ </div>
368
+ </div>
369
+ </template>
370
+
371
+ <style lang="scss" scoped>
372
+ .loader {
373
+ text-align: center;
374
+ color: #bbbbbb;
375
+ }
376
+
377
+ .must {
378
+ width: 4px;
379
+ height: 4px;
380
+ top: 0;
381
+ margin-top: 5px;
382
+ margin-left: 2px;
383
+ }
384
+ </style>