@zintrust/core 0.1.19 → 0.1.21
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 +10 -10
- package/bin/zintrust-main.d.ts.map +1 -1
- package/bin/zintrust-main.js +9 -0
- package/package.json +3 -2
- package/public/error-pages/404.html +145 -0
- package/public/error-pages/500.html +266 -0
- package/public/error-pages/error.css +628 -0
- package/public/error-pages/error.js +428 -0
- package/public/zintrust.svg +30 -0
- package/routes/api.d.ts.map +1 -1
- package/routes/api.js +41 -17
- package/routes/metrics.d.ts +9 -0
- package/routes/metrics.d.ts.map +1 -0
- package/routes/metrics.js +20 -0
- package/routes/openapi.d.ts +9 -0
- package/routes/openapi.d.ts.map +1 -0
- package/routes/openapi.js +76 -0
- package/src/boot/Application.d.ts +2 -2
- package/src/boot/Application.d.ts.map +1 -1
- package/src/boot/Application.js +66 -13
- package/src/boot/Server.d.ts +3 -2
- package/src/boot/Server.d.ts.map +1 -1
- package/src/boot/Server.js +39 -165
- package/src/boot/bootstrap.js +2 -0
- package/src/cache/Cache.d.ts +1 -1
- package/src/cache/Cache.d.ts.map +1 -1
- package/src/cache/CacheDriver.d.ts +4 -0
- package/src/cache/CacheDriver.d.ts.map +1 -1
- package/src/cache/drivers/KVDriver.d.ts +1 -1
- package/src/cache/drivers/KVDriver.d.ts.map +1 -1
- package/src/cache/drivers/MemoryDriver.d.ts +1 -1
- package/src/cache/drivers/MemoryDriver.d.ts.map +1 -1
- package/src/cache/drivers/MemoryDriver.js +16 -0
- package/src/cache/drivers/MongoDriver.d.ts +1 -1
- package/src/cache/drivers/MongoDriver.d.ts.map +1 -1
- package/src/cache/drivers/RedisDriver.d.ts +1 -1
- package/src/cache/drivers/RedisDriver.d.ts.map +1 -1
- package/src/cli/CLI.d.ts.map +1 -1
- package/src/cli/CLI.js +10 -4
- package/src/cli/commands/AddCommand.d.ts +2 -2
- package/src/cli/commands/AddCommand.d.ts.map +1 -1
- package/src/cli/commands/AddCommand.js +135 -58
- package/src/cli/commands/ConfigCommand.d.ts +1 -1
- package/src/cli/commands/ConfigCommand.d.ts.map +1 -1
- package/src/cli/commands/CreateCommand.d.ts +15 -0
- package/src/cli/commands/CreateCommand.d.ts.map +1 -0
- package/src/cli/commands/CreateCommand.js +143 -0
- package/src/cli/commands/D1MigrateCommand.d.ts +1 -1
- package/src/cli/commands/D1MigrateCommand.d.ts.map +1 -1
- package/src/cli/commands/D1MigrateCommand.js +16 -20
- package/src/cli/commands/DbSeedCommand.d.ts +9 -0
- package/src/cli/commands/DbSeedCommand.d.ts.map +1 -0
- package/src/cli/commands/DbSeedCommand.js +171 -0
- package/src/cli/commands/DebugCommand.d.ts +1 -1
- package/src/cli/commands/DebugCommand.d.ts.map +1 -1
- package/src/cli/commands/FixCommand.d.ts +1 -1
- package/src/cli/commands/FixCommand.d.ts.map +1 -1
- package/src/cli/commands/JwtDevCommand.d.ts +8 -0
- package/src/cli/commands/JwtDevCommand.d.ts.map +1 -0
- package/src/cli/commands/JwtDevCommand.js +114 -0
- package/src/cli/commands/KeyGenerateCommand.d.ts +1 -1
- package/src/cli/commands/KeyGenerateCommand.d.ts.map +1 -1
- package/src/cli/commands/LogsCommand.d.ts +2 -2
- package/src/cli/commands/LogsCommand.d.ts.map +1 -1
- package/src/cli/commands/LogsCommand.js +36 -2
- package/src/cli/commands/MakeMailTemplateCommand.d.ts +1 -1
- package/src/cli/commands/MakeMailTemplateCommand.d.ts.map +1 -1
- package/src/cli/commands/MakeNotificationTemplateCommand.d.ts +1 -1
- package/src/cli/commands/MakeNotificationTemplateCommand.d.ts.map +1 -1
- package/src/cli/commands/MigrateCommand.d.ts +1 -1
- package/src/cli/commands/MigrateCommand.d.ts.map +1 -1
- package/src/cli/commands/MigrateCommand.js +324 -35
- package/src/cli/commands/NewCommand.d.ts +1 -1
- package/src/cli/commands/NewCommand.d.ts.map +1 -1
- package/src/cli/commands/NewCommand.js +12 -4
- package/src/cli/commands/PluginCommand.d.ts +1 -1
- package/src/cli/commands/PluginCommand.d.ts.map +1 -1
- package/src/cli/commands/PrepareCommand.d.ts +1 -1
- package/src/cli/commands/PrepareCommand.d.ts.map +1 -1
- package/src/cli/commands/QACommand.d.ts +2 -2
- package/src/cli/commands/QACommand.d.ts.map +1 -1
- package/src/cli/commands/RoutesCommand.d.ts +10 -0
- package/src/cli/commands/RoutesCommand.d.ts.map +1 -0
- package/src/cli/commands/RoutesCommand.js +242 -0
- package/src/cli/commands/SimulateCommand.d.ts +1 -1
- package/src/cli/commands/SimulateCommand.d.ts.map +1 -1
- package/src/cli/commands/index.d.ts +3 -0
- package/src/cli/commands/index.d.ts.map +1 -1
- package/src/cli/commands/index.js +3 -0
- package/src/cli/config/ConfigManager.d.ts +1 -1
- package/src/cli/config/ConfigManager.d.ts.map +1 -1
- package/src/cli/config/ConfigValidator.d.ts +1 -1
- package/src/cli/config/ConfigValidator.d.ts.map +1 -1
- package/src/cli/config/ConfigValidator.js +1 -1
- package/src/cli/d1/D1SqlMigrations.d.ts +20 -0
- package/src/cli/d1/D1SqlMigrations.d.ts.map +1 -0
- package/src/cli/d1/D1SqlMigrations.js +229 -0
- package/src/cli/d1/WranglerConfig.d.ts +4 -0
- package/src/cli/d1/WranglerConfig.d.ts.map +1 -0
- package/src/cli/d1/WranglerConfig.js +122 -0
- package/src/cli/d1/WranglerD1.d.ts +11 -0
- package/src/cli/d1/WranglerD1.d.ts.map +1 -0
- package/src/cli/d1/WranglerD1.js +16 -0
- package/src/cli/scaffolding/ControllerGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/ControllerGenerator.js +76 -26
- package/src/cli/scaffolding/FactoryGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/FactoryGenerator.js +3 -1
- package/src/cli/scaffolding/GovernanceScaffolder.d.ts +23 -0
- package/src/cli/scaffolding/GovernanceScaffolder.d.ts.map +1 -0
- package/src/cli/scaffolding/GovernanceScaffolder.js +327 -0
- package/src/cli/scaffolding/MigrationGenerator.d.ts +10 -0
- package/src/cli/scaffolding/MigrationGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/MigrationGenerator.js +137 -51
- package/src/cli/scaffolding/ModelGenerator.js +1 -1
- package/src/cli/scaffolding/ProjectScaffolder.d.ts.map +1 -1
- package/src/cli/scaffolding/ProjectScaffolder.js +36 -4
- package/src/cli/scaffolding/RouteGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/RouteGenerator.js +79 -43
- package/src/cli/scaffolding/SeederGenerator.d.ts +5 -0
- package/src/cli/scaffolding/SeederGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/SeederGenerator.js +63 -15
- package/src/cli/scaffolding/ServiceScaffolder.d.ts.map +1 -1
- package/src/cli/scaffolding/ServiceScaffolder.js +28 -7
- package/src/cli/scaffolding/index.d.ts +2 -0
- package/src/cli/scaffolding/index.d.ts.map +1 -1
- package/src/cli/scaffolding/index.js +1 -0
- package/src/common/index.d.ts +8 -0
- package/src/common/index.d.ts.map +1 -1
- package/src/common/index.js +28 -0
- package/src/common/utility.d.ts +38 -0
- package/src/common/utility.d.ts.map +1 -0
- package/src/common/utility.js +101 -0
- package/src/config/FileLogWriter.d.ts +2 -1
- package/src/config/FileLogWriter.d.ts.map +1 -1
- package/src/config/FileLogWriter.js +83 -2
- package/src/config/app.d.ts.map +1 -1
- package/src/config/app.js +3 -1
- package/src/config/broadcast.d.ts +14 -28
- package/src/config/broadcast.d.ts.map +1 -1
- package/src/config/broadcast.js +69 -35
- package/src/config/cache.d.ts +13 -45
- package/src/config/cache.d.ts.map +1 -1
- package/src/config/cache.js +69 -25
- package/src/config/cloudflare.d.ts +1 -1
- package/src/config/cloudflare.d.ts.map +1 -1
- package/src/config/database.d.ts +22 -64
- package/src/config/database.d.ts.map +1 -1
- package/src/config/database.js +191 -37
- package/src/config/env.d.ts +12 -0
- package/src/config/env.d.ts.map +1 -1
- package/src/config/env.js +14 -0
- package/src/config/index.d.ts +33 -137
- package/src/config/index.d.ts.map +1 -1
- package/src/config/logging/KvLogger.js +1 -1
- package/src/config/logging/SlackLogger.js +2 -2
- package/src/config/mail.d.ts +19 -55
- package/src/config/mail.d.ts.map +1 -1
- package/src/config/mail.js +63 -21
- package/src/config/middleware.d.ts +44 -1
- package/src/config/middleware.d.ts.map +1 -1
- package/src/config/middleware.js +157 -5
- package/src/config/notification.d.ts +14 -27
- package/src/config/notification.d.ts.map +1 -1
- package/src/config/notification.js +82 -36
- package/src/config/queue.d.ts +21 -51
- package/src/config/queue.d.ts.map +1 -1
- package/src/config/queue.js +72 -27
- package/src/config/security.d.ts +1 -1
- package/src/config/security.js +1 -1
- package/src/config/storage.d.ts +27 -34
- package/src/config/storage.d.ts.map +1 -1
- package/src/config/storage.js +97 -56
- package/src/config/type.d.ts +13 -2
- package/src/config/type.d.ts.map +1 -1
- package/src/events/EventDispatcher.d.ts.map +1 -1
- package/src/events/EventDispatcher.js +6 -4
- package/src/exceptions/ZintrustError.d.ts +7 -0
- package/src/exceptions/ZintrustError.d.ts.map +1 -1
- package/src/exceptions/ZintrustError.js +56 -0
- package/src/features/Auth.d.ts +1 -1
- package/src/features/Auth.d.ts.map +1 -1
- package/src/features/Auth.js +3 -3
- package/src/features/Queue.js +1 -1
- package/src/functions/cloudflare.d.ts.map +1 -1
- package/src/functions/cloudflare.js +3 -14
- package/src/functions/deno.d.ts.map +1 -1
- package/src/functions/deno.js +3 -14
- package/src/functions/lambda.d.ts.map +1 -1
- package/src/functions/lambda.js +3 -14
- package/src/health/StartupHealthChecks.js +1 -1
- package/src/http/Controller.d.ts +2 -2
- package/src/http/Controller.d.ts.map +1 -1
- package/src/http/FileUpload.d.ts +68 -0
- package/src/http/FileUpload.d.ts.map +1 -0
- package/src/http/FileUpload.js +120 -0
- package/src/http/Kernel.d.ts +5 -5
- package/src/http/Kernel.d.ts.map +1 -1
- package/src/http/Kernel.js +139 -23
- package/src/http/Request.d.ts +20 -1
- package/src/http/Request.d.ts.map +1 -1
- package/src/http/Request.js +23 -0
- package/src/http/RequestContext.d.ts +6 -0
- package/src/http/RequestContext.d.ts.map +1 -1
- package/src/http/RequestContext.js +77 -1
- package/src/http/Response.d.ts +1 -1
- package/src/http/Response.d.ts.map +1 -1
- package/src/http/ValidationHelper.d.ts +78 -0
- package/src/http/ValidationHelper.d.ts.map +1 -0
- package/src/http/ValidationHelper.js +121 -0
- package/src/http/error-pages/ErrorPageRenderer.d.ts +17 -0
- package/src/http/error-pages/ErrorPageRenderer.d.ts.map +1 -0
- package/src/http/error-pages/ErrorPageRenderer.js +88 -0
- package/src/http/middleware/BodyParsingMiddleware.d.ts +12 -0
- package/src/http/middleware/BodyParsingMiddleware.d.ts.map +1 -0
- package/src/http/middleware/BodyParsingMiddleware.js +251 -0
- package/src/http/middleware/FileUploadMiddleware.d.ts +12 -0
- package/src/http/middleware/FileUploadMiddleware.d.ts.map +1 -0
- package/src/http/middleware/FileUploadMiddleware.js +74 -0
- package/src/http/parsers/BodyParsers.d.ts +32 -0
- package/src/http/parsers/BodyParsers.d.ts.map +1 -0
- package/src/http/parsers/BodyParsers.js +159 -0
- package/src/http/parsers/MultipartParser.d.ts +33 -0
- package/src/http/parsers/MultipartParser.d.ts.map +1 -0
- package/src/http/parsers/MultipartParser.js +156 -0
- package/src/http/parsers/MultipartParserRegistry.d.ts +34 -0
- package/src/http/parsers/MultipartParserRegistry.d.ts.map +1 -0
- package/src/http/parsers/MultipartParserRegistry.js +20 -0
- package/src/http/validated.d.ts +12 -0
- package/src/http/validated.d.ts.map +1 -0
- package/src/http/validated.js +41 -0
- package/src/index.d.ts +73 -12
- package/src/index.d.ts.map +1 -1
- package/src/index.js +60 -5
- package/src/microservices/PostgresAdapter.d.ts.map +1 -1
- package/src/microservices/PostgresAdapter.js +0 -1
- package/src/microservices/RequestTracingMiddleware.d.ts +2 -2
- package/src/microservices/RequestTracingMiddleware.d.ts.map +1 -1
- package/src/microservices/RequestTracingMiddleware.js +3 -0
- package/src/microservices/ServiceAuthMiddleware.d.ts +2 -2
- package/src/microservices/ServiceAuthMiddleware.d.ts.map +1 -1
- package/src/middleware/AuthMiddleware.d.ts +10 -0
- package/src/middleware/AuthMiddleware.d.ts.map +1 -0
- package/src/middleware/AuthMiddleware.js +16 -0
- package/src/middleware/CsrfMiddleware.d.ts +11 -1
- package/src/middleware/CsrfMiddleware.d.ts.map +1 -1
- package/src/middleware/CsrfMiddleware.js +33 -0
- package/src/middleware/JwtAuthMiddleware.d.ts +11 -0
- package/src/middleware/JwtAuthMiddleware.d.ts.map +1 -0
- package/src/middleware/JwtAuthMiddleware.js +73 -0
- package/src/middleware/LoggingMiddleware.d.ts.map +1 -1
- package/src/middleware/LoggingMiddleware.js +8 -3
- package/src/middleware/MiddlewareStack.d.ts +2 -2
- package/src/middleware/MiddlewareStack.d.ts.map +1 -1
- package/src/middleware/RateLimiter.d.ts +2 -2
- package/src/middleware/RateLimiter.d.ts.map +1 -1
- package/src/middleware/SanitizeBodyMiddleware.d.ts +12 -0
- package/src/middleware/SanitizeBodyMiddleware.d.ts.map +1 -0
- package/src/middleware/SanitizeBodyMiddleware.js +31 -0
- package/src/middleware/SecurityMiddleware.d.ts +1 -1
- package/src/middleware/SecurityMiddleware.d.ts.map +1 -1
- package/src/middleware/SessionMiddleware.d.ts +1 -1
- package/src/middleware/SessionMiddleware.d.ts.map +1 -1
- package/src/middleware/ValidationMiddleware.d.ts +25 -0
- package/src/middleware/ValidationMiddleware.d.ts.map +1 -0
- package/src/middleware/ValidationMiddleware.js +251 -0
- package/src/migrations/MigrationDiscovery.d.ts +5 -0
- package/src/migrations/MigrationDiscovery.d.ts.map +1 -0
- package/src/migrations/MigrationDiscovery.js +16 -0
- package/src/migrations/MigrationLoader.d.ts +5 -0
- package/src/migrations/MigrationLoader.d.ts.map +1 -0
- package/src/migrations/MigrationLoader.js +43 -0
- package/src/migrations/MigrationLock.d.ts +4 -0
- package/src/migrations/MigrationLock.d.ts.map +1 -0
- package/src/migrations/MigrationLock.js +33 -0
- package/src/migrations/Migrator.d.ts +23 -0
- package/src/migrations/Migrator.d.ts.map +1 -0
- package/src/migrations/Migrator.js +4 -0
- package/src/migrations/MigratorFactory.d.ts +25 -0
- package/src/migrations/MigratorFactory.d.ts.map +1 -0
- package/src/migrations/MigratorFactory.js +339 -0
- package/src/migrations/schema/Blueprint.d.ts +5 -0
- package/src/migrations/schema/Blueprint.d.ts.map +1 -0
- package/src/migrations/schema/Blueprint.js +189 -0
- package/src/migrations/schema/Schema.d.ts +8 -0
- package/src/migrations/schema/Schema.d.ts.map +1 -0
- package/src/migrations/schema/Schema.js +141 -0
- package/src/migrations/schema/SchemaCompiler.d.ts +20 -0
- package/src/migrations/schema/SchemaCompiler.d.ts.map +1 -0
- package/src/migrations/schema/SchemaCompiler.js +262 -0
- package/src/migrations/schema/index.d.ts +5 -0
- package/src/migrations/schema/index.d.ts.map +1 -0
- package/src/migrations/schema/index.js +3 -0
- package/src/migrations/schema/types.d.ts +86 -0
- package/src/migrations/schema/types.d.ts.map +1 -0
- package/src/migrations/schema/types.js +1 -0
- package/src/migrations/types.d.ts +45 -0
- package/src/migrations/types.d.ts.map +1 -0
- package/src/migrations/types.js +1 -0
- package/src/node-singletons/crypto.d.ts +1 -1
- package/src/node-singletons/crypto.d.ts.map +1 -1
- package/src/node-singletons/crypto.js +1 -1
- package/src/node-singletons/fs.d.ts +2 -2
- package/src/node-singletons/fs.d.ts.map +1 -1
- package/src/node-singletons/fs.js +1 -1
- package/src/node-singletons/util.d.ts +6 -0
- package/src/node-singletons/util.d.ts.map +1 -0
- package/src/node-singletons/util.js +5 -0
- package/src/node.d.ts +3 -1
- package/src/node.d.ts.map +1 -1
- package/src/node.js +6 -2
- package/src/observability/OpenTelemetry.d.ts +62 -0
- package/src/observability/OpenTelemetry.d.ts.map +1 -0
- package/src/observability/OpenTelemetry.js +167 -0
- package/src/observability/PrometheusMetrics.d.ts +25 -0
- package/src/observability/PrometheusMetrics.d.ts.map +1 -0
- package/src/observability/PrometheusMetrics.js +114 -0
- package/src/openapi/OpenApiGenerator.d.ts +68 -0
- package/src/openapi/OpenApiGenerator.d.ts.map +1 -0
- package/src/openapi/OpenApiGenerator.js +287 -0
- package/src/orm/Database.d.ts +5 -2
- package/src/orm/Database.d.ts.map +1 -1
- package/src/orm/Database.js +219 -63
- package/src/orm/DatabaseAdapter.d.ts +14 -0
- package/src/orm/DatabaseAdapter.d.ts.map +1 -1
- package/src/orm/DatabaseAdapterRegistry.d.ts.map +1 -1
- package/src/orm/DatabaseAdapterRegistry.js +3 -1
- package/src/orm/DatabaseRuntimeRegistration.d.ts.map +1 -1
- package/src/orm/DatabaseRuntimeRegistration.js +12 -0
- package/src/orm/Model.d.ts +30 -2
- package/src/orm/Model.d.ts.map +1 -1
- package/src/orm/Model.js +255 -62
- package/src/orm/QueryBuilder.d.ts +22 -1
- package/src/orm/QueryBuilder.d.ts.map +1 -1
- package/src/orm/QueryBuilder.js +406 -99
- package/src/orm/Relationships.d.ts +7 -1
- package/src/orm/Relationships.d.ts.map +1 -1
- package/src/orm/Relationships.js +18 -0
- package/src/orm/SchemaCompiler.d.ts +9 -0
- package/src/orm/SchemaCompiler.d.ts.map +1 -0
- package/src/orm/SchemaCompiler.js +145 -0
- package/src/orm/adapters/D1Adapter.d.ts +1 -1
- package/src/orm/adapters/D1Adapter.d.ts.map +1 -1
- package/src/orm/adapters/MySQLAdapter.d.ts +1 -1
- package/src/orm/adapters/MySQLAdapter.d.ts.map +1 -1
- package/src/orm/adapters/MySQLAdapter.js +88 -69
- package/src/orm/adapters/PostgreSQLAdapter.d.ts +1 -1
- package/src/orm/adapters/PostgreSQLAdapter.d.ts.map +1 -1
- package/src/orm/adapters/PostgreSQLAdapter.js +88 -69
- package/src/orm/adapters/SQLServerAdapter.d.ts +1 -1
- package/src/orm/adapters/SQLServerAdapter.d.ts.map +1 -1
- package/src/orm/adapters/SQLiteAdapter.d.ts +1 -1
- package/src/orm/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/src/orm/adapters/SQLiteAdapter.js +59 -3
- package/src/orm/maintenance/SqliteMaintenance.d.ts +5 -0
- package/src/orm/maintenance/SqliteMaintenance.d.ts.map +1 -0
- package/src/orm/maintenance/SqliteMaintenance.js +14 -0
- package/src/orm/migrations/MigrationStore.d.ts +38 -0
- package/src/orm/migrations/MigrationStore.d.ts.map +1 -0
- package/src/orm/migrations/MigrationStore.js +157 -0
- package/src/performance/CodeGenerationBenchmark.d.ts.map +1 -1
- package/src/performance/Optimizer.d.ts +7 -6
- package/src/performance/Optimizer.d.ts.map +1 -1
- package/src/performance/Optimizer.js +170 -55
- package/src/profiling/MemoryProfiler.d.ts +1 -1
- package/src/profiling/MemoryProfiler.d.ts.map +1 -1
- package/src/profiling/N1Detector.d.ts +1 -1
- package/src/profiling/N1Detector.d.ts.map +1 -1
- package/src/profiling/QueryLogger.d.ts +1 -1
- package/src/profiling/QueryLogger.d.ts.map +1 -1
- package/src/profiling/RequestProfiler.d.ts +3 -3
- package/src/profiling/RequestProfiler.d.ts.map +1 -1
- package/src/routes/metrics.d.ts +2 -0
- package/src/routes/metrics.d.ts.map +1 -0
- package/src/routes/metrics.js +1 -0
- package/src/routing/CoreRoutes.d.ts +12 -0
- package/src/routing/CoreRoutes.d.ts.map +1 -0
- package/src/routing/CoreRoutes.js +151 -0
- package/src/routing/RouteRegistry.d.ts +39 -0
- package/src/routing/RouteRegistry.d.ts.map +1 -0
- package/src/routing/RouteRegistry.js +44 -0
- package/src/routing/Router.d.ts +26 -9
- package/src/routing/Router.d.ts.map +1 -1
- package/src/routing/Router.js +79 -35
- package/src/routing/common.d.ts +15 -0
- package/src/routing/common.d.ts.map +1 -0
- package/src/routing/common.js +47 -0
- package/src/routing/doc.d.ts +27 -0
- package/src/routing/doc.d.ts.map +1 -0
- package/src/routing/doc.js +110 -0
- package/src/routing/error.d.ts +21 -0
- package/src/routing/error.d.ts.map +1 -0
- package/src/routing/error.js +126 -0
- package/src/routing/errorPages.d.ts +14 -0
- package/src/routing/errorPages.d.ts.map +1 -0
- package/src/routing/errorPages.js +103 -0
- package/src/routing/publicRoot.d.ts +27 -0
- package/src/routing/publicRoot.d.ts.map +1 -0
- package/src/routing/publicRoot.js +110 -0
- package/src/runtime/PluginAutoImports.d.ts +21 -0
- package/src/runtime/PluginAutoImports.d.ts.map +1 -0
- package/src/runtime/PluginAutoImports.js +59 -0
- package/src/runtime/PluginManager.d.ts +1 -5
- package/src/runtime/PluginManager.d.ts.map +1 -1
- package/src/runtime/PluginManager.js +25 -18
- package/src/runtime/RuntimeDetector.d.ts +1 -1
- package/src/runtime/RuntimeDetector.d.ts.map +1 -1
- package/src/runtime/StartupConfigFileRegistry.d.ts +20 -0
- package/src/runtime/StartupConfigFileRegistry.d.ts.map +1 -0
- package/src/runtime/StartupConfigFileRegistry.js +44 -0
- package/src/runtime/adapters/CloudflareAdapter.d.ts +1 -1
- package/src/runtime/adapters/CloudflareAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/CloudflareAdapter.js +1 -1
- package/src/runtime/adapters/DenoAdapter.d.ts +1 -1
- package/src/runtime/adapters/DenoAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/DenoAdapter.js +1 -1
- package/src/runtime/adapters/LambdaAdapter.d.ts +1 -1
- package/src/runtime/adapters/LambdaAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/LambdaAdapter.js +1 -1
- package/src/runtime/adapters/NodeServerAdapter.d.ts +1 -1
- package/src/runtime/adapters/NodeServerAdapter.d.ts.map +1 -1
- package/src/runtime/getKernel.d.ts +9 -0
- package/src/runtime/getKernel.d.ts.map +1 -0
- package/src/runtime/getKernel.js +27 -0
- package/src/runtime/useFileLoader.d.ts +26 -0
- package/src/runtime/useFileLoader.d.ts.map +1 -0
- package/src/runtime/useFileLoader.js +188 -0
- package/src/scripts/TemplateImportsCheck.js +40 -0
- package/src/scripts/TemplateSync.js +90 -24
- package/src/security/Encryptor.d.ts.map +1 -1
- package/src/security/Encryptor.js +64 -7
- package/src/security/JwtManager.d.ts +1 -0
- package/src/security/JwtManager.d.ts.map +1 -1
- package/src/security/JwtManager.js +33 -0
- package/src/security/Sanitizer.d.ts +76 -0
- package/src/security/Sanitizer.d.ts.map +1 -0
- package/src/security/Sanitizer.js +412 -0
- package/src/security/TokenRevocation.d.ts +7 -0
- package/src/security/TokenRevocation.d.ts.map +1 -0
- package/src/security/TokenRevocation.js +57 -0
- package/src/security/XssProtection.d.ts.map +1 -1
- package/src/security/XssProtection.js +62 -14
- package/src/seeders/SeederDiscovery.d.ts +5 -0
- package/src/seeders/SeederDiscovery.d.ts.map +1 -0
- package/src/seeders/SeederDiscovery.js +21 -0
- package/src/seeders/SeederLoader.d.ts +5 -0
- package/src/seeders/SeederLoader.d.ts.map +1 -0
- package/src/seeders/SeederLoader.js +60 -0
- package/src/seeders/types.d.ts +18 -0
- package/src/seeders/types.d.ts.map +1 -0
- package/src/seeders/types.js +1 -0
- package/src/session/SessionManager.js +1 -1
- package/src/templates/adapters/MySQLAdapter.ts.tpl +109 -85
- package/src/templates/adapters/PostgreSQLAdapter.ts.tpl +129 -88
- package/src/templates/adapters/SQLServerAdapter.ts.tpl +5 -9
- package/src/templates/adapters/SQLiteAdapter.ts.tpl +78 -11
- package/src/templates/features/Queue.ts.tpl +3 -2
- package/src/templates/project/basic/app/Controllers/AuthController.ts.tpl +217 -0
- package/src/templates/project/basic/app/Controllers/UserController.ts.tpl +1 -12
- package/src/templates/project/basic/app/Types/controller.ts.tpl +46 -0
- package/src/templates/project/basic/config/FileLogWriter.ts.tpl +5 -236
- package/src/templates/project/basic/config/SecretsManager.ts.tpl +10 -447
- package/src/templates/project/basic/config/StartupConfigValidator.ts.tpl +9 -268
- package/src/templates/project/basic/config/app.ts.tpl +13 -153
- package/src/templates/project/basic/config/broadcast.ts.tpl +29 -126
- package/src/templates/project/basic/config/cache.ts.tpl +12 -70
- package/src/templates/project/basic/config/cloudflare.ts.tpl +4 -39
- package/src/templates/project/basic/config/constants.ts.tpl +9 -65
- package/src/templates/project/basic/config/database.ts.tpl +66 -123
- package/src/templates/project/basic/config/env.ts.tpl +5 -169
- package/src/templates/project/basic/config/features.ts.tpl +6 -54
- package/src/templates/project/basic/config/index.ts.tpl +8 -23
- package/src/templates/project/basic/config/logging/HttpLogger.ts.tpl +7 -114
- package/src/templates/project/basic/config/mail.ts.tpl +9 -62
- package/src/templates/project/basic/config/microservices.ts.tpl +11 -97
- package/src/templates/project/basic/config/middleware.ts.tpl +25 -43
- package/src/templates/project/basic/config/notification.ts.tpl +13 -114
- package/src/templates/project/basic/config/queue.ts.tpl +9 -40
- package/src/templates/project/basic/config/security.ts.tpl +11 -163
- package/src/templates/project/basic/config/startup.ts.tpl +10 -21
- package/src/templates/project/basic/config/storage.ts.tpl +57 -137
- package/src/templates/project/basic/config/type.ts.tpl +32 -451
- package/src/templates/project/basic/database/factories/UserFactory.ts.tpl +80 -0
- package/src/templates/project/basic/database/migrations/create_tasks_table.ts.tpl +28 -0
- package/src/templates/project/basic/database/migrations/create_users_table.ts.tpl +29 -0
- package/src/templates/project/basic/database/seeders/DatabaseSeeder.ts.tpl +19 -0
- package/src/templates/project/basic/database/seeders/UserSeeder.ts.tpl +18 -0
- package/src/templates/project/basic/database/seeders/index.ts.tpl +2 -0
- package/src/templates/project/basic/routes/api.ts.tpl +71 -33
- package/src/templates/project/basic/routes/metrics.ts.tpl +22 -0
- package/src/templates/project/basic/src/index.ts.tpl +3 -0
- package/src/templates/project/basic/tsconfig.json.tpl +12 -11
- package/src/testing/TestEnvironment.d.ts +40 -0
- package/src/testing/TestEnvironment.d.ts.map +1 -0
- package/src/testing/TestEnvironment.js +141 -0
- package/src/testing/TestHttp.d.ts +29 -0
- package/src/testing/TestHttp.d.ts.map +1 -0
- package/src/testing/TestHttp.js +96 -0
- package/src/testing/index.d.ts +5 -0
- package/src/testing/index.d.ts.map +1 -0
- package/src/testing/index.js +2 -0
- package/src/time/DateTime.d.ts +181 -0
- package/src/time/DateTime.d.ts.map +1 -0
- package/src/time/DateTime.js +300 -0
- package/src/time/index.d.ts +7 -0
- package/src/time/index.d.ts.map +1 -0
- package/src/time/index.js +5 -0
- package/src/tools/http/Http.d.ts.map +1 -1
- package/src/tools/http/Http.js +4 -0
- package/src/tools/mail/drivers/Smtp.js +1 -1
- package/src/tools/queue/drivers/InMemory.d.ts +1 -1
- package/src/tools/queue/drivers/InMemory.d.ts.map +1 -1
- package/src/tools/queue/drivers/InMemory.js +1 -1
- package/src/tools/queue/drivers/Redis.d.ts +1 -1
- package/src/tools/queue/drivers/Redis.d.ts.map +1 -1
- package/src/tools/queue/drivers/Redis.js +1 -1
- package/src/validation/ValidationError.d.ts.map +1 -1
- package/src/validation/ValidationError.js +4 -2
- package/src/validation/Validator.d.ts +49 -16
- package/src/validation/Validator.d.ts.map +1 -1
- package/src/validation/Validator.js +307 -5
- package/src/common/uuid.d.ts +0 -3
- package/src/common/uuid.d.ts.map +0 -1
- package/src/common/uuid.js +0 -30
- package/src/templates/project/basic/.env.example.tpl +0 -74
- package/src/templates/project/basic/.env.tpl +0 -166
- package/src/templates/project/basic/config/logging/KvLogger.ts.tpl +0 -181
- package/src/templates/project/basic/config/logging/SlackLogger.ts.tpl +0 -156
- package/src/templates/project/basic/database/migrations/index.ts.tpl +0 -2
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Helper
|
|
3
|
+
* Utilities for working with validated request data
|
|
4
|
+
*/
|
|
5
|
+
import { ErrorFactory } from '../exceptions/ZintrustError.js';
|
|
6
|
+
const getValidated = (req) => {
|
|
7
|
+
return req.validated;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Extract validated body from request
|
|
11
|
+
* Returns the validated body if present, undefined otherwise
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const body = getValidatedBody(req);
|
|
16
|
+
* if (!body) {
|
|
17
|
+
* Logger.error('Validation middleware not configured');
|
|
18
|
+
* return res.setStatus(500).json({ error: 'Internal server error' });
|
|
19
|
+
* }
|
|
20
|
+
* const email = getString(body['email']);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function getValidatedBody(req) {
|
|
24
|
+
const validated = getValidated(req);
|
|
25
|
+
if (validated === undefined)
|
|
26
|
+
return undefined;
|
|
27
|
+
if (validated.body === undefined)
|
|
28
|
+
return undefined;
|
|
29
|
+
return validated.body;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if request has a validated body
|
|
33
|
+
* Type guard for validated body existence
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* if (!hasValidatedBody(req)) {
|
|
38
|
+
* Logger.error('Validation middleware not configured');
|
|
39
|
+
* return res.setStatus(500).json({ error: 'Internal server error' });
|
|
40
|
+
* }
|
|
41
|
+
* const body = getValidatedBody(req)!; // Safe to use non-null assertion
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function hasValidatedBody(req) {
|
|
45
|
+
const validated = getValidated(req);
|
|
46
|
+
if (validated === undefined)
|
|
47
|
+
return false;
|
|
48
|
+
if (validated.body === undefined)
|
|
49
|
+
return false;
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Extract validated body or throw error
|
|
54
|
+
* Throws if validation middleware is not properly configured
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* try {
|
|
59
|
+
* const body = requireValidatedBody(req);
|
|
60
|
+
* const email = getString(body['email']);
|
|
61
|
+
* } catch (error) {
|
|
62
|
+
* Logger.error('Validation middleware error', error);
|
|
63
|
+
* return res.setStatus(500).json({ error: 'Internal server error' });
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export function requireValidatedBody(req) {
|
|
68
|
+
const body = getValidatedBody(req);
|
|
69
|
+
if (body === undefined) {
|
|
70
|
+
throw ErrorFactory.createValidationError('Validation middleware did not populate req.validated.body');
|
|
71
|
+
}
|
|
72
|
+
return body;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Extract validated query parameters from request
|
|
76
|
+
* Returns the validated query if present, undefined otherwise
|
|
77
|
+
*/
|
|
78
|
+
export function getValidatedQuery(req) {
|
|
79
|
+
const validated = getValidated(req);
|
|
80
|
+
if (validated === undefined)
|
|
81
|
+
return undefined;
|
|
82
|
+
if (validated.query === undefined)
|
|
83
|
+
return undefined;
|
|
84
|
+
return validated.query;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Extract validated route parameters from request
|
|
88
|
+
* Returns the validated params if present, undefined otherwise
|
|
89
|
+
*/
|
|
90
|
+
export function getValidatedParams(req) {
|
|
91
|
+
const validated = getValidated(req);
|
|
92
|
+
if (validated === undefined)
|
|
93
|
+
return undefined;
|
|
94
|
+
if (validated.params === undefined)
|
|
95
|
+
return undefined;
|
|
96
|
+
return validated.params;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Extract validated headers from request
|
|
100
|
+
* Returns the validated headers if present, undefined otherwise
|
|
101
|
+
*/
|
|
102
|
+
export function getValidatedHeaders(req) {
|
|
103
|
+
const validated = getValidated(req);
|
|
104
|
+
if (validated === undefined)
|
|
105
|
+
return undefined;
|
|
106
|
+
if (validated.headers === undefined)
|
|
107
|
+
return undefined;
|
|
108
|
+
return validated.headers;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Validation Helper - Sealed namespace
|
|
112
|
+
*/
|
|
113
|
+
export const ValidationHelper = Object.freeze({
|
|
114
|
+
getValidatedBody,
|
|
115
|
+
hasValidatedBody,
|
|
116
|
+
requireValidatedBody,
|
|
117
|
+
getValidatedQuery,
|
|
118
|
+
getValidatedParams,
|
|
119
|
+
getValidatedHeaders,
|
|
120
|
+
});
|
|
121
|
+
export default ValidationHelper;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IRequest } from '../Request';
|
|
2
|
+
type RenderInput = {
|
|
3
|
+
statusCode: number;
|
|
4
|
+
errorName: string;
|
|
5
|
+
errorMessage: string;
|
|
6
|
+
requestPath: string;
|
|
7
|
+
stackPretty?: string;
|
|
8
|
+
stackRaw?: string;
|
|
9
|
+
requestPretty?: string;
|
|
10
|
+
requestRaw?: string;
|
|
11
|
+
};
|
|
12
|
+
export declare const ErrorPageRenderer: Readonly<{
|
|
13
|
+
shouldSendHtml(request: IRequest): boolean;
|
|
14
|
+
renderHtml(publicRoot: string, input: RenderInput): string | undefined;
|
|
15
|
+
}>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=ErrorPageRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorPageRenderer.d.ts","sourceRoot":"","sources":["../../../../src/http/error-pages/ErrorPageRenderer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAM9C,KAAK,WAAW,GAAG;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AA2EF,eAAO,MAAM,iBAAiB;4BACJ,QAAQ,GAAG,OAAO;2BAInB,MAAM,SAAS,WAAW,GAAG,MAAM,GAAG,SAAS;EAUtE,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ErrorFactory } from '../../exceptions/ZintrustError.js';
|
|
2
|
+
import * as fs from '../../node-singletons/fs.js';
|
|
3
|
+
import * as path from '../../node-singletons/path.js';
|
|
4
|
+
const escapeHtml = (value) => {
|
|
5
|
+
return value
|
|
6
|
+
.replaceAll('&', '&')
|
|
7
|
+
.replaceAll('<', '<')
|
|
8
|
+
.replaceAll('>', '>')
|
|
9
|
+
.replaceAll('"', '"')
|
|
10
|
+
.replaceAll("'", ''');
|
|
11
|
+
};
|
|
12
|
+
const getAcceptHeader = (request) => {
|
|
13
|
+
const accept = request.getHeader('accept');
|
|
14
|
+
if (typeof accept === 'string')
|
|
15
|
+
return accept;
|
|
16
|
+
if (Array.isArray(accept))
|
|
17
|
+
return accept.join(',');
|
|
18
|
+
return '';
|
|
19
|
+
};
|
|
20
|
+
const prefersHtml = (request) => {
|
|
21
|
+
if (request.getPath().startsWith('/api'))
|
|
22
|
+
return false;
|
|
23
|
+
const accept = getAcceptHeader(request).toLowerCase();
|
|
24
|
+
if (accept === '')
|
|
25
|
+
return false;
|
|
26
|
+
// Browser Accept values almost always include one of these.
|
|
27
|
+
return accept.includes('text/html') || accept.includes('application/xhtml+xml');
|
|
28
|
+
};
|
|
29
|
+
const prefersJson = (request) => {
|
|
30
|
+
if (request.getPath().startsWith('/api'))
|
|
31
|
+
return true;
|
|
32
|
+
const accept = getAcceptHeader(request).toLowerCase();
|
|
33
|
+
// If the client explicitly accepts HTML, treat it as an HTML preference.
|
|
34
|
+
if (accept.includes('text/html') || accept.includes('application/xhtml+xml'))
|
|
35
|
+
return false;
|
|
36
|
+
if (accept.includes('application/json'))
|
|
37
|
+
return true;
|
|
38
|
+
// Default to JSON when the client doesn't express a preference.
|
|
39
|
+
return accept === '' || accept.includes('*/*');
|
|
40
|
+
};
|
|
41
|
+
const interpolate = (template, data) => {
|
|
42
|
+
return template
|
|
43
|
+
.replaceAll('{{statusCode}}', escapeHtml(String(data.statusCode)))
|
|
44
|
+
.replaceAll('{{errorName}}', escapeHtml(data.errorName))
|
|
45
|
+
.replaceAll('{{errorMessage}}', escapeHtml(data.errorMessage))
|
|
46
|
+
.replaceAll('{{requestPath}}', escapeHtml(data.requestPath))
|
|
47
|
+
.replaceAll('{{stackPretty}}', escapeHtml(data.stackPretty ?? ''))
|
|
48
|
+
.replaceAll('{{stackRaw}}', escapeHtml(data.stackRaw ?? ''))
|
|
49
|
+
.replaceAll('{{requestPretty}}', escapeHtml(data.requestPretty ?? ''))
|
|
50
|
+
.replaceAll('{{requestRaw}}', escapeHtml(data.requestRaw ?? ''));
|
|
51
|
+
};
|
|
52
|
+
const resolveTemplatePath = (publicRoot, templateName) => {
|
|
53
|
+
return path.join(publicRoot, 'error-pages', `${templateName}.html`);
|
|
54
|
+
};
|
|
55
|
+
const safeReadTemplate = (filePath) => {
|
|
56
|
+
try {
|
|
57
|
+
if (!fs.existsSync(filePath))
|
|
58
|
+
return undefined;
|
|
59
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
60
|
+
return typeof content === 'string' && content.length > 0 ? content : undefined;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
ErrorFactory.createTryCatchError(`Failed to read error page template: ${filePath}`, error);
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const toTemplateName = (statusCode) => {
|
|
68
|
+
if (statusCode === 404)
|
|
69
|
+
return '404';
|
|
70
|
+
if (statusCode === 500)
|
|
71
|
+
return '500';
|
|
72
|
+
return undefined;
|
|
73
|
+
};
|
|
74
|
+
export const ErrorPageRenderer = Object.freeze({
|
|
75
|
+
shouldSendHtml(request) {
|
|
76
|
+
return prefersHtml(request) && !prefersJson(request);
|
|
77
|
+
},
|
|
78
|
+
renderHtml(publicRoot, input) {
|
|
79
|
+
const templateName = toTemplateName(input.statusCode);
|
|
80
|
+
if (templateName === undefined)
|
|
81
|
+
return undefined;
|
|
82
|
+
const templatePath = resolveTemplatePath(publicRoot, templateName);
|
|
83
|
+
const template = safeReadTemplate(templatePath);
|
|
84
|
+
if (template === undefined)
|
|
85
|
+
return undefined;
|
|
86
|
+
return interpolate(template, input);
|
|
87
|
+
},
|
|
88
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Type Detection & Body Parsing Middleware
|
|
3
|
+
* Detects content-type and parses non-JSON request bodies
|
|
4
|
+
*/
|
|
5
|
+
import type { Middleware } from '../../middleware/MiddlewareStack';
|
|
6
|
+
/**
|
|
7
|
+
* Body parsing middleware
|
|
8
|
+
* Automatically detects content-type and parses non-JSON bodies
|
|
9
|
+
*/
|
|
10
|
+
export declare const bodyParsingMiddleware: Middleware;
|
|
11
|
+
export default bodyParsingMiddleware;
|
|
12
|
+
//# sourceMappingURL=BodyParsingMiddleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BodyParsingMiddleware.d.ts","sourceRoot":"","sources":["../../../../src/http/middleware/BodyParsingMiddleware.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAqO9D;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,UAgDnC,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Type Detection & Body Parsing Middleware
|
|
3
|
+
* Detects content-type and parses non-JSON request bodies
|
|
4
|
+
*/
|
|
5
|
+
import { Env } from '../../config/env.js';
|
|
6
|
+
import { Logger } from '../../config/logger.js';
|
|
7
|
+
import { MultipartParser } from '../parsers/MultipartParser.js';
|
|
8
|
+
/**
|
|
9
|
+
* Get content-type from request headers
|
|
10
|
+
*/
|
|
11
|
+
const getContentType = (req) => {
|
|
12
|
+
const contentType = req.getHeader('content-type');
|
|
13
|
+
if (typeof contentType === 'string')
|
|
14
|
+
return contentType.split(';')[0].toLowerCase().trim();
|
|
15
|
+
if (Array.isArray(contentType) && typeof contentType[0] === 'string') {
|
|
16
|
+
return contentType[0].split(';')[0].toLowerCase().trim();
|
|
17
|
+
}
|
|
18
|
+
return '';
|
|
19
|
+
};
|
|
20
|
+
const shouldReadRequestBody = (req) => {
|
|
21
|
+
const method = (req.getMethod?.() ?? 'GET').toUpperCase();
|
|
22
|
+
if (method === 'GET' || method === 'HEAD' || method === 'OPTIONS')
|
|
23
|
+
return false;
|
|
24
|
+
return true;
|
|
25
|
+
};
|
|
26
|
+
const toBuffer = (chunk) => {
|
|
27
|
+
if (Buffer.isBuffer(chunk))
|
|
28
|
+
return chunk;
|
|
29
|
+
if (typeof chunk === 'string')
|
|
30
|
+
return Buffer.from(chunk);
|
|
31
|
+
if (chunk instanceof Uint8Array)
|
|
32
|
+
return Buffer.from(chunk);
|
|
33
|
+
if (chunk instanceof ArrayBuffer)
|
|
34
|
+
return Buffer.from(new Uint8Array(chunk));
|
|
35
|
+
return Buffer.from(String(chunk));
|
|
36
|
+
};
|
|
37
|
+
const validateSize = (bytes, maxBytes) => {
|
|
38
|
+
if (bytes.length > maxBytes) {
|
|
39
|
+
return { ok: false, statusCode: 413, message: 'Payload Too Large' };
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
};
|
|
43
|
+
const handleMockedStringBody = (body, maxBytes) => {
|
|
44
|
+
const bytes = Buffer.from(body);
|
|
45
|
+
const sizeError = validateSize(bytes, maxBytes);
|
|
46
|
+
if (sizeError)
|
|
47
|
+
return sizeError;
|
|
48
|
+
return { ok: true, bytes, text: body };
|
|
49
|
+
};
|
|
50
|
+
const handleMockedBufferBody = (body, maxBytes) => {
|
|
51
|
+
const sizeError = validateSize(body, maxBytes);
|
|
52
|
+
if (sizeError)
|
|
53
|
+
return sizeError;
|
|
54
|
+
return { ok: true, bytes: body, text: body.toString('utf-8') };
|
|
55
|
+
};
|
|
56
|
+
const handleMockedObjectBody = (body, maxBytes) => {
|
|
57
|
+
try {
|
|
58
|
+
const text = JSON.stringify(body);
|
|
59
|
+
const bytes = Buffer.from(text, 'utf-8');
|
|
60
|
+
const sizeError = validateSize(bytes, maxBytes);
|
|
61
|
+
if (sizeError)
|
|
62
|
+
return sizeError;
|
|
63
|
+
return { ok: true, bytes, text };
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return { ok: false, statusCode: 400, message: 'Invalid request body' };
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const handleMockedBody = (mockedBody, maxBytes) => {
|
|
70
|
+
if (typeof mockedBody === 'string') {
|
|
71
|
+
return handleMockedStringBody(mockedBody, maxBytes);
|
|
72
|
+
}
|
|
73
|
+
if (Buffer.isBuffer(mockedBody)) {
|
|
74
|
+
return handleMockedBufferBody(mockedBody, maxBytes);
|
|
75
|
+
}
|
|
76
|
+
if (typeof mockedBody === 'object' && mockedBody !== null) {
|
|
77
|
+
return handleMockedObjectBody(mockedBody, maxBytes);
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
};
|
|
81
|
+
const readStreamBody = async (raw, maxBytes) => {
|
|
82
|
+
const chunks = [];
|
|
83
|
+
let totalSize = 0;
|
|
84
|
+
try {
|
|
85
|
+
for await (const chunk of raw) {
|
|
86
|
+
const buf = toBuffer(chunk);
|
|
87
|
+
totalSize += buf.length;
|
|
88
|
+
if (totalSize > maxBytes) {
|
|
89
|
+
try {
|
|
90
|
+
raw.destroy?.();
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// best-effort
|
|
94
|
+
}
|
|
95
|
+
return { ok: false, statusCode: 413, message: 'Payload Too Large' };
|
|
96
|
+
}
|
|
97
|
+
chunks.push(buf);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return { ok: false, statusCode: 400, message: 'Invalid request body' };
|
|
102
|
+
}
|
|
103
|
+
if (chunks.length === 0)
|
|
104
|
+
return { ok: true, bytes: Buffer.from(''), text: '' };
|
|
105
|
+
const bytes = Buffer.concat(chunks);
|
|
106
|
+
return { ok: true, bytes, text: bytes.toString('utf-8') };
|
|
107
|
+
};
|
|
108
|
+
const readRawBody = async (req, maxBytes) => {
|
|
109
|
+
const raw = req.getRaw();
|
|
110
|
+
// Support tests/mocks that stuff a body directly on the raw request.
|
|
111
|
+
const mockedBody = raw.body;
|
|
112
|
+
const mockedResult = handleMockedBody(mockedBody, maxBytes);
|
|
113
|
+
if (mockedResult) {
|
|
114
|
+
return mockedResult;
|
|
115
|
+
}
|
|
116
|
+
// Read from actual stream
|
|
117
|
+
return readStreamBody(raw, maxBytes);
|
|
118
|
+
};
|
|
119
|
+
const convertExistingToRawResult = (existingBytes, existingText) => {
|
|
120
|
+
if (Buffer.isBuffer(existingBytes)) {
|
|
121
|
+
return { ok: true, bytes: existingBytes, text: existingBytes.toString('utf-8') };
|
|
122
|
+
}
|
|
123
|
+
if (typeof existingText === 'string') {
|
|
124
|
+
return { ok: true, bytes: Buffer.from(existingText, 'utf-8'), text: existingText };
|
|
125
|
+
}
|
|
126
|
+
// Should be unreachable (guarded by `hasExisting`), but keep a safe fallback.
|
|
127
|
+
return { ok: true, bytes: Buffer.from('', 'utf-8'), text: '' };
|
|
128
|
+
};
|
|
129
|
+
const parseJsonBody = (text, contentType, res) => {
|
|
130
|
+
try {
|
|
131
|
+
return text === '' ? null : JSON.parse(text);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
Logger.debug('[Body Parser] Invalid JSON body', {
|
|
135
|
+
contentType,
|
|
136
|
+
byteLength: Buffer.byteLength(text),
|
|
137
|
+
rawBodyPreview: text.slice(0, 256),
|
|
138
|
+
});
|
|
139
|
+
res.setStatus(400).json({ error: 'Invalid JSON body' });
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
const setRequestBody = (req, rawResult, contentType) => {
|
|
144
|
+
const isUrlEncoded = contentType.includes('application/x-www-form-urlencoded');
|
|
145
|
+
const isText = contentType.startsWith('text/') || contentType.includes('application/xml');
|
|
146
|
+
if (isUrlEncoded) {
|
|
147
|
+
req.setBody(parseUrlEncodedBody(rawResult.text));
|
|
148
|
+
}
|
|
149
|
+
else if (isText) {
|
|
150
|
+
req.setBody(rawResult.text);
|
|
151
|
+
}
|
|
152
|
+
else if (contentType !== '') {
|
|
153
|
+
req.setBody(rawResult.bytes);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const parseUrlEncodedBody = (text) => {
|
|
157
|
+
const out = {};
|
|
158
|
+
const params = new URLSearchParams(text);
|
|
159
|
+
for (const [key, value] of params.entries()) {
|
|
160
|
+
const existing = out[key];
|
|
161
|
+
if (existing === undefined) {
|
|
162
|
+
out[key] = value;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (Array.isArray(existing)) {
|
|
166
|
+
existing.push(value);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
out[key] = [existing, value];
|
|
170
|
+
}
|
|
171
|
+
return out;
|
|
172
|
+
};
|
|
173
|
+
const processBodyParsing = async (req, res, contentType, maxBytes) => {
|
|
174
|
+
const rawResult = await readRawBody(req, maxBytes);
|
|
175
|
+
if (rawResult.ok === false) {
|
|
176
|
+
res.setStatus(rawResult.statusCode).json({ error: rawResult.message });
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
// Store raw body for downstream consumers
|
|
180
|
+
req.context['rawBodyBytes'] = rawResult.bytes;
|
|
181
|
+
req.context['rawBodyText'] = rawResult.text;
|
|
182
|
+
// Parse and set body based on content type
|
|
183
|
+
try {
|
|
184
|
+
const isJson = contentType.includes('application/json');
|
|
185
|
+
if (isJson) {
|
|
186
|
+
const parsed = parseJsonBody(rawResult.text, contentType, res);
|
|
187
|
+
if (parsed === null && res.getStatus() === 400) {
|
|
188
|
+
return false; // JSON parsing failed, response already sent
|
|
189
|
+
}
|
|
190
|
+
req.setBody(parsed);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
setRequestBody(req, rawResult, contentType);
|
|
194
|
+
}
|
|
195
|
+
if (Env.getBool('ZIN_DEBUG_BODY_PARSING', false)) {
|
|
196
|
+
Logger.debug('[Body Parser] Parsed request body', {
|
|
197
|
+
contentType,
|
|
198
|
+
byteLength: rawResult.bytes.length,
|
|
199
|
+
parsedType: typeof req.getBody?.(),
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
Logger.error('[Body Parser] Unexpected error during body parsing', error);
|
|
205
|
+
}
|
|
206
|
+
return true;
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* Body parsing middleware
|
|
210
|
+
* Automatically detects content-type and parses non-JSON bodies
|
|
211
|
+
*/
|
|
212
|
+
export const bodyParsingMiddleware = async (req, res, next) => {
|
|
213
|
+
const contentType = getContentType(req);
|
|
214
|
+
// Early exit if body already set
|
|
215
|
+
const existingBody = req.getBody?.();
|
|
216
|
+
if (existingBody !== null && existingBody !== undefined) {
|
|
217
|
+
await next();
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
// Early exit for multipart (handled by upload middleware)
|
|
221
|
+
if (MultipartParser.isMultipart(contentType)) {
|
|
222
|
+
await next();
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
// Early exit for methods that don't have bodies
|
|
226
|
+
if (!shouldReadRequestBody(req)) {
|
|
227
|
+
await next();
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
// Determine if we have existing raw body from adapter
|
|
231
|
+
const existingBytes = req.context['rawBodyBytes'];
|
|
232
|
+
const existingText = req.context['rawBodyText'];
|
|
233
|
+
const hasExisting = Buffer.isBuffer(existingBytes) || typeof existingText === 'string';
|
|
234
|
+
// Calculate size limit based on content type
|
|
235
|
+
const isJson = contentType.includes('application/json');
|
|
236
|
+
const maxJsonSize = Env.getInt('MAX_JSON_SIZE', 1024 * 1024);
|
|
237
|
+
const maxBytes = isJson ? maxJsonSize : Env.MAX_BODY_SIZE;
|
|
238
|
+
// Read or reuse raw body
|
|
239
|
+
if (hasExisting) {
|
|
240
|
+
const rawResult = convertExistingToRawResult(existingBytes, existingText);
|
|
241
|
+
if (rawResult.ok) {
|
|
242
|
+
req.context['rawBodyBytes'] = rawResult.bytes;
|
|
243
|
+
req.context['rawBodyText'] = rawResult.text;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
await processBodyParsing(req, res, contentType, maxBytes);
|
|
248
|
+
}
|
|
249
|
+
await next();
|
|
250
|
+
};
|
|
251
|
+
export default bodyParsingMiddleware;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Upload Middleware
|
|
3
|
+
* Processes multipart/form-data requests and makes files available on request
|
|
4
|
+
*/
|
|
5
|
+
import type { Middleware } from '../../middleware/MiddlewareStack';
|
|
6
|
+
/**
|
|
7
|
+
* File upload middleware
|
|
8
|
+
* Automatically parses multipart/form-data and makes files available
|
|
9
|
+
*/
|
|
10
|
+
export declare const fileUploadMiddleware: Middleware;
|
|
11
|
+
export default fileUploadMiddleware;
|
|
12
|
+
//# sourceMappingURL=FileUploadMiddleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileUploadMiddleware.d.ts","sourceRoot":"","sources":["../../../../src/http/middleware/FileUploadMiddleware.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAW9D;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,UA8DlC,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Upload Middleware
|
|
3
|
+
* Processes multipart/form-data requests and makes files available on request
|
|
4
|
+
*/
|
|
5
|
+
import { Env } from '../../config/env.js';
|
|
6
|
+
import { Logger } from '../../config/logger.js';
|
|
7
|
+
import { MultipartParser } from '../parsers/MultipartParser.js';
|
|
8
|
+
import { MultipartParserRegistry } from '../parsers/MultipartParserRegistry.js';
|
|
9
|
+
/**
|
|
10
|
+
* Extract content-type header safely
|
|
11
|
+
*/
|
|
12
|
+
const getContentType = (req) => {
|
|
13
|
+
const contentType = req.getHeader('content-type');
|
|
14
|
+
if (typeof contentType === 'string')
|
|
15
|
+
return contentType.toLowerCase().trim();
|
|
16
|
+
return '';
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* File upload middleware
|
|
20
|
+
* Automatically parses multipart/form-data and makes files available
|
|
21
|
+
*/
|
|
22
|
+
export const fileUploadMiddleware = async (req, res, next) => {
|
|
23
|
+
const contentType = getContentType(req);
|
|
24
|
+
// Only process multipart/form-data requests
|
|
25
|
+
if (!MultipartParser.isMultipart(contentType)) {
|
|
26
|
+
await next();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// Phase 4 default behavior: multipart requires external streaming parser.
|
|
30
|
+
const provider = MultipartParserRegistry.get();
|
|
31
|
+
if (provider === null) {
|
|
32
|
+
res.setStatus(415).json({
|
|
33
|
+
error: 'multipart/form-data not supported. Install @zintrust/storage to enable uploads.',
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const maxFileSizeBytes = Env.getInt('MAX_FILE_SIZE', 50 * 1024 * 1024);
|
|
39
|
+
const maxFiles = Env.getInt('MAX_FILES', 20);
|
|
40
|
+
const maxFields = Env.getInt('MAX_FIELDS', 200);
|
|
41
|
+
const maxFieldSizeBytes = Env.getInt('MAX_FIELD_SIZE', 128 * 1024);
|
|
42
|
+
const parsed = await provider({
|
|
43
|
+
req: req.getRaw(),
|
|
44
|
+
contentType,
|
|
45
|
+
limits: {
|
|
46
|
+
maxFileSizeBytes,
|
|
47
|
+
maxFiles,
|
|
48
|
+
maxFields,
|
|
49
|
+
maxFieldSizeBytes,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
const currentBody = req.getBody?.();
|
|
53
|
+
const updatedBody = typeof currentBody === 'object' && currentBody !== null ? currentBody : {};
|
|
54
|
+
// Merge fields directly into the request body for ergonomics.
|
|
55
|
+
// Files remain under __files for FileUpload helper compatibility.
|
|
56
|
+
req.setBody({
|
|
57
|
+
...updatedBody,
|
|
58
|
+
...parsed.fields,
|
|
59
|
+
__files: parsed.files,
|
|
60
|
+
});
|
|
61
|
+
if (Env.getBool('ZIN_DEBUG_FILE_UPLOAD', false)) {
|
|
62
|
+
Logger.debug('[File Upload] Successfully parsed multipart data', {
|
|
63
|
+
fieldsCount: Object.keys(parsed.fields).length,
|
|
64
|
+
filesCount: Object.keys(parsed.files).length,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
Logger.error('[File Upload] Error parsing multipart data', error);
|
|
70
|
+
// Continue with unparsed body
|
|
71
|
+
}
|
|
72
|
+
await next();
|
|
73
|
+
};
|
|
74
|
+
export default fileUploadMiddleware;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Body Parsers - Content-Type specific parsing
|
|
3
|
+
* Handles form-data, plain text, CSV, and other non-JSON formats
|
|
4
|
+
*/
|
|
5
|
+
interface BodyParserResult {
|
|
6
|
+
ok: boolean;
|
|
7
|
+
data?: Record<string, unknown> | string | unknown[];
|
|
8
|
+
error?: string;
|
|
9
|
+
}
|
|
10
|
+
interface IBodyParser {
|
|
11
|
+
canParse(contentType: string): boolean;
|
|
12
|
+
parse(body: string | Buffer): BodyParserResult;
|
|
13
|
+
}
|
|
14
|
+
export declare const BodyParsers: Readonly<{
|
|
15
|
+
FormDataParser: IBodyParser;
|
|
16
|
+
TextParser: IBodyParser;
|
|
17
|
+
CSVParser: IBodyParser;
|
|
18
|
+
/**
|
|
19
|
+
* Get all registered parsers
|
|
20
|
+
*/
|
|
21
|
+
getAll(): IBodyParser[];
|
|
22
|
+
/**
|
|
23
|
+
* Find parser for content-type
|
|
24
|
+
*/
|
|
25
|
+
findParser(contentType: string): IBodyParser | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Parse body based on content-type
|
|
28
|
+
*/
|
|
29
|
+
parse(contentType: string, body: string | Buffer): BodyParserResult;
|
|
30
|
+
}>;
|
|
31
|
+
export default BodyParsers;
|
|
32
|
+
//# sourceMappingURL=BodyParsers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BodyParsers.d.ts","sourceRoot":"","sources":["../../../../src/http/parsers/BodyParsers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,UAAU,gBAAgB;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,OAAO,EAAE,CAAC;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IACvC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,gBAAgB,CAAC;CAChD;AA6ID,eAAO,MAAM,WAAW;;;;IAKtB;;OAEG;cACO,WAAW,EAAE;IAIvB;;OAEG;4BACqB,MAAM,GAAG,WAAW,GAAG,SAAS;IAIxD;;OAEG;uBACgB,MAAM,QAAQ,MAAM,GAAG,MAAM,GAAG,gBAAgB;EAQnE,CAAC;AAEH,eAAe,WAAW,CAAC"}
|