@zintrust/core 0.1.1 → 0.1.3
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 +3 -3
- package/bin/zintrust.d.ts.map +1 -1
- package/bin/zintrust.js +18 -1
- package/package.json +15 -1
- package/src/boot/Application.d.ts.map +1 -1
- package/src/boot/Application.js +46 -3
- package/src/boot/Server.d.ts.map +1 -1
- package/src/boot/Server.js +3 -4
- package/src/boot/bootstrap.js +77 -6
- package/src/builder/BundleOptimizer.d.ts.map +1 -1
- package/src/builder/BundleOptimizer.js +6 -4
- package/src/cache/drivers/KVDriver.d.ts.map +1 -1
- package/src/cache/drivers/KVDriver.js +6 -6
- package/src/cache/drivers/RedisDriver.js +1 -1
- package/src/cli/BaseCommand.d.ts +2 -2
- package/src/cli/BaseCommand.d.ts.map +1 -1
- package/src/cli/BaseCommand.js +2 -1
- package/src/cli/CLI.d.ts.map +1 -1
- package/src/cli/CLI.js +11 -4
- package/src/cli/commands/AddCommand.js +1 -1
- package/src/cli/commands/ConfigCommand.d.ts.map +1 -1
- package/src/cli/commands/ConfigCommand.js +34 -4
- package/src/cli/commands/D1MigrateCommand.d.ts +4 -0
- package/src/cli/commands/D1MigrateCommand.d.ts.map +1 -1
- package/src/cli/commands/D1MigrateCommand.js +4 -3
- package/src/cli/commands/FixCommand.d.ts.map +1 -1
- package/src/cli/commands/FixCommand.js +3 -16
- package/src/cli/commands/LogsCleanupCommand.d.ts +6 -0
- package/src/cli/commands/LogsCleanupCommand.d.ts.map +1 -0
- package/src/cli/commands/LogsCleanupCommand.js +20 -0
- package/src/cli/commands/LogsCommand.d.ts.map +1 -1
- package/src/cli/commands/LogsCommand.js +1 -1
- package/src/cli/commands/MakeMailTemplateCommand.d.ts +10 -0
- package/src/cli/commands/MakeMailTemplateCommand.d.ts.map +1 -0
- package/src/cli/commands/MakeMailTemplateCommand.js +74 -0
- package/src/cli/commands/MakeNotificationTemplateCommand.d.ts +10 -0
- package/src/cli/commands/MakeNotificationTemplateCommand.d.ts.map +1 -0
- package/src/cli/commands/MakeNotificationTemplateCommand.js +113 -0
- package/src/cli/commands/NewCommand.d.ts +4 -0
- package/src/cli/commands/NewCommand.d.ts.map +1 -1
- package/src/cli/commands/NewCommand.js +33 -20
- package/src/cli/commands/PluginCommand.d.ts.map +1 -1
- package/src/cli/commands/PluginCommand.js +8 -4
- package/src/cli/commands/PrepareCommand.d.ts.map +1 -1
- package/src/cli/commands/PrepareCommand.js +1 -1
- package/src/cli/commands/QACommand.d.ts.map +1 -1
- package/src/cli/commands/QACommand.js +11 -20
- package/src/cli/commands/SecretsCommand.d.ts +16 -0
- package/src/cli/commands/SecretsCommand.d.ts.map +1 -0
- package/src/cli/commands/SecretsCommand.js +91 -0
- package/src/cli/commands/StartCommand.d.ts.map +1 -1
- package/src/cli/commands/StartCommand.js +2 -2
- package/src/cli/commands/TemplatesCommand.d.ts +3 -0
- package/src/cli/commands/TemplatesCommand.d.ts.map +1 -0
- package/src/cli/commands/TemplatesCommand.js +65 -0
- package/src/cli/commands/index.d.ts +5 -0
- package/src/cli/commands/index.d.ts.map +1 -1
- package/src/cli/commands/index.js +5 -0
- package/src/cli/config/ConfigManager.js +1 -1
- package/src/cli/index.d.ts +2 -1
- package/src/cli/index.d.ts.map +1 -1
- package/src/cli/index.js +2 -1
- package/src/cli/scaffolding/ControllerGenerator.js +1 -1
- package/src/cli/scaffolding/FeatureScaffolder.js +4 -4
- package/src/cli/scaffolding/FileGenerator.js +1 -1
- package/src/cli/scaffolding/ModelGenerator.js +1 -1
- package/src/cli/scaffolding/ProjectScaffolder.d.ts.map +1 -1
- package/src/cli/scaffolding/ProjectScaffolder.js +61 -11
- package/src/cli/scaffolding/ResponseFactoryGenerator.d.ts.map +1 -1
- package/src/cli/scaffolding/ResponseFactoryGenerator.js +3 -2
- package/src/cli/scaffolding/RouteGenerator.js +1 -1
- package/src/cli/scaffolding/ServiceIntegrationTestGenerator.js +1 -1
- package/src/cli/scaffolding/ServiceScaffolder.js +2 -2
- package/src/cli/scaffolding/TemplateGenerator.d.ts +40 -0
- package/src/cli/scaffolding/TemplateGenerator.d.ts.map +1 -0
- package/src/cli/scaffolding/TemplateGenerator.js +172 -0
- package/src/cli/scaffolding/index.d.ts +1 -0
- package/src/cli/scaffolding/index.d.ts.map +1 -1
- package/src/cli/scaffolding/index.js +1 -0
- package/src/cli/utils/spawn.js +1 -1
- package/src/common/AwsSigV4.d.ts +41 -0
- package/src/common/AwsSigV4.d.ts.map +1 -0
- package/src/common/AwsSigV4.js +69 -0
- package/src/common/index.d.ts +39 -0
- package/src/common/index.d.ts.map +1 -1
- package/src/common/index.js +101 -8
- package/src/common/uuid.d.ts +3 -0
- package/src/common/uuid.d.ts.map +1 -0
- package/src/common/uuid.js +30 -0
- package/src/config/FileLogWriter.d.ts +22 -0
- package/src/config/FileLogWriter.d.ts.map +1 -0
- package/src/config/FileLogWriter.js +192 -0
- package/src/config/SecretsManager.d.ts.map +1 -1
- package/src/config/SecretsManager.js +37 -11
- package/src/config/StartupConfigValidator.d.ts +15 -0
- package/src/config/StartupConfigValidator.d.ts.map +1 -0
- package/src/config/StartupConfigValidator.js +86 -0
- package/src/config/app.d.ts +2 -1
- package/src/config/app.d.ts.map +1 -1
- package/src/config/app.js +65 -15
- package/src/config/broadcast.d.ts +47 -0
- package/src/config/broadcast.d.ts.map +1 -0
- package/src/config/broadcast.js +54 -0
- package/src/config/cache.d.ts +13 -17
- package/src/config/cache.d.ts.map +1 -1
- package/src/config/cache.js +9 -11
- package/src/config/cloudflare.d.ts +26 -0
- package/src/config/cloudflare.d.ts.map +1 -0
- package/src/config/cloudflare.js +38 -0
- package/src/config/env.d.ts +6 -0
- package/src/config/env.d.ts.map +1 -1
- package/src/config/env.js +6 -0
- package/src/config/index.d.ts +52 -28
- package/src/config/index.d.ts.map +1 -1
- package/src/config/index.js +3 -0
- package/src/config/logger.d.ts +2 -0
- package/src/config/logger.d.ts.map +1 -1
- package/src/config/logger.js +270 -11
- package/src/config/logging/HttpLogger.d.ts +23 -0
- package/src/config/logging/HttpLogger.d.ts.map +1 -0
- package/src/config/logging/HttpLogger.js +93 -0
- package/src/config/logging/KvLogger.d.ts +22 -0
- package/src/config/logging/KvLogger.d.ts.map +1 -0
- package/src/config/logging/KvLogger.js +143 -0
- package/src/config/logging/SlackLogger.d.ts +23 -0
- package/src/config/logging/SlackLogger.d.ts.map +1 -0
- package/src/config/logging/SlackLogger.js +119 -0
- package/src/config/mail.d.ts +81 -0
- package/src/config/mail.d.ts.map +1 -0
- package/src/config/mail.js +73 -0
- package/src/config/middleware.d.ts +8 -0
- package/src/config/middleware.d.ts.map +1 -0
- package/src/config/middleware.js +18 -0
- package/src/config/notification.d.ts +62 -0
- package/src/config/notification.d.ts.map +1 -0
- package/src/config/notification.js +43 -0
- package/src/config/security.d.ts.map +1 -1
- package/src/config/security.js +2 -2
- package/src/config/startup.d.ts +23 -0
- package/src/config/startup.d.ts.map +1 -0
- package/src/config/startup.js +15 -0
- package/src/config/storage.d.ts +21 -35
- package/src/config/storage.d.ts.map +1 -1
- package/src/config/storage.js +57 -37
- package/src/database/migrations/index.d.ts +1 -1
- package/src/database/migrations/index.d.ts.map +1 -1
- package/src/database/migrations/index.js +2 -1
- package/src/features/Queue.js +1 -25
- package/src/health/RuntimeHealthProbes.d.ts +13 -0
- package/src/health/RuntimeHealthProbes.d.ts.map +1 -0
- package/src/health/RuntimeHealthProbes.js +62 -0
- package/src/health/StartupHealthChecks.d.ts +26 -0
- package/src/health/StartupHealthChecks.d.ts.map +1 -0
- package/src/health/StartupHealthChecks.js +124 -0
- package/src/http/ErrorResponse.d.ts +28 -0
- package/src/http/ErrorResponse.d.ts.map +1 -0
- package/src/http/ErrorResponse.js +42 -0
- package/src/http/Kernel.d.ts +5 -0
- package/src/http/Kernel.d.ts.map +1 -1
- package/src/http/Kernel.js +96 -30
- package/src/http/RequestContext.d.ts +20 -0
- package/src/http/RequestContext.d.ts.map +1 -0
- package/src/http/RequestContext.js +77 -0
- package/src/index.d.ts +9 -1
- package/src/index.d.ts.map +1 -1
- package/src/index.js +8 -2
- package/src/microservices/MicroserviceManager.d.ts.map +1 -1
- package/src/microservices/MicroserviceManager.js +9 -6
- package/src/microservices/PostgresAdapter.d.ts.map +1 -1
- package/src/microservices/PostgresAdapter.js +3 -1
- package/src/microservices/ServiceBundler.d.ts.map +1 -1
- package/src/microservices/ServiceBundler.js +6 -4
- package/src/microservices/ServiceHealthMonitor.js +2 -2
- package/src/middleware/CsrfMiddleware.d.ts.map +1 -1
- package/src/middleware/CsrfMiddleware.js +2 -19
- package/src/middleware/ErrorHandlerMiddleware.d.ts +6 -0
- package/src/middleware/ErrorHandlerMiddleware.d.ts.map +1 -0
- package/src/middleware/ErrorHandlerMiddleware.js +33 -0
- package/src/middleware/LoggingMiddleware.d.ts +9 -0
- package/src/middleware/LoggingMiddleware.d.ts.map +1 -0
- package/src/middleware/LoggingMiddleware.js +36 -0
- package/src/middleware/index.d.ts +2 -0
- package/src/middleware/index.d.ts.map +1 -1
- package/src/middleware/index.js +2 -0
- package/src/node-singletons/async_hooks.d.ts +9 -0
- package/src/node-singletons/async_hooks.d.ts.map +1 -0
- package/src/node-singletons/async_hooks.js +8 -0
- 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 +2 -2
- package/src/node-singletons/http.d.ts +1 -1
- package/src/node-singletons/http.d.ts.map +1 -1
- package/src/node-singletons/http.js +1 -1
- package/src/node-singletons/index.d.ts +4 -0
- package/src/node-singletons/index.d.ts.map +1 -1
- package/src/node-singletons/index.js +4 -0
- package/src/node-singletons/net.d.ts +9 -0
- package/src/node-singletons/net.d.ts.map +1 -0
- package/src/node-singletons/net.js +8 -0
- package/src/node-singletons/os.d.ts +3 -3
- package/src/node-singletons/os.d.ts.map +1 -1
- package/src/node-singletons/os.js +3 -4
- package/src/node-singletons/path.d.ts +3 -1
- package/src/node-singletons/path.d.ts.map +1 -1
- package/src/node-singletons/path.js +3 -1
- package/src/node-singletons/perf-hooks.d.ts +3 -1
- package/src/node-singletons/perf-hooks.d.ts.map +1 -1
- package/src/node-singletons/perf-hooks.js +3 -1
- package/src/node-singletons/process.d.ts +23 -0
- package/src/node-singletons/process.d.ts.map +1 -0
- package/src/node-singletons/process.js +8 -0
- package/src/node-singletons/readline.d.ts +3 -3
- package/src/node-singletons/readline.d.ts.map +1 -1
- package/src/node-singletons/readline.js +3 -4
- package/src/node-singletons/tls.d.ts +9 -0
- package/src/node-singletons/tls.d.ts.map +1 -0
- package/src/node-singletons/tls.js +8 -0
- package/src/node-singletons/url.d.ts +3 -1
- package/src/node-singletons/url.d.ts.map +1 -1
- package/src/node-singletons/url.js +3 -1
- package/src/orm/ConnectionManager.d.ts +6 -1
- package/src/orm/ConnectionManager.d.ts.map +1 -1
- package/src/orm/ConnectionManager.js +14 -0
- package/src/orm/DatabaseAdapter.d.ts +6 -0
- package/src/orm/DatabaseAdapter.d.ts.map +1 -1
- package/src/orm/QueryBuilder.d.ts +8 -1
- package/src/orm/QueryBuilder.d.ts.map +1 -1
- package/src/orm/QueryBuilder.js +188 -28
- package/src/orm/adapters/D1Adapter.d.ts.map +1 -1
- package/src/orm/adapters/D1Adapter.js +18 -12
- package/src/orm/adapters/MySQLAdapter.d.ts.map +1 -1
- package/src/orm/adapters/MySQLAdapter.js +4 -0
- package/src/orm/adapters/PostgreSQLAdapter.d.ts.map +1 -1
- package/src/orm/adapters/PostgreSQLAdapter.js +4 -0
- package/src/orm/adapters/SQLServerAdapter.d.ts.map +1 -1
- package/src/orm/adapters/SQLServerAdapter.js +4 -0
- package/src/orm/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/src/orm/adapters/SQLiteAdapter.js +4 -0
- package/src/performance/CodeGenerationBenchmark.js +3 -3
- package/src/performance/Optimizer.d.ts +1 -1
- package/src/performance/Optimizer.d.ts.map +1 -1
- package/src/performance/Optimizer.js +150 -75
- package/src/performance/establish-baseline.js +3 -3
- package/src/runtime/PluginManager.d.ts +3 -1
- package/src/runtime/PluginManager.d.ts.map +1 -1
- package/src/runtime/PluginManager.js +124 -28
- package/src/runtime/RuntimeDetector.d.ts.map +1 -1
- package/src/runtime/RuntimeDetector.js +47 -6
- package/src/runtime/adapters/CloudflareAdapter.js +2 -2
- package/src/runtime/adapters/FargateAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/FargateAdapter.js +2 -1
- package/src/runtime/adapters/LambdaAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/LambdaAdapter.js +4 -2
- package/src/runtime/adapters/NodeServerAdapter.d.ts.map +1 -1
- package/src/runtime/adapters/NodeServerAdapter.js +2 -1
- package/src/scheduler/ScheduleRunner.d.ts +18 -0
- package/src/scheduler/ScheduleRunner.d.ts.map +1 -0
- package/src/scheduler/ScheduleRunner.js +155 -0
- package/src/scheduler/index.d.ts +3 -0
- package/src/scheduler/index.d.ts.map +1 -0
- package/src/scheduler/index.js +1 -0
- package/src/scheduler/types.d.ts +16 -0
- package/src/scheduler/types.d.ts.map +1 -0
- package/src/scheduler/types.js +4 -0
- package/src/schedules/index.d.ts +2 -0
- package/src/schedules/index.d.ts.map +1 -0
- package/src/schedules/index.js +1 -0
- package/src/schedules/log-cleanup.d.ts +4 -0
- package/src/schedules/log-cleanup.d.ts.map +1 -0
- package/src/schedules/log-cleanup.js +18 -0
- package/src/scripts/GenerateEnvArtifacts.d.ts +13 -0
- package/src/scripts/GenerateEnvArtifacts.d.ts.map +1 -0
- package/src/scripts/GenerateEnvArtifacts.js +171 -0
- package/src/scripts/TemplateSync.js +109 -70
- package/src/security/CsrfTokenManager.js +1 -1
- package/src/security/Encryptor.js +1 -1
- package/src/security/Hash.d.ts +14 -0
- package/src/security/Hash.d.ts.map +1 -0
- package/src/security/Hash.js +81 -0
- package/src/security/StartupSecretValidation.d.ts +20 -0
- package/src/security/StartupSecretValidation.d.ts.map +1 -0
- package/src/security/StartupSecretValidation.js +61 -0
- package/src/security/UrlValidator.d.ts +0 -1
- package/src/security/UrlValidator.d.ts.map +1 -1
- package/src/security/UrlValidator.js +1 -2
- package/src/security/Xss.d.ts +14 -0
- package/src/security/Xss.d.ts.map +1 -0
- package/src/security/Xss.js +57 -0
- package/src/security/XssProtection.d.ts.map +1 -1
- package/src/security/XssProtection.js +155 -17
- package/src/templates/adapters/MySQLAdapter.ts.tpl +5 -0
- package/src/templates/adapters/PostgreSQLAdapter.ts.tpl +5 -0
- package/src/templates/adapters/SQLServerAdapter.ts.tpl +5 -0
- package/src/templates/adapters/SQLiteAdapter.ts.tpl +5 -0
- package/src/templates/features/Queue.ts.tpl +1 -29
- package/src/templates/project/basic/.env.example.tpl +48 -0
- package/src/templates/project/basic/.env.tpl +89 -94
- package/src/templates/project/basic/app/Toolkit/Broadcast/sendBroadcast.ts.tpl +7 -0
- package/src/templates/project/basic/app/Toolkit/Mail/sendWelcomeEmail.ts.tpl +30 -0
- package/src/templates/project/basic/app/Toolkit/Notification/sendSlackNotification.ts.tpl +10 -0
- package/src/templates/project/basic/app/Toolkit/Notification/sendSms.ts.tpl +13 -0
- package/src/templates/project/basic/config/FileLogWriter.ts.tpl +240 -0
- package/src/templates/project/basic/config/SecretsManager.ts.tpl +44 -21
- package/src/templates/project/basic/config/StartupConfigValidator.ts.tpl +151 -0
- package/src/templates/project/basic/config/app.ts.tpl +84 -15
- package/src/templates/project/basic/config/broadcast.ts.tpl +97 -0
- package/src/templates/project/basic/config/cache.ts.tpl +19 -23
- package/src/templates/project/basic/config/cloudflare.ts.tpl +57 -0
- package/src/templates/project/basic/config/env.ts.tpl +7 -1
- package/src/templates/project/basic/config/index.ts.tpl +3 -0
- package/src/templates/project/basic/config/logger.ts.tpl +301 -11
- package/src/templates/project/basic/config/logging/HttpLogger.ts.tpl +121 -0
- package/src/templates/project/basic/config/logging/KvLogger.ts.tpl +181 -0
- package/src/templates/project/basic/config/logging/SlackLogger.ts.tpl +156 -0
- package/src/templates/project/basic/config/mail.ts.tpl +141 -0
- package/src/templates/project/basic/config/middleware.ts.tpl +27 -0
- package/src/templates/project/basic/config/notification.ts.tpl +86 -0
- package/src/templates/project/basic/config/security.ts.tpl +4 -5
- package/src/templates/project/basic/config/startup.ts.tpl +27 -0
- package/src/templates/project/basic/config/storage.ts.tpl +77 -42
- package/src/templates/project/basic/database/migrations/index.ts.tpl +1 -1
- package/src/templates/project/basic/package.json.tpl +1 -1
- package/src/templates/project/basic/routes/api.ts.tpl +11 -37
- package/src/templates/project/basic/routes/broadcast.ts.tpl +32 -0
- package/src/templates/project/basic/routes/health.ts.tpl +134 -0
- package/src/templates/project/basic/routes/storage.ts.tpl +42 -0
- package/src/templates/project/basic/src/index.ts.tpl +38 -11
- package/src/templates/project/basic/template.json +3 -0
- package/src/toolkit/Secrets/EnvFile.d.ts +15 -0
- package/src/toolkit/Secrets/EnvFile.d.ts.map +1 -0
- package/src/toolkit/Secrets/EnvFile.js +63 -0
- package/src/toolkit/Secrets/Manifest.d.ts +24 -0
- package/src/toolkit/Secrets/Manifest.d.ts.map +1 -0
- package/src/toolkit/Secrets/Manifest.js +71 -0
- package/src/toolkit/Secrets/index.d.ts +42 -0
- package/src/toolkit/Secrets/index.d.ts.map +1 -0
- package/src/toolkit/Secrets/index.js +119 -0
- package/src/toolkit/Secrets/providers/AwsSecretsManager.d.ts +14 -0
- package/src/toolkit/Secrets/providers/AwsSecretsManager.d.ts.map +1 -0
- package/src/toolkit/Secrets/providers/AwsSecretsManager.js +131 -0
- package/src/toolkit/Secrets/providers/CloudflareKv.d.ts +9 -0
- package/src/toolkit/Secrets/providers/CloudflareKv.d.ts.map +1 -0
- package/src/toolkit/Secrets/providers/CloudflareKv.js +73 -0
- package/src/tools/broadcast/Broadcast.d.ts +7 -0
- package/src/tools/broadcast/Broadcast.d.ts.map +1 -0
- package/src/tools/broadcast/Broadcast.js +37 -0
- package/src/tools/broadcast/drivers/BaseDriver.d.ts +5 -0
- package/src/tools/broadcast/drivers/BaseDriver.d.ts.map +1 -0
- package/src/tools/broadcast/drivers/BaseDriver.js +8 -0
- package/src/tools/broadcast/drivers/InMemory.d.ts +18 -0
- package/src/tools/broadcast/drivers/InMemory.d.ts.map +1 -0
- package/src/tools/broadcast/drivers/InMemory.js +16 -0
- package/src/tools/broadcast/drivers/Pusher.d.ts +8 -0
- package/src/tools/broadcast/drivers/Pusher.d.ts.map +1 -0
- package/src/tools/broadcast/drivers/Pusher.js +75 -0
- package/src/tools/broadcast/drivers/Redis.d.ts +19 -0
- package/src/tools/broadcast/drivers/Redis.d.ts.map +1 -0
- package/src/tools/broadcast/drivers/Redis.js +73 -0
- package/src/tools/broadcast/drivers/RedisHttps.d.ts +14 -0
- package/src/tools/broadcast/drivers/RedisHttps.d.ts.map +1 -0
- package/src/tools/broadcast/drivers/RedisHttps.js +50 -0
- package/src/tools/broadcast/index.d.ts +7 -0
- package/src/tools/broadcast/index.d.ts.map +1 -0
- package/src/tools/broadcast/index.js +6 -0
- package/src/tools/http/Http.d.ts +49 -0
- package/src/tools/http/Http.d.ts.map +1 -0
- package/src/tools/http/Http.js +169 -0
- package/src/tools/http/HttpResponse.d.ts +32 -0
- package/src/tools/http/HttpResponse.d.ts.map +1 -0
- package/src/tools/http/HttpResponse.js +80 -0
- package/src/tools/http/index.d.ts +15 -0
- package/src/tools/http/index.d.ts.map +1 -0
- package/src/tools/http/index.js +9 -0
- package/src/tools/mail/Mail.d.ts +22 -0
- package/src/tools/mail/Mail.d.ts.map +1 -0
- package/src/tools/mail/Mail.js +105 -0
- package/src/tools/mail/attachments.d.ts +23 -0
- package/src/tools/mail/attachments.d.ts.map +1 -0
- package/src/tools/mail/attachments.js +26 -0
- package/src/tools/mail/drivers/BaseDriver.d.ts +5 -0
- package/src/tools/mail/drivers/BaseDriver.d.ts.map +1 -0
- package/src/tools/mail/drivers/BaseDriver.js +8 -0
- package/src/tools/mail/drivers/Mailgun.d.ts +31 -0
- package/src/tools/mail/drivers/Mailgun.d.ts.map +1 -0
- package/src/tools/mail/drivers/Mailgun.js +81 -0
- package/src/tools/mail/drivers/SendGrid.d.ts +29 -0
- package/src/tools/mail/drivers/SendGrid.d.ts.map +1 -0
- package/src/tools/mail/drivers/SendGrid.js +57 -0
- package/src/tools/mail/drivers/Ses.d.ts +24 -0
- package/src/tools/mail/drivers/Ses.d.ts.map +1 -0
- package/src/tools/mail/drivers/Ses.js +116 -0
- package/src/tools/mail/drivers/Smtp.d.ts +38 -0
- package/src/tools/mail/drivers/Smtp.d.ts.map +1 -0
- package/src/tools/mail/drivers/Smtp.js +327 -0
- package/src/tools/mail/templates/index.d.ts +27 -0
- package/src/tools/mail/templates/index.d.ts.map +1 -0
- package/src/tools/mail/templates/index.js +35 -0
- package/src/tools/mail/templates/markdown/index.d.ts +17 -0
- package/src/tools/mail/templates/markdown/index.d.ts.map +1 -0
- package/src/tools/mail/templates/markdown/index.js +49 -0
- package/src/tools/mail/templates/markdown/registry.d.ts +15 -0
- package/src/tools/mail/templates/markdown/registry.d.ts.map +1 -0
- package/src/tools/mail/templates/markdown/registry.js +34 -0
- package/src/tools/mail/templates/markdown/validator.d.ts +16 -0
- package/src/tools/mail/templates/markdown/validator.d.ts.map +1 -0
- package/src/tools/mail/templates/markdown/validator.js +24 -0
- package/src/tools/mail/testing.d.ts +41 -0
- package/src/tools/mail/testing.d.ts.map +1 -0
- package/src/tools/mail/testing.js +34 -0
- package/src/tools/notification/Driver.d.ts +11 -0
- package/src/tools/notification/Driver.d.ts.map +1 -0
- package/src/tools/notification/Driver.js +1 -0
- package/src/tools/notification/Notification.d.ts +11 -0
- package/src/tools/notification/Notification.d.ts.map +1 -0
- package/src/tools/notification/Notification.js +11 -0
- package/src/tools/notification/Registry.d.ts +10 -0
- package/src/tools/notification/Registry.d.ts.map +1 -0
- package/src/tools/notification/Registry.js +22 -0
- package/src/tools/notification/Service.d.ts +6 -0
- package/src/tools/notification/Service.d.ts.map +1 -0
- package/src/tools/notification/Service.js +18 -0
- package/src/tools/notification/config.d.ts +5 -0
- package/src/tools/notification/config.d.ts.map +1 -0
- package/src/tools/notification/config.js +5 -0
- package/src/tools/notification/drivers/BaseDriver.d.ts +5 -0
- package/src/tools/notification/drivers/BaseDriver.d.ts.map +1 -0
- package/src/tools/notification/drivers/BaseDriver.js +8 -0
- package/src/tools/notification/drivers/Console.d.ts +7 -0
- package/src/tools/notification/drivers/Console.d.ts.map +1 -0
- package/src/tools/notification/drivers/Console.js +13 -0
- package/src/tools/notification/drivers/Slack.d.ts +16 -0
- package/src/tools/notification/drivers/Slack.d.ts.map +1 -0
- package/src/tools/notification/drivers/Slack.js +24 -0
- package/src/tools/notification/drivers/Termii.d.ts +10 -0
- package/src/tools/notification/drivers/Termii.d.ts.map +1 -0
- package/src/tools/notification/drivers/Termii.js +47 -0
- package/src/tools/notification/drivers/Twilio.d.ts +21 -0
- package/src/tools/notification/drivers/Twilio.d.ts.map +1 -0
- package/src/tools/notification/drivers/Twilio.js +48 -0
- package/src/tools/notification/templates/markdown/index.d.ts +15 -0
- package/src/tools/notification/templates/markdown/index.d.ts.map +1 -0
- package/src/tools/notification/templates/markdown/index.js +38 -0
- package/src/tools/notification/templates/markdown/registry.d.ts +15 -0
- package/src/tools/notification/templates/markdown/registry.d.ts.map +1 -0
- package/src/tools/notification/templates/markdown/registry.js +36 -0
- package/src/tools/notification/testing.d.ts +19 -0
- package/src/tools/notification/testing.d.ts.map +1 -0
- package/src/tools/notification/testing.js +35 -0
- package/src/tools/notification/testingHelpers.d.ts +12 -0
- package/src/tools/notification/testingHelpers.d.ts.map +1 -0
- package/src/tools/notification/testingHelpers.js +32 -0
- package/src/tools/queue/Queue.d.ts +23 -0
- package/src/tools/queue/Queue.d.ts.map +1 -0
- package/src/tools/queue/Queue.js +38 -0
- package/src/tools/queue/drivers/InMemory.d.ts +10 -0
- package/src/tools/queue/drivers/InMemory.d.ts.map +1 -0
- package/src/tools/queue/drivers/InMemory.js +55 -0
- package/src/tools/queue/drivers/Redis.d.ts +10 -0
- package/src/tools/queue/drivers/Redis.d.ts.map +1 -0
- package/src/tools/queue/drivers/Redis.js +91 -0
- package/src/tools/storage/LocalSignedUrl.d.ts +12 -0
- package/src/tools/storage/LocalSignedUrl.d.ts.map +1 -0
- package/src/tools/storage/LocalSignedUrl.js +108 -0
- package/src/tools/storage/drivers/Gcs.d.ts +20 -0
- package/src/tools/storage/drivers/Gcs.d.ts.map +1 -0
- package/src/tools/storage/drivers/Gcs.js +152 -0
- package/src/tools/storage/drivers/Local.d.ts +18 -0
- package/src/tools/storage/drivers/Local.d.ts.map +1 -0
- package/src/tools/storage/drivers/Local.js +89 -0
- package/src/tools/storage/drivers/R2.d.ts +20 -0
- package/src/tools/storage/drivers/R2.d.ts.map +1 -0
- package/src/tools/storage/drivers/R2.js +73 -0
- package/src/tools/storage/drivers/S3.d.ts +26 -0
- package/src/tools/storage/drivers/S3.d.ts.map +1 -0
- package/src/tools/storage/drivers/S3.js +258 -0
- package/src/tools/storage/index.d.ts +24 -0
- package/src/tools/storage/index.d.ts.map +1 -0
- package/src/tools/storage/index.js +111 -0
- package/src/tools/storage/testing.d.ts +23 -0
- package/src/tools/storage/testing.d.ts.map +1 -0
- package/src/tools/storage/testing.js +52 -0
- package/src/tools/templates/MarkdownRenderer.d.ts +14 -0
- package/src/tools/templates/MarkdownRenderer.d.ts.map +1 -0
- package/src/tools/templates/MarkdownRenderer.js +300 -0
- package/src/tools/templates/index.d.ts +5 -0
- package/src/tools/templates/index.d.ts.map +1 -0
- package/src/tools/templates/index.js +4 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ErrorFactory } from '../../exceptions/ZintrustError';
|
|
2
|
+
const drivers = new Map();
|
|
3
|
+
export const Queue = Object.freeze({
|
|
4
|
+
register(name, driver) {
|
|
5
|
+
drivers.set(name.toLowerCase(), driver);
|
|
6
|
+
},
|
|
7
|
+
get(name) {
|
|
8
|
+
const driverName = (name ?? process.env['QUEUE_DRIVER'] ?? 'inmemory')
|
|
9
|
+
.toString()
|
|
10
|
+
.trim()
|
|
11
|
+
.toLowerCase();
|
|
12
|
+
const driver = drivers.get(driverName);
|
|
13
|
+
if (!driver)
|
|
14
|
+
throw ErrorFactory.createConfigError(`Queue driver not registered: ${driverName}`);
|
|
15
|
+
return driver;
|
|
16
|
+
},
|
|
17
|
+
async enqueue(queue, payload, driverName) {
|
|
18
|
+
const driver = Queue.get(driverName);
|
|
19
|
+
return driver.enqueue(queue, payload);
|
|
20
|
+
},
|
|
21
|
+
async dequeue(queue, driverName) {
|
|
22
|
+
const driver = Queue.get(driverName);
|
|
23
|
+
return driver.dequeue(queue);
|
|
24
|
+
},
|
|
25
|
+
async ack(queue, id, driverName) {
|
|
26
|
+
const driver = Queue.get(driverName);
|
|
27
|
+
return driver.ack(queue, id);
|
|
28
|
+
},
|
|
29
|
+
async length(queue, driverName) {
|
|
30
|
+
const driver = Queue.get(driverName);
|
|
31
|
+
return driver.length(queue);
|
|
32
|
+
},
|
|
33
|
+
async drain(queue, driverName) {
|
|
34
|
+
const driver = Queue.get(driverName);
|
|
35
|
+
return driver.drain(queue);
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
export default Queue;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { QueueMessage } from '../../queue/Queue';
|
|
2
|
+
export declare const InMemoryQueue: {
|
|
3
|
+
readonly enqueue: <T = unknown>(queue: string, payload: T) => Promise<string>;
|
|
4
|
+
readonly dequeue: <T = unknown>(queue: string) => Promise<QueueMessage<T> | undefined>;
|
|
5
|
+
readonly ack: (_queue: string, _id: string) => Promise<void>;
|
|
6
|
+
readonly length: (queue: string) => Promise<number>;
|
|
7
|
+
readonly drain: (queue: string) => Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
export default InMemoryQueue;
|
|
10
|
+
//# sourceMappingURL=InMemory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InMemory.d.ts","sourceRoot":"","sources":["../../../../../src/tools/queue/drivers/InMemory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIlD,eAAO,MAAM,aAAa;uBAQR,CAAC,mBAAmB,MAAM,WAAW,CAAC,KAAG,OAAO,CAAC,MAAM,CAAC;uBAmBxD,CAAC,mBAAmB,MAAM,KAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;2BAW7D,MAAM,OAAO,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;6BAKjC,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;4BAOzB,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;CAMzC,CAAC;AAEL,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { generateUuid } from '../../../common/uuid';
|
|
2
|
+
export const InMemoryQueue = (() => {
|
|
3
|
+
const store = new Map();
|
|
4
|
+
const ensure = (queue) => {
|
|
5
|
+
if (!store.has(queue))
|
|
6
|
+
store.set(queue, []);
|
|
7
|
+
};
|
|
8
|
+
return {
|
|
9
|
+
async enqueue(queue, payload) {
|
|
10
|
+
await Promise.resolve();
|
|
11
|
+
ensure(queue);
|
|
12
|
+
const id = generateUuid();
|
|
13
|
+
const msg = {
|
|
14
|
+
id,
|
|
15
|
+
payload: payload,
|
|
16
|
+
attempts: 0,
|
|
17
|
+
enqueuedAt: Date.now(),
|
|
18
|
+
};
|
|
19
|
+
const arr = store.get(queue);
|
|
20
|
+
if (arr && arr.length > 0) {
|
|
21
|
+
arr.push(msg);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
store.set(queue, [msg]);
|
|
25
|
+
}
|
|
26
|
+
return id;
|
|
27
|
+
},
|
|
28
|
+
async dequeue(queue) {
|
|
29
|
+
await Promise.resolve();
|
|
30
|
+
ensure(queue);
|
|
31
|
+
const arr = store.get(queue);
|
|
32
|
+
if (arr && arr.length > 0) {
|
|
33
|
+
const msg = arr.shift();
|
|
34
|
+
return msg;
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
},
|
|
38
|
+
async ack(_queue, _id) {
|
|
39
|
+
// in-memory dequeue already removed the message; ack is a no-op
|
|
40
|
+
await Promise.resolve();
|
|
41
|
+
},
|
|
42
|
+
async length(queue) {
|
|
43
|
+
await Promise.resolve();
|
|
44
|
+
ensure(queue);
|
|
45
|
+
const arr = store.get(queue);
|
|
46
|
+
return Array.isArray(arr) ? arr.length : 0;
|
|
47
|
+
},
|
|
48
|
+
async drain(queue) {
|
|
49
|
+
await Promise.resolve();
|
|
50
|
+
ensure(queue);
|
|
51
|
+
store.set(queue, []);
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
})();
|
|
55
|
+
export default InMemoryQueue;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { QueueMessage } from '../../queue/Queue';
|
|
2
|
+
export declare const RedisQueue: {
|
|
3
|
+
readonly enqueue: <T = unknown>(queue: string, payload: T) => Promise<string>;
|
|
4
|
+
readonly dequeue: <T = unknown>(queue: string) => Promise<QueueMessage<T> | undefined>;
|
|
5
|
+
readonly ack: (_queue: string, _id: string) => Promise<void>;
|
|
6
|
+
readonly length: (queue: string) => Promise<number>;
|
|
7
|
+
readonly drain: (queue: string) => Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
export default RedisQueue;
|
|
10
|
+
//# sourceMappingURL=Redis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Redis.d.ts","sourceRoot":"","sources":["../../../../../src/tools/queue/drivers/Redis.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAelD,eAAO,MAAM,UAAU;uBAuDL,CAAC,mBAAmB,MAAM,WAAW,CAAC,KAAG,OAAO,CAAC,MAAM,CAAC;uBAQxD,CAAC,mBAAmB,MAAM,KAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;2BAY7D,MAAM,OAAO,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;6BAMjC,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;4BAKzB,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;CAKzC,CAAC;AAEL,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { generateUuid } from '../../../common/uuid';
|
|
2
|
+
import { ErrorFactory } from '../../../exceptions/ZintrustError';
|
|
3
|
+
const getRedisUrl = () => {
|
|
4
|
+
const url = (process.env['REDIS_URL'] ?? '').trim();
|
|
5
|
+
return url.length > 0 ? url : null;
|
|
6
|
+
};
|
|
7
|
+
export const RedisQueue = (() => {
|
|
8
|
+
let client = null;
|
|
9
|
+
let connected = false;
|
|
10
|
+
const ensureClient = async () => {
|
|
11
|
+
if (connected && client !== null)
|
|
12
|
+
return client;
|
|
13
|
+
const url = getRedisUrl();
|
|
14
|
+
if (url === null)
|
|
15
|
+
throw ErrorFactory.createConfigError('Redis queue driver requires REDIS_URL');
|
|
16
|
+
// Import lazily so package is optional for environments that don't use Redis
|
|
17
|
+
// Prefer real 'redis' package when available, otherwise allow tests to inject a fake client
|
|
18
|
+
try {
|
|
19
|
+
// Dynamically import the redis package if available (optional dependency)
|
|
20
|
+
// Tests can inject a fake client on `globalThis.__fakeRedisClient` if the package is absent.
|
|
21
|
+
// Dynamically import the redis package if available (optional dependency)
|
|
22
|
+
const mod = (await import('redis'));
|
|
23
|
+
const createClient = mod.createClient;
|
|
24
|
+
client = createClient({ url });
|
|
25
|
+
if (typeof client.connect === 'function') {
|
|
26
|
+
try {
|
|
27
|
+
// Await connect to ensure readiness; network errors will be surfaced
|
|
28
|
+
await client.connect();
|
|
29
|
+
connected = true;
|
|
30
|
+
}
|
|
31
|
+
catch (connectionError) {
|
|
32
|
+
connected = false;
|
|
33
|
+
// log non-fatally — operations will surface errors as needed
|
|
34
|
+
// eslint-disable-next-line no-console
|
|
35
|
+
console.warn('Redis client connect failed:', String(connectionError));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
connected = true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
const globalFake = globalThis
|
|
44
|
+
.__fakeRedisClient;
|
|
45
|
+
if (globalFake === undefined) {
|
|
46
|
+
throw ErrorFactory.createConfigError("Redis queue driver requires the 'redis' package or a test fake client set in globalThis.__fakeRedisClient");
|
|
47
|
+
}
|
|
48
|
+
client = globalFake;
|
|
49
|
+
connected = true;
|
|
50
|
+
}
|
|
51
|
+
if (client === null)
|
|
52
|
+
throw ErrorFactory.createConfigError('Redis client could not be initialized');
|
|
53
|
+
return client;
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
async enqueue(queue, payload) {
|
|
57
|
+
const cli = await ensureClient();
|
|
58
|
+
const id = generateUuid();
|
|
59
|
+
const msg = JSON.stringify({ id, payload, attempts: 0 });
|
|
60
|
+
await cli.rPush(queue, msg);
|
|
61
|
+
return id;
|
|
62
|
+
},
|
|
63
|
+
async dequeue(queue) {
|
|
64
|
+
const cli = await ensureClient();
|
|
65
|
+
const raw = await cli.lPop(queue);
|
|
66
|
+
if (raw === null)
|
|
67
|
+
return undefined;
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(raw);
|
|
70
|
+
return parsed;
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
throw ErrorFactory.createTryCatchError('Failed to parse queue message', err);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
async ack(_queue, _id) {
|
|
77
|
+
// Simple list-based queue removes on dequeue, so ack is a no-op here.
|
|
78
|
+
// For visibility timeout or retry semantics, implement BRPOPLPUSH and a processing list.
|
|
79
|
+
return Promise.resolve(); // NOSONAR
|
|
80
|
+
},
|
|
81
|
+
async length(queue) {
|
|
82
|
+
const cli = await ensureClient();
|
|
83
|
+
return cli.lLen(queue);
|
|
84
|
+
},
|
|
85
|
+
async drain(queue) {
|
|
86
|
+
const cli = await ensureClient();
|
|
87
|
+
await cli.del(queue);
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
})();
|
|
91
|
+
export default RedisQueue;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type LocalSignedUrlPayload = {
|
|
2
|
+
disk: 'local';
|
|
3
|
+
key: string;
|
|
4
|
+
exp: number;
|
|
5
|
+
method: 'GET';
|
|
6
|
+
};
|
|
7
|
+
export declare const LocalSignedUrl: Readonly<{
|
|
8
|
+
createToken(payload: LocalSignedUrlPayload, secret: string): string;
|
|
9
|
+
verifyToken(token: string, secret: string, nowMs?: number): LocalSignedUrlPayload;
|
|
10
|
+
}>;
|
|
11
|
+
export default LocalSignedUrl;
|
|
12
|
+
//# sourceMappingURL=LocalSignedUrl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalSignedUrl.d.ts","sourceRoot":"","sources":["../../../../src/tools/storage/LocalSignedUrl.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,KAAK,CAAC;CACf,CAAC;AA8DF,eAAO,MAAM,cAAc;yBACJ,qBAAqB,UAAU,MAAM,GAAG,MAAM;uBAyBhD,MAAM,UAAU,MAAM,UAAS,MAAM,GAAgB,qBAAqB;EA2C7F,CAAC;AAEH,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { ErrorFactory } from '../../exceptions/ZintrustError';
|
|
2
|
+
import { createHmac } from '../../node-singletons/crypto';
|
|
3
|
+
const base64UrlEncode = (value) => {
|
|
4
|
+
const base64 = Buffer.isBuffer(value)
|
|
5
|
+
? value.toString('base64')
|
|
6
|
+
: Buffer.from(value).toString('base64');
|
|
7
|
+
// replace characters used in regular base64 and remove any trailing '=' padding
|
|
8
|
+
let result = base64.replaceAll('+', '-').replaceAll('/', '_');
|
|
9
|
+
// Remove trailing '=' characters without using a regex to avoid potential super-linear backtracking.
|
|
10
|
+
while (result.endsWith('=')) {
|
|
11
|
+
result = result.slice(0, -1);
|
|
12
|
+
}
|
|
13
|
+
return result;
|
|
14
|
+
};
|
|
15
|
+
const base64UrlDecodeToString = (value) => {
|
|
16
|
+
const padded = value + '==='.slice((value.length + 3) % 4);
|
|
17
|
+
const base64 = padded.replaceAll('-', '+').replaceAll('_', '/');
|
|
18
|
+
return Buffer.from(base64, 'base64').toString('utf8');
|
|
19
|
+
};
|
|
20
|
+
const timingSafeEquals = (a, b) => {
|
|
21
|
+
if (a.length !== b.length)
|
|
22
|
+
return false;
|
|
23
|
+
let result = 0;
|
|
24
|
+
for (let i = 0; i < a.length; i++) {
|
|
25
|
+
result |= (a.codePointAt(i) ?? 0) ^ (b.codePointAt(i) ?? 0);
|
|
26
|
+
}
|
|
27
|
+
return result === 0;
|
|
28
|
+
};
|
|
29
|
+
const assertValidKey = (key) => {
|
|
30
|
+
if (key.trim() === '') {
|
|
31
|
+
throw ErrorFactory.createValidationError('Local signed url: key is required');
|
|
32
|
+
}
|
|
33
|
+
// Hard fail on obvious traversal / absolute paths.
|
|
34
|
+
// Keep this strict; keys should be relative like `uploads/a.png`.
|
|
35
|
+
if (key.startsWith('/') || key.startsWith('\\')) {
|
|
36
|
+
throw ErrorFactory.createValidationError('Local signed url: key must be relative');
|
|
37
|
+
}
|
|
38
|
+
const segments = key.split(/[/\\]+/g);
|
|
39
|
+
if (segments.some((s) => s === '..' || s === '.')) {
|
|
40
|
+
throw ErrorFactory.createValidationError('Local signed url: invalid key');
|
|
41
|
+
}
|
|
42
|
+
if (key.includes('\0')) {
|
|
43
|
+
throw ErrorFactory.createValidationError('Local signed url: invalid key');
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const sign = (payloadEncoded, secret) => {
|
|
47
|
+
if (secret.trim() === '') {
|
|
48
|
+
throw ErrorFactory.createConfigError('Local signed url: signing secret not configured (set APP_KEY)');
|
|
49
|
+
}
|
|
50
|
+
const signature = createHmac('sha256', secret).update(payloadEncoded).digest();
|
|
51
|
+
return base64UrlEncode(signature);
|
|
52
|
+
};
|
|
53
|
+
export const LocalSignedUrl = Object.freeze({
|
|
54
|
+
createToken(payload, secret) {
|
|
55
|
+
assertValidKey(payload.key);
|
|
56
|
+
if (payload.disk !== 'local') {
|
|
57
|
+
throw ErrorFactory.createValidationError('Local signed url: unsupported disk', {
|
|
58
|
+
disk: payload.disk,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (payload.method !== 'GET') {
|
|
62
|
+
throw ErrorFactory.createValidationError('Local signed url: unsupported method', {
|
|
63
|
+
method: payload.method,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (!Number.isFinite(payload.exp) || payload.exp <= 0) {
|
|
67
|
+
throw ErrorFactory.createValidationError('Local signed url: invalid expiration');
|
|
68
|
+
}
|
|
69
|
+
const payloadEncoded = base64UrlEncode(JSON.stringify(payload));
|
|
70
|
+
const signatureEncoded = sign(payloadEncoded, secret);
|
|
71
|
+
return `${payloadEncoded}.${signatureEncoded}`;
|
|
72
|
+
},
|
|
73
|
+
verifyToken(token, secret, nowMs = Date.now()) {
|
|
74
|
+
if (token.trim() === '') {
|
|
75
|
+
throw ErrorFactory.createValidationError('Local signed url: token is required');
|
|
76
|
+
}
|
|
77
|
+
const parts = token.split('.');
|
|
78
|
+
if (parts.length !== 2) {
|
|
79
|
+
throw ErrorFactory.createValidationError('Local signed url: malformed token');
|
|
80
|
+
}
|
|
81
|
+
const payloadEncoded = parts[0] ?? '';
|
|
82
|
+
const signatureEncoded = parts[1] ?? '';
|
|
83
|
+
const expectedSignature = sign(payloadEncoded, secret);
|
|
84
|
+
if (!timingSafeEquals(signatureEncoded, expectedSignature)) {
|
|
85
|
+
throw ErrorFactory.createSecurityError('Local signed url: invalid signature');
|
|
86
|
+
}
|
|
87
|
+
let payload;
|
|
88
|
+
try {
|
|
89
|
+
payload = JSON.parse(base64UrlDecodeToString(payloadEncoded));
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
throw ErrorFactory.createValidationError('Local signed url: invalid payload', { error: err });
|
|
93
|
+
}
|
|
94
|
+
const p = payload;
|
|
95
|
+
if (p.disk !== 'local' ||
|
|
96
|
+
typeof p.key !== 'string' ||
|
|
97
|
+
typeof p.exp !== 'number' ||
|
|
98
|
+
p.method !== 'GET') {
|
|
99
|
+
throw ErrorFactory.createValidationError('Local signed url: invalid payload');
|
|
100
|
+
}
|
|
101
|
+
assertValidKey(p.key);
|
|
102
|
+
if (p.exp < nowMs) {
|
|
103
|
+
throw ErrorFactory.createSecurityError('Local signed url: token expired');
|
|
104
|
+
}
|
|
105
|
+
return p;
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
export default LocalSignedUrl;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type GcsConfig = {
|
|
2
|
+
bucket: string;
|
|
3
|
+
projectId?: string;
|
|
4
|
+
keyFile?: string;
|
|
5
|
+
url?: string;
|
|
6
|
+
};
|
|
7
|
+
type TempUrlOptions = {
|
|
8
|
+
expiresIn?: number;
|
|
9
|
+
method?: 'GET' | 'PUT';
|
|
10
|
+
};
|
|
11
|
+
export declare const GcsDriver: Readonly<{
|
|
12
|
+
url(config: GcsConfig, key: string): string | undefined;
|
|
13
|
+
put(config: GcsConfig, key: string, content: string | Buffer): Promise<string>;
|
|
14
|
+
get(config: GcsConfig, key: string): Promise<Buffer>;
|
|
15
|
+
exists(config: GcsConfig, key: string): Promise<boolean>;
|
|
16
|
+
delete(config: GcsConfig, key: string): Promise<void>;
|
|
17
|
+
tempUrl(config: GcsConfig, key: string, options?: TempUrlOptions): Promise<string>;
|
|
18
|
+
}>;
|
|
19
|
+
export default GcsDriver;
|
|
20
|
+
//# sourceMappingURL=Gcs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Gcs.d.ts","sourceRoot":"","sources":["../../../../../src/tools/storage/drivers/Gcs.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,KAAK,cAAc,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,CAAA;CAAE,CAAC;AA+ErE,eAAO,MAAM,SAAS;gBACR,SAAS,OAAO,MAAM,GAAG,MAAM,GAAG,SAAS;gBAWrC,SAAS,OAAO,MAAM,WAAW,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;gBAkBlE,SAAS,OAAO,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;mBAiBrC,SAAS,OAAO,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;mBAgBzC,SAAS,OAAO,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;oBAiBrC,SAAS,OAAO,MAAM,YAAY,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;EA8BxF,CAAC;AAEH,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { ErrorFactory } from '../../../exceptions/ZintrustError';
|
|
2
|
+
let cachedRealClient;
|
|
3
|
+
const getInjectedStorageModule = () => {
|
|
4
|
+
return globalThis
|
|
5
|
+
.__fakeGoogleCloudStorageModule;
|
|
6
|
+
};
|
|
7
|
+
const getInjectedFakeClient = () => {
|
|
8
|
+
const v = globalThis.__fakeGcsClient;
|
|
9
|
+
return v;
|
|
10
|
+
};
|
|
11
|
+
const loadRealClient = async (config) => {
|
|
12
|
+
if (cachedRealClient !== undefined)
|
|
13
|
+
return cachedRealClient;
|
|
14
|
+
// Avoid a string-literal import so TypeScript doesn't require the module at build time.
|
|
15
|
+
const specifier = '@google-cloud/storage';
|
|
16
|
+
const injected = getInjectedStorageModule();
|
|
17
|
+
let mod;
|
|
18
|
+
try {
|
|
19
|
+
mod = (injected ?? (await import(specifier)));
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
throw ErrorFactory.createConfigError('GCS: missing optional dependency @google-cloud/storage (install it or inject globalThis.__fakeGcsClient for tests)', { error: err });
|
|
23
|
+
}
|
|
24
|
+
if (typeof mod.Storage !== 'function') {
|
|
25
|
+
throw ErrorFactory.createConfigError('GCS: @google-cloud/storage did not export Storage');
|
|
26
|
+
}
|
|
27
|
+
const opts = {};
|
|
28
|
+
if (typeof config.projectId === 'string' && config.projectId.trim() !== '') {
|
|
29
|
+
opts['projectId'] = config.projectId;
|
|
30
|
+
}
|
|
31
|
+
if (typeof config.keyFile === 'string' && config.keyFile.trim() !== '') {
|
|
32
|
+
opts['keyFilename'] = config.keyFile;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
cachedRealClient = new mod.Storage(opts);
|
|
36
|
+
return cachedRealClient;
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
throw ErrorFactory.createConfigError('GCS: failed to initialize Storage client', {
|
|
40
|
+
error: err,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const getClient = async (config) => {
|
|
45
|
+
const injected = getInjectedFakeClient();
|
|
46
|
+
if (injected !== undefined)
|
|
47
|
+
return injected;
|
|
48
|
+
return loadRealClient(config);
|
|
49
|
+
};
|
|
50
|
+
const encodePathSegments = (key) => key
|
|
51
|
+
.split('/')
|
|
52
|
+
.map((seg) => encodeURIComponent(seg))
|
|
53
|
+
.join('/');
|
|
54
|
+
export const GcsDriver = Object.freeze({
|
|
55
|
+
url(config, key) {
|
|
56
|
+
const bucket = String(config.bucket ?? '').trim();
|
|
57
|
+
if (bucket === '')
|
|
58
|
+
return undefined;
|
|
59
|
+
const base = typeof config.url === 'string' ? config.url.trim() : '';
|
|
60
|
+
if (base !== '')
|
|
61
|
+
return `${base.replace(/\/$/, '')}/${key}`;
|
|
62
|
+
const encodedKey = encodePathSegments(key);
|
|
63
|
+
return `https://storage.googleapis.com/${encodeURIComponent(bucket)}/${encodedKey}`;
|
|
64
|
+
},
|
|
65
|
+
async put(config, key, content) {
|
|
66
|
+
const bucket = String(config.bucket ?? '').trim();
|
|
67
|
+
if (bucket === '')
|
|
68
|
+
throw ErrorFactory.createConfigError('GCS: bucket is not configured');
|
|
69
|
+
const client = await getClient(config);
|
|
70
|
+
const file = client.bucket(bucket).file(key);
|
|
71
|
+
if (typeof file.save !== 'function') {
|
|
72
|
+
throw ErrorFactory.createConfigError('GCS: client is missing file.save()');
|
|
73
|
+
}
|
|
74
|
+
await file.save(content);
|
|
75
|
+
const url = GcsDriver.url(config, key);
|
|
76
|
+
if (url === undefined)
|
|
77
|
+
return '';
|
|
78
|
+
return url;
|
|
79
|
+
},
|
|
80
|
+
async get(config, key) {
|
|
81
|
+
const bucket = String(config.bucket ?? '').trim();
|
|
82
|
+
if (bucket === '')
|
|
83
|
+
throw ErrorFactory.createConfigError('GCS: bucket is not configured');
|
|
84
|
+
const client = await getClient(config);
|
|
85
|
+
const file = client.bucket(bucket).file(key);
|
|
86
|
+
if (typeof file.download !== 'function') {
|
|
87
|
+
throw ErrorFactory.createConfigError('GCS: client is missing file.download()');
|
|
88
|
+
}
|
|
89
|
+
const [data] = await file.download();
|
|
90
|
+
if (Buffer.isBuffer(data))
|
|
91
|
+
return data;
|
|
92
|
+
if (typeof data === 'string')
|
|
93
|
+
return Buffer.from(data);
|
|
94
|
+
return Buffer.from(data);
|
|
95
|
+
},
|
|
96
|
+
async exists(config, key) {
|
|
97
|
+
const bucket = String(config.bucket ?? '').trim();
|
|
98
|
+
if (bucket === '')
|
|
99
|
+
throw ErrorFactory.createConfigError('GCS: bucket is not configured');
|
|
100
|
+
const client = await getClient(config);
|
|
101
|
+
const file = client.bucket(bucket).file(key);
|
|
102
|
+
if (typeof file.exists !== 'function') {
|
|
103
|
+
// if client doesn't support exists, assume true (matches Storage.exists default behavior)
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
const [exists] = await file.exists();
|
|
107
|
+
return Boolean(exists);
|
|
108
|
+
},
|
|
109
|
+
async delete(config, key) {
|
|
110
|
+
const bucket = String(config.bucket ?? '').trim();
|
|
111
|
+
if (bucket === '')
|
|
112
|
+
throw ErrorFactory.createConfigError('GCS: bucket is not configured');
|
|
113
|
+
const client = await getClient(config);
|
|
114
|
+
const file = client.bucket(bucket).file(key);
|
|
115
|
+
if (typeof file.delete !== 'function')
|
|
116
|
+
return;
|
|
117
|
+
try {
|
|
118
|
+
// google-cloud-storage supports ignoreNotFound, but keep it flexible for fakes
|
|
119
|
+
await file.delete({ ignoreNotFound: true });
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
void err; // NOSONAR
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
async tempUrl(config, key, options) {
|
|
126
|
+
const bucket = String(config.bucket ?? '').trim();
|
|
127
|
+
if (bucket === '')
|
|
128
|
+
throw ErrorFactory.createConfigError('GCS: bucket is not configured');
|
|
129
|
+
const expiresIn = options?.expiresIn ?? 900;
|
|
130
|
+
if (!Number.isFinite(expiresIn) || expiresIn <= 0) {
|
|
131
|
+
throw ErrorFactory.createValidationError('GCS: expiresIn must be a positive number', {
|
|
132
|
+
expiresIn,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
if (expiresIn > 604800) {
|
|
136
|
+
throw ErrorFactory.createValidationError('GCS: expiresIn exceeds 7 days', {
|
|
137
|
+
expiresIn,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
const method = options?.method ?? 'GET';
|
|
141
|
+
const action = method === 'PUT' ? 'write' : 'read';
|
|
142
|
+
const client = await getClient(config);
|
|
143
|
+
const file = client.bucket(bucket).file(key);
|
|
144
|
+
if (typeof file.getSignedUrl !== 'function') {
|
|
145
|
+
throw ErrorFactory.createConfigError('GCS: client is missing file.getSignedUrl()');
|
|
146
|
+
}
|
|
147
|
+
const expires = Date.now() + expiresIn * 1000;
|
|
148
|
+
const [url] = await file.getSignedUrl({ version: 'v4', action, expires });
|
|
149
|
+
return url;
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
export default GcsDriver;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type LocalConfig = {
|
|
2
|
+
root: string;
|
|
3
|
+
url?: string;
|
|
4
|
+
};
|
|
5
|
+
export declare const LocalDriver: Readonly<{
|
|
6
|
+
resolveKey(config: LocalConfig, key: string): string;
|
|
7
|
+
put(config: LocalConfig, key: string, content: string | Buffer): Promise<string>;
|
|
8
|
+
get(config: LocalConfig, key: string): Promise<Buffer>;
|
|
9
|
+
exists(config: LocalConfig, key: string): Promise<boolean>;
|
|
10
|
+
delete(config: LocalConfig, key: string): Promise<void>;
|
|
11
|
+
url(config: LocalConfig, key: string): string | undefined;
|
|
12
|
+
tempUrl(config: LocalConfig, key: string, options?: {
|
|
13
|
+
expiresIn?: number;
|
|
14
|
+
method?: "GET" | "PUT";
|
|
15
|
+
}): string;
|
|
16
|
+
}>;
|
|
17
|
+
export default LocalDriver;
|
|
18
|
+
//# sourceMappingURL=Local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Local.d.ts","sourceRoot":"","sources":["../../../../../src/tools/storage/drivers/Local.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,eAAO,MAAM,WAAW;uBACH,WAAW,OAAO,MAAM,GAAG,MAAM;gBAuBlC,WAAW,OAAO,MAAM,WAAW,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;gBAapE,WAAW,OAAO,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;mBASvC,WAAW,OAAO,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;mBAU3C,WAAW,OAAO,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;gBASjD,WAAW,OAAO,MAAM,GAAG,MAAM,GAAG,SAAS;oBAM/C,WAAW,OACd,MAAM,YACD;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,CAAA;KAAE,GACvD,MAAM;EA4BT,CAAC;AAEH,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Env } from '../../../config/env';
|
|
2
|
+
import { ErrorFactory } from '../../../exceptions/ZintrustError';
|
|
3
|
+
import { fsPromises as fs } from '../../../node-singletons/fs';
|
|
4
|
+
import * as path from '../../../node-singletons/path';
|
|
5
|
+
import { LocalSignedUrl } from '../LocalSignedUrl';
|
|
6
|
+
export const LocalDriver = Object.freeze({
|
|
7
|
+
resolveKey(config, key) {
|
|
8
|
+
if (!config.root || config.root.trim() === '') {
|
|
9
|
+
throw ErrorFactory.createConfigError('Local storage root is not configured');
|
|
10
|
+
}
|
|
11
|
+
if (key.trim() === '') {
|
|
12
|
+
throw ErrorFactory.createValidationError('Local storage: key is required');
|
|
13
|
+
}
|
|
14
|
+
if (key.startsWith('/') || key.startsWith('\\')) {
|
|
15
|
+
throw ErrorFactory.createValidationError('Local storage: key must be relative');
|
|
16
|
+
}
|
|
17
|
+
const segments = key.split(/[/\\]+/g);
|
|
18
|
+
if (segments.some((s) => s === '..' || s === '.')) {
|
|
19
|
+
throw ErrorFactory.createValidationError('Local storage: invalid key');
|
|
20
|
+
}
|
|
21
|
+
const fullPath = path.resolve(path.join(config.root, key));
|
|
22
|
+
return fullPath;
|
|
23
|
+
},
|
|
24
|
+
async put(config, key, content) {
|
|
25
|
+
const fullPath = LocalDriver.resolveKey(config, key);
|
|
26
|
+
const dir = path.dirname(fullPath);
|
|
27
|
+
await fs.mkdir(dir, { recursive: true });
|
|
28
|
+
if (typeof content === 'string') {
|
|
29
|
+
await fs.writeFile(fullPath, content, 'utf8');
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
await fs.writeFile(fullPath, content);
|
|
33
|
+
}
|
|
34
|
+
return fullPath;
|
|
35
|
+
},
|
|
36
|
+
async get(config, key) {
|
|
37
|
+
const fullPath = LocalDriver.resolveKey(config, key);
|
|
38
|
+
try {
|
|
39
|
+
return await fs.readFile(fullPath);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
throw ErrorFactory.createNotFoundError('Local storage: file not found', { key, error: err });
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
async exists(config, key) {
|
|
46
|
+
const fullPath = LocalDriver.resolveKey(config, key);
|
|
47
|
+
try {
|
|
48
|
+
await fs.access(fullPath);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
async delete(config, key) {
|
|
56
|
+
const fullPath = LocalDriver.resolveKey(config, key);
|
|
57
|
+
try {
|
|
58
|
+
await fs.unlink(fullPath);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// ignore not found
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
url(config, key) {
|
|
65
|
+
if (config?.url === undefined || config.url.trim() === '')
|
|
66
|
+
return undefined;
|
|
67
|
+
return `${config.url.replace(/\/$/, '')}/${key}`;
|
|
68
|
+
},
|
|
69
|
+
tempUrl(config, key, options) {
|
|
70
|
+
if (options?.method === 'PUT') {
|
|
71
|
+
throw ErrorFactory.createValidationError('Local storage: tempUrl does not support PUT');
|
|
72
|
+
}
|
|
73
|
+
if (config?.url === undefined || config.url.trim() === '') {
|
|
74
|
+
throw ErrorFactory.createConfigError('Local storage: url is not configured (set STORAGE_URL)');
|
|
75
|
+
}
|
|
76
|
+
const appKey = Env.get('APP_KEY', '');
|
|
77
|
+
if (appKey.trim() === '') {
|
|
78
|
+
throw ErrorFactory.createConfigError('Local storage: APP_KEY is required for signed tempUrl()');
|
|
79
|
+
}
|
|
80
|
+
// Ensure key is safe before embedding in a signed token.
|
|
81
|
+
LocalDriver.resolveKey(config, key);
|
|
82
|
+
const expiresInMs = Math.max(1, options?.expiresIn ?? 60_000);
|
|
83
|
+
const exp = Date.now() + expiresInMs;
|
|
84
|
+
const token = LocalSignedUrl.createToken({ disk: 'local', key, exp, method: 'GET' }, appKey);
|
|
85
|
+
const baseUrl = config.url.replace(/\/$/, '');
|
|
86
|
+
return `${baseUrl}/download?token=${encodeURIComponent(token)}`;
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
export default LocalDriver;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type R2Config = {
|
|
2
|
+
bucket: string;
|
|
3
|
+
region?: string;
|
|
4
|
+
accessKeyId: string;
|
|
5
|
+
secretAccessKey: string;
|
|
6
|
+
endpoint?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const R2Driver: Readonly<{
|
|
9
|
+
put(config: R2Config, key: string, content: string | Buffer): Promise<string>;
|
|
10
|
+
get(config: R2Config, key: string): Promise<Buffer>;
|
|
11
|
+
exists(config: R2Config, key: string): Promise<boolean>;
|
|
12
|
+
delete(config: R2Config, key: string): Promise<void>;
|
|
13
|
+
url(config: R2Config, key: string): string;
|
|
14
|
+
tempUrl(config: R2Config, key: string, options?: {
|
|
15
|
+
expiresIn?: number;
|
|
16
|
+
method?: "GET" | "PUT";
|
|
17
|
+
}): string;
|
|
18
|
+
}>;
|
|
19
|
+
export default R2Driver;
|
|
20
|
+
//# sourceMappingURL=R2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"R2.d.ts","sourceRoot":"","sources":["../../../../../src/tools/storage/drivers/R2.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,QAAQ;gBACD,QAAQ,OAAO,MAAM,WAAW,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;gBAkBjE,QAAQ,OAAO,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;mBAapC,QAAQ,OAAO,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;mBAaxC,QAAQ,OAAO,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;gBAa9C,QAAQ,OAAO,MAAM,GAAG,MAAM;oBAQhC,QAAQ,OACX,MAAM,YACD;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,CAAA;KAAE,GACvD,MAAM;EAgBT,CAAC;AAEH,eAAe,QAAQ,CAAC"}
|