@shohaghinfo/aerojs 0.1.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/AEROJS.md +12 -0
- package/AGENTS.md +709 -0
- package/LICENSE +21 -0
- package/README.md +1186 -0
- package/bin/aero.js +24 -0
- package/dist/application.d.ts +251 -0
- package/dist/application.d.ts.map +1 -0
- package/dist/application.js +658 -0
- package/dist/application.js.map +1 -0
- package/dist/audit/audit-trail.d.ts +122 -0
- package/dist/audit/audit-trail.d.ts.map +1 -0
- package/dist/audit/audit-trail.js +154 -0
- package/dist/audit/audit-trail.js.map +1 -0
- package/dist/auth/auth-manager.d.ts +95 -0
- package/dist/auth/auth-manager.d.ts.map +1 -0
- package/dist/auth/auth-manager.js +130 -0
- package/dist/auth/auth-manager.js.map +1 -0
- package/dist/auth/bouncer.d.ts +143 -0
- package/dist/auth/bouncer.d.ts.map +1 -0
- package/dist/auth/bouncer.js +243 -0
- package/dist/auth/bouncer.js.map +1 -0
- package/dist/auth/guards/api-token-guard.d.ts +68 -0
- package/dist/auth/guards/api-token-guard.d.ts.map +1 -0
- package/dist/auth/guards/api-token-guard.js +107 -0
- package/dist/auth/guards/api-token-guard.js.map +1 -0
- package/dist/auth/guards/guard.d.ts +35 -0
- package/dist/auth/guards/guard.d.ts.map +1 -0
- package/dist/auth/guards/guard.js +7 -0
- package/dist/auth/guards/guard.js.map +1 -0
- package/dist/auth/guards/jwt-guard.d.ts +64 -0
- package/dist/auth/guards/jwt-guard.d.ts.map +1 -0
- package/dist/auth/guards/jwt-guard.js +104 -0
- package/dist/auth/guards/jwt-guard.js.map +1 -0
- package/dist/auth/guards/session-guard.d.ts +57 -0
- package/dist/auth/guards/session-guard.d.ts.map +1 -0
- package/dist/auth/guards/session-guard.js +101 -0
- package/dist/auth/guards/session-guard.js.map +1 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +2 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/policy.d.ts +20 -0
- package/dist/auth/policy.d.ts.map +1 -0
- package/dist/auth/policy.js +49 -0
- package/dist/auth/policy.js.map +1 -0
- package/dist/body-parser.d.ts +40 -0
- package/dist/body-parser.d.ts.map +1 -0
- package/dist/body-parser.js +99 -0
- package/dist/body-parser.js.map +1 -0
- package/dist/cache/cache-driver.d.ts +43 -0
- package/dist/cache/cache-driver.d.ts.map +1 -0
- package/dist/cache/cache-driver.js +6 -0
- package/dist/cache/cache-driver.js.map +1 -0
- package/dist/cache/cache-manager.d.ts +44 -0
- package/dist/cache/cache-manager.d.ts.map +1 -0
- package/dist/cache/cache-manager.js +160 -0
- package/dist/cache/cache-manager.js.map +1 -0
- package/dist/cache/drivers/database-cache-driver.d.ts +18 -0
- package/dist/cache/drivers/database-cache-driver.d.ts.map +1 -0
- package/dist/cache/drivers/database-cache-driver.js +77 -0
- package/dist/cache/drivers/database-cache-driver.js.map +1 -0
- package/dist/cache/drivers/file-cache-driver.d.ts +21 -0
- package/dist/cache/drivers/file-cache-driver.d.ts.map +1 -0
- package/dist/cache/drivers/file-cache-driver.js +95 -0
- package/dist/cache/drivers/file-cache-driver.js.map +1 -0
- package/dist/cache/drivers/memory-cache-driver.d.ts +21 -0
- package/dist/cache/drivers/memory-cache-driver.d.ts.map +1 -0
- package/dist/cache/drivers/memory-cache-driver.js +82 -0
- package/dist/cache/drivers/memory-cache-driver.js.map +1 -0
- package/dist/cache/drivers/redis-cache-driver.d.ts +18 -0
- package/dist/cache/drivers/redis-cache-driver.d.ts.map +1 -0
- package/dist/cache/drivers/redis-cache-driver.js +95 -0
- package/dist/cache/drivers/redis-cache-driver.js.map +1 -0
- package/dist/cache/index.d.ts +7 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +7 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cli/commands/init.d.ts +10 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +471 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/make.d.ts +16 -0
- package/dist/cli/commands/make.d.ts.map +1 -0
- package/dist/cli/commands/make.js +157 -0
- package/dist/cli/commands/make.js.map +1 -0
- package/dist/cli/commands/new.d.ts +7 -0
- package/dist/cli/commands/new.d.ts.map +1 -0
- package/dist/cli/commands/new.js +175 -0
- package/dist/cli/commands/new.js.map +1 -0
- package/dist/cli/commands/vault.d.ts +7 -0
- package/dist/cli/commands/vault.d.ts.map +1 -0
- package/dist/cli/commands/vault.js +39 -0
- package/dist/cli/commands/vault.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +8 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/runner.d.ts +10 -0
- package/dist/cli/runner.d.ts.map +1 -0
- package/dist/cli/runner.js +207 -0
- package/dist/cli/runner.js.map +1 -0
- package/dist/cli/templates/ecommerce-erp.d.ts +6 -0
- package/dist/cli/templates/ecommerce-erp.d.ts.map +1 -0
- package/dist/cli/templates/ecommerce-erp.js +1760 -0
- package/dist/cli/templates/ecommerce-erp.js.map +1 -0
- package/dist/cli/templates/fullstack-templates.d.ts +17 -0
- package/dist/cli/templates/fullstack-templates.d.ts.map +1 -0
- package/dist/cli/templates/fullstack-templates.js +17 -0
- package/dist/cli/templates/fullstack-templates.js.map +1 -0
- package/dist/config/config.d.ts +25 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +53 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/env-schema.d.ts +62 -0
- package/dist/config/env-schema.d.ts.map +1 -0
- package/dist/config/env-schema.js +203 -0
- package/dist/config/env-schema.js.map +1 -0
- package/dist/config/env.d.ts +31 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +153 -0
- package/dist/config/env.js.map +1 -0
- package/dist/context.d.ts +181 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +277 -0
- package/dist/context.js.map +1 -0
- package/dist/core/application-core.d.ts +79 -0
- package/dist/core/application-core.d.ts.map +1 -0
- package/dist/core/application-core.js +560 -0
- package/dist/core/application-core.js.map +1 -0
- package/dist/core/application.d.ts +121 -0
- package/dist/core/application.d.ts.map +1 -0
- package/dist/core/application.js +179 -0
- package/dist/core/application.js.map +1 -0
- package/dist/core/body-parser.d.ts +12 -0
- package/dist/core/body-parser.d.ts.map +1 -0
- package/dist/core/body-parser.js +85 -0
- package/dist/core/body-parser.js.map +1 -0
- package/dist/core/context.d.ts +94 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +278 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/error-dashboard.d.ts +35 -0
- package/dist/core/error-dashboard.d.ts.map +1 -0
- package/dist/core/error-dashboard.js +481 -0
- package/dist/core/error-dashboard.js.map +1 -0
- package/dist/core/errors.d.ts +83 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +117 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/hooks.d.ts +39 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +65 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/middleware.d.ts +15 -0
- package/dist/core/middleware.d.ts.map +1 -0
- package/dist/core/middleware.js +45 -0
- package/dist/core/middleware.js.map +1 -0
- package/dist/core/request.d.ts +50 -0
- package/dist/core/request.d.ts.map +1 -0
- package/dist/core/request.js +94 -0
- package/dist/core/request.js.map +1 -0
- package/dist/core/response.d.ts +49 -0
- package/dist/core/response.d.ts.map +1 -0
- package/dist/core/response.js +302 -0
- package/dist/core/response.js.map +1 -0
- package/dist/core/router.d.ts +58 -0
- package/dist/core/router.d.ts.map +1 -0
- package/dist/core/router.js +298 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/types.d.ts +70 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +6 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/utils.d.ts +36 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core/utils.js +108 -0
- package/dist/core/utils.js.map +1 -0
- package/dist/database/connection.d.ts +97 -0
- package/dist/database/connection.d.ts.map +1 -0
- package/dist/database/connection.js +251 -0
- package/dist/database/connection.js.map +1 -0
- package/dist/database/drizzle.d.ts +10 -0
- package/dist/database/drizzle.d.ts.map +1 -0
- package/dist/database/drizzle.js +13 -0
- package/dist/database/drizzle.js.map +1 -0
- package/dist/database/factory.d.ts +39 -0
- package/dist/database/factory.d.ts.map +1 -0
- package/dist/database/factory.js +74 -0
- package/dist/database/factory.js.map +1 -0
- package/dist/database/index.d.ts +16 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +16 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/knex.d.ts +33 -0
- package/dist/database/knex.d.ts.map +1 -0
- package/dist/database/knex.js +123 -0
- package/dist/database/knex.js.map +1 -0
- package/dist/database/migrator.d.ts +29 -0
- package/dist/database/migrator.d.ts.map +1 -0
- package/dist/database/migrator.js +83 -0
- package/dist/database/migrator.js.map +1 -0
- package/dist/database/model-hooks.d.ts +61 -0
- package/dist/database/model-hooks.d.ts.map +1 -0
- package/dist/database/model-hooks.js +126 -0
- package/dist/database/model-hooks.js.map +1 -0
- package/dist/database/model.d.ts +279 -0
- package/dist/database/model.d.ts.map +1 -0
- package/dist/database/model.js +960 -0
- package/dist/database/model.js.map +1 -0
- package/dist/database/prisma.d.ts +13 -0
- package/dist/database/prisma.d.ts.map +1 -0
- package/dist/database/prisma.js +28 -0
- package/dist/database/prisma.js.map +1 -0
- package/dist/database/query-builder.d.ts +178 -0
- package/dist/database/query-builder.d.ts.map +1 -0
- package/dist/database/query-builder.js +607 -0
- package/dist/database/query-builder.js.map +1 -0
- package/dist/database/schema.d.ts +38 -0
- package/dist/database/schema.d.ts.map +1 -0
- package/dist/database/schema.js +134 -0
- package/dist/database/schema.js.map +1 -0
- package/dist/database/seeder.d.ts +24 -0
- package/dist/database/seeder.d.ts.map +1 -0
- package/dist/database/seeder.js +27 -0
- package/dist/database/seeder.js.map +1 -0
- package/dist/di/container.d.ts +52 -0
- package/dist/di/container.d.ts.map +1 -0
- package/dist/di/container.js +124 -0
- package/dist/di/container.js.map +1 -0
- package/dist/di/decorators.d.ts +17 -0
- package/dist/di/decorators.d.ts.map +1 -0
- package/dist/di/decorators.js +63 -0
- package/dist/di/decorators.js.map +1 -0
- package/dist/di/inject.d.ts +11 -0
- package/dist/di/inject.d.ts.map +1 -0
- package/dist/di/inject.js +30 -0
- package/dist/di/inject.js.map +1 -0
- package/dist/di/provider.d.ts +32 -0
- package/dist/di/provider.d.ts.map +1 -0
- package/dist/di/provider.js +30 -0
- package/dist/di/provider.js.map +1 -0
- package/dist/diagnostics/diagnostics-plugin.d.ts +9 -0
- package/dist/diagnostics/diagnostics-plugin.d.ts.map +1 -0
- package/dist/diagnostics/diagnostics-plugin.js +49 -0
- package/dist/diagnostics/diagnostics-plugin.js.map +1 -0
- package/dist/diagnostics/health-check.d.ts +51 -0
- package/dist/diagnostics/health-check.d.ts.map +1 -0
- package/dist/diagnostics/health-check.js +122 -0
- package/dist/diagnostics/health-check.js.map +1 -0
- package/dist/diagnostics/index.d.ts +4 -0
- package/dist/diagnostics/index.d.ts.map +1 -0
- package/dist/diagnostics/index.js +4 -0
- package/dist/diagnostics/index.js.map +1 -0
- package/dist/diagnostics/prometheus.d.ts +19 -0
- package/dist/diagnostics/prometheus.d.ts.map +1 -0
- package/dist/diagnostics/prometheus.js +99 -0
- package/dist/diagnostics/prometheus.js.map +1 -0
- package/dist/errors.d.ts +139 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +173 -0
- package/dist/errors.js.map +1 -0
- package/dist/events/event-bus.d.ts +178 -0
- package/dist/events/event-bus.d.ts.map +1 -0
- package/dist/events/event-bus.js +182 -0
- package/dist/events/event-bus.js.map +1 -0
- package/dist/graphql/adapter.d.ts +48 -0
- package/dist/graphql/adapter.d.ts.map +1 -0
- package/dist/graphql/adapter.js +109 -0
- package/dist/graphql/adapter.js.map +1 -0
- package/dist/graphql/executor.d.ts +24 -0
- package/dist/graphql/executor.d.ts.map +1 -0
- package/dist/graphql/executor.js +124 -0
- package/dist/graphql/executor.js.map +1 -0
- package/dist/graphql/index.d.ts +8 -0
- package/dist/graphql/index.d.ts.map +1 -0
- package/dist/graphql/index.js +8 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/graphql/lexer.d.ts +52 -0
- package/dist/graphql/lexer.d.ts.map +1 -0
- package/dist/graphql/lexer.js +188 -0
- package/dist/graphql/lexer.js.map +1 -0
- package/dist/graphql/parser.d.ts +29 -0
- package/dist/graphql/parser.d.ts.map +1 -0
- package/dist/graphql/parser.js +206 -0
- package/dist/graphql/parser.js.map +1 -0
- package/dist/graphql/plugin.d.ts +13 -0
- package/dist/graphql/plugin.d.ts.map +1 -0
- package/dist/graphql/plugin.js +103 -0
- package/dist/graphql/plugin.js.map +1 -0
- package/dist/graphql/schema.d.ts +15 -0
- package/dist/graphql/schema.d.ts.map +1 -0
- package/dist/graphql/schema.js +17 -0
- package/dist/graphql/schema.js.map +1 -0
- package/dist/graphql/types.d.ts +65 -0
- package/dist/graphql/types.d.ts.map +1 -0
- package/dist/graphql/types.js +74 -0
- package/dist/graphql/types.js.map +1 -0
- package/dist/hooks.d.ts +67 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +115 -0
- package/dist/hooks.js.map +1 -0
- package/dist/i18n/i18n.d.ts +42 -0
- package/dist/i18n/i18n.d.ts.map +1 -0
- package/dist/i18n/i18n.js +158 -0
- package/dist/i18n/i18n.js.map +1 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -0
- package/dist/inertia/inertia.d.ts +62 -0
- package/dist/inertia/inertia.d.ts.map +1 -0
- package/dist/inertia/inertia.js +159 -0
- package/dist/inertia/inertia.js.map +1 -0
- package/dist/logging/index.d.ts +7 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +7 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.d.ts +62 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +197 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/logging/request-context.d.ts +29 -0
- package/dist/logging/request-context.d.ts.map +1 -0
- package/dist/logging/request-context.js +29 -0
- package/dist/logging/request-context.js.map +1 -0
- package/dist/mail/drivers/log-mail-driver.d.ts +11 -0
- package/dist/mail/drivers/log-mail-driver.d.ts.map +1 -0
- package/dist/mail/drivers/log-mail-driver.js +23 -0
- package/dist/mail/drivers/log-mail-driver.js.map +1 -0
- package/dist/mail/drivers/mail-driver.d.ts +14 -0
- package/dist/mail/drivers/mail-driver.d.ts.map +1 -0
- package/dist/mail/drivers/mail-driver.js +6 -0
- package/dist/mail/drivers/mail-driver.js.map +1 -0
- package/dist/mail/drivers/memory-mail-driver.d.ts +14 -0
- package/dist/mail/drivers/memory-mail-driver.d.ts.map +1 -0
- package/dist/mail/drivers/memory-mail-driver.js +24 -0
- package/dist/mail/drivers/memory-mail-driver.js.map +1 -0
- package/dist/mail/index.d.ts +10 -0
- package/dist/mail/index.d.ts.map +1 -0
- package/dist/mail/index.js +10 -0
- package/dist/mail/index.js.map +1 -0
- package/dist/mail/mailer.d.ts +48 -0
- package/dist/mail/mailer.d.ts.map +1 -0
- package/dist/mail/mailer.js +111 -0
- package/dist/mail/mailer.js.map +1 -0
- package/dist/mail/message.d.ts +30 -0
- package/dist/mail/message.d.ts.map +1 -0
- package/dist/mail/message.js +77 -0
- package/dist/mail/message.js.map +1 -0
- package/dist/middleware/cors.d.ts +16 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +76 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware.d.ts +26 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +45 -0
- package/dist/middleware.js.map +1 -0
- package/dist/pdf/index.d.ts +2 -0
- package/dist/pdf/index.d.ts.map +1 -0
- package/dist/pdf/index.js +2 -0
- package/dist/pdf/index.js.map +1 -0
- package/dist/pdf/pdf.d.ts +86 -0
- package/dist/pdf/pdf.d.ts.map +1 -0
- package/dist/pdf/pdf.js +237 -0
- package/dist/pdf/pdf.js.map +1 -0
- package/dist/plugins/plugin.d.ts +25 -0
- package/dist/plugins/plugin.d.ts.map +1 -0
- package/dist/plugins/plugin.js +17 -0
- package/dist/plugins/plugin.js.map +1 -0
- package/dist/queue/drivers/database-queue-driver.d.ts +21 -0
- package/dist/queue/drivers/database-queue-driver.d.ts.map +1 -0
- package/dist/queue/drivers/database-queue-driver.js +84 -0
- package/dist/queue/drivers/database-queue-driver.js.map +1 -0
- package/dist/queue/drivers/memory-queue-driver.d.ts +17 -0
- package/dist/queue/drivers/memory-queue-driver.d.ts.map +1 -0
- package/dist/queue/drivers/memory-queue-driver.js +71 -0
- package/dist/queue/drivers/memory-queue-driver.js.map +1 -0
- package/dist/queue/drivers/queue-driver.d.ts +44 -0
- package/dist/queue/drivers/queue-driver.d.ts.map +1 -0
- package/dist/queue/drivers/queue-driver.js +6 -0
- package/dist/queue/drivers/queue-driver.js.map +1 -0
- package/dist/queue/drivers/redis-queue-driver.d.ts +16 -0
- package/dist/queue/drivers/redis-queue-driver.d.ts.map +1 -0
- package/dist/queue/drivers/redis-queue-driver.js +92 -0
- package/dist/queue/drivers/redis-queue-driver.js.map +1 -0
- package/dist/queue/index.d.ts +12 -0
- package/dist/queue/index.d.ts.map +1 -0
- package/dist/queue/index.js +12 -0
- package/dist/queue/index.js.map +1 -0
- package/dist/queue/job.d.ts +20 -0
- package/dist/queue/job.d.ts.map +1 -0
- package/dist/queue/job.js +19 -0
- package/dist/queue/job.js.map +1 -0
- package/dist/queue/queue-manager.d.ts +41 -0
- package/dist/queue/queue-manager.d.ts.map +1 -0
- package/dist/queue/queue-manager.js +98 -0
- package/dist/queue/queue-manager.js.map +1 -0
- package/dist/queue/worker.d.ts +57 -0
- package/dist/queue/worker.d.ts.map +1 -0
- package/dist/queue/worker.js +156 -0
- package/dist/queue/worker.js.map +1 -0
- package/dist/redis/index.d.ts +5 -0
- package/dist/redis/index.d.ts.map +1 -0
- package/dist/redis/index.js +5 -0
- package/dist/redis/index.js.map +1 -0
- package/dist/redis/redis-client.d.ts +44 -0
- package/dist/redis/redis-client.d.ts.map +1 -0
- package/dist/redis/redis-client.js +131 -0
- package/dist/redis/redis-client.js.map +1 -0
- package/dist/redis/redis-connection.d.ts +32 -0
- package/dist/redis/redis-connection.d.ts.map +1 -0
- package/dist/redis/redis-connection.js +151 -0
- package/dist/redis/redis-connection.js.map +1 -0
- package/dist/redis/redis-manager.d.ts +28 -0
- package/dist/redis/redis-manager.d.ts.map +1 -0
- package/dist/redis/redis-manager.js +68 -0
- package/dist/redis/redis-manager.js.map +1 -0
- package/dist/redis/resp-parser.d.ts +29 -0
- package/dist/redis/resp-parser.d.ts.map +1 -0
- package/dist/redis/resp-parser.js +113 -0
- package/dist/redis/resp-parser.js.map +1 -0
- package/dist/request.d.ts +122 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/request.js +171 -0
- package/dist/request.js.map +1 -0
- package/dist/response.d.ts +208 -0
- package/dist/response.d.ts.map +1 -0
- package/dist/response.js +375 -0
- package/dist/response.js.map +1 -0
- package/dist/router.d.ts +146 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +341 -0
- package/dist/router.js.map +1 -0
- package/dist/routing/controller.d.ts +18 -0
- package/dist/routing/controller.d.ts.map +1 -0
- package/dist/routing/controller.js +49 -0
- package/dist/routing/controller.js.map +1 -0
- package/dist/routing/named-middleware.d.ts +27 -0
- package/dist/routing/named-middleware.d.ts.map +1 -0
- package/dist/routing/named-middleware.js +41 -0
- package/dist/routing/named-middleware.js.map +1 -0
- package/dist/routing/route-builder.d.ts +54 -0
- package/dist/routing/route-builder.d.ts.map +1 -0
- package/dist/routing/route-builder.js +95 -0
- package/dist/routing/route-builder.js.map +1 -0
- package/dist/routing/route-group.d.ts +39 -0
- package/dist/routing/route-group.d.ts.map +1 -0
- package/dist/routing/route-group.js +79 -0
- package/dist/routing/route-group.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +85 -0
- package/dist/scheduler/scheduler.d.ts.map +1 -0
- package/dist/scheduler/scheduler.js +216 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/security/csrf.d.ts +19 -0
- package/dist/security/csrf.d.ts.map +1 -0
- package/dist/security/csrf.js +69 -0
- package/dist/security/csrf.js.map +1 -0
- package/dist/security/hash.d.ts +30 -0
- package/dist/security/hash.d.ts.map +1 -0
- package/dist/security/hash.js +86 -0
- package/dist/security/hash.js.map +1 -0
- package/dist/security/headers.d.ts +56 -0
- package/dist/security/headers.d.ts.map +1 -0
- package/dist/security/headers.js +81 -0
- package/dist/security/headers.js.map +1 -0
- package/dist/security/index.d.ts +13 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +13 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/jwt.d.ts +96 -0
- package/dist/security/jwt.d.ts.map +1 -0
- package/dist/security/jwt.js +308 -0
- package/dist/security/jwt.js.map +1 -0
- package/dist/security/rate-limiter.d.ts +80 -0
- package/dist/security/rate-limiter.d.ts.map +1 -0
- package/dist/security/rate-limiter.js +127 -0
- package/dist/security/rate-limiter.js.map +1 -0
- package/dist/security/totp.d.ts +43 -0
- package/dist/security/totp.d.ts.map +1 -0
- package/dist/security/totp.js +122 -0
- package/dist/security/totp.js.map +1 -0
- package/dist/security/vault.d.ts +28 -0
- package/dist/security/vault.d.ts.map +1 -0
- package/dist/security/vault.js +73 -0
- package/dist/security/vault.js.map +1 -0
- package/dist/session/session-driver.d.ts +53 -0
- package/dist/session/session-driver.d.ts.map +1 -0
- package/dist/session/session-driver.js +132 -0
- package/dist/session/session-driver.js.map +1 -0
- package/dist/session/session-manager.d.ts +100 -0
- package/dist/session/session-manager.d.ts.map +1 -0
- package/dist/session/session-manager.js +186 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/sse/index.d.ts +2 -0
- package/dist/sse/index.d.ts.map +1 -0
- package/dist/sse/index.js +2 -0
- package/dist/sse/index.js.map +1 -0
- package/dist/sse/sse.d.ts +32 -0
- package/dist/sse/sse.d.ts.map +1 -0
- package/dist/sse/sse.js +87 -0
- package/dist/sse/sse.js.map +1 -0
- package/dist/ssr/engine.d.ts +58 -0
- package/dist/ssr/engine.d.ts.map +1 -0
- package/dist/ssr/engine.js +121 -0
- package/dist/ssr/engine.js.map +1 -0
- package/dist/ssr/index.d.ts +6 -0
- package/dist/ssr/index.d.ts.map +1 -0
- package/dist/ssr/index.js +6 -0
- package/dist/ssr/index.js.map +1 -0
- package/dist/static/static.d.ts +22 -0
- package/dist/static/static.d.ts.map +1 -0
- package/dist/static/static.js +134 -0
- package/dist/static/static.js.map +1 -0
- package/dist/storage/chunked-uploader.d.ts +53 -0
- package/dist/storage/chunked-uploader.d.ts.map +1 -0
- package/dist/storage/chunked-uploader.js +135 -0
- package/dist/storage/chunked-uploader.js.map +1 -0
- package/dist/storage/drivers/local-driver.d.ts +25 -0
- package/dist/storage/drivers/local-driver.d.ts.map +1 -0
- package/dist/storage/drivers/local-driver.js +75 -0
- package/dist/storage/drivers/local-driver.js.map +1 -0
- package/dist/storage/drivers/memory-driver.d.ts +23 -0
- package/dist/storage/drivers/memory-driver.d.ts.map +1 -0
- package/dist/storage/drivers/memory-driver.js +55 -0
- package/dist/storage/drivers/memory-driver.js.map +1 -0
- package/dist/storage/drivers/s3-driver.d.ts +34 -0
- package/dist/storage/drivers/s3-driver.d.ts.map +1 -0
- package/dist/storage/drivers/s3-driver.js +186 -0
- package/dist/storage/drivers/s3-driver.js.map +1 -0
- package/dist/storage/drivers/storage-driver.d.ts +40 -0
- package/dist/storage/drivers/storage-driver.d.ts.map +1 -0
- package/dist/storage/drivers/storage-driver.js +6 -0
- package/dist/storage/drivers/storage-driver.js.map +1 -0
- package/dist/storage/index.d.ts +13 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +13 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/multipart.d.ts +12 -0
- package/dist/storage/multipart.d.ts.map +1 -0
- package/dist/storage/multipart.js +79 -0
- package/dist/storage/multipart.js.map +1 -0
- package/dist/storage/storage-manager.d.ts +48 -0
- package/dist/storage/storage-manager.d.ts.map +1 -0
- package/dist/storage/storage-manager.js +106 -0
- package/dist/storage/storage-manager.js.map +1 -0
- package/dist/storage/uploaded-file.d.ts +40 -0
- package/dist/storage/uploaded-file.d.ts.map +1 -0
- package/dist/storage/uploaded-file.js +73 -0
- package/dist/storage/uploaded-file.js.map +1 -0
- package/dist/swagger/generator.d.ts +44 -0
- package/dist/swagger/generator.d.ts.map +1 -0
- package/dist/swagger/generator.js +117 -0
- package/dist/swagger/generator.js.map +1 -0
- package/dist/swagger/index.d.ts +8 -0
- package/dist/swagger/index.d.ts.map +1 -0
- package/dist/swagger/index.js +8 -0
- package/dist/swagger/index.js.map +1 -0
- package/dist/swagger/swagger.d.ts +9 -0
- package/dist/swagger/swagger.d.ts.map +1 -0
- package/dist/swagger/swagger.js +32 -0
- package/dist/swagger/swagger.js.map +1 -0
- package/dist/swagger/ui.d.ts +11 -0
- package/dist/swagger/ui.d.ts.map +1 -0
- package/dist/swagger/ui.js +93 -0
- package/dist/swagger/ui.js.map +1 -0
- package/dist/tcp/hl7.d.ts +19 -0
- package/dist/tcp/hl7.d.ts.map +1 -0
- package/dist/tcp/hl7.js +42 -0
- package/dist/tcp/hl7.js.map +1 -0
- package/dist/tcp/index.d.ts +4 -0
- package/dist/tcp/index.d.ts.map +1 -0
- package/dist/tcp/index.js +4 -0
- package/dist/tcp/index.js.map +1 -0
- package/dist/tcp/mllp.d.ts +22 -0
- package/dist/tcp/mllp.d.ts.map +1 -0
- package/dist/tcp/mllp.js +44 -0
- package/dist/tcp/mllp.js.map +1 -0
- package/dist/tcp/tcp-server.d.ts +20 -0
- package/dist/tcp/tcp-server.d.ts.map +1 -0
- package/dist/tcp/tcp-server.js +59 -0
- package/dist/tcp/tcp-server.js.map +1 -0
- package/dist/tenancy/index.d.ts +2 -0
- package/dist/tenancy/index.d.ts.map +1 -0
- package/dist/tenancy/index.js +2 -0
- package/dist/tenancy/index.js.map +1 -0
- package/dist/tenancy/tenant.d.ts +22 -0
- package/dist/tenancy/tenant.d.ts.map +1 -0
- package/dist/tenancy/tenant.js +32 -0
- package/dist/tenancy/tenant.js.map +1 -0
- package/dist/testing/test-client.d.ts +36 -0
- package/dist/testing/test-client.d.ts.map +1 -0
- package/dist/testing/test-client.js +128 -0
- package/dist/testing/test-client.js.map +1 -0
- package/dist/validation/index.d.ts +10 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +10 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/rules-validator.d.ts +65 -0
- package/dist/validation/rules-validator.d.ts.map +1 -0
- package/dist/validation/rules-validator.js +301 -0
- package/dist/validation/rules-validator.js.map +1 -0
- package/dist/validation/schema.d.ts +34 -0
- package/dist/validation/schema.d.ts.map +1 -0
- package/dist/validation/schema.js +174 -0
- package/dist/validation/schema.js.map +1 -0
- package/dist/validation/vine.d.ts +23 -0
- package/dist/validation/vine.d.ts.map +1 -0
- package/dist/validation/vine.js +97 -0
- package/dist/validation/vine.js.map +1 -0
- package/dist/views/view.d.ts +51 -0
- package/dist/views/view.d.ts.map +1 -0
- package/dist/views/view.js +91 -0
- package/dist/views/view.js.map +1 -0
- package/dist/views/vite.d.ts +19 -0
- package/dist/views/vite.d.ts.map +1 -0
- package/dist/views/vite.js +60 -0
- package/dist/views/vite.js.map +1 -0
- package/dist/webhook/index.d.ts +2 -0
- package/dist/webhook/index.d.ts.map +1 -0
- package/dist/webhook/index.js +2 -0
- package/dist/webhook/index.js.map +1 -0
- package/dist/webhook/webhook.d.ts +30 -0
- package/dist/webhook/webhook.d.ts.map +1 -0
- package/dist/webhook/webhook.js +124 -0
- package/dist/webhook/webhook.js.map +1 -0
- package/dist/ws/broadcaster.d.ts +43 -0
- package/dist/ws/broadcaster.d.ts.map +1 -0
- package/dist/ws/broadcaster.js +81 -0
- package/dist/ws/broadcaster.js.map +1 -0
- package/dist/ws/channel.d.ts +23 -0
- package/dist/ws/channel.d.ts.map +1 -0
- package/dist/ws/channel.js +27 -0
- package/dist/ws/channel.js.map +1 -0
- package/dist/ws/index.d.ts +5 -0
- package/dist/ws/index.d.ts.map +1 -0
- package/dist/ws/index.js +5 -0
- package/dist/ws/index.js.map +1 -0
- package/dist/ws/websocket-hub.d.ts +52 -0
- package/dist/ws/websocket-hub.d.ts.map +1 -0
- package/dist/ws/websocket-hub.js +187 -0
- package/dist/ws/websocket-hub.js.map +1 -0
- package/dist/ws/websocket.d.ts +43 -0
- package/dist/ws/websocket.d.ts.map +1 -0
- package/dist/ws/websocket.js +214 -0
- package/dist/ws/websocket.js.map +1 -0
- package/package.json +141 -0
package/README.md
ADDED
|
@@ -0,0 +1,1186 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="./assets/logo.png" alt="AeroJS Full-Stack Web Framework Logo" width="280" style="border-radius: 16px; margin-bottom: 20px;" />
|
|
3
|
+
|
|
4
|
+
# AeroJS
|
|
5
|
+
### The Blazing-Fast, Zero-Dependency Full-Stack Web Framework for Node.js
|
|
6
|
+
|
|
7
|
+
[](https://github.com/atifsoftware/AeroJS/actions/workflows/ci.yml)
|
|
8
|
+
[](https://npmjs.com/package/aerojs)
|
|
9
|
+
[](package.json)
|
|
10
|
+
[](package.json)
|
|
11
|
+
[](package.json)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<strong>Fastify's speed. AdonisJS's DX. Express's simplicity.</strong><br>
|
|
16
|
+
Natively crafted for <strong>React</strong>, <strong>Vue 3</strong> (Inertia.js), and <strong>SSR Monoliths</strong> (Edge.js, EJS).
|
|
17
|
+
</p>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## ๐ Table of Contents
|
|
23
|
+
|
|
24
|
+
- [Overview & Philosophy](#-overview--philosophy)
|
|
25
|
+
- [Key Features](#-key-features)
|
|
26
|
+
- [Architecture & Request Lifecycle](#-architecture--request-lifecycle)
|
|
27
|
+
- [Installation](#-installation)
|
|
28
|
+
- [Quick Start](#-quick-start)
|
|
29
|
+
- [Core Concepts & Guides](#-core-concepts--guides)
|
|
30
|
+
1. [Radix Tree Router & Path Parameters](#1-radix-tree-router--path-parameters)
|
|
31
|
+
2. [Onion Middleware Model (Koa-style)](#2-onion-middleware-model-koa-style)
|
|
32
|
+
3. [Lifecycle Hooks (Fastify-style)](#3-lifecycle-hooks-fastify-style)
|
|
33
|
+
4. [Unified Context, Request & Response](#4-unified-context-request--response)
|
|
34
|
+
5. [Stream Body Parsing](#5-stream-body-parsing)
|
|
35
|
+
6. [JSON Schema Validation & Fast Serializer](#6-json-schema-validation--fast-serializer)
|
|
36
|
+
7. [IoC Container & Service Providers (AdonisJS-style)](#7-ioc-container--service-providers-adonisjs-style)
|
|
37
|
+
8. [Typed Configuration & Environment Validator](#8-typed-configuration--environment-validator)
|
|
38
|
+
9. [Named Middleware & Route Groups](#9-named-middleware--route-groups)
|
|
39
|
+
10. [Class-Based Controllers & Auto-Injection](#10-class-based-controllers--auto-injection)
|
|
40
|
+
11. [Modular Plugins & Scope Encapsulation](#11-modular-plugins--scope-encapsulation)
|
|
41
|
+
12. [Type-Safe Routes & urlFor Reverse Routing](#12-type-safe-routes--urlfor-reverse-routing)
|
|
42
|
+
13. [In-Process Testing Client (`./testing`)](#13-in-process-testing-client-testing)
|
|
43
|
+
14. [Static Asset & SPA Serving](#14-static-asset--spa-serving)
|
|
44
|
+
15. [Cross-Origin Resource Sharing (CORS)](#15-cross-origin-resource-sharing-cors)
|
|
45
|
+
16. [Server-Side Templating & View Engines (Edge.js, EJS)](#16-server-side-templating--view-engines-edgejs-ejs)
|
|
46
|
+
17. [Full-Stack Modern SPAs with Inertia.js (React & Vue 3)](#17-full-stack-modern-spas-with-inertiajs-react--vue-3)
|
|
47
|
+
18. [Zero-Dependency JWT Authentication (`jwt`, `jwtAuth`)](#18-zero-dependency-jwt-authentication-jwt-jwtauth)
|
|
48
|
+
19. [Memory-Safe Rate Limiter (`useRateLimit`, `rateLimit`)](#19-memory-safe-rate-limiter-useratelimit-ratelimit)
|
|
49
|
+
20. [Security Headers & CSRF Protection (`useSecurityHeaders`, `csrf`)](#20-security-headers--csrf-protection-usesecurityheaders-csrf)
|
|
50
|
+
21. [Real-Time WebSocket Support (`app.ws`, `AeroWebSocket`)](#21-real-time-websocket-support-appws-aerowebsocket)
|
|
51
|
+
22. [Active Record ORM & QueryBuilder (`Model`, `DB`, `Migrator`)](#22-active-record-orm--querybuilder-model-db-migrator)
|
|
52
|
+
23. [Knex, Prisma & Drizzle ORM Integrations](#23-knex-prisma--drizzle-orm-integrations)
|
|
53
|
+
24. [RFC 5424 Structured Logger (`Logger`, `RequestContext`)](#24-rfc-5424-structured-logger-logger-requestcontext)
|
|
54
|
+
25. [VineJS & Rules Validation (`Validator`, `VineHelper`)](#25-vinejs--rules-validation-validator-vinehelper)
|
|
55
|
+
26. [Next.js-Style Server-Side Rendering (`SSREngine`)](#26-nextjs-style-server-side-rendering-ssrengine)
|
|
56
|
+
27. [Multi-Disk Storage & File Uploads (`Storage`, `UploadedFile`)](#27-multi-disk-storage--file-uploads-storage-uploadedfile)
|
|
57
|
+
28. [Background Queue & Mail System (`Queue`, `Mail`)](#28-background-queue--mail-system-queue-mail)
|
|
58
|
+
29. [OpenAPI 3.0 & Interactive Swagger UI (`useSwagger`)](#29-openapi-30--interactive-swagger-ui-useswagger)
|
|
59
|
+
30. [Aero Command-Line Interface (`aero` CLI)](#30-aero-command-line-interface-aero-cli)
|
|
60
|
+
- [Performance, Size & Advantages](#-performance-size--advantages)
|
|
61
|
+
- [Comparison Matrix](#-comparison-matrix)
|
|
62
|
+
- [License](#-license)
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## ๐ฏ Overview & Philosophy
|
|
67
|
+
|
|
68
|
+
Aero is engineered from first principles to combine the best architectural concepts in the Node.js ecosystem into a single unified library:
|
|
69
|
+
|
|
70
|
+
1. **Zero Runtime Dependencies:** Pure Node.js 20+ built-ins (`node:http`, `node:url`, `node:stream`, `node:events`). No supply chain vulnerabilities, instant installations, tiny footprint.
|
|
71
|
+
2. **TypeScript-First & Type-Safe:** Built with TypeScript strict mode, emitting clean ESM JavaScript.
|
|
72
|
+
3. **Onion Middleware:** Downstream and upstream execution (`await next()`).
|
|
73
|
+
4. **Lifecycle Hooks:** 8 deterministic lifecycle hooks for monitoring, transformation, and security.
|
|
74
|
+
5. **IoC & Service Providers:** AdonisJS-inspired inversion-of-control container with constructor and property `@inject` decorators.
|
|
75
|
+
6. **Encapsulated Plugins:** Fastify-style child scope encapsulation where child registrations don't leak to parents.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## โจ Key Features
|
|
80
|
+
|
|
81
|
+
- **โก Blazing Fast:** O(k) Radix Tree routing (>730,000 ops/sec) with cached regex matching.
|
|
82
|
+
- **๐ง
Onion Middleware:** Koa-style async pipeline with double-`next()` guards (>1,300,000 ops/sec).
|
|
83
|
+
- **๐ฃ 8 Lifecycle Hooks:** `onRequest`, `preParsing`, `preValidation`, `preHandler`, `preSerialization`, `onSend`, `onResponse`, `onError`.
|
|
84
|
+
- **๐๏ธ AdonisJS-Style DI Container:** Transient bindings, singletons, instance bindings, and auto-wiring `@inject` decorators.
|
|
85
|
+
- **๐ Route Groups & Fluent Builder:** Prefixes, group-level middleware, and `.as()`, `.middleware()`, `.schema()` chaining.
|
|
86
|
+
- **๐ฎ Controllers as First-Class Citizens:** Route tuples like `[UsersController, 'index']` resolved via the IoC container.
|
|
87
|
+
- **๐ Zero-Dependency Validation:** JSON Schema engine supporting `type`, `properties`, `required`, `enum`, `minimum`, `maximum`, `minLength`, `pattern`, and formats (`email`, `uuid`).
|
|
88
|
+
- **โก Fast JSON Serializer:** Compile-time schema-directed serializer (>1,500,000 ops/sec).
|
|
89
|
+
- **๐ Encapsulated Plugins:** Child application scopes with inherited contexts and `createPlugin` (fastify-plugin) escape hatches.
|
|
90
|
+
- **๐งช Ultra-Fast Test Client:** In-process testing client (`createTestClient`) running >40,000 reqs/sec without TCP sockets or port conflicts.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## ๐ Architecture & Request Lifecycle
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
Incoming HTTP Request
|
|
98
|
+
โ
|
|
99
|
+
โผ
|
|
100
|
+
[ Create AeroContext ]
|
|
101
|
+
โ
|
|
102
|
+
โผ
|
|
103
|
+
[ onRequest Hooks ]
|
|
104
|
+
โ
|
|
105
|
+
โผ
|
|
106
|
+
[ Route Matching & Param Extraction ]
|
|
107
|
+
โ
|
|
108
|
+
โผ
|
|
109
|
+
[ preParsing Hooks & Body Parser ]
|
|
110
|
+
โ
|
|
111
|
+
โผ
|
|
112
|
+
[ preValidation Hooks ]
|
|
113
|
+
โ
|
|
114
|
+
โผ
|
|
115
|
+
[ JSON Schema Validation ]
|
|
116
|
+
โ
|
|
117
|
+
โผ
|
|
118
|
+
[ preHandler Hooks ]
|
|
119
|
+
โ
|
|
120
|
+
โผ
|
|
121
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
122
|
+
โ Onion Middleware Pipeline โ
|
|
123
|
+
โ [ Global Middlewares ] โ
|
|
124
|
+
โ โ โ
|
|
125
|
+
โ โผ โ
|
|
126
|
+
โ [ Group & Route Middlewares ] โ
|
|
127
|
+
โ โ โ
|
|
128
|
+
โ โผ โ
|
|
129
|
+
โ [ Controller Action / Route Handler ] โ
|
|
130
|
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
131
|
+
โ
|
|
132
|
+
โผ
|
|
133
|
+
[ preSerialization Hooks ]
|
|
134
|
+
โ
|
|
135
|
+
โผ
|
|
136
|
+
[ onSend Hooks ]
|
|
137
|
+
โ
|
|
138
|
+
โผ
|
|
139
|
+
[ HTTP Response Flushed ]
|
|
140
|
+
โ
|
|
141
|
+
โผ
|
|
142
|
+
[ onResponse Hooks ]
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## ๐ฆ Installation
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npm install aerojs
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Requirements:
|
|
154
|
+
- Node.js >= 20.0.0
|
|
155
|
+
- ESM project (`"type": "module"` in `package.json`)
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## โก Quick Start
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { AeroJS } from 'aerojs';
|
|
163
|
+
|
|
164
|
+
const app = new AeroJS();
|
|
165
|
+
|
|
166
|
+
// Global onion middleware
|
|
167
|
+
app.use(async (ctx, next) => {
|
|
168
|
+
const start = Date.now();
|
|
169
|
+
await next();
|
|
170
|
+
const ms = Date.now() - start;
|
|
171
|
+
ctx.set('X-Response-Time', `${ms}ms`);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Basic route
|
|
175
|
+
app.get('/', (ctx) => {
|
|
176
|
+
ctx.json({ framework: 'AeroJS', status: 'online' });
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Parameterized route
|
|
180
|
+
app.get('/hello/:name', (ctx) => {
|
|
181
|
+
ctx.text(`Hello, ${ctx.params.name}!`);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
await app.listen(3000);
|
|
185
|
+
console.log('Server running at http://localhost:3000');
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## ๐ Core Concepts & Guides
|
|
191
|
+
|
|
192
|
+
### 1. Radix Tree Router & Path Parameters
|
|
193
|
+
|
|
194
|
+
Aero uses a high-performance Radix Tree router supporting exact paths, parameters, and wildcards:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
// Named path parameter
|
|
198
|
+
app.get('/users/:id', (ctx) => {
|
|
199
|
+
ctx.json({ id: ctx.params.id });
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Multiple parameters
|
|
203
|
+
app.get('/orgs/:orgId/repos/:repoId', (ctx) => {
|
|
204
|
+
ctx.json({ org: ctx.params.orgId, repo: ctx.params.repoId });
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Wildcards
|
|
208
|
+
app.get('/static/*filePath', (ctx) => {
|
|
209
|
+
ctx.text(`Accessing static file: ${ctx.params.filePath}`);
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Automatic features:
|
|
214
|
+
- **Trailing-slash normalization:** `/users/` and `/users` match identically.
|
|
215
|
+
- **405 Method Not Allowed:** Automatically returns allowed verbs in the `Allow` header.
|
|
216
|
+
- **OPTIONS Handling:** Auto-responds with 204 No Content and supported methods.
|
|
217
|
+
- **Transparent HEAD support:** Routes matching `GET` automatically serve `HEAD` without bodies.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### 2. Onion Middleware Model (Koa-style)
|
|
222
|
+
|
|
223
|
+
Middleware executes in a nested "onion" pipeline. Code before `await next()` runs downstream; code after runs upstream:
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
app.use(async (ctx, next) => {
|
|
227
|
+
console.log('1. Downstream before route');
|
|
228
|
+
await next();
|
|
229
|
+
console.log('3. Upstream after route');
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
app.get('/demo', (ctx) => {
|
|
233
|
+
console.log('2. Route handler execution');
|
|
234
|
+
ctx.send('Hello from Aero!');
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
### 3. Lifecycle Hooks (Fastify-style)
|
|
241
|
+
|
|
242
|
+
Aero provides 8 deterministic lifecycle hooks:
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
// Inspect or reject incoming requests before routing
|
|
246
|
+
app.addHook('onRequest', async (ctx) => {
|
|
247
|
+
if (ctx.headers['x-blacklisted']) {
|
|
248
|
+
ctx.status(403).json({ error: 'Access denied' });
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Pre-parsing hook (inspect headers before body parsing)
|
|
253
|
+
app.addHook('preParsing', async (ctx) => {
|
|
254
|
+
// modify or validate headers
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// Pre-validation hook
|
|
258
|
+
app.addHook('preValidation', async (ctx) => {
|
|
259
|
+
// prepare data for schema validation
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Pre-handler hook (authentication / authorization)
|
|
263
|
+
app.addHook('preHandler', async (ctx) => {
|
|
264
|
+
// verify authentication
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Pre-serialization hook (transform response payload before JSON encoding)
|
|
268
|
+
app.addHook('preSerialization', async (ctx, payload) => {
|
|
269
|
+
return { data: payload, meta: { timestamp: Date.now() } };
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// onSend hook (modify payload before headers/body are sent)
|
|
273
|
+
app.addHook('onSend', async (ctx, payload) => {
|
|
274
|
+
return payload;
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// onResponse hook (metrics, access logs)
|
|
278
|
+
app.addHook('onResponse', async (ctx) => {
|
|
279
|
+
console.log(`${ctx.method} ${ctx.path} - ${ctx.res.statusCode}`);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// onError hook (error tracking / logging)
|
|
283
|
+
app.addHook('onError', async (error, ctx) => {
|
|
284
|
+
console.error('Handled error:', error);
|
|
285
|
+
});
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
### 4. Unified Context, Request & Response
|
|
291
|
+
|
|
292
|
+
`AeroContext` (`ctx`) unifies the HTTP request and response into an ergonomic API:
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
app.get('/context-demo', (ctx) => {
|
|
296
|
+
// Request
|
|
297
|
+
const method = ctx.method;
|
|
298
|
+
const path = ctx.path;
|
|
299
|
+
const query = ctx.query;
|
|
300
|
+
const body = ctx.body;
|
|
301
|
+
const header = ctx.header('authorization');
|
|
302
|
+
const ip = ctx.req.ip;
|
|
303
|
+
|
|
304
|
+
// State (shared across middlewares)
|
|
305
|
+
ctx.state.user = { id: 1 };
|
|
306
|
+
|
|
307
|
+
// Cookies
|
|
308
|
+
const sessionId = ctx.cookies['session_id'];
|
|
309
|
+
ctx.cookie('session_id', 'new_value', { httpOnly: true, secure: true });
|
|
310
|
+
|
|
311
|
+
// Response Helpers
|
|
312
|
+
ctx.status(200);
|
|
313
|
+
ctx.set('X-Custom-Header', 'Value');
|
|
314
|
+
ctx.json({ ok: true });
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Automatic content-type handling in `ctx.send()`:
|
|
319
|
+
- `string` starting with `<` and ending with `>`: `text/html; charset=utf-8`
|
|
320
|
+
- other `string`: `text/plain; charset=utf-8`
|
|
321
|
+
- `object` / `array`: `application/json; charset=utf-8`
|
|
322
|
+
- `Buffer` / `Uint8Array`: `application/octet-stream`
|
|
323
|
+
- `Readable` stream: piped to socket
|
|
324
|
+
- `null` / `undefined`: `204 No Content`
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
### 5. Stream Body Parsing
|
|
329
|
+
|
|
330
|
+
Aero safely parses request bodies as streams with configurable size limits (default 1MB):
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
const app = new Aero({
|
|
334
|
+
bodyLimit: 5 * 1024 * 1024, // 5MB limit
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
app.post('/api/data', (ctx) => {
|
|
338
|
+
// Automatically parsed for application/json,
|
|
339
|
+
// application/x-www-form-urlencoded, or text/plain
|
|
340
|
+
ctx.json({ received: ctx.body });
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Throws `PayloadTooLargeError` (413) if the limit is exceeded.
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
### 6. JSON Schema Validation & Fast Serializer
|
|
349
|
+
|
|
350
|
+
Validate requests declaratively without external runtime dependencies:
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
app.post(
|
|
354
|
+
'/users',
|
|
355
|
+
{
|
|
356
|
+
schema: {
|
|
357
|
+
body: {
|
|
358
|
+
type: 'object',
|
|
359
|
+
required: ['email', 'age'],
|
|
360
|
+
properties: {
|
|
361
|
+
email: { type: 'string', format: 'email' },
|
|
362
|
+
age: { type: 'number', minimum: 18 },
|
|
363
|
+
role: { enum: ['admin', 'user', 'guest'] },
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
response: {
|
|
367
|
+
201: {
|
|
368
|
+
type: 'object',
|
|
369
|
+
properties: {
|
|
370
|
+
id: { type: 'number' },
|
|
371
|
+
email: { type: 'string' },
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
(ctx) => {
|
|
378
|
+
ctx.status(201).json({ id: 1, email: (ctx.body as any).email });
|
|
379
|
+
}
|
|
380
|
+
);
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
Failed validations return structured 400 Bad Request responses with detailed field-level errors.
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
### 7. IoC Container & Service Providers (AdonisJS-style)
|
|
388
|
+
|
|
389
|
+
Aero includes a full-featured Inversion of Control container:
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
import { Aero, ServiceProvider, inject } from 'aero';
|
|
393
|
+
|
|
394
|
+
class DatabaseService {
|
|
395
|
+
public query(sql: string) { return [{ id: 1, name: 'Sample' }]; }
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
class UserRepository {
|
|
399
|
+
constructor(@inject('DatabaseService') private db: DatabaseService) {}
|
|
400
|
+
public all() { return this.db.query('SELECT * FROM users'); }
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Service Provider
|
|
404
|
+
class AppServiceProvider extends ServiceProvider {
|
|
405
|
+
public register() {
|
|
406
|
+
this.container.singleton('DatabaseService', () => new DatabaseService());
|
|
407
|
+
this.container.bind('UserRepository', (c) => c.make(UserRepository));
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
public async boot() {
|
|
411
|
+
// Database connection, migrations, etc.
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const app = new Aero();
|
|
416
|
+
app.register(AppServiceProvider);
|
|
417
|
+
await app.boot();
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
### 8. Typed Configuration & Environment Validator
|
|
423
|
+
|
|
424
|
+
Manage configuration and environment variables safely:
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
import { Aero, env } from 'aero';
|
|
428
|
+
|
|
429
|
+
// Validates process.env with coercion and required checks
|
|
430
|
+
const validatedEnv = env.validate({
|
|
431
|
+
PORT: { type: 'number', default: 3000 },
|
|
432
|
+
DB_HOST: { type: 'string', required: true },
|
|
433
|
+
ENABLE_CACHE: { type: 'boolean', default: false },
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
const app = new Aero();
|
|
437
|
+
|
|
438
|
+
// Dot-notation configuration store
|
|
439
|
+
app.config.set('database.connection.host', validatedEnv.DB_HOST);
|
|
440
|
+
app.config.set('database.connection.port', 5432);
|
|
441
|
+
|
|
442
|
+
const dbHost = app.config.get<string>('database.connection.host');
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
### 9. Named Middleware & Route Groups
|
|
448
|
+
|
|
449
|
+
Organize complex APIs using route groups and reusable named middleware:
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
// Register named middleware
|
|
453
|
+
app.middleware('auth', async (ctx, next) => {
|
|
454
|
+
if (!ctx.headers['authorization']) {
|
|
455
|
+
return ctx.status(401).json({ error: 'Unauthorized' });
|
|
456
|
+
}
|
|
457
|
+
await next();
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// Route Groups with shared prefixes and middleware
|
|
461
|
+
app.group('/api/v1', (api) => {
|
|
462
|
+
api.use(async (ctx, next) => {
|
|
463
|
+
ctx.set('X-Api-Version', 'v1');
|
|
464
|
+
await next();
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
api.get('/public', (ctx) => ctx.send('public data'));
|
|
468
|
+
|
|
469
|
+
// Nested Admin Group
|
|
470
|
+
api.group('/admin', (admin) => {
|
|
471
|
+
admin.use('auth'); // Applied to all admin routes
|
|
472
|
+
|
|
473
|
+
admin.get('/stats', (ctx) => ctx.json({ server: 'healthy' }));
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
### 10. Class-Based Controllers & Auto-Injection
|
|
481
|
+
|
|
482
|
+
Pass controller class-action tuples directly into route definitions:
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
class UsersController {
|
|
486
|
+
constructor(@inject('UserRepository') private users: UserRepository) {}
|
|
487
|
+
|
|
488
|
+
public async index(ctx: AeroContext) {
|
|
489
|
+
// Returning an object automatically sends JSON
|
|
490
|
+
return { users: this.users.all() };
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
public async show(ctx: AeroContext) {
|
|
494
|
+
return { id: ctx.params.id };
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Fluent RouteBuilder chaining with controller action tuples
|
|
499
|
+
app.get('/users', [UsersController, 'index'])
|
|
500
|
+
.as('users.index')
|
|
501
|
+
.middleware('auth');
|
|
502
|
+
|
|
503
|
+
app.get('/users/:id', [UsersController, 'show'])
|
|
504
|
+
.as('users.show');
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
### 11. Modular Plugins & Scope Encapsulation
|
|
510
|
+
|
|
511
|
+
Fastify-style child scope encapsulation ensures feature plugins do not leak decorators or middleware to their parent application:
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
import { Aero, createPlugin } from 'aero';
|
|
515
|
+
|
|
516
|
+
// Encapsulated Plugin
|
|
517
|
+
const authPlugin = async (child: Aero) => {
|
|
518
|
+
child.decorate('jwtSecret', 'super-secret-key');
|
|
519
|
+
|
|
520
|
+
child.use(async (ctx, next) => {
|
|
521
|
+
ctx.set('X-Feature', 'Auth');
|
|
522
|
+
await next();
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
child.get('/login', (ctx) => {
|
|
526
|
+
// 'jwtSecret' is accessible here
|
|
527
|
+
ctx.text(`Secret: ${(child as any).jwtSecret}`);
|
|
528
|
+
});
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
// Global Plugin (breaks out of encapsulation using createPlugin)
|
|
532
|
+
const globalPlugin = createPlugin(async (root) => {
|
|
533
|
+
root.decorate('appName', 'MyAeroApp');
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
const app = new Aero();
|
|
537
|
+
await app.register(globalPlugin);
|
|
538
|
+
await app.register(authPlugin, { prefix: '/auth' });
|
|
539
|
+
|
|
540
|
+
// (app as any).jwtSecret is undefined! (Encapsulated)
|
|
541
|
+
// (app as any).appName is 'MyAeroApp'! (Global)
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
546
|
+
### 12. Type-Safe Routes & urlFor Reverse Routing
|
|
547
|
+
|
|
548
|
+
Type inference extracts route parameters from string literals, and `urlFor` provides reverse routing:
|
|
549
|
+
|
|
550
|
+
```typescript
|
|
551
|
+
import { type ExtractRouteParams } from 'aero';
|
|
552
|
+
|
|
553
|
+
type Params = ExtractRouteParams<'/users/:id/posts/:postId'>;
|
|
554
|
+
// Inferred as: { id: string; postId: string }
|
|
555
|
+
|
|
556
|
+
// Define named route
|
|
557
|
+
app.get('/users/:id', (ctx) => {
|
|
558
|
+
ctx.send(`User ${ctx.params.id}`);
|
|
559
|
+
}).as('users.profile');
|
|
560
|
+
|
|
561
|
+
// Reverse URL generation with URI encoding & query params
|
|
562
|
+
const url = app.urlFor('users.profile', {
|
|
563
|
+
id: '42',
|
|
564
|
+
tab: 'activity',
|
|
565
|
+
});
|
|
566
|
+
// Generates: '/users/42?tab=activity'
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
### 13. In-Process Testing Client (`./testing`)
|
|
572
|
+
|
|
573
|
+
Test your Aero application without binding network sockets, avoiding port conflicts and latency:
|
|
574
|
+
|
|
575
|
+
```typescript
|
|
576
|
+
import { describe, it, expect } from 'vitest';
|
|
577
|
+
import { Aero } from 'aero';
|
|
578
|
+
import { createTestClient } from 'aero/testing';
|
|
579
|
+
|
|
580
|
+
describe('API Tests', () => {
|
|
581
|
+
it('tests endpoints in-process', async () => {
|
|
582
|
+
const app = new Aero();
|
|
583
|
+
app.post('/items', (ctx) => {
|
|
584
|
+
ctx.status(201).json({ created: true, body: ctx.body });
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
const client = createTestClient(app);
|
|
588
|
+
|
|
589
|
+
const res = await client.post('/items', {
|
|
590
|
+
body: { title: 'Laptop' },
|
|
591
|
+
headers: { 'X-Test': 'true' },
|
|
592
|
+
});
|
|
593
|
+
|
|
594
|
+
expect(res.status).toBe(201);
|
|
595
|
+
expect(res.json()).toEqual({ created: true, body: { title: 'Laptop' } });
|
|
596
|
+
});
|
|
597
|
+
});
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
### 14. Static Asset & SPA Serving
|
|
603
|
+
|
|
604
|
+
Serve static directories with automatic MIME type detection, ETag 304 caching, and client-side single-page app (SPA) fallback:
|
|
605
|
+
|
|
606
|
+
```typescript
|
|
607
|
+
// Mount static assets at /assets prefix
|
|
608
|
+
app.serveStatic('/assets', './public');
|
|
609
|
+
|
|
610
|
+
// Or enable client-side SPA fallback for React/Vue/Svelte
|
|
611
|
+
app.serveStatic({
|
|
612
|
+
root: './dist/client',
|
|
613
|
+
spa: true, // Rewrites unmatched text/html routes to index.html
|
|
614
|
+
maxAge: 3600, // Cache-Control max-age in seconds
|
|
615
|
+
etag: true, // Automatic HTTP 304 Not Modified support
|
|
616
|
+
});
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
### 15. Cross-Origin Resource Sharing (CORS)
|
|
622
|
+
|
|
623
|
+
Configure CORS with fine-grained control and zero external dependencies:
|
|
624
|
+
|
|
625
|
+
```typescript
|
|
626
|
+
app.useCors({
|
|
627
|
+
origin: (origin) => origin.endsWith('.example.com') || 'http://localhost:5173',
|
|
628
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
629
|
+
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
630
|
+
exposedHeaders: ['X-Total-Count'],
|
|
631
|
+
credentials: true,
|
|
632
|
+
maxAge: 86400, // Cache preflight response for 24h
|
|
633
|
+
});
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
---
|
|
637
|
+
|
|
638
|
+
### 16. Server-Side Templating & View Engines (Edge.js, EJS)
|
|
639
|
+
|
|
640
|
+
Render SSR views using any template engine with the `ViewDriver` interface. Aero includes built-in drivers for `@edge-js/edge` (AdonisJS-style) and `ejs`:
|
|
641
|
+
|
|
642
|
+
```typescript
|
|
643
|
+
import { createEdgeDriver, createEjsDriver, SimpleViewDriver } from 'aero';
|
|
644
|
+
|
|
645
|
+
// Option A: Edge.js (AdonisJS template engine)
|
|
646
|
+
import { Edge } from 'edge.js';
|
|
647
|
+
const edge = Edge.create();
|
|
648
|
+
edge.mount(new URL('./views', import.meta.url));
|
|
649
|
+
app.useViewEngine(createEdgeDriver(edge));
|
|
650
|
+
|
|
651
|
+
// Option B: EJS
|
|
652
|
+
// import ejs from 'ejs';
|
|
653
|
+
// app.useViewEngine(createEjsDriver(ejs));
|
|
654
|
+
|
|
655
|
+
// Option C: Built-in Simple View Driver (zero-dependency {{ var }})
|
|
656
|
+
// app.useViewEngine(new SimpleViewDriver({
|
|
657
|
+
// 'welcome': '<h1>Hello, {{ user.name }}!</h1>'
|
|
658
|
+
// }));
|
|
659
|
+
|
|
660
|
+
// Render directly in route handlers
|
|
661
|
+
app.get('/', async (ctx) => {
|
|
662
|
+
await ctx.view('welcome', {
|
|
663
|
+
user: { name: 'Ada Lovelace' },
|
|
664
|
+
title: 'Home Page',
|
|
665
|
+
});
|
|
666
|
+
});
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
---
|
|
670
|
+
|
|
671
|
+
### 17. Full-Stack Modern SPAs with Inertia.js (React & Vue 3)
|
|
672
|
+
|
|
673
|
+
Build classic monolithic server-driven applications with modern client-side SPAs using **Inertia.js** without creating a separate REST or GraphQL API!
|
|
674
|
+
|
|
675
|
+
Aero provides a first-class, zero-dependency Inertia.js protocol adapter supporting:
|
|
676
|
+
- Initial HTML shell rendering (`@inertia` placeholder)
|
|
677
|
+
- Subsequent AJAX page updates (`X-Inertia: true`)
|
|
678
|
+
- Automatic asset version tracking (409 Conflict with `X-Inertia-Location`)
|
|
679
|
+
- Partial reloads & deferred evaluation (`lazy()`)
|
|
680
|
+
- Form submissions & 303 redirects
|
|
681
|
+
|
|
682
|
+
```typescript
|
|
683
|
+
import { Aero, lazy } from 'aero';
|
|
684
|
+
|
|
685
|
+
const app = new Aero();
|
|
686
|
+
|
|
687
|
+
// Register Inertia with asset versioning and root template
|
|
688
|
+
app.useInertia({
|
|
689
|
+
version: '1.0.0',
|
|
690
|
+
rootView: `
|
|
691
|
+
<!DOCTYPE html>
|
|
692
|
+
<html lang="en">
|
|
693
|
+
<head>
|
|
694
|
+
<meta charset="utf-8">
|
|
695
|
+
<title>Aero + Inertia App</title>
|
|
696
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
697
|
+
</head>
|
|
698
|
+
<body>
|
|
699
|
+
@inertia
|
|
700
|
+
</body>
|
|
701
|
+
</html>
|
|
702
|
+
`,
|
|
703
|
+
share: (ctx) => ({
|
|
704
|
+
auth: { user: ctx.state.user ?? null },
|
|
705
|
+
flash: { message: ctx.cookies['flash_message'] },
|
|
706
|
+
}),
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
// Render React or Vue 3 components seamlessly
|
|
710
|
+
app.get('/users', async (ctx) => {
|
|
711
|
+
await ctx.inertia.render('Users/Index', {
|
|
712
|
+
users: await fetchUsersFromDb(),
|
|
713
|
+
// Lazy loaded only if requested during partial reload:
|
|
714
|
+
detailedAnalytics: lazy(() => calculateHeavyMetrics()),
|
|
715
|
+
});
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// Handling form submissions
|
|
719
|
+
app.post('/users', async (ctx) => {
|
|
720
|
+
await createUser(ctx.body);
|
|
721
|
+
// Automatic 303 See Other redirect for Inertia client
|
|
722
|
+
ctx.inertia.redirect('/users');
|
|
723
|
+
});
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
#### Client-side Setup (React or Vue 3)
|
|
727
|
+
|
|
728
|
+
In your client bundle (e.g. Vite + React):
|
|
729
|
+
```tsx
|
|
730
|
+
import { createInertiaApp } from '@inertiajs/react';
|
|
731
|
+
import { createRoot } from 'react-dom/client';
|
|
732
|
+
|
|
733
|
+
createInertiaApp({
|
|
734
|
+
resolve: (name) => {
|
|
735
|
+
const pages = import.meta.glob('./Pages/**/*.tsx', { eager: true });
|
|
736
|
+
return pages[`./Pages/${name}.tsx`];
|
|
737
|
+
},
|
|
738
|
+
setup({ el, App, props }) {
|
|
739
|
+
createRoot(el).render(<App {...props} />);
|
|
740
|
+
},
|
|
741
|
+
});
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
---
|
|
745
|
+
|
|
746
|
+
### 18. Zero-Dependency JWT Authentication (`jwt`, `jwtAuth`)
|
|
747
|
+
|
|
748
|
+
Aero provides native, cryptographic JSON Web Token signing, verification, and authentication middleware built directly on Node.js's `node:crypto`. Zero external packages, zero supply-chain risk.
|
|
749
|
+
|
|
750
|
+
- **Algorithms:** `HS256`, `HS384`, `HS512`
|
|
751
|
+
- **Timing-Safe:** Immune to timing attacks using `crypto.timingSafeEqual`
|
|
752
|
+
- **Claims Verification:** Automatic validation of `exp` (expiration), `nbf` (not before), `iss` (issuer), `sub` (subject), and `aud` (audience)
|
|
753
|
+
- **Token Extraction:** Automatically extracts tokens from `Authorization: Bearer <token>`, cookies, or custom resolvers
|
|
754
|
+
|
|
755
|
+
```typescript
|
|
756
|
+
import { Aero, jwt, jwtAuth } from 'aero';
|
|
757
|
+
|
|
758
|
+
const app = new Aero();
|
|
759
|
+
const SECRET = 'your-super-secret-key-at-least-32-chars';
|
|
760
|
+
|
|
761
|
+
// 1. Issue a token on login
|
|
762
|
+
app.post('/api/login', (ctx) => {
|
|
763
|
+
const token = jwt.sign(
|
|
764
|
+
{ userId: 101, role: 'admin' },
|
|
765
|
+
SECRET,
|
|
766
|
+
{ expiresIn: '2h', issuer: 'my-app' }
|
|
767
|
+
);
|
|
768
|
+
ctx.json({ token });
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
// 2. Protect route groups with jwtAuth middleware
|
|
772
|
+
app.group('/api/admin', (admin) => {
|
|
773
|
+
admin.use(jwtAuth({ secret: SECRET }));
|
|
774
|
+
|
|
775
|
+
admin.get('/dashboard', (ctx) => {
|
|
776
|
+
// Decoded payload is attached to ctx.state.user
|
|
777
|
+
ctx.json({ user: ctx.state.user });
|
|
778
|
+
});
|
|
779
|
+
});
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
---
|
|
783
|
+
|
|
784
|
+
### 19. Memory-Safe Rate Limiter (`useRateLimit`, `rateLimit`)
|
|
785
|
+
|
|
786
|
+
Prevent denial-of-service and brute-force attacks with Aero's built-in sliding/fixed window rate limiter. Includes automatic memory garbage collection of expired IP buckets to prevent memory leak attacks.
|
|
787
|
+
|
|
788
|
+
- **RFC 6585 Headers:** `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, `Retry-After`
|
|
789
|
+
- **Customizable:** Configure `windowMs`, `max`, `keyGenerator` (default IP), and `skip` predicates (e.g. skip internal health checks).
|
|
790
|
+
|
|
791
|
+
```typescript
|
|
792
|
+
import { Aero, rateLimit } from 'aero';
|
|
793
|
+
|
|
794
|
+
const app = new Aero();
|
|
795
|
+
|
|
796
|
+
// Global rate limiter via convenience method:
|
|
797
|
+
app.useRateLimit({
|
|
798
|
+
windowMs: 60_000, // 1 minute
|
|
799
|
+
max: 100, // Limit each IP to 100 requests per window
|
|
800
|
+
message: { error: 'Too many requests. Please slow down!' },
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
// Or scoped rate limiting for sensitive endpoints:
|
|
804
|
+
const loginLimiter = rateLimit({
|
|
805
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
806
|
+
max: 5, // 5 login attempts per 15 minutes
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
app.post('/api/auth/login', loginLimiter, (ctx) => {
|
|
810
|
+
// Authentication logic
|
|
811
|
+
});
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
---
|
|
815
|
+
|
|
816
|
+
### 20. Security Headers & CSRF Protection (`useSecurityHeaders`, `csrf`)
|
|
817
|
+
|
|
818
|
+
Secure your HTTP responses with production-grade headers (Helmet-equivalent) and protect against Cross-Site Request Forgery (CSRF) attacks with zero external dependencies.
|
|
819
|
+
|
|
820
|
+
#### Security Headers (Helmet-like)
|
|
821
|
+
```typescript
|
|
822
|
+
import { Aero } from 'aero';
|
|
823
|
+
|
|
824
|
+
const app = new Aero();
|
|
825
|
+
|
|
826
|
+
app.useSecurityHeaders({
|
|
827
|
+
frameOptions: 'SAMEORIGIN', // Clickjacking defense
|
|
828
|
+
hsts: { maxAge: 31536000, includeSubDomains: true }, // HSTS
|
|
829
|
+
contentSecurityPolicy: {
|
|
830
|
+
defaultSrc: ["'self'"],
|
|
831
|
+
scriptSrc: ["'self'", 'https://cdn.example.com'],
|
|
832
|
+
},
|
|
833
|
+
});
|
|
834
|
+
```
|
|
835
|
+
Automatically sets:
|
|
836
|
+
- `X-Content-Type-Options: nosniff`
|
|
837
|
+
- `X-Frame-Options: SAMEORIGIN` / `DENY`
|
|
838
|
+
- `X-XSS-Protection: 0`
|
|
839
|
+
- `Strict-Transport-Security: max-age=...; includeSubDomains`
|
|
840
|
+
- `Referrer-Policy: no-referrer`
|
|
841
|
+
- `Cross-Origin-Opener-Policy: same-origin`
|
|
842
|
+
- `Cross-Origin-Resource-Policy: same-origin`
|
|
843
|
+
- Strips `X-Powered-By` header
|
|
844
|
+
|
|
845
|
+
#### CSRF Protection
|
|
846
|
+
```typescript
|
|
847
|
+
import { Aero, csrf } from 'aero';
|
|
848
|
+
|
|
849
|
+
const app = new Aero();
|
|
850
|
+
app.use(csrf());
|
|
851
|
+
|
|
852
|
+
app.get('/form', (ctx) => {
|
|
853
|
+
// ctx.csrfToken() retrieves the cryptographic CSRF token
|
|
854
|
+
ctx.html(`<form method="POST" action="/submit">
|
|
855
|
+
<input type="hidden" name="_csrf" value="${ctx.csrfToken()}">
|
|
856
|
+
<button type="submit">Submit</button>
|
|
857
|
+
</form>`);
|
|
858
|
+
});
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
---
|
|
862
|
+
|
|
863
|
+
### 21. Real-Time WebSocket Support (`app.ws`, `AeroWebSocket`)
|
|
864
|
+
|
|
865
|
+
Aero provides native RFC 6455 WebSocket support utilizing Node.js's built-in HTTP server `upgrade` event. Create real-time applications without external socket libraries or combine with existing WebSocket packages seamlessly.
|
|
866
|
+
|
|
867
|
+
```typescript
|
|
868
|
+
import { Aero } from 'aero';
|
|
869
|
+
|
|
870
|
+
const app = new Aero();
|
|
871
|
+
|
|
872
|
+
// 1. Regular HTTP route
|
|
873
|
+
app.get('/', (ctx) => ctx.text('Aero Real-Time Server'));
|
|
874
|
+
|
|
875
|
+
// 2. Real-Time WebSocket route
|
|
876
|
+
app.ws('/ws', (ws, req) => {
|
|
877
|
+
console.log('โก Client connected to /ws');
|
|
878
|
+
|
|
879
|
+
// Send message to client
|
|
880
|
+
ws.send({ event: 'welcome', message: 'Hello from Aero WebSocket!' });
|
|
881
|
+
|
|
882
|
+
// Listen for client messages
|
|
883
|
+
ws.on('message', (message) => {
|
|
884
|
+
console.log('Received:', message);
|
|
885
|
+
ws.send({ echo: message });
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
ws.on('close', () => {
|
|
889
|
+
console.log('Client disconnected');
|
|
890
|
+
});
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
app.listen(3000);
|
|
894
|
+
```
|
|
895
|
+
|
|
896
|
+
---
|
|
897
|
+
|
|
898
|
+
### 22. Active Record ORM & QueryBuilder (`Model`, `DB`, `Migrator`)
|
|
899
|
+
|
|
900
|
+
Eloquent and Lucid inspired Active Record ORM with Proxy auto-wiring, relationships, and schema migrations:
|
|
901
|
+
|
|
902
|
+
```typescript
|
|
903
|
+
import { Model, DB, Schema, Migrator } from 'aero';
|
|
904
|
+
|
|
905
|
+
// 1. Define Model with Relationships
|
|
906
|
+
class User extends Model {
|
|
907
|
+
public static override table = 'users';
|
|
908
|
+
public static override hidden = ['password'];
|
|
909
|
+
public static override softDeletes = true;
|
|
910
|
+
|
|
911
|
+
public posts() {
|
|
912
|
+
return this.hasMany(Post, 'user_id', 'id');
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
class Post extends Model {
|
|
917
|
+
public static override table = 'posts';
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// 2. Active Record Operations & Mutation via Proxy
|
|
921
|
+
const user = await User.create({ name: 'Alice', email: 'alice@aero.org' });
|
|
922
|
+
user.name = 'Alice Smith';
|
|
923
|
+
await user.save();
|
|
924
|
+
|
|
925
|
+
// 3. Eager Loading (Solves N+1 Query Problem)
|
|
926
|
+
const usersWithPosts = await User.query().with('posts').get();
|
|
927
|
+
|
|
928
|
+
// 4. Fluent QueryBuilder
|
|
929
|
+
const admins = await DB.table('users')
|
|
930
|
+
.where('role', 'admin')
|
|
931
|
+
.orderBy('id', 'DESC')
|
|
932
|
+
.paginate(1, 15);
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
---
|
|
936
|
+
|
|
937
|
+
### 23. Knex, Prisma & Drizzle ORM Integrations
|
|
938
|
+
|
|
939
|
+
First-class adapters allowing developers to choose any database query engine while enjoying full Aero integration:
|
|
940
|
+
|
|
941
|
+
```typescript
|
|
942
|
+
import Aero from 'aero';
|
|
943
|
+
import knex from 'knex';
|
|
944
|
+
import { PrismaClient } from '@prisma/client';
|
|
945
|
+
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
946
|
+
|
|
947
|
+
const app = new Aero();
|
|
948
|
+
|
|
949
|
+
// 1. Knex Integration
|
|
950
|
+
app.useKnex(knex({ client: 'pg', connection: process.env.DATABASE_URL }));
|
|
951
|
+
|
|
952
|
+
// 2. Prisma Integration
|
|
953
|
+
app.usePrisma(new PrismaClient());
|
|
954
|
+
|
|
955
|
+
// 3. Drizzle Integration
|
|
956
|
+
app.useDrizzle(drizzle(process.env.DATABASE_URL));
|
|
957
|
+
|
|
958
|
+
app.get('/users', async (ctx) => {
|
|
959
|
+
// Access via context
|
|
960
|
+
const usersKnex = await ctx.knex('users').where('active', true);
|
|
961
|
+
const usersPrisma = await ctx.prisma.user.findMany();
|
|
962
|
+
const usersDrizzle = await ctx.drizzle.select().from(...);
|
|
963
|
+
});
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
---
|
|
967
|
+
|
|
968
|
+
### 24. RFC 5424 Structured Logger (`Logger`, `RequestContext`)
|
|
969
|
+
|
|
970
|
+
Structured logger supporting 8 RFC 5424 Syslog levels, automatic RequestContext correlation via `AsyncLocalStorage`, and slow database query detection:
|
|
971
|
+
|
|
972
|
+
```typescript
|
|
973
|
+
import { Logger, requestLogger } from 'aero';
|
|
974
|
+
|
|
975
|
+
app.use(requestLogger());
|
|
976
|
+
|
|
977
|
+
app.get('/orders', async (ctx) => {
|
|
978
|
+
Logger.info('Processing order', { orderId: 452 });
|
|
979
|
+
// Automatically logs with client IP, user identity, and HTTP method/path
|
|
980
|
+
});
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
---
|
|
984
|
+
|
|
985
|
+
### 25. VineJS & Rules Validation (`Validator`, `VineHelper`)
|
|
986
|
+
|
|
987
|
+
Fast input validation with bilingual (Bengali & English) localized error messages:
|
|
988
|
+
|
|
989
|
+
```typescript
|
|
990
|
+
app.post('/register', async (ctx) => {
|
|
991
|
+
// Validates params, query, and body in one call
|
|
992
|
+
const validated = await ctx.validate({
|
|
993
|
+
name: 'required|min:3',
|
|
994
|
+
email: 'required|email|unique:users,email',
|
|
995
|
+
password: 'required|min:8|confirmed',
|
|
996
|
+
}, { locale: 'bn' }); // Returns formatted Bengali errors on 422 Unprocessable Entity
|
|
997
|
+
});
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
---
|
|
1001
|
+
|
|
1002
|
+
### 26. Next.js-Style Server-Side Rendering (`SSREngine`)
|
|
1003
|
+
|
|
1004
|
+
Server-side pre-rendering for React and Vue 3 Inertia components with automatic SEO `<head>` tag extraction:
|
|
1005
|
+
|
|
1006
|
+
```typescript
|
|
1007
|
+
app.useInertia({
|
|
1008
|
+
ssr: {
|
|
1009
|
+
components: {
|
|
1010
|
+
Home: (props) => ({
|
|
1011
|
+
head: ['<title>Home - Aero Framework</title>'],
|
|
1012
|
+
body: `<h1>Welcome, ${props.name}!</h1>`,
|
|
1013
|
+
}),
|
|
1014
|
+
},
|
|
1015
|
+
},
|
|
1016
|
+
});
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
---
|
|
1020
|
+
|
|
1021
|
+
### 27. Multi-Disk Storage & File Uploads (`Storage`, `UploadedFile`)
|
|
1022
|
+
|
|
1023
|
+
Zero-dependency RFC 7578 multipart file upload parser with multi-disk support (`local`, `s3`, `memory`):
|
|
1024
|
+
|
|
1025
|
+
```typescript
|
|
1026
|
+
import { Storage } from 'aero';
|
|
1027
|
+
|
|
1028
|
+
app.post('/upload', async (ctx) => {
|
|
1029
|
+
const avatar = ctx.file('avatar');
|
|
1030
|
+
|
|
1031
|
+
// Validate size, extensions, and MIME
|
|
1032
|
+
const check = avatar.validate({ maxSize: 2 * 1024 * 1024, extensions: ['.png', '.jpg'] });
|
|
1033
|
+
if (!check.valid) return ctx.status(422).json({ error: check.errors[0] });
|
|
1034
|
+
|
|
1035
|
+
// Store file on configured disk
|
|
1036
|
+
const path = await avatar.store('avatars', 'local');
|
|
1037
|
+
ctx.status(201).json({ url: Storage.url(path) });
|
|
1038
|
+
});
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
---
|
|
1042
|
+
|
|
1043
|
+
### 28. Background Queue & Mail System (`Queue`, `Mail`)
|
|
1044
|
+
|
|
1045
|
+
Database and memory-backed background job queue with retry backoffs, failure hooks, and fluent transactional mailing:
|
|
1046
|
+
|
|
1047
|
+
```typescript
|
|
1048
|
+
import { Queue, Job, Mail } from 'aero';
|
|
1049
|
+
|
|
1050
|
+
class SendWelcomeEmail extends Job {
|
|
1051
|
+
constructor(public email: string) { super(); this.tries = 3; }
|
|
1052
|
+
async handle() {
|
|
1053
|
+
await Mail.send(msg => {
|
|
1054
|
+
msg.to(this.email).subject('Welcome!').html('<h1>Glad to have you!</h1>');
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
// Dispatch to background queue
|
|
1060
|
+
await Queue.dispatch(new SendWelcomeEmail('user@aero.org'));
|
|
1061
|
+
|
|
1062
|
+
// Or queue mail directly
|
|
1063
|
+
await Mail.queue(msg => msg.to('user@aero.org').subject('Newsletter'));
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
---
|
|
1067
|
+
|
|
1068
|
+
### 29. OpenAPI 3.0 & Interactive Swagger UI (`useSwagger`)
|
|
1069
|
+
|
|
1070
|
+
Instant, zero-dependency interactive Swagger documentation at `/docs` with live request runner and dark theme:
|
|
1071
|
+
|
|
1072
|
+
```typescript
|
|
1073
|
+
app.useSwagger({
|
|
1074
|
+
title: 'My Project API',
|
|
1075
|
+
version: '1.0.0',
|
|
1076
|
+
route: '/docs', // Interactive Swagger UI
|
|
1077
|
+
specRoute: '/openapi.json', // OpenAPI 3.0 JSON specification
|
|
1078
|
+
security: true, // JWT Bearer auth button
|
|
1079
|
+
});
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
---
|
|
1083
|
+
|
|
1084
|
+
### 30. Aero Command-Line Interface (`aero` CLI)
|
|
1085
|
+
|
|
1086
|
+
Developer CLI tool for scaffolding boilerplate and running database migrations:
|
|
1087
|
+
|
|
1088
|
+
```bash
|
|
1089
|
+
# Display help and commands
|
|
1090
|
+
npx aero --help
|
|
1091
|
+
|
|
1092
|
+
# Generate controllers, models, and middleware
|
|
1093
|
+
npx aero make:controller UserController
|
|
1094
|
+
npx aero make:model Product -m
|
|
1095
|
+
npx aero make:middleware Authenticate
|
|
1096
|
+
npx aero make:migration create_orders_table
|
|
1097
|
+
|
|
1098
|
+
# Database migrations
|
|
1099
|
+
npx aero migrate
|
|
1100
|
+
npx aero migrate:rollback
|
|
1101
|
+
npx aero migrate:status
|
|
1102
|
+
```
|
|
1103
|
+
|
|
1104
|
+
---
|
|
1105
|
+
|
|
1106
|
+
## โก Performance, Size & Advantages
|
|
1107
|
+
|
|
1108
|
+
AeroJS is engineered from the ground up for extreme speed, minimal memory usage, zero supply-chain risk, and unmatched developer velocity.
|
|
1109
|
+
|
|
1110
|
+
### ๐ 1. Real Micro-Benchmark Throughput
|
|
1111
|
+
|
|
1112
|
+
Benchmarked on **Node.js v24 (x64)** using `npm run benchmark`:
|
|
1113
|
+
|
|
1114
|
+
| Benchmark Phase | Operations | Duration | Throughput | Complexity |
|
|
1115
|
+
|---|---|---|---|:---:|
|
|
1116
|
+
| **Radix Tree Route Lookup** | 1,000,000 | ~1,340 ms | **746,140 ops/sec** | `O(k)` |
|
|
1117
|
+
| **Onion Middleware Composition** | 1,000,000 | ~815 ms | **1,226,641 ops/sec** | `O(1)` |
|
|
1118
|
+
| **Fast JSON Serialization** | 1,000,000 | ~935 ms | **1,069,200 ops/sec** | `O(n)` |
|
|
1119
|
+
| **In-Process Request Testing** | 20,000 | ~853 ms | **23,433 reqs/sec** | Socket-Free |
|
|
1120
|
+
|
|
1121
|
+
---
|
|
1122
|
+
|
|
1123
|
+
### ๐ฆ 2. Package Size & Footprint Comparison
|
|
1124
|
+
|
|
1125
|
+
Unlike legacy Node.js frameworks that ship with bloated dependency trees, AeroJS has **ZERO runtime dependencies**.
|
|
1126
|
+
|
|
1127
|
+
| Framework | Runtime Dependencies | `node_modules` Install Size | Cold Start Time | Baseline Idle RAM |
|
|
1128
|
+
|---|:---:|:---:|:---:|:---:|
|
|
1129
|
+
| **Express** | 31 packages | ~5.2 MB | ~28 ms | ~38 MB |
|
|
1130
|
+
| **Fastify** | 16 packages | ~8.4 MB | ~24 ms | ~32 MB |
|
|
1131
|
+
| **AdonisJS** | 50+ packages | ~38 MB | ~110 ms | ~68 MB |
|
|
1132
|
+
| **NestJS (Express)** | 72 packages | ~54 MB | ~195 ms | ~85 MB |
|
|
1133
|
+
| **AeroJS** | **0 (Zero)** | **~180 KB (Self only)** | **< 4 ms** | **~16 MB** |
|
|
1134
|
+
|
|
1135
|
+
---
|
|
1136
|
+
|
|
1137
|
+
### ๐ 3. Key Advantages of AeroJS
|
|
1138
|
+
|
|
1139
|
+
#### ๐ก๏ธ 100% Zero Supply-Chain Risk
|
|
1140
|
+
- **Zero third-party code in production:** `npm audit` will always return `0 vulnerabilities`.
|
|
1141
|
+
- Completely immune to upstream dependency attacks, malicious package compromises, and breaking transitive updates.
|
|
1142
|
+
|
|
1143
|
+
#### โก Sub-Millisecond Cold Starts (< 4ms)
|
|
1144
|
+
- Because Node.js doesn't have to scan, resolve, or compile hundreds of files in `node_modules`, AeroJS boots virtually instantaneously.
|
|
1145
|
+
- Ideal for **Serverless environments** (AWS Lambda, Cloudflare Containers, Vercel Serverless, Google Cloud Run) and autoscaling Docker microservices.
|
|
1146
|
+
|
|
1147
|
+
#### ๐๏ธ Lightning-Fast CI/CD Deployments
|
|
1148
|
+
- `npm install aero` downloads only a few kilobytes and completes in **1โ2 seconds**, drastically cutting down pipeline build times and bandwidth costs.
|
|
1149
|
+
|
|
1150
|
+
#### ๐ Unified Full-Stack Architecture
|
|
1151
|
+
- Eliminates context switching and multi-repository overhead: build **REST APIs**, **React/Vue 3 SPAs (Inertia.js)**, and traditional **SSR Views (Edge.js/EJS)** in a single cohesive codebase.
|
|
1152
|
+
|
|
1153
|
+
#### ๐งช Socket-Free In-Process Testing (`aero/testing`)
|
|
1154
|
+
- Write unit and integration tests that run at **>23,000 requests/second** without opening TCP sockets, eliminating OS port collisions, firewall popups, and socket leaks.
|
|
1155
|
+
|
|
1156
|
+
---
|
|
1157
|
+
|
|
1158
|
+
## ๐ Comparison Matrix
|
|
1159
|
+
|
|
1160
|
+
| Feature | Express | Koa | Fastify | AdonisJS | **Aero** |
|
|
1161
|
+
|---|:---:|:---:|:---:|:---:|:---:|
|
|
1162
|
+
| **Zero Runtime Dependencies** | โ (30+) | โ (20+) | โ (15+) | โ (50+) | **โ
ZERO** |
|
|
1163
|
+
| **Radix Tree Routing** | โ | โ | โ
| โ | **โ
O(k)** |
|
|
1164
|
+
| **Onion Middleware (`await next()`)** | โ | โ
| โ | โ
| **โ
** |
|
|
1165
|
+
| **Lifecycle Hooks (8 stages)** | โ | โ | โ
| โ | **โ
** |
|
|
1166
|
+
| **Built-in IoC Container** | โ | โ | โ | โ
| **โ
** |
|
|
1167
|
+
| **Class-Based Controllers** | โ | โ | โ | โ
| **โ
** |
|
|
1168
|
+
| **Route Groups & Fluent Builder** | โ | โ | โ | โ
| **โ
** |
|
|
1169
|
+
| **Schema Validation & Fast JSON** | โ | โ | โ
| โ | **โ
Built-in** |
|
|
1170
|
+
| **Encapsulated Plugin Architecture** | โ | โ | โ
| โ | **โ
** |
|
|
1171
|
+
| **In-Process Testing Client** | โ | โ | โ
(`inject`) | โ | **โ
(`aero/testing`)** |
|
|
1172
|
+
| **Static & SPA Fallback Serving** | โ (external) | โ (external) | โ (plugin) | โ (plugin) | **โ
Built-in** |
|
|
1173
|
+
| **Zero-Dependency CORS** | โ (external) | โ (external) | โ (plugin) | โ (package) | **โ
Built-in** |
|
|
1174
|
+
| **SSR Views (Edge.js, EJS)** | โ (external) | โ (external) | โ (plugin) | โ
(Edge) | **โ
Unified** |
|
|
1175
|
+
| **First-Class Inertia.js Adapter**| โ (community) | โ (community) | โ (community) | โ
(package) | **โ
Built-in** |
|
|
1176
|
+
|
|
1177
|
+
> [!NOTE]
|
|
1178
|
+
> **Design Philosophy Note:**
|
|
1179
|
+
> Express, Koa, Fastify, and AdonisJS are battle-tested giants that deeply inspired AeroJS. While those frameworks achieve many of these capabilities through extensive third-party plugins and ecosystem packages, AeroJS is uniquely architected to provide these full-stack features **out-of-the-box with ZERO runtime dependencies**.
|
|
1180
|
+
|
|
1181
|
+
---
|
|
1182
|
+
|
|
1183
|
+
## ๐ License
|
|
1184
|
+
|
|
1185
|
+
[MIT](LICENSE) ยฉ 2026 Aero Core Team.
|
|
1186
|
+
|