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.
- package/README.md +233 -0
- package/express/.dockerignore +14 -0
- package/express/.env +44 -0
- package/express/.env.example +42 -0
- package/express/.vscode/settings.json +26 -0
- package/express/LICENSE +21 -0
- package/express/README.md +211 -0
- package/express/biome.json +66 -0
- package/express/drizzle.config.ts +25 -0
- package/express/gitignore-stub +24 -0
- package/express/package.json +108 -0
- package/express/public/.gitkeep +0 -0
- package/express/src/config/app.ts +41 -0
- package/express/src/config/auth.ts +12 -0
- package/express/src/config/cache.ts +16 -0
- package/express/src/config/cookie.ts +15 -0
- package/express/src/config/cors.ts +12 -0
- package/express/src/config/database.ts +29 -0
- package/express/src/config/index.ts +83 -0
- package/express/src/config/jwt.ts +19 -0
- package/express/src/config/logging.ts +13 -0
- package/express/src/config/mail.ts +24 -0
- package/express/src/config/openapi.ts +54 -0
- package/express/src/config/queue.ts +30 -0
- package/express/src/config/rateLimit.ts +17 -0
- package/express/src/config/realtime.ts +15 -0
- package/express/src/config/redis.ts +18 -0
- package/express/src/config/security.ts +44 -0
- package/express/src/config/session.ts +17 -0
- package/express/src/config/storage.ts +22 -0
- package/express/src/config/validate.ts +40 -0
- package/express/src/database/migrations/sqlite/0000_init.sql +61 -0
- package/express/src/database/migrations/sqlite/meta/0000_snapshot.json +412 -0
- package/express/src/database/migrations/sqlite/meta/_journal.json +13 -0
- package/express/src/database/schema.ts +3 -0
- package/express/src/env.ts +76 -0
- package/express/src/framework/cache/cache.ts +81 -0
- package/express/src/framework/circuit-breaker/cb.ts +60 -0
- package/express/src/framework/database/connection.ts +196 -0
- package/express/src/framework/database/migrate-hooks.ts +87 -0
- package/express/src/framework/database/paginate.ts +227 -0
- package/express/src/framework/database/schema.ts +20 -0
- package/express/src/framework/database/seed.ts +139 -0
- package/express/src/framework/events/dispatcher.ts +49 -0
- package/express/src/framework/facade.ts +48 -0
- package/express/src/framework/http/app.ts +107 -0
- package/express/src/framework/http/cors.ts +7 -0
- package/express/src/framework/http/logger.ts +69 -0
- package/express/src/framework/http/metrics.ts +22 -0
- package/express/src/framework/http/openapi.ts +54 -0
- package/express/src/framework/http/ratelimiter.ts +16 -0
- package/express/src/framework/http/router.ts +178 -0
- package/express/src/framework/http/security.ts +23 -0
- package/express/src/framework/http/static.ts +23 -0
- package/express/src/framework/http/validation.ts +18 -0
- package/express/src/framework/kernel.ts +52 -0
- package/express/src/framework/maker-cli/db/core.mjs +288 -0
- package/express/src/framework/maker-cli/db/index.mjs +204 -0
- package/express/src/framework/maker-cli/deploy/core.mjs +1047 -0
- package/express/src/framework/maker-cli/deploy/index.mjs +91 -0
- package/express/src/framework/maker-cli/index.mjs +53 -0
- package/express/src/framework/maker-cli/middleware/core.mjs +47 -0
- package/express/src/framework/maker-cli/middleware/index.mjs +17 -0
- package/express/src/framework/maker-cli/module/core.mjs +684 -0
- package/express/src/framework/maker-cli/module/index.mjs +140 -0
- package/express/src/framework/maker-cli/runtime/build-ui.mjs +16 -0
- package/express/src/framework/maker-cli/runtime/core.mjs +543 -0
- package/express/src/framework/maker-cli/runtime/index.mjs +104 -0
- package/express/src/framework/maker-cli/runtime/redis-commander-patch.cjs +20 -0
- package/express/src/framework/maker-cli/stubs/controller/openapi.ts.stub +47 -0
- package/express/src/framework/maker-cli/stubs/controller/openapi.with-model.ts.stub +48 -0
- package/express/src/framework/maker-cli/stubs/controller/plain.ts.stub +54 -0
- package/express/src/framework/maker-cli/stubs/controller/schema.plain.ts.stub +14 -0
- package/express/src/framework/maker-cli/stubs/controller/schema.ts.stub +33 -0
- package/express/src/framework/maker-cli/stubs/deploy/Dockerfile.bun.stub +52 -0
- package/express/src/framework/maker-cli/stubs/deploy/Dockerfile.pnpm.stub +55 -0
- package/express/src/framework/maker-cli/stubs/deploy/Dockerfile.stub +51 -0
- package/express/src/framework/maker-cli/stubs/deploy/Dockerfile.yarn.stub +55 -0
- package/express/src/framework/maker-cli/stubs/deploy/README.stub +59 -0
- package/express/src/framework/maker-cli/stubs/deploy/compose/mysql.server.stub +45 -0
- package/express/src/framework/maker-cli/stubs/deploy/compose/postgres.server.stub +45 -0
- package/express/src/framework/maker-cli/stubs/deploy/compose/sqlite.stub +45 -0
- package/express/src/framework/maker-cli/stubs/deploy/env/mysql.server.stub +68 -0
- package/express/src/framework/maker-cli/stubs/deploy/env/postgres.server.stub +68 -0
- package/express/src/framework/maker-cli/stubs/deploy/env/sqlite.stub +67 -0
- package/express/src/framework/maker-cli/stubs/deploy/scripts/auto-migrate.sh.stub +41 -0
- package/express/src/framework/maker-cli/stubs/deploy/server/README.stub +78 -0
- package/express/src/framework/maker-cli/stubs/deploy/server/compose/noredis.stub +120 -0
- package/express/src/framework/maker-cli/stubs/deploy/server/compose/redis.dev.stub +133 -0
- package/express/src/framework/maker-cli/stubs/deploy/server/compose/redis.stub +131 -0
- package/express/src/framework/maker-cli/stubs/deploy/server/env/local.example.stub +11 -0
- package/express/src/framework/maker-cli/stubs/deploy/server/env/noredis.stub +25 -0
- package/express/src/framework/maker-cli/stubs/deploy/server/env/redis.stub +25 -0
- package/express/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/README.stub +16 -0
- package/express/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/app.example.com.stub +13 -0
- package/express/src/framework/maker-cli/stubs/deploy/server/pgadmin/servers.stub +14 -0
- package/express/src/framework/maker-cli/stubs/deploy/server/redis/redis.conf.stub +7 -0
- package/express/src/framework/maker-cli/stubs/deploy/supervisor/noredis.stub +54 -0
- package/express/src/framework/maker-cli/stubs/deploy/supervisor/redis.stub +70 -0
- package/express/src/framework/maker-cli/stubs/deploy/workflow/local.json.stub +25 -0
- package/express/src/framework/maker-cli/stubs/deploy/workflow/remote.json.stub +24 -0
- package/express/src/framework/maker-cli/stubs/example/console.ts.stub +34 -0
- package/express/src/framework/maker-cli/stubs/example/controller.ts.stub +418 -0
- package/express/src/framework/maker-cli/stubs/example/job.ts.stub +75 -0
- package/express/src/framework/maker-cli/stubs/example/route.api.ts.stub +207 -0
- package/express/src/framework/maker-cli/stubs/example/route.plain.ts.stub +18 -0
- package/express/src/framework/maker-cli/stubs/example/schema.plain.ts.stub +42 -0
- package/express/src/framework/maker-cli/stubs/example/schema.ts.stub +42 -0
- package/express/src/framework/maker-cli/stubs/job/name.ts.stub +25 -0
- package/express/src/framework/maker-cli/stubs/middleware/name.ts.stub +14 -0
- package/express/src/framework/maker-cli/stubs/model/name.mysql.ts.stub +9 -0
- package/express/src/framework/maker-cli/stubs/model/name.postgresql.ts.stub +9 -0
- package/express/src/framework/maker-cli/stubs/model/name.sqlite.ts.stub +9 -0
- package/express/src/framework/maker-cli/stubs/notification/controller.ts.stub +77 -0
- package/express/src/framework/maker-cli/stubs/notification/job.ts.stub +13 -0
- package/express/src/framework/maker-cli/stubs/notification/route.api.ts.stub +50 -0
- package/express/src/framework/maker-cli/stubs/notification/route.plain.ts.stub +12 -0
- package/express/src/framework/maker-cli/stubs/notification/schema.plain.ts.stub +26 -0
- package/express/src/framework/maker-cli/stubs/notification/schema.ts.stub +26 -0
- package/express/src/framework/maker-cli/stubs/route/api.ts.stub +80 -0
- package/express/src/framework/maker-cli/stubs/route/plain.ts.stub +11 -0
- package/express/src/framework/maker-cli/stubs/schedule/name.ts.stub +36 -0
- package/express/src/framework/maker-cli/stubs/seeder/name.ts.stub +20 -0
- package/express/src/framework/maker-cli/stubs/test/unit.ts.stub +22 -0
- package/express/src/framework/maker-cli/utils/env-config.mjs +44 -0
- package/express/src/framework/maker-cli/utils/env-db.mjs +61 -0
- package/express/src/framework/maker-cli/utils/file-ops.mjs +30 -0
- package/express/src/framework/maker-cli/utils/flags.mjs +14 -0
- package/express/src/framework/maker-cli/utils/help.mjs +50 -0
- package/express/src/framework/maker-cli/utils/naming.mjs +13 -0
- package/express/src/framework/maker-cli/utils/process.mjs +52 -0
- package/express/src/framework/modules/discover.ts +54 -0
- package/express/src/framework/modules/routes.ts +21 -0
- package/express/src/framework/notification/index.ts +116 -0
- package/express/src/framework/queue/clear.ts +22 -0
- package/express/src/framework/queue/queue.ts +342 -0
- package/express/src/framework/queue/ui.ts +187 -0
- package/express/src/framework/queue/worker.ts +61 -0
- package/express/src/framework/realtime/broadcast.ts +46 -0
- package/express/src/framework/realtime/index.ts +2 -0
- package/express/src/framework/realtime/socket-cookie.ts +71 -0
- package/express/src/framework/realtime/socket.ts +119 -0
- package/express/src/framework/realtime/types.ts +6 -0
- package/express/src/framework/realtime/ui.ts +16 -0
- package/express/src/framework/redis/client.ts +151 -0
- package/express/src/framework/runtime/runtime.ts +23 -0
- package/express/src/framework/runtime/server-adapter.ts +34 -0
- package/express/src/framework/scheduler/lock.ts +116 -0
- package/express/src/framework/scheduler/run.ts +48 -0
- package/express/src/framework/scheduler/scheduler.ts +155 -0
- package/express/src/framework/server.ts +177 -0
- package/express/src/framework/session/session.ts +98 -0
- package/express/src/framework/storage/storage.ts +785 -0
- package/express/src/framework/support/cookie.ts +62 -0
- package/express/src/framework/support/jwt.ts +33 -0
- package/express/src/framework/support/lifecycle.ts +35 -0
- package/express/src/framework/support/logger.ts +148 -0
- package/express/src/framework/support/mail.ts +48 -0
- package/express/src/framework/support/password.ts +23 -0
- package/express/src/framework/support/upload.ts +160 -0
- package/express/src/framework/support/url.ts +41 -0
- package/express/src/middlewares/auth-middleware.ts +98 -0
- package/express/src/middlewares/role-middleware.ts +25 -0
- package/express/src/modules/auth/controllers/auth.controller.ts +358 -0
- package/express/src/modules/auth/controllers/auth.helpers.ts +104 -0
- package/express/src/modules/auth/controllers/auth.schema.ts +102 -0
- package/express/src/modules/auth/controllers/role.controller.ts +15 -0
- package/express/src/modules/auth/database/models/notifications.ts +24 -0
- package/express/src/modules/auth/database/models/role.ts +14 -0
- package/express/src/modules/auth/database/models/user.ts +46 -0
- package/express/src/modules/auth/database/seeders/role.ts +18 -0
- package/express/src/modules/auth/database/seeders/user.ts +35 -0
- package/express/src/modules/auth/jobs/forgetpass.ts +20 -0
- package/express/src/modules/auth/jobs/registeruser.ts +23 -0
- package/express/src/modules/auth/jobs/verifyemail.ts +18 -0
- package/express/src/modules/auth/routes/api.ts +150 -0
- package/express/src/modules/auth/routes/role.ts +33 -0
- package/express/src/resources/index.html +17 -0
- package/express/src/resources/src/App.vue +5 -0
- package/express/src/resources/src/assets/css/styles.css +14761 -0
- package/express/src/resources/src/assets/css/styles.css.map +1 -0
- package/express/src/resources/src/assets/fonts/public-sans/public-sans-latin-ext.woff2 +0 -0
- package/express/src/resources/src/assets/fonts/public-sans/public-sans-latin.woff2 +0 -0
- package/express/src/resources/src/assets/images/favicon/favicon.ico +0 -0
- package/express/src/resources/src/assets/images/logo.png +0 -0
- package/express/src/resources/src/assets/scss/custom.css +217 -0
- package/express/src/resources/src/assets/scss/custom.css.map +1 -0
- package/express/src/resources/src/assets/scss/custom.scss +1346 -0
- package/express/src/resources/src/components/Button.vue +32 -0
- package/express/src/resources/src/components/Checkbox.vue +29 -0
- package/express/src/resources/src/components/Datepicker.vue +106 -0
- package/express/src/resources/src/components/FeatureButton.vue +53 -0
- package/express/src/resources/src/components/FloatButton.vue +33 -0
- package/express/src/resources/src/components/Href.vue +32 -0
- package/express/src/resources/src/components/Input.vue +223 -0
- package/express/src/resources/src/components/InputGroup.vue +145 -0
- package/express/src/resources/src/components/InputPasswordToggle.vue +213 -0
- package/express/src/resources/src/components/Modal.vue +55 -0
- package/express/src/resources/src/components/Pagebar.vue +26 -0
- package/express/src/resources/src/components/Select.vue +384 -0
- package/express/src/resources/src/components/Spinner.vue +42 -0
- package/express/src/resources/src/components/Switch.vue +65 -0
- package/express/src/resources/src/components/TextArea.vue +117 -0
- package/express/src/resources/src/components/Toast.vue +56 -0
- package/express/src/resources/src/components/datatable/DataTableSkeleton.vue +98 -0
- package/express/src/resources/src/components/datatable/Pagination.vue +147 -0
- package/express/src/resources/src/components/datatable/SelectOpption.vue +64 -0
- package/express/src/resources/src/components/datatable/index.vue +199 -0
- package/express/src/resources/src/composables/useAuth.ts +52 -0
- package/express/src/resources/src/helpers/nformatter.ts +10 -0
- package/express/src/resources/src/helpers/utils.ts +75 -0
- package/express/src/resources/src/layouts/AuthLayout.vue +20 -0
- package/express/src/resources/src/layouts/Layout/Footer.vue +23 -0
- package/express/src/resources/src/layouts/Layout/Header.vue +105 -0
- package/express/src/resources/src/layouts/Layout/Sidebar.vue +137 -0
- package/express/src/resources/src/layouts/Layout/index.vue +87 -0
- package/express/src/resources/src/main.ts +26 -0
- package/express/src/resources/src/pages/auth/forgetPassword.vue +82 -0
- package/express/src/resources/src/pages/auth/login.vue +99 -0
- package/express/src/resources/src/pages/auth/register.vue +133 -0
- package/express/src/resources/src/pages/auth/resetPassword.vue +118 -0
- package/express/src/resources/src/pages/auth/verifyEmail.vue +68 -0
- package/express/src/resources/src/pages/dashboard/index.vue +66 -0
- package/express/src/resources/src/plugins/axios.ts +31 -0
- package/express/src/resources/src/plugins/browserDetect.ts +55 -0
- package/express/src/resources/src/plugins/dialog.ts +216 -0
- package/express/src/resources/src/plugins/gum.ts +367 -0
- package/express/src/resources/src/plugins/pulse.ts +147 -0
- package/express/src/resources/src/plugins/routeProgress.ts +87 -0
- package/express/src/resources/src/router/index.ts +85 -0
- package/express/src/resources/src/stores/admin-ui.ts +148 -0
- package/express/src/resources/src/stores/auth.ts +164 -0
- package/express/src/resources/tsconfig.json +19 -0
- package/express/src/resources/vite.config.ts +46 -0
- package/express/src/storage/app/private/.gitkeep +0 -0
- package/express/src/storage/app/public/.gitkeep +0 -0
- package/express/src/storage/app/tmp/generated/.gitkeep +0 -0
- package/express/src/storage/database/nexwire.sqlite +0 -0
- package/express/src/storage/logs/.gitkeep +0 -0
- package/express/src/storage/tmp/.gitkeep +0 -0
- package/express/src/storage/trash/modules/.gitkeep +0 -0
- package/express/src/types/global.d.ts +26 -0
- package/express/tsconfig.json +19 -0
- package/express/vitest.config.ts +23 -0
- package/hono/.dockerignore +14 -0
- package/hono/.env +44 -0
- package/hono/.env.example +42 -0
- package/hono/.vscode/settings.json +26 -0
- package/hono/LICENSE +21 -0
- package/hono/README.md +211 -0
- package/hono/biome.json +76 -0
- package/hono/drizzle.config.ts +25 -0
- package/hono/gitignore-stub +24 -0
- package/hono/package.json +99 -0
- package/hono/public/.gitkeep +0 -0
- package/hono/src/config/app.ts +41 -0
- package/hono/src/config/auth.ts +12 -0
- package/hono/src/config/cache.ts +16 -0
- package/hono/src/config/cookie.ts +15 -0
- package/hono/src/config/cors.ts +12 -0
- package/hono/src/config/database.ts +29 -0
- package/hono/src/config/index.ts +83 -0
- package/hono/src/config/jwt.ts +19 -0
- package/hono/src/config/logging.ts +13 -0
- package/hono/src/config/mail.ts +24 -0
- package/hono/src/config/openapi.ts +54 -0
- package/hono/src/config/queue.ts +30 -0
- package/hono/src/config/rateLimit.ts +17 -0
- package/hono/src/config/realtime.ts +15 -0
- package/hono/src/config/redis.ts +18 -0
- package/hono/src/config/security.ts +44 -0
- package/hono/src/config/session.ts +17 -0
- package/hono/src/config/storage.ts +22 -0
- package/hono/src/config/validate.ts +40 -0
- package/hono/src/database/migrations/sqlite/0000_init.sql +61 -0
- package/hono/src/database/migrations/sqlite/meta/0000_snapshot.json +412 -0
- package/hono/src/database/migrations/sqlite/meta/_journal.json +13 -0
- package/hono/src/database/schema.ts +3 -0
- package/hono/src/env.ts +76 -0
- package/hono/src/framework/cache/cache.ts +81 -0
- package/hono/src/framework/circuit-breaker/cb.ts +60 -0
- package/hono/src/framework/database/connection.ts +196 -0
- package/hono/src/framework/database/migrate-hooks.ts +87 -0
- package/hono/src/framework/database/paginate.ts +253 -0
- package/hono/src/framework/database/schema.ts +20 -0
- package/hono/src/framework/database/seed.ts +139 -0
- package/hono/src/framework/events/dispatcher.ts +49 -0
- package/hono/src/framework/facade.ts +29 -0
- package/hono/src/framework/http/app.ts +109 -0
- package/hono/src/framework/http/cors.ts +19 -0
- package/hono/src/framework/http/logger.ts +81 -0
- package/hono/src/framework/http/metrics.ts +22 -0
- package/hono/src/framework/http/openapi.ts +42 -0
- package/hono/src/framework/http/ratelimiter.ts +172 -0
- package/hono/src/framework/http/router.ts +76 -0
- package/hono/src/framework/http/security.ts +23 -0
- package/hono/src/framework/http/static.ts +70 -0
- package/hono/src/framework/http/validation.ts +21 -0
- package/hono/src/framework/kernel.ts +48 -0
- package/hono/src/framework/maker-cli/db/core.mjs +288 -0
- package/hono/src/framework/maker-cli/db/index.mjs +204 -0
- package/hono/src/framework/maker-cli/deploy/core.mjs +1038 -0
- package/hono/src/framework/maker-cli/deploy/index.mjs +91 -0
- package/hono/src/framework/maker-cli/index.mjs +53 -0
- package/hono/src/framework/maker-cli/middleware/core.mjs +47 -0
- package/hono/src/framework/maker-cli/middleware/index.mjs +12 -0
- package/hono/src/framework/maker-cli/module/core.mjs +684 -0
- package/hono/src/framework/maker-cli/module/index.mjs +140 -0
- package/hono/src/framework/maker-cli/runtime/build-ui.mjs +17 -0
- package/hono/src/framework/maker-cli/runtime/core.mjs +543 -0
- package/hono/src/framework/maker-cli/runtime/index.mjs +104 -0
- package/hono/src/framework/maker-cli/runtime/redis-commander-patch.cjs +20 -0
- package/hono/src/framework/maker-cli/stubs/controller/openapi.ts.stub +57 -0
- package/hono/src/framework/maker-cli/stubs/controller/openapi.with-model.ts.stub +58 -0
- package/hono/src/framework/maker-cli/stubs/controller/plain.ts.stub +59 -0
- package/hono/src/framework/maker-cli/stubs/controller/schema.plain.ts.stub +14 -0
- package/hono/src/framework/maker-cli/stubs/controller/schema.ts.stub +33 -0
- package/hono/src/framework/maker-cli/stubs/deploy/Dockerfile.bun.stub +52 -0
- package/hono/src/framework/maker-cli/stubs/deploy/Dockerfile.pnpm.stub +55 -0
- package/hono/src/framework/maker-cli/stubs/deploy/Dockerfile.stub +51 -0
- package/hono/src/framework/maker-cli/stubs/deploy/Dockerfile.yarn.stub +55 -0
- package/hono/src/framework/maker-cli/stubs/deploy/README.stub +59 -0
- package/hono/src/framework/maker-cli/stubs/deploy/compose/mysql.server.stub +45 -0
- package/hono/src/framework/maker-cli/stubs/deploy/compose/postgres.server.stub +45 -0
- package/hono/src/framework/maker-cli/stubs/deploy/compose/sqlite.stub +45 -0
- package/hono/src/framework/maker-cli/stubs/deploy/env/mysql.server.stub +68 -0
- package/hono/src/framework/maker-cli/stubs/deploy/env/postgres.server.stub +68 -0
- package/hono/src/framework/maker-cli/stubs/deploy/env/sqlite.stub +67 -0
- package/hono/src/framework/maker-cli/stubs/deploy/scripts/auto-migrate.sh.stub +41 -0
- package/hono/src/framework/maker-cli/stubs/deploy/server/README.stub +78 -0
- package/hono/src/framework/maker-cli/stubs/deploy/server/compose/noredis.stub +120 -0
- package/hono/src/framework/maker-cli/stubs/deploy/server/compose/redis.dev.stub +133 -0
- package/hono/src/framework/maker-cli/stubs/deploy/server/compose/redis.stub +131 -0
- package/hono/src/framework/maker-cli/stubs/deploy/server/env/local.example.stub +11 -0
- package/hono/src/framework/maker-cli/stubs/deploy/server/env/noredis.stub +25 -0
- package/hono/src/framework/maker-cli/stubs/deploy/server/env/redis.stub +25 -0
- package/hono/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/README.stub +16 -0
- package/hono/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/app.example.com.stub +13 -0
- package/hono/src/framework/maker-cli/stubs/deploy/server/pgadmin/servers.stub +14 -0
- package/hono/src/framework/maker-cli/stubs/deploy/server/redis/redis.conf.stub +7 -0
- package/hono/src/framework/maker-cli/stubs/deploy/supervisor/noredis.stub +54 -0
- package/hono/src/framework/maker-cli/stubs/deploy/supervisor/redis.stub +70 -0
- package/hono/src/framework/maker-cli/stubs/deploy/workflow/local.json.stub +25 -0
- package/hono/src/framework/maker-cli/stubs/deploy/workflow/remote.json.stub +24 -0
- package/hono/src/framework/maker-cli/stubs/example/console.ts.stub +34 -0
- package/hono/src/framework/maker-cli/stubs/example/controller.ts.stub +505 -0
- package/hono/src/framework/maker-cli/stubs/example/job.ts.stub +75 -0
- package/hono/src/framework/maker-cli/stubs/example/route.api.ts.stub +207 -0
- package/hono/src/framework/maker-cli/stubs/example/route.plain.ts.stub +18 -0
- package/hono/src/framework/maker-cli/stubs/example/schema.plain.ts.stub +42 -0
- package/hono/src/framework/maker-cli/stubs/example/schema.ts.stub +42 -0
- package/hono/src/framework/maker-cli/stubs/job/name.ts.stub +25 -0
- package/hono/src/framework/maker-cli/stubs/middleware/name.ts.stub +14 -0
- package/hono/src/framework/maker-cli/stubs/model/name.mysql.ts.stub +9 -0
- package/hono/src/framework/maker-cli/stubs/model/name.postgresql.ts.stub +9 -0
- package/hono/src/framework/maker-cli/stubs/model/name.sqlite.ts.stub +9 -0
- package/hono/src/framework/maker-cli/stubs/notification/controller.ts.stub +86 -0
- package/hono/src/framework/maker-cli/stubs/notification/job.ts.stub +13 -0
- package/hono/src/framework/maker-cli/stubs/notification/route.api.ts.stub +50 -0
- package/hono/src/framework/maker-cli/stubs/notification/route.plain.ts.stub +12 -0
- package/hono/src/framework/maker-cli/stubs/notification/schema.plain.ts.stub +26 -0
- package/hono/src/framework/maker-cli/stubs/notification/schema.ts.stub +26 -0
- package/hono/src/framework/maker-cli/stubs/route/api.ts.stub +80 -0
- package/hono/src/framework/maker-cli/stubs/route/plain.ts.stub +11 -0
- package/hono/src/framework/maker-cli/stubs/schedule/name.ts.stub +36 -0
- package/hono/src/framework/maker-cli/stubs/seeder/name.ts.stub +20 -0
- package/hono/src/framework/maker-cli/stubs/test/unit.ts.stub +22 -0
- package/hono/src/framework/maker-cli/utils/env-config.mjs +44 -0
- package/hono/src/framework/maker-cli/utils/env-db.mjs +61 -0
- package/hono/src/framework/maker-cli/utils/file-ops.mjs +30 -0
- package/hono/src/framework/maker-cli/utils/flags.mjs +14 -0
- package/hono/src/framework/maker-cli/utils/help.mjs +50 -0
- package/hono/src/framework/maker-cli/utils/naming.mjs +13 -0
- package/hono/src/framework/maker-cli/utils/process.mjs +52 -0
- package/hono/src/framework/modules/discover.ts +54 -0
- package/hono/src/framework/modules/routes.ts +24 -0
- package/hono/src/framework/notification/index.ts +116 -0
- package/hono/src/framework/queue/clear.ts +22 -0
- package/hono/src/framework/queue/queue.ts +342 -0
- package/hono/src/framework/queue/ui.ts +214 -0
- package/hono/src/framework/queue/worker.ts +61 -0
- package/hono/src/framework/realtime/broadcast.ts +46 -0
- package/hono/src/framework/realtime/index.ts +2 -0
- package/hono/src/framework/realtime/socket-cookie.ts +68 -0
- package/hono/src/framework/realtime/socket.ts +196 -0
- package/hono/src/framework/realtime/types.ts +6 -0
- package/hono/src/framework/realtime/ui.ts +16 -0
- package/hono/src/framework/redis/client.ts +151 -0
- package/hono/src/framework/runtime/runtime.ts +23 -0
- package/hono/src/framework/runtime/server-adapter.ts +94 -0
- package/hono/src/framework/scheduler/lock.ts +116 -0
- package/hono/src/framework/scheduler/run.ts +48 -0
- package/hono/src/framework/scheduler/scheduler.ts +155 -0
- package/hono/src/framework/server.ts +183 -0
- package/hono/src/framework/session/session.ts +116 -0
- package/hono/src/framework/storage/storage.ts +785 -0
- package/hono/src/framework/support/cookie.ts +99 -0
- package/hono/src/framework/support/jwt.ts +45 -0
- package/hono/src/framework/support/lifecycle.ts +35 -0
- package/hono/src/framework/support/logger.ts +148 -0
- package/hono/src/framework/support/mail.ts +48 -0
- package/hono/src/framework/support/password.ts +23 -0
- package/hono/src/framework/support/url.ts +41 -0
- package/hono/src/middlewares/auth-middleware.ts +98 -0
- package/hono/src/middlewares/role-middleware.ts +25 -0
- package/hono/src/modules/auth/controllers/auth.controller.ts +413 -0
- package/hono/src/modules/auth/controllers/auth.helpers.ts +128 -0
- package/hono/src/modules/auth/controllers/auth.schema.ts +102 -0
- package/hono/src/modules/auth/controllers/role.controller.ts +25 -0
- package/hono/src/modules/auth/database/models/notifications.ts +24 -0
- package/hono/src/modules/auth/database/models/role.ts +14 -0
- package/hono/src/modules/auth/database/models/user.ts +46 -0
- package/hono/src/modules/auth/database/seeders/role.ts +18 -0
- package/hono/src/modules/auth/database/seeders/user.ts +35 -0
- package/hono/src/modules/auth/jobs/forgetpass.ts +20 -0
- package/hono/src/modules/auth/jobs/registeruser.ts +23 -0
- package/hono/src/modules/auth/jobs/verifyemail.ts +18 -0
- package/hono/src/modules/auth/routes/api.ts +150 -0
- package/hono/src/modules/auth/routes/role.ts +33 -0
- package/hono/src/resources/index.html +17 -0
- package/hono/src/resources/src/App.vue +5 -0
- package/hono/src/resources/src/assets/css/styles.css +14913 -0
- package/hono/src/resources/src/assets/css/styles.css.map +1 -0
- package/hono/src/resources/src/assets/fonts/public-sans/public-sans-latin-ext.woff2 +0 -0
- package/hono/src/resources/src/assets/fonts/public-sans/public-sans-latin.woff2 +0 -0
- package/hono/src/resources/src/assets/images/favicon/favicon.ico +0 -0
- package/hono/src/resources/src/assets/images/logo.png +0 -0
- package/hono/src/resources/src/assets/scss/custom.css +217 -0
- package/hono/src/resources/src/assets/scss/custom.css.map +1 -0
- package/hono/src/resources/src/assets/scss/custom.scss +1346 -0
- package/hono/src/resources/src/components/Button.vue +32 -0
- package/hono/src/resources/src/components/Checkbox.vue +29 -0
- package/hono/src/resources/src/components/Datepicker.vue +106 -0
- package/hono/src/resources/src/components/FeatureButton.vue +53 -0
- package/hono/src/resources/src/components/FloatButton.vue +33 -0
- package/hono/src/resources/src/components/Href.vue +32 -0
- package/hono/src/resources/src/components/Input.vue +234 -0
- package/hono/src/resources/src/components/InputGroup.vue +149 -0
- package/hono/src/resources/src/components/InputPasswordToggle.vue +222 -0
- package/hono/src/resources/src/components/Modal.vue +55 -0
- package/hono/src/resources/src/components/Pagebar.vue +26 -0
- package/hono/src/resources/src/components/Select.vue +415 -0
- package/hono/src/resources/src/components/Spinner.vue +42 -0
- package/hono/src/resources/src/components/Switch.vue +65 -0
- package/hono/src/resources/src/components/TextArea.vue +121 -0
- package/hono/src/resources/src/components/Toast.vue +56 -0
- package/hono/src/resources/src/components/datatable/DataTableSkeleton.vue +98 -0
- package/hono/src/resources/src/components/datatable/Pagination.vue +147 -0
- package/hono/src/resources/src/components/datatable/SelectOpption.vue +64 -0
- package/hono/src/resources/src/components/datatable/index.vue +199 -0
- package/hono/src/resources/src/composables/useAuth.ts +52 -0
- package/hono/src/resources/src/helpers/nformatter.ts +10 -0
- package/hono/src/resources/src/helpers/utils.ts +75 -0
- package/hono/src/resources/src/layouts/AuthLayout.vue +20 -0
- package/hono/src/resources/src/layouts/Layout/Footer.vue +23 -0
- package/hono/src/resources/src/layouts/Layout/Header.vue +105 -0
- package/hono/src/resources/src/layouts/Layout/Sidebar.vue +137 -0
- package/hono/src/resources/src/layouts/Layout/index.vue +87 -0
- package/hono/src/resources/src/main.ts +26 -0
- package/hono/src/resources/src/pages/auth/forgetPassword.vue +82 -0
- package/hono/src/resources/src/pages/auth/login.vue +99 -0
- package/hono/src/resources/src/pages/auth/register.vue +133 -0
- package/hono/src/resources/src/pages/auth/resetPassword.vue +118 -0
- package/hono/src/resources/src/pages/auth/verifyEmail.vue +68 -0
- package/hono/src/resources/src/pages/dashboard/index.vue +66 -0
- package/hono/src/resources/src/plugins/axios.ts +31 -0
- package/hono/src/resources/src/plugins/browserDetect.ts +55 -0
- package/hono/src/resources/src/plugins/dialog.ts +216 -0
- package/hono/src/resources/src/plugins/gum.ts +367 -0
- package/hono/src/resources/src/plugins/pulse.ts +147 -0
- package/hono/src/resources/src/plugins/routeProgress.ts +87 -0
- package/hono/src/resources/src/router/index.ts +85 -0
- package/hono/src/resources/src/stores/admin-ui.ts +148 -0
- package/hono/src/resources/src/stores/auth.ts +164 -0
- package/hono/src/resources/tsconfig.json +19 -0
- package/hono/src/resources/vite.config.ts +46 -0
- package/hono/src/storage/app/private/.gitkeep +0 -0
- package/hono/src/storage/app/public/.gitkeep +0 -0
- package/hono/src/storage/app/tmp/generated/.gitkeep +0 -0
- package/hono/src/storage/database/nexwire.sqlite +0 -0
- package/hono/src/storage/logs/.gitkeep +0 -0
- package/hono/src/storage/tmp/.gitkeep +0 -0
- package/hono/src/storage/trash/modules/.gitkeep +0 -0
- package/hono/src/types/global.d.ts +26 -0
- package/hono/tsconfig.json +20 -0
- package/hono/vitest.config.ts +23 -0
- package/package.json +238 -0
- package/src/index.js +204 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { queueJob } from "@/framework/queue/queue.js";
|
|
2
|
+
import { type BroadcastOptions, broadcast } from "@/framework/realtime/broadcast.js";
|
|
3
|
+
|
|
4
|
+
type CommandHandler = (payload: any) => Promise<any>;
|
|
5
|
+
|
|
6
|
+
const commandHandlers = new Map<string, CommandHandler>();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Why: Registers in-memory command handler for synchronous dispatch.
|
|
10
|
+
* When: Module startup files register command handlers.
|
|
11
|
+
* Where: Job/command style module code.
|
|
12
|
+
* How: Stores handler in a process-level map by command name.
|
|
13
|
+
*/
|
|
14
|
+
export function command(name: string, handler: CommandHandler) {
|
|
15
|
+
commandHandlers.set(name, handler);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Why: Executes command immediately or queues it for async processing.
|
|
20
|
+
* When: Application logic needs command pattern behavior.
|
|
21
|
+
* Where: Controllers, jobs, and service layers.
|
|
22
|
+
* How: Runs local handler unless async requested; otherwise enqueues.
|
|
23
|
+
*/
|
|
24
|
+
export async function dispatchCommand(name: string, payload: any, options: { async?: boolean; queue?: string } = {}) {
|
|
25
|
+
if (!options.async) {
|
|
26
|
+
const handler = commandHandlers.get(name);
|
|
27
|
+
if (handler) return await handler(payload);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return await queueJob(name, payload, { queue: options.queue || "default" });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Why: Dispatches domain events with optional queueing and websocket fan-out.
|
|
35
|
+
* When: Domain actions need side effects or realtime notifications.
|
|
36
|
+
* Where: Controllers/jobs across modules.
|
|
37
|
+
* How: Broadcasts via Socket.IO and optionally enqueues job.
|
|
38
|
+
*/
|
|
39
|
+
export async function dispatchEvent(name: string, payload: any, options: { queue?: boolean | string; broadcast?: BroadcastOptions } = {}) {
|
|
40
|
+
if (options.broadcast) {
|
|
41
|
+
broadcast(name, payload, options.broadcast);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (options.queue) {
|
|
45
|
+
return await queueJob(name, payload, {
|
|
46
|
+
queue: typeof options.queue === "string" ? options.queue : "default"
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why: Central public API surface for framework consumers.
|
|
3
|
+
* When: Modules/middlewares need framework utilities.
|
|
4
|
+
* Where: App-layer imports should target this file.
|
|
5
|
+
* How: Re-exports stable, reusable helpers while hiding setup internals.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { createRoute, z } from "@hono/zod-openapi";
|
|
9
|
+
export * as lodash from "lodash-es";
|
|
10
|
+
export * as HttpStatusCodes from "stoker/http-status-codes";
|
|
11
|
+
export { jsonContent } from "stoker/openapi/helpers";
|
|
12
|
+
export { cache } from "@/framework/cache/cache.js";
|
|
13
|
+
export { database, db } from "@/framework/database/connection.js";
|
|
14
|
+
export { type PaginatedResult, paginate, paginateModel, paginateQuery, paginateTable } from "@/framework/database/paginate.js";
|
|
15
|
+
export { command, dispatchCommand, dispatchEvent } from "@/framework/events/dispatcher.js";
|
|
16
|
+
export { createRouter, group } from "@/framework/http/router.js";
|
|
17
|
+
export { validate } from "@/framework/http/validation.js";
|
|
18
|
+
export { notify } from "@/framework/notification/index.js";
|
|
19
|
+
export { queue, queueJob, shouldQueue } from "@/framework/queue/queue.js";
|
|
20
|
+
export { broadcast } from "@/framework/realtime/index.js";
|
|
21
|
+
export { defineSchedule } from "@/framework/scheduler/scheduler.js";
|
|
22
|
+
export { session } from "@/framework/session/session.js";
|
|
23
|
+
export { storage } from "@/framework/storage/storage.js";
|
|
24
|
+
export { cookie } from "@/framework/support/cookie.js";
|
|
25
|
+
export { jwt } from "@/framework/support/jwt.js";
|
|
26
|
+
export { logger } from "@/framework/support/logger.js";
|
|
27
|
+
export { mail } from "@/framework/support/mail.js";
|
|
28
|
+
export { password } from "@/framework/support/password.js";
|
|
29
|
+
export { urls } from "@/framework/support/url.js";
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { createRoute, z } from "@hono/zod-openapi";
|
|
2
|
+
import { appConfig, redisConfig } from "@/config/index.js";
|
|
3
|
+
import { database } from "@/framework/database/connection.js";
|
|
4
|
+
import { corsMiddleware } from "@/framework/http/cors.js";
|
|
5
|
+
import { loggerMiddleware, notFound, onError } from "@/framework/http/logger.js";
|
|
6
|
+
import { getMetrics, incrementRequestCount } from "@/framework/http/metrics.js";
|
|
7
|
+
import { configureOpenApi } from "@/framework/http/openapi.js";
|
|
8
|
+
import { rateLimiterMiddleware } from "@/framework/http/ratelimiter.js";
|
|
9
|
+
import { createRouter } from "@/framework/http/router.js";
|
|
10
|
+
import { securityMiddleware } from "@/framework/http/security.js";
|
|
11
|
+
import { hasUiBuild, storageStaticMiddleware } from "@/framework/http/static.js";
|
|
12
|
+
import { redisClientIfReady } from "@/framework/redis/client.js";
|
|
13
|
+
import { sessionMiddleware } from "@/framework/session/session.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Why: Builds the main HTTP app with middleware, health, and error handlers.
|
|
17
|
+
* When: Kernel creates application server instance.
|
|
18
|
+
* Where: Framework bootstrap path.
|
|
19
|
+
* How: Composes router, optional OpenAPI, middleware stack, and fallbacks.
|
|
20
|
+
*/
|
|
21
|
+
export function createHttpApp() {
|
|
22
|
+
const app = createRouter();
|
|
23
|
+
|
|
24
|
+
const healthRoute = createRoute({
|
|
25
|
+
path: "/health",
|
|
26
|
+
method: "get",
|
|
27
|
+
tags: ["System"],
|
|
28
|
+
responses: {
|
|
29
|
+
200: {
|
|
30
|
+
description: "Application health status",
|
|
31
|
+
content: {
|
|
32
|
+
"application/json": {
|
|
33
|
+
schema: z.object({ message: z.string() })
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (appConfig.openApiEnabled) {
|
|
41
|
+
configureOpenApi(app);
|
|
42
|
+
app.api(healthRoute, (c: any) => c.json({ message: "Application is healthy" }));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
app.use("*", sessionMiddleware);
|
|
46
|
+
app.use("*", corsMiddleware);
|
|
47
|
+
app.use("*", securityMiddleware);
|
|
48
|
+
app.use("*", async (_c, next) => {
|
|
49
|
+
incrementRequestCount();
|
|
50
|
+
await next();
|
|
51
|
+
});
|
|
52
|
+
app.use("*", loggerMiddleware);
|
|
53
|
+
app.use("*", rateLimiterMiddleware);
|
|
54
|
+
app.use("/storage/*", storageStaticMiddleware);
|
|
55
|
+
|
|
56
|
+
app.get("/ready", (c) => {
|
|
57
|
+
const checks: Record<string, string> = {};
|
|
58
|
+
let allOk = true;
|
|
59
|
+
try {
|
|
60
|
+
database();
|
|
61
|
+
checks["database"] = "ok";
|
|
62
|
+
} catch {
|
|
63
|
+
checks["database"] = "error";
|
|
64
|
+
allOk = false;
|
|
65
|
+
}
|
|
66
|
+
if (redisConfig.enabled) {
|
|
67
|
+
if (redisClientIfReady()) {
|
|
68
|
+
checks["redis"] = "ok";
|
|
69
|
+
} else {
|
|
70
|
+
checks["redis"] = "error";
|
|
71
|
+
allOk = false;
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
checks["redis"] = "disabled";
|
|
75
|
+
}
|
|
76
|
+
const status = allOk ? 200 : 503;
|
|
77
|
+
return c.json({ status: allOk ? "ready" : "not_ready", checks }, status);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
app.get("/live", (c) => {
|
|
81
|
+
return c.json({ status: "alive" });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
app.get("/metrics", (c) => {
|
|
85
|
+
const m = getMetrics();
|
|
86
|
+
const output = [
|
|
87
|
+
"# HELP http_requests_total Total HTTP requests",
|
|
88
|
+
"# TYPE http_requests_total counter",
|
|
89
|
+
`http_requests_total ${m.requestCount}`,
|
|
90
|
+
"# HELP http_errors_total Total HTTP errors",
|
|
91
|
+
"# TYPE http_errors_total counter",
|
|
92
|
+
`http_errors_total ${m.errorCount}`
|
|
93
|
+
].join("\n");
|
|
94
|
+
return c.body(output, 200, { "content-type": "text/plain" });
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
if (!hasUiBuild()) {
|
|
98
|
+
app.get("/", (c: any) => c.json({ name: appConfig.name, ok: true }));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!appConfig.openApiEnabled) {
|
|
102
|
+
app.get("/health", (c: any) => c.json({ message: "Application is healthy" }));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
app.notFound(notFound);
|
|
106
|
+
app.onError(onError);
|
|
107
|
+
|
|
108
|
+
return app;
|
|
109
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { cors } from "hono/cors";
|
|
2
|
+
import { corsConfig } from "@/config/index.js";
|
|
3
|
+
import { parseCsvOrFallback } from "@/framework/support/lifecycle.js";
|
|
4
|
+
|
|
5
|
+
const corsOrigins = parseCsvOrFallback(corsConfig.origin, []);
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Why: Applies credential-aware CORS policy.
|
|
9
|
+
* When: Global HTTP middleware processing.
|
|
10
|
+
* Where: App middleware stack.
|
|
11
|
+
* How: Reflects origin for wildcard mode or validates against allowlist.
|
|
12
|
+
*/
|
|
13
|
+
export const corsMiddleware = cors({
|
|
14
|
+
origin: (origin) => {
|
|
15
|
+
if (corsConfig.origin === "*") return origin;
|
|
16
|
+
return corsOrigins.includes(origin) ? origin : undefined;
|
|
17
|
+
},
|
|
18
|
+
credentials: true
|
|
19
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Context, Next } from "hono";
|
|
2
|
+
import { loggingConfig } from "@/config/index.js";
|
|
3
|
+
import { logger } from "@/framework/support/logger.js";
|
|
4
|
+
|
|
5
|
+
function ip(c: Context) {
|
|
6
|
+
return c.req.header("cf-connecting-ip") || c.req.header("x-forwarded-for") || c.req.header("x-real-ip") || null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function shouldSkipHttpLog(pathname: string) {
|
|
10
|
+
return pathname.startsWith("/queues");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Why: Logs each HTTP request with latency and request metadata.
|
|
15
|
+
* When: Applied globally to app routes.
|
|
16
|
+
* Where: HTTP middleware stack.
|
|
17
|
+
* How: Captures start time, assigns request id, logs after downstream response.
|
|
18
|
+
*/
|
|
19
|
+
export async function loggerMiddleware(c: Context, next: Next) {
|
|
20
|
+
const start = Date.now();
|
|
21
|
+
const requestId = crypto.randomUUID();
|
|
22
|
+
|
|
23
|
+
c.set("requestId", requestId);
|
|
24
|
+
await next();
|
|
25
|
+
|
|
26
|
+
if (!loggingConfig.httpRequests || shouldSkipHttpLog(c.req.path)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
logger.info("HTTP Request", {
|
|
31
|
+
requestId,
|
|
32
|
+
method: c.req.method,
|
|
33
|
+
path: c.req.path,
|
|
34
|
+
url: c.req.url,
|
|
35
|
+
status: c.res.status,
|
|
36
|
+
duration_ms: Date.now() - start,
|
|
37
|
+
ip: ip(c),
|
|
38
|
+
userAgent: c.req.header("user-agent") || null
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Why: Standard 404 handler with structured log context.
|
|
44
|
+
* When: No route matches request path.
|
|
45
|
+
* Where: App notFound handler registration.
|
|
46
|
+
* How: Emits warning log and returns JSON 404 payload.
|
|
47
|
+
*/
|
|
48
|
+
export function notFound(c: Context) {
|
|
49
|
+
logger.warn("404 Not Found", {
|
|
50
|
+
requestId: c.get("requestId") || null,
|
|
51
|
+
method: c.req.method,
|
|
52
|
+
path: c.req.path,
|
|
53
|
+
url: c.req.url,
|
|
54
|
+
ip: ip(c),
|
|
55
|
+
userAgent: c.req.header("user-agent") || null
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return c.json({ message: "Not Found" }, 404);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Why: Centralized unhandled error responder and logger.
|
|
63
|
+
* When: Route/middleware throws uncaught error.
|
|
64
|
+
* Where: App onError handler registration.
|
|
65
|
+
* How: Logs stack + request context and returns status/message JSON.
|
|
66
|
+
*/
|
|
67
|
+
export function onError(error: any, c: Context) {
|
|
68
|
+
logger.error("Unhandled Application Error", {
|
|
69
|
+
requestId: c.get("requestId") || null,
|
|
70
|
+
name: error?.name || "Error",
|
|
71
|
+
message: error?.message,
|
|
72
|
+
stack: error?.stack,
|
|
73
|
+
method: c.req.method,
|
|
74
|
+
path: c.req.path,
|
|
75
|
+
url: c.req.url,
|
|
76
|
+
ip: ip(c),
|
|
77
|
+
userAgent: c.req.header("user-agent") || null
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return c.json({ message: error?.message || "Internal Server Error" }, error?.status || 500);
|
|
81
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
let requestCount = 0;
|
|
2
|
+
let errorCount = 0;
|
|
3
|
+
|
|
4
|
+
export function incrementRequestCount() {
|
|
5
|
+
requestCount++;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function incrementErrorCount() {
|
|
9
|
+
errorCount++;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function resetMetrics() {
|
|
13
|
+
requestCount = 0;
|
|
14
|
+
errorCount = 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getMetrics() {
|
|
18
|
+
return {
|
|
19
|
+
requestCount,
|
|
20
|
+
errorCount
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { Scalar } from "@scalar/hono-api-reference";
|
|
4
|
+
import { openApiConfig } from "@/config/index.js";
|
|
5
|
+
import type { NexwireRouter } from "@/framework/http/router.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Why: Registers OpenAPI document and interactive docs UI.
|
|
9
|
+
* When: OPEN_API is enabled during app boot.
|
|
10
|
+
* Where: HTTP app setup.
|
|
11
|
+
* How: Exposes `/doc` spec and `/api-docs` Scalar viewer.
|
|
12
|
+
*/
|
|
13
|
+
export function configureOpenApi(app: NexwireRouter) {
|
|
14
|
+
app.doc("/doc", {
|
|
15
|
+
openapi: openApiConfig.version,
|
|
16
|
+
info: {
|
|
17
|
+
title: openApiConfig.title,
|
|
18
|
+
version: openApiConfig.apiVersion,
|
|
19
|
+
...(openApiConfig.description ? { description: openApiConfig.description } : {})
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (openApiConfig.scalar.favicon) {
|
|
24
|
+
app.get("/favicon.ico", (c) => {
|
|
25
|
+
const faviconPath = path.join(process.cwd(), openApiConfig.scalar.favicon);
|
|
26
|
+
if (!fs.existsSync(faviconPath)) return c.notFound();
|
|
27
|
+
return c.body(fs.readFileSync(faviconPath), 200, { "content-type": "image/x-icon" });
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
app.get(
|
|
32
|
+
openApiConfig.scalar.docsPath,
|
|
33
|
+
Scalar({
|
|
34
|
+
url: openApiConfig.scalar.specUrl,
|
|
35
|
+
layout: openApiConfig.scalar.layout,
|
|
36
|
+
theme: openApiConfig.scalar.theme,
|
|
37
|
+
pageTitle: openApiConfig.scalar.pageTitle,
|
|
38
|
+
defaultHttpClient: openApiConfig.scalar.defaultHttpClient,
|
|
39
|
+
defaultOpenAllTags: openApiConfig.scalar.defaultOpenAllTags
|
|
40
|
+
})
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { Context, MiddlewareHandler, Next } from "hono";
|
|
2
|
+
import { MemoryStore, RedisStore, rateLimiter } from "hono-rate-limiter";
|
|
3
|
+
import { rateLimitConfig } from "@/config/index.js";
|
|
4
|
+
import { redisClientIfReady } from "@/framework/redis/client.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Why: Protects API from burst abuse and accidental flooding.
|
|
8
|
+
* When: Applied globally in HTTP middleware chain.
|
|
9
|
+
* Where: App bootstrap middleware stack.
|
|
10
|
+
* How: Limits requests per-user (authenticated) or per-session (guest)
|
|
11
|
+
* using Redis store when available, falling back to in-memory.
|
|
12
|
+
* Sends standard RateLimit-* headers so clients can back off.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
function adaptRedis(raw: any) {
|
|
16
|
+
return {
|
|
17
|
+
scriptLoad: (script: string) => raw.script("load", script),
|
|
18
|
+
evalsha: (sha1: string, keys: string[], args: unknown[]) => raw.evalsha(sha1, keys.length, ...keys, ...args),
|
|
19
|
+
decr: (key: string) => raw.decr(key),
|
|
20
|
+
del: (key: string) => raw.del(key)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const REDIS_RETRY_MS = 30_000;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Why: Uses Redis for distributed rate limiting when available, but never lets
|
|
28
|
+
* a Redis outage break requests.
|
|
29
|
+
* When: The global and login limiters run on every request; Redis can go away
|
|
30
|
+
* after the middleware was already built (so the store choice cannot be
|
|
31
|
+
* frozen at first request).
|
|
32
|
+
* Where: src/framework/http/ratelimiter.ts.
|
|
33
|
+
* How: Backs every call with an always-usable MemoryStore. A RedisStore is
|
|
34
|
+
* created lazily (after a ping health check) and used only while it
|
|
35
|
+
* responds; any Redis command failure drops the store and starts a
|
|
36
|
+
* cooldown, during which traffic is served from memory. After the
|
|
37
|
+
* cooldown the store is re-attempted, so a recovered Redis is picked up.
|
|
38
|
+
*/
|
|
39
|
+
function createFailingOverStore() {
|
|
40
|
+
const memoryStore = new MemoryStore();
|
|
41
|
+
let redisStore: RedisStore | null = null;
|
|
42
|
+
let cooldownUntil = 0;
|
|
43
|
+
let options: any = null;
|
|
44
|
+
|
|
45
|
+
function enterCooldown() {
|
|
46
|
+
redisStore = null;
|
|
47
|
+
cooldownUntil = Date.now() + REDIS_RETRY_MS;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function redisStoreIfUsable() {
|
|
51
|
+
if (cooldownUntil > Date.now()) return null;
|
|
52
|
+
|
|
53
|
+
if (!redisStore) {
|
|
54
|
+
const raw = redisClientIfReady();
|
|
55
|
+
if (!raw) return null;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
await raw.ping();
|
|
59
|
+
} catch {
|
|
60
|
+
enterCooldown();
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
redisStore = new RedisStore({ client: adaptRedis(raw), prefix: rateLimitConfig.keyPrefix });
|
|
66
|
+
redisStore.init(options);
|
|
67
|
+
} catch {
|
|
68
|
+
enterCooldown();
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return redisStore;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
init(opts: any) {
|
|
78
|
+
options = opts;
|
|
79
|
+
memoryStore.init(opts);
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
async increment(key: string) {
|
|
83
|
+
const redis = await redisStoreIfUsable();
|
|
84
|
+
if (redis) {
|
|
85
|
+
try {
|
|
86
|
+
return await redis.increment(key);
|
|
87
|
+
} catch {
|
|
88
|
+
enterCooldown();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return memoryStore.increment(key);
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
async decrement(key: string) {
|
|
95
|
+
const redis = await redisStoreIfUsable();
|
|
96
|
+
if (redis) {
|
|
97
|
+
try {
|
|
98
|
+
await redis.decrement(key);
|
|
99
|
+
return;
|
|
100
|
+
} catch {
|
|
101
|
+
enterCooldown();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
memoryStore.decrement(key);
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
async resetKey(key: string) {
|
|
108
|
+
const redis = await redisStoreIfUsable();
|
|
109
|
+
if (redis) {
|
|
110
|
+
try {
|
|
111
|
+
await redis.resetKey(key);
|
|
112
|
+
return;
|
|
113
|
+
} catch {
|
|
114
|
+
enterCooldown();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
memoryStore.resetKey(key);
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
async get(key: string) {
|
|
121
|
+
const redis = await redisStoreIfUsable();
|
|
122
|
+
if (redis) {
|
|
123
|
+
try {
|
|
124
|
+
const info = await redis.get(key);
|
|
125
|
+
if (info) return info;
|
|
126
|
+
} catch {
|
|
127
|
+
enterCooldown();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return memoryStore.get(key);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let middleware: MiddlewareHandler | null = null;
|
|
136
|
+
|
|
137
|
+
export const rateLimiterMiddleware = async (c: Context, next: Next) => {
|
|
138
|
+
if (!middleware) {
|
|
139
|
+
middleware = rateLimiter({
|
|
140
|
+
windowMs: rateLimitConfig.windowMs,
|
|
141
|
+
limit: rateLimitConfig.maxRequests,
|
|
142
|
+
keyGenerator: (c: any) => {
|
|
143
|
+
const sessionId = c.get("sessionId");
|
|
144
|
+
if (sessionId) return `session:${sessionId}`;
|
|
145
|
+
return c.req.header("x-forwarded-for") ?? "unknown";
|
|
146
|
+
},
|
|
147
|
+
store: createFailingOverStore(),
|
|
148
|
+
standardHeaders: "draft-6"
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return middleware(c, next);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
let loginLimiterMiddleware: MiddlewareHandler | null = null;
|
|
156
|
+
|
|
157
|
+
export const loginLimiter = async (c: Context, next: Next) => {
|
|
158
|
+
if (!loginLimiterMiddleware) {
|
|
159
|
+
loginLimiterMiddleware = rateLimiter({
|
|
160
|
+
windowMs: rateLimitConfig.windowMs,
|
|
161
|
+
limit: rateLimitConfig.loginMaxRequests,
|
|
162
|
+
keyGenerator: (c: any) => {
|
|
163
|
+
const ip = c.req.header("x-forwarded-for") ?? "unknown";
|
|
164
|
+
return `login:${ip}`;
|
|
165
|
+
},
|
|
166
|
+
store: createFailingOverStore(),
|
|
167
|
+
standardHeaders: "draft-6"
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return loginLimiterMiddleware(c, next);
|
|
172
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { OpenAPIHono } from "@hono/zod-openapi";
|
|
2
|
+
import { defaultHook } from "stoker/openapi";
|
|
3
|
+
|
|
4
|
+
export type NexwireRouter = OpenAPIHono & {
|
|
5
|
+
group: (...middlewares: any[]) => NexwireRouter;
|
|
6
|
+
api: (route: any, handlerOrMiddlewares: any, handler?: any) => NexwireRouter;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Why: Creates the framework router with OpenAPI + helper methods.
|
|
11
|
+
* When: Building root app and module route files.
|
|
12
|
+
* Where: HTTP app bootstrap and route stubs.
|
|
13
|
+
* How: Wraps OpenAPIHono and adds group/api convenience APIs.
|
|
14
|
+
*/
|
|
15
|
+
export function createRouter(): NexwireRouter {
|
|
16
|
+
const router = new OpenAPIHono({ strict: false, defaultHook }) as NexwireRouter;
|
|
17
|
+
const baseOpenapi = router.openapi.bind(router);
|
|
18
|
+
|
|
19
|
+
router.group = function (...middlewares) {
|
|
20
|
+
for (const middleware of middlewares) {
|
|
21
|
+
this.use("*", middleware);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return this;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
router.api = function (route: any, handlerOrMiddlewares: any, handler?: any) {
|
|
28
|
+
if (!Array.isArray(handlerOrMiddlewares)) {
|
|
29
|
+
baseOpenapi(route, handlerOrMiddlewares);
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const middlewares = handlerOrMiddlewares;
|
|
34
|
+
const finalHandler = handler;
|
|
35
|
+
|
|
36
|
+
if (typeof finalHandler !== "function") {
|
|
37
|
+
throw new Error("api(route, middlewares, handler) requires a handler function");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const wrappedHandler = async (c: any) => {
|
|
41
|
+
let index = 0;
|
|
42
|
+
|
|
43
|
+
const next = async (): Promise<any> => {
|
|
44
|
+
if (index < middlewares.length) {
|
|
45
|
+
const middleware = middlewares[index++];
|
|
46
|
+
let downstream: any;
|
|
47
|
+
const result = await middleware(c, async () => {
|
|
48
|
+
downstream = await next();
|
|
49
|
+
return downstream;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return result === undefined ? downstream : result;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return await finalHandler(c);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return await next();
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
baseOpenapi(route, wrappedHandler);
|
|
62
|
+
return this;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return router;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Why: Shorthand for creating grouped router middleware chain.
|
|
70
|
+
* When: Route files need shared middleware composition.
|
|
71
|
+
* Where: Module route declarations.
|
|
72
|
+
* How: Creates a router instance and applies all provided middlewares.
|
|
73
|
+
*/
|
|
74
|
+
export function group(...middlewares: any[]) {
|
|
75
|
+
return createRouter().group(...middlewares);
|
|
76
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from "hono";
|
|
2
|
+
import { securityConfig } from "@/config/index.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Why: Sets browser security response headers (CSP, HSTS, X-Frame).
|
|
6
|
+
* When: Every incoming HTTP request.
|
|
7
|
+
* Where: App middleware stack, after CORS and session.
|
|
8
|
+
* How: All headers disabled when securityConfig.enabled is false.
|
|
9
|
+
* HSTS only applied when request is HTTPS.
|
|
10
|
+
*/
|
|
11
|
+
export const securityMiddleware: MiddlewareHandler = async (c, next) => {
|
|
12
|
+
if (securityConfig.enabled) {
|
|
13
|
+
c.header("Content-Security-Policy", securityConfig.csp);
|
|
14
|
+
const proto = c.req.header("x-forwarded-proto");
|
|
15
|
+
if (securityConfig.hsts && proto === "https") {
|
|
16
|
+
c.header("Strict-Transport-Security", securityConfig.hstsMaxAge);
|
|
17
|
+
}
|
|
18
|
+
c.header("X-Frame-Options", securityConfig.xFrame);
|
|
19
|
+
c.header("X-Content-Type-Options", "nosniff");
|
|
20
|
+
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
21
|
+
}
|
|
22
|
+
await next();
|
|
23
|
+
};
|