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,379 @@
1
+ /**
2
+ * Why: Detects the package manager used to run the CLI, for help usage text.
3
+ * When: Building the program name shown in the "Usage:" line.
4
+ * Where: Maker CLI entry flow.
5
+ * How: Reads npm config user-agent and maps to the corresponding prefix string.
6
+ */
7
+ export function makerCommandPrefix() {
8
+ const ua = String(process.env.npm_config_user_agent || "").toLowerCase();
9
+ if (ua.startsWith("pnpm/")) return "pnpm";
10
+ if (ua.startsWith("yarn/")) return "yarn";
11
+ if (ua.startsWith("bun/")) return "bun";
12
+ if (ua.startsWith("npm/")) return "npm run";
13
+ return "";
14
+ }
15
+
16
+ /**
17
+ * Why: Overrides Commander's help so the subcommand listing shows the actual
18
+ * long flags (e.g. `--app-only|--server-only|--dev`) instead of a generic
19
+ * `[options]` marker.
20
+ * When: Building the CLI program before commands are registered.
21
+ * Where: Maker CLI entry flow.
22
+ * How: Injects a custom `subcommandTerm` via `configureHelp`.
23
+ */
24
+ export function configureDeployHelp(program) {
25
+ program.configureHelp({
26
+ subcommandTerm(cmd) {
27
+ const flags = cmd.options
28
+ .map((option) => option.flags.split(" ")[0])
29
+ .filter((flag) => flag.startsWith("--"))
30
+ .join("|");
31
+ const args = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" ");
32
+ return cmd.name() + (flags ? ` [${flags}]` : "") + (args ? ` ${args}` : "");
33
+ }
34
+ });
35
+ }
36
+
37
+ function humanReadableArgName(arg) {
38
+ const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
39
+ return arg.required ? `<${nameOutput}>` : `[${nameOutput}]`;
40
+ }
41
+
42
+ /**
43
+ * Why: Shows commander-generated help for the maker CLI program.
44
+ * When: CLI runs without a valid command.
45
+ * Where: Maker CLI entry flow and error handlers.
46
+ * How: Delegates to commander's outputHelp for consistent automatically-synced output.
47
+ */
48
+ export function showHelp(program) {
49
+ program.outputHelp();
50
+ }
51
+
52
+ /**
53
+ * Marks a command as coming from the project's own maker/commands.mjs, so the
54
+ * help screen can put it beside `maker:init` instead of in the fallback section.
55
+ * Set by registerProjectCommands, read by groupCommands below.
56
+ */
57
+ export const PROJECT_COMMAND_FLAG = "makerProjectCommand";
58
+
59
+ /** Where a command nobody classified ends up. Better labelled than missing. */
60
+ export const FALLBACK_GROUP_TITLE = "Other commands";
61
+
62
+ /**
63
+ * Why: Groups the top-level command list so a developer can find a command by
64
+ * the question they are asking rather than by scrolling 57 flat lines.
65
+ * When: `maker --help`, and the help commander prints for an unknown command.
66
+ * Where: Maker CLI help rendering, applied by configureGroupedHelp.
67
+ * How: Explicit name lists rather than prefix patterns. A `module:make-*`
68
+ * pattern would also swallow `module:migrate` and `module:make-notification`
69
+ * into the generators section, and a command filed under the wrong heading
70
+ * is worse than an extra line of configuration here. The cost is that a new
71
+ * command must be added here too - which is the intent, because
72
+ * __tests__/help.test.ts fails when it is not, so nothing can be quietly
73
+ * dropped from the screen.
74
+ *
75
+ * Names only, no argument or option markers. Commander's default listing
76
+ * prints `[options] <module> <name>`, which pushed the description column
77
+ * to 47 characters and left almost no room to say what anything did. That
78
+ * detail is still one command away: `maker <command> --help`.
79
+ */
80
+ const COMMAND_GROUPS = [
81
+ {
82
+ title: "Getting started",
83
+ commands: ["dev", "serve", "ui:dev", "admin:dev", "maildev:view", "redis:view", "vite:cache:clear"]
84
+ },
85
+ {
86
+ title: "Generators - global",
87
+ // Deliberately separated from the module generators. `middleware:make`
88
+ // writes to src/middlewares and applies to the whole app;
89
+ // `module:make-middleware` writes inside one module and applies only to it.
90
+ // In the same section the two look interchangeable, which is exactly the
91
+ // mistake a developer is about to make.
92
+ //
93
+ // `provider:make` follows the same split: it writes to src/providers and
94
+ // applies to the whole app, `module:make-provider` writes inside one
95
+ // module and applies only to it.
96
+ commands: ["middleware:make", "provider:make"]
97
+ },
98
+ {
99
+ title: "Generators - modules",
100
+ commands: [
101
+ "module:make",
102
+ "module:make-notification",
103
+ "module:make-model",
104
+ "module:make-schema",
105
+ "module:make-service",
106
+ "module:make-controller",
107
+ "module:make-route",
108
+ "module:make-job",
109
+ "module:make-console",
110
+ "module:make-seeder",
111
+ "module:make-test",
112
+ "module:make-helper",
113
+ "module:make-middleware",
114
+ "module:make-provider",
115
+ "module:make-type"
116
+ ]
117
+ },
118
+ {
119
+ title: "Modules - manage",
120
+ commands: [
121
+ "module:list",
122
+ "module:seed",
123
+ "module:migrate",
124
+ "module:delete",
125
+ "module:delete-notification",
126
+ "module:trash:clean"
127
+ ]
128
+ },
129
+ {
130
+ title: "Database",
131
+ commands: [
132
+ "db",
133
+ "db:schema",
134
+ "db:generate",
135
+ "db:migrate",
136
+ "db:migrate:run",
137
+ "db:migrate:reset",
138
+ "db:fresh",
139
+ "db:seed",
140
+ "db:module:seed",
141
+ "db:status",
142
+ "db:push",
143
+ "db:check",
144
+ "db:studio",
145
+ "db:reset",
146
+ "db:wipe"
147
+ ]
148
+ },
149
+ {
150
+ title: "Queue and scheduler",
151
+ commands: ["queue:work", "queue:clear", "schedule:work"]
152
+ },
153
+ {
154
+ title: "Deploy",
155
+ commands: [
156
+ "deploy:init",
157
+ "deploy:db:import",
158
+ "deploy:db:import:remote",
159
+ "deploy:workflow",
160
+ "deploy:workflow:remote",
161
+ "deploy:workflow:promote"
162
+ ]
163
+ },
164
+ {
165
+ title: "Testing",
166
+ commands: ["test", "test:watch", "test:coverage", "test:ui"]
167
+ },
168
+ {
169
+ title: "Your commands",
170
+ commands: ["maker:init"],
171
+ includeProjectCommands: true
172
+ }
173
+ ];
174
+
175
+ /** Widest name column before descriptions start on their own space anyway. */
176
+ const MAX_TERM_WIDTH = 30;
177
+ const MIN_DESCRIPTION_WIDTH = 28;
178
+
179
+ /**
180
+ * Why: Sorts commands into their display sections.
181
+ * When: Rendering `maker --help`, and asserted directly by the tests.
182
+ * Where: Maker CLI help rendering.
183
+ * How: Walks COMMAND_GROUPS in declared order and claims each named command.
184
+ * Anything left over goes to a fallback section rather than disappearing,
185
+ * so a newly added command is visible even in the moment before anyone
186
+ * decides where it belongs.
187
+ */
188
+ export function groupCommands(commands) {
189
+ const visible = commands.filter((command) => !command._hidden);
190
+ const claimed = new Set();
191
+ const groups = [];
192
+
193
+ for (const group of COMMAND_GROUPS) {
194
+ const members = [];
195
+
196
+ for (const name of group.commands) {
197
+ const command = visible.find((candidate) => candidate.name() === name && !claimed.has(name));
198
+ if (command) {
199
+ members.push(command);
200
+ claimed.add(name);
201
+ }
202
+ }
203
+
204
+ if (group.includeProjectCommands) {
205
+ for (const command of visible) {
206
+ if (command[PROJECT_COMMAND_FLAG] && !claimed.has(command.name())) {
207
+ members.push(command);
208
+ claimed.add(command.name());
209
+ }
210
+ }
211
+ }
212
+
213
+ if (members.length > 0) {
214
+ groups.push({ title: group.title, commands: members });
215
+ }
216
+ }
217
+
218
+ const leftovers = visible.filter((command) => !claimed.has(command.name()));
219
+ if (leftovers.length > 0) {
220
+ groups.push({ title: FALLBACK_GROUP_TITLE, commands: leftovers });
221
+ }
222
+
223
+ return groups;
224
+ }
225
+
226
+ /**
227
+ * Why: The plain-text header, and the ASCII wordmark used when there is room.
228
+ * When: Rendering the top of `maker --help`.
229
+ * Where: Maker CLI help rendering.
230
+ * How: The wordmark is a fixed literal. figlet was used to design it offline and
231
+ * is deliberately not a dependency: the CLI runs from source inside the
232
+ * user's project, so a runtime figlet would mean every scaffolded project
233
+ * installs it purely to print five fixed lines. Nothing is computed here.
234
+ *
235
+ * Three rules keep it from getting in the developer's way, which is the
236
+ * only thing a banner has to be careful about:
237
+ *
238
+ * 1. A terminal narrower than the art gets plain text, because art that
239
+ * overflows wraps into an unreadable mess.
240
+ * 2. Piped output gets plain text. Nobody asked for a wordmark at the top
241
+ * of their log file, and `maker > out.txt` should stay readable.
242
+ * 3. Per-command help gets no banner at all - see configureGroupedHelp.
243
+ */
244
+ const NEXWIRE_WORDMARK = [
245
+ " _",
246
+ " ____ ___ _ ___ __(_)_______",
247
+ " / __ \\/ _ \\| |/_/ | /| / / / ___/ _ \\",
248
+ " / / / / __/> < | |/ |/ / / / / __/",
249
+ "/_/ /_/\\___/_/|_| |__/|__/_/_/ \\___/"
250
+ ];
251
+
252
+ const PLAIN_HEADER = "nexwire maker";
253
+
254
+ /** Widest wordmark line, measured from the literal above. */
255
+ const WORDMARK_WIDTH = Math.max(...NEXWIRE_WORDMARK.map((line) => line.length));
256
+
257
+ /** Two columns of breathing room, so the art never touches the window edge. */
258
+ const MINIMUM_TERMINAL_WIDTH = WORDMARK_WIDTH + 2;
259
+
260
+ export function makerBanner(stream = process.stdout) {
261
+ if (!stream.isTTY) return PLAIN_HEADER;
262
+ if ((stream.columns || 80) < MINIMUM_TERMINAL_WIDTH) return PLAIN_HEADER;
263
+ return NEXWIRE_WORDMARK.join("\n");
264
+ }
265
+
266
+ /**
267
+ * Why: Replaces the top-level help screen with the grouped one.
268
+ * When: Once, while building the program, before anything prints help.
269
+ * Where: Maker CLI entry flow, alongside the other program configuration.
270
+ * How: Overrides commander's formatHelp and rebuilds the screen from the
271
+ * documented Help helpers (commandUsage, visibleOptions, subcommandTerm).
272
+ * Deliberately not string surgery on commander's output: that would depend
273
+ * on the exact shape of its "Commands:" heading and break on a version bump.
274
+ * Per-command help is left to commander, so `maker <command> --help` is
275
+ * unchanged and carries no wordmark.
276
+ */
277
+ export function configureGroupedHelp(program, { stream = process.stdout } = {}) {
278
+ program.configureHelp({
279
+ formatHelp(cmd, helper) {
280
+ const width = helper.helpWidth || stream.columns || 100;
281
+ // commandUsage returns the bare "maker [options] [command]"; the heading
282
+ // word is styled separately by commander and is not part of that string.
283
+ const blocks = [];
284
+
285
+ // cmd.parent is null only for the top-level program, which is what makes
286
+ // the wordmark an overview-only flourish rather than something on screen
287
+ // every time someone checks a flag.
288
+ if (!cmd.parent) blocks.push(makerBanner(stream));
289
+
290
+ blocks.push(`Usage: ${helper.commandUsage(cmd)}`);
291
+
292
+ const description = helper.commandDescription(cmd);
293
+ if (description) blocks.push(description);
294
+
295
+ const options = helper.visibleOptions(cmd);
296
+ if (options.length > 0) {
297
+ blocks.push(renderTable("Options", options.map((option) => [helper.optionTerm(option), helper.optionDescription(option)]), width));
298
+ }
299
+
300
+ const argumentsList = helper.visibleArguments(cmd);
301
+ if (argumentsList.length > 0) {
302
+ blocks.push(
303
+ renderTable(
304
+ "Arguments",
305
+ argumentsList.map((argument) => [helper.argumentTerm(argument), helper.argumentDescription(argument)]),
306
+ width
307
+ )
308
+ );
309
+ }
310
+
311
+ for (const group of groupCommands(cmd.commands)) {
312
+ blocks.push(
313
+ renderTable(
314
+ group.title,
315
+ group.commands.map((command) => [command.name(), helper.subcommandDescription(command)]),
316
+ width
317
+ )
318
+ );
319
+ }
320
+
321
+ // Commander adds its own `help [command]` lazily, after this formatter has
322
+ // already run, so the command is working but cannot be listed here. Rather
323
+ // than drop it silently, name both spellings in the footer - and prefer
324
+ // that to a heading containing one leftover entry, which reads as a
325
+ // mistake. __tests__/help.test.ts asserts `maker help <command>` works.
326
+ blocks.push("Run `maker <command> --help`, or `maker help <command>`, for the options and arguments of one command.");
327
+
328
+ return `${blocks.join("\n\n")}\n`;
329
+ }
330
+ });
331
+ }
332
+
333
+ /** Renders one `Heading:` block of `name description` rows. Exported for tests. */
334
+ export function renderTable(heading, rows, width) {
335
+ const termWidth = Math.min(MAX_TERM_WIDTH, Math.max(0, ...rows.map(([term]) => term.length)));
336
+ const descriptionWidth = Math.max(MIN_DESCRIPTION_WIDTH, width - termWidth - 4);
337
+
338
+ const lines = [`${heading}:`];
339
+
340
+ for (const [term, description] of rows) {
341
+ const gap = Math.max(2, termWidth - term.length + 2);
342
+ // A continuation line must start where the description started, not at the
343
+ // left edge. That column is 2 (indent) + termWidth (widest term) + gap.
344
+ const descriptionColumn = 2 + termWidth + gap;
345
+ const indent = " ".repeat(descriptionColumn);
346
+
347
+ if (!description) {
348
+ lines.push(` ${term}`);
349
+ continue;
350
+ }
351
+
352
+ const wrapped = wrapText(description, descriptionWidth);
353
+ lines.push(` ${term}${" ".repeat(gap)}${wrapped[0]}`);
354
+ for (const line of wrapped.slice(1)) lines.push(`${indent}${line}`);
355
+ }
356
+
357
+ return lines.join("\n");
358
+ }
359
+
360
+ /** Greedy word wrap. Keeps a long description readable instead of one huge line. */
361
+ function wrapText(text, width) {
362
+ const words = String(text).split(/\s+/).filter(Boolean);
363
+ if (words.length === 0) return [""];
364
+
365
+ const lines = [];
366
+ let line = "";
367
+
368
+ for (const word of words) {
369
+ if (line === "") line = word;
370
+ else if (line.length + 1 + word.length <= width) line += ` ${word}`;
371
+ else {
372
+ lines.push(line);
373
+ line = word;
374
+ }
375
+ }
376
+ if (line !== "") lines.push(line);
377
+
378
+ return lines;
379
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Name handling for the generators.
3
+ *
4
+ * A developer may type a name in any common casing: `game-config`,
5
+ * `game_config`, `gameConfig` or `GameConfig`. All of them must resolve to the
6
+ * same thing, because a generator writes the name into four different places
7
+ * that each need a different shape:
8
+ *
9
+ * file name game-config.ts kebab
10
+ * SQL table game_configs snake
11
+ * identifier gameConfigs camel
12
+ * class name GameConfigSeeder pascal
13
+ *
14
+ * `normalizeName` produces the single canonical form (kebab). The other three
15
+ * are derived from it. This has to happen *before* lowercasing, because
16
+ * lowercasing `gameConfig` to `gameconfig` destroys the word boundary and no
17
+ * later step can recover it.
18
+ */
19
+
20
+ /**
21
+ * A name is safe when it can be used as a folder name, a URL segment, a table
22
+ * name and a TypeScript identifier without further quoting.
23
+ *
24
+ * Kebab-case, snake_case, camelCase and PascalCase all pass: they are folded
25
+ * to one canonical kebab form first. What fails is anything that would produce
26
+ * uncompilable code - spaces and dots break the generated `@/modules/...`
27
+ * import, a leading digit breaks the identifier.
28
+ */
29
+ const RAW_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;
30
+
31
+ /**
32
+ * Fold any accepted casing to canonical kebab-case.
33
+ *
34
+ * `gameConfig` and `GameConfig` split on the lowercase/uppercase boundary;
35
+ * `game_config` splits on the underscore; repeated separators collapse to one
36
+ * dash. An all-caps run such as `GAMECONFIG` carries no boundary information
37
+ * and is deliberately kept as the single word `gameconfig`.
38
+ */
39
+ export function normalizeName(value) {
40
+ return String(value)
41
+ .trim()
42
+ .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
43
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2")
44
+ .replace(/[^A-Za-z0-9]+/g, "-")
45
+ .replace(/-{2,}/g, "-")
46
+ .replace(/^-+|-+$/g, "")
47
+ .toLowerCase();
48
+ }
49
+
50
+ /** Convert a kebab-case or camelCase string to snake_case (the SQL table name). */
51
+ export function snakeCase(input) {
52
+ return String(input)
53
+ .trim()
54
+ .replace(/[^A-Za-z0-9]+/g, "_")
55
+ .replace(/_{2,}/g, "_")
56
+ .replace(/^_+|_+$/g, "")
57
+ .toLowerCase();
58
+ }
59
+
60
+ /**
61
+ * Pluralise an identifier for a table/collection name.
62
+ *
63
+ * Deliberately minimal: consonant + `y` becomes `ies` (so `auditEntry` yields
64
+ * `auditEntries`, matching the export a developer would hand-write), anything
65
+ * else takes a plain `s`. A word that already ends in `s` is returned
66
+ * unchanged so the helper is idempotent. English irregulars (`person` ->
67
+ * `people`) are not modelled; correct those by hand after generating.
68
+ */
69
+ export function plural(word) {
70
+ const value = String(word);
71
+ if (!value) return value;
72
+ if (/[^aeiou]y$/i.test(value)) return `${value.slice(0, -1)}ies`;
73
+ if (/s$/i.test(value)) return value;
74
+ return `${value}s`;
75
+ }
76
+
77
+ /**
78
+ * Best-effort readable repair of a rejected name, used only in error text.
79
+ * Returns "" when no safe suggestion exists (e.g., a leading digit cannot be
80
+ * reordered without guessing the developer's intent).
81
+ */
82
+ function suggestName(value) {
83
+ const cleaned = normalizeName(value);
84
+ if (!cleaned || !/^[a-z]/.test(cleaned)) return "";
85
+ return cleaned;
86
+ }
87
+
88
+ /**
89
+ * Validate a name value exists and is safe to use, and return its canonical
90
+ * form so every generator writes the same name to disk.
91
+ * Throws with the exact command to run instead when the value is unusable.
92
+ */
93
+ export function assertName(value, label) {
94
+ if (!value) {
95
+ throw new Error(`${label} is required.`);
96
+ }
97
+
98
+ const trimmed = value.trim();
99
+ if (!RAW_PATTERN.test(trimmed)) {
100
+ const suggestion = suggestName(value);
101
+ const reason = /^[0-9]/.test(trimmed)
102
+ ? "must start with a lowercase letter"
103
+ : "may only contain lowercase letters, numbers, dashes and underscores";
104
+ throw new Error(`Invalid ${label.toLowerCase()}: "${value}" - a name ${reason}.${suggestion ? ` Use "${suggestion}" instead.` : ""}`);
105
+ }
106
+
107
+ return normalizeName(trimmed);
108
+ }
109
+
110
+ /** Convert a kebab-case or snake_case string to PascalCase. */
111
+ export function pascal(input) {
112
+ return input.replace(/(^\w|[-_]\w)/g, (part) => part.replace(/[-_]/g, "").toUpperCase());
113
+ }
114
+
115
+ /** Convert a kebab-case or snake_case string to camelCase. */
116
+ export function camelCase(input) {
117
+ const p = pascal(input);
118
+ return p.charAt(0).toLowerCase() + p.slice(1);
119
+ }
@@ -0,0 +1,52 @@
1
+ import { spawn } from "node:child_process";
2
+ import fsSync from "node:fs";
3
+ import path from "node:path";
4
+
5
+ /** Run a Node.js script as a child process using the current Node executable. */
6
+ export async function runNodeScript(script, args = [], options = {}) {
7
+ await new Promise((resolve, reject) => {
8
+ const child = spawn(process.execPath, [script, ...args], {
9
+ stdio: options.silent ? "ignore" : "inherit"
10
+ });
11
+ child.on("exit", (code) => (code === 0 ? resolve() : reject(new Error(`${script} ${args.join(" ")} failed with code ${code}`))));
12
+ child.on("error", reject);
13
+ });
14
+ }
15
+
16
+ /** Resolve the path to a script inside a package in node_modules. */
17
+ export function packageScript(packageName, scriptPath) {
18
+ return path.resolve(process.cwd(), "node_modules", packageName, scriptPath);
19
+ }
20
+
21
+ /** Find a local .bin executable (handles OS extensions like .cmd on Windows). */
22
+ export function localBin(name) {
23
+ const extensions = process.platform === "win32" ? [".cmd", ".exe", ".ps1", ""] : [""];
24
+
25
+ for (const extension of extensions) {
26
+ const candidate = path.resolve(process.cwd(), "node_modules", ".bin", `${name}${extension}`);
27
+ if (fsSync.existsSync(candidate)) return candidate;
28
+ }
29
+
30
+ throw new Error(`Missing local binary: ${name}. Install project dependencies first.`);
31
+ }
32
+
33
+ /** Run an arbitrary command as a child process. Uses shell mode for Windows scripts. */
34
+ export async function runCommand(commandName, commandArgs = [], options = {}) {
35
+ await new Promise((resolve, reject) => {
36
+ const isWindowsScript = process.platform === "win32" && /\.(cmd|ps1)$/i.test(commandName);
37
+ const child = isWindowsScript
38
+ ? spawn([commandName, ...commandArgs].map((part) => (/\s/.test(part) ? `"${part.replace(/"/g, '\\"')}"` : part)).join(" "), {
39
+ shell: true,
40
+ stdio: options.silent ? "ignore" : "inherit"
41
+ })
42
+ : spawn(commandName, commandArgs, {
43
+ shell: false,
44
+ stdio: options.silent ? "ignore" : "inherit"
45
+ });
46
+
47
+ child.on("exit", (code) =>
48
+ code === 0 ? resolve() : reject(new Error(`${commandName} ${commandArgs.join(" ")} failed with code ${code}`))
49
+ );
50
+ child.on("error", reject);
51
+ });
52
+ }