alepha 0.15.1 → 0.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -80
- package/dist/api/audits/index.d.ts +10 -33
- 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 +10 -3
- 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 +43 -50
- 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 +1081 -760
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +2539 -218
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +138 -132
- 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 +440 -8
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/bucket/index.js +1861 -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 +638 -5645
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2550 -368
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +203 -45
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +2060 -71
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +70 -40
- 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 +90 -40
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +70 -40
- 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 +323 -20
- package/dist/email/index.d.ts.map +1 -1
- package/dist/email/index.js +1857 -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 +10 -30
- 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 +39 -20
- package/dist/orm/index.bun.js.map +1 -1
- package/dist/orm/index.d.ts +517 -540
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +58 -71
- 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 +1974 -0
- package/dist/react/router/index.browser.js.map +1 -0
- package/dist/react/router/index.d.ts +1956 -0
- package/dist/react/router/index.d.ts.map +1 -0
- package/dist/react/router/index.js +4722 -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 +41 -44
- 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 +140 -49
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +164 -32
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +12 -7
- 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 +124 -23
- 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 +8 -2
- 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 +11 -6
- 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 +1853 -5
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts +309 -6
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +1854 -6
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +309 -7
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js +1856 -7
- package/dist/sms/index.js.map +1 -1
- package/dist/system/index.browser.js +1218 -0
- package/dist/system/index.browser.js.map +1 -0
- package/dist/{file → system}/index.d.ts +343 -16
- package/dist/system/index.d.ts.map +1 -0
- package/dist/{file → system}/index.js +419 -22
- 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 +5 -6272
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +23 -10
- 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 +82 -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 +55 -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 +10 -1
- package/src/cli/atoms/buildOptions.ts +99 -9
- package/src/cli/commands/build.ts +150 -37
- package/src/cli/commands/db.ts +22 -18
- 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 +588 -0
- package/src/cli/commands/init.ts +115 -58
- 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 +35 -16
- package/src/cli/services/AlephaCliUtils.ts +52 -121
- package/src/cli/services/PackageManagerUtils.ts +129 -11
- package/src/cli/services/ProjectScaffolder.spec.ts +97 -0
- package/src/cli/services/ProjectScaffolder.ts +148 -81
- package/src/cli/services/ViteUtils.ts +82 -0
- package/src/cli/{assets/claudeMd.ts → templates/agentMd.ts} +37 -24
- package/src/cli/templates/apiAppSecurityTs.ts +11 -0
- package/src/cli/templates/apiIndexTs.ts +30 -0
- 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 +74 -0
- package/src/cli/templates/webHelloComponentTsx.ts +30 -0
- package/src/command/helpers/Runner.spec.ts +139 -0
- package/src/command/helpers/Runner.ts +7 -22
- package/src/command/index.ts +12 -4
- package/src/command/providers/CliProvider.spec.ts +1392 -0
- package/src/command/providers/CliProvider.ts +320 -47
- package/src/core/Alepha.ts +34 -27
- 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 +5 -3
- package/src/orm/index.ts +23 -53
- package/src/orm/providers/drivers/BunSqliteProvider.ts +5 -1
- package/src/orm/providers/drivers/CloudflareD1Provider.ts +57 -30
- package/src/orm/providers/drivers/DatabaseProvider.ts +9 -1
- package/src/orm/providers/drivers/NodeSqliteProvider.ts +4 -1
- 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 +146 -0
- package/src/react/router/primitives/$page.browser.spec.tsx +851 -0
- package/src/react/router/primitives/$page.spec.tsx +676 -0
- package/src/react/router/primitives/$page.ts +489 -0
- package/src/react/router/providers/ReactBrowserProvider.ts +312 -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/ReactPreloadProvider.spec.ts +142 -0
- package/src/react/router/providers/ReactPreloadProvider.ts +85 -0
- package/src/react/router/providers/ReactServerProvider.spec.tsx +316 -0
- package/src/react/router/providers/ReactServerProvider.ts +487 -0
- package/src/react/router/providers/ReactServerTemplateProvider.spec.ts +210 -0
- package/src/react/router/providers/ReactServerTemplateProvider.ts +542 -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 +90 -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 +63 -41
- 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.spec.ts +9 -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 +36 -0
- package/src/system/index.ts +62 -0
- package/src/system/index.workerd.ts +1 -0
- package/src/{file → system}/providers/FileSystemProvider.ts +24 -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 +47 -2
- 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 +19 -13
- package/src/vite/tasks/generateCloudflare.ts +10 -7
- package/src/vite/tasks/generateDocker.ts +4 -0
- 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/apiIndexTs.ts +0 -16
- package/src/cli/assets/mainServerTs.ts +0 -24
- package/src/cli/assets/webAppRouterTs.ts +0 -16
- package/src/cli/assets/webHelloComponentTsx.ts +0 -20
- 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}/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,242 @@
|
|
|
1
|
+
import type { Static } from "alepha";
|
|
2
|
+
import { useAlepha, useInject } from "alepha/react";
|
|
3
|
+
import type { ChannelPrimitive, TWSObject } from "alepha/websocket";
|
|
4
|
+
import { WebSocketClient } from "alepha/websocket";
|
|
5
|
+
import { useEffect, useRef, useState } from "react";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* UseRoom options
|
|
9
|
+
*/
|
|
10
|
+
export interface UseRoomOptions<
|
|
11
|
+
TClient extends TWSObject,
|
|
12
|
+
TServer extends TWSObject,
|
|
13
|
+
> {
|
|
14
|
+
/**
|
|
15
|
+
* Room ID to connect to
|
|
16
|
+
*/
|
|
17
|
+
roomId: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Channel primitive defining the schemas
|
|
21
|
+
*/
|
|
22
|
+
channel: ChannelPrimitive<TClient, TServer>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Handler for incoming messages from the server
|
|
26
|
+
*/
|
|
27
|
+
handler: (message: Static<TClient>) => void;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Optional WebSocket URL override
|
|
31
|
+
* Defaults to auto-detected URL based on window.location
|
|
32
|
+
*/
|
|
33
|
+
url?: string;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Enable automatic reconnection on disconnect
|
|
37
|
+
* @default true
|
|
38
|
+
*/
|
|
39
|
+
autoReconnect?: boolean;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Reconnection interval in milliseconds
|
|
43
|
+
* @default 3000
|
|
44
|
+
*/
|
|
45
|
+
reconnectInterval?: number;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Maximum reconnection attempts (-1 for infinite)
|
|
49
|
+
* @default 10
|
|
50
|
+
*/
|
|
51
|
+
maxReconnectAttempts?: number;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Called when connection is established
|
|
55
|
+
*/
|
|
56
|
+
onConnect?: () => void;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Called when connection is closed
|
|
60
|
+
*/
|
|
61
|
+
onDisconnect?: () => void;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Called on connection error
|
|
65
|
+
*/
|
|
66
|
+
onError?: (error: Error) => void;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* UseRoom return value
|
|
71
|
+
*/
|
|
72
|
+
export interface UseRoomReturn<TServer extends TWSObject> {
|
|
73
|
+
/**
|
|
74
|
+
* Send a message to the server
|
|
75
|
+
*/
|
|
76
|
+
send: (message: Static<TServer>) => Promise<void>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Whether the connection is established
|
|
80
|
+
*/
|
|
81
|
+
isConnected: boolean;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Whether the connection is in progress
|
|
85
|
+
*/
|
|
86
|
+
isConnecting: boolean;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Whether there was an error
|
|
90
|
+
*/
|
|
91
|
+
isError: boolean;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The error object if any
|
|
95
|
+
*/
|
|
96
|
+
error?: Error;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Manually reconnect
|
|
100
|
+
*/
|
|
101
|
+
reconnect: () => void;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Manually disconnect
|
|
105
|
+
*/
|
|
106
|
+
disconnect: () => void;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* React hook for WebSocket room communication
|
|
111
|
+
*
|
|
112
|
+
* Provides automatic connection management, reconnection, and type-safe messaging
|
|
113
|
+
* for WebSocket rooms using the injected WebSocketClient service.
|
|
114
|
+
*
|
|
115
|
+
* Multiple useRoom hooks on the same channel will share a single WebSocket connection.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```tsx
|
|
119
|
+
* const chat = useRoom({
|
|
120
|
+
* roomId: "room-123",
|
|
121
|
+
* channel: chatChannel,
|
|
122
|
+
* handler: (message) => {
|
|
123
|
+
* if (message.type === "append") {
|
|
124
|
+
* setMessages(prev => [...prev, message]);
|
|
125
|
+
* }
|
|
126
|
+
* }
|
|
127
|
+
* }, [roomId]);
|
|
128
|
+
*
|
|
129
|
+
* const sendMessage = async () => {
|
|
130
|
+
* await chat.send({
|
|
131
|
+
* content: "Hello, world!"
|
|
132
|
+
* });
|
|
133
|
+
* };
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export const useRoom = <TClient extends TWSObject, TServer extends TWSObject>(
|
|
137
|
+
options: UseRoomOptions<TClient, TServer>,
|
|
138
|
+
deps: unknown[],
|
|
139
|
+
): UseRoomReturn<TServer> => {
|
|
140
|
+
const webSocketClient = useInject(WebSocketClient);
|
|
141
|
+
const unsubscribeRef = useRef<(() => void) | null>(null);
|
|
142
|
+
|
|
143
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
144
|
+
const [isConnecting, setIsConnecting] = useState(false);
|
|
145
|
+
const [isError, setIsError] = useState(false);
|
|
146
|
+
const [error, setError] = useState<Error | undefined>(undefined);
|
|
147
|
+
|
|
148
|
+
const {
|
|
149
|
+
roomId,
|
|
150
|
+
channel,
|
|
151
|
+
handler,
|
|
152
|
+
url,
|
|
153
|
+
autoReconnect,
|
|
154
|
+
reconnectInterval,
|
|
155
|
+
maxReconnectAttempts,
|
|
156
|
+
onConnect,
|
|
157
|
+
onDisconnect,
|
|
158
|
+
onError,
|
|
159
|
+
} = options;
|
|
160
|
+
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
// Subscribe to room
|
|
163
|
+
const unsubscribe = webSocketClient.subscribe(roomId, channel, handler, {
|
|
164
|
+
url,
|
|
165
|
+
autoReconnect,
|
|
166
|
+
reconnectInterval,
|
|
167
|
+
maxReconnectAttempts,
|
|
168
|
+
onConnect: () => {
|
|
169
|
+
setIsConnected(true);
|
|
170
|
+
setIsConnecting(false);
|
|
171
|
+
setIsError(false);
|
|
172
|
+
setError(undefined);
|
|
173
|
+
onConnect?.();
|
|
174
|
+
},
|
|
175
|
+
onDisconnect: () => {
|
|
176
|
+
setIsConnected(false);
|
|
177
|
+
setIsConnecting(false);
|
|
178
|
+
onDisconnect?.();
|
|
179
|
+
},
|
|
180
|
+
onError: (err) => {
|
|
181
|
+
setIsError(true);
|
|
182
|
+
setError(err);
|
|
183
|
+
setIsConnecting(false);
|
|
184
|
+
onError?.(err);
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
unsubscribeRef.current = unsubscribe;
|
|
189
|
+
|
|
190
|
+
// Get initial state from connection
|
|
191
|
+
const connection = webSocketClient.getConnection(channel);
|
|
192
|
+
if (connection) {
|
|
193
|
+
setIsConnected(connection.isConnected);
|
|
194
|
+
setIsConnecting(connection.isConnecting);
|
|
195
|
+
setIsError(connection.isError);
|
|
196
|
+
setError(connection.error);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Cleanup on unmount or deps change
|
|
200
|
+
return () => {
|
|
201
|
+
unsubscribe();
|
|
202
|
+
unsubscribeRef.current = null;
|
|
203
|
+
};
|
|
204
|
+
}, deps);
|
|
205
|
+
|
|
206
|
+
const alepha = useAlepha();
|
|
207
|
+
|
|
208
|
+
if (!alepha.isBrowser()) {
|
|
209
|
+
return {
|
|
210
|
+
send: async (_message: Static<TServer>) => {
|
|
211
|
+
// No-op on server
|
|
212
|
+
},
|
|
213
|
+
isConnected: false,
|
|
214
|
+
isConnecting: false,
|
|
215
|
+
isError: false,
|
|
216
|
+
error: undefined,
|
|
217
|
+
reconnect: () => {
|
|
218
|
+
// No-op on server
|
|
219
|
+
},
|
|
220
|
+
disconnect: () => {
|
|
221
|
+
// No-op on server
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
send: async (message: Static<TServer>) => {
|
|
228
|
+
await webSocketClient.send(roomId, channel, message);
|
|
229
|
+
},
|
|
230
|
+
isConnected,
|
|
231
|
+
isConnecting,
|
|
232
|
+
isError,
|
|
233
|
+
error,
|
|
234
|
+
reconnect: () => {
|
|
235
|
+
const connection = webSocketClient.getConnection(channel);
|
|
236
|
+
connection?.reconnect();
|
|
237
|
+
},
|
|
238
|
+
disconnect: () => {
|
|
239
|
+
unsubscribeRef.current?.();
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
};
|
|
@@ -55,4 +55,17 @@ describe("Redis", () => {
|
|
|
55
55
|
await redis.lpush("test:b", "b");
|
|
56
56
|
await alepha.stop();
|
|
57
57
|
});
|
|
58
|
+
|
|
59
|
+
it("should increment values atomically", async ({ expect }) => {
|
|
60
|
+
const key = `test:incr:${randomUUID()}`;
|
|
61
|
+
|
|
62
|
+
const val1 = await redis.incr(key, 1);
|
|
63
|
+
expect(val1).toBe(1);
|
|
64
|
+
|
|
65
|
+
const val2 = await redis.incr(key, 5);
|
|
66
|
+
expect(val2).toBe(6);
|
|
67
|
+
|
|
68
|
+
const val3 = await redis.incr(key, -2);
|
|
69
|
+
expect(val3).toBe(4);
|
|
70
|
+
});
|
|
58
71
|
});
|
package/src/redis/index.ts
CHANGED
|
@@ -18,34 +18,18 @@ export * from "./providers/RedisSubscriberProvider.ts";
|
|
|
18
18
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* | type | quality | stability |
|
|
22
|
+
* |------|---------|-----------|
|
|
23
|
+
* | backend | standard | stable |
|
|
22
24
|
*
|
|
23
|
-
*
|
|
24
|
-
* - Bun: Uses `BunRedisProvider` with Bun's native Redis client (7.9x faster than ioredis)
|
|
25
|
-
* - Node.js: Uses `NodeRedisProvider` with `@redis/client`
|
|
25
|
+
* Redis client wrapper.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
27
|
+
* **Features:**
|
|
28
|
+
* - Connection pooling
|
|
29
|
+
* - Automatic reconnection
|
|
30
|
+
* - Command pipelining
|
|
31
|
+
* - Pub/sub support
|
|
31
32
|
*
|
|
32
|
-
* // Use common operations
|
|
33
|
-
* await redis.set("key", "value");
|
|
34
|
-
* const value = await redis.get("key");
|
|
35
|
-
*
|
|
36
|
-
* // For pub/sub
|
|
37
|
-
* const subscriber = alepha.inject(RedisSubscriberProvider);
|
|
38
|
-
* await subscriber.subscribe("channel", (message, channel) => {
|
|
39
|
-
* console.log(`Received: ${message} on ${channel}`);
|
|
40
|
-
* });
|
|
41
|
-
* ```
|
|
42
|
-
*
|
|
43
|
-
* @see {@link RedisProvider} - Abstract base class
|
|
44
|
-
* @see {@link NodeRedisProvider} - Node.js implementation
|
|
45
|
-
* @see {@link BunRedisProvider} - Bun implementation
|
|
46
|
-
* @see {@link RedisSubscriberProvider} - Abstract subscriber base class
|
|
47
|
-
* @see {@link NodeRedisSubscriberProvider} - Node.js subscriber implementation
|
|
48
|
-
* @see {@link BunRedisSubscriberProvider} - Bun subscriber implementation
|
|
49
33
|
* @module alepha.redis
|
|
50
34
|
*/
|
|
51
35
|
export const AlephaRedis = $module({
|
|
@@ -264,6 +264,15 @@ export class BunRedisProvider extends RedisProvider {
|
|
|
264
264
|
await this.publisher.publish(channel, message);
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
// ---------------------------------------------------------
|
|
268
|
+
// Counter operations
|
|
269
|
+
// ---------------------------------------------------------
|
|
270
|
+
|
|
271
|
+
public override async incr(key: string, amount: number): Promise<number> {
|
|
272
|
+
const result = await this.publisher.send("INCRBY", [key, String(amount)]);
|
|
273
|
+
return Number(result);
|
|
274
|
+
}
|
|
275
|
+
|
|
267
276
|
/**
|
|
268
277
|
* Get the Redis connection URL.
|
|
269
278
|
*/
|
|
@@ -233,6 +233,14 @@ export class NodeRedisProvider extends RedisProvider {
|
|
|
233
233
|
await this.publisher.publish(channel, message);
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
+
// ---------------------------------------------------------
|
|
237
|
+
// Counter operations
|
|
238
|
+
// ---------------------------------------------------------
|
|
239
|
+
|
|
240
|
+
public override async incr(key: string, amount: number): Promise<number> {
|
|
241
|
+
return this.publisher.INCRBY(key, amount);
|
|
242
|
+
}
|
|
243
|
+
|
|
236
244
|
/**
|
|
237
245
|
* Get the Redis connection URL.
|
|
238
246
|
*/
|
|
@@ -108,6 +108,22 @@ export abstract class RedisProvider {
|
|
|
108
108
|
* @param message The message to publish.
|
|
109
109
|
*/
|
|
110
110
|
public abstract publish(channel: string, message: string): Promise<void>;
|
|
111
|
+
|
|
112
|
+
// ---------------------------------------------------------
|
|
113
|
+
// Counter operations
|
|
114
|
+
// ---------------------------------------------------------
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Increment the integer value of a key by the given amount.
|
|
118
|
+
*
|
|
119
|
+
* If the key does not exist, it is set to 0 before performing the operation.
|
|
120
|
+
* This operation is atomic.
|
|
121
|
+
*
|
|
122
|
+
* @param key The key to increment.
|
|
123
|
+
* @param amount The amount to increment by.
|
|
124
|
+
* @returns The new value after incrementing.
|
|
125
|
+
*/
|
|
126
|
+
public abstract incr(key: string, amount: number): Promise<number>;
|
|
111
127
|
}
|
|
112
128
|
|
|
113
129
|
/**
|
package/src/retry/index.ts
CHANGED
|
@@ -12,9 +12,18 @@ export * from "./providers/RetryProvider.ts";
|
|
|
12
12
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* | type | quality | stability |
|
|
16
|
+
* |------|---------|-----------|
|
|
17
|
+
* | backend | standard | stable |
|
|
18
|
+
*
|
|
19
|
+
* Automatic retry with backoff.
|
|
20
|
+
*
|
|
21
|
+
* **Features:**
|
|
22
|
+
* - Retry configuration
|
|
23
|
+
* - Exponential backoff
|
|
24
|
+
* - Max retry limits
|
|
25
|
+
* - Custom retry predicates
|
|
16
26
|
*
|
|
17
|
-
* @see {@link RetryProvider}
|
|
18
27
|
* @module alepha.retry
|
|
19
28
|
*/
|
|
20
29
|
export const AlephaRetry = $module({
|
package/src/router/index.ts
CHANGED
|
@@ -1 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* | type | quality | stability |
|
|
3
|
+
* |------|---------|-----------|
|
|
4
|
+
* | frontend | standard | stable |
|
|
5
|
+
*
|
|
6
|
+
* Frontend routing infrastructure.
|
|
7
|
+
*
|
|
8
|
+
* **Features:**
|
|
9
|
+
* - Route state management
|
|
10
|
+
* - Navigation methods
|
|
11
|
+
* - Route matching
|
|
12
|
+
*
|
|
13
|
+
* @module alepha.router
|
|
14
|
+
*/
|
|
15
|
+
|
|
1
16
|
export * from "./providers/RouterProvider.ts";
|
package/src/scheduler/index.ts
CHANGED
|
@@ -35,9 +35,18 @@ declare module "alepha" {
|
|
|
35
35
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
38
|
+
* | type | quality | stability |
|
|
39
|
+
* |------|---------|-----------|
|
|
40
|
+
* | backend | rare | stable |
|
|
41
|
+
*
|
|
42
|
+
* Cron and interval-based task execution.
|
|
43
|
+
*
|
|
44
|
+
* **Features:**
|
|
45
|
+
* - Scheduled tasks with cron expressions (e.g., `0 0 * * *`)
|
|
46
|
+
* - Interval-based scheduling
|
|
47
|
+
* - Distributed locking to prevent duplicate execution
|
|
48
|
+
* - Lifecycle hooks: `begin`, `success`, `error`, `end`
|
|
39
49
|
*
|
|
40
|
-
* @see {@link $scheduler}
|
|
41
50
|
* @module alepha.scheduler
|
|
42
51
|
*/
|
|
43
52
|
export const AlephaScheduler = $module({
|
|
@@ -24,6 +24,7 @@ describe("Basic Authentication", () => {
|
|
|
24
24
|
|
|
25
25
|
// Action without basic auth
|
|
26
26
|
publicAction = $action({
|
|
27
|
+
secure: false,
|
|
27
28
|
handler: () => "public success",
|
|
28
29
|
});
|
|
29
30
|
|
|
@@ -48,6 +49,7 @@ describe("Basic Authentication", () => {
|
|
|
48
49
|
});
|
|
49
50
|
|
|
50
51
|
customAuthAction = $action({
|
|
52
|
+
secure: false,
|
|
51
53
|
handler: async (request) => {
|
|
52
54
|
this.customAuth.check(request);
|
|
53
55
|
return "custom auth success";
|
|
@@ -15,6 +15,7 @@ describe("ServerSecurityProvider", () => {
|
|
|
15
15
|
it("should protect action from unauthorized users", async () => {
|
|
16
16
|
class TestApp {
|
|
17
17
|
ok = $action({
|
|
18
|
+
secure: true,
|
|
18
19
|
handler: () => "OK",
|
|
19
20
|
});
|
|
20
21
|
}
|
|
@@ -23,16 +24,24 @@ describe("ServerSecurityProvider", () => {
|
|
|
23
24
|
const app = alepha.inject(TestApp);
|
|
24
25
|
await alepha.start();
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
expect(await app.ok.run({})).toBe("OK");
|
|
28
|
-
|
|
29
|
-
// but you can force empty user
|
|
27
|
+
await expect(app.ok.run({})).rejects.toThrowError(UnauthorizedError);
|
|
30
28
|
await expect(app.ok.run({}, { user: undefined })).rejects.toThrowError(
|
|
31
29
|
UnauthorizedError,
|
|
32
30
|
);
|
|
33
31
|
|
|
34
32
|
// .fetch() will also generates a dummy user in testing environment
|
|
35
|
-
expect(
|
|
33
|
+
expect(
|
|
34
|
+
await app.ok
|
|
35
|
+
.fetch(
|
|
36
|
+
{},
|
|
37
|
+
{
|
|
38
|
+
user: {
|
|
39
|
+
id: randomUUID(),
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
)
|
|
43
|
+
.then((it) => it.data),
|
|
44
|
+
).toBe("OK");
|
|
36
45
|
|
|
37
46
|
// but you can also force empty user
|
|
38
47
|
await expect(app.ok.fetch({}, { user: undefined })).rejects.toThrowError(
|
|
@@ -55,10 +64,12 @@ describe("ServerSecurityProvider", () => {
|
|
|
55
64
|
it("should guard by permission", async () => {
|
|
56
65
|
class TestApp {
|
|
57
66
|
admin = $action({
|
|
67
|
+
secure: true,
|
|
58
68
|
group: "read",
|
|
59
69
|
handler: () => "ADMIN",
|
|
60
70
|
});
|
|
61
71
|
user = $action({
|
|
72
|
+
secure: true,
|
|
62
73
|
group: "read",
|
|
63
74
|
handler: () => "USER",
|
|
64
75
|
});
|
|
@@ -120,4 +131,78 @@ describe("ServerSecurityProvider", () => {
|
|
|
120
131
|
await app.admin.fetch({}, { user: admin }).then((it) => it.data),
|
|
121
132
|
).toBe("ADMIN");
|
|
122
133
|
});
|
|
134
|
+
|
|
135
|
+
it("should allow public actions by default (no secure option)", async () => {
|
|
136
|
+
class TestApp {
|
|
137
|
+
public = $action({
|
|
138
|
+
handler: () => "PUBLIC",
|
|
139
|
+
});
|
|
140
|
+
issuer = $issuer({
|
|
141
|
+
secret: "test",
|
|
142
|
+
roles: [{ name: "user", permissions: [{ name: "*" }] }],
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const alepha = Alepha.create().with(AlephaServer).with(AlephaSecurity);
|
|
147
|
+
const app = alepha.inject(TestApp);
|
|
148
|
+
await alepha.start();
|
|
149
|
+
|
|
150
|
+
// Should work without authentication via .run()
|
|
151
|
+
expect(await app.public.run({})).toBe("PUBLIC");
|
|
152
|
+
|
|
153
|
+
// Should work without authentication via .fetch()
|
|
154
|
+
expect(await app.public.fetch({}).then((it) => it.data)).toBe("PUBLIC");
|
|
155
|
+
|
|
156
|
+
// Should work via HTTP without token
|
|
157
|
+
const response = await fetch(
|
|
158
|
+
`${alepha.inject(ServerProvider).hostname}${app.public.route.path}`,
|
|
159
|
+
);
|
|
160
|
+
expect(response.status).toBe(200);
|
|
161
|
+
expect(await response.text()).toBe("PUBLIC");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("should allow explicit secure: false", async () => {
|
|
165
|
+
class TestApp {
|
|
166
|
+
public = $action({
|
|
167
|
+
secure: false,
|
|
168
|
+
handler: () => "PUBLIC",
|
|
169
|
+
});
|
|
170
|
+
issuer = $issuer({
|
|
171
|
+
secret: "test",
|
|
172
|
+
roles: [{ name: "user", permissions: [{ name: "*" }] }],
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const alepha = Alepha.create().with(AlephaServer).with(AlephaSecurity);
|
|
177
|
+
const app = alepha.inject(TestApp);
|
|
178
|
+
await alepha.start();
|
|
179
|
+
|
|
180
|
+
// Should work without authentication
|
|
181
|
+
expect(await app.public.run({})).toBe("PUBLIC");
|
|
182
|
+
expect(await app.public.fetch({}).then((it) => it.data)).toBe("PUBLIC");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("should require auth when secure: true is explicit", async () => {
|
|
186
|
+
class TestApp {
|
|
187
|
+
protected = $action({
|
|
188
|
+
secure: true,
|
|
189
|
+
handler: () => "PROTECTED",
|
|
190
|
+
});
|
|
191
|
+
issuer = $issuer({
|
|
192
|
+
secret: "test",
|
|
193
|
+
roles: [{ name: "user", permissions: [{ name: "*" }] }],
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const alepha = Alepha.create().with(AlephaServer).with(AlephaSecurity);
|
|
198
|
+
const app = alepha.inject(TestApp);
|
|
199
|
+
await alepha.start();
|
|
200
|
+
|
|
201
|
+
// Should fail without user
|
|
202
|
+
await expect(app.protected.run({})).rejects.toThrowError(UnauthorizedError);
|
|
203
|
+
|
|
204
|
+
// Should succeed with user
|
|
205
|
+
const user = { id: randomUUID(), roles: ["user"] };
|
|
206
|
+
expect(await app.protected.run({}, { user })).toBe("PROTECTED");
|
|
207
|
+
});
|
|
123
208
|
});
|
package/src/security/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ import type { UserAccount } from "./schemas/userAccountInfoSchema.ts";
|
|
|
15
15
|
export * from "./errors/InvalidCredentialsError.ts";
|
|
16
16
|
export * from "./errors/InvalidPermissionError.ts";
|
|
17
17
|
export * from "./errors/SecurityError.ts";
|
|
18
|
+
export * from "./interfaces/IssuerResolver.ts";
|
|
18
19
|
export * from "./interfaces/UserAccountToken.ts";
|
|
19
20
|
export * from "./primitives/$basicAuth.ts";
|
|
20
21
|
export * from "./primitives/$issuer.ts";
|
|
@@ -88,19 +89,23 @@ declare module "alepha/server" {
|
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
/**
|
|
91
|
-
*
|
|
92
|
+
* | type | quality | stability |
|
|
93
|
+
* |------|---------|-----------|
|
|
94
|
+
* | backend | epic | stable |
|
|
92
95
|
*
|
|
93
|
-
*
|
|
94
|
-
* on class properties. It offers JWT-based authentication, fine-grained permissions, service accounts, and seamless
|
|
95
|
-
* integration with various authentication providers and user management systems.
|
|
96
|
+
* Complete authentication and authorization system with JWT, RBAC, and multi-issuer support.
|
|
96
97
|
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
98
|
+
* **Features:**
|
|
99
|
+
* - JWT token issuer with role definitions
|
|
100
|
+
* - Role-based access control (RBAC)
|
|
101
|
+
* - Fine-grained permissions
|
|
102
|
+
* - HTTP Basic Authentication
|
|
103
|
+
* - Service-to-service authentication
|
|
104
|
+
* - Multi-issuer support for federated auth
|
|
105
|
+
* - JWKS (JSON Web Key Set) for external issuers
|
|
106
|
+
* - Token refresh logic
|
|
107
|
+
* - User profile extraction from JWT
|
|
99
108
|
*
|
|
100
|
-
* @see {@link $issuer}
|
|
101
|
-
* @see {@link $role}
|
|
102
|
-
* @see {@link $permission}
|
|
103
|
-
* @see {@link $basicAuth}
|
|
104
109
|
* @module alepha.security
|
|
105
110
|
*/
|
|
106
111
|
export const AlephaSecurity = $module({
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ServerRequest } from "alepha/server";
|
|
2
|
+
import type { UserAccount } from "../schemas/userAccountInfoSchema.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* User info that a resolver returns.
|
|
6
|
+
* This is the input to `SecurityProvider.createUser()`.
|
|
7
|
+
*/
|
|
8
|
+
export type UserInfo = Omit<UserAccount, "sessionId"> & {
|
|
9
|
+
sessionId?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Resolver definition for authenticating users from requests.
|
|
14
|
+
*/
|
|
15
|
+
export interface IssuerResolver {
|
|
16
|
+
/**
|
|
17
|
+
* Priority (lower = first). Default: 100
|
|
18
|
+
*/
|
|
19
|
+
priority?: number;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Resolve user from HTTP request.
|
|
23
|
+
* Return UserInfo if authenticated, null to try next resolver.
|
|
24
|
+
* Throw UnauthorizedError to stop chain.
|
|
25
|
+
*/
|
|
26
|
+
onRequest: (req: ServerRequest) => Promise<UserInfo | null>;
|
|
27
|
+
}
|