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,48 @@
|
|
|
1
|
+
import { initDatabase } from "@/framework/database/connection.js";
|
|
2
|
+
import { bootQueueJobs, stopQueueRuntime } from "@/framework/queue/queue.js";
|
|
3
|
+
import { closeRedis, initRedis } from "@/framework/redis/client.js";
|
|
4
|
+
import { startScheduler, stopScheduler } from "@/framework/scheduler/scheduler.js";
|
|
5
|
+
import { registerShutdownSignals, type ShutdownSignal } from "@/framework/support/lifecycle.js";
|
|
6
|
+
import { logger } from "@/framework/support/logger.js";
|
|
7
|
+
|
|
8
|
+
export interface SchedulerHandle {
|
|
9
|
+
count: number;
|
|
10
|
+
shutdown: (signal: ShutdownSignal) => Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Why: Starts the scheduler and wires DB/Redis/queue shutdown.
|
|
15
|
+
* When: CLI `schedule:work` command or E2E test bootstrap.
|
|
16
|
+
* Where: Scheduler entrypoint.
|
|
17
|
+
* How: Inits DB/Redis, boots queue jobs, starts scheduler, registers signals.
|
|
18
|
+
* When called as the main module, also prints the startup banner.
|
|
19
|
+
*/
|
|
20
|
+
export async function startSchedulerRuntime(): Promise<SchedulerHandle> {
|
|
21
|
+
await initDatabase();
|
|
22
|
+
await initRedis();
|
|
23
|
+
await bootQueueJobs();
|
|
24
|
+
const count = await startScheduler();
|
|
25
|
+
console.log(`Scheduler started [${count} schedule(s)]`);
|
|
26
|
+
|
|
27
|
+
let shuttingDown = false;
|
|
28
|
+
|
|
29
|
+
async function shutdown(signal: ShutdownSignal) {
|
|
30
|
+
if (shuttingDown) return;
|
|
31
|
+
shuttingDown = true;
|
|
32
|
+
|
|
33
|
+
logger.info("Scheduler shutdown signal received", { signal });
|
|
34
|
+
await Promise.allSettled([Promise.resolve(stopScheduler()), stopQueueRuntime()]);
|
|
35
|
+
await closeRedis();
|
|
36
|
+
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
registerShutdownSignals(shutdown);
|
|
41
|
+
|
|
42
|
+
return { count, shutdown };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const isMain = process.argv[1]?.endsWith("run.ts") || process.argv[1]?.endsWith("run.js");
|
|
46
|
+
if (isMain) {
|
|
47
|
+
await startSchedulerRuntime();
|
|
48
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Cron } from "croner";
|
|
2
|
+
import { discoverModuleFiles, importFile } from "@/framework/modules/discover.js";
|
|
3
|
+
import { getQueue } from "@/framework/queue/queue.js";
|
|
4
|
+
import { runWithLock } from "@/framework/scheduler/lock.js";
|
|
5
|
+
|
|
6
|
+
type Schedule = {
|
|
7
|
+
name: string;
|
|
8
|
+
expression: string;
|
|
9
|
+
handler?: () => void | Promise<void>;
|
|
10
|
+
/** Queue mode: on each tick dispatches `job` to the given queue for its worker to process. */
|
|
11
|
+
queue?: string;
|
|
12
|
+
/** Queue mode: job name enqueued on each tick (defaults to `name`). */
|
|
13
|
+
job?: string;
|
|
14
|
+
/** Queue mode: static data passed to every enqueued job. */
|
|
15
|
+
data?: any;
|
|
16
|
+
timezone?: string;
|
|
17
|
+
/** Queue mode: also dispatch one job immediately at scheduler boot. */
|
|
18
|
+
immediately?: boolean;
|
|
19
|
+
runOnInit?: boolean;
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
ttlMs?: number;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const schedules: Schedule[] = [];
|
|
25
|
+
const tasks: Cron[] = [];
|
|
26
|
+
|
|
27
|
+
const PAD = 60;
|
|
28
|
+
|
|
29
|
+
function pad(str: string, len: number, char = " ") {
|
|
30
|
+
return str.length >= len ? str : str + char.repeat(len - str.length);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function printHeader() {
|
|
34
|
+
console.log("");
|
|
35
|
+
console.log("Running Scheduled Commands");
|
|
36
|
+
console.log(`${"=".repeat(PAD)}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function printScheduleResult(name: string, startMs: number, success: boolean, _message?: string) {
|
|
40
|
+
const elapsed = ((Date.now() - startMs) / 1000).toFixed(2);
|
|
41
|
+
const now = new Date().toLocaleString("en-GB", { hour12: true });
|
|
42
|
+
const dots = ".".repeat(Math.max(1, PAD - name.length - 8));
|
|
43
|
+
const status = success ? `${elapsed}s` : `FAIL`;
|
|
44
|
+
console.log(` ${name} ${dots} ${status}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Why: Registers a cron schedule definition at runtime.
|
|
49
|
+
* When: Module console/schedule files are imported.
|
|
50
|
+
* Where: Scheduler-related module files.
|
|
51
|
+
* How: Pushes normalized schedule config into in-memory registry. Handler
|
|
52
|
+
* schedules run an in-process callback on each tick; queue-mode schedules
|
|
53
|
+
* dispatch a job to their queue on each tick. `schedule:work` is the sole
|
|
54
|
+
* trigger — queue workers never fire schedules on their own.
|
|
55
|
+
*/
|
|
56
|
+
export function defineSchedule(schedule: Schedule) {
|
|
57
|
+
const normalized = { enabled: true, runOnInit: false, ttlMs: 120_000, ...schedule };
|
|
58
|
+
schedules.push(normalized);
|
|
59
|
+
|
|
60
|
+
if (normalized.queue) {
|
|
61
|
+
// nothing to pre-register: schedule:work dispatches on each tick
|
|
62
|
+
} else if (!normalized.handler) {
|
|
63
|
+
console.warn(`Schedule "${normalized.name}" has no handler and no queue; nothing will run`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Why: Loads module schedule files so schedules are registered.
|
|
69
|
+
* When: Scheduler boot process starts.
|
|
70
|
+
* Where: Scheduler worker startup.
|
|
71
|
+
* How: Discovers schedules/console files and imports them.
|
|
72
|
+
*/
|
|
73
|
+
export async function bootSchedules() {
|
|
74
|
+
const files = await discoverModuleFiles("**/{schedules,console}/*.{ts,js}");
|
|
75
|
+
for (const file of files) await importFile(file);
|
|
76
|
+
return files.length;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function handlerRun(schedule: Schedule) {
|
|
80
|
+
return async () => {
|
|
81
|
+
await runWithLock(
|
|
82
|
+
schedule.name,
|
|
83
|
+
async () => {
|
|
84
|
+
const startMs = Date.now();
|
|
85
|
+
try {
|
|
86
|
+
await schedule.handler!();
|
|
87
|
+
printScheduleResult(schedule.name, startMs, true);
|
|
88
|
+
} catch (err: any) {
|
|
89
|
+
printScheduleResult(schedule.name, startMs, false, err?.message || String(err));
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{ ttlMs: schedule.ttlMs }
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function queueDispatchRun(schedule: Schedule) {
|
|
98
|
+
return async () => {
|
|
99
|
+
await runWithLock(
|
|
100
|
+
schedule.name,
|
|
101
|
+
async () => {
|
|
102
|
+
const startMs = Date.now();
|
|
103
|
+
try {
|
|
104
|
+
const queue = getQueue(schedule.queue);
|
|
105
|
+
if (!queue) throw new Error(`Queue "${schedule.queue}" is unavailable`);
|
|
106
|
+
await queue.add(schedule.job ?? schedule.name, schedule.data ?? {});
|
|
107
|
+
printScheduleResult(schedule.name, startMs, true);
|
|
108
|
+
} catch (err: any) {
|
|
109
|
+
printScheduleResult(schedule.name, startMs, false, err?.message || String(err));
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
{ ttlMs: schedule.ttlMs }
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Why: Starts cron tasks for all enabled schedules.
|
|
119
|
+
* When: Scheduler worker process boots.
|
|
120
|
+
* Where: `schedule:work` runtime.
|
|
121
|
+
* How: Creates a croner task per enabled schedule — handler schedules run the
|
|
122
|
+
* callback in-process, queue-mode schedules dispatch a job to their queue
|
|
123
|
+
* on each tick (the target worker processes it). Boots once for
|
|
124
|
+
* `runOnInit` handlers and `immediately` queue schedules.
|
|
125
|
+
*/
|
|
126
|
+
export async function startScheduler() {
|
|
127
|
+
await bootSchedules();
|
|
128
|
+
|
|
129
|
+
for (const schedule of schedules) {
|
|
130
|
+
if (!schedule.enabled) continue;
|
|
131
|
+
const run = schedule.handler ? handlerRun(schedule) : queueDispatchRun(schedule);
|
|
132
|
+
tasks.push(new Cron(schedule.expression, { timezone: schedule.timezone, name: schedule.name }, run));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
printHeader();
|
|
136
|
+
|
|
137
|
+
for (const schedule of schedules) {
|
|
138
|
+
if (!schedule.enabled) continue;
|
|
139
|
+
if (schedule.handler && schedule.runOnInit) await handlerRun(schedule)();
|
|
140
|
+
if (schedule.queue && schedule.immediately) await queueDispatchRun(schedule)();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return schedules.length;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Why: Stops and destroys active cron tasks.
|
|
148
|
+
* When: Scheduler shutdown.
|
|
149
|
+
* Where: Process lifecycle handlers.
|
|
150
|
+
* How: Iterates task registry and invokes stop on each croner job.
|
|
151
|
+
*/
|
|
152
|
+
export async function stopScheduler() {
|
|
153
|
+
await Promise.all(tasks.map((task) => task.stop()));
|
|
154
|
+
tasks.length = 0;
|
|
155
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { appConfig, mailConfig, realtimeConfig, redisConfig } from "@/config/index.js";
|
|
5
|
+
import { createKernel } from "@/framework/kernel.js";
|
|
6
|
+
import { stopQueueRuntime } from "@/framework/queue/queue.js";
|
|
7
|
+
import { stopQueueDashboard } from "@/framework/queue/ui.js";
|
|
8
|
+
import { broadcast, closeRealtime, initRealtime, WS_PATH } from "@/framework/realtime/index.js";
|
|
9
|
+
import { setupSocketAdminUI } from "@/framework/realtime/ui.js";
|
|
10
|
+
import { closeRedis, redisClientIfReady, redisError, redisReady } from "@/framework/redis/client.js";
|
|
11
|
+
import { isBun } from "@/framework/runtime/runtime.js";
|
|
12
|
+
import { type HttpServerHandle, startHttpServer } from "@/framework/runtime/server-adapter.js";
|
|
13
|
+
import { parseCsvOrFallback, registerShutdownSignals, type ShutdownSignal } from "@/framework/support/lifecycle.js";
|
|
14
|
+
import { logger } from "@/framework/support/logger.js";
|
|
15
|
+
|
|
16
|
+
const redisBackedServices = "cache, session, queue, events, Queue Dashboard";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Why: Builds reliable local URL string for runtime service output.
|
|
20
|
+
* When: Printing API/docs/Queue Dashboard endpoints at startup.
|
|
21
|
+
* Where: Server runtime logging.
|
|
22
|
+
* How: Derives bound port from server address and normalizes hostname.
|
|
23
|
+
*/
|
|
24
|
+
function serverUrl(server: HttpServerHandle, pathname = "") {
|
|
25
|
+
const address = server.address();
|
|
26
|
+
const port = typeof address === "object" && address ? address.port : appConfig.port;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const currentUrl = new URL(appConfig.url);
|
|
30
|
+
currentUrl.port = String(port);
|
|
31
|
+
if (currentUrl.hostname === "0.0.0.0" || currentUrl.hostname === "::") {
|
|
32
|
+
currentUrl.hostname = "localhost";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return `${currentUrl.toString().replace(/\/$/, "")}${pathname}`;
|
|
36
|
+
} catch {
|
|
37
|
+
return `http://localhost:${port}${pathname}`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ServerHandle {
|
|
42
|
+
app: Awaited<ReturnType<typeof createKernel>>["app"];
|
|
43
|
+
bullBoard: Awaited<ReturnType<typeof createKernel>>["bullBoard"];
|
|
44
|
+
server: HttpServerHandle;
|
|
45
|
+
realtime: Awaited<ReturnType<typeof initRealtime>>;
|
|
46
|
+
broadcastSubClient: ReturnType<typeof redisClientIfReady> | null;
|
|
47
|
+
shutdown: (signal: ShutdownSignal) => Promise<void>;
|
|
48
|
+
closeHttpServer: () => Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Why: Starts the HTTP server and wires realtime/queue/redis shutdown.
|
|
53
|
+
* When: CLI `serve` command or E2E test bootstrap.
|
|
54
|
+
* Where: Server entrypoint.
|
|
55
|
+
* How: Creates kernel, starts HTTP, registers signal handlers, returns handle.
|
|
56
|
+
* When called as the main module, also prints startup banners.
|
|
57
|
+
*/
|
|
58
|
+
export async function startServer(): Promise<ServerHandle> {
|
|
59
|
+
const { app, bullBoard } = await createKernel();
|
|
60
|
+
|
|
61
|
+
let realtime = null as Awaited<ReturnType<typeof initRealtime>>;
|
|
62
|
+
let server: HttpServerHandle;
|
|
63
|
+
|
|
64
|
+
if (isBun()) {
|
|
65
|
+
realtime = await initRealtime({ app });
|
|
66
|
+
server = await startHttpServer(app, appConfig.port, realtime?.websocketServe);
|
|
67
|
+
} else {
|
|
68
|
+
server = await startHttpServer(app, appConfig.port);
|
|
69
|
+
realtime = await initRealtime({ httpServer: server.native });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const socketAdmin = setupSocketAdminUI(realtime?.io ?? null);
|
|
73
|
+
|
|
74
|
+
let shuttingDown = false;
|
|
75
|
+
let broadcastSubClient: ReturnType<typeof redisClientIfReady> | null = null;
|
|
76
|
+
|
|
77
|
+
async function closeHttpServer() {
|
|
78
|
+
await server.close();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function shutdown(signal: ShutdownSignal) {
|
|
82
|
+
if (shuttingDown) return;
|
|
83
|
+
shuttingDown = true;
|
|
84
|
+
|
|
85
|
+
logger.info("Shutdown signal received", { signal });
|
|
86
|
+
if (broadcastSubClient) {
|
|
87
|
+
try {
|
|
88
|
+
await broadcastSubClient.quit();
|
|
89
|
+
} catch {
|
|
90
|
+
broadcastSubClient.disconnect();
|
|
91
|
+
}
|
|
92
|
+
broadcastSubClient = null;
|
|
93
|
+
}
|
|
94
|
+
await Promise.allSettled([closeRealtime(), stopQueueRuntime(), closeHttpServer()]);
|
|
95
|
+
stopQueueDashboard();
|
|
96
|
+
await closeRedis();
|
|
97
|
+
|
|
98
|
+
process.exit(0);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
registerShutdownSignals(shutdown);
|
|
102
|
+
|
|
103
|
+
if (redisConfig.enabled && realtime) {
|
|
104
|
+
const redis = redisClientIfReady();
|
|
105
|
+
if (redis) {
|
|
106
|
+
broadcastSubClient = redis.duplicate();
|
|
107
|
+
await broadcastSubClient.connect();
|
|
108
|
+
const channel = `${redisConfig.prefix}:broadcast`;
|
|
109
|
+
await broadcastSubClient.subscribe(channel);
|
|
110
|
+
broadcastSubClient.on("message", (_channel: string, message: string) => {
|
|
111
|
+
try {
|
|
112
|
+
const { event, payload, options } = JSON.parse(message);
|
|
113
|
+
if (event) broadcast(event, payload, options);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
logger.error("Broadcast relay error", { error });
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const views = new Set(parseCsvOrFallback(process.env.NEXWIRE_DEV_VIEWS, []).map((view) => view.toLowerCase()));
|
|
122
|
+
let redisWarnColor: ((text: string) => string) | null = null;
|
|
123
|
+
console.log(`API Docs: ${serverUrl(server, "/api-docs")}`);
|
|
124
|
+
|
|
125
|
+
if (appConfig.uiEnabled) {
|
|
126
|
+
if (process.env.NEXWIRE_FRONTEND_URL) {
|
|
127
|
+
console.log(`UI: ${process.env.NEXWIRE_FRONTEND_URL}`);
|
|
128
|
+
} else {
|
|
129
|
+
console.log("UI enabled");
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
console.log(chalk.gray("UI disabled (disabled in src/config/app.ts)"));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const bullboardLine = `${bullBoard.enabled ? "Queue Dashboard enabled" : "Queue Dashboard unavailable"}: ${serverUrl(server, bullBoard.basePath)}`;
|
|
136
|
+
console.log(redisWarnColor ? redisWarnColor(bullboardLine) : bullboardLine);
|
|
137
|
+
|
|
138
|
+
if (views.has("maildev")) {
|
|
139
|
+
const maildevLine = `MailDev: http://localhost:${mailConfig.maildev.webPort} (SMTP ${mailConfig.maildev.smtpPort})`;
|
|
140
|
+
const line = `${maildevLine} (requested; see dev process status)`;
|
|
141
|
+
console.log(redisWarnColor ? redisWarnColor(line) : line);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (views.has("studio")) {
|
|
145
|
+
console.log("Drizzle Studio requested: https://local.drizzle.studio (see dev process status)");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const socketLine = !realtimeConfig.enabled
|
|
149
|
+
? "Realtime (Socket.IO) disabled"
|
|
150
|
+
: realtime
|
|
151
|
+
? `Realtime (Socket.IO) enabled: ${socketAdmin.enabled ? "Admin UI: https://admin.socket.io" : ""} ${"| " + serverUrl(server, WS_PATH).replace(/^http/, "ws")}`
|
|
152
|
+
: "Realtime (Socket.IO) unavailable";
|
|
153
|
+
console.log(!realtimeConfig.enabled ? chalk.gray(socketLine) : realtime ? chalk.green(socketLine) : chalk.yellow(socketLine));
|
|
154
|
+
|
|
155
|
+
if (views.has("redis")) {
|
|
156
|
+
const redisUiLine = `Redis UI: http://localhost:${redisConfig.commanderPort}`;
|
|
157
|
+
const line = `${redisUiLine} (requested; see dev process status)`;
|
|
158
|
+
console.log(redisWarnColor ? redisWarnColor(line) : line);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (!redisConfig.enabled) {
|
|
162
|
+
redisWarnColor = chalk.cyan;
|
|
163
|
+
console.log(chalk.cyan("Redis disabled (configured in src/config/redis.ts)"));
|
|
164
|
+
console.log(chalk.cyan(`Redis-backed services disabled: ${redisBackedServices}`));
|
|
165
|
+
} else if (redisReady()) {
|
|
166
|
+
console.log(chalk.green(`Redis connected: ${redisConfig.url}`));
|
|
167
|
+
console.log(chalk.green(`Redis-backed services enabled: ${redisBackedServices}`));
|
|
168
|
+
} else {
|
|
169
|
+
redisWarnColor = chalk.yellow;
|
|
170
|
+
console.log(chalk.yellow(`Redis unavailable: ${redisError() || "not connected"}`));
|
|
171
|
+
console.log(chalk.yellow(`Redis-backed services unavailable: ${redisBackedServices}`));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
console.log(`${appConfig.name} API running on ${serverUrl(server)}`);
|
|
175
|
+
|
|
176
|
+
return { app, bullBoard, server, realtime, broadcastSubClient, shutdown, closeHttpServer };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
180
|
+
const isMain = process.argv[1] && path.resolve(process.argv[1]) === path.resolve(currentFile);
|
|
181
|
+
if (isMain) {
|
|
182
|
+
await startServer();
|
|
183
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import type { Context, Next } from "hono";
|
|
3
|
+
import { getCookie, setCookie } from "hono/cookie";
|
|
4
|
+
import { appConfig, redisConfig, sessionConfig } from "@/config/index.js";
|
|
5
|
+
import { redisClientIfReady } from "@/framework/redis/client.js";
|
|
6
|
+
|
|
7
|
+
/** Extract origin from a URL string. Returns empty string on invalid/missing input. */
|
|
8
|
+
function originOf(url?: string) {
|
|
9
|
+
if (!url) return "";
|
|
10
|
+
try {
|
|
11
|
+
return new URL(url).origin;
|
|
12
|
+
} catch {
|
|
13
|
+
return "";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Returns true when FRONTEND_URL and APP_URL point to different origins — requires SameSite=None; Secure for session cookies. */
|
|
18
|
+
function needsCrossSiteCookie() {
|
|
19
|
+
const appOrigin = originOf(appConfig.url);
|
|
20
|
+
const frontendOrigin = originOf(appConfig.frontendUrl);
|
|
21
|
+
return Boolean(appOrigin && frontendOrigin && appOrigin !== frontendOrigin);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Builds the Redis key for a session id using the configured prefix. */
|
|
25
|
+
function sessionKey(id: string) {
|
|
26
|
+
return `${sessionConfig.keyPrefix}:${id}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Global middleware that ensures every request has a session cookie.
|
|
31
|
+
* - Reads existing session cookie from request.
|
|
32
|
+
* - If missing: generates a UUID, sets a new cookie (SameSite=None; Secure if cross-origin, else Lax).
|
|
33
|
+
* - Stores sessionId in Hono context (`c.get("sessionId")`).
|
|
34
|
+
* - Refreshes the Redis session TTL on every request.
|
|
35
|
+
*/
|
|
36
|
+
export async function sessionMiddleware(c: Context, next: Next) {
|
|
37
|
+
let sessionId = getCookie(c, sessionConfig.cookieName);
|
|
38
|
+
|
|
39
|
+
if (!sessionId) {
|
|
40
|
+
sessionId = randomUUID();
|
|
41
|
+
const crossSiteCookie = needsCrossSiteCookie();
|
|
42
|
+
setCookie(c, sessionConfig.cookieName, sessionId, {
|
|
43
|
+
httpOnly: true,
|
|
44
|
+
sameSite: crossSiteCookie ? "None" : "Lax",
|
|
45
|
+
secure: crossSiteCookie,
|
|
46
|
+
path: "/",
|
|
47
|
+
maxAge: sessionConfig.ttlSeconds
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
c.set("sessionId", sessionId);
|
|
52
|
+
await session.refresh(sessionId);
|
|
53
|
+
await next();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Redis-backed server-side session store. Each session is a namespaced JSON document with configurable TTL. */
|
|
57
|
+
export const session = {
|
|
58
|
+
/** Create a new session document in Redis. Returns the generated session id, or empty string when Redis is unavailable. */
|
|
59
|
+
async start(data: Record<string, unknown> = {}) {
|
|
60
|
+
const client = redisClientIfReady();
|
|
61
|
+
if (!client) return "";
|
|
62
|
+
|
|
63
|
+
const id = randomUUID();
|
|
64
|
+
await client.set(sessionKey(id), JSON.stringify(data), "EX", sessionConfig.ttlSeconds);
|
|
65
|
+
return id;
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
/** Get the full session payload for a given id. Returns null when session doesn't exist or Redis is unavailable. */
|
|
69
|
+
async all<T = Record<string, unknown>>(id: string): Promise<T | null> {
|
|
70
|
+
const client = redisClientIfReady();
|
|
71
|
+
if (!client) return null;
|
|
72
|
+
|
|
73
|
+
const data = await client.get(sessionKey(id));
|
|
74
|
+
return data ? JSON.parse(data) : null;
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/** Read a single key from the session payload. Returns null if the key or session doesn't exist. */
|
|
78
|
+
async get<T>(id: string, key: string): Promise<T | null> {
|
|
79
|
+
const data = await session.all<Record<string, T>>(id);
|
|
80
|
+
return data?.[key] ?? null;
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
/** Write or update a single key in the session payload. Rewrites the entire document with a fresh TTL. Returns false when Redis is unavailable. */
|
|
84
|
+
async put(id: string, key: string, value: unknown) {
|
|
85
|
+
const client = redisClientIfReady();
|
|
86
|
+
if (!client) return false;
|
|
87
|
+
|
|
88
|
+
const data = (await session.all<Record<string, unknown>>(id)) || {};
|
|
89
|
+
data[key] = value;
|
|
90
|
+
await client.set(sessionKey(id), JSON.stringify(data), "EX", sessionConfig.ttlSeconds);
|
|
91
|
+
return true;
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
/** Extend the TTL of an existing session. Called automatically by sessionMiddleware. Returns false when Redis is unavailable. */
|
|
95
|
+
async refresh(id: string) {
|
|
96
|
+
const client = redisClientIfReady();
|
|
97
|
+
if (!client) return false;
|
|
98
|
+
|
|
99
|
+
await client.expire(sessionKey(id), sessionConfig.ttlSeconds);
|
|
100
|
+
return true;
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
/** Delete a session document from Redis. Use on logout or session expiry. Returns false when Redis is unavailable. */
|
|
104
|
+
async destroy(id: string) {
|
|
105
|
+
const client = redisClientIfReady();
|
|
106
|
+
if (!client) return false;
|
|
107
|
+
|
|
108
|
+
await client.del(sessionKey(id));
|
|
109
|
+
return true;
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
/** Returns true when Redis is enabled and the Redis client is ready — guards against using session store without Redis. */
|
|
113
|
+
isAvailable() {
|
|
114
|
+
return redisConfig.enabled && redisClientIfReady() !== null;
|
|
115
|
+
}
|
|
116
|
+
};
|