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,334 @@
|
|
|
1
|
+
import { $inject, Alepha, type Static } from "alepha";
|
|
2
|
+
import {
|
|
3
|
+
type SsrManifestAtomSchema,
|
|
4
|
+
ssrManifestAtom,
|
|
5
|
+
} from "../atoms/ssrManifestAtom.ts";
|
|
6
|
+
import { PAGE_PRELOAD_KEY } from "../constants/PAGE_PRELOAD_KEY.ts";
|
|
7
|
+
import type { PageRoute } from "./ReactPageProvider.ts";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Provider for SSR manifest data used for module preloading.
|
|
11
|
+
*
|
|
12
|
+
* The manifest is populated at build time by embedding data into the
|
|
13
|
+
* generated index.js via the ssrManifestAtom. This eliminates filesystem
|
|
14
|
+
* reads at runtime, making it optimal for serverless deployments.
|
|
15
|
+
*
|
|
16
|
+
* Manifest files are generated during `vite build`:
|
|
17
|
+
* - manifest.json (client manifest)
|
|
18
|
+
* - preload-manifest.json (from viteAlephaSsrPreload plugin)
|
|
19
|
+
*/
|
|
20
|
+
export class SSRManifestProvider {
|
|
21
|
+
protected readonly alepha = $inject(Alepha);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get the manifest from the store at runtime.
|
|
25
|
+
* This ensures the manifest is available even when set after module load.
|
|
26
|
+
*/
|
|
27
|
+
protected get manifest(): Static<SsrManifestAtomSchema> {
|
|
28
|
+
return (
|
|
29
|
+
(this.alepha.store.get(
|
|
30
|
+
ssrManifestAtom,
|
|
31
|
+
) as Static<SsrManifestAtomSchema>) ?? {}
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get the base path for assets (from Vite's base config).
|
|
37
|
+
* Returns empty string if base is "/" (default), otherwise returns the base path.
|
|
38
|
+
*/
|
|
39
|
+
protected get base(): string {
|
|
40
|
+
return this.manifest.base ?? "";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get the preload manifest.
|
|
45
|
+
*/
|
|
46
|
+
protected get preloadManifest(): PreloadManifest | undefined {
|
|
47
|
+
return this.manifest.preload;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get the client manifest.
|
|
52
|
+
*/
|
|
53
|
+
protected get clientManifest(): ClientManifest | undefined {
|
|
54
|
+
return this.manifest.client;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Resolve a preload key to its source path.
|
|
59
|
+
*
|
|
60
|
+
* The key is a short hash injected by viteAlephaSsrPreload plugin,
|
|
61
|
+
* which maps to the full source path in the preload manifest.
|
|
62
|
+
*
|
|
63
|
+
* @param key - Short hash key (e.g., "a1b2c3d4")
|
|
64
|
+
* @returns Source path (e.g., "src/pages/UserDetail.tsx") or undefined
|
|
65
|
+
*/
|
|
66
|
+
public resolvePreloadKey(key: string): string | undefined {
|
|
67
|
+
return this.preloadManifest?.[key];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get all chunks required for a source file, including transitive dependencies.
|
|
72
|
+
*
|
|
73
|
+
* Uses the client manifest to recursively resolve all imported chunks.
|
|
74
|
+
*
|
|
75
|
+
* @param sourcePath - Source file path (e.g., "src/pages/Home.tsx")
|
|
76
|
+
* @returns Array of chunk URLs to preload, or empty array if not found
|
|
77
|
+
*/
|
|
78
|
+
public getChunks(sourcePath: string): string[] {
|
|
79
|
+
if (!this.clientManifest) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Find entry in client manifest
|
|
84
|
+
const entry = this.findManifestEntry(sourcePath);
|
|
85
|
+
if (!entry) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Recursively collect all chunks
|
|
90
|
+
const chunks = new Set<string>();
|
|
91
|
+
const visited = new Set<string>();
|
|
92
|
+
|
|
93
|
+
this.collectChunksRecursive(sourcePath, chunks, visited);
|
|
94
|
+
|
|
95
|
+
return Array.from(chunks);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Find manifest entry for a source path, trying different extensions.
|
|
100
|
+
*/
|
|
101
|
+
protected findManifestEntry(sourcePath: string) {
|
|
102
|
+
if (!this.clientManifest) return undefined;
|
|
103
|
+
|
|
104
|
+
// Try exact match
|
|
105
|
+
if (this.clientManifest[sourcePath]) {
|
|
106
|
+
return this.clientManifest[sourcePath];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Try with different extensions
|
|
110
|
+
const basePath = sourcePath.replace(/\.[^.]+$/, "");
|
|
111
|
+
for (const ext of [".tsx", ".ts", ".jsx", ".js"]) {
|
|
112
|
+
const pathWithExt = basePath + ext;
|
|
113
|
+
if (this.clientManifest[pathWithExt]) {
|
|
114
|
+
return this.clientManifest[pathWithExt];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Recursively collect all chunk URLs for a manifest entry.
|
|
123
|
+
*/
|
|
124
|
+
protected collectChunksRecursive(
|
|
125
|
+
key: string,
|
|
126
|
+
chunks: Set<string>,
|
|
127
|
+
visited: Set<string>,
|
|
128
|
+
): void {
|
|
129
|
+
if (visited.has(key)) return;
|
|
130
|
+
visited.add(key);
|
|
131
|
+
|
|
132
|
+
if (!this.clientManifest) return;
|
|
133
|
+
|
|
134
|
+
const entry = this.clientManifest[key];
|
|
135
|
+
if (!entry) return;
|
|
136
|
+
|
|
137
|
+
const base = this.base;
|
|
138
|
+
|
|
139
|
+
// Add main chunk file (with base path for URL)
|
|
140
|
+
if (entry.file) {
|
|
141
|
+
chunks.add(`${base}/${entry.file}`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Add CSS files
|
|
145
|
+
if (entry.css) {
|
|
146
|
+
for (const css of entry.css) {
|
|
147
|
+
chunks.add(`${base}/${css}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Recursively process imports (but skip entry point)
|
|
152
|
+
if (entry.imports) {
|
|
153
|
+
for (const imp of entry.imports) {
|
|
154
|
+
// Skip the main entry point (index.html) - it's already being loaded
|
|
155
|
+
if (imp === "index.html" || imp.endsWith(".html")) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
this.collectChunksRecursive(imp, chunks, visited);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Note: We intentionally do NOT follow dynamicImports
|
|
163
|
+
// Those are lazy-loaded and shouldn't be preloaded
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Collect modulepreload links for a route and its parent chain.
|
|
168
|
+
*/
|
|
169
|
+
public collectPreloadLinks(
|
|
170
|
+
route: PageRoute,
|
|
171
|
+
): Array<{ rel: string; href: string; as?: string; crossorigin?: string }> {
|
|
172
|
+
if (!this.isAvailable()) {
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const preloadPaths: string[] = [];
|
|
177
|
+
let current: PageRoute | undefined = route;
|
|
178
|
+
|
|
179
|
+
while (current) {
|
|
180
|
+
const preloadKey = current[PAGE_PRELOAD_KEY];
|
|
181
|
+
if (preloadKey) {
|
|
182
|
+
const sourcePath = this.resolvePreloadKey(preloadKey);
|
|
183
|
+
if (sourcePath) {
|
|
184
|
+
preloadPaths.push(sourcePath);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
current = current.parent;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (preloadPaths.length === 0) {
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const chunks = this.getChunksForMultiple(preloadPaths);
|
|
195
|
+
|
|
196
|
+
return chunks.map((href) => {
|
|
197
|
+
if (href.endsWith(".css")) {
|
|
198
|
+
return { rel: "preload", href, as: "style", crossorigin: "" };
|
|
199
|
+
}
|
|
200
|
+
return { rel: "modulepreload", href };
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get all chunks for multiple source files.
|
|
206
|
+
*
|
|
207
|
+
* @param sourcePaths - Array of source file paths
|
|
208
|
+
* @returns Deduplicated array of chunk URLs
|
|
209
|
+
*/
|
|
210
|
+
public getChunksForMultiple(sourcePaths: string[]): string[] {
|
|
211
|
+
const allChunks = new Set<string>();
|
|
212
|
+
|
|
213
|
+
for (const path of sourcePaths) {
|
|
214
|
+
const chunks = this.getChunks(path);
|
|
215
|
+
for (const chunk of chunks) {
|
|
216
|
+
allChunks.add(chunk);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return Array.from(allChunks);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Check if manifest is loaded and available.
|
|
225
|
+
*/
|
|
226
|
+
public isAvailable(): boolean {
|
|
227
|
+
return this.clientManifest !== undefined;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Cached entry assets - computed once at first access.
|
|
232
|
+
*/
|
|
233
|
+
protected cachedEntryAssets: EntryAssets | null = null;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Get the entry point assets (main entry.js and associated CSS files).
|
|
237
|
+
*
|
|
238
|
+
* These assets are always required for all pages and can be preloaded
|
|
239
|
+
* before page-specific loaders run.
|
|
240
|
+
*
|
|
241
|
+
* @returns Entry assets with js and css paths, or null if manifest unavailable
|
|
242
|
+
*/
|
|
243
|
+
public getEntryAssets(): EntryAssets | null {
|
|
244
|
+
if (this.cachedEntryAssets) {
|
|
245
|
+
return this.cachedEntryAssets;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (!this.clientManifest) {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const base = this.base;
|
|
253
|
+
|
|
254
|
+
// Find the entry point in the client manifest
|
|
255
|
+
for (const [key, entry] of Object.entries(this.clientManifest)) {
|
|
256
|
+
if (entry.isEntry) {
|
|
257
|
+
this.cachedEntryAssets = {
|
|
258
|
+
js: `${base}/${entry.file}`,
|
|
259
|
+
css: entry.css?.map((css) => `${base}/${css}`) ?? [],
|
|
260
|
+
};
|
|
261
|
+
return this.cachedEntryAssets;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Build preload link tags for entry assets.
|
|
270
|
+
*
|
|
271
|
+
* @returns Array of link objects ready to be rendered
|
|
272
|
+
*/
|
|
273
|
+
public getEntryPreloadLinks(): Array<{
|
|
274
|
+
rel: string;
|
|
275
|
+
href: string;
|
|
276
|
+
as?: string;
|
|
277
|
+
crossorigin?: string;
|
|
278
|
+
}> {
|
|
279
|
+
const assets = this.getEntryAssets();
|
|
280
|
+
if (!assets) {
|
|
281
|
+
return [];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const links: Array<{
|
|
285
|
+
rel: string;
|
|
286
|
+
href: string;
|
|
287
|
+
as?: string;
|
|
288
|
+
crossorigin?: string;
|
|
289
|
+
}> = [];
|
|
290
|
+
|
|
291
|
+
// Add CSS preloads first (critical for rendering)
|
|
292
|
+
for (const css of assets.css) {
|
|
293
|
+
links.push({ rel: "stylesheet", href: css, crossorigin: "" });
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Add entry JS modulepreload
|
|
297
|
+
if (assets.js) {
|
|
298
|
+
links.push({ rel: "modulepreload", href: assets.js });
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return links;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ---------------------------------------------------------------------------------------------------------------------
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Entry assets structure containing the main entry JS and associated CSS files.
|
|
309
|
+
*/
|
|
310
|
+
export interface EntryAssets {
|
|
311
|
+
/** Main entry JavaScript file (e.g., "/assets/entry.abc123.js") */
|
|
312
|
+
js?: string;
|
|
313
|
+
/** Associated CSS files (e.g., ["/assets/style.abc123.css"]) */
|
|
314
|
+
css: string[];
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Client manifest structure from Vite.
|
|
319
|
+
* Only includes fields actually used for preloading.
|
|
320
|
+
*/
|
|
321
|
+
export interface ClientManifest {
|
|
322
|
+
[key: string]: {
|
|
323
|
+
file: string;
|
|
324
|
+
isEntry?: boolean;
|
|
325
|
+
imports?: string[];
|
|
326
|
+
css?: string[];
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Preload manifest mapping short keys to source paths.
|
|
332
|
+
* Generated by viteAlephaSsrPreload plugin at build time.
|
|
333
|
+
*/
|
|
334
|
+
export type PreloadManifest = Record<string, string>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { $inject, AlephaError } from "alepha";
|
|
2
|
+
import { ServerProvider } from "alepha/server";
|
|
3
|
+
import type {
|
|
4
|
+
PagePrimitiveRenderOptions,
|
|
5
|
+
PagePrimitiveRenderResult,
|
|
6
|
+
} from "../primitives/$page.ts";
|
|
7
|
+
import { ReactServerProvider } from "../providers/ReactServerProvider.ts";
|
|
8
|
+
import { ReactServerTemplateProvider } from "../providers/ReactServerTemplateProvider.ts";
|
|
9
|
+
import { ReactPageService } from "./ReactPageService.ts";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* $page methods for server-side.
|
|
13
|
+
*/
|
|
14
|
+
export class ReactPageServerService extends ReactPageService {
|
|
15
|
+
protected readonly reactServerProvider = $inject(ReactServerProvider);
|
|
16
|
+
protected readonly templateProvider = $inject(ReactServerTemplateProvider);
|
|
17
|
+
protected readonly serverProvider = $inject(ServerProvider);
|
|
18
|
+
|
|
19
|
+
public async render(
|
|
20
|
+
name: string,
|
|
21
|
+
options: PagePrimitiveRenderOptions = {},
|
|
22
|
+
): Promise<PagePrimitiveRenderResult> {
|
|
23
|
+
return this.reactServerProvider.render(name, options);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public async fetch(
|
|
27
|
+
pathname: string,
|
|
28
|
+
options: PagePrimitiveRenderOptions = {},
|
|
29
|
+
): Promise<{
|
|
30
|
+
html: string;
|
|
31
|
+
response: Response;
|
|
32
|
+
}> {
|
|
33
|
+
const response = await fetch(`${this.serverProvider.hostname}/${pathname}`);
|
|
34
|
+
|
|
35
|
+
const html = await response.text();
|
|
36
|
+
if (options?.html) {
|
|
37
|
+
return { html, response };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// take only text inside the root div
|
|
41
|
+
const rootContent = this.templateProvider.extractRootContent(html);
|
|
42
|
+
if (rootContent !== undefined) {
|
|
43
|
+
return { html: rootContent, response };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
throw new AlephaError("Invalid HTML response");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AlephaError } from "alepha";
|
|
2
|
+
import type {
|
|
3
|
+
PagePrimitiveRenderOptions,
|
|
4
|
+
PagePrimitiveRenderResult,
|
|
5
|
+
} from "../../router/primitives/$page.ts";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* $page methods interface.
|
|
9
|
+
*/
|
|
10
|
+
export abstract class ReactPageService {
|
|
11
|
+
public fetch(
|
|
12
|
+
pathname: string,
|
|
13
|
+
options: PagePrimitiveRenderOptions = {},
|
|
14
|
+
): Promise<{
|
|
15
|
+
html: string;
|
|
16
|
+
response: Response;
|
|
17
|
+
}> {
|
|
18
|
+
throw new AlephaError("Fetch is not available for this environment.");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public render(
|
|
22
|
+
name: string,
|
|
23
|
+
options: PagePrimitiveRenderOptions = {},
|
|
24
|
+
): Promise<PagePrimitiveRenderResult> {
|
|
25
|
+
throw new AlephaError("Render is not available for this environment.");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { $inject, Alepha } from "alepha";
|
|
2
|
+
import type { PagePrimitive } from "../primitives/$page.ts";
|
|
3
|
+
import { ReactBrowserProvider } from "../providers/ReactBrowserProvider.ts";
|
|
4
|
+
import {
|
|
5
|
+
type AnchorProps,
|
|
6
|
+
ReactPageProvider,
|
|
7
|
+
type ReactRouterState,
|
|
8
|
+
} from "../providers/ReactPageProvider.ts";
|
|
9
|
+
|
|
10
|
+
export interface RouterPushOptions {
|
|
11
|
+
replace?: boolean;
|
|
12
|
+
params?: Record<string, string>;
|
|
13
|
+
query?: Record<string, string>;
|
|
14
|
+
meta?: Record<string, any>;
|
|
15
|
+
/**
|
|
16
|
+
* Recreate the whole page, ignoring the current state.
|
|
17
|
+
*/
|
|
18
|
+
force?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Friendly browser router API.
|
|
23
|
+
*
|
|
24
|
+
* Can be safely used server-side, but most methods will be no-op.
|
|
25
|
+
*/
|
|
26
|
+
export class ReactRouter<T extends object> {
|
|
27
|
+
protected readonly alepha = $inject(Alepha);
|
|
28
|
+
protected readonly pageApi = $inject(ReactPageProvider);
|
|
29
|
+
|
|
30
|
+
public get state(): ReactRouterState {
|
|
31
|
+
return this.alepha.store.get("alepha.react.router.state")!;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public get pages() {
|
|
35
|
+
return this.pageApi.getPages();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public get concretePages() {
|
|
39
|
+
return this.pageApi.getConcretePages();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public get browser(): ReactBrowserProvider | undefined {
|
|
43
|
+
if (this.alepha.isBrowser()) {
|
|
44
|
+
return this.alepha.inject(ReactBrowserProvider);
|
|
45
|
+
}
|
|
46
|
+
// server-side
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public isActive(
|
|
51
|
+
href: string,
|
|
52
|
+
options: {
|
|
53
|
+
startWith?: boolean;
|
|
54
|
+
} = {},
|
|
55
|
+
): boolean {
|
|
56
|
+
const current = this.state.url.pathname;
|
|
57
|
+
let isActive =
|
|
58
|
+
current === href || current === `${href}/` || `${current}/` === href;
|
|
59
|
+
|
|
60
|
+
if (options.startWith && !isActive) {
|
|
61
|
+
isActive = current.startsWith(href);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return isActive;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public node(
|
|
68
|
+
name: keyof VirtualRouter<T> | string,
|
|
69
|
+
config: {
|
|
70
|
+
params?: Record<string, any>;
|
|
71
|
+
query?: Record<string, any>;
|
|
72
|
+
} = {},
|
|
73
|
+
): any {
|
|
74
|
+
// TODO: improve typing (or just remove this method)
|
|
75
|
+
const page = this.pageApi.page(name as string);
|
|
76
|
+
if (!page.lazy && !page.component) {
|
|
77
|
+
return {
|
|
78
|
+
...page,
|
|
79
|
+
label: page.label ?? page.name,
|
|
80
|
+
children: undefined,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
...page,
|
|
86
|
+
label: page.label ?? page.name,
|
|
87
|
+
href: this.path(name, config),
|
|
88
|
+
children: undefined,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public path(
|
|
93
|
+
name: keyof VirtualRouter<T> | string,
|
|
94
|
+
config: {
|
|
95
|
+
params?: Record<string, any>;
|
|
96
|
+
query?: Record<string, any>;
|
|
97
|
+
} = {},
|
|
98
|
+
): string {
|
|
99
|
+
return this.pageApi.pathname(name as string, {
|
|
100
|
+
params: {
|
|
101
|
+
...this.state?.params,
|
|
102
|
+
...config.params,
|
|
103
|
+
},
|
|
104
|
+
query: config.query,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Reload the current page.
|
|
110
|
+
* This is equivalent to calling `go()` with the current pathname and search.
|
|
111
|
+
*/
|
|
112
|
+
public async reload() {
|
|
113
|
+
if (!this.browser) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
await this.push(this.location.pathname + this.location.search, {
|
|
118
|
+
replace: true,
|
|
119
|
+
force: true,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public getURL(): URL {
|
|
124
|
+
if (!this.browser) {
|
|
125
|
+
return this.state.url;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return new URL(this.location.href);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public get location(): Location {
|
|
132
|
+
if (!this.browser) {
|
|
133
|
+
throw new Error("Browser is required");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return this.browser.location;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
public get current(): ReactRouterState {
|
|
140
|
+
return this.state;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public get pathname(): string {
|
|
144
|
+
return this.state.url.pathname;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public get query(): Record<string, string> {
|
|
148
|
+
const query: Record<string, string> = {};
|
|
149
|
+
|
|
150
|
+
for (const [key, value] of new URLSearchParams(
|
|
151
|
+
this.state.url.search,
|
|
152
|
+
).entries()) {
|
|
153
|
+
query[key] = String(value);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return query;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public async back() {
|
|
160
|
+
this.browser?.history.back();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
public async forward() {
|
|
164
|
+
this.browser?.history.forward();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public async invalidate(props?: Record<string, any>) {
|
|
168
|
+
await this.browser?.invalidate(props);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public async push(path: string, options?: RouterPushOptions): Promise<void>;
|
|
172
|
+
public async push(
|
|
173
|
+
path: keyof VirtualRouter<T>,
|
|
174
|
+
options?: RouterPushOptions,
|
|
175
|
+
): Promise<void>;
|
|
176
|
+
public async push(
|
|
177
|
+
path: string | keyof VirtualRouter<T>,
|
|
178
|
+
options?: RouterPushOptions,
|
|
179
|
+
): Promise<void> {
|
|
180
|
+
for (const page of this.pages) {
|
|
181
|
+
if (page.name === path) {
|
|
182
|
+
await this.browser?.push(
|
|
183
|
+
this.path(path as keyof VirtualRouter<T>, options),
|
|
184
|
+
options,
|
|
185
|
+
);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
await this.browser?.push(path as string, options);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
public anchor(path: string, options?: RouterPushOptions): AnchorProps;
|
|
194
|
+
public anchor(
|
|
195
|
+
path: keyof VirtualRouter<T>,
|
|
196
|
+
options?: RouterPushOptions,
|
|
197
|
+
): AnchorProps;
|
|
198
|
+
public anchor(
|
|
199
|
+
path: string | keyof VirtualRouter<T>,
|
|
200
|
+
options: RouterPushOptions = {},
|
|
201
|
+
): AnchorProps {
|
|
202
|
+
let href = path as string;
|
|
203
|
+
|
|
204
|
+
for (const page of this.pages) {
|
|
205
|
+
if (page.name === path) {
|
|
206
|
+
href = this.path(path as keyof VirtualRouter<T>, options);
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
href: this.base(href),
|
|
213
|
+
onClick: (ev: any) => {
|
|
214
|
+
ev.stopPropagation();
|
|
215
|
+
ev.preventDefault();
|
|
216
|
+
|
|
217
|
+
this.push(href, options).catch(console.error);
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
public base(path: string): string {
|
|
223
|
+
const base = import.meta.env?.BASE_URL;
|
|
224
|
+
if (!base || base === "/") {
|
|
225
|
+
return path;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return base + path;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Set query params.
|
|
233
|
+
*
|
|
234
|
+
* @param record
|
|
235
|
+
* @param options
|
|
236
|
+
*/
|
|
237
|
+
public setQueryParams(
|
|
238
|
+
record:
|
|
239
|
+
| Record<string, any>
|
|
240
|
+
| ((queryParams: Record<string, any>) => Record<string, any>),
|
|
241
|
+
options: {
|
|
242
|
+
/**
|
|
243
|
+
* If true, this will add a new entry to the history stack.
|
|
244
|
+
*/
|
|
245
|
+
push?: boolean;
|
|
246
|
+
} = {},
|
|
247
|
+
) {
|
|
248
|
+
const func = typeof record === "function" ? record : () => record;
|
|
249
|
+
const search = new URLSearchParams(func(this.query)).toString();
|
|
250
|
+
const state = search ? `${this.pathname}?${search}` : this.pathname;
|
|
251
|
+
|
|
252
|
+
if (options.push) {
|
|
253
|
+
window.history.pushState({}, "", state);
|
|
254
|
+
} else {
|
|
255
|
+
window.history.replaceState({}, "", state);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export type VirtualRouter<T> = {
|
|
261
|
+
[K in keyof T as T[K] extends PagePrimitive ? K : never]: T[K];
|
|
262
|
+
};
|