alepha 0.15.1 → 0.15.2
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.d.ts +342 -365
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +10 -33
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.d.ts +180 -173
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +10 -3
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +162 -155
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +10 -3
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.d.ts +413 -0
- package/dist/api/keys/index.d.ts.map +1 -0
- package/dist/api/keys/index.js +476 -0
- package/dist/api/keys/index.js.map +1 -0
- package/dist/api/notifications/index.d.ts +10 -4
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +10 -4
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.d.ts +294 -301
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +30 -37
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/users/index.d.ts +1079 -769
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +2534 -218
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +10 -4
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +12 -4
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/batch/index.d.ts +20 -40
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +31 -44
- package/dist/batch/index.js.map +1 -1
- package/dist/bucket/index.d.ts +432 -8
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/bucket/index.js +1856 -12
- package/dist/bucket/index.js.map +1 -1
- package/dist/cache/core/index.d.ts +179 -7
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/core/index.js +213 -7
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cache/redis/index.d.ts +1 -0
- package/dist/cache/redis/index.d.ts.map +1 -1
- package/dist/cache/redis/index.js +4 -0
- package/dist/cache/redis/index.js.map +1 -1
- package/dist/cli/index.d.ts +488 -5612
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2326 -311
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +194 -46
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +1995 -60
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +42 -19
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +34 -13
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +62 -19
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +42 -19
- package/dist/core/index.native.js.map +1 -1
- package/dist/datetime/index.d.ts +15 -0
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/datetime/index.js +15 -0
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/index.d.ts +315 -20
- package/dist/email/index.d.ts.map +1 -1
- package/dist/email/index.js +1852 -7
- package/dist/email/index.js.map +1 -1
- package/dist/fake/index.d.ts +90 -8
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js +91 -20
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +11 -4
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/core/index.js +11 -4
- package/dist/lock/core/index.js.map +1 -1
- package/dist/logger/index.d.ts +17 -66
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +14 -63
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +15 -35
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +12 -35
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/index.browser.js +3 -3
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.bun.js +7 -4
- package/dist/orm/index.bun.js.map +1 -1
- package/dist/orm/index.d.ts +514 -540
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +24 -49
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +18 -10
- package/dist/queue/core/index.d.ts.map +1 -1
- package/dist/queue/core/index.js +14 -6
- package/dist/queue/core/index.js.map +1 -1
- package/dist/react/auth/index.browser.js +108 -0
- package/dist/react/auth/index.browser.js.map +1 -0
- package/dist/react/auth/index.d.ts +100 -0
- package/dist/react/auth/index.d.ts.map +1 -0
- package/dist/react/auth/index.js +145 -0
- package/dist/react/auth/index.js.map +1 -0
- package/dist/react/core/index.d.ts +469 -0
- package/dist/react/core/index.d.ts.map +1 -0
- package/dist/react/core/index.js +464 -0
- package/dist/react/core/index.js.map +1 -0
- package/dist/react/form/index.d.ts +232 -0
- package/dist/react/form/index.d.ts.map +1 -0
- package/dist/react/form/index.js +432 -0
- package/dist/react/form/index.js.map +1 -0
- package/dist/react/head/index.browser.js +423 -0
- package/dist/react/head/index.browser.js.map +1 -0
- package/dist/react/head/index.d.ts +288 -0
- package/dist/react/head/index.d.ts.map +1 -0
- package/dist/react/head/index.js +465 -0
- package/dist/react/head/index.js.map +1 -0
- package/dist/react/i18n/index.d.ts +175 -0
- package/dist/react/i18n/index.d.ts.map +1 -0
- package/dist/react/i18n/index.js +224 -0
- package/dist/react/i18n/index.js.map +1 -0
- package/dist/react/router/index.browser.js +1980 -0
- package/dist/react/router/index.browser.js.map +1 -0
- package/dist/react/router/index.d.ts +2068 -0
- package/dist/react/router/index.d.ts.map +1 -0
- package/dist/react/router/index.js +4932 -0
- package/dist/react/router/index.js.map +1 -0
- package/dist/react/websocket/index.d.ts +117 -0
- package/dist/react/websocket/index.d.ts.map +1 -0
- package/dist/react/websocket/index.js +107 -0
- package/dist/react/websocket/index.js.map +1 -0
- package/dist/redis/index.bun.js +4 -0
- package/dist/redis/index.bun.js.map +1 -1
- package/dist/redis/index.d.ts +22 -25
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/redis/index.js +16 -25
- package/dist/redis/index.js.map +1 -1
- package/dist/retry/index.d.ts +11 -2
- package/dist/retry/index.d.ts.map +1 -1
- package/dist/retry/index.js +11 -2
- package/dist/retry/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +11 -2
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +11 -2
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.d.ts +110 -19
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +157 -26
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +179 -174
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +12 -7
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.d.ts +7 -22
- package/dist/server/cache/index.d.ts.map +1 -1
- package/dist/server/cache/index.js +7 -22
- package/dist/server/cache/index.js.map +1 -1
- package/dist/server/compress/index.d.ts +10 -2
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/compress/index.js +10 -2
- package/dist/server/compress/index.js.map +1 -1
- package/dist/server/cookies/index.d.ts +40 -16
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/cookies/index.js +7 -5
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.d.ts +115 -14
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +231 -14
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +13 -23
- package/dist/server/cors/index.d.ts.map +1 -1
- package/dist/server/cors/index.js +7 -21
- package/dist/server/cors/index.js.map +1 -1
- package/dist/server/health/index.d.ts +25 -19
- package/dist/server/health/index.d.ts.map +1 -1
- package/dist/server/health/index.js +8 -2
- package/dist/server/health/index.js.map +1 -1
- package/dist/server/helmet/index.d.ts +11 -3
- package/dist/server/helmet/index.d.ts.map +1 -1
- package/dist/server/helmet/index.js +11 -3
- package/dist/server/helmet/index.js.map +1 -1
- package/dist/server/links/index.d.ts +50 -45
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +11 -6
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +10 -3
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/metrics/index.js +10 -3
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/multipart/index.d.ts +9 -3
- package/dist/server/multipart/index.d.ts.map +1 -1
- package/dist/server/multipart/index.js +9 -3
- package/dist/server/multipart/index.js.map +1 -1
- package/dist/server/proxy/index.d.ts +8 -2
- package/dist/server/proxy/index.d.ts.map +1 -1
- package/dist/server/proxy/index.js +8 -2
- package/dist/server/proxy/index.js.map +1 -1
- package/dist/server/rate-limit/index.d.ts +30 -35
- package/dist/server/rate-limit/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.js +18 -55
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/static/index.d.ts +137 -4
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/static/index.js +1848 -5
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts +301 -6
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +1849 -6
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +301 -7
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js +1851 -7
- package/dist/sms/index.js.map +1 -1
- package/dist/system/index.browser.js +496 -0
- package/dist/system/index.browser.js.map +1 -0
- package/dist/{file → system}/index.d.ts +335 -16
- package/dist/system/index.d.ts.map +1 -0
- package/dist/{file → system}/index.js +412 -20
- package/dist/system/index.js.map +1 -0
- package/dist/thread/index.d.ts +11 -2
- package/dist/thread/index.d.ts.map +1 -1
- package/dist/thread/index.js +11 -2
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/core/index.d.ts +12 -5
- package/dist/topic/core/index.d.ts.map +1 -1
- package/dist/topic/core/index.js +12 -5
- package/dist/topic/core/index.js.map +1 -1
- package/dist/vite/index.d.ts +4 -6271
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +8 -3
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.d.ts +12 -8
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +12 -8
- package/dist/websocket/index.js.map +1 -1
- package/package.json +80 -11
- package/src/api/audits/index.ts +10 -33
- package/src/api/files/__tests__/$bucket.spec.ts +1 -1
- package/src/api/files/controllers/AdminFileStatsController.spec.ts +1 -1
- package/src/api/files/controllers/FileController.spec.ts +1 -1
- package/src/api/files/index.ts +10 -3
- package/src/api/files/jobs/FileJobs.spec.ts +1 -1
- package/src/api/files/services/FileService.spec.ts +1 -1
- package/src/api/jobs/index.ts +10 -3
- package/src/api/keys/controllers/AdminApiKeyController.ts +75 -0
- package/src/api/keys/controllers/ApiKeyController.ts +103 -0
- package/src/api/keys/entities/apiKeyEntity.ts +41 -0
- package/src/api/keys/index.ts +49 -0
- package/src/api/keys/schemas/adminApiKeyQuerySchema.ts +7 -0
- package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +17 -0
- package/src/api/keys/schemas/createApiKeyBodySchema.ts +7 -0
- package/src/api/keys/schemas/createApiKeyResponseSchema.ts +11 -0
- package/src/api/keys/schemas/listApiKeyResponseSchema.ts +15 -0
- package/src/api/keys/schemas/revokeApiKeyParamsSchema.ts +5 -0
- package/src/api/keys/schemas/revokeApiKeyResponseSchema.ts +5 -0
- package/src/api/keys/services/ApiKeyService.spec.ts +553 -0
- package/src/api/keys/services/ApiKeyService.ts +306 -0
- package/src/api/logs/TODO.md +52 -0
- package/src/api/notifications/index.ts +10 -4
- package/src/api/parameters/index.ts +9 -30
- package/src/api/parameters/primitives/$config.ts +12 -4
- package/src/api/parameters/services/ConfigStore.ts +9 -3
- package/src/api/users/__tests__/ApiKeys-integration.spec.ts +1035 -0
- package/src/api/users/__tests__/ApiKeys.spec.ts +401 -0
- package/src/api/users/index.ts +14 -3
- package/src/api/users/primitives/$realm.ts +33 -5
- package/src/api/users/providers/RealmProvider.ts +1 -12
- package/src/api/users/services/SessionService.ts +1 -1
- package/src/api/verifications/controllers/VerificationController.ts +2 -0
- package/src/api/verifications/index.ts +10 -4
- package/src/batch/index.ts +9 -36
- package/src/batch/primitives/$batch.ts +0 -8
- package/src/batch/providers/BatchProvider.ts +29 -2
- package/src/bucket/__tests__/shared.ts +1 -1
- package/src/bucket/index.ts +13 -6
- package/src/bucket/primitives/$bucket.ts +1 -1
- package/src/bucket/providers/LocalFileStorageProvider.ts +1 -1
- package/src/bucket/providers/MemoryFileStorageProvider.ts +1 -1
- package/src/cache/core/__tests__/shared.ts +30 -0
- package/src/cache/core/index.ts +11 -6
- package/src/cache/core/primitives/$cache.spec.ts +5 -0
- package/src/cache/core/providers/CacheProvider.ts +17 -0
- package/src/cache/core/providers/MemoryCacheProvider.ts +300 -1
- package/src/cache/redis/__tests__/cache-redis.spec.ts +5 -0
- package/src/cache/redis/providers/RedisCacheProvider.ts +9 -0
- package/src/cli/apps/AlephaCli.ts +1 -14
- package/src/cli/apps/AlephaPackageBuilderCli.ts +1 -1
- package/src/cli/commands/build.ts +1 -5
- package/src/cli/commands/db.ts +17 -11
- package/src/cli/commands/deploy.ts +1 -1
- package/src/cli/commands/dev.ts +1 -20
- package/src/cli/commands/gen/env.ts +5 -2
- package/src/cli/commands/gen/openapi.ts +5 -2
- package/src/cli/commands/init.spec.ts +544 -0
- package/src/cli/commands/init.ts +89 -55
- package/src/cli/commands/lint.ts +7 -1
- package/src/cli/commands/typecheck.ts +11 -0
- package/src/cli/providers/AppEntryProvider.ts +1 -1
- package/src/cli/providers/ViteBuildProvider.ts +8 -50
- package/src/cli/providers/ViteDevServerProvider.ts +36 -8
- package/src/cli/services/AlephaCliUtils.ts +37 -122
- package/src/cli/services/PackageManagerUtils.ts +127 -11
- package/src/cli/services/ProjectScaffolder.ts +122 -77
- package/src/cli/services/ViteUtils.ts +82 -0
- package/src/cli/{assets/claudeMd.ts → templates/agentMd.ts} +32 -24
- package/src/cli/templates/gitignore.ts +39 -0
- package/src/cli/{assets → templates}/mainCss.ts +11 -2
- package/src/cli/templates/mainServerTs.ts +33 -0
- package/src/cli/templates/webAppRouterTs.ts +50 -0
- package/src/cli/{assets → templates}/webHelloComponentTsx.ts +2 -2
- package/src/command/helpers/Runner.spec.ts +4 -0
- package/src/command/helpers/Runner.ts +3 -21
- package/src/command/index.ts +12 -4
- package/src/command/providers/CliProvider.spec.ts +1067 -0
- package/src/command/providers/CliProvider.ts +203 -40
- package/src/core/Alepha.ts +2 -2
- package/src/core/__tests__/Alepha-start.spec.ts +4 -4
- package/src/core/helpers/jsonSchemaToTypeBox.spec.ts +771 -0
- package/src/core/helpers/jsonSchemaToTypeBox.ts +62 -10
- package/src/core/index.shared.ts +1 -0
- package/src/core/index.ts +20 -0
- package/src/core/providers/EventManager.spec.ts +0 -71
- package/src/core/providers/EventManager.ts +3 -15
- package/src/core/providers/Json.ts +2 -14
- package/src/datetime/index.ts +15 -0
- package/src/email/index.ts +10 -5
- package/src/email/providers/LocalEmailProvider.spec.ts +1 -1
- package/src/email/providers/LocalEmailProvider.ts +1 -1
- package/src/fake/__tests__/keyName.example.ts +1 -1
- package/src/fake/__tests__/keyName.spec.ts +5 -5
- package/src/fake/index.ts +9 -6
- package/src/fake/providers/FakeProvider.spec.ts +258 -40
- package/src/fake/providers/FakeProvider.ts +133 -19
- package/src/lock/core/index.ts +11 -4
- package/src/logger/index.ts +17 -66
- package/src/mcp/index.ts +10 -27
- package/src/mcp/transports/SseMcpTransport.ts +0 -11
- package/src/orm/__tests__/PostgresProvider.spec.ts +2 -2
- package/src/orm/index.browser.ts +2 -2
- package/src/orm/index.bun.ts +4 -2
- package/src/orm/index.ts +21 -47
- package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -0
- package/src/orm/services/Repository.ts +7 -3
- package/src/queue/core/index.ts +14 -6
- package/src/react/auth/__tests__/$auth.spec.ts +202 -0
- package/src/react/auth/hooks/useAuth.ts +32 -0
- package/src/react/auth/index.browser.ts +13 -0
- package/src/react/auth/index.shared.ts +2 -0
- package/src/react/auth/index.ts +48 -0
- package/src/react/auth/providers/ReactAuthProvider.ts +16 -0
- package/src/react/auth/services/ReactAuth.ts +135 -0
- package/src/react/core/__tests__/Router.spec.tsx +169 -0
- package/src/react/core/components/ClientOnly.tsx +49 -0
- package/src/react/core/components/ErrorBoundary.tsx +73 -0
- package/src/react/core/contexts/AlephaContext.ts +7 -0
- package/src/react/core/contexts/AlephaProvider.tsx +42 -0
- package/src/react/core/hooks/useAction.browser.spec.tsx +569 -0
- package/src/react/core/hooks/useAction.ts +480 -0
- package/src/react/core/hooks/useAlepha.ts +26 -0
- package/src/react/core/hooks/useClient.ts +17 -0
- package/src/react/core/hooks/useEvents.ts +51 -0
- package/src/react/core/hooks/useInject.ts +12 -0
- package/src/react/core/hooks/useStore.ts +52 -0
- package/src/react/core/index.ts +90 -0
- package/src/react/form/components/FormState.tsx +17 -0
- package/src/react/form/errors/FormValidationError.ts +18 -0
- package/src/react/form/hooks/useForm.browser.spec.tsx +366 -0
- package/src/react/form/hooks/useForm.ts +47 -0
- package/src/react/form/hooks/useFormState.ts +130 -0
- package/src/react/form/index.ts +44 -0
- package/src/react/form/services/FormModel.ts +614 -0
- package/src/react/head/helpers/SeoExpander.spec.ts +203 -0
- package/src/react/head/helpers/SeoExpander.ts +142 -0
- package/src/react/head/hooks/useHead.spec.tsx +288 -0
- package/src/react/head/hooks/useHead.ts +62 -0
- package/src/react/head/index.browser.ts +26 -0
- package/src/react/head/index.ts +44 -0
- package/src/react/head/interfaces/Head.ts +105 -0
- package/src/react/head/primitives/$head.ts +25 -0
- package/src/react/head/providers/BrowserHeadProvider.browser.spec.ts +196 -0
- package/src/react/head/providers/BrowserHeadProvider.ts +212 -0
- package/src/react/head/providers/HeadProvider.ts +168 -0
- package/src/react/head/providers/ServerHeadProvider.ts +31 -0
- package/src/react/i18n/__tests__/integration.spec.tsx +239 -0
- package/src/react/i18n/components/Localize.spec.tsx +357 -0
- package/src/react/i18n/components/Localize.tsx +35 -0
- package/src/react/i18n/hooks/useI18n.browser.spec.tsx +438 -0
- package/src/react/i18n/hooks/useI18n.ts +18 -0
- package/src/react/i18n/index.ts +41 -0
- package/src/react/i18n/primitives/$dictionary.ts +69 -0
- package/src/react/i18n/providers/I18nProvider.spec.ts +389 -0
- package/src/react/i18n/providers/I18nProvider.ts +278 -0
- package/src/react/router/__tests__/page-head-browser.browser.spec.ts +95 -0
- package/src/react/router/__tests__/page-head.spec.ts +48 -0
- package/src/react/router/__tests__/seo-head.spec.ts +125 -0
- package/src/react/router/atoms/ssrManifestAtom.ts +58 -0
- package/src/react/router/components/ErrorViewer.tsx +872 -0
- package/src/react/router/components/Link.tsx +23 -0
- package/src/react/router/components/NestedView.tsx +223 -0
- package/src/react/router/components/NotFound.tsx +30 -0
- package/src/react/router/constants/PAGE_PRELOAD_KEY.ts +6 -0
- package/src/react/router/contexts/RouterLayerContext.ts +12 -0
- package/src/react/router/errors/Redirection.ts +28 -0
- package/src/react/router/hooks/useActive.ts +52 -0
- package/src/react/router/hooks/useQueryParams.ts +63 -0
- package/src/react/router/hooks/useRouter.ts +20 -0
- package/src/react/router/hooks/useRouterState.ts +11 -0
- package/src/react/router/index.browser.ts +45 -0
- package/src/react/router/index.shared.ts +19 -0
- package/src/react/router/index.ts +142 -0
- package/src/react/router/primitives/$page.browser.spec.tsx +851 -0
- package/src/react/router/primitives/$page.spec.tsx +708 -0
- package/src/react/router/primitives/$page.ts +497 -0
- package/src/react/router/providers/ReactBrowserProvider.ts +309 -0
- package/src/react/router/providers/ReactBrowserRendererProvider.ts +25 -0
- package/src/react/router/providers/ReactBrowserRouterProvider.ts +168 -0
- package/src/react/router/providers/ReactPageProvider.ts +726 -0
- package/src/react/router/providers/ReactServerProvider.spec.tsx +316 -0
- package/src/react/router/providers/ReactServerProvider.ts +558 -0
- package/src/react/router/providers/ReactServerTemplateProvider.ts +979 -0
- package/src/react/router/providers/SSRManifestProvider.ts +334 -0
- package/src/react/router/services/ReactPageServerService.ts +48 -0
- package/src/react/router/services/ReactPageService.ts +27 -0
- package/src/react/router/services/ReactRouter.ts +262 -0
- package/src/react/websocket/hooks/useRoom.tsx +242 -0
- package/src/react/websocket/index.ts +7 -0
- package/src/redis/__tests__/redis.spec.ts +13 -0
- package/src/redis/index.ts +9 -25
- package/src/redis/providers/BunRedisProvider.ts +9 -0
- package/src/redis/providers/NodeRedisProvider.ts +8 -0
- package/src/redis/providers/RedisProvider.ts +16 -0
- package/src/retry/index.ts +11 -2
- package/src/router/index.ts +15 -0
- package/src/scheduler/index.ts +11 -2
- package/src/security/__tests__/BasicAuth.spec.ts +2 -0
- package/src/security/__tests__/ServerSecurityProvider.spec.ts +13 -5
- package/src/security/index.ts +15 -10
- package/src/security/interfaces/IssuerResolver.ts +27 -0
- package/src/security/primitives/$issuer.ts +55 -0
- package/src/security/providers/SecurityProvider.ts +179 -0
- package/src/security/providers/ServerBasicAuthProvider.ts +6 -2
- package/src/security/providers/ServerSecurityProvider.ts +36 -22
- package/src/server/auth/index.ts +12 -7
- package/src/server/cache/index.ts +7 -22
- package/src/server/compress/index.ts +10 -2
- package/src/server/cookies/index.ts +7 -5
- package/src/server/cookies/primitives/$cookie.ts +33 -11
- package/src/server/core/index.ts +16 -6
- package/src/server/core/interfaces/ServerRequest.ts +83 -1
- package/src/server/core/primitives/$action.spec.ts +1 -1
- package/src/server/core/primitives/$action.ts +8 -3
- package/src/server/core/providers/NodeHttpServerProvider.ts +9 -3
- package/src/server/core/services/ServerRequestParser.spec.ts +520 -0
- package/src/server/core/services/ServerRequestParser.ts +306 -13
- package/src/server/cors/index.ts +7 -21
- package/src/server/cors/primitives/$cors.ts +6 -2
- package/src/server/health/index.ts +8 -2
- package/src/server/helmet/index.ts +11 -3
- package/src/server/links/index.ts +11 -6
- package/src/server/metrics/index.ts +10 -3
- package/src/server/multipart/index.ts +9 -3
- package/src/server/proxy/index.ts +8 -2
- package/src/server/rate-limit/index.ts +21 -25
- package/src/server/rate-limit/primitives/$rateLimit.ts +6 -2
- package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +38 -14
- package/src/server/rate-limit/providers/ServerRateLimitProvider.ts +22 -56
- package/src/server/static/index.ts +8 -2
- package/src/server/static/providers/ServerStaticProvider.ts +1 -1
- package/src/server/swagger/index.ts +9 -4
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +1 -1
- package/src/sms/index.ts +9 -5
- package/src/sms/providers/LocalSmsProvider.spec.ts +1 -1
- package/src/sms/providers/LocalSmsProvider.ts +1 -1
- package/src/system/index.browser.ts +11 -0
- package/src/system/index.ts +62 -0
- package/src/{file → system}/providers/FileSystemProvider.ts +16 -0
- package/src/{file → system}/providers/MemoryFileSystemProvider.ts +116 -3
- package/src/system/providers/MemoryShellProvider.ts +164 -0
- package/src/{file → system}/providers/NodeFileSystemProvider.spec.ts +2 -2
- package/src/{file → system}/providers/NodeFileSystemProvider.ts +36 -0
- package/src/system/providers/NodeShellProvider.ts +184 -0
- package/src/system/providers/ShellProvider.ts +74 -0
- package/src/{file → system}/services/FileDetector.spec.ts +2 -2
- package/src/thread/index.ts +11 -2
- package/src/topic/core/index.ts +12 -5
- package/src/vite/tasks/buildClient.ts +2 -7
- package/src/vite/tasks/buildServer.ts +17 -1
- package/src/websocket/index.ts +12 -8
- package/dist/file/index.d.ts.map +0 -1
- package/dist/file/index.js.map +0 -1
- package/src/cli/assets/mainServerTs.ts +0 -24
- package/src/cli/assets/webAppRouterTs.ts +0 -16
- package/src/cli/providers/ViteTemplateProvider.ts +0 -27
- package/src/file/index.ts +0 -43
- /package/src/cli/{assets → templates}/apiHelloControllerTs.ts +0 -0
- /package/src/cli/{assets → templates}/apiIndexTs.ts +0 -0
- /package/src/cli/{assets → templates}/biomeJson.ts +0 -0
- /package/src/cli/{assets → templates}/dummySpecTs.ts +0 -0
- /package/src/cli/{assets → templates}/editorconfig.ts +0 -0
- /package/src/cli/{assets → templates}/mainBrowserTs.ts +0 -0
- /package/src/cli/{assets → templates}/tsconfigJson.ts +0 -0
- /package/src/cli/{assets → templates}/webIndexTs.ts +0 -0
- /package/src/{file → system}/errors/FileError.ts +0 -0
- /package/src/{file → system}/services/FileDetector.ts +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
type ErrorInfo,
|
|
3
|
+
type PropsWithChildren,
|
|
4
|
+
type ReactNode,
|
|
5
|
+
} from "react";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Props for the ErrorBoundary component.
|
|
9
|
+
*/
|
|
10
|
+
export interface ErrorBoundaryProps {
|
|
11
|
+
/**
|
|
12
|
+
* Fallback React node to render when an error is caught.
|
|
13
|
+
* If not provided, a default error message will be shown.
|
|
14
|
+
*/
|
|
15
|
+
fallback: (error: Error) => ReactNode;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Optional callback that receives the error and error info.
|
|
19
|
+
* Use this to log errors to a monitoring service.
|
|
20
|
+
*/
|
|
21
|
+
onError?: (error: Error, info: ErrorInfo) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* State of the ErrorBoundary component.
|
|
26
|
+
*/
|
|
27
|
+
interface ErrorBoundaryState {
|
|
28
|
+
error?: Error;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A reusable error boundary for catching rendering errors in any part of the React component tree.
|
|
33
|
+
*
|
|
34
|
+
* It's already included in the Alepha React framework when using page or layout components.
|
|
35
|
+
*/
|
|
36
|
+
export class ErrorBoundary extends React.Component<
|
|
37
|
+
PropsWithChildren<ErrorBoundaryProps>,
|
|
38
|
+
ErrorBoundaryState
|
|
39
|
+
> {
|
|
40
|
+
constructor(props: ErrorBoundaryProps) {
|
|
41
|
+
super(props);
|
|
42
|
+
this.state = {};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Update state so the next render shows the fallback UI.
|
|
47
|
+
*/
|
|
48
|
+
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
|
|
49
|
+
return {
|
|
50
|
+
error,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Lifecycle method called when an error is caught.
|
|
56
|
+
* You can log the error or perform side effects here.
|
|
57
|
+
*/
|
|
58
|
+
componentDidCatch(error: Error, info: ErrorInfo): void {
|
|
59
|
+
if (this.props.onError) {
|
|
60
|
+
this.props.onError(error, info);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
render(): ReactNode {
|
|
65
|
+
if (this.state.error) {
|
|
66
|
+
return this.props.fallback(this.state.error);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return this.props.children;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default ErrorBoundary;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Alepha } from "alepha";
|
|
2
|
+
import { type ReactNode, useEffect, useMemo, useState } from "react";
|
|
3
|
+
import { AlephaContext } from "./AlephaContext.ts";
|
|
4
|
+
|
|
5
|
+
export interface AlephaProviderProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
onError: (error: Error) => ReactNode;
|
|
8
|
+
onLoading: () => ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* AlephaProvider component to initialize and provide Alepha instance to the app.
|
|
13
|
+
*
|
|
14
|
+
* This isn't recommended for apps using `alepha/react/router`, as Router will handle this for you.
|
|
15
|
+
*/
|
|
16
|
+
export const AlephaProvider = (props: AlephaProviderProps) => {
|
|
17
|
+
const alepha = useMemo(() => Alepha.create(), []);
|
|
18
|
+
|
|
19
|
+
const [started, setStarted] = useState(false);
|
|
20
|
+
const [error, setError] = useState<Error | undefined>();
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
alepha
|
|
24
|
+
.start()
|
|
25
|
+
.then(() => setStarted(true))
|
|
26
|
+
.catch((err) => setError(err));
|
|
27
|
+
}, [alepha]);
|
|
28
|
+
|
|
29
|
+
if (error) {
|
|
30
|
+
return props.onError(error);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!started) {
|
|
34
|
+
return props.onLoading();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<AlephaContext.Provider value={alepha}>
|
|
39
|
+
{props.children}
|
|
40
|
+
</AlephaContext.Provider>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react";
|
|
2
|
+
import { Alepha } from "alepha";
|
|
3
|
+
import { AlephaDateTime } from "alepha/datetime";
|
|
4
|
+
import type { ReactNode } from "react";
|
|
5
|
+
import { describe, test, vi } from "vitest";
|
|
6
|
+
import { AlephaContext } from "../contexts/AlephaContext.ts";
|
|
7
|
+
import { useAction } from "./useAction.ts";
|
|
8
|
+
|
|
9
|
+
describe("useAction", () => {
|
|
10
|
+
test("should handle successful action", async ({ expect }) => {
|
|
11
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
12
|
+
await alepha.start();
|
|
13
|
+
|
|
14
|
+
const mockAction = vi.fn(async (value: string, ctx) => {
|
|
15
|
+
return `result: ${value}`;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
19
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const { result } = renderHook(
|
|
23
|
+
() => useAction({ handler: mockAction }, []),
|
|
24
|
+
{
|
|
25
|
+
wrapper,
|
|
26
|
+
},
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const action = result.current;
|
|
30
|
+
|
|
31
|
+
expect(action.loading).toBe(false);
|
|
32
|
+
expect(action.error).toBe(undefined);
|
|
33
|
+
expect(action.cancel).toBeDefined();
|
|
34
|
+
expect(action.run).toBeDefined();
|
|
35
|
+
|
|
36
|
+
const actionResult = await action.run("test");
|
|
37
|
+
|
|
38
|
+
expect(actionResult).toBe("result: test");
|
|
39
|
+
expect(mockAction).toHaveBeenCalledWith(
|
|
40
|
+
"test",
|
|
41
|
+
expect.objectContaining({
|
|
42
|
+
signal: expect.any(AbortSignal),
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
expect(result.current.loading).toBe(false);
|
|
47
|
+
expect(result.current.error).toBe(undefined);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("should emit react:action events", async ({ expect }) => {
|
|
51
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
52
|
+
await alepha.start();
|
|
53
|
+
|
|
54
|
+
const events: string[] = [];
|
|
55
|
+
|
|
56
|
+
alepha.events.on("react:action:begin", () => {
|
|
57
|
+
events.push("begin");
|
|
58
|
+
});
|
|
59
|
+
alepha.events.on("react:action:success", () => {
|
|
60
|
+
events.push("success");
|
|
61
|
+
});
|
|
62
|
+
alepha.events.on("react:action:end", () => {
|
|
63
|
+
events.push("end");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const mockAction = vi.fn(async (ctx) => "done");
|
|
67
|
+
|
|
68
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
69
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const { result } = renderHook(
|
|
73
|
+
() => useAction({ handler: mockAction }, []),
|
|
74
|
+
{
|
|
75
|
+
wrapper,
|
|
76
|
+
},
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const action = result.current;
|
|
80
|
+
await action.run();
|
|
81
|
+
|
|
82
|
+
expect(events).toEqual(["begin", "success", "end"]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test.skip("should handle errors", async ({ expect }) => {
|
|
86
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
87
|
+
await alepha.start();
|
|
88
|
+
|
|
89
|
+
const error = new Error("Test error");
|
|
90
|
+
const mockAction = vi.fn(async (ctx) => {
|
|
91
|
+
throw error;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
95
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const { result } = renderHook(
|
|
99
|
+
() => useAction({ handler: mockAction }, []),
|
|
100
|
+
{
|
|
101
|
+
wrapper,
|
|
102
|
+
},
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const action = result.current;
|
|
106
|
+
|
|
107
|
+
await expect(() => action.run()).rejects.toThrow("Test error");
|
|
108
|
+
|
|
109
|
+
expect(result.current.error).toBe(error);
|
|
110
|
+
expect(result.current.loading).toBe(false);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("should emit react:action:error on failure", async ({ expect }) => {
|
|
114
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
115
|
+
await alepha.start();
|
|
116
|
+
|
|
117
|
+
const events: Array<{ type: string; error?: Error }> = [];
|
|
118
|
+
|
|
119
|
+
alepha.events.on("react:action:error", (ev) => {
|
|
120
|
+
events.push({ type: "error", error: ev.error });
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const error = new Error("Test error");
|
|
124
|
+
const mockAction = vi.fn(async (ctx) => {
|
|
125
|
+
throw error;
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
129
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const { result } = renderHook(
|
|
133
|
+
() => useAction({ handler: mockAction }, []),
|
|
134
|
+
{
|
|
135
|
+
wrapper,
|
|
136
|
+
},
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const action = result.current;
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
await action.run();
|
|
143
|
+
} catch {
|
|
144
|
+
// Expected
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
expect(events).toHaveLength(1);
|
|
148
|
+
expect(events[0].type).toBe("error");
|
|
149
|
+
expect(events[0].error).toBe(error);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("should call custom error handler", async ({ expect }) => {
|
|
153
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
154
|
+
await alepha.start();
|
|
155
|
+
|
|
156
|
+
const error = new Error("Test error");
|
|
157
|
+
const mockAction = vi.fn(async (ctx) => {
|
|
158
|
+
throw error;
|
|
159
|
+
});
|
|
160
|
+
const onError = vi.fn();
|
|
161
|
+
|
|
162
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
163
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const { result } = renderHook(
|
|
167
|
+
() => useAction({ handler: mockAction, onError }, []),
|
|
168
|
+
{ wrapper },
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const action = result.current;
|
|
172
|
+
await action.run();
|
|
173
|
+
|
|
174
|
+
expect(onError).toHaveBeenCalledWith(error);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("should call custom success handler", async ({ expect }) => {
|
|
178
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
179
|
+
await alepha.start();
|
|
180
|
+
|
|
181
|
+
const mockAction = vi.fn(async (ctx) => "result");
|
|
182
|
+
const onSuccess = vi.fn();
|
|
183
|
+
|
|
184
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
185
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const { result } = renderHook(
|
|
189
|
+
() => useAction({ handler: mockAction, onSuccess }, []),
|
|
190
|
+
{ wrapper },
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const action = result.current;
|
|
194
|
+
await action.run();
|
|
195
|
+
|
|
196
|
+
expect(onSuccess).toHaveBeenCalledWith("result");
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("should include action id in events", async ({ expect }) => {
|
|
200
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
201
|
+
await alepha.start();
|
|
202
|
+
|
|
203
|
+
const events: Array<{ id?: string }> = [];
|
|
204
|
+
|
|
205
|
+
alepha.events.on("react:action:begin", (ev) => {
|
|
206
|
+
events.push({ id: ev.id });
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const mockAction = vi.fn(async (ctx) => "done");
|
|
210
|
+
|
|
211
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
212
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const { result } = renderHook(
|
|
216
|
+
() => useAction({ handler: mockAction, id: "test-action" }, []),
|
|
217
|
+
{ wrapper },
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
const action = result.current;
|
|
221
|
+
await action.run();
|
|
222
|
+
|
|
223
|
+
expect(events[0].id).toBe("test-action");
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("should prevent concurrent executions", async ({ expect }) => {
|
|
227
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
228
|
+
await alepha.start();
|
|
229
|
+
|
|
230
|
+
let executionCount = 0;
|
|
231
|
+
const mockAction = vi.fn(async (ctx) => {
|
|
232
|
+
executionCount++;
|
|
233
|
+
// Simulate slow operation
|
|
234
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
235
|
+
return executionCount;
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
239
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
const { result } = renderHook(
|
|
243
|
+
() => useAction({ handler: mockAction }, []),
|
|
244
|
+
{ wrapper },
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
const action = result.current;
|
|
248
|
+
|
|
249
|
+
// Call 100 times rapidly
|
|
250
|
+
const promises = Array.from({ length: 100 }, () => action.run());
|
|
251
|
+
|
|
252
|
+
// Wait for all to complete
|
|
253
|
+
await Promise.all(promises);
|
|
254
|
+
|
|
255
|
+
// Should have only executed once
|
|
256
|
+
expect(mockAction).toHaveBeenCalledTimes(1);
|
|
257
|
+
expect(executionCount).toBe(1);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test("should debounce action calls", async ({ expect }) => {
|
|
261
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
262
|
+
await alepha.start();
|
|
263
|
+
|
|
264
|
+
const mockAction = vi.fn(async (value: string, ctx) => value);
|
|
265
|
+
|
|
266
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
267
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const { result } = renderHook(
|
|
271
|
+
() => useAction({ handler: mockAction, debounce: 50 }, []),
|
|
272
|
+
{ wrapper },
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
const action = result.current;
|
|
276
|
+
|
|
277
|
+
// Call 100 times rapidly with different values
|
|
278
|
+
for (let i = 0; i < 100; i++) {
|
|
279
|
+
action.run(`value-${i}`);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Wait for debounce to complete
|
|
283
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
284
|
+
|
|
285
|
+
// Should have only executed once with the last value
|
|
286
|
+
expect(mockAction).toHaveBeenCalledTimes(1);
|
|
287
|
+
expect(mockAction).toHaveBeenCalledWith("value-99", expect.any(Object));
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("should reset debounce timer on each call", async ({ expect }) => {
|
|
291
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
292
|
+
await alepha.start();
|
|
293
|
+
|
|
294
|
+
const mockAction = vi.fn(async (value: string, ctx) => value);
|
|
295
|
+
|
|
296
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
297
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
const { result } = renderHook(
|
|
301
|
+
() => useAction({ handler: mockAction, debounce: 50 }, []),
|
|
302
|
+
{ wrapper },
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
const action = result.current;
|
|
306
|
+
|
|
307
|
+
// Call multiple times with delays
|
|
308
|
+
action.run("first");
|
|
309
|
+
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
310
|
+
action.run("second");
|
|
311
|
+
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
312
|
+
action.run("third");
|
|
313
|
+
|
|
314
|
+
// Wait for final debounce
|
|
315
|
+
await new Promise((resolve) => setTimeout(resolve, 60));
|
|
316
|
+
|
|
317
|
+
// Should have only executed once with the last value
|
|
318
|
+
expect(mockAction).toHaveBeenCalledTimes(1);
|
|
319
|
+
expect(mockAction).toHaveBeenCalledWith("third", expect.any(Object));
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
test("should pass AbortSignal to handler", async ({ expect }) => {
|
|
323
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
324
|
+
await alepha.start();
|
|
325
|
+
|
|
326
|
+
let receivedSignal: AbortSignal | undefined;
|
|
327
|
+
|
|
328
|
+
const mockAction = vi.fn(async (value: string, { signal }) => {
|
|
329
|
+
receivedSignal = signal as AbortSignal;
|
|
330
|
+
return value;
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
334
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
const { result } = renderHook(
|
|
338
|
+
() => useAction({ handler: mockAction }, []),
|
|
339
|
+
{ wrapper },
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
const action = result.current;
|
|
343
|
+
await action.run("test");
|
|
344
|
+
|
|
345
|
+
expect(receivedSignal).toBeInstanceOf(AbortSignal);
|
|
346
|
+
expect(receivedSignal?.aborted).toBe(false);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
test("should cancel in-flight request with cancel()", async ({ expect }) => {
|
|
350
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
351
|
+
await alepha.start();
|
|
352
|
+
|
|
353
|
+
let wasAborted = false;
|
|
354
|
+
const mockAction = vi.fn(async (ctx) => {
|
|
355
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
356
|
+
wasAborted = ctx.signal.aborted;
|
|
357
|
+
return "done";
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
361
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
const { result } = renderHook(
|
|
365
|
+
() => useAction({ handler: mockAction }, []),
|
|
366
|
+
{ wrapper },
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
const action = result.current;
|
|
370
|
+
|
|
371
|
+
// Start action
|
|
372
|
+
const promise = action.run();
|
|
373
|
+
|
|
374
|
+
// Cancel after 50ms
|
|
375
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
376
|
+
action.cancel();
|
|
377
|
+
|
|
378
|
+
await promise;
|
|
379
|
+
|
|
380
|
+
expect(wasAborted).toBe(true);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
test("should cancel debounced action", async ({ expect }) => {
|
|
384
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
385
|
+
await alepha.start();
|
|
386
|
+
|
|
387
|
+
const mockAction = vi.fn(async (value: string, ctx) => value);
|
|
388
|
+
|
|
389
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
390
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
const { result } = renderHook(
|
|
394
|
+
() => useAction({ handler: mockAction, debounce: 100 }, []),
|
|
395
|
+
{ wrapper },
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
const action = result.current;
|
|
399
|
+
|
|
400
|
+
// Call handler
|
|
401
|
+
action.run("test");
|
|
402
|
+
|
|
403
|
+
// Cancel before debounce completes
|
|
404
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
405
|
+
action.cancel();
|
|
406
|
+
|
|
407
|
+
// Wait for debounce period
|
|
408
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
409
|
+
|
|
410
|
+
// Should not have executed
|
|
411
|
+
expect(mockAction).not.toHaveBeenCalled();
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
test("should handle AbortError gracefully", async ({ expect }) => {
|
|
415
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
416
|
+
await alepha.start();
|
|
417
|
+
|
|
418
|
+
const mockAction = vi.fn(async (ctx) => {
|
|
419
|
+
const abortError = new Error("The operation was aborted");
|
|
420
|
+
abortError.name = "AbortError";
|
|
421
|
+
throw abortError;
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
425
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
426
|
+
);
|
|
427
|
+
|
|
428
|
+
const { result } = renderHook(
|
|
429
|
+
() => useAction({ handler: mockAction }, []),
|
|
430
|
+
{ wrapper },
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
const action = result.current;
|
|
434
|
+
await action.run();
|
|
435
|
+
|
|
436
|
+
// Should not set error state for abort errors
|
|
437
|
+
expect(result.current.error).toBe(undefined);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
test("should run action on mount with runOnInit", async ({ expect }) => {
|
|
441
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
442
|
+
await alepha.start();
|
|
443
|
+
|
|
444
|
+
const mockAction = vi.fn(async (ctx) => "initialized");
|
|
445
|
+
|
|
446
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
447
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
renderHook(() => useAction({ handler: mockAction, runOnInit: true }, []), {
|
|
451
|
+
wrapper,
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
// Wait a tick for the effect to run
|
|
455
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
456
|
+
|
|
457
|
+
// Should have been called once on mount
|
|
458
|
+
expect(mockAction).toHaveBeenCalledTimes(1);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
test("should not run action on mount without runOnInit", async ({
|
|
462
|
+
expect,
|
|
463
|
+
}) => {
|
|
464
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
465
|
+
await alepha.start();
|
|
466
|
+
|
|
467
|
+
const mockAction = vi.fn(async (ctx) => "result");
|
|
468
|
+
|
|
469
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
470
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
471
|
+
);
|
|
472
|
+
|
|
473
|
+
renderHook(() => useAction({ handler: mockAction }, []), {
|
|
474
|
+
wrapper,
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
// Wait a tick
|
|
478
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
479
|
+
|
|
480
|
+
// Should not have been called
|
|
481
|
+
expect(mockAction).not.toHaveBeenCalled();
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
test("should run action periodically with runEvery (milliseconds)", async ({
|
|
485
|
+
expect,
|
|
486
|
+
}) => {
|
|
487
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
488
|
+
await alepha.start();
|
|
489
|
+
|
|
490
|
+
const mockAction = vi.fn(async (ctx) => "fired");
|
|
491
|
+
|
|
492
|
+
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
493
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
const { unmount } = renderHook(
|
|
497
|
+
() => useAction({ handler: mockAction, runEvery: 60 }, []),
|
|
498
|
+
{ wrapper },
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
// Wait for multiple intervals
|
|
502
|
+
await new Promise((resolve) => setTimeout(resolve, 160));
|
|
503
|
+
|
|
504
|
+
// Should have been called approximately 3 times (at 50ms, 100ms, 150ms)
|
|
505
|
+
expect(mockAction.mock.calls.length).toBeGreaterThanOrEqual(2);
|
|
506
|
+
expect(mockAction.mock.calls.length).toBeLessThanOrEqual(4);
|
|
507
|
+
|
|
508
|
+
// Cleanup
|
|
509
|
+
unmount();
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
test("should run action periodically with runEvery (duration tuple)", async ({
|
|
513
|
+
expect,
|
|
514
|
+
}) => {
|
|
515
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
516
|
+
await alepha.start();
|
|
517
|
+
|
|
518
|
+
const mockAction = vi.fn(async (ctx) => "polled");
|
|
519
|
+
|
|
520
|
+
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
521
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
const { unmount } = renderHook(
|
|
525
|
+
() =>
|
|
526
|
+
useAction({ handler: mockAction, runEvery: [50, "milliseconds"] }, []),
|
|
527
|
+
{ wrapper },
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
// Wait for multiple intervals
|
|
531
|
+
await new Promise((resolve) => setTimeout(resolve, 160));
|
|
532
|
+
|
|
533
|
+
// Should have been called approximately 3 times
|
|
534
|
+
expect(mockAction.mock.calls.length).toBeGreaterThanOrEqual(2);
|
|
535
|
+
expect(mockAction.mock.calls.length).toBeLessThanOrEqual(4);
|
|
536
|
+
|
|
537
|
+
// Cleanup
|
|
538
|
+
unmount();
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
test("should cleanup interval on unmount", async ({ expect }) => {
|
|
542
|
+
const alepha = Alepha.create().with(AlephaDateTime);
|
|
543
|
+
await alepha.start();
|
|
544
|
+
|
|
545
|
+
const mockAction = vi.fn(async (ctx) => "polled");
|
|
546
|
+
|
|
547
|
+
const wrapper = ({ children }: { children: ReactNode }) => (
|
|
548
|
+
<AlephaContext.Provider value={alepha}>{children}</AlephaContext.Provider>
|
|
549
|
+
);
|
|
550
|
+
|
|
551
|
+
const { unmount } = renderHook(
|
|
552
|
+
() => useAction({ handler: mockAction, runEvery: 50 }, []),
|
|
553
|
+
{ wrapper },
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
// Wait for one interval
|
|
557
|
+
await new Promise((resolve) => setTimeout(resolve, 75));
|
|
558
|
+
const callsBeforeUnmount = mockAction.mock.calls.length;
|
|
559
|
+
|
|
560
|
+
// Unmount
|
|
561
|
+
unmount();
|
|
562
|
+
|
|
563
|
+
// Wait for what would be another interval
|
|
564
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
565
|
+
|
|
566
|
+
// Should not have been called again after unmount
|
|
567
|
+
expect(mockAction.mock.calls.length).toBe(callsBeforeUnmount);
|
|
568
|
+
});
|
|
569
|
+
});
|