@zintrust/core 0.1.18 → 0.1.20
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 +16 -10
- package/bin/zintrust-main.d.ts.map +1 -1
- package/bin/zintrust-main.js +9 -0
- package/package.json +11 -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/index.html +1 -1
- package/public/zintrust.svg +30 -0
- package/routes/api.d.ts +7 -0
- package/routes/api.d.ts.map +1 -0
- package/routes/api.js +115 -0
- package/routes/broadcast.d.ts +9 -0
- package/routes/broadcast.d.ts.map +1 -0
- package/routes/broadcast.js +27 -0
- package/routes/health.d.ts +7 -0
- package/routes/health.d.ts.map +1 -0
- package/routes/health.js +127 -0
- 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/routes/storage.d.ts +4 -0
- package/routes/storage.d.ts.map +1 -0
- package/routes/storage.js +35 -0
- package/src/boot/Application.d.ts +2 -2
- package/src/boot/Application.d.ts.map +1 -1
- package/src/boot/Application.js +18 -3
- 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 +1 -1
- 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 +12 -4
- package/src/cli/PromptHelper.d.ts.map +1 -1
- package/src/cli/PromptHelper.js +4 -3
- 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 +291 -35
- package/src/cli/commands/NewCommand.d.ts +2 -2
- package/src/cli/commands/NewCommand.d.ts.map +1 -1
- package/src/cli/commands/NewCommand.js +38 -13
- 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/SimulateCommand.js +1 -1
- package/src/cli/commands/StartCommand.d.ts.map +1 -1
- package/src/cli/commands/StartCommand.js +90 -3
- package/src/cli/commands/UpgradeCommand.d.ts +16 -0
- package/src/cli/commands/UpgradeCommand.d.ts.map +1 -0
- package/src/cli/commands/UpgradeCommand.js +107 -0
- 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/commands/runner/index.d.ts +3 -0
- package/src/cli/commands/runner/index.d.ts.map +1 -0
- package/src/cli/commands/runner/index.js +139 -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 +224 -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/env/EnvFileBackfill.d.ts +10 -0
- package/src/cli/env/EnvFileBackfill.d.ts.map +1 -0
- package/src/cli/env/EnvFileBackfill.js +64 -0
- package/src/cli/scaffolding/ControllerGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/ControllerGenerator.js +72 -22
- 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/ProjectScaffolder.d.ts.map +1 -1
- package/src/cli/scaffolding/ProjectScaffolder.js +54 -59
- 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 +24 -3
- 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/cli/utils/DistPackager.d.ts.map +1 -1
- package/src/cli/utils/DistPackager.js +8 -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 +1 -1
- package/src/config/broadcast.d.ts.map +1 -1
- package/src/config/broadcast.js +1 -1
- package/src/config/cache.d.ts +1 -1
- package/src/config/cache.d.ts.map +1 -1
- package/src/config/cloudflare.d.ts +1 -1
- package/src/config/cloudflare.d.ts.map +1 -1
- package/src/config/database.d.ts +7 -1
- package/src/config/database.d.ts.map +1 -1
- package/src/config/database.js +99 -7
- package/src/config/env.d.ts +6 -0
- package/src/config/env.d.ts.map +1 -1
- package/src/config/env.js +7 -0
- package/src/config/index.d.ts +8 -2
- 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/middleware.d.ts +22 -2
- package/src/config/middleware.d.ts.map +1 -1
- package/src/config/middleware.js +179 -11
- package/src/config/notification.js +1 -1
- package/src/config/security.d.ts +1 -1
- package/src/config/security.js +1 -1
- package/src/config/storage.js +1 -1
- package/src/config/type.d.ts +8 -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 +129 -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 +65 -7
- package/src/index.d.ts.map +1 -1
- package/src/index.js +59 -5
- 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/RateLimiter.js +26 -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 +323 -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 +2 -0
- package/src/node.d.ts.map +1 -1
- package/src/node.js +7 -0
- 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 +4 -2
- package/src/orm/Database.d.ts.map +1 -1
- package/src/orm/Database.js +142 -29
- package/src/orm/DatabaseAdapter.d.ts +13 -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 +4 -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 +405 -95
- 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 +63 -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 +1 -0
- package/src/performance/Optimizer.d.ts.map +1 -1
- package/src/performance/Optimizer.js +37 -3
- 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/api.d.ts +2 -0
- package/src/routes/api.d.ts.map +1 -0
- package/src/routes/api.js +1 -0
- package/src/routes/broadcast.d.ts +2 -0
- package/src/routes/broadcast.d.ts.map +1 -0
- package/src/routes/broadcast.js +1 -0
- package/src/routes/health.d.ts +2 -0
- package/src/routes/health.d.ts.map +1 -0
- package/src/routes/health.js +1 -0
- 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/routes/storage.d.ts +2 -0
- package/src/routes/storage.d.ts.map +1 -0
- package/src/routes/storage.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 +28 -0
- package/src/routing/doc.d.ts.map +1 -0
- package/src/routing/doc.js +95 -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 +18 -0
- package/src/routing/publicRoot.d.ts.map +1 -0
- package/src/routing/publicRoot.js +49 -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/RuntimeAdapter.d.ts.map +1 -1
- package/src/runtime/RuntimeAdapter.js +20 -1
- package/src/runtime/RuntimeDetector.d.ts +1 -1
- package/src/runtime/RuntimeDetector.d.ts.map +1 -1
- 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 +3 -3
- 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/scripts/TemplateImportsCheck.js +47 -7
- package/src/scripts/TemplateSync.js +92 -20
- 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/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/start.d.ts +21 -0
- package/src/start.d.ts.map +1 -0
- package/src/start.js +60 -0
- 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 +2 -2
- package/src/templates/project/basic/app/Controllers/AuthController.ts.tpl +217 -0
- package/src/templates/project/basic/app/Controllers/UserController.ts.tpl +3 -16
- package/src/templates/project/basic/app/Middleware/ProfilerMiddleware.ts.tpl +1 -3
- package/src/templates/project/basic/app/Middleware/index.ts.tpl +3 -8
- package/src/templates/project/basic/app/Models/Post.ts.tpl +2 -3
- package/src/templates/project/basic/app/Models/User.ts.tpl +1 -1
- 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 +13 -450
- 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 +15 -129
- package/src/templates/project/basic/config/cache.ts.tpl +15 -92
- 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 +29 -116
- 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 +27 -24
- package/src/templates/project/basic/config/logger.ts.tpl +5 -381
- package/src/templates/project/basic/config/logging/HttpLogger.ts.tpl +1 -1
- package/src/templates/project/basic/config/logging/KvLogger.ts.tpl +2 -2
- package/src/templates/project/basic/config/logging/SlackLogger.ts.tpl +1 -1
- package/src/templates/project/basic/config/mail.ts.tpl +15 -115
- package/src/templates/project/basic/config/microservices.ts.tpl +11 -97
- package/src/templates/project/basic/config/middleware.ts.tpl +27 -18
- package/src/templates/project/basic/config/notification.ts.tpl +14 -127
- package/src/templates/project/basic/config/queue.ts.tpl +16 -79
- 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 +15 -133
- package/src/templates/project/basic/config/type.ts.tpl +33 -441
- 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/package.json.tpl +1 -1
- package/src/templates/project/basic/routes/api.ts.tpl +74 -36
- package/src/templates/project/basic/routes/health.ts.tpl +1 -6
- package/src/templates/project/basic/routes/metrics.ts.tpl +22 -0
- package/src/templates/project/basic/src/index.ts.tpl +7 -80
- package/src/templates/project/basic/tsconfig.json.tpl +12 -13
- 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/database/migrations/index.ts.tpl +0 -2
|
@@ -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"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Body Parsers - Content-Type specific parsing
|
|
3
|
+
* Handles form-data, plain text, CSV, and other non-JSON formats
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* URL-encoded form data parser
|
|
7
|
+
* Content-Type: application/x-www-form-urlencoded
|
|
8
|
+
*/
|
|
9
|
+
const FormDataParser = {
|
|
10
|
+
canParse: (contentType) => contentType.includes('application/x-www-form-urlencoded'),
|
|
11
|
+
parse: (body) => {
|
|
12
|
+
try {
|
|
13
|
+
const text = typeof body === 'string' ? body : body.toString('utf-8');
|
|
14
|
+
if (!text.trim())
|
|
15
|
+
return { ok: true, data: {} };
|
|
16
|
+
const params = new URLSearchParams(text);
|
|
17
|
+
const result = {};
|
|
18
|
+
for (const [key, value] of params.entries()) {
|
|
19
|
+
if (Object.prototype.hasOwnProperty.call(result, key)) {
|
|
20
|
+
// Handle multiple values with same key
|
|
21
|
+
const existing = result[key];
|
|
22
|
+
if (Array.isArray(existing)) {
|
|
23
|
+
existing.push(value);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
result[key] = [existing, value];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
result[key] = value;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { ok: true, data: result };
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
37
|
+
return { ok: false, error: `Failed to parse form data: ${errorMsg}` };
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Plain text parser
|
|
43
|
+
* Content-Type: text/plain
|
|
44
|
+
*/
|
|
45
|
+
const TextParser = {
|
|
46
|
+
canParse: (contentType) => contentType.includes('text/plain'),
|
|
47
|
+
parse: (body) => {
|
|
48
|
+
try {
|
|
49
|
+
const text = typeof body === 'string' ? body : body.toString('utf-8');
|
|
50
|
+
return { ok: true, data: text };
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
54
|
+
return { ok: false, error: `Failed to parse text: ${errorMsg}` };
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* CSV parser implementation helper
|
|
60
|
+
*/
|
|
61
|
+
const parseCSVLine = (line) => {
|
|
62
|
+
const result = [];
|
|
63
|
+
let current = '';
|
|
64
|
+
let inQuotes = false;
|
|
65
|
+
let i = 0;
|
|
66
|
+
while (i < line.length) {
|
|
67
|
+
const char = line[i];
|
|
68
|
+
if (char === '"') {
|
|
69
|
+
if (inQuotes && line[i + 1] === '"') {
|
|
70
|
+
current += '"';
|
|
71
|
+
i += 2;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
inQuotes = !inQuotes;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (char === ',' && !inQuotes) {
|
|
79
|
+
result.push(current.trim());
|
|
80
|
+
current = '';
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
current += char;
|
|
84
|
+
}
|
|
85
|
+
i++;
|
|
86
|
+
}
|
|
87
|
+
result.push(current.trim());
|
|
88
|
+
return result;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* CSV parser
|
|
92
|
+
* Content-Type: text/csv
|
|
93
|
+
*/
|
|
94
|
+
const CSVParser = {
|
|
95
|
+
canParse: (contentType) => contentType.includes('text/csv'),
|
|
96
|
+
parse: (body) => {
|
|
97
|
+
try {
|
|
98
|
+
const text = typeof body === 'string' ? body : body.toString('utf-8');
|
|
99
|
+
if (text.length === 0)
|
|
100
|
+
return { ok: true, data: [] };
|
|
101
|
+
// Stream-like processing: iterate lines without creating an array of all lines
|
|
102
|
+
const rows = [];
|
|
103
|
+
let headers;
|
|
104
|
+
let cursor = 0;
|
|
105
|
+
while (cursor < text.length) {
|
|
106
|
+
let lineEnd = text.indexOf('\n', cursor);
|
|
107
|
+
if (lineEnd === -1)
|
|
108
|
+
lineEnd = text.length;
|
|
109
|
+
const line = text.slice(cursor, lineEnd).trim();
|
|
110
|
+
cursor = lineEnd + 1;
|
|
111
|
+
if (line.length === 0)
|
|
112
|
+
continue;
|
|
113
|
+
const values = parseCSVLine(line);
|
|
114
|
+
if (!headers) {
|
|
115
|
+
headers = values;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const row = {};
|
|
119
|
+
for (let j = 0; j < headers.length; j++) {
|
|
120
|
+
row[headers[j]] = values[j] ?? '';
|
|
121
|
+
}
|
|
122
|
+
rows.push(row);
|
|
123
|
+
}
|
|
124
|
+
return { ok: true, data: rows };
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
128
|
+
return { ok: false, error: `Failed to parse CSV: ${errorMsg}` };
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
export const BodyParsers = Object.freeze({
|
|
133
|
+
FormDataParser,
|
|
134
|
+
TextParser,
|
|
135
|
+
CSVParser,
|
|
136
|
+
/**
|
|
137
|
+
* Get all registered parsers
|
|
138
|
+
*/
|
|
139
|
+
getAll() {
|
|
140
|
+
return [this.FormDataParser, this.TextParser, this.CSVParser];
|
|
141
|
+
},
|
|
142
|
+
/**
|
|
143
|
+
* Find parser for content-type
|
|
144
|
+
*/
|
|
145
|
+
findParser(contentType) {
|
|
146
|
+
return this.getAll().find((parser) => parser.canParse(contentType));
|
|
147
|
+
},
|
|
148
|
+
/**
|
|
149
|
+
* Parse body based on content-type
|
|
150
|
+
*/
|
|
151
|
+
parse(contentType, body) {
|
|
152
|
+
const parser = this.findParser(contentType);
|
|
153
|
+
if (parser === undefined) {
|
|
154
|
+
return { ok: false, error: `No parser found for content-type: ${contentType}` };
|
|
155
|
+
}
|
|
156
|
+
return parser.parse(body);
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
export default BodyParsers;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multipart Form-Data Parser
|
|
3
|
+
* Parses multipart/form-data requests for file uploads and form fields
|
|
4
|
+
*/
|
|
5
|
+
import type { UploadedFile } from '../FileUpload';
|
|
6
|
+
interface ParsedMultipartData {
|
|
7
|
+
fields: Record<string, string | string[]>;
|
|
8
|
+
files: Record<string, UploadedFile[]>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parse multipart/form-data body
|
|
12
|
+
* Note: This is a simplified parser. For production use a proper multipart library
|
|
13
|
+
*/
|
|
14
|
+
export declare const parseMultipartFormData: (body: Buffer | string, boundary: string) => ParsedMultipartData;
|
|
15
|
+
/**
|
|
16
|
+
* Parse multipart/form-data from request
|
|
17
|
+
*/
|
|
18
|
+
export declare const MultipartParser: Readonly<{
|
|
19
|
+
/**
|
|
20
|
+
* Check if content-type is multipart/form-data
|
|
21
|
+
*/
|
|
22
|
+
isMultipart(contentType: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Get boundary from content-type header
|
|
25
|
+
*/
|
|
26
|
+
getBoundary(contentType: string): string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Parse multipart body
|
|
29
|
+
*/
|
|
30
|
+
parse(body: Buffer | string, boundary: string): ParsedMultipartData;
|
|
31
|
+
}>;
|
|
32
|
+
export default MultipartParser;
|
|
33
|
+
//# sourceMappingURL=MultipartParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MultipartParser.d.ts","sourceRoot":"","sources":["../../../../src/http/parsers/MultipartParser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;CACvC;AAqGD;;;GAGG;AACH,eAAO,MAAM,sBAAsB,GACjC,MAAM,MAAM,GAAG,MAAM,EACrB,UAAU,MAAM,KACf,mBAaF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe;IAC1B;;OAEG;6BACsB,MAAM,GAAG,OAAO;IAIzC;;OAEG;6BACsB,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpD;;OAEG;gBACS,MAAM,GAAG,MAAM,YAAY,MAAM,GAAG,mBAAmB;EAGnE,CAAC;AAEH,eAAe,eAAe,CAAC"}
|