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,306 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import { $inject, Alepha } from "alepha";
|
|
3
|
+
import { $cache } from "alepha/cache";
|
|
4
|
+
import { DateTimeProvider } from "alepha/datetime";
|
|
5
|
+
import { $logger } from "alepha/logger";
|
|
6
|
+
import { $repository, sql } from "alepha/orm";
|
|
7
|
+
import type { IssuerResolver, UserInfo } from "alepha/security";
|
|
8
|
+
import {
|
|
9
|
+
ForbiddenError,
|
|
10
|
+
NotFoundError,
|
|
11
|
+
type ServerRequest,
|
|
12
|
+
} from "alepha/server";
|
|
13
|
+
import { type ApiKeyEntity, apiKeyEntity } from "../entities/apiKeyEntity.ts";
|
|
14
|
+
|
|
15
|
+
export class ApiKeyService {
|
|
16
|
+
protected readonly alepha = $inject(Alepha);
|
|
17
|
+
protected readonly dateTimeProvider = $inject(DateTimeProvider);
|
|
18
|
+
protected readonly log = $logger();
|
|
19
|
+
protected readonly repo = $repository(apiKeyEntity);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Cache validated API keys for 15 minutes.
|
|
23
|
+
*/
|
|
24
|
+
protected readonly validationCache = $cache<ApiKeyEntity | null, [string]>({
|
|
25
|
+
name: "api-key-validation",
|
|
26
|
+
ttl: [15, "minutes"],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// -------------------------------------------------------------------------
|
|
30
|
+
// Resolver
|
|
31
|
+
// -------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create an issuer resolver for API key authentication.
|
|
35
|
+
* Lower priority means it runs before JWT resolver.
|
|
36
|
+
*
|
|
37
|
+
* @param options.priority - Priority of this resolver (default: 50, JWT is 100)
|
|
38
|
+
* @param options.prefix - API key prefix to match in Bearer header (default: "ak")
|
|
39
|
+
*/
|
|
40
|
+
public createResolver(
|
|
41
|
+
options: { priority?: number; prefix?: string } = {},
|
|
42
|
+
): IssuerResolver {
|
|
43
|
+
const { priority = 50, prefix = "ak" } = options;
|
|
44
|
+
const prefixPattern = `${prefix}_`;
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
priority,
|
|
48
|
+
onRequest: async (req: ServerRequest) => {
|
|
49
|
+
// Try query param first
|
|
50
|
+
const url = typeof req.url === "string" ? new URL(req.url) : req.url;
|
|
51
|
+
let token = url.searchParams.get("api_key");
|
|
52
|
+
|
|
53
|
+
// Try Bearer header - only if token starts with expected prefix
|
|
54
|
+
if (!token) {
|
|
55
|
+
const auth = req.headers.authorization;
|
|
56
|
+
if (auth?.startsWith("Bearer ")) {
|
|
57
|
+
const bearerToken = auth.slice(7);
|
|
58
|
+
if (bearerToken.startsWith(prefixPattern)) {
|
|
59
|
+
token = bearerToken;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!token) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return this.validate(token);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// -------------------------------------------------------------------------
|
|
74
|
+
// CRUD
|
|
75
|
+
// -------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Create a new API key for a user.
|
|
79
|
+
* Returns both the API key entity and the plain token (which is only available once).
|
|
80
|
+
*/
|
|
81
|
+
public async create(options: {
|
|
82
|
+
userId: string;
|
|
83
|
+
name: string;
|
|
84
|
+
roles: string[];
|
|
85
|
+
description?: string;
|
|
86
|
+
expiresAt?: Date;
|
|
87
|
+
prefix?: string;
|
|
88
|
+
}): Promise<{ apiKey: ApiKeyEntity; token: string }> {
|
|
89
|
+
const prefix = options.prefix ?? "ak";
|
|
90
|
+
const random = randomBytes(24).toString("base64url");
|
|
91
|
+
const token = `${prefix}_${random}`;
|
|
92
|
+
const hash = this.hashToken(token);
|
|
93
|
+
const suffix = token.slice(-8);
|
|
94
|
+
|
|
95
|
+
const apiKey = await this.repo.create({
|
|
96
|
+
userId: options.userId,
|
|
97
|
+
name: options.name,
|
|
98
|
+
description: options.description,
|
|
99
|
+
tokenHash: hash,
|
|
100
|
+
tokenPrefix: prefix,
|
|
101
|
+
tokenSuffix: suffix,
|
|
102
|
+
roles: options.roles,
|
|
103
|
+
expiresAt: options.expiresAt?.toISOString(),
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
this.log.info("API key created", {
|
|
107
|
+
apiKeyId: apiKey.id,
|
|
108
|
+
userId: options.userId,
|
|
109
|
+
name: options.name,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return { apiKey, token };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* List all non-revoked API keys for a user.
|
|
117
|
+
*/
|
|
118
|
+
public async list(userId: string): Promise<ApiKeyEntity[]> {
|
|
119
|
+
return this.repo.findMany({
|
|
120
|
+
where: {
|
|
121
|
+
userId: { eq: userId },
|
|
122
|
+
revokedAt: { isNull: true },
|
|
123
|
+
},
|
|
124
|
+
orderBy: { column: "createdAt", direction: "desc" },
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// -------------------------------------------------------------------------
|
|
129
|
+
// Admin Operations
|
|
130
|
+
// -------------------------------------------------------------------------
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Find all API keys with optional filtering (admin only).
|
|
134
|
+
*/
|
|
135
|
+
public async findAll(query: {
|
|
136
|
+
userId?: string;
|
|
137
|
+
includeRevoked?: boolean;
|
|
138
|
+
page?: number;
|
|
139
|
+
size?: number;
|
|
140
|
+
sort?: string;
|
|
141
|
+
}) {
|
|
142
|
+
query.sort ??= "-createdAt";
|
|
143
|
+
|
|
144
|
+
const where = this.repo.createQueryWhere();
|
|
145
|
+
|
|
146
|
+
if (query.userId) {
|
|
147
|
+
where.userId = { eq: query.userId };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!query.includeRevoked) {
|
|
151
|
+
where.revokedAt = { isNull: true };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return this.repo.paginate(query, { where }, { count: true });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Get an API key by ID (admin only).
|
|
159
|
+
*/
|
|
160
|
+
public async getById(id: string): Promise<ApiKeyEntity> {
|
|
161
|
+
const apiKey = await this.repo.findById(id).catch(() => null);
|
|
162
|
+
|
|
163
|
+
if (!apiKey) {
|
|
164
|
+
throw new NotFoundError("API key not found");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return apiKey;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Revoke any API key (admin only).
|
|
172
|
+
*/
|
|
173
|
+
public async revokeByAdmin(id: string): Promise<void> {
|
|
174
|
+
const apiKey = await this.repo.findById(id).catch(() => null);
|
|
175
|
+
|
|
176
|
+
if (!apiKey) {
|
|
177
|
+
throw new NotFoundError("API key not found");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (apiKey.revokedAt) {
|
|
181
|
+
return; // Already revoked
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Invalidate cache
|
|
185
|
+
await this.validationCache.invalidate(apiKey.tokenHash);
|
|
186
|
+
|
|
187
|
+
await this.repo.updateById(id, {
|
|
188
|
+
revokedAt: this.dateTimeProvider.now().toISOString(),
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
this.log.info("API key revoked by admin", {
|
|
192
|
+
apiKeyId: id,
|
|
193
|
+
userId: apiKey.userId,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// -------------------------------------------------------------------------
|
|
198
|
+
// User Operations
|
|
199
|
+
// -------------------------------------------------------------------------
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Revoke an API key. Only the owner can revoke their own keys.
|
|
203
|
+
*/
|
|
204
|
+
public async revoke(id: string, userId: string): Promise<void> {
|
|
205
|
+
const apiKey = await this.repo.findById(id).catch(() => null);
|
|
206
|
+
|
|
207
|
+
if (!apiKey) {
|
|
208
|
+
throw new NotFoundError("API key not found");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (apiKey.userId !== userId) {
|
|
212
|
+
throw new ForbiddenError("Not your API key");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
await this.validationCache.invalidate(apiKey.tokenHash);
|
|
216
|
+
|
|
217
|
+
await this.repo.updateById(id, {
|
|
218
|
+
revokedAt: this.dateTimeProvider.now().toISOString(),
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
this.log.info("API key revoked", {
|
|
222
|
+
apiKeyId: id,
|
|
223
|
+
userId,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// -------------------------------------------------------------------------
|
|
228
|
+
// Validation
|
|
229
|
+
// -------------------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Validate an API key token and return user info if valid.
|
|
233
|
+
*/
|
|
234
|
+
public async validate(token: string): Promise<UserInfo | null> {
|
|
235
|
+
// Quick check for API key format
|
|
236
|
+
if (!token.includes("_")) {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const hash = this.hashToken(token);
|
|
241
|
+
|
|
242
|
+
// Try cache first
|
|
243
|
+
let apiKey = await this.validationCache.get(hash);
|
|
244
|
+
|
|
245
|
+
// If not in cache, look up in database
|
|
246
|
+
if (apiKey === undefined) {
|
|
247
|
+
apiKey = await this.repo
|
|
248
|
+
.findOne({
|
|
249
|
+
where: { tokenHash: { eq: hash } },
|
|
250
|
+
})
|
|
251
|
+
.catch(() => null);
|
|
252
|
+
|
|
253
|
+
// Store in cache (even if null, to prevent repeated lookups)
|
|
254
|
+
if (apiKey) {
|
|
255
|
+
await this.validationCache.set(hash, apiKey);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (!apiKey) {
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Check revocation
|
|
264
|
+
if (apiKey.revokedAt) {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Check expiration
|
|
269
|
+
if (
|
|
270
|
+
apiKey.expiresAt &&
|
|
271
|
+
this.dateTimeProvider.now().isAfter(apiKey.expiresAt)
|
|
272
|
+
) {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Update usage stats (fire and forget)
|
|
277
|
+
this.updateUsage(apiKey.id).catch((error) => {
|
|
278
|
+
this.log.warn("Failed to update API key usage", { error });
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
id: apiKey.userId,
|
|
283
|
+
roles: apiKey.roles,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Update usage statistics for an API key.
|
|
289
|
+
*/
|
|
290
|
+
protected async updateUsage(id: string): Promise<void> {
|
|
291
|
+
const request = this.alepha.context.get<ServerRequest>("request");
|
|
292
|
+
|
|
293
|
+
await this.repo.updateById(id, {
|
|
294
|
+
lastUsedAt: this.dateTimeProvider.now().toISOString(),
|
|
295
|
+
lastUsedIp: request?.ip,
|
|
296
|
+
usageCount: sql`${this.repo.table.usageCount} + 1`,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Hash a token using SHA-256.
|
|
302
|
+
*/
|
|
303
|
+
protected hashToken(token: string): string {
|
|
304
|
+
return createHash("sha256").update(token).digest("hex");
|
|
305
|
+
}
|
|
306
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
|
|
2
|
+
# Alepha Logs
|
|
3
|
+
|
|
4
|
+
3 modules across different locations:
|
|
5
|
+
|
|
6
|
+
## `alepha/api/logs` - AlephaApiLogs (Server)
|
|
7
|
+
|
|
8
|
+
Module for handling logs collected from various sources.
|
|
9
|
+
|
|
10
|
+
- 1-2 days retention policy for logs (configurable)
|
|
11
|
+
- Independent SQLite storage for logs with querying capabilities
|
|
12
|
+
- Output can be sent to Postgres (TimescaleDB) if big data storage is needed
|
|
13
|
+
|
|
14
|
+
## `alepha/api/logs-client` - AlephaApiLogsClient (Client)
|
|
15
|
+
|
|
16
|
+
Client module for interacting with AlephaApiLogs automatically.
|
|
17
|
+
|
|
18
|
+
- Uses Alepha micro-services features to collect logs from different services
|
|
19
|
+
- Keyless Codec, Batching, ...
|
|
20
|
+
|
|
21
|
+
## `@alepha/ui/logs` - AlephaUiLogs (UI)
|
|
22
|
+
|
|
23
|
+
UI components for displaying and managing logs within the Alepha framework.
|
|
24
|
+
|
|
25
|
+
- Devtools UI for log visualization and querying
|
|
26
|
+
|
|
27
|
+
--- CLIENT ----
|
|
28
|
+
|
|
29
|
+
class LogCollectorClient {
|
|
30
|
+
collector = $remote({
|
|
31
|
+
url: "http://localhost:5000/",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
client = $client<LogController>();
|
|
35
|
+
|
|
36
|
+
batchLog = $batch({
|
|
37
|
+
maxDuration: [10, "seconds"],
|
|
38
|
+
maxItems: 50,
|
|
39
|
+
handler: (logs: Logs[]) => {
|
|
40
|
+
return this.client.collect({ body: logs });
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
onLog = $hook({
|
|
45
|
+
on: "log",
|
|
46
|
+
handler: (log) => {
|
|
47
|
+
if (log.level === "trace") return;
|
|
48
|
+
return this.batchLog.push(log);
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const $collector = (opts: {url}) => $context().alepha.with(LogCollectorClient).set(logCollectorOptions, {url})
|
|
54
|
+
|
|
55
|
+
---- SERVER ----
|
|
@@ -25,12 +25,18 @@ export * from "./services/NotificationService.ts";
|
|
|
25
25
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* | type | quality | stability |
|
|
29
|
+
* |------|---------|-----------|
|
|
30
|
+
* | backend | standard | stable |
|
|
29
31
|
*
|
|
30
|
-
*
|
|
31
|
-
* and user notification preferences management.
|
|
32
|
+
* User notification management.
|
|
32
33
|
*
|
|
33
|
-
*
|
|
34
|
+
* **Features:**
|
|
35
|
+
* - Notification definitions
|
|
36
|
+
* - Email/SMS notification sending
|
|
37
|
+
* - Status tracking
|
|
38
|
+
* - User preferences
|
|
39
|
+
* - Queue integration
|
|
34
40
|
*
|
|
35
41
|
* @module alepha.api.notifications
|
|
36
42
|
*/
|
|
@@ -19,38 +19,17 @@ export * from "./services/ConfigStore.ts";
|
|
|
19
19
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* | type | quality | stability |
|
|
23
|
+
* |------|---------|-----------|
|
|
24
|
+
* | backend | standard | stable |
|
|
23
25
|
*
|
|
24
|
-
*
|
|
25
|
-
* - Type-safe, versioned configuration with `$config` primitive
|
|
26
|
-
* - Schema validation with auto-migration detection
|
|
27
|
-
* - Scheduled activation (FUTURE, NEXT, CURRENT, EXPIRED statuses)
|
|
28
|
-
* - PostgreSQL persistence with full version history
|
|
29
|
-
* - Cross-instance synchronization via topic
|
|
30
|
-
* - Tree view support via dot-notation naming
|
|
31
|
-
* - REST API for configuration management
|
|
32
|
-
* - Automatic activation scheduler
|
|
26
|
+
* Application configuration management.
|
|
33
27
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* const alepha = Alepha.create();
|
|
40
|
-
* alepha.with(AlephaApiParameters);
|
|
41
|
-
*
|
|
42
|
-
* // Then use $config in your services:
|
|
43
|
-
* class AppConfig {
|
|
44
|
-
* features = $config({
|
|
45
|
-
* name: "app.features.flags",
|
|
46
|
-
* schema: t.object({
|
|
47
|
-
* enableBeta: t.boolean(),
|
|
48
|
-
* maxUploadSize: t.number()
|
|
49
|
-
* }),
|
|
50
|
-
* default: { enableBeta: false, maxUploadSize: 10485760 }
|
|
51
|
-
* });
|
|
52
|
-
* }
|
|
53
|
-
* ```
|
|
28
|
+
* **Features:**
|
|
29
|
+
* - Versioned configuration definitions
|
|
30
|
+
* - Scheduled activation (FUTURE, NEXT, CURRENT, EXPIRED)
|
|
31
|
+
* - Schema validation with migration detection
|
|
32
|
+
* - Cross-instance sync via pub/sub
|
|
54
33
|
*
|
|
55
34
|
* @module alepha.api.parameters
|
|
56
35
|
*/
|
|
@@ -84,16 +84,24 @@ export class ConfigPrimitive<T extends TObject> extends Primitive<
|
|
|
84
84
|
protected readonly log = $logger();
|
|
85
85
|
protected readonly store = $inject(ConfigStore);
|
|
86
86
|
|
|
87
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Internal atom key for state management.
|
|
89
|
+
*/
|
|
88
90
|
protected atomKey!: string;
|
|
89
91
|
|
|
90
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* Schema hash for migration detection.
|
|
94
|
+
*/
|
|
91
95
|
protected schemaHash!: string;
|
|
92
96
|
|
|
93
|
-
/**
|
|
97
|
+
/**
|
|
98
|
+
* Whether we're currently syncing (to avoid loops).
|
|
99
|
+
*/
|
|
94
100
|
protected syncing = false;
|
|
95
101
|
|
|
96
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* Whether initial load has completed.
|
|
104
|
+
*/
|
|
97
105
|
protected loaded = false;
|
|
98
106
|
|
|
99
107
|
/**
|
|
@@ -36,13 +36,19 @@ export class ConfigStore {
|
|
|
36
36
|
protected readonly dateTimeProvider = $inject(DateTimeProvider);
|
|
37
37
|
protected readonly repo = $repository(parameters);
|
|
38
38
|
|
|
39
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Unique identifier for this instance (to avoid self-updates).
|
|
41
|
+
*/
|
|
40
42
|
protected readonly instanceId = crypto.randomUUID();
|
|
41
43
|
|
|
42
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* In-memory cache of registered configs.
|
|
46
|
+
*/
|
|
43
47
|
protected readonly configs = new Map<string, ConfigPrimitive<any>>();
|
|
44
48
|
|
|
45
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* Topic for cross-instance synchronization.
|
|
51
|
+
*/
|
|
46
52
|
public readonly syncTopic = $topic({
|
|
47
53
|
name: "config:sync",
|
|
48
54
|
schema: {
|