alepha 0.14.2 → 0.14.4
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 +1 -1
- package/dist/api/audits/index.browser.js +5 -5
- package/dist/api/audits/index.browser.js.map +1 -1
- package/dist/api/audits/index.d.ts +706 -785
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +13 -13
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.browser.js +5 -5
- package/dist/api/files/index.browser.js.map +1 -1
- package/dist/api/files/index.d.ts +58 -137
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +71 -71
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.browser.js +5 -5
- package/dist/api/jobs/index.browser.js.map +1 -1
- package/dist/api/jobs/index.d.ts +29 -108
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +10 -10
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/notifications/index.browser.js +10 -10
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +504 -171
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +12 -12
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.browser.js +163 -10
- package/dist/api/parameters/index.browser.js.map +1 -1
- package/dist/api/parameters/index.d.ts +277 -351
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +196 -91
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/users/index.browser.js +19 -19
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +787 -852
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +827 -596
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.browser.js +6 -6
- package/dist/api/verifications/index.browser.js.map +1 -1
- package/dist/api/verifications/index.d.ts +128 -128
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +6 -6
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/bin/index.d.ts +1 -2
- package/dist/bin/index.js +0 -1
- package/dist/bin/index.js.map +1 -1
- package/dist/cli/index.d.ts +252 -131
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +595 -395
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +46 -11
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +99 -19
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +40 -22
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +45 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +40 -22
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +40 -22
- package/dist/core/index.native.js.map +1 -1
- package/dist/fake/index.js +195 -168
- package/dist/fake/index.js.map +1 -1
- package/dist/file/index.d.ts +8 -0
- package/dist/file/index.d.ts.map +1 -1
- package/dist/file/index.js +3 -0
- package/dist/file/index.js.map +1 -1
- package/dist/logger/index.d.ts +1 -1
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +12 -2
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/index.d.ts +59 -195
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +201 -430
- package/dist/orm/index.js.map +1 -1
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +171 -155
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +0 -1
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.d.ts +12 -0
- package/dist/server/cache/index.d.ts.map +1 -1
- package/dist/server/cache/index.js +55 -2
- package/dist/server/cache/index.js.map +1 -1
- package/dist/server/compress/index.d.ts +6 -0
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/compress/index.js +38 -1
- package/dist/server/compress/index.js.map +1 -1
- package/dist/server/core/index.browser.js +2 -2
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts +10 -10
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +7 -4
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/links/index.browser.js +22 -6
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +46 -44
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +24 -41
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/static/index.js +4 -0
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts +2 -1
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +9 -5
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/vite/index.d.ts +101 -106
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +574 -503
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.d.ts +7 -7
- package/package.json +7 -7
- package/src/api/audits/controllers/{AuditController.ts → AdminAuditController.ts} +5 -6
- package/src/api/audits/entities/audits.ts +5 -5
- package/src/api/audits/index.browser.ts +1 -1
- package/src/api/audits/index.ts +3 -3
- package/src/api/audits/primitives/$audit.spec.ts +276 -0
- package/src/api/audits/services/AuditService.spec.ts +495 -0
- package/src/api/files/__tests__/$bucket.spec.ts +91 -0
- package/src/api/files/controllers/AdminFileStatsController.spec.ts +166 -0
- package/src/api/files/controllers/{StorageStatsController.ts → AdminFileStatsController.ts} +2 -2
- package/src/api/files/controllers/FileController.spec.ts +558 -0
- package/src/api/files/controllers/FileController.ts +4 -5
- package/src/api/files/entities/files.ts +5 -5
- package/src/api/files/index.browser.ts +1 -1
- package/src/api/files/index.ts +4 -4
- package/src/api/files/jobs/FileJobs.spec.ts +52 -0
- package/src/api/files/services/FileService.spec.ts +109 -0
- package/src/api/jobs/__tests__/JobController.spec.ts +343 -0
- package/src/api/jobs/controllers/{JobController.ts → AdminJobController.ts} +2 -2
- package/src/api/jobs/entities/jobExecutions.ts +5 -5
- package/src/api/jobs/index.ts +3 -3
- package/src/api/jobs/primitives/$job.spec.ts +476 -0
- package/src/api/notifications/controllers/{NotificationController.ts → AdminNotificationController.ts} +4 -5
- package/src/api/notifications/entities/notifications.ts +5 -5
- package/src/api/notifications/index.browser.ts +1 -1
- package/src/api/notifications/index.ts +4 -4
- package/src/api/parameters/controllers/{ConfigController.ts → AdminConfigController.ts} +46 -107
- package/src/api/parameters/entities/parameters.ts +7 -17
- package/src/api/parameters/index.ts +3 -3
- package/src/api/parameters/primitives/$config.spec.ts +356 -0
- package/src/api/parameters/schemas/activateConfigBodySchema.ts +12 -0
- package/src/api/parameters/schemas/checkScheduledResponseSchema.ts +8 -0
- package/src/api/parameters/schemas/configCurrentResponseSchema.ts +13 -0
- package/src/api/parameters/schemas/configHistoryResponseSchema.ts +9 -0
- package/src/api/parameters/schemas/configNameParamSchema.ts +10 -0
- package/src/api/parameters/schemas/configNamesResponseSchema.ts +8 -0
- package/src/api/parameters/schemas/configTreeNodeSchema.ts +13 -0
- package/src/api/parameters/schemas/configVersionParamSchema.ts +9 -0
- package/src/api/parameters/schemas/configVersionResponseSchema.ts +9 -0
- package/src/api/parameters/schemas/configsByStatusResponseSchema.ts +9 -0
- package/src/api/parameters/schemas/createConfigVersionBodySchema.ts +24 -0
- package/src/api/parameters/schemas/index.ts +15 -0
- package/src/api/parameters/schemas/parameterResponseSchema.ts +26 -0
- package/src/api/parameters/schemas/parameterStatusSchema.ts +13 -0
- package/src/api/parameters/schemas/rollbackConfigBodySchema.ts +15 -0
- package/src/api/parameters/schemas/statusParamSchema.ts +9 -0
- package/src/api/users/__tests__/EmailVerification.spec.ts +369 -0
- package/src/api/users/__tests__/PasswordReset.spec.ts +550 -0
- package/src/api/users/controllers/AdminIdentityController.spec.ts +365 -0
- package/src/api/users/controllers/{IdentityController.ts → AdminIdentityController.ts} +3 -4
- package/src/api/users/controllers/AdminSessionController.spec.ts +274 -0
- package/src/api/users/controllers/{SessionController.ts → AdminSessionController.ts} +3 -4
- package/src/api/users/controllers/AdminUserController.spec.ts +372 -0
- package/src/api/users/controllers/AdminUserController.ts +116 -0
- package/src/api/users/controllers/UserController.ts +4 -107
- package/src/api/users/controllers/UserRealmController.ts +3 -0
- package/src/api/users/entities/identities.ts +6 -6
- package/src/api/users/entities/sessions.ts +6 -6
- package/src/api/users/entities/users.ts +9 -9
- package/src/api/users/index.ts +9 -6
- package/src/api/users/primitives/$userRealm.ts +13 -8
- package/src/api/users/services/CredentialService.spec.ts +509 -0
- package/src/api/users/services/CredentialService.ts +46 -0
- package/src/api/users/services/IdentityService.ts +15 -0
- package/src/api/users/services/RegistrationService.spec.ts +630 -0
- package/src/api/users/services/RegistrationService.ts +18 -0
- package/src/api/users/services/SessionService.spec.ts +301 -0
- package/src/api/users/services/SessionService.ts +110 -1
- package/src/api/users/services/UserService.ts +67 -2
- package/src/api/verifications/__tests__/CodeVerification.spec.ts +318 -0
- package/src/api/verifications/__tests__/LinkVerification.spec.ts +279 -0
- package/src/api/verifications/entities/verifications.ts +6 -6
- package/src/api/verifications/jobs/VerificationJobs.spec.ts +50 -0
- package/src/batch/__tests__/startup-buffering.spec.ts +458 -0
- package/src/batch/primitives/$batch.spec.ts +766 -0
- package/src/batch/providers/BatchProvider.spec.ts +786 -0
- package/src/bin/index.ts +0 -1
- package/src/bucket/__tests__/shared.ts +194 -0
- package/src/bucket/primitives/$bucket.spec.ts +104 -0
- package/src/bucket/providers/FileStorageProvider.spec.ts +13 -0
- package/src/bucket/providers/LocalFileStorageProvider.spec.ts +77 -0
- package/src/bucket/providers/MemoryFileStorageProvider.spec.ts +82 -0
- package/src/cache/core/__tests__/shared.ts +377 -0
- package/src/cache/core/primitives/$cache.spec.ts +111 -0
- package/src/cache/redis/__tests__/cache-redis.spec.ts +70 -0
- package/src/cli/apps/AlephaCli.ts +25 -6
- package/src/cli/atoms/buildOptions.ts +88 -0
- package/src/cli/commands/build.ts +32 -69
- package/src/cli/commands/db.ts +0 -4
- package/src/cli/commands/dev.ts +34 -10
- package/src/cli/commands/gen/changelog.spec.ts +315 -0
- package/src/cli/commands/{changelog.ts → gen/changelog.ts} +9 -9
- package/src/cli/commands/gen/env.ts +53 -0
- package/src/cli/commands/gen/openapi.ts +71 -0
- package/src/cli/commands/gen/resource.ts +15 -0
- package/src/cli/commands/gen.ts +24 -0
- package/src/cli/commands/init.ts +2 -1
- package/src/cli/commands/root.ts +12 -3
- package/src/cli/commands/test.ts +0 -1
- package/src/cli/commands/typecheck.ts +5 -0
- package/src/cli/commands/verify.ts +1 -1
- package/src/cli/defineConfig.ts +49 -7
- package/src/cli/index.ts +2 -2
- package/src/cli/services/AlephaCliUtils.ts +105 -55
- package/src/cli/services/GitMessageParser.ts +1 -1
- package/src/command/helpers/Asker.spec.ts +127 -0
- package/src/command/helpers/Runner.spec.ts +126 -0
- package/src/command/helpers/Runner.ts +1 -1
- package/src/command/primitives/$command.spec.ts +1588 -0
- package/src/command/primitives/$command.ts +0 -6
- package/src/command/providers/CliProvider.ts +75 -27
- package/src/core/Alepha.ts +87 -0
- package/src/core/__tests__/Alepha-emit.spec.ts +22 -0
- package/src/core/__tests__/Alepha-graph.spec.ts +93 -0
- package/src/core/__tests__/Alepha-has.spec.ts +41 -0
- package/src/core/__tests__/Alepha-inject.spec.ts +93 -0
- package/src/core/__tests__/Alepha-register.spec.ts +81 -0
- package/src/core/__tests__/Alepha-start.spec.ts +176 -0
- package/src/core/__tests__/Alepha-with.spec.ts +14 -0
- package/src/core/__tests__/TypeBox-usecases.spec.ts +35 -0
- package/src/core/__tests__/TypeBoxLocale.spec.ts +15 -0
- package/src/core/__tests__/descriptor.spec.ts +34 -0
- package/src/core/__tests__/fixtures/A.ts +5 -0
- package/src/core/__tests__/pagination.spec.ts +77 -0
- package/src/core/helpers/jsonSchemaToTypeBox.ts +2 -2
- package/src/core/primitives/$atom.spec.ts +43 -0
- package/src/core/primitives/$hook.spec.ts +130 -0
- package/src/core/primitives/$inject.spec.ts +175 -0
- package/src/core/primitives/$module.spec.ts +115 -0
- package/src/core/providers/CodecManager.spec.ts +740 -0
- package/src/core/providers/EventManager.spec.ts +762 -0
- package/src/core/providers/EventManager.ts +4 -0
- package/src/core/providers/StateManager.spec.ts +365 -0
- package/src/core/providers/TypeProvider.spec.ts +1607 -0
- package/src/core/providers/TypeProvider.ts +20 -26
- package/src/datetime/primitives/$interval.spec.ts +103 -0
- package/src/datetime/providers/DateTimeProvider.spec.ts +86 -0
- package/src/email/primitives/$email.spec.ts +175 -0
- package/src/email/providers/LocalEmailProvider.spec.ts +341 -0
- package/src/fake/__tests__/keyName.example.ts +40 -0
- package/src/fake/__tests__/keyName.spec.ts +152 -0
- package/src/fake/__tests__/module.example.ts +32 -0
- package/src/fake/providers/FakeProvider.spec.ts +438 -0
- package/src/file/providers/FileSystemProvider.ts +8 -0
- package/src/file/providers/NodeFileSystemProvider.spec.ts +418 -0
- package/src/file/providers/NodeFileSystemProvider.ts +5 -0
- package/src/file/services/FileDetector.spec.ts +591 -0
- package/src/lock/core/__tests__/shared.ts +190 -0
- package/src/lock/core/providers/MemoryLockProvider.spec.ts +25 -0
- package/src/lock/redis/providers/RedisLockProvider.spec.ts +25 -0
- package/src/logger/__tests__/SimpleFormatterProvider.spec.ts +109 -0
- package/src/logger/index.ts +15 -3
- package/src/logger/primitives/$logger.spec.ts +108 -0
- package/src/logger/services/Logger.spec.ts +295 -0
- package/src/mcp/__tests__/errors.spec.ts +175 -0
- package/src/mcp/__tests__/integration.spec.ts +450 -0
- package/src/mcp/helpers/jsonrpc.spec.ts +380 -0
- package/src/mcp/primitives/$prompt.spec.ts +468 -0
- package/src/mcp/primitives/$resource.spec.ts +390 -0
- package/src/mcp/primitives/$tool.spec.ts +406 -0
- package/src/mcp/providers/McpServerProvider.spec.ts +797 -0
- package/src/mcp/transports/StdioMcpTransport.ts +1 -1
- package/src/orm/__tests__/$repository-crud.spec.ts +276 -0
- package/src/orm/__tests__/$repository-hooks.spec.ts +325 -0
- package/src/orm/__tests__/$repository-orderBy.spec.ts +128 -0
- package/src/orm/__tests__/$repository-pagination-sort.spec.ts +149 -0
- package/src/orm/__tests__/$repository-save.spec.ts +37 -0
- package/src/orm/__tests__/ModelBuilder-integration.spec.ts +490 -0
- package/src/orm/__tests__/ModelBuilder-types.spec.ts +186 -0
- package/src/orm/__tests__/PostgresProvider.spec.ts +46 -0
- package/src/orm/__tests__/delete-returning.spec.ts +256 -0
- package/src/orm/__tests__/deletedAt.spec.ts +80 -0
- package/src/orm/__tests__/enums.spec.ts +315 -0
- package/src/orm/__tests__/execute.spec.ts +72 -0
- package/src/orm/__tests__/fixtures/bigEntitySchema.ts +65 -0
- package/src/orm/__tests__/fixtures/userEntitySchema.ts +27 -0
- package/src/orm/__tests__/joins.spec.ts +1114 -0
- package/src/orm/__tests__/page.spec.ts +287 -0
- package/src/orm/__tests__/primaryKey.spec.ts +87 -0
- package/src/orm/__tests__/query-date-encoding.spec.ts +402 -0
- package/src/orm/__tests__/ref-auto-onDelete.spec.ts +156 -0
- package/src/orm/__tests__/references.spec.ts +102 -0
- package/src/orm/__tests__/security.spec.ts +710 -0
- package/src/orm/__tests__/sqlite.spec.ts +111 -0
- package/src/orm/__tests__/string-operators.spec.ts +429 -0
- package/src/orm/__tests__/timestamps.spec.ts +388 -0
- package/src/orm/__tests__/validation.spec.ts +183 -0
- package/src/orm/__tests__/version.spec.ts +64 -0
- package/src/orm/helpers/parseQueryString.spec.ts +196 -0
- package/src/orm/index.ts +2 -8
- package/src/orm/primitives/$repository.spec.ts +137 -0
- package/src/orm/primitives/$sequence.spec.ts +29 -0
- package/src/orm/primitives/$transaction.spec.ts +82 -0
- package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -3
- package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
- package/src/orm/providers/drivers/CloudflareD1Provider.ts +1 -1
- package/src/orm/providers/drivers/DatabaseProvider.ts +1 -1
- package/src/orm/providers/drivers/NodePostgresProvider.ts +3 -3
- package/src/orm/providers/drivers/NodeSqliteProvider.ts +1 -1
- package/src/orm/providers/drivers/PglitePostgresProvider.ts +2 -2
- package/src/orm/services/ModelBuilder.spec.ts +575 -0
- package/src/orm/services/Repository.spec.ts +137 -0
- package/src/queue/core/__tests__/shared.ts +143 -0
- package/src/queue/core/providers/MemoryQueueProvider.spec.ts +23 -0
- package/src/queue/core/providers/WorkerProvider.spec.ts +394 -0
- package/src/queue/redis/providers/RedisQueueProvider.spec.ts +23 -0
- package/src/redis/__tests__/redis.spec.ts +58 -0
- package/src/retry/primitives/$retry.spec.ts +234 -0
- package/src/retry/providers/RetryProvider.spec.ts +438 -0
- package/src/router/__tests__/match.spec.ts +252 -0
- package/src/router/providers/RouterProvider.spec.ts +197 -0
- package/src/scheduler/__tests__/$scheduler-cron.spec.ts +25 -0
- package/src/scheduler/__tests__/$scheduler-interval.spec.ts +25 -0
- package/src/scheduler/__tests__/shared.ts +77 -0
- package/src/security/__tests__/bug-1-wildcard-after-start.spec.ts +229 -0
- package/src/security/__tests__/bug-2-password-validation.spec.ts +245 -0
- package/src/security/__tests__/bug-3-regex-vulnerability.spec.ts +407 -0
- package/src/security/__tests__/bug-4-oauth2-validation.spec.ts +439 -0
- package/src/security/__tests__/multi-layer-permissions.spec.ts +522 -0
- package/src/security/primitives/$permission.spec.ts +30 -0
- package/src/security/primitives/$permission.ts +2 -2
- package/src/security/primitives/$realm.spec.ts +101 -0
- package/src/security/primitives/$role.spec.ts +52 -0
- package/src/security/primitives/$serviceAccount.spec.ts +61 -0
- package/src/security/providers/SecurityProvider.spec.ts +350 -0
- package/src/server/auth/providers/ServerAuthProvider.ts +0 -2
- package/src/server/cache/providers/ServerCacheProvider.spec.ts +1125 -0
- package/src/server/cache/providers/ServerCacheProvider.ts +94 -9
- package/src/server/compress/providers/ServerCompressProvider.spec.ts +31 -0
- package/src/server/compress/providers/ServerCompressProvider.ts +63 -2
- package/src/server/cookies/providers/ServerCookiesProvider.spec.ts +253 -0
- package/src/server/core/__tests__/ServerRouterProvider-getRoutes.spec.ts +334 -0
- package/src/server/core/__tests__/ServerRouterProvider-requestId.spec.ts +129 -0
- package/src/server/core/helpers/ServerReply.ts +2 -2
- package/src/server/core/primitives/$action.spec.ts +191 -0
- package/src/server/core/primitives/$route.spec.ts +65 -0
- package/src/server/core/providers/ServerBodyParserProvider.spec.ts +93 -0
- package/src/server/core/providers/ServerLoggerProvider.spec.ts +100 -0
- package/src/server/core/providers/ServerProvider.ts +14 -2
- package/src/server/core/services/HttpClient.spec.ts +123 -0
- package/src/server/core/services/UserAgentParser.spec.ts +111 -0
- package/src/server/cors/providers/ServerCorsProvider.spec.ts +481 -0
- package/src/server/health/providers/ServerHealthProvider.spec.ts +22 -0
- package/src/server/helmet/providers/ServerHelmetProvider.spec.ts +105 -0
- package/src/server/links/__tests__/$action.spec.ts +238 -0
- package/src/server/links/__tests__/fixtures/CrudApp.ts +122 -0
- package/src/server/links/__tests__/requestId.spec.ts +120 -0
- package/src/server/links/primitives/$remote.spec.ts +228 -0
- package/src/server/links/providers/LinkProvider.spec.ts +54 -0
- package/src/server/links/providers/LinkProvider.ts +49 -3
- package/src/server/links/providers/ServerLinksProvider.ts +1 -53
- package/src/server/links/schemas/apiLinksResponseSchema.ts +7 -0
- package/src/server/metrics/providers/ServerMetricsProvider.spec.ts +25 -0
- package/src/server/multipart/providers/ServerMultipartProvider.spec.ts +528 -0
- package/src/server/proxy/primitives/$proxy.spec.ts +87 -0
- package/src/server/rate-limit/__tests__/ActionRateLimit.spec.ts +211 -0
- package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +344 -0
- package/src/server/security/__tests__/BasicAuth.spec.ts +684 -0
- package/src/server/security/__tests__/ServerSecurityProvider-realm.spec.ts +388 -0
- package/src/server/security/providers/ServerSecurityProvider.spec.ts +123 -0
- package/src/server/static/primitives/$serve.spec.ts +193 -0
- package/src/server/static/providers/ServerStaticProvider.ts +10 -0
- package/src/server/swagger/__tests__/ui.spec.ts +52 -0
- package/src/server/swagger/primitives/$swagger.spec.ts +193 -0
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +19 -12
- package/src/sms/primitives/$sms.spec.ts +165 -0
- package/src/sms/providers/LocalSmsProvider.spec.ts +224 -0
- package/src/sms/providers/MemorySmsProvider.spec.ts +193 -0
- package/src/thread/primitives/$thread.spec.ts +186 -0
- package/src/topic/core/__tests__/shared.ts +144 -0
- package/src/topic/core/providers/MemoryTopicProvider.spec.ts +23 -0
- package/src/topic/redis/providers/RedisTopicProvider.spec.ts +23 -0
- package/src/vite/helpers/importViteReact.ts +13 -0
- package/src/vite/index.ts +1 -21
- package/src/vite/plugins/viteAlephaDev.ts +32 -5
- package/src/vite/plugins/viteAlephaSsrPreload.ts +222 -0
- package/src/vite/tasks/buildClient.ts +11 -0
- package/src/vite/tasks/buildServer.ts +47 -3
- package/src/vite/tasks/devServer.ts +69 -0
- package/src/vite/tasks/index.ts +2 -1
- package/src/vite/tasks/runAlepha.ts +7 -1
- package/src/websocket/__tests__/$websocket-new.spec.ts +195 -0
- package/src/websocket/primitives/$channel.spec.ts +30 -0
- package/src/cli/assets/viteConfigTs.ts +0 -14
- package/src/cli/commands/run.ts +0 -24
- package/src/vite/plugins/viteAlepha.ts +0 -37
- package/src/vite/plugins/viteAlephaBuild.ts +0 -281
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { Alepha } from "alepha";
|
|
2
|
+
import { AlephaCache } from "alepha/cache";
|
|
3
|
+
import { $action, AlephaServer, HttpError } from "alepha/server";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
5
|
+
import { $rateLimit, AlephaServerRateLimit } from "../index.ts";
|
|
6
|
+
|
|
7
|
+
describe("Action Rate Limiting", () => {
|
|
8
|
+
let alepha: Alepha;
|
|
9
|
+
|
|
10
|
+
class TestApp {
|
|
11
|
+
// Action with rate limiting enabled via options
|
|
12
|
+
limitedAction = $action({
|
|
13
|
+
rateLimit: { max: 2, windowMs: 1000 },
|
|
14
|
+
handler: () => "success",
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// Action with custom key generator
|
|
18
|
+
userBasedAction = $action({
|
|
19
|
+
rateLimit: {
|
|
20
|
+
max: 3,
|
|
21
|
+
windowMs: 2000,
|
|
22
|
+
keyGenerator: (req) => `user:${req.headers["user-id"] || "anonymous"}`,
|
|
23
|
+
},
|
|
24
|
+
handler: () => "user success",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Action without rate limiting
|
|
28
|
+
unlimitedAction = $action({
|
|
29
|
+
handler: () => "unlimited success",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Rate limit primitive usage
|
|
33
|
+
customRateLimit = $rateLimit({ max: 1, windowMs: 500 });
|
|
34
|
+
|
|
35
|
+
primitiveAction = $action({
|
|
36
|
+
handler: async (request) => {
|
|
37
|
+
const result = await this.customRateLimit.check(request, {
|
|
38
|
+
max: 1,
|
|
39
|
+
windowMs: 500,
|
|
40
|
+
});
|
|
41
|
+
if (!result.allowed) {
|
|
42
|
+
throw new HttpError({
|
|
43
|
+
status: 429,
|
|
44
|
+
message: `Rate limit exceeded. Reset in ${result.retryAfter}s`,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return "primitive success";
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
beforeEach(async () => {
|
|
53
|
+
alepha = Alepha.create()
|
|
54
|
+
.with(AlephaCache)
|
|
55
|
+
.with(AlephaServer)
|
|
56
|
+
.with(AlephaServerRateLimit)
|
|
57
|
+
.with(TestApp);
|
|
58
|
+
|
|
59
|
+
await alepha.start();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
afterEach(async () => {
|
|
63
|
+
await alepha.stop();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("Action rateLimit option", () => {
|
|
67
|
+
it("should allow requests within rate limit", async () => {
|
|
68
|
+
const app = alepha.inject(TestApp);
|
|
69
|
+
|
|
70
|
+
const result1 = await app.limitedAction.run({});
|
|
71
|
+
expect(result1).toBe("success");
|
|
72
|
+
|
|
73
|
+
const result2 = await app.limitedAction.run({});
|
|
74
|
+
expect(result2).toBe("success");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should block requests exceeding rate limit", async () => {
|
|
78
|
+
const app = alepha.inject(TestApp);
|
|
79
|
+
|
|
80
|
+
// First two requests should succeed
|
|
81
|
+
await app.limitedAction.run({});
|
|
82
|
+
await app.limitedAction.run({});
|
|
83
|
+
|
|
84
|
+
// Third request should be rate limited
|
|
85
|
+
await expect(app.limitedAction.run({})).rejects.toThrow(
|
|
86
|
+
"Too Many Requests",
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("should use custom key generator", async () => {
|
|
91
|
+
const app = alepha.inject(TestApp);
|
|
92
|
+
|
|
93
|
+
// Test that the custom key generator allows more requests per user
|
|
94
|
+
// since each user gets their own rate limit bucket
|
|
95
|
+
const result1 = await app.userBasedAction.run({});
|
|
96
|
+
expect(result1).toBe("user success");
|
|
97
|
+
|
|
98
|
+
const result2 = await app.userBasedAction.run({});
|
|
99
|
+
expect(result2).toBe("user success");
|
|
100
|
+
|
|
101
|
+
const result3 = await app.userBasedAction.run({});
|
|
102
|
+
expect(result3).toBe("user success");
|
|
103
|
+
|
|
104
|
+
// Fourth request should be blocked (limit is 3)
|
|
105
|
+
await expect(app.userBasedAction.run({})).rejects.toThrow(
|
|
106
|
+
"Too Many Requests",
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("should not affect unlimited actions", async () => {
|
|
111
|
+
const app = alepha.inject(TestApp);
|
|
112
|
+
|
|
113
|
+
// Should be able to make many requests to unlimited action
|
|
114
|
+
for (let i = 0; i < 10; i++) {
|
|
115
|
+
const result = await app.unlimitedAction.run({});
|
|
116
|
+
expect(result).toBe("unlimited success");
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("should reset rate limit after window expires", async () => {
|
|
121
|
+
const app = alepha.inject(TestApp);
|
|
122
|
+
|
|
123
|
+
// Use up the rate limit
|
|
124
|
+
await app.limitedAction.run({});
|
|
125
|
+
await app.limitedAction.run({});
|
|
126
|
+
|
|
127
|
+
// Should be blocked
|
|
128
|
+
await expect(app.limitedAction.run({})).rejects.toThrow(
|
|
129
|
+
"Too Many Requests",
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
// Wait for the window to expire (1000ms + buffer)
|
|
133
|
+
await new Promise((resolve) => setTimeout(resolve, 1100));
|
|
134
|
+
|
|
135
|
+
// Should be allowed again
|
|
136
|
+
const result = await app.limitedAction.run({});
|
|
137
|
+
expect(result).toBe("success");
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe("$rateLimit primitive", () => {
|
|
142
|
+
it("should create rate limit primitive with options", () => {
|
|
143
|
+
const app = alepha.inject(TestApp);
|
|
144
|
+
|
|
145
|
+
expect(app.customRateLimit).toBeDefined();
|
|
146
|
+
expect(app.customRateLimit.name).toBe("customRateLimit");
|
|
147
|
+
expect(app.customRateLimit.options.max).toBe(1);
|
|
148
|
+
expect(app.customRateLimit.options.windowMs).toBe(500);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("should handle rate limiting in custom action logic", async () => {
|
|
152
|
+
const app = alepha.inject(TestApp);
|
|
153
|
+
|
|
154
|
+
// First request should succeed
|
|
155
|
+
const result1 = await app.primitiveAction.run({});
|
|
156
|
+
expect(result1).toBe("primitive success");
|
|
157
|
+
|
|
158
|
+
// Second request should be blocked by custom logic
|
|
159
|
+
await expect(app.primitiveAction.run({})).rejects.toThrow(
|
|
160
|
+
"Rate limit exceeded",
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe("Integration", () => {
|
|
166
|
+
it("should integrate rate limiting with action hooks", async () => {
|
|
167
|
+
const app = alepha.inject(TestApp);
|
|
168
|
+
|
|
169
|
+
// Just verify that the hook is working by checking that rate limiting is applied
|
|
170
|
+
await app.limitedAction.run({});
|
|
171
|
+
await app.limitedAction.run({});
|
|
172
|
+
|
|
173
|
+
// Third request should trigger rate limiting
|
|
174
|
+
await expect(app.limitedAction.run({})).rejects.toThrow(
|
|
175
|
+
"Too Many Requests",
|
|
176
|
+
);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe("Performance and edge cases", () => {
|
|
181
|
+
it("should handle concurrent requests correctly", async () => {
|
|
182
|
+
const app = alepha.inject(TestApp);
|
|
183
|
+
|
|
184
|
+
// Test sequential requests to avoid race conditions in testing
|
|
185
|
+
let successCount = 0;
|
|
186
|
+
let rateLimitedCount = 0;
|
|
187
|
+
|
|
188
|
+
for (let i = 0; i < 5; i++) {
|
|
189
|
+
try {
|
|
190
|
+
await app.limitedAction.run({});
|
|
191
|
+
successCount++;
|
|
192
|
+
} catch (e: any) {
|
|
193
|
+
if (e.message === "Too Many Requests") {
|
|
194
|
+
rateLimitedCount++;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
expect(successCount).toBe(2);
|
|
200
|
+
expect(rateLimitedCount).toBe(3);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("should handle missing IP gracefully", async () => {
|
|
204
|
+
const app = alepha.inject(TestApp);
|
|
205
|
+
|
|
206
|
+
// Should still work with default IP handling
|
|
207
|
+
const result = await app.limitedAction.run({});
|
|
208
|
+
expect(result).toBe("success");
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
});
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { Alepha } from "alepha";
|
|
2
|
+
import { AlephaCache } from "alepha/cache";
|
|
3
|
+
import {
|
|
4
|
+
$action,
|
|
5
|
+
AlephaServer,
|
|
6
|
+
ServerProvider,
|
|
7
|
+
type ServerRequest,
|
|
8
|
+
} from "alepha/server";
|
|
9
|
+
import { afterEach, beforeEach, describe, expect, it, test } from "vitest";
|
|
10
|
+
import {
|
|
11
|
+
$rateLimit,
|
|
12
|
+
AlephaServerRateLimit,
|
|
13
|
+
rateLimitOptions,
|
|
14
|
+
ServerRateLimitProvider,
|
|
15
|
+
} from "../index.ts";
|
|
16
|
+
|
|
17
|
+
describe("ServerRateLimitProvider", () => {
|
|
18
|
+
let alepha: Alepha;
|
|
19
|
+
let provider: ServerRateLimitProvider;
|
|
20
|
+
|
|
21
|
+
beforeEach(async () => {
|
|
22
|
+
alepha = Alepha.create().with(AlephaCache);
|
|
23
|
+
provider = alepha.inject(ServerRateLimitProvider);
|
|
24
|
+
await alepha.start();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(async () => {
|
|
28
|
+
await alepha.stop();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const createMockRequest = (ip: string = "127.0.0.1"): ServerRequest =>
|
|
32
|
+
({
|
|
33
|
+
ip,
|
|
34
|
+
headers: {},
|
|
35
|
+
method: "GET",
|
|
36
|
+
url: "/test",
|
|
37
|
+
path: "/test",
|
|
38
|
+
query: {},
|
|
39
|
+
params: {},
|
|
40
|
+
body: undefined,
|
|
41
|
+
}) as any;
|
|
42
|
+
|
|
43
|
+
it("should allow requests within limit", async () => {
|
|
44
|
+
const req = createMockRequest();
|
|
45
|
+
const result = await provider.checkLimit(req, { max: 5, windowMs: 60000 });
|
|
46
|
+
|
|
47
|
+
expect(result.allowed).toBe(true);
|
|
48
|
+
expect(result.limit).toBe(5);
|
|
49
|
+
expect(result.remaining).toBe(4);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("should block requests exceeding limit", async () => {
|
|
53
|
+
const req = createMockRequest();
|
|
54
|
+
const options = { max: 2, windowMs: 60000 };
|
|
55
|
+
|
|
56
|
+
// First request should be allowed
|
|
57
|
+
const result1 = await provider.checkLimit(req, options);
|
|
58
|
+
expect(result1.allowed).toBe(true);
|
|
59
|
+
expect(result1.remaining).toBe(1);
|
|
60
|
+
|
|
61
|
+
// Second request should be allowed
|
|
62
|
+
const result2 = await provider.checkLimit(req, options);
|
|
63
|
+
expect(result2.allowed).toBe(true);
|
|
64
|
+
expect(result2.remaining).toBe(0);
|
|
65
|
+
|
|
66
|
+
// Third request should be blocked
|
|
67
|
+
const result3 = await provider.checkLimit(req, options);
|
|
68
|
+
expect(result3.allowed).toBe(false);
|
|
69
|
+
expect(result3.remaining).toBe(0);
|
|
70
|
+
expect(result3.retryAfter).toBeGreaterThan(0);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should handle different IPs separately", async () => {
|
|
74
|
+
const req1 = createMockRequest("192.168.1.1");
|
|
75
|
+
const req2 = createMockRequest("192.168.1.2");
|
|
76
|
+
const options = { max: 1, windowMs: 60000 };
|
|
77
|
+
|
|
78
|
+
// Both requests should be allowed as they come from different IPs
|
|
79
|
+
const result1 = await provider.checkLimit(req1, options);
|
|
80
|
+
const result2 = await provider.checkLimit(req2, options);
|
|
81
|
+
|
|
82
|
+
expect(result1.allowed).toBe(true);
|
|
83
|
+
expect(result2.allowed).toBe(true);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should extract IP from x-forwarded-for header", async () => {
|
|
87
|
+
const options = { max: 1, windowMs: 60000 };
|
|
88
|
+
|
|
89
|
+
// First request with x-forwarded-for: 203.0.113.1
|
|
90
|
+
const req1 = createMockRequest("127.0.0.1");
|
|
91
|
+
req1.headers["x-forwarded-for"] = "203.0.113.1, 192.168.1.1";
|
|
92
|
+
|
|
93
|
+
const result1 = await provider.checkLimit(req1, options);
|
|
94
|
+
expect(result1.allowed).toBe(true);
|
|
95
|
+
|
|
96
|
+
// Second request with same x-forwarded-for should be blocked
|
|
97
|
+
const req2 = createMockRequest("127.0.0.1");
|
|
98
|
+
req2.headers["x-forwarded-for"] = "203.0.113.1, 192.168.1.1";
|
|
99
|
+
|
|
100
|
+
const result2 = await provider.checkLimit(req2, options);
|
|
101
|
+
expect(result2.allowed).toBe(false);
|
|
102
|
+
|
|
103
|
+
// Request with different x-forwarded-for should be allowed
|
|
104
|
+
const req3 = createMockRequest("127.0.0.1");
|
|
105
|
+
req3.headers["x-forwarded-for"] = "198.51.100.1, 192.168.1.1";
|
|
106
|
+
|
|
107
|
+
const result3 = await provider.checkLimit(req3, options);
|
|
108
|
+
expect(result3.allowed).toBe(true);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe("ServerRateLimitProvider Module Integration", () => {
|
|
113
|
+
let alepha: Alepha;
|
|
114
|
+
let provider: ServerRateLimitProvider;
|
|
115
|
+
|
|
116
|
+
class TestApp {
|
|
117
|
+
test = $action({
|
|
118
|
+
handler: () => "success",
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
beforeEach(async () => {
|
|
123
|
+
alepha = Alepha.create()
|
|
124
|
+
.with(AlephaCache)
|
|
125
|
+
.with(AlephaServer)
|
|
126
|
+
.with(AlephaServerRateLimit)
|
|
127
|
+
.with(TestApp);
|
|
128
|
+
provider = alepha.inject(ServerRateLimitProvider);
|
|
129
|
+
await alepha.start();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
afterEach(async () => {
|
|
133
|
+
await alepha.stop();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("should integrate with Alepha framework successfully", async () => {
|
|
137
|
+
expect(provider).toBeDefined();
|
|
138
|
+
expect(provider).toBeInstanceOf(ServerRateLimitProvider);
|
|
139
|
+
expect(typeof provider.checkLimit).toBe("function");
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should work with real action requests", async () => {
|
|
143
|
+
// Configure rate limit for testing
|
|
144
|
+
alepha.store.mut(rateLimitOptions, () => ({
|
|
145
|
+
max: 10,
|
|
146
|
+
windowMs: 60000,
|
|
147
|
+
}));
|
|
148
|
+
|
|
149
|
+
const app = alepha.inject(TestApp);
|
|
150
|
+
|
|
151
|
+
// First request should succeed
|
|
152
|
+
const result = await app.test.run({});
|
|
153
|
+
expect(result).toBe("success");
|
|
154
|
+
|
|
155
|
+
// Multiple requests should still work within limit
|
|
156
|
+
for (let i = 0; i < 5; i++) {
|
|
157
|
+
const result = await app.test.run({});
|
|
158
|
+
expect(result).toBe("success");
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// ---------------------------------------------------------------------------------------------------------------------
|
|
164
|
+
|
|
165
|
+
describe("$rateLimit primitive", () => {
|
|
166
|
+
let alepha: Alepha;
|
|
167
|
+
let server: ServerProvider;
|
|
168
|
+
|
|
169
|
+
afterEach(async () => {
|
|
170
|
+
if (alepha) {
|
|
171
|
+
await alepha.stop();
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("should apply path-specific rate limit to matching routes", async () => {
|
|
176
|
+
class AppWithRateLimit {
|
|
177
|
+
// Path-specific rate limit for /api/v1/* routes
|
|
178
|
+
apiRateLimit = $rateLimit({
|
|
179
|
+
paths: ["/api/v1/*"],
|
|
180
|
+
max: 2,
|
|
181
|
+
windowMs: 60000,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// $action with path "/v1/data" creates route at "/api/v1/data"
|
|
185
|
+
apiAction = $action({
|
|
186
|
+
path: "/v1/data",
|
|
187
|
+
method: "POST",
|
|
188
|
+
handler: () => "success",
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
alepha = Alepha.create()
|
|
193
|
+
.with(AlephaCache)
|
|
194
|
+
.with(AlephaServer)
|
|
195
|
+
.with(AlephaServerRateLimit)
|
|
196
|
+
.with(AppWithRateLimit);
|
|
197
|
+
|
|
198
|
+
server = alepha.inject(ServerProvider);
|
|
199
|
+
await alepha.start();
|
|
200
|
+
|
|
201
|
+
// First two requests should succeed
|
|
202
|
+
const response1 = await fetch(`${server.hostname}/api/v1/data`, {
|
|
203
|
+
method: "POST",
|
|
204
|
+
});
|
|
205
|
+
expect(response1.status).toBe(200);
|
|
206
|
+
expect(response1.headers.get("x-ratelimit-limit")).toBe("2");
|
|
207
|
+
expect(response1.headers.get("x-ratelimit-remaining")).toBe("1");
|
|
208
|
+
|
|
209
|
+
const response2 = await fetch(`${server.hostname}/api/v1/data`, {
|
|
210
|
+
method: "POST",
|
|
211
|
+
});
|
|
212
|
+
expect(response2.status).toBe(200);
|
|
213
|
+
expect(response2.headers.get("x-ratelimit-remaining")).toBe("0");
|
|
214
|
+
|
|
215
|
+
// Third request should be rate limited
|
|
216
|
+
const response3 = await fetch(`${server.hostname}/api/v1/data`, {
|
|
217
|
+
method: "POST",
|
|
218
|
+
});
|
|
219
|
+
expect(response3.status).toBe(429);
|
|
220
|
+
expect(response3.headers.get("retry-after")).toBeDefined();
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test("should register rate limit configs with provider", async () => {
|
|
224
|
+
class RegistrationApp {
|
|
225
|
+
limit1 = $rateLimit({
|
|
226
|
+
name: "api-limit",
|
|
227
|
+
paths: ["/api/*"],
|
|
228
|
+
max: 100,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
limit2 = $rateLimit({
|
|
232
|
+
name: "admin-limit",
|
|
233
|
+
paths: ["/admin/*"],
|
|
234
|
+
max: 10,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
alepha = Alepha.create()
|
|
239
|
+
.with(AlephaCache)
|
|
240
|
+
.with(AlephaServer)
|
|
241
|
+
.with(AlephaServerRateLimit)
|
|
242
|
+
.with(RegistrationApp);
|
|
243
|
+
|
|
244
|
+
const rateLimitProvider = alepha.inject(ServerRateLimitProvider);
|
|
245
|
+
await alepha.start();
|
|
246
|
+
|
|
247
|
+
expect(rateLimitProvider.registeredConfigs).toHaveLength(2);
|
|
248
|
+
expect(rateLimitProvider.registeredConfigs[0].name).toBe("api-limit");
|
|
249
|
+
expect(rateLimitProvider.registeredConfigs[1].name).toBe("admin-limit");
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test("should apply different rate limits to different paths", async () => {
|
|
253
|
+
class MultiRateLimitApp {
|
|
254
|
+
// Strict limit for admin routes
|
|
255
|
+
adminLimit = $rateLimit({
|
|
256
|
+
paths: ["/api/admin/*"],
|
|
257
|
+
max: 1,
|
|
258
|
+
windowMs: 60000,
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Lenient limit for public routes
|
|
262
|
+
publicLimit = $rateLimit({
|
|
263
|
+
paths: ["/api/public/*"],
|
|
264
|
+
max: 10,
|
|
265
|
+
windowMs: 60000,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
adminAction = $action({
|
|
269
|
+
path: "/admin/users",
|
|
270
|
+
method: "GET",
|
|
271
|
+
handler: () => "admin",
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
publicAction = $action({
|
|
275
|
+
path: "/public/status",
|
|
276
|
+
method: "GET",
|
|
277
|
+
handler: () => "public",
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
alepha = Alepha.create()
|
|
282
|
+
.with(AlephaCache)
|
|
283
|
+
.with(AlephaServer)
|
|
284
|
+
.with(AlephaServerRateLimit)
|
|
285
|
+
.with(MultiRateLimitApp);
|
|
286
|
+
|
|
287
|
+
server = alepha.inject(ServerProvider);
|
|
288
|
+
await alepha.start();
|
|
289
|
+
|
|
290
|
+
// Admin route should have max: 1
|
|
291
|
+
const adminResponse1 = await fetch(`${server.hostname}/api/admin/users`);
|
|
292
|
+
expect(adminResponse1.status).toBe(200);
|
|
293
|
+
expect(adminResponse1.headers.get("x-ratelimit-limit")).toBe("1");
|
|
294
|
+
|
|
295
|
+
// Second admin request should be rate limited
|
|
296
|
+
const adminResponse2 = await fetch(`${server.hostname}/api/admin/users`);
|
|
297
|
+
expect(adminResponse2.status).toBe(429);
|
|
298
|
+
|
|
299
|
+
// Public route should have max: 10
|
|
300
|
+
const publicResponse = await fetch(`${server.hostname}/api/public/status`);
|
|
301
|
+
expect(publicResponse.status).toBe(200);
|
|
302
|
+
expect(publicResponse.headers.get("x-ratelimit-limit")).toBe("10");
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
test("should handle multiple paths in single $rateLimit primitive", async () => {
|
|
306
|
+
class MultiPathApp {
|
|
307
|
+
apiLimit = $rateLimit({
|
|
308
|
+
paths: ["/api/v1/*", "/api/v2/*"],
|
|
309
|
+
max: 5,
|
|
310
|
+
windowMs: 60000,
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
action1 = $action({
|
|
314
|
+
path: "/v1/data",
|
|
315
|
+
method: "GET",
|
|
316
|
+
handler: () => "v1",
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
action2 = $action({
|
|
320
|
+
path: "/v2/data",
|
|
321
|
+
method: "GET",
|
|
322
|
+
handler: () => "v2",
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
alepha = Alepha.create()
|
|
327
|
+
.with(AlephaCache)
|
|
328
|
+
.with(AlephaServer)
|
|
329
|
+
.with(AlephaServerRateLimit)
|
|
330
|
+
.with(MultiPathApp);
|
|
331
|
+
|
|
332
|
+
server = alepha.inject(ServerProvider);
|
|
333
|
+
await alepha.start();
|
|
334
|
+
|
|
335
|
+
// Both paths should have max: 5
|
|
336
|
+
const v1Response = await fetch(`${server.hostname}/api/v1/data`);
|
|
337
|
+
expect(v1Response.status).toBe(200);
|
|
338
|
+
expect(v1Response.headers.get("x-ratelimit-limit")).toBe("5");
|
|
339
|
+
|
|
340
|
+
const v2Response = await fetch(`${server.hostname}/api/v2/data`);
|
|
341
|
+
expect(v2Response.status).toBe(200);
|
|
342
|
+
expect(v2Response.headers.get("x-ratelimit-limit")).toBe("5");
|
|
343
|
+
});
|
|
344
|
+
});
|