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,401 @@
|
|
|
1
|
+
import { Alepha } from "alepha";
|
|
2
|
+
import { ApiKeyService } from "alepha/api/keys";
|
|
3
|
+
import { DateTimeProvider } from "alepha/datetime";
|
|
4
|
+
import { AlephaEmail } from "alepha/email";
|
|
5
|
+
import { AlephaSecurity } from "alepha/security";
|
|
6
|
+
import { AlephaServer, ForbiddenError } from "alepha/server";
|
|
7
|
+
import { describe, it } from "vitest";
|
|
8
|
+
import { $realm, AlephaApiUsers, SessionService } from "../index.ts";
|
|
9
|
+
|
|
10
|
+
const setup = async () => {
|
|
11
|
+
const alepha = Alepha.create({
|
|
12
|
+
env: { LOG_LEVEL: "error" },
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
alepha.with(AlephaServer);
|
|
16
|
+
alepha.with(AlephaSecurity);
|
|
17
|
+
alepha.with(AlephaEmail);
|
|
18
|
+
alepha.with(AlephaApiUsers);
|
|
19
|
+
|
|
20
|
+
// Create a realm with API keys enabled
|
|
21
|
+
class TestApp {
|
|
22
|
+
realm = $realm({
|
|
23
|
+
apiKeys: true,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
alepha.inject(TestApp);
|
|
28
|
+
await alepha.start();
|
|
29
|
+
|
|
30
|
+
const sessionService = alepha.inject(SessionService);
|
|
31
|
+
const apiKeyService = alepha.inject(ApiKeyService);
|
|
32
|
+
const dateTimeProvider = alepha.inject(DateTimeProvider);
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
alepha,
|
|
36
|
+
sessionService,
|
|
37
|
+
apiKeyService,
|
|
38
|
+
dateTimeProvider,
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
describe("alepha/api/users - API Keys Integration", () => {
|
|
43
|
+
it("should create an API key for a user", async ({ expect }) => {
|
|
44
|
+
const { sessionService, apiKeyService } = await setup();
|
|
45
|
+
|
|
46
|
+
// Create a user
|
|
47
|
+
const user = await sessionService.users().create({
|
|
48
|
+
username: "testuser",
|
|
49
|
+
email: "test@example.com",
|
|
50
|
+
roles: ["user"],
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Create an API key
|
|
54
|
+
const { apiKey, token } = await apiKeyService.create({
|
|
55
|
+
userId: user.id,
|
|
56
|
+
name: "My API Key",
|
|
57
|
+
roles: ["user"],
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(apiKey.name).toBe("My API Key");
|
|
61
|
+
expect(apiKey.userId).toBe(user.id);
|
|
62
|
+
expect(apiKey.roles).toEqual(["user"]);
|
|
63
|
+
expect(token).toMatch(/^ak_/);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should validate API key and return user info", async ({ expect }) => {
|
|
67
|
+
const { sessionService, apiKeyService } = await setup();
|
|
68
|
+
|
|
69
|
+
// Create a user
|
|
70
|
+
const user = await sessionService.users().create({
|
|
71
|
+
username: "testuser",
|
|
72
|
+
email: "test@example.com",
|
|
73
|
+
roles: ["user"],
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Create an API key
|
|
77
|
+
const { token } = await apiKeyService.create({
|
|
78
|
+
userId: user.id,
|
|
79
|
+
name: "My API Key",
|
|
80
|
+
roles: ["user"],
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Validate the API key
|
|
84
|
+
const userInfo = await apiKeyService.validate(token);
|
|
85
|
+
|
|
86
|
+
expect(userInfo).not.toBeNull();
|
|
87
|
+
expect(userInfo?.id).toBe(user.id);
|
|
88
|
+
expect(userInfo?.roles).toEqual(["user"]);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should resolve user from API key in query param via resolver", async ({
|
|
92
|
+
expect,
|
|
93
|
+
}) => {
|
|
94
|
+
const { sessionService, apiKeyService } = await setup();
|
|
95
|
+
|
|
96
|
+
// Create a user
|
|
97
|
+
const user = await sessionService.users().create({
|
|
98
|
+
username: "testuser",
|
|
99
|
+
email: "test@example.com",
|
|
100
|
+
roles: ["user"],
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Create an API key
|
|
104
|
+
const { token } = await apiKeyService.create({
|
|
105
|
+
userId: user.id,
|
|
106
|
+
name: "My API Key",
|
|
107
|
+
roles: ["user"],
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Create resolver and test with query param
|
|
111
|
+
const resolver = apiKeyService.createResolver();
|
|
112
|
+
const userInfo = await resolver.onRequest({
|
|
113
|
+
url: new URL(`http://localhost/profile?api_key=${token}`),
|
|
114
|
+
headers: {},
|
|
115
|
+
} as any);
|
|
116
|
+
|
|
117
|
+
expect(userInfo).not.toBeNull();
|
|
118
|
+
expect(userInfo?.id).toBe(user.id);
|
|
119
|
+
expect(userInfo?.roles).toEqual(["user"]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should resolve user from API key in Bearer header via resolver", async ({
|
|
123
|
+
expect,
|
|
124
|
+
}) => {
|
|
125
|
+
const { sessionService, apiKeyService } = await setup();
|
|
126
|
+
|
|
127
|
+
// Create a user
|
|
128
|
+
const user = await sessionService.users().create({
|
|
129
|
+
username: "testuser",
|
|
130
|
+
email: "test@example.com",
|
|
131
|
+
roles: ["user"],
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Create an API key
|
|
135
|
+
const { token } = await apiKeyService.create({
|
|
136
|
+
userId: user.id,
|
|
137
|
+
name: "My API Key",
|
|
138
|
+
roles: ["user"],
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Create resolver and test with Bearer header
|
|
142
|
+
const resolver = apiKeyService.createResolver();
|
|
143
|
+
const userInfo = await resolver.onRequest({
|
|
144
|
+
url: new URL("http://localhost/profile"),
|
|
145
|
+
headers: { authorization: `Bearer ${token}` },
|
|
146
|
+
} as any);
|
|
147
|
+
|
|
148
|
+
expect(userInfo).not.toBeNull();
|
|
149
|
+
expect(userInfo?.id).toBe(user.id);
|
|
150
|
+
expect(userInfo?.roles).toEqual(["user"]);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("should not resolve JWT tokens as API keys", async ({ expect }) => {
|
|
154
|
+
const { apiKeyService } = await setup();
|
|
155
|
+
|
|
156
|
+
// Create resolver and test with a JWT-like token (contains dots)
|
|
157
|
+
const resolver = apiKeyService.createResolver();
|
|
158
|
+
const userInfo = await resolver.onRequest({
|
|
159
|
+
url: new URL("http://localhost/profile"),
|
|
160
|
+
headers: {
|
|
161
|
+
authorization:
|
|
162
|
+
"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature",
|
|
163
|
+
},
|
|
164
|
+
} as any);
|
|
165
|
+
|
|
166
|
+
// Should return null because JWT tokens should be handled by JWT resolver
|
|
167
|
+
expect(userInfo).toBeNull();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("should reject revoked API key", async ({ expect }) => {
|
|
171
|
+
const { sessionService, apiKeyService } = await setup();
|
|
172
|
+
|
|
173
|
+
// Create a user
|
|
174
|
+
const user = await sessionService.users().create({
|
|
175
|
+
username: "testuser",
|
|
176
|
+
email: "test@example.com",
|
|
177
|
+
roles: ["user"],
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Create an API key
|
|
181
|
+
const { apiKey, token } = await apiKeyService.create({
|
|
182
|
+
userId: user.id,
|
|
183
|
+
name: "My API Key",
|
|
184
|
+
roles: ["user"],
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Verify key is valid
|
|
188
|
+
const beforeRevoke = await apiKeyService.validate(token);
|
|
189
|
+
expect(beforeRevoke).not.toBeNull();
|
|
190
|
+
|
|
191
|
+
// Revoke the key
|
|
192
|
+
await apiKeyService.revoke(apiKey.id, user.id);
|
|
193
|
+
|
|
194
|
+
// Verify key is now invalid
|
|
195
|
+
const afterRevoke = await apiKeyService.validate(token);
|
|
196
|
+
expect(afterRevoke).toBeNull();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it("should reject expired API key", async ({ expect }) => {
|
|
200
|
+
const { sessionService, apiKeyService, dateTimeProvider } = await setup();
|
|
201
|
+
|
|
202
|
+
// Create a user
|
|
203
|
+
const user = await sessionService.users().create({
|
|
204
|
+
username: "testuser",
|
|
205
|
+
email: "test@example.com",
|
|
206
|
+
roles: ["user"],
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Create an API key that expires in 1 hour
|
|
210
|
+
const expiresAt = dateTimeProvider.now().add(1, "hour").toDate();
|
|
211
|
+
const { token } = await apiKeyService.create({
|
|
212
|
+
userId: user.id,
|
|
213
|
+
name: "Expiring Key",
|
|
214
|
+
roles: ["user"],
|
|
215
|
+
expiresAt,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Verify key is valid
|
|
219
|
+
const beforeExpiry = await apiKeyService.validate(token);
|
|
220
|
+
expect(beforeExpiry).not.toBeNull();
|
|
221
|
+
|
|
222
|
+
// Travel forward in time past expiry
|
|
223
|
+
dateTimeProvider.travel(2, "hours");
|
|
224
|
+
|
|
225
|
+
// Verify key is now invalid
|
|
226
|
+
const afterExpiry = await apiKeyService.validate(token);
|
|
227
|
+
expect(afterExpiry).toBeNull();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("should reject invalid API key", async ({ expect }) => {
|
|
231
|
+
await setup();
|
|
232
|
+
|
|
233
|
+
const { apiKeyService } = await setup();
|
|
234
|
+
|
|
235
|
+
// Try to validate an invalid token
|
|
236
|
+
const result = await apiKeyService.validate("ak_invalid_token_12345678");
|
|
237
|
+
expect(result).toBeNull();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it("should list user's API keys", async ({ expect }) => {
|
|
241
|
+
const { sessionService, apiKeyService } = await setup();
|
|
242
|
+
|
|
243
|
+
// Create a user
|
|
244
|
+
const user = await sessionService.users().create({
|
|
245
|
+
username: "testuser",
|
|
246
|
+
email: "test@example.com",
|
|
247
|
+
roles: ["user"],
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Create multiple API keys
|
|
251
|
+
await apiKeyService.create({
|
|
252
|
+
userId: user.id,
|
|
253
|
+
name: "Key 1",
|
|
254
|
+
roles: ["user"],
|
|
255
|
+
});
|
|
256
|
+
await apiKeyService.create({
|
|
257
|
+
userId: user.id,
|
|
258
|
+
name: "Key 2",
|
|
259
|
+
roles: ["user"],
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// List keys
|
|
263
|
+
const keys = await apiKeyService.list(user.id);
|
|
264
|
+
|
|
265
|
+
expect(keys).toHaveLength(2);
|
|
266
|
+
expect(keys.map((k) => k.name).sort()).toEqual(["Key 1", "Key 2"]);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("should not allow revoking another user's API key", async ({ expect }) => {
|
|
270
|
+
const { sessionService, apiKeyService } = await setup();
|
|
271
|
+
|
|
272
|
+
// Create two users
|
|
273
|
+
const user1 = await sessionService.users().create({
|
|
274
|
+
username: "user1",
|
|
275
|
+
email: "user1@example.com",
|
|
276
|
+
roles: ["user"],
|
|
277
|
+
});
|
|
278
|
+
const user2 = await sessionService.users().create({
|
|
279
|
+
username: "user2",
|
|
280
|
+
email: "user2@example.com",
|
|
281
|
+
roles: ["user"],
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// Create an API key for user1
|
|
285
|
+
const { apiKey } = await apiKeyService.create({
|
|
286
|
+
userId: user1.id,
|
|
287
|
+
name: "User1 Key",
|
|
288
|
+
roles: ["user"],
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// Try to revoke user1's key as user2
|
|
292
|
+
await expect(
|
|
293
|
+
apiKeyService.revoke(apiKey.id, user2.id),
|
|
294
|
+
).rejects.toThrowError(ForbiddenError);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it("should create API key with description", async ({ expect }) => {
|
|
298
|
+
const { sessionService, apiKeyService } = await setup();
|
|
299
|
+
|
|
300
|
+
// Create a user
|
|
301
|
+
const user = await sessionService.users().create({
|
|
302
|
+
username: "testuser",
|
|
303
|
+
email: "test@example.com",
|
|
304
|
+
roles: ["user", "admin"],
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Create API key with description
|
|
308
|
+
const { apiKey, token } = await apiKeyService.create({
|
|
309
|
+
userId: user.id,
|
|
310
|
+
name: "My Key",
|
|
311
|
+
description: "Used for CI/CD pipeline",
|
|
312
|
+
roles: ["user", "admin"],
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
expect(apiKey.name).toBe("My Key");
|
|
316
|
+
expect(apiKey.description).toBe("Used for CI/CD pipeline");
|
|
317
|
+
expect(apiKey.roles).toEqual(["user", "admin"]);
|
|
318
|
+
expect(token).toMatch(/^ak_/);
|
|
319
|
+
|
|
320
|
+
// Validate works
|
|
321
|
+
const userInfo = await apiKeyService.validate(token);
|
|
322
|
+
expect(userInfo?.id).toBe(user.id);
|
|
323
|
+
expect(userInfo?.roles).toEqual(["user", "admin"]);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it("should support API key with admin role", async ({ expect }) => {
|
|
327
|
+
const { sessionService, apiKeyService } = await setup();
|
|
328
|
+
|
|
329
|
+
// Create an admin user
|
|
330
|
+
const adminUser = await sessionService.users().create({
|
|
331
|
+
username: "admin",
|
|
332
|
+
email: "admin@example.com",
|
|
333
|
+
roles: ["admin"],
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// Create an API key with admin role
|
|
337
|
+
const { token } = await apiKeyService.create({
|
|
338
|
+
userId: adminUser.id,
|
|
339
|
+
name: "Admin API Key",
|
|
340
|
+
roles: ["admin"],
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// Validate API key returns admin role
|
|
344
|
+
const userInfo = await apiKeyService.validate(token);
|
|
345
|
+
expect(userInfo).not.toBeNull();
|
|
346
|
+
expect(userInfo?.id).toBe(adminUser.id);
|
|
347
|
+
expect(userInfo?.roles).toEqual(["admin"]);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it("should not revoke already revoked keys twice", async ({ expect }) => {
|
|
351
|
+
const { sessionService, apiKeyService } = await setup();
|
|
352
|
+
|
|
353
|
+
// Create a user
|
|
354
|
+
const user = await sessionService.users().create({
|
|
355
|
+
username: "testuser",
|
|
356
|
+
email: "test@example.com",
|
|
357
|
+
roles: ["user"],
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// Create and revoke an API key
|
|
361
|
+
const { apiKey, token } = await apiKeyService.create({
|
|
362
|
+
userId: user.id,
|
|
363
|
+
name: "My Key",
|
|
364
|
+
roles: ["user"],
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
await apiKeyService.revoke(apiKey.id, user.id);
|
|
368
|
+
|
|
369
|
+
// Verify key is revoked
|
|
370
|
+
const result = await apiKeyService.validate(token);
|
|
371
|
+
expect(result).toBeNull();
|
|
372
|
+
|
|
373
|
+
// Admin revoke should not fail on already revoked key
|
|
374
|
+
await apiKeyService.revokeByAdmin(apiKey.id);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it("should create API key with custom prefix", async ({ expect }) => {
|
|
378
|
+
const { sessionService, apiKeyService } = await setup();
|
|
379
|
+
|
|
380
|
+
// Create a user
|
|
381
|
+
const user = await sessionService.users().create({
|
|
382
|
+
username: "testuser",
|
|
383
|
+
email: "test@example.com",
|
|
384
|
+
roles: ["user"],
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// Create an API key with custom prefix
|
|
388
|
+
const { token } = await apiKeyService.create({
|
|
389
|
+
userId: user.id,
|
|
390
|
+
name: "Custom Key",
|
|
391
|
+
roles: ["user"],
|
|
392
|
+
prefix: "prod",
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
expect(token).toMatch(/^prod_/);
|
|
396
|
+
|
|
397
|
+
// Should still validate
|
|
398
|
+
const userInfo = await apiKeyService.validate(token);
|
|
399
|
+
expect(userInfo).not.toBeNull();
|
|
400
|
+
});
|
|
401
|
+
});
|
package/src/api/users/index.ts
CHANGED
|
@@ -57,10 +57,21 @@ export * from "./services/UserService.ts";
|
|
|
57
57
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
|
-
*
|
|
60
|
+
* | type | quality | stability |
|
|
61
|
+
* |------|---------|-----------|
|
|
62
|
+
* | backend | epic | stable |
|
|
61
63
|
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
+
* Complete user management with multi-realm support for multi-tenant applications.
|
|
65
|
+
*
|
|
66
|
+
* **Features:**
|
|
67
|
+
* - User registration, login, and profile management
|
|
68
|
+
* - Password reset workflows
|
|
69
|
+
* - Email verification
|
|
70
|
+
* - Session management with multiple devices
|
|
71
|
+
* - Identity management (social logins, SSO)
|
|
72
|
+
* - Multi-realm support for tenant isolation
|
|
73
|
+
* - Credential management
|
|
74
|
+
* - Entities: `users`, `identities`, `sessions`
|
|
64
75
|
*
|
|
65
76
|
* @module alepha.api.users
|
|
66
77
|
*/
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { $context } from "alepha";
|
|
2
2
|
import { AlephaApiAudits } from "alepha/api/audits";
|
|
3
3
|
import { AlephaApiFiles } from "alepha/api/files";
|
|
4
|
+
import { AlephaApiJobs } from "alepha/api/jobs";
|
|
5
|
+
import { AlephaApiKeys, ApiKeyService } from "alepha/api/keys";
|
|
4
6
|
import type { Repository } from "alepha/orm";
|
|
5
7
|
import {
|
|
6
8
|
$issuer,
|
|
7
9
|
type IssuerPrimitive,
|
|
8
10
|
type IssuerPrimitiveOptions,
|
|
11
|
+
type IssuerResolver,
|
|
9
12
|
SecurityProvider,
|
|
10
13
|
} from "alepha/security";
|
|
11
14
|
import {
|
|
@@ -65,13 +68,29 @@ export const $realm = (options: RealmOptions = {}): RealmPrimitive => {
|
|
|
65
68
|
|
|
66
69
|
const realmRegistration = realmProvider.register(name, options);
|
|
67
70
|
|
|
71
|
+
// For now, all modules are enabled
|
|
68
72
|
alepha.with(AlephaApiFiles);
|
|
69
73
|
alepha.with(AlephaApiAudits);
|
|
74
|
+
alepha.with(AlephaApiJobs);
|
|
75
|
+
|
|
76
|
+
// Collect custom resolvers that will be registered during $issuer.onInit()
|
|
77
|
+
// This ensures they are registered AFTER the realm is created (not on the default test realm)
|
|
78
|
+
const customResolvers: IssuerResolver[] = [
|
|
79
|
+
...(options.issuer?.resolvers ?? []),
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
// Enable API key authentication - must be added to customResolvers before $issuer() call
|
|
83
|
+
if (options.apiKeys) {
|
|
84
|
+
alepha.with(AlephaApiKeys);
|
|
85
|
+
const apiKeyService = alepha.inject(ApiKeyService);
|
|
86
|
+
customResolvers.push(apiKeyService.createResolver());
|
|
87
|
+
}
|
|
70
88
|
|
|
71
89
|
const realm: RealmPrimitive = $issuer({
|
|
72
90
|
...options.issuer,
|
|
73
91
|
name,
|
|
74
92
|
secret: options.secret ?? securityProvider.secretKey,
|
|
93
|
+
resolvers: customResolvers,
|
|
75
94
|
roles: options.issuer?.roles ?? [
|
|
76
95
|
{
|
|
77
96
|
name: "admin",
|
|
@@ -189,9 +208,18 @@ export interface RealmOptions {
|
|
|
189
208
|
github?: true;
|
|
190
209
|
};
|
|
191
210
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
211
|
+
/**
|
|
212
|
+
* Enable API key authentication.
|
|
213
|
+
*
|
|
214
|
+
* When enabled, users can create API keys to access protected endpoints
|
|
215
|
+
* without using JWT tokens. API keys are useful for:
|
|
216
|
+
* - Programmatic access (CLI tools, scripts)
|
|
217
|
+
* - Long-lived authentication tokens
|
|
218
|
+
* - Third-party integrations
|
|
219
|
+
*
|
|
220
|
+
* API keys can be passed via:
|
|
221
|
+
* - Query parameter: `?api_key=ak_xxx`
|
|
222
|
+
* - Bearer header: `Authorization: Bearer ak_xxx`
|
|
223
|
+
*/
|
|
224
|
+
apiKeys?: boolean;
|
|
197
225
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $
|
|
1
|
+
import { $inject, Alepha, AlephaError } from "alepha";
|
|
2
2
|
import { $bucket } from "alepha/bucket";
|
|
3
3
|
import { $repository, type Repository } from "alepha/orm";
|
|
4
4
|
import {
|
|
@@ -36,17 +36,6 @@ export class RealmProvider {
|
|
|
36
36
|
mimeTypes: ["image/jpeg", "image/png", "image/gif", "image/webp"],
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
protected readonly onConfigure = $hook({
|
|
40
|
-
on: "configure",
|
|
41
|
-
handler: () => {
|
|
42
|
-
this.alepha.store.set("alepha.server.security.system.user", {
|
|
43
|
-
id: "00000000-0000-0000-0000-000000000000",
|
|
44
|
-
name: "system",
|
|
45
|
-
roles: ["admin"], // TODO: use realm config
|
|
46
|
-
});
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
|
|
50
39
|
public register(realmName: string, realmOptions: RealmOptions = {}) {
|
|
51
40
|
this.realms.set(realmName, {
|
|
52
41
|
name: realmName,
|
|
@@ -3,7 +3,6 @@ import { $inject, Alepha } from "alepha";
|
|
|
3
3
|
import { AuditService } from "alepha/api/audits";
|
|
4
4
|
import type { FileController } from "alepha/api/files";
|
|
5
5
|
import { DateTimeProvider } from "alepha/datetime";
|
|
6
|
-
import { FileSystemProvider } from "alepha/file";
|
|
7
6
|
import { $logger } from "alepha/logger";
|
|
8
7
|
import {
|
|
9
8
|
CryptoProvider,
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
import { type ServerRequest, UnauthorizedError } from "alepha/server";
|
|
14
13
|
import type { OAuth2Profile } from "alepha/server/auth";
|
|
15
14
|
import { $client } from "alepha/server/links";
|
|
15
|
+
import { FileSystemProvider } from "alepha/system";
|
|
16
16
|
import type { UserEntity } from "../entities/users.ts";
|
|
17
17
|
import { RealmProvider } from "../providers/RealmProvider.ts";
|
|
18
18
|
|
|
@@ -15,6 +15,7 @@ export class VerificationController {
|
|
|
15
15
|
path: `${this.url}/:type`,
|
|
16
16
|
group: this.group,
|
|
17
17
|
method: "POST",
|
|
18
|
+
secure: false,
|
|
18
19
|
schema: {
|
|
19
20
|
params: t.object({
|
|
20
21
|
type: verificationTypeEnumSchema,
|
|
@@ -36,6 +37,7 @@ export class VerificationController {
|
|
|
36
37
|
path: `${this.url}/:type/validate`,
|
|
37
38
|
group: this.group,
|
|
38
39
|
method: "POST",
|
|
40
|
+
secure: false,
|
|
39
41
|
schema: {
|
|
40
42
|
params: t.object({
|
|
41
43
|
type: verificationTypeEnumSchema,
|
|
@@ -18,11 +18,17 @@ export * from "./services/VerificationService.ts";
|
|
|
18
18
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* | type | quality | stability |
|
|
22
|
+
* |------|---------|-----------|
|
|
23
|
+
* | backend | standard | stable |
|
|
22
24
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
25
|
+
* Email and phone verification workflows.
|
|
26
|
+
*
|
|
27
|
+
* **Features:**
|
|
28
|
+
* - Verification token generation
|
|
29
|
+
* - Verification code sending
|
|
30
|
+
* - Verification completion tracking
|
|
31
|
+
* - Resend functionality
|
|
26
32
|
*
|
|
27
33
|
* @module alepha.api.verifications
|
|
28
34
|
*/
|
package/src/batch/index.ts
CHANGED
|
@@ -10,45 +10,18 @@ export * from "./providers/BatchProvider.ts";
|
|
|
10
10
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* | type | quality | stability |
|
|
14
|
+
* |------|---------|-----------|
|
|
15
|
+
* | backend | standard | stable |
|
|
15
16
|
*
|
|
16
|
-
*
|
|
17
|
-
* import { Alepha, $hook, run, t } from "alepha";
|
|
18
|
-
* import { $batch } from "alepha/batch";
|
|
17
|
+
* Batch accumulation and processing.
|
|
19
18
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* maxDuration: [5, "seconds"],
|
|
26
|
-
* handler: async (items) => {
|
|
27
|
-
* console.log(`[BATCH LOG] Processing ${items.length} events:`, items);
|
|
28
|
-
* },
|
|
29
|
-
* });
|
|
19
|
+
* **Features:**
|
|
20
|
+
* - Batch accumulator with handler
|
|
21
|
+
* - Configurable batch size
|
|
22
|
+
* - Time-based triggers
|
|
23
|
+
* - Status tracking
|
|
30
24
|
*
|
|
31
|
-
* // example of how to use it
|
|
32
|
-
* onReady = $hook({
|
|
33
|
-
* on: "ready",
|
|
34
|
-
* handler: async () => {
|
|
35
|
-
* // push() returns an ID immediately
|
|
36
|
-
* const id1 = await this.logBatch.push("Application started.");
|
|
37
|
-
* const id2 = await this.logBatch.push("User authenticated.");
|
|
38
|
-
*
|
|
39
|
-
* // optionally wait for processing to complete
|
|
40
|
-
* await this.logBatch.wait(id1);
|
|
41
|
-
*
|
|
42
|
-
* // or check the status
|
|
43
|
-
* const status = this.logBatch.status(id2);
|
|
44
|
-
* console.log(status?.status); // "pending" | "processing" | "completed" | "failed"
|
|
45
|
-
* },
|
|
46
|
-
* });
|
|
47
|
-
* }
|
|
48
|
-
* ```
|
|
49
|
-
*
|
|
50
|
-
* @see {@link $batch}
|
|
51
|
-
* @see {@link BatchProvider}
|
|
52
25
|
* @module alepha.batch
|
|
53
26
|
*/
|
|
54
27
|
export const AlephaBatch = $module({
|
|
@@ -159,14 +159,6 @@ export class BatchPrimitive<
|
|
|
159
159
|
await this.batchProvider.markReady(this.context);
|
|
160
160
|
},
|
|
161
161
|
});
|
|
162
|
-
|
|
163
|
-
protected readonly dispose = $hook({
|
|
164
|
-
on: "stop",
|
|
165
|
-
priority: "first",
|
|
166
|
-
handler: async () => {
|
|
167
|
-
await this.batchProvider.shutdown(this.context);
|
|
168
|
-
},
|
|
169
|
-
});
|
|
170
162
|
}
|
|
171
163
|
|
|
172
164
|
$batch[KIND] = BatchPrimitive;
|