alepha 0.14.2 → 0.14.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/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 +784 -784
- 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 +57 -57
- 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 +165 -165
- 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 +583 -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 +281 -276
- 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 +1137 -1123
- 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 +13 -13
- 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 +137 -112
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +371 -259
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +45 -5
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +97 -17
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +14 -18
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +29 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +14 -18
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +14 -18
- 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/mcp/index.d.ts.map +1 -1
- package/dist/orm/index.d.ts +32 -32
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +12 -12
- 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/compress/index.d.ts.map +1 -1
- package/dist/server/compress/index.js +2 -0
- package/dist/server/compress/index.js.map +1 -1
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +1 -1
- 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/security/index.d.ts +9 -9
- 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 +8 -3
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +12 -4
- 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 -4
- package/src/cli/commands/dev.ts +19 -7
- 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/openapi.ts +71 -0
- package/src/cli/commands/gen.ts +18 -0
- package/src/cli/commands/init.ts +2 -0
- package/src/cli/commands/root.ts +12 -3
- package/src/cli/commands/typecheck.ts +5 -0
- package/src/cli/index.ts +2 -1
- package/src/cli/services/AlephaCliUtils.ts +71 -32
- 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/primitives/$command.spec.ts +1588 -0
- package/src/command/providers/CliProvider.ts +74 -24
- package/src/core/Alepha.ts +45 -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/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/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/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 +378 -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 +942 -0
- package/src/server/compress/providers/ServerCompressProvider.spec.ts +31 -0
- package/src/server/compress/providers/ServerCompressProvider.ts +2 -0
- 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/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 +3 -1
- 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/swagger/__tests__/ui.spec.ts +52 -0
- package/src/server/swagger/primitives/$swagger.spec.ts +193 -0
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +18 -8
- 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/plugins/viteAlephaDev.ts +16 -4
- 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
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
import { Alepha } from "alepha";
|
|
2
|
+
import { AlephaApiVerification } from "alepha/api/verifications";
|
|
3
|
+
import { DateTimeProvider } from "alepha/datetime";
|
|
4
|
+
import { AlephaEmail, MemoryEmailProvider } from "alepha/email";
|
|
5
|
+
import { AlephaSecurity, CryptoProvider } from "alepha/security";
|
|
6
|
+
import { BadRequestError } from "alepha/server";
|
|
7
|
+
import { describe, it } from "vitest";
|
|
8
|
+
import {
|
|
9
|
+
AlephaApiUsers,
|
|
10
|
+
CredentialService,
|
|
11
|
+
SessionService,
|
|
12
|
+
UserController,
|
|
13
|
+
} from "../index.ts";
|
|
14
|
+
|
|
15
|
+
const setup = async () => {
|
|
16
|
+
const alepha = Alepha.create({
|
|
17
|
+
env: { LOG_LEVEL: "error" },
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
alepha.with(AlephaSecurity);
|
|
21
|
+
alepha.with(AlephaEmail);
|
|
22
|
+
alepha.with(AlephaApiVerification);
|
|
23
|
+
alepha.with(AlephaApiUsers);
|
|
24
|
+
|
|
25
|
+
await alepha.start();
|
|
26
|
+
|
|
27
|
+
const emailProvider = alepha.inject(MemoryEmailProvider);
|
|
28
|
+
emailProvider.records = [];
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
alepha,
|
|
32
|
+
credentialService: alepha.inject(CredentialService),
|
|
33
|
+
sessionService: alepha.inject(SessionService),
|
|
34
|
+
cryptoProvider: alepha.inject(CryptoProvider),
|
|
35
|
+
dateTimeProvider: alepha.inject(DateTimeProvider),
|
|
36
|
+
emailProvider,
|
|
37
|
+
actions: alepha.inject(UserController),
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Helper to extract code from email
|
|
42
|
+
const extractCode = (emailBody: string): string => {
|
|
43
|
+
// Code is displayed in the email body as a 6-digit number
|
|
44
|
+
const match = emailBody.match(/(\d{6})/);
|
|
45
|
+
if (!match) throw new Error("Code not found in email");
|
|
46
|
+
return match[1];
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
describe("alepha/api/users - Password Reset", () => {
|
|
50
|
+
it("should successfully request password reset and send email", async ({
|
|
51
|
+
expect,
|
|
52
|
+
}) => {
|
|
53
|
+
const { credentialService, cryptoProvider, emailProvider, actions } =
|
|
54
|
+
await setup();
|
|
55
|
+
|
|
56
|
+
// Create a test user with credentials
|
|
57
|
+
const hashedPassword = await cryptoProvider.hashPassword("OldPassword123");
|
|
58
|
+
const user = await credentialService.users().create({
|
|
59
|
+
username: "testuser",
|
|
60
|
+
email: "test@example.com",
|
|
61
|
+
roles: ["user"],
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
await credentialService.identities().create({
|
|
65
|
+
userId: user.id,
|
|
66
|
+
provider: "credentials",
|
|
67
|
+
providerUserId: "test@example.com",
|
|
68
|
+
providerData: { password: hashedPassword },
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Request password reset
|
|
72
|
+
const result = await actions.requestPasswordReset({
|
|
73
|
+
body: {
|
|
74
|
+
email: "test@example.com",
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
expect(result.success).toBe(true);
|
|
79
|
+
expect(result.message).toContain("password reset code has been sent");
|
|
80
|
+
|
|
81
|
+
// Verify email was sent via password reset notification
|
|
82
|
+
await expect.poll(() => emailProvider.records.length).toBe(1);
|
|
83
|
+
const email = emailProvider.records[0];
|
|
84
|
+
expect(email.to).toBe("test@example.com");
|
|
85
|
+
expect(email.subject).toBe("Reset your password");
|
|
86
|
+
// Check for 6-digit code in email
|
|
87
|
+
expect(email.body).toMatch(/\d{6}/);
|
|
88
|
+
expect(email.body).toContain("5 minutes"); // Default code verification expiration
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should not reveal if email does not exist", async ({ expect }) => {
|
|
92
|
+
const { emailProvider, actions } = await setup();
|
|
93
|
+
|
|
94
|
+
// Request password reset for non-existent email
|
|
95
|
+
const result = await actions.requestPasswordReset({
|
|
96
|
+
body: {
|
|
97
|
+
email: "nonexistent@example.com",
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Should return success to prevent email enumeration
|
|
102
|
+
expect(result.success).toBe(true);
|
|
103
|
+
expect(result.message).toContain("password reset code has been sent");
|
|
104
|
+
|
|
105
|
+
// But no email should be sent
|
|
106
|
+
expect(emailProvider.records).toHaveLength(0);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should not send email for OAuth-only users", async ({ expect }) => {
|
|
110
|
+
const { credentialService, emailProvider, actions } = await setup();
|
|
111
|
+
|
|
112
|
+
// Create a user with only OAuth identity (no credentials)
|
|
113
|
+
const user = await credentialService.users().create({
|
|
114
|
+
username: "oauthuser",
|
|
115
|
+
email: "oauth@example.com",
|
|
116
|
+
roles: ["user"],
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await credentialService.identities().create({
|
|
120
|
+
userId: user.id,
|
|
121
|
+
provider: "google",
|
|
122
|
+
providerUserId: "google-123",
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Request password reset
|
|
126
|
+
const result = await actions.requestPasswordReset({
|
|
127
|
+
body: {
|
|
128
|
+
email: "oauth@example.com",
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Should return success but not send email
|
|
133
|
+
expect(result.success).toBe(true);
|
|
134
|
+
expect(emailProvider.records).toHaveLength(0);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("should validate a valid reset token", async ({ expect }) => {
|
|
138
|
+
const { credentialService, cryptoProvider, emailProvider, actions } =
|
|
139
|
+
await setup();
|
|
140
|
+
|
|
141
|
+
// Create a test user with credentials
|
|
142
|
+
const hashedPassword = await cryptoProvider.hashPassword("OldPassword123");
|
|
143
|
+
const user = await credentialService.users().create({
|
|
144
|
+
username: "testuser",
|
|
145
|
+
email: "test@example.com",
|
|
146
|
+
roles: ["user"],
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
await credentialService.identities().create({
|
|
150
|
+
userId: user.id,
|
|
151
|
+
provider: "credentials",
|
|
152
|
+
providerUserId: "test@example.com",
|
|
153
|
+
providerData: { password: hashedPassword },
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Request password reset
|
|
157
|
+
await credentialService.requestPasswordReset("test@example.com");
|
|
158
|
+
|
|
159
|
+
// Extract code from email
|
|
160
|
+
await expect.poll(() => emailProvider.records.length).toBe(1);
|
|
161
|
+
const token = extractCode(emailProvider.records[0].body);
|
|
162
|
+
|
|
163
|
+
// Validate token
|
|
164
|
+
const result = await actions.validateResetToken({
|
|
165
|
+
query: { email: "test@example.com", token },
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
expect(result.valid).toBe(true);
|
|
169
|
+
expect(result.email).toBe("test@example.com");
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("should reject invalid reset token", async ({ expect }) => {
|
|
173
|
+
const { actions } = await setup();
|
|
174
|
+
|
|
175
|
+
// Validate invalid token
|
|
176
|
+
const result = await actions.validateResetToken({
|
|
177
|
+
query: {
|
|
178
|
+
email: "test@example.com",
|
|
179
|
+
token: "550e8400-e29b-41d4-a716-446655440000",
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
expect(result.valid).toBe(false);
|
|
184
|
+
expect(result.email).toBeUndefined();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("should reject expired reset token", async ({ expect }) => {
|
|
188
|
+
const {
|
|
189
|
+
credentialService,
|
|
190
|
+
cryptoProvider,
|
|
191
|
+
dateTimeProvider,
|
|
192
|
+
emailProvider,
|
|
193
|
+
actions,
|
|
194
|
+
} = await setup();
|
|
195
|
+
|
|
196
|
+
// Create a test user with credentials
|
|
197
|
+
const hashedPassword = await cryptoProvider.hashPassword("OldPassword123");
|
|
198
|
+
const user = await credentialService.users().create({
|
|
199
|
+
username: "testuser",
|
|
200
|
+
email: "test@example.com",
|
|
201
|
+
roles: ["user"],
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
await credentialService.identities().create({
|
|
205
|
+
userId: user.id,
|
|
206
|
+
provider: "credentials",
|
|
207
|
+
providerUserId: "test@example.com",
|
|
208
|
+
providerData: { password: hashedPassword },
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Request password reset
|
|
212
|
+
await credentialService.requestPasswordReset("test@example.com");
|
|
213
|
+
|
|
214
|
+
// Extract code
|
|
215
|
+
await expect.poll(() => emailProvider.records.length).toBe(1);
|
|
216
|
+
const token = extractCode(emailProvider.records[0].body);
|
|
217
|
+
|
|
218
|
+
// Travel forward in time to expire the token (default expiration is 5 minutes for code verification)
|
|
219
|
+
dateTimeProvider.travel(6, "minutes");
|
|
220
|
+
|
|
221
|
+
// Validate expired token
|
|
222
|
+
const result = await actions.validateResetToken({
|
|
223
|
+
query: { email: "test@example.com", token },
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
expect(result.valid).toBe(false);
|
|
227
|
+
expect(result.email).toBeUndefined();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("should successfully reset password with valid token", async ({
|
|
231
|
+
expect,
|
|
232
|
+
}) => {
|
|
233
|
+
const {
|
|
234
|
+
credentialService,
|
|
235
|
+
sessionService,
|
|
236
|
+
cryptoProvider,
|
|
237
|
+
emailProvider,
|
|
238
|
+
actions,
|
|
239
|
+
} = await setup();
|
|
240
|
+
|
|
241
|
+
// Create a test user with credentials
|
|
242
|
+
const hashedPassword = await cryptoProvider.hashPassword("OldPassword123");
|
|
243
|
+
const user = await credentialService.users().create({
|
|
244
|
+
username: "testuser",
|
|
245
|
+
email: "test@example.com",
|
|
246
|
+
roles: ["user"],
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
await credentialService.identities().create({
|
|
250
|
+
userId: user.id,
|
|
251
|
+
provider: "credentials",
|
|
252
|
+
providerUserId: "test@example.com",
|
|
253
|
+
providerData: { password: hashedPassword },
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Request password reset
|
|
257
|
+
await credentialService.requestPasswordReset("test@example.com");
|
|
258
|
+
|
|
259
|
+
// Extract code
|
|
260
|
+
await expect.poll(() => emailProvider.records.length).toBe(1);
|
|
261
|
+
const token = extractCode(emailProvider.records[0].body);
|
|
262
|
+
|
|
263
|
+
// Reset password
|
|
264
|
+
const result = await actions.resetPassword({
|
|
265
|
+
body: {
|
|
266
|
+
email: "test@example.com",
|
|
267
|
+
token,
|
|
268
|
+
newPassword: "NewPassword456",
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
expect(result.success).toBe(true);
|
|
273
|
+
expect(result.message).toContain("Password has been reset successfully");
|
|
274
|
+
|
|
275
|
+
// Verify old password no longer works
|
|
276
|
+
await expect(
|
|
277
|
+
sessionService.login("credentials", "test@example.com", "OldPassword123"),
|
|
278
|
+
).rejects.toThrow();
|
|
279
|
+
|
|
280
|
+
// Verify new password works
|
|
281
|
+
const loggedInUser = await sessionService.login(
|
|
282
|
+
"credentials",
|
|
283
|
+
"test@example.com",
|
|
284
|
+
"NewPassword456",
|
|
285
|
+
);
|
|
286
|
+
expect(loggedInUser?.email).toBe("test@example.com");
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it("should reject password reset with invalid token", async ({ expect }) => {
|
|
290
|
+
const { actions } = await setup();
|
|
291
|
+
|
|
292
|
+
// Attempt to reset password with invalid token
|
|
293
|
+
await expect(
|
|
294
|
+
actions.resetPassword({
|
|
295
|
+
body: {
|
|
296
|
+
email: "test@example.com",
|
|
297
|
+
token: "550e8400-e29b-41d4-a716-446655440000",
|
|
298
|
+
newPassword: "NewPassword456",
|
|
299
|
+
},
|
|
300
|
+
}),
|
|
301
|
+
).rejects.toThrowError(BadRequestError);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it("should reject password reset with expired token", async ({ expect }) => {
|
|
305
|
+
const {
|
|
306
|
+
credentialService,
|
|
307
|
+
cryptoProvider,
|
|
308
|
+
dateTimeProvider,
|
|
309
|
+
emailProvider,
|
|
310
|
+
actions,
|
|
311
|
+
} = await setup();
|
|
312
|
+
|
|
313
|
+
// Create a test user with credentials
|
|
314
|
+
const hashedPassword = await cryptoProvider.hashPassword("OldPassword123");
|
|
315
|
+
const user = await credentialService.users().create({
|
|
316
|
+
username: "testuser",
|
|
317
|
+
email: "test@example.com",
|
|
318
|
+
roles: ["user"],
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
await credentialService.identities().create({
|
|
322
|
+
userId: user.id,
|
|
323
|
+
provider: "credentials",
|
|
324
|
+
providerUserId: "test@example.com",
|
|
325
|
+
providerData: { password: hashedPassword },
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Request password reset
|
|
329
|
+
await credentialService.requestPasswordReset("test@example.com");
|
|
330
|
+
|
|
331
|
+
// Extract code
|
|
332
|
+
await expect.poll(() => emailProvider.records.length).toBe(1);
|
|
333
|
+
const token = extractCode(emailProvider.records[0].body);
|
|
334
|
+
|
|
335
|
+
// Travel forward in time to expire the token (5 minutes for code)
|
|
336
|
+
dateTimeProvider.travel(6, "minutes");
|
|
337
|
+
|
|
338
|
+
// Attempt to reset password with expired token
|
|
339
|
+
await expect(
|
|
340
|
+
actions.resetPassword({
|
|
341
|
+
body: {
|
|
342
|
+
email: "test@example.com",
|
|
343
|
+
token,
|
|
344
|
+
newPassword: "NewPassword456",
|
|
345
|
+
},
|
|
346
|
+
}),
|
|
347
|
+
).rejects.toThrowError(BadRequestError);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it("should not allow token reuse after successful password reset", async ({
|
|
351
|
+
expect,
|
|
352
|
+
}) => {
|
|
353
|
+
const { credentialService, cryptoProvider, emailProvider, actions } =
|
|
354
|
+
await setup();
|
|
355
|
+
|
|
356
|
+
// Create a test user with credentials
|
|
357
|
+
const hashedPassword = await cryptoProvider.hashPassword("OldPassword123");
|
|
358
|
+
const user = await credentialService.users().create({
|
|
359
|
+
username: "testuser",
|
|
360
|
+
email: "test@example.com",
|
|
361
|
+
roles: ["user"],
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
await credentialService.identities().create({
|
|
365
|
+
userId: user.id,
|
|
366
|
+
provider: "credentials",
|
|
367
|
+
providerUserId: "test@example.com",
|
|
368
|
+
providerData: { password: hashedPassword },
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// Request password reset
|
|
372
|
+
await credentialService.requestPasswordReset("test@example.com");
|
|
373
|
+
|
|
374
|
+
// Extract code
|
|
375
|
+
await expect.poll(() => emailProvider.records.length).toBe(1);
|
|
376
|
+
const token = extractCode(emailProvider.records[0].body);
|
|
377
|
+
|
|
378
|
+
// Reset password
|
|
379
|
+
await actions.resetPassword({
|
|
380
|
+
body: {
|
|
381
|
+
email: "test@example.com",
|
|
382
|
+
token,
|
|
383
|
+
newPassword: "NewPassword456",
|
|
384
|
+
},
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// Attempt to use the same token again should fail
|
|
388
|
+
await expect(
|
|
389
|
+
actions.resetPassword({
|
|
390
|
+
body: {
|
|
391
|
+
email: "test@example.com",
|
|
392
|
+
token,
|
|
393
|
+
newPassword: "AnotherPassword789",
|
|
394
|
+
},
|
|
395
|
+
}),
|
|
396
|
+
).rejects.toThrowError(BadRequestError);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it("should invalidate all sessions after password reset", async ({
|
|
400
|
+
expect,
|
|
401
|
+
}) => {
|
|
402
|
+
const {
|
|
403
|
+
credentialService,
|
|
404
|
+
sessionService,
|
|
405
|
+
cryptoProvider,
|
|
406
|
+
emailProvider,
|
|
407
|
+
actions,
|
|
408
|
+
} = await setup();
|
|
409
|
+
|
|
410
|
+
// Create a test user with credentials
|
|
411
|
+
const hashedPassword = await cryptoProvider.hashPassword("OldPassword123");
|
|
412
|
+
const user = await credentialService.users().create({
|
|
413
|
+
username: "testuser",
|
|
414
|
+
email: "test@example.com",
|
|
415
|
+
roles: ["user"],
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
await credentialService.identities().create({
|
|
419
|
+
userId: user.id,
|
|
420
|
+
provider: "credentials",
|
|
421
|
+
providerUserId: "test@example.com",
|
|
422
|
+
providerData: { password: hashedPassword },
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// Create some sessions
|
|
426
|
+
await sessionService.createSession(user, 3600);
|
|
427
|
+
await sessionService.createSession(user, 3600);
|
|
428
|
+
|
|
429
|
+
// Verify sessions exist
|
|
430
|
+
const existingSessions = await sessionService.sessions().findMany({
|
|
431
|
+
where: { userId: { eq: user.id } },
|
|
432
|
+
});
|
|
433
|
+
expect(existingSessions).toHaveLength(2);
|
|
434
|
+
|
|
435
|
+
// Request password reset and reset password
|
|
436
|
+
await credentialService.requestPasswordReset("test@example.com");
|
|
437
|
+
|
|
438
|
+
await expect.poll(() => emailProvider.records.length).toBe(1);
|
|
439
|
+
const token = extractCode(emailProvider.records[0].body);
|
|
440
|
+
|
|
441
|
+
await actions.resetPassword({
|
|
442
|
+
body: {
|
|
443
|
+
email: "test@example.com",
|
|
444
|
+
token,
|
|
445
|
+
newPassword: "NewPassword456",
|
|
446
|
+
},
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
// Verify all sessions are deleted
|
|
450
|
+
const remainingSessions = await sessionService.sessions().findMany({
|
|
451
|
+
where: { userId: { eq: user.id } },
|
|
452
|
+
});
|
|
453
|
+
expect(remainingSessions).toHaveLength(0);
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
it("should enforce minimum password length", async ({ expect }) => {
|
|
457
|
+
const { credentialService, cryptoProvider, emailProvider, actions } =
|
|
458
|
+
await setup();
|
|
459
|
+
|
|
460
|
+
// Create a test user with credentials
|
|
461
|
+
const hashedPassword = await cryptoProvider.hashPassword("OldPassword123");
|
|
462
|
+
const user = await credentialService.users().create({
|
|
463
|
+
username: "testuser",
|
|
464
|
+
email: "test@example.com",
|
|
465
|
+
roles: ["user"],
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
await credentialService.identities().create({
|
|
469
|
+
userId: user.id,
|
|
470
|
+
provider: "credentials",
|
|
471
|
+
providerUserId: "test@example.com",
|
|
472
|
+
providerData: { password: hashedPassword },
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
// Request password reset
|
|
476
|
+
await credentialService.requestPasswordReset("test@example.com");
|
|
477
|
+
|
|
478
|
+
await expect.poll(() => emailProvider.records.length).toBe(1);
|
|
479
|
+
const token = extractCode(emailProvider.records[0].body);
|
|
480
|
+
|
|
481
|
+
// Attempt to reset with short password (less than 8 characters)
|
|
482
|
+
await expect(
|
|
483
|
+
actions.resetPassword({
|
|
484
|
+
body: {
|
|
485
|
+
email: "test@example.com",
|
|
486
|
+
token,
|
|
487
|
+
newPassword: "Short1", // Only 6 characters
|
|
488
|
+
},
|
|
489
|
+
}),
|
|
490
|
+
).rejects.toThrow();
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
it("should respect rate limiting on password reset requests", async ({
|
|
494
|
+
expect,
|
|
495
|
+
}) => {
|
|
496
|
+
const {
|
|
497
|
+
credentialService,
|
|
498
|
+
cryptoProvider,
|
|
499
|
+
dateTimeProvider,
|
|
500
|
+
emailProvider,
|
|
501
|
+
actions,
|
|
502
|
+
} = await setup();
|
|
503
|
+
|
|
504
|
+
// Create a test user with credentials
|
|
505
|
+
const hashedPassword = await cryptoProvider.hashPassword("OldPassword123");
|
|
506
|
+
const user = await credentialService.users().create({
|
|
507
|
+
username: "testuser",
|
|
508
|
+
email: "test@example.com",
|
|
509
|
+
roles: ["user"],
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
await credentialService.identities().create({
|
|
513
|
+
userId: user.id,
|
|
514
|
+
provider: "credentials",
|
|
515
|
+
providerUserId: "test@example.com",
|
|
516
|
+
providerData: { password: hashedPassword },
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
// Request password reset multiple times within cooldown period
|
|
520
|
+
await actions.requestPasswordReset({
|
|
521
|
+
body: {
|
|
522
|
+
email: "test@example.com",
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
await expect.poll(() => emailProvider.records.length).toBe(1);
|
|
527
|
+
|
|
528
|
+
// Second request should be silently ignored (cooldown)
|
|
529
|
+
await actions.requestPasswordReset({
|
|
530
|
+
body: {
|
|
531
|
+
email: "test@example.com",
|
|
532
|
+
},
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// Still only 1 email
|
|
536
|
+
expect(emailProvider.records.length).toBe(1);
|
|
537
|
+
|
|
538
|
+
// Wait for cooldown to pass (90 seconds default)
|
|
539
|
+
dateTimeProvider.travel(91, "seconds");
|
|
540
|
+
|
|
541
|
+
// Now should work
|
|
542
|
+
await actions.requestPasswordReset({
|
|
543
|
+
body: {
|
|
544
|
+
email: "test@example.com",
|
|
545
|
+
},
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
await expect.poll(() => emailProvider.records.length).toBe(2);
|
|
549
|
+
});
|
|
550
|
+
});
|