@zintrust/core 0.1.19 → 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 +10 -10
- package/bin/zintrust-main.d.ts.map +1 -1
- package/bin/zintrust-main.js +9 -0
- package/package.json +2 -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 +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/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 +291 -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 +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/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 +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 +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/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/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 +1 -1
- package/src/config/database.d.ts.map +1 -1
- package/src/config/database.js +92 -6
- 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 +1 -1
- package/src/config/logging/KvLogger.js +1 -1
- package/src/config/logging/SlackLogger.js +2 -2
- package/src/config/middleware.d.ts +20 -1
- package/src/config/middleware.d.ts.map +1 -1
- package/src/config/middleware.js +135 -3
- package/src/config/security.d.ts +1 -1
- package/src/config/security.js +1 -1
- package/src/config/type.d.ts +1 -1
- 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 +64 -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/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 +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 +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/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 -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 +58 -2
- 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/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 +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/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 +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/scripts/TemplateImportsCheck.js +40 -0
- package/src/scripts/TemplateSync.js +86 -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/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 +15 -128
- package/src/templates/project/basic/config/cache.ts.tpl +15 -91
- 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 -122
- 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/mail.ts.tpl +15 -114
- 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 +14 -126
- 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 -132
- package/src/templates/project/basic/config/type.ts.tpl +33 -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/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/database/migrations/index.ts.tpl +0 -2
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input Sanitizer (Character Whitelisting)
|
|
3
|
+
*
|
|
4
|
+
* Provides small utilities to remove unwanted characters from user input.
|
|
5
|
+
*
|
|
6
|
+
* Important:
|
|
7
|
+
* - This is NOT a complete SQL injection defense.
|
|
8
|
+
* - Always use parameterized queries / the ORM / QueryBuilder.
|
|
9
|
+
*
|
|
10
|
+
* Use this for:
|
|
11
|
+
* - Normalizing identifiers (username, slug-ish strings)
|
|
12
|
+
* - Cleaning phone numbers / numeric strings
|
|
13
|
+
* - Reducing unexpected characters before storage/logging
|
|
14
|
+
*
|
|
15
|
+
* Bulletproof Mode:
|
|
16
|
+
* - Enabled by default (`bulletproof=true`) for security-critical methods
|
|
17
|
+
* - Throws SanitizerError instead of returning empty/invalid values
|
|
18
|
+
* - Validates numeric ranges, leading zeros, type coercion attacks
|
|
19
|
+
* - ~5-15% performance overhead; disable for performance-critical paths
|
|
20
|
+
*/
|
|
21
|
+
import { ErrorFactory } from '../exceptions/ZintrustError.js';
|
|
22
|
+
const MAX_NUMERIC_INPUT_LEN = 64;
|
|
23
|
+
const MAX_EMAIL_LEN = 254;
|
|
24
|
+
const MAX_NAME_LEN = 200;
|
|
25
|
+
const MAX_PASSWORD_LEN = 256;
|
|
26
|
+
const assertMaxLen = (method, label, value, maxLen) => {
|
|
27
|
+
if (value.length <= maxLen)
|
|
28
|
+
return;
|
|
29
|
+
throw ErrorFactory.createSanitizerError(method, `${label} too long`, value);
|
|
30
|
+
};
|
|
31
|
+
const isEmpty = (value) => {
|
|
32
|
+
// Preserve legacy semantics: treat 0 and "0" as empty.
|
|
33
|
+
return (value === null ||
|
|
34
|
+
value === undefined ||
|
|
35
|
+
value === false ||
|
|
36
|
+
value === 0 ||
|
|
37
|
+
value === '' ||
|
|
38
|
+
value === '0');
|
|
39
|
+
};
|
|
40
|
+
const toStr = (value) => {
|
|
41
|
+
return String(value ?? '');
|
|
42
|
+
};
|
|
43
|
+
const stripSpaces = (value) => {
|
|
44
|
+
return toStr(value).replaceAll(' ', '');
|
|
45
|
+
};
|
|
46
|
+
const sanitize = (value, pattern, stripSpace = false) => {
|
|
47
|
+
const input = stripSpace ? stripSpaces(value) : toStr(value);
|
|
48
|
+
return input.replace(pattern, '');
|
|
49
|
+
};
|
|
50
|
+
const isNumericString = (value) => {
|
|
51
|
+
const trimmed = value.trim();
|
|
52
|
+
if (trimmed.length === 0)
|
|
53
|
+
return false;
|
|
54
|
+
const n = Number(trimmed);
|
|
55
|
+
return Number.isFinite(n);
|
|
56
|
+
};
|
|
57
|
+
const parseAmount = (value, bulletproof = true) => {
|
|
58
|
+
if (isEmpty(value))
|
|
59
|
+
return 0;
|
|
60
|
+
const cleaned = sanitize(value, /[^0-9.-]/g, true);
|
|
61
|
+
const num = Number(cleaned);
|
|
62
|
+
if (bulletproof) {
|
|
63
|
+
// Handle string edge cases - check original value
|
|
64
|
+
const str = String(value);
|
|
65
|
+
const trimmed = str.trim();
|
|
66
|
+
assertMaxLen('parseAmount', 'Input', trimmed, MAX_NUMERIC_INPUT_LEN);
|
|
67
|
+
// Reject explicit plus sign prefixes (type confusion)
|
|
68
|
+
if (trimmed.startsWith('+')) {
|
|
69
|
+
throw ErrorFactory.createSanitizerError('parseAmount', 'Plus sign not allowed', value);
|
|
70
|
+
}
|
|
71
|
+
// Reject "Infinity", "-Infinity", "NaN" explicitly
|
|
72
|
+
if (/^[+-]?infinity$/i.test(trimmed) || /^nan$/i.test(trimmed)) {
|
|
73
|
+
throw ErrorFactory.createSanitizerError('parseAmount', 'Non-finite number', value);
|
|
74
|
+
}
|
|
75
|
+
// Reject scientific notation (e.g., "1e308", "2.5e10")
|
|
76
|
+
if (/[eE]/.test(trimmed)) {
|
|
77
|
+
throw ErrorFactory.createSanitizerError('parseAmount', 'Scientific notation not allowed', value);
|
|
78
|
+
}
|
|
79
|
+
assertMaxLen('parseAmount', 'Sanitized numeric', cleaned, MAX_NUMERIC_INPUT_LEN);
|
|
80
|
+
// Require a strict numeric shape after sanitization (prevents "1-2" -> NaN etc.)
|
|
81
|
+
if (!/^-?\d+(?:\.\d+)?$/.test(cleaned)) {
|
|
82
|
+
throw ErrorFactory.createSanitizerError('parseAmount', 'Invalid numeric format', value);
|
|
83
|
+
}
|
|
84
|
+
// Reject Infinity, NaN, and overflow attacks
|
|
85
|
+
if (!Number.isFinite(num)) {
|
|
86
|
+
throw ErrorFactory.createSanitizerError('parseAmount', 'Non-finite number', value);
|
|
87
|
+
}
|
|
88
|
+
if (Math.abs(num) > Number.MAX_SAFE_INTEGER) {
|
|
89
|
+
throw ErrorFactory.createSanitizerError('parseAmount', 'Number exceeds safe integer range', value);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return Number.isFinite(num) ? num : 0;
|
|
93
|
+
};
|
|
94
|
+
const alphanumeric = (value) => {
|
|
95
|
+
if (isEmpty(value))
|
|
96
|
+
return '';
|
|
97
|
+
return sanitize(value, /[^A-Za-z0-9]/g, true);
|
|
98
|
+
};
|
|
99
|
+
const alphanumericDotDash = (value) => {
|
|
100
|
+
if (isEmpty(value))
|
|
101
|
+
return '';
|
|
102
|
+
return sanitize(value, /[^A-Za-z0-9\-.]/g, true);
|
|
103
|
+
};
|
|
104
|
+
const validateNonNegativeNumericStringPreSanitization = (trimmed, value) => {
|
|
105
|
+
assertMaxLen('nonNegativeNumericStringOrNull', 'Input', trimmed, MAX_NUMERIC_INPUT_LEN);
|
|
106
|
+
// Reject explicit plus sign prefixes (type confusion)
|
|
107
|
+
if (trimmed.startsWith('+')) {
|
|
108
|
+
throw ErrorFactory.createSanitizerError('nonNegativeNumericStringOrNull', 'Plus sign not allowed', value);
|
|
109
|
+
}
|
|
110
|
+
// Reject scientific notation before sanitization can mask it
|
|
111
|
+
if (/[eE]/.test(trimmed)) {
|
|
112
|
+
throw ErrorFactory.createSanitizerError('nonNegativeNumericStringOrNull', 'Scientific notation not allowed', value);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const validateNonNegativeNumericStringPostSanitization = (da, value) => {
|
|
116
|
+
assertMaxLen('nonNegativeNumericStringOrNull', 'Sanitized numeric', da, MAX_NUMERIC_INPUT_LEN);
|
|
117
|
+
// Strict shape: allow optional leading '-' and optional fractional part.
|
|
118
|
+
if (!/^-?\d+(?:\.\d+)?$/.test(da)) {
|
|
119
|
+
throw ErrorFactory.createSanitizerError('nonNegativeNumericStringOrNull', 'Invalid numeric format', value);
|
|
120
|
+
}
|
|
121
|
+
// For integers (no decimal point), validate leading zeros
|
|
122
|
+
if (da.includes('.')) {
|
|
123
|
+
// For decimals, only check overflow
|
|
124
|
+
const num = Number(da);
|
|
125
|
+
if (Math.abs(num) > Number.MAX_SAFE_INTEGER) {
|
|
126
|
+
throw ErrorFactory.createSanitizerError('nonNegativeNumericStringOrNull', 'Number exceeds safe integer range', value);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const numericId = Number.parseInt(da, 10);
|
|
131
|
+
if (!Number.isFinite(numericId) ||
|
|
132
|
+
numericId < 0 ||
|
|
133
|
+
numericId > Number.MAX_SAFE_INTEGER ||
|
|
134
|
+
numericId.toString() !== da) {
|
|
135
|
+
throw ErrorFactory.createSanitizerError('nonNegativeNumericStringOrNull', 'Invalid numeric format (leading zeros, overflow, or type mismatch)', value);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
const nonNegativeNumericStringOrNull = (value, bulletproof = true) => {
|
|
140
|
+
if (isEmpty(value))
|
|
141
|
+
return 0;
|
|
142
|
+
const raw = stripSpaces(value);
|
|
143
|
+
if (bulletproof) {
|
|
144
|
+
const trimmed = raw.trim();
|
|
145
|
+
validateNonNegativeNumericStringPreSanitization(trimmed, value);
|
|
146
|
+
}
|
|
147
|
+
const da = raw.replaceAll(/[^0-9\-.]/g, '');
|
|
148
|
+
const numeric = isNumericString(da);
|
|
149
|
+
if (numeric && Number(da) < 0)
|
|
150
|
+
return 0;
|
|
151
|
+
if (!numeric) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
if (bulletproof) {
|
|
155
|
+
validateNonNegativeNumericStringPostSanitization(da, value);
|
|
156
|
+
}
|
|
157
|
+
return da;
|
|
158
|
+
};
|
|
159
|
+
const digitsOnly = (value, bulletproof = true) => {
|
|
160
|
+
// Special handling for '0' string
|
|
161
|
+
if (value === '0') {
|
|
162
|
+
if (bulletproof) {
|
|
163
|
+
throw ErrorFactory.createSanitizerError('digitsOnly', 'Invalid numeric ID (zero, negative, overflow, or leading zeros)', value);
|
|
164
|
+
}
|
|
165
|
+
return '0';
|
|
166
|
+
}
|
|
167
|
+
if (isEmpty(value))
|
|
168
|
+
return '';
|
|
169
|
+
const da = sanitize(value, /\D/g);
|
|
170
|
+
if (bulletproof) {
|
|
171
|
+
assertMaxLen('digitsOnly', 'Sanitized numeric', da, 16);
|
|
172
|
+
// After removing non-digits, check if result is empty
|
|
173
|
+
if (da.length === 0) {
|
|
174
|
+
throw ErrorFactory.createSanitizerError('digitsOnly', 'Empty result after removing non-digits', value);
|
|
175
|
+
}
|
|
176
|
+
// Check for special characters that get stripped (like +)
|
|
177
|
+
const str = String(value);
|
|
178
|
+
if (/^[+-]/.test(str.trim())) {
|
|
179
|
+
throw ErrorFactory.createSanitizerError('digitsOnly', 'Invalid numeric ID (starts with +/- sign)', value);
|
|
180
|
+
}
|
|
181
|
+
const numericId = Number.parseInt(da, 10);
|
|
182
|
+
if (!Number.isFinite(numericId) ||
|
|
183
|
+
numericId <= 0 ||
|
|
184
|
+
numericId > Number.MAX_SAFE_INTEGER ||
|
|
185
|
+
numericId.toString() !== da) {
|
|
186
|
+
throw ErrorFactory.createSanitizerError('digitsOnly', 'Invalid numeric ID (zero, negative, overflow, or leading zeros)', value);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return da.replaceAll(' ', '');
|
|
190
|
+
};
|
|
191
|
+
const validateDecimalStringPreSanitization = (trimmed, value) => {
|
|
192
|
+
assertMaxLen('decimalString', 'Input', trimmed, MAX_NUMERIC_INPUT_LEN);
|
|
193
|
+
// Reject explicit plus/minus prefixes and scientific notation (type confusion)
|
|
194
|
+
if (/^[+-]/.test(trimmed)) {
|
|
195
|
+
throw ErrorFactory.createSanitizerError('decimalString', 'Signed values not allowed', value);
|
|
196
|
+
}
|
|
197
|
+
if (/[eE]/.test(trimmed)) {
|
|
198
|
+
throw ErrorFactory.createSanitizerError('decimalString', 'Scientific notation not allowed', value);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
const validateDecimalStringPostSanitization = (result, cleaned, value) => {
|
|
202
|
+
assertMaxLen('decimalString', 'Sanitized numeric', cleaned, MAX_NUMERIC_INPUT_LEN);
|
|
203
|
+
if (result.length === 0) {
|
|
204
|
+
throw ErrorFactory.createSanitizerError('decimalString', 'Empty result after sanitization', value);
|
|
205
|
+
}
|
|
206
|
+
if (!/^\d+(?:\.\d+)?$/.test(result)) {
|
|
207
|
+
throw ErrorFactory.createSanitizerError('decimalString', 'Invalid decimal format', value);
|
|
208
|
+
}
|
|
209
|
+
const num = Number(result);
|
|
210
|
+
if (!Number.isFinite(num)) {
|
|
211
|
+
throw ErrorFactory.createSanitizerError('decimalString', 'Non-numeric decimal value', value);
|
|
212
|
+
}
|
|
213
|
+
if (Math.abs(num) > Number.MAX_SAFE_INTEGER) {
|
|
214
|
+
throw ErrorFactory.createSanitizerError('decimalString', 'Decimal value exceeds safe range', value);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
const decimalString = (value, bulletproof = true) => {
|
|
218
|
+
if (isEmpty(value))
|
|
219
|
+
return '';
|
|
220
|
+
if (bulletproof) {
|
|
221
|
+
const trimmed = String(value).trim();
|
|
222
|
+
validateDecimalStringPreSanitization(trimmed, value);
|
|
223
|
+
}
|
|
224
|
+
// Allow only valid decimal format: digits and at most one decimal point
|
|
225
|
+
const cleaned = sanitize(value, /[^0-9.]/g);
|
|
226
|
+
const parts = cleaned.split('.');
|
|
227
|
+
// Bulletproof mode: reject multiple decimal points rather than merging.
|
|
228
|
+
// Legacy/unsafe mode: normalize by keeping the first decimal point.
|
|
229
|
+
let result;
|
|
230
|
+
if (parts.length > 2) {
|
|
231
|
+
result = bulletproof ? '' : `${parts[0]}.${parts.slice(1).join('')}`;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
result = cleaned;
|
|
235
|
+
}
|
|
236
|
+
if (bulletproof) {
|
|
237
|
+
validateDecimalStringPostSanitization(result, cleaned, value);
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
};
|
|
241
|
+
const numericDotOnly = (value) => {
|
|
242
|
+
if (isEmpty(value))
|
|
243
|
+
return '';
|
|
244
|
+
return sanitize(value, /[^0-9.]/g);
|
|
245
|
+
};
|
|
246
|
+
const createBasicSanitizers = () => {
|
|
247
|
+
return {
|
|
248
|
+
parseAmount,
|
|
249
|
+
alphanumeric,
|
|
250
|
+
alphanumericDotDash,
|
|
251
|
+
nonNegativeNumericStringOrNull,
|
|
252
|
+
digitsOnly,
|
|
253
|
+
decimalString,
|
|
254
|
+
numericDotOnly,
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
const addressTextSanitizer = (value) => {
|
|
258
|
+
if (isEmpty(value))
|
|
259
|
+
return '';
|
|
260
|
+
return sanitize(value, /[^A-Za-z0-9\-.@+, _]/g);
|
|
261
|
+
};
|
|
262
|
+
const emailLikeSanitizer = (value) => {
|
|
263
|
+
if (isEmpty(value))
|
|
264
|
+
return '';
|
|
265
|
+
return sanitize(value, /[^A-Za-z0-9\-.@+_]/g);
|
|
266
|
+
};
|
|
267
|
+
const emailSanitizer = (value, bulletproof = true) => {
|
|
268
|
+
if (isEmpty(value))
|
|
269
|
+
return '';
|
|
270
|
+
const result = sanitize(value, /[^A-Za-z0-9\-.@_]/g);
|
|
271
|
+
if (bulletproof) {
|
|
272
|
+
const trimmed = result.trim();
|
|
273
|
+
assertMaxLen('email', 'Email', trimmed, MAX_EMAIL_LEN);
|
|
274
|
+
if (trimmed.length === 0) {
|
|
275
|
+
throw ErrorFactory.createSanitizerError('email', 'Empty result after sanitization', value);
|
|
276
|
+
}
|
|
277
|
+
if (!trimmed.includes('@')) {
|
|
278
|
+
throw ErrorFactory.createSanitizerError('email', 'Missing @ symbol in email', value);
|
|
279
|
+
}
|
|
280
|
+
// Basic validation: something@something
|
|
281
|
+
const parts = trimmed.split('@');
|
|
282
|
+
if (parts.length !== 2 || parts[0].length === 0 || parts[1].length === 0) {
|
|
283
|
+
throw ErrorFactory.createSanitizerError('email', 'Invalid email format', value);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return result;
|
|
287
|
+
};
|
|
288
|
+
const messageTextSanitizer = (value) => {
|
|
289
|
+
if (isEmpty(value))
|
|
290
|
+
return '';
|
|
291
|
+
return sanitize(value, /[^A-Za-z0-9\-.@+_&$%!,()? ]/g);
|
|
292
|
+
};
|
|
293
|
+
const nameTextSanitizer = (value, bulletproof = true) => {
|
|
294
|
+
if (isEmpty(value))
|
|
295
|
+
return '';
|
|
296
|
+
const result = sanitize(value, /[^A-Za-z0-9 .]/g);
|
|
297
|
+
if (bulletproof) {
|
|
298
|
+
const trimmed = result.trim();
|
|
299
|
+
assertMaxLen('nameText', 'Name', trimmed, MAX_NAME_LEN);
|
|
300
|
+
if (trimmed.length === 0) {
|
|
301
|
+
throw ErrorFactory.createSanitizerError('nameText', 'Empty or whitespace-only result', value);
|
|
302
|
+
}
|
|
303
|
+
// Names should have at least one letter
|
|
304
|
+
if (!/[A-Za-z]/.test(trimmed)) {
|
|
305
|
+
throw ErrorFactory.createSanitizerError('nameText', 'Name must contain at least one letter', value);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return result;
|
|
309
|
+
};
|
|
310
|
+
const wordCharsAndSpacesSanitizer = (value) => {
|
|
311
|
+
if (isEmpty(value))
|
|
312
|
+
return '';
|
|
313
|
+
return sanitize(value, /[^A-Za-z0-9_\s]/g);
|
|
314
|
+
};
|
|
315
|
+
const safePasswordCharsSanitizer = (value, bulletproof = true) => {
|
|
316
|
+
if (isEmpty(value))
|
|
317
|
+
return '';
|
|
318
|
+
const result = sanitize(value, /[^!@#$%&*/\sA-Za-z0-9_]/g);
|
|
319
|
+
if (bulletproof) {
|
|
320
|
+
const trimmed = result.trim();
|
|
321
|
+
assertMaxLen('safePasswordChars', 'Password', trimmed, MAX_PASSWORD_LEN);
|
|
322
|
+
if (trimmed.length === 0) {
|
|
323
|
+
throw ErrorFactory.createSanitizerError('safePasswordChars', 'Empty result after sanitization', value);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return result;
|
|
327
|
+
};
|
|
328
|
+
const createTextSanitizers = () => {
|
|
329
|
+
return {
|
|
330
|
+
addressText: addressTextSanitizer,
|
|
331
|
+
emailLike: emailLikeSanitizer,
|
|
332
|
+
email: emailSanitizer,
|
|
333
|
+
messageText: messageTextSanitizer,
|
|
334
|
+
nameText: nameTextSanitizer,
|
|
335
|
+
wordCharsAndSpaces: wordCharsAndSpacesSanitizer,
|
|
336
|
+
safePasswordChars: safePasswordCharsSanitizer,
|
|
337
|
+
};
|
|
338
|
+
};
|
|
339
|
+
const createSpecializedSanitizers = () => {
|
|
340
|
+
const ipAddressText = (value) => {
|
|
341
|
+
if (isEmpty(value))
|
|
342
|
+
return '';
|
|
343
|
+
return sanitize(value, /[^A-Za-z0-9:.]/g);
|
|
344
|
+
};
|
|
345
|
+
const alphaNumericColonDash = (value) => {
|
|
346
|
+
if (isEmpty(value))
|
|
347
|
+
return '';
|
|
348
|
+
return sanitize(value, /[^A-Za-z0-9:-]/g);
|
|
349
|
+
};
|
|
350
|
+
const dateSlash = (value) => {
|
|
351
|
+
if (isEmpty(value))
|
|
352
|
+
return '';
|
|
353
|
+
return sanitize(value, /[^0-9/]/g);
|
|
354
|
+
};
|
|
355
|
+
const lowercaseAlphanumeric = (value) => {
|
|
356
|
+
if (isEmpty(value))
|
|
357
|
+
return '';
|
|
358
|
+
return sanitize(value, /[^A-Za-z0-9]/g).toLowerCase();
|
|
359
|
+
};
|
|
360
|
+
const uppercaseAlphanumeric = (value) => {
|
|
361
|
+
if (isEmpty(value))
|
|
362
|
+
return '';
|
|
363
|
+
return sanitize(value, /[^A-Za-z0-9]/g).toUpperCase();
|
|
364
|
+
};
|
|
365
|
+
const alphanumericNoSpaces = (value) => {
|
|
366
|
+
if (isEmpty(value))
|
|
367
|
+
return '';
|
|
368
|
+
return sanitize(value, /[^A-Za-z0-9 ]/g, true);
|
|
369
|
+
};
|
|
370
|
+
const dateSlashNoSpaces = (value) => {
|
|
371
|
+
if (isEmpty(value))
|
|
372
|
+
return '';
|
|
373
|
+
return sanitize(value, /[^0-9/]/g, true);
|
|
374
|
+
};
|
|
375
|
+
// Legacy naming was misleading; this is closer to a "uuid/token safe" whitelist.
|
|
376
|
+
const uuidTokenSafe = (value) => {
|
|
377
|
+
if (isEmpty(value))
|
|
378
|
+
return '';
|
|
379
|
+
return sanitize(value, /[^A-Za-z0-9\-=]/g, true);
|
|
380
|
+
};
|
|
381
|
+
// Base64url-like (plus "=") token whitelisting.
|
|
382
|
+
const tokenSafe = (value) => {
|
|
383
|
+
if (isEmpty(value))
|
|
384
|
+
return '';
|
|
385
|
+
return sanitize(value, /[^A-Za-z0-9\-=_]/g, true);
|
|
386
|
+
};
|
|
387
|
+
const keyLike = (value) => {
|
|
388
|
+
if (isEmpty(value))
|
|
389
|
+
return '';
|
|
390
|
+
return sanitize(value, /[^A-Za-z0-9\-:. ]/g, true);
|
|
391
|
+
};
|
|
392
|
+
return {
|
|
393
|
+
ipAddressText,
|
|
394
|
+
alphaNumericColonDash,
|
|
395
|
+
dateSlash,
|
|
396
|
+
lowercaseAlphanumeric,
|
|
397
|
+
uppercaseAlphanumeric,
|
|
398
|
+
alphanumericNoSpaces,
|
|
399
|
+
dateSlashNoSpaces,
|
|
400
|
+
uuidTokenSafe,
|
|
401
|
+
tokenSafe,
|
|
402
|
+
keyLike,
|
|
403
|
+
};
|
|
404
|
+
};
|
|
405
|
+
export const createSanitizer = () => {
|
|
406
|
+
return Object.freeze({
|
|
407
|
+
...createBasicSanitizers(),
|
|
408
|
+
...createTextSanitizers(),
|
|
409
|
+
...createSpecializedSanitizers(),
|
|
410
|
+
});
|
|
411
|
+
};
|
|
412
|
+
export const Sanitizer = createSanitizer();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type AuthorizationHeader = string | string[] | undefined;
|
|
2
|
+
export declare const TokenRevocation: Readonly<{
|
|
3
|
+
revoke(header: AuthorizationHeader): string | null;
|
|
4
|
+
isRevoked(token: string): boolean;
|
|
5
|
+
}>;
|
|
6
|
+
export default TokenRevocation;
|
|
7
|
+
//# sourceMappingURL=TokenRevocation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenRevocation.d.ts","sourceRoot":"","sources":["../../../src/security/TokenRevocation.ts"],"names":[],"mappings":"AAGA,KAAK,mBAAmB,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;AAsCzD,eAAO,MAAM,eAAe;mBACX,mBAAmB,GAAG,MAAM,GAAG,IAAI;qBASjC,MAAM,GAAG,OAAO;EAUjC,CAAC;AAEH,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { securityConfig } from '../config/security.js';
|
|
2
|
+
import { JwtManager } from './JwtManager.js';
|
|
3
|
+
const revokedTokens = new Map();
|
|
4
|
+
const defaultTtlMs = Math.max(securityConfig.jwt.expiresIn * 1000, 60_000);
|
|
5
|
+
const getBearerToken = (header) => {
|
|
6
|
+
const value = Array.isArray(header) ? header[0] : header;
|
|
7
|
+
if (typeof value !== 'string')
|
|
8
|
+
return null;
|
|
9
|
+
const [scheme, token] = value.trim().split(' ');
|
|
10
|
+
if (scheme.toLowerCase() !== 'bearer')
|
|
11
|
+
return null;
|
|
12
|
+
if (typeof token !== 'string' || token.trim() === '')
|
|
13
|
+
return null;
|
|
14
|
+
return token;
|
|
15
|
+
};
|
|
16
|
+
const cleanupExpired = () => {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
for (const [token, expiresAt] of revokedTokens.entries()) {
|
|
19
|
+
if (expiresAt <= now) {
|
|
20
|
+
revokedTokens.delete(token);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const resolveExpiryMs = (token) => {
|
|
25
|
+
try {
|
|
26
|
+
const payload = JwtManager.create().decode(token);
|
|
27
|
+
if (typeof payload.exp === 'number' && Number.isFinite(payload.exp)) {
|
|
28
|
+
return payload.exp * 1000;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// ignore decode errors; fallback to default TTL
|
|
33
|
+
}
|
|
34
|
+
return Date.now() + defaultTtlMs;
|
|
35
|
+
};
|
|
36
|
+
export const TokenRevocation = Object.freeze({
|
|
37
|
+
revoke(header) {
|
|
38
|
+
const token = getBearerToken(header);
|
|
39
|
+
if (token === null)
|
|
40
|
+
return null;
|
|
41
|
+
cleanupExpired();
|
|
42
|
+
revokedTokens.set(token, resolveExpiryMs(token));
|
|
43
|
+
return token;
|
|
44
|
+
},
|
|
45
|
+
isRevoked(token) {
|
|
46
|
+
cleanupExpired();
|
|
47
|
+
const expiresAt = revokedTokens.get(token);
|
|
48
|
+
if (expiresAt === undefined)
|
|
49
|
+
return false;
|
|
50
|
+
if (expiresAt <= Date.now()) {
|
|
51
|
+
revokedTokens.delete(token);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
export default TokenRevocation;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SeederDiscovery.d.ts","sourceRoot":"","sources":["../../../src/seeders/SeederDiscovery.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,eAAe;4BACF,MAAM,OAAO,MAAM,GAAG,MAAM;yBAI/B,MAAM,GAAG,MAAM,EAAE;EAQtC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from '../node-singletons/fs.js';
|
|
2
|
+
import * as path from '../node-singletons/path.js';
|
|
3
|
+
const isSeederFile = (file) => {
|
|
4
|
+
if (file.endsWith('.d.ts'))
|
|
5
|
+
return false;
|
|
6
|
+
return file.endsWith('.ts') || file.endsWith('.js');
|
|
7
|
+
};
|
|
8
|
+
export const SeederDiscovery = Object.freeze({
|
|
9
|
+
resolveDir(projectRoot, dir) {
|
|
10
|
+
return path.resolve(projectRoot, dir);
|
|
11
|
+
},
|
|
12
|
+
listSeederFiles(dir) {
|
|
13
|
+
if (!fs.existsSync(dir))
|
|
14
|
+
return [];
|
|
15
|
+
const files = fs.readdirSync(dir);
|
|
16
|
+
return files
|
|
17
|
+
.filter(isSeederFile)
|
|
18
|
+
.sort((a, b) => a.localeCompare(b))
|
|
19
|
+
.map((f) => path.join(dir, f));
|
|
20
|
+
},
|
|
21
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SeederLoader.d.ts","sourceRoot":"","sources":["../../../src/seeders/SeederLoader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,iBAAiB,CAAC;AAwDnE,eAAO,MAAM,YAAY;mBACF,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;EA0BnD,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ErrorFactory } from '../exceptions/ZintrustError.js';
|
|
2
|
+
import * as path from '../node-singletons/path.js';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
function isFunction(value) {
|
|
5
|
+
return typeof value === 'function';
|
|
6
|
+
}
|
|
7
|
+
function isRecord(value) {
|
|
8
|
+
return typeof value === 'object' && value !== null;
|
|
9
|
+
}
|
|
10
|
+
function hasRun(value) {
|
|
11
|
+
return typeof value === 'object' && value !== null && 'run' in value;
|
|
12
|
+
}
|
|
13
|
+
function normalizeHandler(fn, label) {
|
|
14
|
+
if (!isFunction(fn)) {
|
|
15
|
+
throw ErrorFactory.createValidationError(`Invalid seeder export: expected function for ${label}`);
|
|
16
|
+
}
|
|
17
|
+
return async (db) => {
|
|
18
|
+
// Support both (db) => Promise<void> and () => Promise<void>.
|
|
19
|
+
if (fn.length <= 0) {
|
|
20
|
+
await Promise.resolve(fn());
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
await Promise.resolve(fn(db));
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function selectSeederExport(mod, baseName) {
|
|
27
|
+
const defaultExport = mod.default;
|
|
28
|
+
const defaultNamed = isRecord(defaultExport) ? defaultExport[baseName] : undefined;
|
|
29
|
+
// Prefer conventional exports first.
|
|
30
|
+
const candidate = mod.seeder ?? mod[baseName] ?? mod.run ?? defaultExport ?? defaultNamed;
|
|
31
|
+
if (candidate !== undefined)
|
|
32
|
+
return candidate;
|
|
33
|
+
// Last resort: pick the first export that looks like a seeder object.
|
|
34
|
+
for (const value of Object.values(mod)) {
|
|
35
|
+
if (hasRun(value))
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
export const SeederLoader = Object.freeze({
|
|
41
|
+
async load(filePath) {
|
|
42
|
+
const url = pathToFileURL(filePath).href;
|
|
43
|
+
const raw = (await import(url));
|
|
44
|
+
const mod = isRecord(raw) ? raw : {};
|
|
45
|
+
const baseName = path.basename(filePath, path.extname(filePath));
|
|
46
|
+
const picked = selectSeederExport(mod, baseName);
|
|
47
|
+
const baseExport = mod[baseName];
|
|
48
|
+
const runFn = (hasRun(picked) ? picked.run : undefined) ??
|
|
49
|
+
(hasRun(baseExport) ? baseExport.run : undefined) ??
|
|
50
|
+
mod.run;
|
|
51
|
+
if (runFn === undefined) {
|
|
52
|
+
throw ErrorFactory.createValidationError(`Seeder '${filePath}' is missing a runnable export (expected '${baseName}.run()', 'seeder.run()', 'run()', or default export with 'run()')`);
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
name: baseName,
|
|
56
|
+
filePath,
|
|
57
|
+
run: normalizeHandler(runFn, 'run'),
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IDatabase } from '../orm/Database';
|
|
2
|
+
export type SeederModule = {
|
|
3
|
+
/** Common pattern: export const UserSeeder = { run() { ... } } */
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
/** Alternative: export const seeder = { run() { ... } } */
|
|
6
|
+
seeder?: unknown;
|
|
7
|
+
/** Alternative: export async function run() { ... } */
|
|
8
|
+
run?: unknown;
|
|
9
|
+
/** Interop: export default { run() { ... } } */
|
|
10
|
+
default?: unknown;
|
|
11
|
+
};
|
|
12
|
+
export type SeederHandler = (db: IDatabase) => Promise<void>;
|
|
13
|
+
export type LoadedSeeder = {
|
|
14
|
+
name: string;
|
|
15
|
+
filePath: string;
|
|
16
|
+
run: SeederHandler;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/seeders/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,MAAM,YAAY,GAAG;IACzB,kEAAkE;IAClE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uDAAuD;IACvD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,EAAE,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE7D,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,aAAa,CAAC;CACpB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|