alepha 0.19.1 → 0.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +6 -9
- package/dist/api/audits/index.d.ts +378 -346
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/files/index.d.ts +216 -184
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/jobs/index.d.ts +528 -496
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +3 -3
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.d.ts +207 -207
- package/dist/api/keys/index.d.ts.map +1 -1
- package/dist/api/notifications/index.d.ts +152 -152
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/organizations/index.browser.js +48 -0
- package/dist/api/organizations/index.browser.js.map +1 -0
- package/dist/api/organizations/index.d.ts +516 -0
- package/dist/api/organizations/index.d.ts.map +1 -0
- package/dist/api/organizations/index.js +202 -0
- package/dist/api/organizations/index.js.map +1 -0
- package/dist/api/parameters/index.d.ts +391 -358
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +5 -1
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/users/index.browser.js +7 -5
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +978 -913
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +160 -112
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +135 -135
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +2 -2
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/batch/index.d.ts +6 -6
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/billing/index.d.ts +1048 -0
- package/dist/billing/index.d.ts.map +1 -0
- package/dist/billing/index.js +713 -0
- package/dist/billing/index.js.map +1 -0
- package/dist/bin/index.js +0 -2
- package/dist/bin/index.js.map +1 -1
- package/dist/bucket/index.d.ts +10 -10
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/bucket/index.js +2 -2
- package/dist/bucket/index.js.map +1 -1
- package/dist/cache/core/index.d.ts +9 -9
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/core/index.js +2 -2
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cache/core/index.workerd.js +2 -2
- package/dist/cache/core/index.workerd.js.map +1 -1
- package/dist/cache/redis/index.d.ts +6 -6
- package/dist/cache/redis/index.d.ts.map +1 -1
- package/dist/cache/redis/index.js +2 -2
- package/dist/cache/redis/index.js.map +1 -1
- package/dist/cli/config/index.d.ts +12 -2
- package/dist/cli/config/index.d.ts.map +1 -1
- package/dist/cli/config/index.js +4 -0
- package/dist/cli/config/index.js.map +1 -1
- package/dist/cli/core/index.d.ts +183 -140
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +279 -89
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/devtools/index.d.ts +45 -0
- package/dist/cli/devtools/index.d.ts.map +1 -0
- package/dist/cli/devtools/index.js +170 -0
- package/dist/cli/devtools/index.js.map +1 -0
- package/dist/cli/platform/index.d.ts +383 -492
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +42 -511
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/cli/vendor/index.d.ts +196 -0
- package/dist/cli/vendor/index.d.ts.map +1 -0
- package/dist/cli/vendor/index.js +384 -0
- package/dist/cli/vendor/index.js.map +1 -0
- package/dist/command/index.d.ts +18 -18
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +2 -2
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +4 -4
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +10 -10
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -4
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +4 -4
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +4 -4
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/crypto/index.d.ts +7 -7
- package/dist/crypto/index.d.ts.map +1 -1
- package/dist/datetime/index.d.ts +4 -4
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/email/brevo/index.d.ts +4 -4
- package/dist/email/brevo/index.d.ts.map +1 -1
- package/dist/email/core/index.d.ts +15 -11
- package/dist/email/core/index.d.ts.map +1 -1
- package/dist/email/core/index.js +12 -35
- package/dist/email/core/index.js.map +1 -1
- package/dist/email/smtp/index.d.ts +12 -12
- package/dist/email/smtp/index.d.ts.map +1 -1
- package/dist/email/smtp/index.js +7 -4
- package/dist/email/smtp/index.js.map +1 -1
- package/dist/fake/index.d.ts +4 -8
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js +55 -889
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +13 -13
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/core/index.js +2 -2
- package/dist/lock/core/index.js.map +1 -1
- package/dist/lock/redis/index.d.ts +4 -4
- package/dist/lock/redis/index.d.ts.map +1 -1
- package/dist/logger/index.d.ts +16 -15
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +5 -2
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +11 -11
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +2 -2
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/core/index.browser.js +11 -1
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +53 -16
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +95 -51
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +55 -14
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.d.ts +18 -17
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/queue/core/index.d.ts +14 -14
- package/dist/queue/core/index.d.ts.map +1 -1
- package/dist/queue/core/index.js +2 -2
- package/dist/queue/core/index.js.map +1 -1
- package/dist/queue/core/index.workerd.js +2 -2
- package/dist/queue/core/index.workerd.js.map +1 -1
- package/dist/queue/redis/index.d.ts +4 -4
- package/dist/queue/redis/index.d.ts.map +1 -1
- package/dist/queue/redis/index.js +2 -2
- package/dist/queue/redis/index.js.map +1 -1
- package/dist/react/auth/index.d.ts +9 -9
- package/dist/react/auth/index.d.ts.map +1 -1
- package/dist/react/core/index.d.ts +6 -6
- package/dist/react/core/index.d.ts.map +1 -1
- package/dist/react/core/index.js +5 -4
- package/dist/react/core/index.js.map +1 -1
- package/dist/react/form/index.d.ts +4 -4
- package/dist/react/form/index.d.ts.map +1 -1
- package/dist/react/head/index.d.ts +4 -4
- package/dist/react/head/index.d.ts.map +1 -1
- package/dist/react/i18n/index.d.ts +9 -9
- package/dist/react/i18n/index.d.ts.map +1 -1
- package/dist/react/intro/index.d.ts +2 -2
- package/dist/react/intro/index.d.ts.map +1 -1
- package/dist/react/intro/index.js +1 -1
- package/dist/react/intro/index.js.map +1 -1
- package/dist/react/router/index.browser.js +4 -5
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +215 -215
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +6 -7
- package/dist/react/router/index.js.map +1 -1
- package/dist/react/testing/index.d.ts +2 -2
- package/dist/react/testing/index.d.ts.map +1 -1
- package/dist/react/testing/index.js +2 -4
- package/dist/react/testing/index.js.map +1 -1
- package/dist/redis/index.d.ts +19 -19
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/retry/index.d.ts +4 -4
- package/dist/retry/index.d.ts.map +1 -1
- package/dist/scheduler/index.d.ts +13 -13
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +2 -2
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/index.workerd.js +2 -2
- package/dist/scheduler/index.workerd.js.map +1 -1
- package/dist/security/index.browser.js +1 -1
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts +47 -47
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +9 -12
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +170 -169
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +16 -2
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cookies/index.d.ts +7 -7
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/core/index.d.ts +76 -76
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +23 -17
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +13 -13
- package/dist/server/cors/index.d.ts.map +1 -1
- package/dist/server/cors/index.js +2 -2
- package/dist/server/cors/index.js.map +1 -1
- package/dist/server/etag/index.d.ts +9 -9
- package/dist/server/etag/index.d.ts.map +1 -1
- package/dist/server/health/index.d.ts +20 -20
- package/dist/server/health/index.d.ts.map +1 -1
- package/dist/server/links/index.browser.js +2 -2
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +66 -66
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +4 -4
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +7 -7
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/proxy/index.d.ts +5 -5
- package/dist/server/proxy/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.d.ts +12 -12
- package/dist/server/rate-limit/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.js +2 -2
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/static/index.d.ts +5 -5
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/swagger/index.d.ts +7 -7
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +2 -2
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +11 -7
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js +9 -15
- package/dist/sms/index.js.map +1 -1
- package/dist/system/index.d.ts +4 -4
- package/dist/system/index.d.ts.map +1 -1
- package/dist/topic/core/index.d.ts +6 -6
- package/dist/topic/core/index.d.ts.map +1 -1
- package/dist/topic/redis/index.d.ts +7 -7
- package/dist/topic/redis/index.d.ts.map +1 -1
- package/dist/topic/redis/index.js +2 -2
- package/dist/topic/redis/index.js.map +1 -1
- package/dist/websocket/index.d.ts +36 -36
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +2 -2
- package/dist/websocket/index.js.map +1 -1
- package/package.json +36 -14
- package/src/api/jobs/{services → __tests__}/JobService.spec.ts +1 -1
- package/src/api/jobs/providers/JobProvider.ts +3 -3
- package/src/api/keys/{services → __tests__}/ApiKeyService.spec.ts +1 -1
- package/src/api/organizations/__tests__/OrganizationService.spec.ts +193 -0
- package/src/api/organizations/controllers/AdminOrganizationController.ts +103 -0
- package/src/api/organizations/entities/organizations.ts +20 -0
- package/src/api/organizations/index.browser.ts +10 -0
- package/src/api/organizations/index.ts +31 -0
- package/src/api/organizations/schemas/createOrganizationSchema.ts +10 -0
- package/src/api/organizations/schemas/organizationQuerySchema.ts +10 -0
- package/src/api/organizations/schemas/organizationResourceSchema.ts +6 -0
- package/src/api/organizations/schemas/updateOrganizationSchema.ts +7 -0
- package/src/api/organizations/services/OrganizationService.ts +75 -0
- package/src/api/parameters/services/ParameterProvider.ts +6 -1
- package/src/api/users/{services → __tests__}/SessionService.spec.ts +67 -0
- package/src/api/users/{jobs → __tests__}/UserJobs.spec.ts +1 -1
- package/src/api/users/entities/users.ts +9 -3
- package/src/api/users/index.ts +23 -4
- package/src/api/users/primitives/$realm.ts +6 -4
- package/src/api/users/providers/RealmProvider.ts +1 -1
- package/src/api/users/services/RegistrationService.ts +1 -1
- package/src/api/users/services/SessionService.ts +92 -5
- package/src/api/users/services/UserService.ts +1 -1
- package/src/api/verifications/{jobs → __tests__}/VerificationJobs.spec.ts +4 -2
- package/src/api/verifications/parameters/VerificationParameters.ts +2 -2
- package/src/billing/__tests__/BillingService.spec.ts +136 -0
- package/src/billing/__tests__/PaymentMethodService.spec.ts +78 -0
- package/src/billing/controllers/AdminBillingController.ts +149 -0
- package/src/billing/controllers/BillingController.ts +108 -0
- package/src/billing/entities/paymentIntents.ts +34 -0
- package/src/billing/entities/paymentMethods.ts +24 -0
- package/src/billing/entities/refunds.ts +22 -0
- package/src/billing/errors/BillingError.ts +5 -0
- package/src/billing/index.ts +76 -0
- package/src/billing/providers/BillingProvider.ts +79 -0
- package/src/billing/providers/MemoryBillingProvider.ts +139 -0
- package/src/billing/schemas/intentSchemas.ts +60 -0
- package/src/billing/schemas/paymentMethodSchemas.ts +13 -0
- package/src/billing/schemas/refundSchemas.ts +6 -0
- package/src/billing/services/BillingService.ts +325 -0
- package/src/billing/services/PaymentMethodService.ts +82 -0
- package/src/bin/index.ts +0 -2
- package/src/bucket/providers/LocalFileStorageProvider.ts +2 -2
- package/src/cache/core/{primitives → __tests__}/$cache.middleware.spec.ts +1 -1
- package/src/cache/core/{providers → __tests__}/MemoryCacheProvider.spec.ts +1 -1
- package/src/cache/core/primitives/$cache.ts +2 -2
- package/src/cache/redis/providers/RedisCacheProvider.ts +2 -2
- package/src/cli/config/defineConfig.ts +20 -0
- package/src/cli/core/{services → __tests__}/ProjectScaffolder.spec.ts +1 -1
- package/src/cli/core/{commands/gen → __tests__}/changelog.spec.ts +1 -1
- package/src/cli/core/{commands → __tests__}/init.spec.ts +2 -8
- package/src/cli/core/atoms/devOptions.ts +0 -5
- package/src/cli/core/commands/build.ts +2 -2
- package/src/cli/core/commands/dev.ts +165 -30
- package/src/cli/core/commands/gen/changelog.ts +2 -2
- package/src/cli/core/commands/init.ts +2 -7
- package/src/cli/core/commands/verify.ts +0 -1
- package/src/cli/core/providers/AppEntryProvider.ts +2 -2
- package/src/cli/core/providers/ViteDevServerProvider.ts +54 -66
- package/src/cli/core/services/PackageManagerUtils.ts +8 -3
- package/src/cli/core/services/ProjectScaffolder.ts +18 -18
- package/src/cli/core/tasks/BuildClientTask.ts +8 -0
- package/src/cli/core/tasks/BuildServerTask.ts +17 -4
- package/src/cli/core/templates/alephaConfigTs.ts +0 -6
- package/src/cli/core/templates/webAdminDashboardTsx.ts +17 -0
- package/src/cli/core/templates/webAppRouterTs.ts +85 -2
- package/src/cli/devtools/atoms/devtoolsOptions.ts +26 -0
- package/src/cli/devtools/index.ts +194 -0
- package/src/cli/platform/{adapters → __tests__}/CloudflareAdapter.spec.ts +2 -2
- package/src/cli/platform/{providers → __tests__}/GitHubSecretStore.spec.ts +1 -1
- package/src/cli/platform/{services → __tests__}/NamingService.spec.ts +1 -1
- package/src/cli/platform/{providers → __tests__}/PlatformCacheProvider.spec.ts +1 -1
- package/src/cli/platform/{services → __tests__}/PlatformInspector.spec.ts +1 -1
- package/src/cli/platform/{services → __tests__}/PlatformOrchestrator.spec.ts +3 -3
- package/src/cli/platform/{services → __tests__}/SecretFilterService.spec.ts +1 -1
- package/src/cli/platform/{commands → __tests__}/SecretsCommand.spec.ts +1 -1
- package/src/cli/platform/{adapters → __tests__}/VercelAdapter.spec.ts +2 -2
- package/src/cli/platform/atoms/platformOptions.ts +2 -10
- package/src/cli/platform/commands/SecretsCommand.ts +2 -2
- package/src/cli/platform/commands/platform.ts +2 -11
- package/src/cli/platform/index.ts +34 -11
- package/src/cli/platform/services/PlatformInspector.ts +2 -2
- package/src/cli/platform/services/PlatformOrchestrator.ts +0 -9
- package/src/cli/vendor/__tests__/VendorService.spec.ts +407 -0
- package/src/cli/vendor/atoms/vendorOptions.ts +41 -0
- package/src/cli/vendor/commands/VendorCommand.ts +204 -0
- package/src/cli/vendor/index.ts +43 -0
- package/src/cli/vendor/services/VendorService.ts +338 -0
- package/src/command/{providers → __tests__}/CliProvider.spec.ts +1 -1
- package/src/command/{helpers → __tests__}/EnvUtils.spec.ts +1 -1
- package/src/command/providers/CliProvider.ts +2 -2
- package/src/core/{primitives → __tests__}/$atom.spec.ts +2 -2
- package/src/core/{primitives → __tests__}/$memoize.spec.ts +1 -1
- package/src/core/{primitives → __tests__}/$mode.spec.ts +1 -1
- package/src/core/{primitives → __tests__}/$pipeline.spec.ts +1 -1
- package/src/core/{primitives → __tests__}/$scope.spec.ts +2 -2
- package/src/core/{providers → __tests__}/KeylessJsonSchemaCodec.spec.ts +1 -1
- package/src/core/{providers → __tests__}/SchemaValidator.spec.ts +1 -1
- package/src/core/{helpers → __tests__}/jsonSchemaToTypeBox.spec.ts +1 -1
- package/src/core/index.shared.ts +1 -1
- package/src/core/primitives/{$use.ts → $state.ts} +4 -4
- package/src/crypto/{providers → __tests__}/BrowserCryptoProvider.browser.spec.ts +1 -1
- package/src/crypto/{providers → __tests__}/CryptoProvider.spec.ts +1 -1
- package/src/datetime/{primitives → __tests__}/$debounce.spec.ts +1 -1
- package/src/datetime/{primitives → __tests__}/$throttle.spec.ts +1 -1
- package/src/datetime/{primitives → __tests__}/$timeout.spec.ts +1 -1
- package/src/email/brevo/{providers → __tests__}/BrevoEmailProvider.spec.ts +1 -1
- package/src/email/core/{providers → __tests__}/LocalEmailProvider.spec.ts +39 -150
- package/src/email/core/providers/LocalEmailProvider.ts +13 -51
- package/src/email/smtp/providers/NodemailerEmailProvider.ts +2 -2
- package/src/lock/core/{primitives → __tests__}/$lock.middleware.spec.ts +1 -1
- package/src/lock/core/primitives/$lock.ts +2 -2
- package/src/logger/index.ts +10 -4
- package/src/mcp/transports/SseMcpTransport.ts +2 -2
- package/src/orm/__tests__/ModelBuilder-tests.ts +53 -0
- package/src/orm/__tests__/ModelBuilder.spec.ts +80 -0
- package/src/orm/__tests__/organization-tests.ts +200 -0
- package/src/orm/__tests__/organization.spec.ts +103 -0
- package/src/orm/core/{providers/drivers → __tests__}/BunSqliteProvider.bun.spec.ts +5 -2
- package/src/orm/core/constants/PG_SYMBOLS.ts +2 -0
- package/src/orm/core/index.shared.ts +1 -0
- package/src/orm/core/primitives/$entity.ts +31 -0
- package/src/orm/core/providers/DatabaseTypeProvider.ts +11 -0
- package/src/orm/core/providers/DrizzleKitProvider.ts +1 -1
- package/src/orm/core/providers/drivers/BunSqliteProvider.ts +2 -2
- package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +3 -3
- package/src/orm/core/services/ModelBuilder.ts +11 -0
- package/src/orm/core/services/QueryManager.ts +16 -2
- package/src/orm/core/services/Repository.ts +70 -10
- package/src/orm/postgres/{providers → __tests__}/BunPostgresProvider.bun.spec.ts +1 -1
- package/src/queue/core/providers/WorkerProvider.ts +2 -2
- package/src/queue/redis/providers/RedisQueueProvider.ts +2 -2
- package/src/react/core/{hooks → __tests__}/useAction.browser.spec.tsx +1 -1
- package/src/react/core/hooks/useAction.ts +7 -6
- package/src/react/head/{providers → __tests__}/BrowserHeadProvider.browser.spec.ts +1 -1
- package/src/react/head/{helpers → __tests__}/SeoExpander.spec.ts +1 -1
- package/src/react/i18n/{providers → __tests__}/I18nProvider.spec.ts +1 -1
- package/src/react/i18n/{hooks → __tests__}/useI18n.browser.spec.tsx +1 -1
- package/src/react/intro/components/GettingStartedDevtoolsSlide.tsx +1 -1
- package/src/react/router/{providers → __tests__}/ReactBrowserProvider.browser.spec.ts +1 -1
- package/src/react/router/providers/ReactBrowserProvider.ts +2 -2
- package/src/react/router/providers/ReactPageProvider.ts +2 -2
- package/src/react/router/providers/ReactServerProvider.ts +3 -3
- package/src/redis/{providers → __tests__}/BunRedisProvider.bun.spec.ts +4 -4
- package/src/retry/{primitives → __tests__}/$retry.middleware.spec.ts +1 -1
- package/src/router/{TemplatedPathParser.spec.ts → __tests__/TemplatedPathParser.spec.ts} +1 -1
- package/src/scheduler/primitives/$scheduler.ts +2 -2
- package/src/security/{primitives → __tests__}/$secure-browser.spec.ts +1 -1
- package/src/security/{primitives → __tests__}/$secure.spec.ts +1 -1
- package/src/security/primitives/$issuer.ts +1 -1
- package/src/security/providers/JwtProvider.ts +6 -10
- package/src/security/providers/SecurityProvider.ts +6 -11
- package/src/security/schemas/userAccountInfoSchema.ts +3 -3
- package/src/server/auth/providers/ServerAuthProvider.ts +24 -2
- package/src/server/cookies/{services → __tests__}/CookieParser.spec.ts +1 -1
- package/src/server/core/{primitives → __tests__}/$circuit.spec.ts +1 -1
- package/src/server/core/{providers → __tests__}/NodeHttpServerProvider.spec.ts +1 -1
- package/src/server/core/{providers → __tests__}/ServerBodyParserProvider.spec.ts +31 -1
- package/src/server/core/{providers → __tests__}/ServerCompressProvider.spec.ts +1 -1
- package/src/server/core/{providers → __tests__}/ServerHelmetProvider.spec.ts +4 -1
- package/src/server/core/{providers → __tests__}/ServerMultipartProvider.spec.ts +1 -1
- package/src/server/core/{services → __tests__}/ServerRequestParser.spec.ts +1 -1
- package/src/server/core/primitives/$action.ts +2 -2
- package/src/server/core/primitives/$sse.ts +2 -2
- package/src/server/core/providers/ServerBodyParserProvider.ts +21 -12
- package/src/server/core/providers/ServerCompressProvider.ts +2 -2
- package/src/server/core/providers/ServerHelmetProvider.ts +2 -2
- package/src/server/core/providers/ServerMultipartProvider.ts +2 -2
- package/src/server/core/providers/ServerRouterProvider.ts +1 -5
- package/src/server/cors/{primitives → __tests__}/$cors.spec.ts +1 -1
- package/src/server/cors/providers/ServerCorsProvider.ts +2 -2
- package/src/server/links/{services → __tests__}/BatchCollector.spec.ts +1 -1
- package/src/server/links/providers/LinkProvider.ts +2 -2
- package/src/server/links/providers/RemotePrimitiveProvider.ts +2 -2
- package/src/server/links/providers/ServerLinksProvider.ts +2 -2
- package/src/server/rate-limit/{primitives → __tests__}/$rateLimit.spec.ts +1 -1
- package/src/server/rate-limit/providers/ServerRateLimitProvider.ts +2 -2
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +2 -2
- package/src/sms/{providers → __tests__}/LocalSmsProvider.spec.ts +35 -29
- package/src/sms/providers/LocalSmsProvider.ts +13 -24
- package/src/system/{providers → __tests__}/MemoryFileSystemProvider.spec.ts +1 -1
- package/src/system/{providers → __tests__}/MemoryShellProvider.spec.ts +1 -1
- package/src/topic/redis/providers/RedisTopicProvider.ts +2 -2
- package/src/websocket/{services → __tests__}/RoomManager.spec.ts +1 -1
- package/src/websocket/providers/NodeWebSocketServerProvider.ts +2 -2
- package/tsconfig.base.json +1 -0
- package/src/cli/platform/adapters/DockerAdapter.spec.ts +0 -378
- package/src/cli/platform/adapters/DockerAdapter.ts +0 -417
- package/src/cli/platform/services/DockerComposeGenerator.spec.ts +0 -490
- package/src/cli/platform/services/DockerComposeGenerator.ts +0 -353
- package/src/cli/platform/services/DockerSshService.spec.ts +0 -47
- package/src/cli/platform/services/DockerSshService.ts +0 -61
- /package/src/api/audits/{primitives → __tests__}/$audit.spec.ts +0 -0
- /package/src/api/audits/{services → __tests__}/AuditService.spec.ts +0 -0
- /package/src/api/files/{controllers → __tests__}/AdminFileStatsController.spec.ts +0 -0
- /package/src/api/files/{controllers → __tests__}/FileController.spec.ts +0 -0
- /package/src/api/files/{jobs → __tests__}/FileJobs.spec.ts +0 -0
- /package/src/api/files/{services → __tests__}/FileService.spec.ts +0 -0
- /package/src/api/jobs/{primitives → __tests__}/$job-middleware.spec.ts +0 -0
- /package/src/api/parameters/{primitives → __tests__}/$parameter.spec.ts +0 -0
- /package/src/api/users/{primitives → __tests__}/$realm.spec.ts +0 -0
- /package/src/api/users/{controllers → __tests__}/AdminIdentityController.spec.ts +0 -0
- /package/src/api/users/{controllers → __tests__}/AdminSessionController.spec.ts +0 -0
- /package/src/api/users/{controllers → __tests__}/AdminUserController.spec.ts +0 -0
- /package/src/api/users/{services → __tests__}/CredentialService.spec.ts +0 -0
- /package/src/api/users/{providers → __tests__}/RealmProvider.spec.ts +0 -0
- /package/src/api/users/{services → __tests__}/RegistrationService.spec.ts +0 -0
- /package/src/batch/{primitives → __tests__}/$batch.spec.ts +0 -0
- /package/src/batch/{providers → __tests__}/BatchProvider.spec.ts +0 -0
- /package/src/bucket/{primitives → __tests__}/$bucket.spec.ts +0 -0
- /package/src/bucket/{providers → __tests__}/FileStorageProvider.spec.ts +0 -0
- /package/src/bucket/{providers → __tests__}/LocalFileStorageProvider.spec.ts +0 -0
- /package/src/bucket/{providers → __tests__}/MemoryFileStorageProvider.spec.ts +0 -0
- /package/src/cache/core/{primitives → __tests__}/$cache.spec.ts +0 -0
- /package/src/cache/redis/{providers → __tests__}/RedisCacheProvider.spec.ts +0 -0
- /package/src/command/{primitives → __tests__}/$command.spec.ts +0 -0
- /package/src/command/{helpers → __tests__}/Asker.spec.ts +0 -0
- /package/src/command/{helpers → __tests__}/Runner.spec.ts +0 -0
- /package/src/core/{primitives → __tests__}/$context.spec.ts +0 -0
- /package/src/core/{primitives → __tests__}/$env.spec.ts +0 -0
- /package/src/core/{primitives → __tests__}/$hook.spec.ts +0 -0
- /package/src/core/{primitives → __tests__}/$inject.spec.ts +0 -0
- /package/src/core/{primitives → __tests__}/$module.spec.ts +0 -0
- /package/src/core/{providers → __tests__}/CodecManager.spec.ts +0 -0
- /package/src/core/{providers → __tests__}/EventManager.spec.ts +0 -0
- /package/src/core/{providers → __tests__}/StateManager.spec.ts +0 -0
- /package/src/core/{providers → __tests__}/TypeProvider.spec.ts +0 -0
- /package/src/datetime/{primitives → __tests__}/$interval.spec.ts +0 -0
- /package/src/datetime/{providers → __tests__}/DateTimeProvider.spec.ts +0 -0
- /package/src/email/core/{primitives → __tests__}/$email.spec.ts +0 -0
- /package/src/fake/{providers → __tests__}/FakeProvider.spec.ts +0 -0
- /package/src/lock/core/{providers → __tests__}/MemoryLockProvider.spec.ts +0 -0
- /package/src/lock/redis/{providers → __tests__}/RedisLockProvider.spec.ts +0 -0
- /package/src/logger/{primitives → __tests__}/$logger.spec.ts +0 -0
- /package/src/logger/{services → __tests__}/Logger.spec.ts +0 -0
- /package/src/mcp/{primitives → __tests__}/$prompt.spec.ts +0 -0
- /package/src/mcp/{primitives → __tests__}/$resource.spec.ts +0 -0
- /package/src/mcp/{primitives → __tests__}/$tool.spec.ts +0 -0
- /package/src/mcp/{providers → __tests__}/McpServerProvider.spec.ts +0 -0
- /package/src/mcp/{helpers → __tests__}/jsonrpc.spec.ts +0 -0
- /package/src/orm/core/{helpers → __tests__}/parseQueryString.spec.ts +0 -0
- /package/src/queue/core/{primitives → __tests__}/$consumer.spec.ts +0 -0
- /package/src/queue/core/{providers → __tests__}/MemoryQueueProvider.spec.ts +0 -0
- /package/src/queue/core/{providers → __tests__}/WorkerProvider.spec.ts +0 -0
- /package/src/queue/redis/{providers → __tests__}/RedisQueueProvider.spec.ts +0 -0
- /package/src/react/form/{hooks → __tests__}/useForm.browser.spec.tsx +0 -0
- /package/src/react/head/{hooks → __tests__}/useHead.spec.tsx +0 -0
- /package/src/react/i18n/{components → __tests__}/Localize.spec.tsx +0 -0
- /package/src/react/router/{primitives → __tests__}/$page.browser.spec.tsx +0 -0
- /package/src/react/router/{primitives → __tests__}/$page.middleware.spec.tsx +0 -0
- /package/src/react/router/{primitives → __tests__}/$page.spec.tsx +0 -0
- /package/src/react/router/{providers → __tests__}/ReactPreloadProvider.spec.ts +0 -0
- /package/src/react/router/{providers → __tests__}/ReactServerProvider.spec.tsx +0 -0
- /package/src/react/router/{providers → __tests__}/ReactServerTemplateProvider.spec.ts +0 -0
- /package/src/retry/{primitives → __tests__}/$retry.spec.ts +0 -0
- /package/src/retry/{providers → __tests__}/RetryProvider.spec.ts +0 -0
- /package/src/router/{providers → __tests__}/RouterProvider.spec.ts +0 -0
- /package/src/security/{primitives → __tests__}/$issuer.spec.ts +0 -0
- /package/src/security/{primitives → __tests__}/$permission.spec.ts +0 -0
- /package/src/security/{primitives → __tests__}/$role.spec.ts +0 -0
- /package/src/security/{primitives → __tests__}/$serviceAccount.spec.ts +0 -0
- /package/src/security/{providers → __tests__}/SecurityProvider.spec.ts +0 -0
- /package/src/server/cookies/{providers → __tests__}/ServerCookiesProvider.spec.ts +0 -0
- /package/src/server/core/{primitives → __tests__}/$action.spec.ts +0 -0
- /package/src/server/core/{primitives → __tests__}/$middleware.spec.ts +0 -0
- /package/src/server/core/{primitives → __tests__}/$route.spec.ts +0 -0
- /package/src/server/core/{primitives → __tests__}/$sse.spec.ts +0 -0
- /package/src/server/core/{providers → __tests__}/BunHttpServerProvider.bun.spec.ts +0 -0
- /package/src/server/core/{services → __tests__}/HttpClient.spec.ts +0 -0
- /package/src/server/core/{providers → __tests__}/ServerLoggerProvider.spec.ts +0 -0
- /package/src/server/core/{services → __tests__}/UserAgentParser.spec.ts +0 -0
- /package/src/server/cors/{providers → __tests__}/ServerCorsProvider.spec.ts +0 -0
- /package/src/server/etag/{providers → __tests__}/ServerEtagProvider.spec.ts +0 -0
- /package/src/server/health/{providers → __tests__}/ServerHealthProvider.spec.ts +0 -0
- /package/src/server/links/{primitives → __tests__}/$remote.spec.ts +0 -0
- /package/src/server/links/{services → __tests__}/BatchEndpoint.spec.ts +0 -0
- /package/src/server/links/{providers → __tests__}/LinkProvider.spec.ts +0 -0
- /package/src/server/links/{providers → __tests__}/ServerLinksProvider.spec.ts +0 -0
- /package/src/server/metrics/{providers → __tests__}/ServerMetricsProvider.spec.ts +0 -0
- /package/src/server/proxy/{primitives → __tests__}/$proxy.spec.ts +0 -0
- /package/src/server/rate-limit/{providers → __tests__}/ServerRateLimitProvider.spec.ts +0 -0
- /package/src/server/static/{primitives → __tests__}/$serve.spec.ts +0 -0
- /package/src/server/swagger/{primitives → __tests__}/$swagger.spec.ts +0 -0
- /package/src/sms/{primitives → __tests__}/$sms.spec.ts +0 -0
- /package/src/sms/{providers → __tests__}/MemorySmsProvider.spec.ts +0 -0
- /package/src/system/{services → __tests__}/FileDetector.spec.ts +0 -0
- /package/src/system/{providers → __tests__}/NodeFileSystemProvider.spec.ts +0 -0
- /package/src/topic/core/{primitives → __tests__}/$subscriber.spec.ts +0 -0
- /package/src/topic/core/{providers → __tests__}/MemoryTopicProvider.spec.ts +0 -0
- /package/src/topic/redis/{providers → __tests__}/RedisTopicProvider.spec.ts +0 -0
- /package/src/websocket/{primitives → __tests__}/$channel.spec.ts +0 -0
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
import * as alepha from "alepha";
|
|
1
|
+
import * as _$alepha from "alepha";
|
|
2
2
|
import { Alepha, Async, KIND, Primitive, Static } from "alepha";
|
|
3
|
-
import * as alepha_server0 from "alepha/server";
|
|
3
|
+
import * as _$alepha_server0 from "alepha/server";
|
|
4
4
|
import { ActionPrimitive, ClientRequestEntry, ClientRequestOptions, ClientRequestResponse, FetchResponse, HttpClient, RequestConfigSchema, ServerRequest, ServerRequestConfigEntry, ServerResponseBody, ServerTimingProvider, SseConfigSchema, SseEventData, SsePrimitive, SseRequestEntry, SseStream } from "alepha/server";
|
|
5
|
-
import * as alepha_logger0 from "alepha/logger";
|
|
5
|
+
import * as _$alepha_logger0 from "alepha/logger";
|
|
6
6
|
import { ProxyPrimitiveOptions, ServerProxyProvider } from "alepha/server/proxy";
|
|
7
7
|
import { SecureOptions, SecurityProvider, ServiceAccountPrimitive, UserAccountToken } from "alepha/security";
|
|
8
8
|
|
|
9
9
|
//#region ../../src/server/links/schemas/apiLinksResponseSchema.d.ts
|
|
10
|
-
declare const apiActionSchema: alepha.TObject<{
|
|
11
|
-
path: alepha.TString;
|
|
12
|
-
method: alepha.TOptional<alepha.TString>;
|
|
13
|
-
contentType: alepha.TOptional<alepha.TString>;
|
|
14
|
-
kind: alepha.TOptional<alepha.TString>;
|
|
15
|
-
service: alepha.TOptional<alepha.TString>;
|
|
10
|
+
declare const apiActionSchema: _$alepha.TObject<{
|
|
11
|
+
path: _$alepha.TString;
|
|
12
|
+
method: _$alepha.TOptional<_$alepha.TString>;
|
|
13
|
+
contentType: _$alepha.TOptional<_$alepha.TString>;
|
|
14
|
+
kind: _$alepha.TOptional<_$alepha.TString>;
|
|
15
|
+
service: _$alepha.TOptional<_$alepha.TString>;
|
|
16
16
|
}>;
|
|
17
|
-
declare const apiRegistryResponseSchema: alepha.TObject<{
|
|
18
|
-
prefix: alepha.TOptional<alepha.TString>;
|
|
19
|
-
actions: alepha.TRecord<"^.*$", alepha.TObject<{
|
|
20
|
-
path: alepha.TString;
|
|
21
|
-
method: alepha.TOptional<alepha.TString>;
|
|
22
|
-
contentType: alepha.TOptional<alepha.TString>;
|
|
23
|
-
kind: alepha.TOptional<alepha.TString>;
|
|
24
|
-
service: alepha.TOptional<alepha.TString>;
|
|
17
|
+
declare const apiRegistryResponseSchema: _$alepha.TObject<{
|
|
18
|
+
prefix: _$alepha.TOptional<_$alepha.TString>;
|
|
19
|
+
actions: _$alepha.TRecord<"^.*$", _$alepha.TObject<{
|
|
20
|
+
path: _$alepha.TString;
|
|
21
|
+
method: _$alepha.TOptional<_$alepha.TString>;
|
|
22
|
+
contentType: _$alepha.TOptional<_$alepha.TString>;
|
|
23
|
+
kind: _$alepha.TOptional<_$alepha.TString>;
|
|
24
|
+
service: _$alepha.TOptional<_$alepha.TString>;
|
|
25
25
|
}>>;
|
|
26
|
-
permissions: alepha.TOptional<alepha.TArray<alepha.TString>>;
|
|
26
|
+
permissions: _$alepha.TOptional<_$alepha.TArray<_$alepha.TString>>;
|
|
27
27
|
}>;
|
|
28
28
|
type ApiRegistryResponse = Static<typeof apiRegistryResponseSchema>;
|
|
29
29
|
type ApiAction = Static<typeof apiActionSchema>;
|
|
30
30
|
/**
|
|
31
31
|
* @deprecated Use `apiRegistryResponseSchema` and `ApiRegistryResponse` instead.
|
|
32
32
|
*/
|
|
33
|
-
declare const apiLinksResponseSchema: alepha.TObject<{
|
|
34
|
-
prefix: alepha.TOptional<alepha.TString>;
|
|
35
|
-
actions: alepha.TRecord<"^.*$", alepha.TObject<{
|
|
36
|
-
path: alepha.TString;
|
|
37
|
-
method: alepha.TOptional<alepha.TString>;
|
|
38
|
-
contentType: alepha.TOptional<alepha.TString>;
|
|
39
|
-
kind: alepha.TOptional<alepha.TString>;
|
|
40
|
-
service: alepha.TOptional<alepha.TString>;
|
|
33
|
+
declare const apiLinksResponseSchema: _$alepha.TObject<{
|
|
34
|
+
prefix: _$alepha.TOptional<_$alepha.TString>;
|
|
35
|
+
actions: _$alepha.TRecord<"^.*$", _$alepha.TObject<{
|
|
36
|
+
path: _$alepha.TString;
|
|
37
|
+
method: _$alepha.TOptional<_$alepha.TString>;
|
|
38
|
+
contentType: _$alepha.TOptional<_$alepha.TString>;
|
|
39
|
+
kind: _$alepha.TOptional<_$alepha.TString>;
|
|
40
|
+
service: _$alepha.TOptional<_$alepha.TString>;
|
|
41
41
|
}>>;
|
|
42
|
-
permissions: alepha.TOptional<alepha.TArray<alepha.TString>>;
|
|
42
|
+
permissions: _$alepha.TOptional<_$alepha.TArray<_$alepha.TString>>;
|
|
43
43
|
}>;
|
|
44
44
|
/**
|
|
45
45
|
* @deprecated Use `ApiRegistryResponse` instead.
|
|
@@ -51,21 +51,21 @@ type ApiLinksResponse = ApiRegistryResponse;
|
|
|
51
51
|
type ApiLink = ApiAction;
|
|
52
52
|
//#endregion
|
|
53
53
|
//#region ../../src/server/links/atoms/apiLinksAtom.d.ts
|
|
54
|
-
declare const apiLinksAtom: alepha.Atom<alepha.TOptional<alepha.TObject<{
|
|
55
|
-
prefix: alepha.TOptional<alepha.TString>;
|
|
56
|
-
actions: alepha.TRecord<"^.*$", alepha.TObject<{
|
|
57
|
-
path: alepha.TString;
|
|
58
|
-
method: alepha.TOptional<alepha.TString>;
|
|
59
|
-
contentType: alepha.TOptional<alepha.TString>;
|
|
60
|
-
kind: alepha.TOptional<alepha.TString>;
|
|
61
|
-
service: alepha.TOptional<alepha.TString>;
|
|
54
|
+
declare const apiLinksAtom: _$alepha.Atom<_$alepha.TOptional<_$alepha.TObject<{
|
|
55
|
+
prefix: _$alepha.TOptional<_$alepha.TString>;
|
|
56
|
+
actions: _$alepha.TRecord<"^.*$", _$alepha.TObject<{
|
|
57
|
+
path: _$alepha.TString;
|
|
58
|
+
method: _$alepha.TOptional<_$alepha.TString>;
|
|
59
|
+
contentType: _$alepha.TOptional<_$alepha.TString>;
|
|
60
|
+
kind: _$alepha.TOptional<_$alepha.TString>;
|
|
61
|
+
service: _$alepha.TOptional<_$alepha.TString>;
|
|
62
62
|
}>>;
|
|
63
|
-
permissions: alepha.TOptional<alepha.TArray<alepha.TString>>;
|
|
63
|
+
permissions: _$alepha.TOptional<_$alepha.TArray<_$alepha.TString>>;
|
|
64
64
|
}>>, "alepha.server.request.apiLinks">;
|
|
65
65
|
//#endregion
|
|
66
66
|
//#region ../../src/server/links/atoms/linkOptionsAtom.d.ts
|
|
67
|
-
declare const linkOptionsAtom: alepha.Atom<alepha.TObject<{
|
|
68
|
-
batch: alepha.TBoolean;
|
|
67
|
+
declare const linkOptionsAtom: _$alepha.Atom<_$alepha.TObject<{
|
|
68
|
+
batch: _$alepha.TBoolean;
|
|
69
69
|
}>, "alepha.server.links.options">;
|
|
70
70
|
//#endregion
|
|
71
71
|
//#region ../../src/server/links/services/BatchCollector.d.ts
|
|
@@ -82,7 +82,7 @@ declare const linkOptionsAtom: alepha.Atom<alepha.TObject<{
|
|
|
82
82
|
*/
|
|
83
83
|
declare class BatchCollector {
|
|
84
84
|
protected static readonly MAX_BATCH_SIZE = 20;
|
|
85
|
-
protected readonly log: alepha_logger0.Logger;
|
|
85
|
+
protected readonly log: _$alepha_logger0.Logger;
|
|
86
86
|
protected readonly httpClient: HttpClient;
|
|
87
87
|
protected pending: PendingBatchEntry[];
|
|
88
88
|
protected scheduled: boolean;
|
|
@@ -118,7 +118,7 @@ declare class LinkProvider {
|
|
|
118
118
|
static path: {
|
|
119
119
|
apiLinks: string;
|
|
120
120
|
};
|
|
121
|
-
protected readonly log: alepha_logger0.Logger;
|
|
121
|
+
protected readonly log: _$alepha_logger0.Logger;
|
|
122
122
|
protected readonly alepha: Alepha;
|
|
123
123
|
protected readonly httpClient: HttpClient;
|
|
124
124
|
protected serverLinkMap: Map<string, HttpClientLink>;
|
|
@@ -282,12 +282,12 @@ declare class RemotePrimitiveProvider {
|
|
|
282
282
|
protected readonly proxyProvider: ServerProxyProvider;
|
|
283
283
|
protected readonly linkProvider: LinkProvider;
|
|
284
284
|
protected readonly remotes: Array<ServerRemote>;
|
|
285
|
-
protected readonly log: alepha_logger0.Logger;
|
|
285
|
+
protected readonly log: _$alepha_logger0.Logger;
|
|
286
286
|
getRemotes(): ServerRemote[];
|
|
287
|
-
readonly configure: alepha.HookPrimitive<"configure">;
|
|
288
|
-
readonly start: alepha.HookPrimitive<"start">;
|
|
287
|
+
readonly configure: _$alepha.HookPrimitive<"configure">;
|
|
288
|
+
readonly start: _$alepha.HookPrimitive<"start">;
|
|
289
289
|
registerRemote(value: RemotePrimitive): Promise<void>;
|
|
290
|
-
protected readonly fetchLinks: alepha.PipelinePrimitiveFn<(opts: FetchLinksOptions) => Promise<ApiRegistryResponse>>;
|
|
290
|
+
protected readonly fetchLinks: _$alepha.PipelinePrimitiveFn<(opts: FetchLinksOptions) => Promise<ApiRegistryResponse>>;
|
|
291
291
|
}
|
|
292
292
|
interface FetchLinksOptions {
|
|
293
293
|
/**
|
|
@@ -352,7 +352,7 @@ declare class ServerLinksProvider {
|
|
|
352
352
|
protected readonly linkProvider: LinkProvider;
|
|
353
353
|
protected readonly remoteProvider: RemotePrimitiveProvider;
|
|
354
354
|
protected readonly serverTimingProvider: ServerTimingProvider;
|
|
355
|
-
protected readonly log: alepha_logger0.Logger;
|
|
355
|
+
protected readonly log: _$alepha_logger0.Logger;
|
|
356
356
|
/**
|
|
357
357
|
* Resolved once on start. Undefined when alepha/security is not loaded.
|
|
358
358
|
*/
|
|
@@ -363,45 +363,45 @@ declare class ServerLinksProvider {
|
|
|
363
363
|
*/
|
|
364
364
|
protected registryCache: Map<string, RegistryCacheEntry>;
|
|
365
365
|
get prefix(): string;
|
|
366
|
-
readonly onRoute: alepha.HookPrimitive<"configure">;
|
|
367
|
-
protected readonly onStart: alepha.HookPrimitive<"start">;
|
|
366
|
+
readonly onRoute: _$alepha.HookPrimitive<"configure">;
|
|
367
|
+
protected readonly onStart: _$alepha.HookPrimitive<"start">;
|
|
368
368
|
/**
|
|
369
369
|
* API registry endpoint — returns all available actions for the user.
|
|
370
370
|
*
|
|
371
371
|
* Response is filtered by the user's permissions.
|
|
372
372
|
* Cached by role set with ETag support.
|
|
373
373
|
*/
|
|
374
|
-
readonly links: alepha_server0.RoutePrimitive<RequestConfigSchema>;
|
|
374
|
+
readonly links: _$alepha_server0.RoutePrimitive<RequestConfigSchema>;
|
|
375
375
|
/**
|
|
376
376
|
* On-demand schemas endpoint — returns JSON Schemas for requested actions.
|
|
377
377
|
*
|
|
378
378
|
* Schemas are filtered by the user's permissions (same logic as the registry).
|
|
379
379
|
*/
|
|
380
|
-
readonly schemas: alepha_server0.RoutePrimitive<{
|
|
381
|
-
body: alepha.TObject<{
|
|
382
|
-
actions: alepha.TArray<alepha.TString>;
|
|
380
|
+
readonly schemas: _$alepha_server0.RoutePrimitive<{
|
|
381
|
+
body: _$alepha.TObject<{
|
|
382
|
+
actions: _$alepha.TArray<_$alepha.TString>;
|
|
383
383
|
}>;
|
|
384
|
-
response: alepha.TRecord<"^.*$", alepha.TObject<{
|
|
385
|
-
body: alepha.TOptional<alepha.TString>;
|
|
386
|
-
response: alepha.TOptional<alepha.TString>;
|
|
384
|
+
response: _$alepha.TRecord<"^.*$", _$alepha.TObject<{
|
|
385
|
+
body: _$alepha.TOptional<_$alepha.TString>;
|
|
386
|
+
response: _$alepha.TOptional<_$alepha.TString>;
|
|
387
387
|
}>>;
|
|
388
388
|
}>;
|
|
389
389
|
/**
|
|
390
390
|
* Batch endpoint — execute multiple actions in a single HTTP request.
|
|
391
391
|
* Each sub-request is independent: errors in one don't affect others.
|
|
392
392
|
*/
|
|
393
|
-
readonly batch: alepha_server0.RoutePrimitive<{
|
|
394
|
-
body: alepha.TArray<alepha.TObject<{
|
|
395
|
-
action: alepha.TString;
|
|
396
|
-
params: alepha.TOptional<alepha.TRecord<"^.*$", alepha.TAny>>;
|
|
397
|
-
query: alepha.TOptional<alepha.TRecord<"^.*$", alepha.TAny>>;
|
|
398
|
-
body: alepha.TOptional<alepha.TRecord<"^.*$", alepha.TAny>>;
|
|
393
|
+
readonly batch: _$alepha_server0.RoutePrimitive<{
|
|
394
|
+
body: _$alepha.TArray<_$alepha.TObject<{
|
|
395
|
+
action: _$alepha.TString;
|
|
396
|
+
params: _$alepha.TOptional<_$alepha.TRecord<"^.*$", _$alepha.TAny>>;
|
|
397
|
+
query: _$alepha.TOptional<_$alepha.TRecord<"^.*$", _$alepha.TAny>>;
|
|
398
|
+
body: _$alepha.TOptional<_$alepha.TRecord<"^.*$", _$alepha.TAny>>;
|
|
399
399
|
}>>;
|
|
400
|
-
response: alepha.TArray<alepha.TObject<{
|
|
401
|
-
action: alepha.TString;
|
|
402
|
-
status: alepha.TInteger;
|
|
403
|
-
data: alepha.TOptional<alepha.TAny>;
|
|
404
|
-
error: alepha.TOptional<alepha.TString>;
|
|
400
|
+
response: _$alepha.TArray<_$alepha.TObject<{
|
|
401
|
+
action: _$alepha.TString;
|
|
402
|
+
status: _$alepha.TInteger;
|
|
403
|
+
data: _$alepha.TOptional<_$alepha.TAny>;
|
|
404
|
+
error: _$alepha.TOptional<_$alepha.TString>;
|
|
405
405
|
}>>;
|
|
406
406
|
}>;
|
|
407
407
|
protected static readonly MAX_BATCH_SIZE = 20;
|
|
@@ -454,7 +454,7 @@ declare module "alepha" {
|
|
|
454
454
|
*
|
|
455
455
|
* @module alepha.server.links
|
|
456
456
|
*/
|
|
457
|
-
declare const AlephaServerLinks: alepha.Service<alepha.Module>;
|
|
457
|
+
declare const AlephaServerLinks: _$alepha.Service<_$alepha.Module>;
|
|
458
458
|
//#endregion
|
|
459
459
|
export { $client, $remote, AlephaServerLinks, ApiAction, ApiLink, ApiLinksResponse, ApiRegistryResponse, BatchCollector, BatchEntry, ClientScope, FetchLinksOptions, GetApiLinksOptions, HttpClientLink, HttpVirtualClient, LinkProvider, RemotePrimitive, RemotePrimitiveOptions, RemotePrimitiveProvider, ServerLinksProvider, ServerRemote, VirtualAction, VirtualSse, apiActionSchema, apiLinksAtom, apiLinksResponseSchema, apiRegistryResponseSchema, linkOptionsAtom };
|
|
460
460
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/server/links/schemas/apiLinksResponseSchema.ts","../../../src/server/links/atoms/apiLinksAtom.ts","../../../src/server/links/atoms/linkOptionsAtom.ts","../../../src/server/links/services/BatchCollector.ts","../../../src/server/links/providers/LinkProvider.ts","../../../src/server/links/primitives/$client.ts","../../../src/server/links/primitives/$remote.ts","../../../src/server/links/providers/RemotePrimitiveProvider.ts","../../../src/server/links/providers/ServerLinksProvider.ts","../../../src/server/links/index.ts"],"mappings":";;;;;;;;;cAGa,eAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/server/links/schemas/apiLinksResponseSchema.ts","../../../src/server/links/atoms/apiLinksAtom.ts","../../../src/server/links/atoms/linkOptionsAtom.ts","../../../src/server/links/services/BatchCollector.ts","../../../src/server/links/providers/LinkProvider.ts","../../../src/server/links/primitives/$client.ts","../../../src/server/links/primitives/$remote.ts","../../../src/server/links/providers/RemotePrimitiveProvider.ts","../../../src/server/links/providers/ServerLinksProvider.ts","../../../src/server/links/index.ts"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $atom, $hook, $inject, $module, $pipeline, $
|
|
1
|
+
import { $atom, $hook, $inject, $module, $pipeline, $state, Alepha, AlephaError, KIND, Primitive, createPrimitive, t } from "alepha";
|
|
2
2
|
import { $action, $route, $sse, AlephaServer, HttpClient, HttpError, ServerReply, ServerTimingProvider, UnauthorizedError, serverApiOptions } from "alepha/server";
|
|
3
3
|
import { $logger } from "alepha/logger";
|
|
4
4
|
import { $retry } from "alepha/retry";
|
|
@@ -162,7 +162,7 @@ var LinkProvider = class LinkProvider {
|
|
|
162
162
|
permissions = /* @__PURE__ */ new Set();
|
|
163
163
|
lastLoadedRegistry = null;
|
|
164
164
|
batchCollector;
|
|
165
|
-
options = $
|
|
165
|
+
options = $state(linkOptionsAtom);
|
|
166
166
|
/**
|
|
167
167
|
* Get applicative links registered on the server.
|
|
168
168
|
* This does not include lazy-loaded remote links.
|
|
@@ -410,7 +410,7 @@ $remote[KIND] = RemotePrimitive;
|
|
|
410
410
|
//#endregion
|
|
411
411
|
//#region ../../src/server/links/providers/RemotePrimitiveProvider.ts
|
|
412
412
|
var RemotePrimitiveProvider = class {
|
|
413
|
-
serverApi = $
|
|
413
|
+
serverApi = $state(serverApiOptions);
|
|
414
414
|
alepha = $inject(Alepha);
|
|
415
415
|
proxyProvider = $inject(ServerProxyProvider);
|
|
416
416
|
linkProvider = $inject(LinkProvider);
|
|
@@ -510,7 +510,7 @@ var RemotePrimitiveProvider = class {
|
|
|
510
510
|
//#endregion
|
|
511
511
|
//#region ../../src/server/links/providers/ServerLinksProvider.ts
|
|
512
512
|
var ServerLinksProvider = class ServerLinksProvider {
|
|
513
|
-
serverApi = $
|
|
513
|
+
serverApi = $state(serverApiOptions);
|
|
514
514
|
alepha = $inject(Alepha);
|
|
515
515
|
linkProvider = $inject(LinkProvider);
|
|
516
516
|
remoteProvider = $inject(RemotePrimitiveProvider);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/server/links/schemas/apiLinksResponseSchema.ts","../../../src/server/links/atoms/apiLinksAtom.ts","../../../src/server/links/atoms/linkOptionsAtom.ts","../../../src/server/links/services/BatchCollector.ts","../../../src/server/links/providers/LinkProvider.ts","../../../src/server/links/primitives/$client.ts","../../../src/server/links/primitives/$remote.ts","../../../src/server/links/providers/RemotePrimitiveProvider.ts","../../../src/server/links/providers/ServerLinksProvider.ts","../../../src/server/links/index.ts"],"sourcesContent":["import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\n\nexport const apiActionSchema = t.object({\n path: t.text({\n description: \"Pathname used to access the action.\",\n }),\n\n method: t.optional(\n t.text({\n description:\n \"HTTP method. Omitted when GET (the default for ~75% of actions).\",\n }),\n ),\n\n contentType: t.optional(\n t.text({\n description:\n \"Content type for the request body. Only present for non-JSON types (e.g. 'multipart/form-data'). When absent, defaults to application/json.\",\n }),\n ),\n\n kind: t.optional(\n t.text({\n description:\n \"Action kind. Used to distinguish special action types (e.g. 'sse' for Server-Sent Events streams).\",\n }),\n ),\n\n service: t.optional(\n t.text({\n description:\n \"Service name associated with the action, used for service discovery and routing.\",\n }),\n ),\n});\n\nexport const apiRegistryResponseSchema = t.object({\n prefix: t.optional(t.text()),\n\n actions: t.record(t.text(), apiActionSchema),\n\n permissions: t.optional(t.array(t.text())),\n});\n\nexport type ApiRegistryResponse = Static<typeof apiRegistryResponseSchema>;\nexport type ApiAction = Static<typeof apiActionSchema>;\n\n/**\n * @deprecated Use `apiRegistryResponseSchema` and `ApiRegistryResponse` instead.\n */\nexport const apiLinksResponseSchema = apiRegistryResponseSchema;\n\n/**\n * @deprecated Use `ApiRegistryResponse` instead.\n */\nexport type ApiLinksResponse = ApiRegistryResponse;\n\n/**\n * @deprecated Use `ApiAction` instead.\n */\nexport type ApiLink = ApiAction;\n","import { $atom, t } from \"alepha\";\nimport { apiRegistryResponseSchema } from \"../schemas/apiLinksResponseSchema.ts\";\n\nexport const apiLinksAtom = $atom({\n name: \"alepha.server.request.apiLinks\",\n schema: t.optional(apiRegistryResponseSchema),\n});\n","import { $atom, t } from \"alepha\";\n\nexport const linkOptionsAtom = $atom({\n name: \"alepha.server.links.options\",\n description: \"Configuration options for the links module.\",\n schema: t.object({\n batch: t.boolean({\n description: \"Enable batch collection for browser-side calls.\",\n default: true,\n }),\n }),\n default: {\n batch: true,\n },\n});\n","import { $inject } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { HttpClient, HttpError } from \"alepha/server\";\n\n/**\n * Collects browser-side action calls within a microtask and\n * sends them as a single `POST /api/_batch` request.\n *\n * Key behaviors:\n * - Single call in the window → direct HTTP call (no batch overhead)\n * - Multiple calls → coalesced into one batch request\n * - Same action + same params/query/body → deduplicated, result shared\n * - Exceeding MAX_BATCH_SIZE → split into multiple batch calls\n * - Transport failure → all pending promises reject\n */\nexport class BatchCollector {\n protected static readonly MAX_BATCH_SIZE = 20;\n\n protected readonly log = $logger();\n protected readonly httpClient = $inject(HttpClient);\n\n protected pending: PendingBatchEntry[] = [];\n protected scheduled = false;\n\n /**\n * Add an action call to the batch. Returns the result when the batch resolves.\n */\n public add(entry: BatchEntry): Promise<any> {\n return new Promise((resolve, reject) => {\n this.pending.push({ entry, resolve, reject });\n\n if (!this.scheduled) {\n this.scheduled = true;\n setTimeout(() => {\n this.scheduled = false;\n this.flush().catch((err) => this.log.error(err));\n }, 10);\n }\n });\n }\n\n protected async flush(): Promise<void> {\n const batch = this.pending.splice(0);\n\n if (batch.length === 0) return;\n\n // Single request — skip batching, call directly via follow\n if (batch.length === 1) {\n const item = batch[0];\n try {\n const result = await item.entry.directCall();\n item.resolve(result);\n } catch (error) {\n item.reject(error);\n }\n return;\n }\n\n // Deduplicate: same action + same params → share result\n const { unique, indexMap } = this.dedupe(batch);\n\n // Split into chunks of MAX_BATCH_SIZE\n const chunks = this.chunk(unique, BatchCollector.MAX_BATCH_SIZE);\n\n try {\n const allResults = (\n await Promise.all(\n chunks.map((chunk) => {\n const actions = [...new Set(chunk.map((b) => b.entry.action))].join(\n \",\",\n );\n\n return this.httpClient\n .fetch(`/api/_batch?actions=${actions}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(\n chunk.map((b) => ({\n action: b.entry.action,\n params: b.entry.params,\n query: b.entry.query,\n body: b.entry.body,\n })),\n ),\n })\n .then((res) => res.data as BatchResponse[]);\n }),\n )\n ).flat();\n\n // Distribute results back (including deduped slots)\n for (let i = 0; i < batch.length; i++) {\n const result = allResults[indexMap[i]];\n if (result.status >= 400) {\n batch[i].reject(\n new HttpError({\n message:\n result.error ?? `${result.action} failed (${result.status})`,\n status: result.status,\n }),\n );\n } else {\n batch[i].resolve(result.data);\n }\n }\n } catch (error) {\n // Transport-level failure — reject all pending promises\n for (const item of batch) {\n item.reject(error);\n }\n }\n }\n\n protected dedupe(batch: PendingBatchEntry[]): {\n unique: PendingBatchEntry[];\n indexMap: number[];\n } {\n const seen = new Map<string, number>();\n const unique: PendingBatchEntry[] = [];\n const indexMap: number[] = [];\n\n for (const item of batch) {\n const key = `${item.entry.action}:${JSON.stringify({\n params: item.entry.params,\n query: item.entry.query,\n body: item.entry.body,\n })}`;\n\n const existing = seen.get(key);\n if (existing !== undefined) {\n indexMap.push(existing);\n } else {\n const idx = unique.length;\n seen.set(key, idx);\n unique.push(item);\n indexMap.push(idx);\n }\n }\n\n return { unique, indexMap };\n }\n\n protected chunk<T>(arr: T[], size: number): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n chunks.push(arr.slice(i, i + size));\n }\n return chunks;\n }\n}\n\n// ---\n\nexport interface BatchEntry {\n action: string;\n params?: Record<string, any>;\n query?: Record<string, any>;\n body?: Record<string, any>;\n directCall: () => Promise<any>;\n}\n\ninterface PendingBatchEntry {\n entry: BatchEntry;\n resolve: (value: any) => void;\n reject: (reason: any) => void;\n}\n\ninterface BatchResponse {\n action: string;\n status: number;\n data?: any;\n error?: string;\n}\n","import { $inject, $use, Alepha, AlephaError, type Async, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { SecureOptions } from \"alepha/security\";\nimport {\n type ActionPrimitive,\n type ClientRequestEntry,\n type ClientRequestOptions,\n type ClientRequestResponse,\n type FetchResponse,\n HttpClient,\n type RequestConfigSchema,\n ServerReply,\n type ServerRequest,\n type ServerRequestConfigEntry,\n type ServerResponseBody,\n type SseConfigSchema,\n type SseEventData,\n type SsePrimitive,\n type SseRequestEntry,\n type SseStream,\n UnauthorizedError,\n} from \"alepha/server\";\nimport { linkOptionsAtom } from \"../atoms/linkOptionsAtom.ts\";\nimport {\n type ApiRegistryResponse,\n apiRegistryResponseSchema,\n} from \"../schemas/apiLinksResponseSchema.ts\";\nimport { BatchCollector } from \"../services/BatchCollector.ts\";\n\n/**\n * Browser, SSR friendly, service to handle links.\n */\nexport class LinkProvider {\n static path = {\n apiLinks: \"/api/_links\",\n };\n\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly httpClient = $inject(HttpClient);\n\n // Server-side: all registered links (local + remote), keyed by name\n protected serverLinkMap = new Map<string, HttpClientLink>();\n\n // Browser/SSR: parsed from the registry response\n protected actionMap = new Map<string, HttpClientLink>();\n protected permissions = new Set<string>();\n protected lastLoadedRegistry: ApiRegistryResponse | null = null;\n\n // Browser-only: batch collector for coalescing multiple calls\n protected batchCollector?: BatchCollector;\n\n protected readonly options = $use(linkOptionsAtom);\n\n /**\n * Get applicative links registered on the server.\n * This does not include lazy-loaded remote links.\n */\n public getServerLinks(): HttpClientLink[] {\n if (this.alepha.isBrowser()) {\n this.log.warn(\n \"Getting server links in the browser is not supported. Use `fetchLinks` to get links from the server.\",\n );\n return [];\n }\n\n return [...this.serverLinkMap.values()];\n }\n\n /**\n * Register a new link for the application.\n */\n public registerLink(link: HttpClientLink): void {\n if (this.alepha.isBrowser()) {\n this.log.warn(\n \"Registering links in the browser is not supported. Use `fetchLinks` to get links from the server.\",\n );\n return;\n }\n\n if (!link.handler && !link.host) {\n throw new AlephaError(\n \"Can't create link - 'handler' or 'host' is required\",\n );\n }\n\n // Detect duplicate local actions (programming error)\n const existing = this.serverLinkMap.get(link.name);\n if (existing?.handler && link.handler) {\n throw new AlephaError(\n `Duplicate action name \"${link.name}\". Each action must have a unique name.`,\n );\n }\n\n this.serverLinkMap.set(link.name, link);\n }\n\n /**\n * Load the registry response into internal stores (actionMap, permissions, definitions).\n * Called when storing from atom/fetch/SSR.\n */\n protected loadRegistry(registry: ApiRegistryResponse): void {\n this.lastLoadedRegistry = registry;\n this.permissions.clear();\n this.actionMap.clear();\n\n for (const [name, action] of Object.entries(registry.actions)) {\n this.actionMap.set(name, {\n name,\n path: action.path,\n kind: action.kind,\n method: action.method,\n contentType: action.contentType,\n service: action.service,\n });\n }\n\n if (registry.permissions) {\n for (const p of registry.permissions) {\n this.permissions.add(p);\n }\n }\n }\n\n public get links(): HttpClientLink[] {\n const registry = this.alepha.store.get(\"alepha.server.request.apiLinks\");\n\n if (registry) {\n if (this.alepha.isBrowser()) {\n // Browser side: use the parsed action map\n // Reload when registry changes (e.g. after login provides new authenticated links)\n if (this.actionMap.size === 0 || registry !== this.lastLoadedRegistry) {\n this.loadRegistry(registry);\n }\n return [...this.actionMap.values()];\n }\n\n // SSR side: map registry actions back to full server links\n const links: HttpClientLink[] = [];\n for (const name of Object.keys(registry.actions)) {\n const originalLink = this.serverLinkMap.get(name);\n if (originalLink) {\n links.push(originalLink);\n }\n }\n return links;\n }\n\n return [...this.serverLinkMap.values()];\n }\n\n /**\n * Force browser to refresh links from the server.\n */\n public async fetchLinks(): Promise<HttpClientLink[]> {\n const { data } = await this.httpClient.fetch(\n `${LinkProvider.path.apiLinks}`,\n {\n method: \"GET\",\n schema: {\n response: apiRegistryResponseSchema,\n },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data);\n this.loadRegistry(data);\n\n return [...this.actionMap.values()];\n }\n\n /**\n * Create a virtual client that can be used to call actions.\n *\n * Use js Proxy under the hood.\n */\n public client<T extends object>(\n scope: ClientScope = {},\n ): HttpVirtualClient<T> {\n return new Proxy<HttpVirtualClient<T>>({} as HttpVirtualClient<T>, {\n get: (_, prop) => {\n if (typeof prop !== \"string\") {\n return;\n }\n\n return this.createVirtualAction<RequestConfigSchema>(prop, scope);\n },\n });\n }\n\n /**\n * Check if a link with the given name exists or a permission matches.\n *\n * Action names never contain colons. Permission names always do.\n * - `can(\"getUsers\")` → O(1) map lookup\n * - `can(\"admin:*\")` → wildcard match against permissions set\n * - `can(\"admin:user:read\")` → O(1) set lookup\n */\n public can(name: string): boolean {\n // Action check — O(1) map lookup\n if (this.actionMap.size > 0) {\n if (this.actionMap.has(name)) return true;\n } else {\n // Fallback for server-side where actionMap may not be populated\n if (this.serverLinkMap.has(name)) return true;\n // Also check links getter (for SSR with atom)\n if (this.links.some((link) => link.name === name)) return true;\n }\n\n // Permission check — wildcard matching\n if (name.includes(\":\")) {\n if (name.endsWith(\"*\")) {\n const prefix = name.slice(0, -1);\n for (const p of this.permissions) {\n if (p.startsWith(prefix)) return true;\n }\n return false;\n }\n return this.permissions.has(name);\n }\n\n return false;\n }\n\n /**\n * Resolve a link by its name and call it.\n * - If link is local, it will call the local handler.\n * - If link is remote, it will make a fetch request to the remote server.\n */\n public async follow(\n name: string,\n config: Partial<ServerRequestConfigEntry> = {},\n options: ClientRequestOptions & ClientScope = {},\n ): Promise<any> {\n this.log.trace(\"Following link\", { name, config, options });\n const link = await this.getLinkByName(name, options);\n\n // if a handler is defined, use it (ssr)\n if (link.handler && !options.request) {\n this.log.trace(\"Local link found\", { name });\n return link.handler(\n {\n method: link.method,\n url: new URL(`http://localhost${link.path}`),\n query: config.query ?? {},\n body: config.body ?? {},\n params: config.params ?? {},\n headers: config.headers ?? {},\n metadata: {},\n reply: new ServerReply(),\n } as Partial<ServerRequest> as ServerRequest,\n options,\n );\n }\n\n this.log.trace(\"Remote link found\", {\n name,\n host: link.host,\n service: link.service,\n });\n\n // Browser-only: use batch collector for calls without explicit host\n if (this.options.batch && this.alepha.isBrowser() && !link.host) {\n this.batchCollector ??= this.alepha.inject(BatchCollector);\n return this.batchCollector.add({\n action: name,\n params: config.params as any,\n query: config.query as any,\n body: config.body as any,\n directCall: () =>\n this.followRemote(link, config, options).then((r) => r.data),\n });\n }\n\n return this.followRemote(link, config, options).then(\n (response) => response.data,\n );\n }\n\n protected createVirtualAction<T extends RequestConfigSchema>(\n name: string,\n scope: ClientScope = {},\n ): VirtualAction<T> {\n const $: VirtualAction<T> = async (\n config: any = {},\n options: ClientRequestOptions = {},\n ) => {\n return this.follow(name, config, {\n ...scope,\n ...options,\n });\n };\n\n Object.defineProperty($, \"name\", {\n value: name,\n writable: false,\n });\n\n $.run = async (config: any = {}, options: ClientRequestOptions = {}) => {\n return this.follow(name, config, {\n ...scope,\n ...options,\n });\n };\n\n $.fetch = async (config: any = {}, options: ClientRequestOptions = {}) => {\n const link = await this.getLinkByName(name, scope);\n return this.followRemote(link, config, options);\n };\n\n $.can = () => {\n return this.can(name);\n };\n\n return $;\n }\n\n protected async followRemote(\n link: HttpClientLink,\n config: Partial<ServerRequestConfigEntry> = {},\n options: ClientRequestOptions = {},\n ): Promise<FetchResponse> {\n options.request ??= {};\n options.request.headers = new Headers(options.request.headers);\n\n const als = this.alepha.store.get(\"alepha.http.request\");\n if (als?.headers.authorization) {\n options.request.headers.set(\"authorization\", als.headers.authorization);\n }\n\n const context = this.alepha.context.get(\"context\");\n if (typeof context === \"string\") {\n options.request.headers.set(\"x-request-id\", context);\n }\n\n const action = {\n ...link,\n // schema is not used in the client,\n // we assume that TypeScript will check\n schema: {\n body: t.any(),\n response: t.any(),\n },\n };\n\n // prefix with service when host is not defined (e.g. browser)\n if (!link.host && link.service) {\n action.path = `/${link.service}${action.path}`;\n }\n\n action.path = `${action.prefix ?? \"/api\"}${action.path}`;\n action.prefix = undefined; // prefix is not used in the client\n\n // else, make a request\n return this.httpClient.fetchAction({\n host: link.host,\n config,\n options,\n action: action as any, // schema.body TAny is not accepted\n });\n }\n\n protected async getLinkByName(\n name: string,\n options: ClientScope = {},\n ): Promise<HttpClientLink> {\n if (\n this.alepha.isBrowser() &&\n !this.alepha.store.get(\"alepha.server.request.apiLinks\")\n ) {\n await this.fetchLinks();\n }\n\n const link = this.links.find(\n (a) =>\n a.name === name && (!options.service || options.service === a.service),\n );\n\n if (!link) {\n const error = new UnauthorizedError(`Action ${name} not found.`);\n // mimic http error handling\n await this.alepha.events.emit(\"client:onError\", {\n route: link,\n error,\n });\n throw error;\n }\n\n if (options.hostname) {\n return {\n ...link,\n host: options.hostname,\n };\n }\n\n return link;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface HttpClientLink {\n name: string;\n path: string;\n method?: string;\n kind?: string;\n contentType?: string;\n service?: string;\n secured?: boolean | SecureOptions;\n prefix?: string;\n group?: string;\n // -- server only --\n host?: string;\n schema?: RequestConfigSchema;\n handler?: (\n request: ServerRequest,\n options: ClientRequestOptions,\n ) => Async<ServerResponseBody>;\n}\n\nexport interface ClientScope {\n service?: string;\n hostname?: string;\n}\n\nexport type HttpVirtualClient<T> = {\n [K in keyof T as T[K] extends ActionPrimitive<RequestConfigSchema>\n ? K\n : never]: T[K] extends ActionPrimitive<infer Schema>\n ? VirtualAction<Schema>\n : never;\n} & {\n [K in keyof T as T[K] extends SsePrimitive<SseConfigSchema>\n ? K\n : never]: T[K] extends SsePrimitive<infer Schema>\n ? VirtualSse<Schema>\n : never;\n};\n\nexport interface VirtualAction<T extends RequestConfigSchema>\n extends Pick<ActionPrimitive<T>, \"name\" | \"run\" | \"fetch\"> {\n (\n config?: ClientRequestEntry<T>,\n opts?: ClientRequestOptions,\n ): Promise<ClientRequestResponse<T>>;\n can: () => boolean;\n}\n\nexport interface VirtualSse<T extends SseConfigSchema> {\n (config?: SseRequestEntry<T>): Promise<SseStream<SseEventData<T>>>;\n name: string;\n can: () => boolean;\n}\n","import { $inject, KIND } from \"alepha\";\nimport {\n type ClientScope,\n type HttpVirtualClient,\n LinkProvider,\n} from \"../providers/LinkProvider.ts\";\n\n/**\n * Create a new client.\n */\nexport const $client = <T extends object>(\n scope?: ClientScope,\n): HttpVirtualClient<T> => {\n return $inject(LinkProvider).client<T>(scope);\n};\n\n$client[KIND] = \"$client\";\n","import { createPrimitive, KIND, Primitive } from \"alepha\";\nimport type { ServiceAccountPrimitive } from \"alepha/security\";\nimport type { ProxyPrimitiveOptions } from \"alepha/server/proxy\";\n\n/**\n * $remote is a primitive that allows you to define remote service access.\n *\n * Use it only when you have 2 or more services that need to communicate with each other.\n *\n * All remote services can be exposed as actions, ... or not.\n *\n * You can add a service account if you want to use a security layer.\n */\nexport const $remote = (options: RemotePrimitiveOptions) => {\n return createPrimitive(RemotePrimitive, options);\n};\n\nexport interface RemotePrimitiveOptions {\n /**\n * The URL of the remote service.\n * You can use a function to generate the URL dynamically.\n * You probably should use $env(env) to get the URL from the environment.\n *\n * @example\n * ```ts\n * import { $remote } from \"alepha/server\";\n * import { $inject, t } from \"alepha\";\n *\n * class App {\n * env = $env(t.object({\n * REMOTE_URL: t.text({default: \"http://localhost:3000\"}),\n * }));\n * remote = $remote({\n * url: this.env.REMOTE_URL,\n * });\n * }\n * ```\n */\n url: string | (() => string);\n\n /**\n * The name of the remote service.\n *\n * @default Member of the class containing the remote service.\n */\n name?: string;\n\n /**\n * If true, all methods of the remote service will be exposed as actions in this context.\n * > Note: Proxy will never use the service account, it just... proxies the request.\n */\n proxy?:\n | boolean\n | Partial<\n ProxyPrimitiveOptions & {\n /**\n * If true, the remote service won't be available internally, only through the proxy.\n */\n noInternal: boolean;\n }\n >;\n\n /**\n * For communication between the server and the remote service with a security layer.\n * This will be used for internal communication and will not be exposed to the client.\n */\n serviceAccount?: ServiceAccountPrimitive;\n}\n\nexport class RemotePrimitive extends Primitive<RemotePrimitiveOptions> {\n public get name(): string {\n return this.options.name ?? this.config.propertyKey;\n }\n}\n\n$remote[KIND] = RemotePrimitive;\n","import { $hook, $inject, $pipeline, $use, Alepha, AlephaError } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { $retry } from \"alepha/retry\";\nimport type { ServiceAccountPrimitive } from \"alepha/security\";\nimport { serverApiOptions } from \"alepha/server\";\nimport { ServerProxyProvider } from \"alepha/server/proxy\";\nimport { $remote, type RemotePrimitive } from \"../primitives/$remote.ts\";\nimport {\n type ApiRegistryResponse,\n apiRegistryResponseSchema,\n} from \"../schemas/apiLinksResponseSchema.ts\";\nimport { LinkProvider } from \"./LinkProvider.ts\";\n\nexport class RemotePrimitiveProvider {\n protected readonly serverApi = $use(serverApiOptions);\n protected readonly alepha = $inject(Alepha);\n protected readonly proxyProvider = $inject(ServerProxyProvider);\n protected readonly linkProvider = $inject(LinkProvider);\n protected readonly remotes: Array<ServerRemote> = [];\n protected readonly log = $logger();\n\n public getRemotes(): ServerRemote[] {\n return this.remotes;\n }\n\n public readonly configure = $hook({\n on: \"configure\",\n handler: async () => {\n const remotes = this.alepha.primitives($remote);\n for (const remote of remotes) {\n await this.registerRemote(remote);\n }\n },\n });\n\n public readonly start = $hook({\n on: \"start\",\n handler: async () => {\n for (const remote of this.remotes) {\n const token =\n typeof remote.serviceAccount?.token === \"function\"\n ? await remote.serviceAccount.token()\n : undefined;\n\n if (!remote.internal) {\n continue; // skip download links for remotes that are not internal\n }\n\n const registry = await remote.links({ authorization: token });\n\n for (const [name, action] of Object.entries(registry.actions)) {\n let path = action.path.replace(remote.prefix, \"\");\n if (action.service) {\n path = `/${action.service}${path}`;\n }\n\n this.linkProvider.registerLink({\n name,\n path,\n method: action.method ?? undefined,\n contentType: action.contentType,\n prefix: remote.prefix,\n host: remote.url,\n service: remote.name,\n });\n }\n\n this.log.info(`Remote '${remote.name}' OK`, {\n actions: Object.keys(registry.actions).length,\n prefix: remote.prefix,\n });\n }\n },\n });\n\n public async registerRemote(value: RemotePrimitive): Promise<void> {\n const options = value.options;\n const url = typeof options.url === \"string\" ? options.url : options.url();\n const linkPath = LinkProvider.path.apiLinks;\n const name = value.name;\n const proxy = typeof options.proxy === \"object\" ? options.proxy : {};\n\n const remote: ServerRemote = {\n url,\n name,\n prefix: \"/api\",\n serviceAccount: options.serviceAccount,\n proxy: !!options.proxy,\n internal: !proxy.noInternal,\n schema: async (opts) => {\n const { authorization, name } = opts;\n return await fetch(`${url}${linkPath}/${name}/schema`, {\n headers: new Headers(\n authorization\n ? {\n authorization,\n }\n : {},\n ),\n }).then((it) => it.json()); // TODO: use schema validation for response\n },\n links: async (opts) => {\n const { authorization } = opts;\n const remoteApi = await this.fetchLinks.run({\n service: name,\n url: `${url}${linkPath}`,\n authorization,\n });\n\n if (remoteApi.prefix != null) {\n remote.prefix = remoteApi.prefix; // monkey patch the prefix, not ideal but works\n }\n\n return remoteApi;\n },\n };\n\n this.remotes.push(remote);\n\n if (options.proxy) {\n this.proxyProvider.createProxy({\n path: `${this.serverApi.prefix}/${name}/*`,\n target: url,\n rewrite: (url) => {\n url.pathname = url.pathname.replace(\n `${this.serverApi.prefix}/${name}`,\n remote.prefix,\n );\n },\n ...proxy,\n });\n }\n }\n\n protected readonly fetchLinks = $pipeline({\n use: [\n $retry({\n max: 10,\n backoff: {\n initial: 1000,\n },\n onError: (_: Error, attempt: number) => {\n this.log.warn(`Failed to fetch links, retry (${attempt})...`);\n },\n }),\n ],\n handler: async (opts: FetchLinksOptions): Promise<ApiRegistryResponse> => {\n const { url, authorization } = opts;\n const response = await fetch(url, {\n headers: new Headers(\n authorization\n ? {\n authorization,\n }\n : {},\n ),\n });\n\n if (!response.ok) {\n throw new AlephaError(`Failed to fetch links from ${url}`);\n }\n\n return this.alepha.codec.decode(\n apiRegistryResponseSchema,\n await response.json(),\n );\n },\n });\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface FetchLinksOptions {\n /**\n * Name of the remote service.\n */\n service: string;\n\n /**\n * URL to fetch links from.\n */\n url: string;\n\n /**\n * Authorization header containing access token.\n */\n authorization?: string;\n}\n\nexport interface ServerRemote {\n /**\n * URL of the remote service.\n */\n url: string;\n\n /**\n * Name of the remote service.\n */\n name: string;\n\n /**\n * Expose links as endpoint. It's not only internal.\n */\n proxy: boolean;\n\n /**\n * It's only used inside the application.\n */\n internal: boolean;\n\n /**\n * Links fetcher.\n */\n links: (args: { authorization?: string }) => Promise<ApiRegistryResponse>;\n\n /**\n * Fetches schema for the remote service.\n */\n schema: (args: { name: string; authorization?: string }) => Promise<any>;\n\n /**\n * Force a default access token provider when not provided.\n */\n serviceAccount?: ServiceAccountPrimitive;\n\n /**\n * Prefix for the remote service links.\n */\n prefix: string;\n}\n","import { createHash } from \"node:crypto\";\nimport { $hook, $inject, $use, Alepha, AlephaError, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { SecurityProvider, UserAccountToken } from \"alepha/security\";\nimport {\n $action,\n $route,\n $sse,\n type ClientRequestEntry,\n type ClientRequestOptions,\n type RequestConfigSchema,\n ServerTimingProvider,\n serverApiOptions,\n} from \"alepha/server\";\nimport type { ApiRegistryResponse } from \"../schemas/apiLinksResponseSchema.ts\";\nimport { type HttpClientLink, LinkProvider } from \"./LinkProvider.ts\";\nimport { RemotePrimitiveProvider } from \"./RemotePrimitiveProvider.ts\";\n\nexport class ServerLinksProvider {\n protected readonly serverApi = $use(serverApiOptions);\n protected readonly alepha = $inject(Alepha);\n protected readonly linkProvider = $inject(LinkProvider);\n protected readonly remoteProvider = $inject(RemotePrimitiveProvider);\n protected readonly serverTimingProvider = $inject(ServerTimingProvider);\n protected readonly log = $logger();\n\n /**\n * Resolved once on start. Undefined when alepha/security is not loaded.\n */\n protected securityProvider: SecurityProvider | undefined;\n\n /**\n * Cache of serialized JSON by role key.\n * Key = sorted roles joined by comma (empty string for unauthenticated).\n */\n protected registryCache = new Map<string, RegistryCacheEntry>();\n\n public get prefix() {\n return this.serverApi.prefix;\n }\n\n public readonly onRoute = $hook({\n on: \"configure\",\n handler: () => {\n // convert all $action to local links\n for (const action of this.alepha.primitives($action)) {\n const bodyContentType = action.getBodyContentType();\n\n this.linkProvider.registerLink({\n name: action.name,\n group: action.group,\n schema: action.options.schema,\n contentType:\n bodyContentType && bodyContentType !== \"application/json\"\n ? bodyContentType\n : undefined,\n secured: action.middlewares.some((m) => m?.name === \"$secure\")\n ? (action.middlewares.find((m) => m?.name === \"$secure\")?.options ??\n true)\n : undefined,\n method: action.method === \"GET\" ? undefined : action.method,\n prefix: action.prefix,\n path: action.path,\n // by local, we mean that it can be called directly via the handler\n handler: (\n config: ClientRequestEntry<RequestConfigSchema>,\n options: ClientRequestOptions = {},\n ) => action.run(config, options),\n });\n }\n\n // convert all $sse to local links\n for (const sse of this.alepha.primitives($sse)) {\n this.linkProvider.registerLink({\n name: sse.name,\n group: sse.group,\n kind: \"sse\",\n schema: {\n body: sse.schema?.body,\n },\n method: \"POST\",\n prefix: sse.prefix,\n path: sse.path,\n handler: async (config) => {\n return sse.run(config as any) as any;\n },\n });\n }\n },\n });\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: () => {\n try {\n this.securityProvider =\n this.alepha.inject<SecurityProvider>(\"SecurityProvider\");\n } catch {\n this.log.debug(\n \"Security module is not loaded — permission checks are disabled\",\n );\n }\n },\n });\n\n /**\n * API registry endpoint — returns all available actions for the user.\n *\n * Response is filtered by the user's permissions.\n * Cached by role set with ETag support.\n */\n public readonly links = $route({\n path: LinkProvider.path.apiLinks,\n handler: async ({ user, headers, reply }) => {\n const roleKey = user?.roles?.slice().sort().join(\",\") ?? \"\";\n const cached = this.registryCache.get(roleKey);\n\n if (cached) {\n // ETag match → 304\n if (headers[\"if-none-match\"] === cached.etag) {\n reply.setStatus(304);\n reply.setHeader(\"etag\", cached.etag);\n return;\n }\n\n reply.setHeader(\"etag\", cached.etag);\n reply.setHeader(\"content-type\", \"application/json\");\n reply.body = cached.json;\n return;\n }\n\n // Cache miss — compute, serialize, cache\n const response = await this.getUserApiLinks({\n user,\n authorization: headers.authorization,\n });\n const json = JSON.stringify(response);\n const etag = `\"${createHash(\"md5\").update(json).digest(\"hex\")}\"`;\n\n this.registryCache.set(roleKey, { json, etag });\n\n reply.setHeader(\"etag\", etag);\n reply.setHeader(\"content-type\", \"application/json\");\n reply.body = json;\n },\n });\n\n /**\n * On-demand schemas endpoint — returns JSON Schemas for requested actions.\n *\n * Schemas are filtered by the user's permissions (same logic as the registry).\n */\n public readonly schemas = $route({\n method: \"POST\",\n path: \"/api/_links/schemas\",\n schema: {\n body: t.object({\n actions: t.array(t.text()),\n }),\n response: t.record(\n t.text(),\n t.object({\n body: t.optional(t.string()),\n response: t.optional(t.string()),\n }),\n ),\n },\n handler: async ({ body, user }) => {\n const result: Record<string, { body?: string; response?: string }> = {};\n\n for (const name of body.actions) {\n const link = this.linkProvider\n .getServerLinks()\n .find((l) => l.name === name && !l.host);\n\n if (!link) continue;\n if (!this.isLinkAccessible(link, user)) continue;\n\n const entry: { body?: string; response?: string } = {};\n if (link.schema?.body) {\n entry.body = JSON.stringify(link.schema.body);\n }\n if (link.schema?.response) {\n entry.response = JSON.stringify(link.schema.response);\n }\n result[name] = entry;\n }\n\n return result as any;\n },\n });\n\n /**\n * Batch endpoint — execute multiple actions in a single HTTP request.\n * Each sub-request is independent: errors in one don't affect others.\n */\n public readonly batch = $route({\n method: \"POST\",\n path: \"/api/_batch\",\n schema: {\n body: t.array(\n t.object({\n action: t.text(),\n params: t.optional(t.record(t.text(), t.any())),\n query: t.optional(t.record(t.text(), t.any())),\n body: t.optional(t.record(t.text(), t.any())),\n }),\n ),\n response: t.array(\n t.object({\n action: t.text(),\n status: t.integer(),\n data: t.optional(t.any()),\n error: t.optional(t.text()),\n }),\n ),\n },\n handler: async ({ body }) => {\n if (body.length > ServerLinksProvider.MAX_BATCH_SIZE) {\n throw new AlephaError(\n `Batch size ${body.length} exceeds maximum of ${ServerLinksProvider.MAX_BATCH_SIZE}`,\n );\n }\n\n const results = await Promise.allSettled(\n body.map((entry) =>\n this.linkProvider.follow(entry.action, {\n params: entry.params as any,\n query: entry.query as any,\n body: entry.body as any,\n }),\n ),\n );\n\n return results.map((result, i) => {\n const action = body[i].action;\n\n if (result.status === \"fulfilled\") {\n return { action, status: 200, data: result.value };\n }\n\n const reason = result.reason;\n const status = reason?.status ?? 500;\n const message = reason?.message ?? \"Internal error\";\n\n this.log.warn(\"Batch action failed\", {\n action,\n status,\n message,\n error: reason,\n });\n\n return { action, status, error: message };\n });\n },\n });\n\n protected static readonly MAX_BATCH_SIZE = 20;\n\n /**\n * Retrieves API registry for the user based on their permissions.\n * Will check on local links and remote links.\n */\n public async getUserApiLinks(\n options: GetApiLinksOptions,\n ): Promise<ApiRegistryResponse> {\n const { user } = options;\n const { securityProvider } = this;\n const securityPermissions =\n securityProvider && user\n ? securityProvider.getPermissions(user)\n : undefined;\n\n const actions: Record<string, any> = {};\n const permissions: string[] = [];\n\n // Collect permissions not related to $action (virtual permissions)\n for (const permission of securityPermissions ?? []) {\n if (\n !permission.path &&\n !permission.method &&\n permission.name &&\n permission.group\n ) {\n permissions.push(`${permission.group}:${permission.name}`);\n }\n }\n\n // Add local links\n for (const link of this.linkProvider.getServerLinks()) {\n // SKIP REMOTE LINKS, remote links are handled separately for security\n if (link.host) continue;\n if (!this.isLinkAccessible(link, user)) continue;\n\n actions[link.name] = {\n path: link.path,\n method: link.method || undefined,\n kind: link.kind,\n contentType: link.contentType,\n service: link.service,\n };\n }\n\n this.serverTimingProvider.beginTiming(\"fetchRemoteLinks\");\n // TODO: remote links can be cached by user.roles\n const remoteResults = await Promise.all(\n this.remoteProvider\n .getRemotes()\n .filter((it) => it.proxy) // add only \"proxy\" remotes\n .map(async (remote) => {\n const registry = await remote.links(options);\n return { remote, registry };\n }),\n );\n\n for (const { remote, registry } of remoteResults) {\n const remotePrefix = registry.prefix ?? \"/api\";\n\n // Merge remote actions\n for (const [name, action] of Object.entries(registry.actions)) {\n let path = action.path.replace(remotePrefix, \"\");\n if (action.service) {\n path = `/${action.service}${path}`;\n }\n\n actions[name] = {\n path,\n method: action.method,\n contentType: action.contentType,\n service: remote.name,\n };\n }\n\n // Merge remote permissions\n if (registry.permissions) {\n permissions.push(...registry.permissions);\n }\n }\n\n this.serverTimingProvider.endTiming(\"fetchRemoteLinks\");\n\n return {\n prefix: this.serverApi.prefix,\n actions,\n permissions: permissions.length > 0 ? permissions : undefined,\n };\n }\n\n /**\n * Check if a link is accessible by the given user based on security rules.\n */\n protected isLinkAccessible(\n link: HttpClientLink,\n user?: UserAccountToken,\n ): boolean {\n const { securityProvider } = this;\n\n if (securityProvider && link.secured) {\n if (!user) return false;\n\n if (typeof link.secured === \"object\") {\n // issuer check\n if (\n link.secured.issuers?.length &&\n (!user.realm || !link.secured.issuers.includes(user.realm))\n ) {\n return false;\n }\n\n // role check\n if (link.secured.roles?.length) {\n const hasRole = link.secured.roles.some((role: string) =>\n user.roles?.includes(role),\n );\n if (!hasRole) return false;\n }\n\n // explicit permission check\n if (link.secured.permissions?.length) {\n for (const perm of link.secured.permissions) {\n const result = securityProvider.checkPermission(\n perm,\n ...(user.roles ?? []),\n );\n if (!result.isAuthorized) return false;\n }\n }\n }\n // link.secured === true → auth only, user is already checked above\n }\n\n return true;\n }\n}\n\nexport interface GetApiLinksOptions {\n user?: UserAccountToken;\n authorization?: string;\n}\n\ninterface RegistryCacheEntry {\n json: string;\n etag: string;\n}\n","import { $module } from \"alepha\";\nimport { AlephaServer } from \"alepha/server\";\nimport { apiLinksAtom } from \"./atoms/apiLinksAtom.ts\";\nimport { linkOptionsAtom } from \"./atoms/linkOptionsAtom.ts\";\nimport { $client } from \"./primitives/$client.ts\";\nimport { $remote } from \"./primitives/$remote.ts\";\nimport { LinkProvider } from \"./providers/LinkProvider.ts\";\nimport { RemotePrimitiveProvider } from \"./providers/RemotePrimitiveProvider.ts\";\nimport { ServerLinksProvider } from \"./providers/ServerLinksProvider.ts\";\nimport type { ApiRegistryResponse } from \"./schemas/apiLinksResponseSchema.ts\";\nimport { BatchCollector } from \"./services/BatchCollector.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./atoms/apiLinksAtom.ts\";\nexport * from \"./atoms/linkOptionsAtom.ts\";\nexport * from \"./primitives/$client.ts\";\nexport * from \"./primitives/$remote.ts\";\nexport * from \"./providers/LinkProvider.ts\";\nexport * from \"./providers/RemotePrimitiveProvider.ts\";\nexport * from \"./providers/ServerLinksProvider.ts\";\nexport * from \"./schemas/apiLinksResponseSchema.ts\";\nexport * from \"./services/BatchCollector.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface State {\n /**\n * API registry attached to the server request state.\n *\n * @see {@link ApiRegistryResponse}\n * @internal\n */\n \"alepha.server.request.apiLinks\"?: ApiRegistryResponse;\n\n /**\n * Configuration options for the links module.\n */\n \"alepha.server.links.options\": {\n batch: boolean;\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Type-safe API client with request deduplication.\n *\n * **Features:**\n * - Virtual HTTP client for type-safe API calls\n * - Remote action definitions\n * - Type inference from action schemas\n * - Request deduplication\n * - Automatic error handling\n *\n * @module alepha.server.links\n */\nexport const AlephaServerLinks = $module({\n name: \"alepha.server.links\",\n atoms: [apiLinksAtom, linkOptionsAtom],\n primitives: [$remote, $client],\n services: [\n AlephaServer,\n ServerLinksProvider,\n RemotePrimitiveProvider,\n LinkProvider,\n BatchCollector,\n ],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/server/links/schemas/apiLinksResponseSchema.ts","../../../src/server/links/atoms/apiLinksAtom.ts","../../../src/server/links/atoms/linkOptionsAtom.ts","../../../src/server/links/services/BatchCollector.ts","../../../src/server/links/providers/LinkProvider.ts","../../../src/server/links/primitives/$client.ts","../../../src/server/links/primitives/$remote.ts","../../../src/server/links/providers/RemotePrimitiveProvider.ts","../../../src/server/links/providers/ServerLinksProvider.ts","../../../src/server/links/index.ts"],"sourcesContent":["import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\n\nexport const apiActionSchema = t.object({\n path: t.text({\n description: \"Pathname used to access the action.\",\n }),\n\n method: t.optional(\n t.text({\n description:\n \"HTTP method. Omitted when GET (the default for ~75% of actions).\",\n }),\n ),\n\n contentType: t.optional(\n t.text({\n description:\n \"Content type for the request body. Only present for non-JSON types (e.g. 'multipart/form-data'). When absent, defaults to application/json.\",\n }),\n ),\n\n kind: t.optional(\n t.text({\n description:\n \"Action kind. Used to distinguish special action types (e.g. 'sse' for Server-Sent Events streams).\",\n }),\n ),\n\n service: t.optional(\n t.text({\n description:\n \"Service name associated with the action, used for service discovery and routing.\",\n }),\n ),\n});\n\nexport const apiRegistryResponseSchema = t.object({\n prefix: t.optional(t.text()),\n\n actions: t.record(t.text(), apiActionSchema),\n\n permissions: t.optional(t.array(t.text())),\n});\n\nexport type ApiRegistryResponse = Static<typeof apiRegistryResponseSchema>;\nexport type ApiAction = Static<typeof apiActionSchema>;\n\n/**\n * @deprecated Use `apiRegistryResponseSchema` and `ApiRegistryResponse` instead.\n */\nexport const apiLinksResponseSchema = apiRegistryResponseSchema;\n\n/**\n * @deprecated Use `ApiRegistryResponse` instead.\n */\nexport type ApiLinksResponse = ApiRegistryResponse;\n\n/**\n * @deprecated Use `ApiAction` instead.\n */\nexport type ApiLink = ApiAction;\n","import { $atom, t } from \"alepha\";\nimport { apiRegistryResponseSchema } from \"../schemas/apiLinksResponseSchema.ts\";\n\nexport const apiLinksAtom = $atom({\n name: \"alepha.server.request.apiLinks\",\n schema: t.optional(apiRegistryResponseSchema),\n});\n","import { $atom, t } from \"alepha\";\n\nexport const linkOptionsAtom = $atom({\n name: \"alepha.server.links.options\",\n description: \"Configuration options for the links module.\",\n schema: t.object({\n batch: t.boolean({\n description: \"Enable batch collection for browser-side calls.\",\n default: true,\n }),\n }),\n default: {\n batch: true,\n },\n});\n","import { $inject } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { HttpClient, HttpError } from \"alepha/server\";\n\n/**\n * Collects browser-side action calls within a microtask and\n * sends them as a single `POST /api/_batch` request.\n *\n * Key behaviors:\n * - Single call in the window → direct HTTP call (no batch overhead)\n * - Multiple calls → coalesced into one batch request\n * - Same action + same params/query/body → deduplicated, result shared\n * - Exceeding MAX_BATCH_SIZE → split into multiple batch calls\n * - Transport failure → all pending promises reject\n */\nexport class BatchCollector {\n protected static readonly MAX_BATCH_SIZE = 20;\n\n protected readonly log = $logger();\n protected readonly httpClient = $inject(HttpClient);\n\n protected pending: PendingBatchEntry[] = [];\n protected scheduled = false;\n\n /**\n * Add an action call to the batch. Returns the result when the batch resolves.\n */\n public add(entry: BatchEntry): Promise<any> {\n return new Promise((resolve, reject) => {\n this.pending.push({ entry, resolve, reject });\n\n if (!this.scheduled) {\n this.scheduled = true;\n setTimeout(() => {\n this.scheduled = false;\n this.flush().catch((err) => this.log.error(err));\n }, 10);\n }\n });\n }\n\n protected async flush(): Promise<void> {\n const batch = this.pending.splice(0);\n\n if (batch.length === 0) return;\n\n // Single request — skip batching, call directly via follow\n if (batch.length === 1) {\n const item = batch[0];\n try {\n const result = await item.entry.directCall();\n item.resolve(result);\n } catch (error) {\n item.reject(error);\n }\n return;\n }\n\n // Deduplicate: same action + same params → share result\n const { unique, indexMap } = this.dedupe(batch);\n\n // Split into chunks of MAX_BATCH_SIZE\n const chunks = this.chunk(unique, BatchCollector.MAX_BATCH_SIZE);\n\n try {\n const allResults = (\n await Promise.all(\n chunks.map((chunk) => {\n const actions = [...new Set(chunk.map((b) => b.entry.action))].join(\n \",\",\n );\n\n return this.httpClient\n .fetch(`/api/_batch?actions=${actions}`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(\n chunk.map((b) => ({\n action: b.entry.action,\n params: b.entry.params,\n query: b.entry.query,\n body: b.entry.body,\n })),\n ),\n })\n .then((res) => res.data as BatchResponse[]);\n }),\n )\n ).flat();\n\n // Distribute results back (including deduped slots)\n for (let i = 0; i < batch.length; i++) {\n const result = allResults[indexMap[i]];\n if (result.status >= 400) {\n batch[i].reject(\n new HttpError({\n message:\n result.error ?? `${result.action} failed (${result.status})`,\n status: result.status,\n }),\n );\n } else {\n batch[i].resolve(result.data);\n }\n }\n } catch (error) {\n // Transport-level failure — reject all pending promises\n for (const item of batch) {\n item.reject(error);\n }\n }\n }\n\n protected dedupe(batch: PendingBatchEntry[]): {\n unique: PendingBatchEntry[];\n indexMap: number[];\n } {\n const seen = new Map<string, number>();\n const unique: PendingBatchEntry[] = [];\n const indexMap: number[] = [];\n\n for (const item of batch) {\n const key = `${item.entry.action}:${JSON.stringify({\n params: item.entry.params,\n query: item.entry.query,\n body: item.entry.body,\n })}`;\n\n const existing = seen.get(key);\n if (existing !== undefined) {\n indexMap.push(existing);\n } else {\n const idx = unique.length;\n seen.set(key, idx);\n unique.push(item);\n indexMap.push(idx);\n }\n }\n\n return { unique, indexMap };\n }\n\n protected chunk<T>(arr: T[], size: number): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n chunks.push(arr.slice(i, i + size));\n }\n return chunks;\n }\n}\n\n// ---\n\nexport interface BatchEntry {\n action: string;\n params?: Record<string, any>;\n query?: Record<string, any>;\n body?: Record<string, any>;\n directCall: () => Promise<any>;\n}\n\ninterface PendingBatchEntry {\n entry: BatchEntry;\n resolve: (value: any) => void;\n reject: (reason: any) => void;\n}\n\ninterface BatchResponse {\n action: string;\n status: number;\n data?: any;\n error?: string;\n}\n","import { $inject, $state, Alepha, AlephaError, type Async, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { SecureOptions } from \"alepha/security\";\nimport {\n type ActionPrimitive,\n type ClientRequestEntry,\n type ClientRequestOptions,\n type ClientRequestResponse,\n type FetchResponse,\n HttpClient,\n type RequestConfigSchema,\n ServerReply,\n type ServerRequest,\n type ServerRequestConfigEntry,\n type ServerResponseBody,\n type SseConfigSchema,\n type SseEventData,\n type SsePrimitive,\n type SseRequestEntry,\n type SseStream,\n UnauthorizedError,\n} from \"alepha/server\";\nimport { linkOptionsAtom } from \"../atoms/linkOptionsAtom.ts\";\nimport {\n type ApiRegistryResponse,\n apiRegistryResponseSchema,\n} from \"../schemas/apiLinksResponseSchema.ts\";\nimport { BatchCollector } from \"../services/BatchCollector.ts\";\n\n/**\n * Browser, SSR friendly, service to handle links.\n */\nexport class LinkProvider {\n static path = {\n apiLinks: \"/api/_links\",\n };\n\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly httpClient = $inject(HttpClient);\n\n // Server-side: all registered links (local + remote), keyed by name\n protected serverLinkMap = new Map<string, HttpClientLink>();\n\n // Browser/SSR: parsed from the registry response\n protected actionMap = new Map<string, HttpClientLink>();\n protected permissions = new Set<string>();\n protected lastLoadedRegistry: ApiRegistryResponse | null = null;\n\n // Browser-only: batch collector for coalescing multiple calls\n protected batchCollector?: BatchCollector;\n\n protected readonly options = $state(linkOptionsAtom);\n\n /**\n * Get applicative links registered on the server.\n * This does not include lazy-loaded remote links.\n */\n public getServerLinks(): HttpClientLink[] {\n if (this.alepha.isBrowser()) {\n this.log.warn(\n \"Getting server links in the browser is not supported. Use `fetchLinks` to get links from the server.\",\n );\n return [];\n }\n\n return [...this.serverLinkMap.values()];\n }\n\n /**\n * Register a new link for the application.\n */\n public registerLink(link: HttpClientLink): void {\n if (this.alepha.isBrowser()) {\n this.log.warn(\n \"Registering links in the browser is not supported. Use `fetchLinks` to get links from the server.\",\n );\n return;\n }\n\n if (!link.handler && !link.host) {\n throw new AlephaError(\n \"Can't create link - 'handler' or 'host' is required\",\n );\n }\n\n // Detect duplicate local actions (programming error)\n const existing = this.serverLinkMap.get(link.name);\n if (existing?.handler && link.handler) {\n throw new AlephaError(\n `Duplicate action name \"${link.name}\". Each action must have a unique name.`,\n );\n }\n\n this.serverLinkMap.set(link.name, link);\n }\n\n /**\n * Load the registry response into internal stores (actionMap, permissions, definitions).\n * Called when storing from atom/fetch/SSR.\n */\n protected loadRegistry(registry: ApiRegistryResponse): void {\n this.lastLoadedRegistry = registry;\n this.permissions.clear();\n this.actionMap.clear();\n\n for (const [name, action] of Object.entries(registry.actions)) {\n this.actionMap.set(name, {\n name,\n path: action.path,\n kind: action.kind,\n method: action.method,\n contentType: action.contentType,\n service: action.service,\n });\n }\n\n if (registry.permissions) {\n for (const p of registry.permissions) {\n this.permissions.add(p);\n }\n }\n }\n\n public get links(): HttpClientLink[] {\n const registry = this.alepha.store.get(\"alepha.server.request.apiLinks\");\n\n if (registry) {\n if (this.alepha.isBrowser()) {\n // Browser side: use the parsed action map\n // Reload when registry changes (e.g. after login provides new authenticated links)\n if (this.actionMap.size === 0 || registry !== this.lastLoadedRegistry) {\n this.loadRegistry(registry);\n }\n return [...this.actionMap.values()];\n }\n\n // SSR side: map registry actions back to full server links\n const links: HttpClientLink[] = [];\n for (const name of Object.keys(registry.actions)) {\n const originalLink = this.serverLinkMap.get(name);\n if (originalLink) {\n links.push(originalLink);\n }\n }\n return links;\n }\n\n return [...this.serverLinkMap.values()];\n }\n\n /**\n * Force browser to refresh links from the server.\n */\n public async fetchLinks(): Promise<HttpClientLink[]> {\n const { data } = await this.httpClient.fetch(\n `${LinkProvider.path.apiLinks}`,\n {\n method: \"GET\",\n schema: {\n response: apiRegistryResponseSchema,\n },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data);\n this.loadRegistry(data);\n\n return [...this.actionMap.values()];\n }\n\n /**\n * Create a virtual client that can be used to call actions.\n *\n * Use js Proxy under the hood.\n */\n public client<T extends object>(\n scope: ClientScope = {},\n ): HttpVirtualClient<T> {\n return new Proxy<HttpVirtualClient<T>>({} as HttpVirtualClient<T>, {\n get: (_, prop) => {\n if (typeof prop !== \"string\") {\n return;\n }\n\n return this.createVirtualAction<RequestConfigSchema>(prop, scope);\n },\n });\n }\n\n /**\n * Check if a link with the given name exists or a permission matches.\n *\n * Action names never contain colons. Permission names always do.\n * - `can(\"getUsers\")` → O(1) map lookup\n * - `can(\"admin:*\")` → wildcard match against permissions set\n * - `can(\"admin:user:read\")` → O(1) set lookup\n */\n public can(name: string): boolean {\n // Action check — O(1) map lookup\n if (this.actionMap.size > 0) {\n if (this.actionMap.has(name)) return true;\n } else {\n // Fallback for server-side where actionMap may not be populated\n if (this.serverLinkMap.has(name)) return true;\n // Also check links getter (for SSR with atom)\n if (this.links.some((link) => link.name === name)) return true;\n }\n\n // Permission check — wildcard matching\n if (name.includes(\":\")) {\n if (name.endsWith(\"*\")) {\n const prefix = name.slice(0, -1);\n for (const p of this.permissions) {\n if (p.startsWith(prefix)) return true;\n }\n return false;\n }\n return this.permissions.has(name);\n }\n\n return false;\n }\n\n /**\n * Resolve a link by its name and call it.\n * - If link is local, it will call the local handler.\n * - If link is remote, it will make a fetch request to the remote server.\n */\n public async follow(\n name: string,\n config: Partial<ServerRequestConfigEntry> = {},\n options: ClientRequestOptions & ClientScope = {},\n ): Promise<any> {\n this.log.trace(\"Following link\", { name, config, options });\n const link = await this.getLinkByName(name, options);\n\n // if a handler is defined, use it (ssr)\n if (link.handler && !options.request) {\n this.log.trace(\"Local link found\", { name });\n return link.handler(\n {\n method: link.method,\n url: new URL(`http://localhost${link.path}`),\n query: config.query ?? {},\n body: config.body ?? {},\n params: config.params ?? {},\n headers: config.headers ?? {},\n metadata: {},\n reply: new ServerReply(),\n } as Partial<ServerRequest> as ServerRequest,\n options,\n );\n }\n\n this.log.trace(\"Remote link found\", {\n name,\n host: link.host,\n service: link.service,\n });\n\n // Browser-only: use batch collector for calls without explicit host\n if (this.options.batch && this.alepha.isBrowser() && !link.host) {\n this.batchCollector ??= this.alepha.inject(BatchCollector);\n return this.batchCollector.add({\n action: name,\n params: config.params as any,\n query: config.query as any,\n body: config.body as any,\n directCall: () =>\n this.followRemote(link, config, options).then((r) => r.data),\n });\n }\n\n return this.followRemote(link, config, options).then(\n (response) => response.data,\n );\n }\n\n protected createVirtualAction<T extends RequestConfigSchema>(\n name: string,\n scope: ClientScope = {},\n ): VirtualAction<T> {\n const $: VirtualAction<T> = async (\n config: any = {},\n options: ClientRequestOptions = {},\n ) => {\n return this.follow(name, config, {\n ...scope,\n ...options,\n });\n };\n\n Object.defineProperty($, \"name\", {\n value: name,\n writable: false,\n });\n\n $.run = async (config: any = {}, options: ClientRequestOptions = {}) => {\n return this.follow(name, config, {\n ...scope,\n ...options,\n });\n };\n\n $.fetch = async (config: any = {}, options: ClientRequestOptions = {}) => {\n const link = await this.getLinkByName(name, scope);\n return this.followRemote(link, config, options);\n };\n\n $.can = () => {\n return this.can(name);\n };\n\n return $;\n }\n\n protected async followRemote(\n link: HttpClientLink,\n config: Partial<ServerRequestConfigEntry> = {},\n options: ClientRequestOptions = {},\n ): Promise<FetchResponse> {\n options.request ??= {};\n options.request.headers = new Headers(options.request.headers);\n\n const als = this.alepha.store.get(\"alepha.http.request\");\n if (als?.headers.authorization) {\n options.request.headers.set(\"authorization\", als.headers.authorization);\n }\n\n const context = this.alepha.context.get(\"context\");\n if (typeof context === \"string\") {\n options.request.headers.set(\"x-request-id\", context);\n }\n\n const action = {\n ...link,\n // schema is not used in the client,\n // we assume that TypeScript will check\n schema: {\n body: t.any(),\n response: t.any(),\n },\n };\n\n // prefix with service when host is not defined (e.g. browser)\n if (!link.host && link.service) {\n action.path = `/${link.service}${action.path}`;\n }\n\n action.path = `${action.prefix ?? \"/api\"}${action.path}`;\n action.prefix = undefined; // prefix is not used in the client\n\n // else, make a request\n return this.httpClient.fetchAction({\n host: link.host,\n config,\n options,\n action: action as any, // schema.body TAny is not accepted\n });\n }\n\n protected async getLinkByName(\n name: string,\n options: ClientScope = {},\n ): Promise<HttpClientLink> {\n if (\n this.alepha.isBrowser() &&\n !this.alepha.store.get(\"alepha.server.request.apiLinks\")\n ) {\n await this.fetchLinks();\n }\n\n const link = this.links.find(\n (a) =>\n a.name === name && (!options.service || options.service === a.service),\n );\n\n if (!link) {\n const error = new UnauthorizedError(`Action ${name} not found.`);\n // mimic http error handling\n await this.alepha.events.emit(\"client:onError\", {\n route: link,\n error,\n });\n throw error;\n }\n\n if (options.hostname) {\n return {\n ...link,\n host: options.hostname,\n };\n }\n\n return link;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface HttpClientLink {\n name: string;\n path: string;\n method?: string;\n kind?: string;\n contentType?: string;\n service?: string;\n secured?: boolean | SecureOptions;\n prefix?: string;\n group?: string;\n // -- server only --\n host?: string;\n schema?: RequestConfigSchema;\n handler?: (\n request: ServerRequest,\n options: ClientRequestOptions,\n ) => Async<ServerResponseBody>;\n}\n\nexport interface ClientScope {\n service?: string;\n hostname?: string;\n}\n\nexport type HttpVirtualClient<T> = {\n [K in keyof T as T[K] extends ActionPrimitive<RequestConfigSchema>\n ? K\n : never]: T[K] extends ActionPrimitive<infer Schema>\n ? VirtualAction<Schema>\n : never;\n} & {\n [K in keyof T as T[K] extends SsePrimitive<SseConfigSchema>\n ? K\n : never]: T[K] extends SsePrimitive<infer Schema>\n ? VirtualSse<Schema>\n : never;\n};\n\nexport interface VirtualAction<T extends RequestConfigSchema>\n extends Pick<ActionPrimitive<T>, \"name\" | \"run\" | \"fetch\"> {\n (\n config?: ClientRequestEntry<T>,\n opts?: ClientRequestOptions,\n ): Promise<ClientRequestResponse<T>>;\n can: () => boolean;\n}\n\nexport interface VirtualSse<T extends SseConfigSchema> {\n (config?: SseRequestEntry<T>): Promise<SseStream<SseEventData<T>>>;\n name: string;\n can: () => boolean;\n}\n","import { $inject, KIND } from \"alepha\";\nimport {\n type ClientScope,\n type HttpVirtualClient,\n LinkProvider,\n} from \"../providers/LinkProvider.ts\";\n\n/**\n * Create a new client.\n */\nexport const $client = <T extends object>(\n scope?: ClientScope,\n): HttpVirtualClient<T> => {\n return $inject(LinkProvider).client<T>(scope);\n};\n\n$client[KIND] = \"$client\";\n","import { createPrimitive, KIND, Primitive } from \"alepha\";\nimport type { ServiceAccountPrimitive } from \"alepha/security\";\nimport type { ProxyPrimitiveOptions } from \"alepha/server/proxy\";\n\n/**\n * $remote is a primitive that allows you to define remote service access.\n *\n * Use it only when you have 2 or more services that need to communicate with each other.\n *\n * All remote services can be exposed as actions, ... or not.\n *\n * You can add a service account if you want to use a security layer.\n */\nexport const $remote = (options: RemotePrimitiveOptions) => {\n return createPrimitive(RemotePrimitive, options);\n};\n\nexport interface RemotePrimitiveOptions {\n /**\n * The URL of the remote service.\n * You can use a function to generate the URL dynamically.\n * You probably should use $env(env) to get the URL from the environment.\n *\n * @example\n * ```ts\n * import { $remote } from \"alepha/server\";\n * import { $inject, t } from \"alepha\";\n *\n * class App {\n * env = $env(t.object({\n * REMOTE_URL: t.text({default: \"http://localhost:3000\"}),\n * }));\n * remote = $remote({\n * url: this.env.REMOTE_URL,\n * });\n * }\n * ```\n */\n url: string | (() => string);\n\n /**\n * The name of the remote service.\n *\n * @default Member of the class containing the remote service.\n */\n name?: string;\n\n /**\n * If true, all methods of the remote service will be exposed as actions in this context.\n * > Note: Proxy will never use the service account, it just... proxies the request.\n */\n proxy?:\n | boolean\n | Partial<\n ProxyPrimitiveOptions & {\n /**\n * If true, the remote service won't be available internally, only through the proxy.\n */\n noInternal: boolean;\n }\n >;\n\n /**\n * For communication between the server and the remote service with a security layer.\n * This will be used for internal communication and will not be exposed to the client.\n */\n serviceAccount?: ServiceAccountPrimitive;\n}\n\nexport class RemotePrimitive extends Primitive<RemotePrimitiveOptions> {\n public get name(): string {\n return this.options.name ?? this.config.propertyKey;\n }\n}\n\n$remote[KIND] = RemotePrimitive;\n","import { $hook, $inject, $pipeline, $state, Alepha, AlephaError } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { $retry } from \"alepha/retry\";\nimport type { ServiceAccountPrimitive } from \"alepha/security\";\nimport { serverApiOptions } from \"alepha/server\";\nimport { ServerProxyProvider } from \"alepha/server/proxy\";\nimport { $remote, type RemotePrimitive } from \"../primitives/$remote.ts\";\nimport {\n type ApiRegistryResponse,\n apiRegistryResponseSchema,\n} from \"../schemas/apiLinksResponseSchema.ts\";\nimport { LinkProvider } from \"./LinkProvider.ts\";\n\nexport class RemotePrimitiveProvider {\n protected readonly serverApi = $state(serverApiOptions);\n protected readonly alepha = $inject(Alepha);\n protected readonly proxyProvider = $inject(ServerProxyProvider);\n protected readonly linkProvider = $inject(LinkProvider);\n protected readonly remotes: Array<ServerRemote> = [];\n protected readonly log = $logger();\n\n public getRemotes(): ServerRemote[] {\n return this.remotes;\n }\n\n public readonly configure = $hook({\n on: \"configure\",\n handler: async () => {\n const remotes = this.alepha.primitives($remote);\n for (const remote of remotes) {\n await this.registerRemote(remote);\n }\n },\n });\n\n public readonly start = $hook({\n on: \"start\",\n handler: async () => {\n for (const remote of this.remotes) {\n const token =\n typeof remote.serviceAccount?.token === \"function\"\n ? await remote.serviceAccount.token()\n : undefined;\n\n if (!remote.internal) {\n continue; // skip download links for remotes that are not internal\n }\n\n const registry = await remote.links({ authorization: token });\n\n for (const [name, action] of Object.entries(registry.actions)) {\n let path = action.path.replace(remote.prefix, \"\");\n if (action.service) {\n path = `/${action.service}${path}`;\n }\n\n this.linkProvider.registerLink({\n name,\n path,\n method: action.method ?? undefined,\n contentType: action.contentType,\n prefix: remote.prefix,\n host: remote.url,\n service: remote.name,\n });\n }\n\n this.log.info(`Remote '${remote.name}' OK`, {\n actions: Object.keys(registry.actions).length,\n prefix: remote.prefix,\n });\n }\n },\n });\n\n public async registerRemote(value: RemotePrimitive): Promise<void> {\n const options = value.options;\n const url = typeof options.url === \"string\" ? options.url : options.url();\n const linkPath = LinkProvider.path.apiLinks;\n const name = value.name;\n const proxy = typeof options.proxy === \"object\" ? options.proxy : {};\n\n const remote: ServerRemote = {\n url,\n name,\n prefix: \"/api\",\n serviceAccount: options.serviceAccount,\n proxy: !!options.proxy,\n internal: !proxy.noInternal,\n schema: async (opts) => {\n const { authorization, name } = opts;\n return await fetch(`${url}${linkPath}/${name}/schema`, {\n headers: new Headers(\n authorization\n ? {\n authorization,\n }\n : {},\n ),\n }).then((it) => it.json()); // TODO: use schema validation for response\n },\n links: async (opts) => {\n const { authorization } = opts;\n const remoteApi = await this.fetchLinks.run({\n service: name,\n url: `${url}${linkPath}`,\n authorization,\n });\n\n if (remoteApi.prefix != null) {\n remote.prefix = remoteApi.prefix; // monkey patch the prefix, not ideal but works\n }\n\n return remoteApi;\n },\n };\n\n this.remotes.push(remote);\n\n if (options.proxy) {\n this.proxyProvider.createProxy({\n path: `${this.serverApi.prefix}/${name}/*`,\n target: url,\n rewrite: (url) => {\n url.pathname = url.pathname.replace(\n `${this.serverApi.prefix}/${name}`,\n remote.prefix,\n );\n },\n ...proxy,\n });\n }\n }\n\n protected readonly fetchLinks = $pipeline({\n use: [\n $retry({\n max: 10,\n backoff: {\n initial: 1000,\n },\n onError: (_: Error, attempt: number) => {\n this.log.warn(`Failed to fetch links, retry (${attempt})...`);\n },\n }),\n ],\n handler: async (opts: FetchLinksOptions): Promise<ApiRegistryResponse> => {\n const { url, authorization } = opts;\n const response = await fetch(url, {\n headers: new Headers(\n authorization\n ? {\n authorization,\n }\n : {},\n ),\n });\n\n if (!response.ok) {\n throw new AlephaError(`Failed to fetch links from ${url}`);\n }\n\n return this.alepha.codec.decode(\n apiRegistryResponseSchema,\n await response.json(),\n );\n },\n });\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface FetchLinksOptions {\n /**\n * Name of the remote service.\n */\n service: string;\n\n /**\n * URL to fetch links from.\n */\n url: string;\n\n /**\n * Authorization header containing access token.\n */\n authorization?: string;\n}\n\nexport interface ServerRemote {\n /**\n * URL of the remote service.\n */\n url: string;\n\n /**\n * Name of the remote service.\n */\n name: string;\n\n /**\n * Expose links as endpoint. It's not only internal.\n */\n proxy: boolean;\n\n /**\n * It's only used inside the application.\n */\n internal: boolean;\n\n /**\n * Links fetcher.\n */\n links: (args: { authorization?: string }) => Promise<ApiRegistryResponse>;\n\n /**\n * Fetches schema for the remote service.\n */\n schema: (args: { name: string; authorization?: string }) => Promise<any>;\n\n /**\n * Force a default access token provider when not provided.\n */\n serviceAccount?: ServiceAccountPrimitive;\n\n /**\n * Prefix for the remote service links.\n */\n prefix: string;\n}\n","import { createHash } from \"node:crypto\";\nimport { $hook, $inject, $state, Alepha, AlephaError, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { SecurityProvider, UserAccountToken } from \"alepha/security\";\nimport {\n $action,\n $route,\n $sse,\n type ClientRequestEntry,\n type ClientRequestOptions,\n type RequestConfigSchema,\n ServerTimingProvider,\n serverApiOptions,\n} from \"alepha/server\";\nimport type { ApiRegistryResponse } from \"../schemas/apiLinksResponseSchema.ts\";\nimport { type HttpClientLink, LinkProvider } from \"./LinkProvider.ts\";\nimport { RemotePrimitiveProvider } from \"./RemotePrimitiveProvider.ts\";\n\nexport class ServerLinksProvider {\n protected readonly serverApi = $state(serverApiOptions);\n protected readonly alepha = $inject(Alepha);\n protected readonly linkProvider = $inject(LinkProvider);\n protected readonly remoteProvider = $inject(RemotePrimitiveProvider);\n protected readonly serverTimingProvider = $inject(ServerTimingProvider);\n protected readonly log = $logger();\n\n /**\n * Resolved once on start. Undefined when alepha/security is not loaded.\n */\n protected securityProvider: SecurityProvider | undefined;\n\n /**\n * Cache of serialized JSON by role key.\n * Key = sorted roles joined by comma (empty string for unauthenticated).\n */\n protected registryCache = new Map<string, RegistryCacheEntry>();\n\n public get prefix() {\n return this.serverApi.prefix;\n }\n\n public readonly onRoute = $hook({\n on: \"configure\",\n handler: () => {\n // convert all $action to local links\n for (const action of this.alepha.primitives($action)) {\n const bodyContentType = action.getBodyContentType();\n\n this.linkProvider.registerLink({\n name: action.name,\n group: action.group,\n schema: action.options.schema,\n contentType:\n bodyContentType && bodyContentType !== \"application/json\"\n ? bodyContentType\n : undefined,\n secured: action.middlewares.some((m) => m?.name === \"$secure\")\n ? (action.middlewares.find((m) => m?.name === \"$secure\")?.options ??\n true)\n : undefined,\n method: action.method === \"GET\" ? undefined : action.method,\n prefix: action.prefix,\n path: action.path,\n // by local, we mean that it can be called directly via the handler\n handler: (\n config: ClientRequestEntry<RequestConfigSchema>,\n options: ClientRequestOptions = {},\n ) => action.run(config, options),\n });\n }\n\n // convert all $sse to local links\n for (const sse of this.alepha.primitives($sse)) {\n this.linkProvider.registerLink({\n name: sse.name,\n group: sse.group,\n kind: \"sse\",\n schema: {\n body: sse.schema?.body,\n },\n method: \"POST\",\n prefix: sse.prefix,\n path: sse.path,\n handler: async (config) => {\n return sse.run(config as any) as any;\n },\n });\n }\n },\n });\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: () => {\n try {\n this.securityProvider =\n this.alepha.inject<SecurityProvider>(\"SecurityProvider\");\n } catch {\n this.log.debug(\n \"Security module is not loaded — permission checks are disabled\",\n );\n }\n },\n });\n\n /**\n * API registry endpoint — returns all available actions for the user.\n *\n * Response is filtered by the user's permissions.\n * Cached by role set with ETag support.\n */\n public readonly links = $route({\n path: LinkProvider.path.apiLinks,\n handler: async ({ user, headers, reply }) => {\n const roleKey = user?.roles?.slice().sort().join(\",\") ?? \"\";\n const cached = this.registryCache.get(roleKey);\n\n if (cached) {\n // ETag match → 304\n if (headers[\"if-none-match\"] === cached.etag) {\n reply.setStatus(304);\n reply.setHeader(\"etag\", cached.etag);\n return;\n }\n\n reply.setHeader(\"etag\", cached.etag);\n reply.setHeader(\"content-type\", \"application/json\");\n reply.body = cached.json;\n return;\n }\n\n // Cache miss — compute, serialize, cache\n const response = await this.getUserApiLinks({\n user,\n authorization: headers.authorization,\n });\n const json = JSON.stringify(response);\n const etag = `\"${createHash(\"md5\").update(json).digest(\"hex\")}\"`;\n\n this.registryCache.set(roleKey, { json, etag });\n\n reply.setHeader(\"etag\", etag);\n reply.setHeader(\"content-type\", \"application/json\");\n reply.body = json;\n },\n });\n\n /**\n * On-demand schemas endpoint — returns JSON Schemas for requested actions.\n *\n * Schemas are filtered by the user's permissions (same logic as the registry).\n */\n public readonly schemas = $route({\n method: \"POST\",\n path: \"/api/_links/schemas\",\n schema: {\n body: t.object({\n actions: t.array(t.text()),\n }),\n response: t.record(\n t.text(),\n t.object({\n body: t.optional(t.string()),\n response: t.optional(t.string()),\n }),\n ),\n },\n handler: async ({ body, user }) => {\n const result: Record<string, { body?: string; response?: string }> = {};\n\n for (const name of body.actions) {\n const link = this.linkProvider\n .getServerLinks()\n .find((l) => l.name === name && !l.host);\n\n if (!link) continue;\n if (!this.isLinkAccessible(link, user)) continue;\n\n const entry: { body?: string; response?: string } = {};\n if (link.schema?.body) {\n entry.body = JSON.stringify(link.schema.body);\n }\n if (link.schema?.response) {\n entry.response = JSON.stringify(link.schema.response);\n }\n result[name] = entry;\n }\n\n return result as any;\n },\n });\n\n /**\n * Batch endpoint — execute multiple actions in a single HTTP request.\n * Each sub-request is independent: errors in one don't affect others.\n */\n public readonly batch = $route({\n method: \"POST\",\n path: \"/api/_batch\",\n schema: {\n body: t.array(\n t.object({\n action: t.text(),\n params: t.optional(t.record(t.text(), t.any())),\n query: t.optional(t.record(t.text(), t.any())),\n body: t.optional(t.record(t.text(), t.any())),\n }),\n ),\n response: t.array(\n t.object({\n action: t.text(),\n status: t.integer(),\n data: t.optional(t.any()),\n error: t.optional(t.text()),\n }),\n ),\n },\n handler: async ({ body }) => {\n if (body.length > ServerLinksProvider.MAX_BATCH_SIZE) {\n throw new AlephaError(\n `Batch size ${body.length} exceeds maximum of ${ServerLinksProvider.MAX_BATCH_SIZE}`,\n );\n }\n\n const results = await Promise.allSettled(\n body.map((entry) =>\n this.linkProvider.follow(entry.action, {\n params: entry.params as any,\n query: entry.query as any,\n body: entry.body as any,\n }),\n ),\n );\n\n return results.map((result, i) => {\n const action = body[i].action;\n\n if (result.status === \"fulfilled\") {\n return { action, status: 200, data: result.value };\n }\n\n const reason = result.reason;\n const status = reason?.status ?? 500;\n const message = reason?.message ?? \"Internal error\";\n\n this.log.warn(\"Batch action failed\", {\n action,\n status,\n message,\n error: reason,\n });\n\n return { action, status, error: message };\n });\n },\n });\n\n protected static readonly MAX_BATCH_SIZE = 20;\n\n /**\n * Retrieves API registry for the user based on their permissions.\n * Will check on local links and remote links.\n */\n public async getUserApiLinks(\n options: GetApiLinksOptions,\n ): Promise<ApiRegistryResponse> {\n const { user } = options;\n const { securityProvider } = this;\n const securityPermissions =\n securityProvider && user\n ? securityProvider.getPermissions(user)\n : undefined;\n\n const actions: Record<string, any> = {};\n const permissions: string[] = [];\n\n // Collect permissions not related to $action (virtual permissions)\n for (const permission of securityPermissions ?? []) {\n if (\n !permission.path &&\n !permission.method &&\n permission.name &&\n permission.group\n ) {\n permissions.push(`${permission.group}:${permission.name}`);\n }\n }\n\n // Add local links\n for (const link of this.linkProvider.getServerLinks()) {\n // SKIP REMOTE LINKS, remote links are handled separately for security\n if (link.host) continue;\n if (!this.isLinkAccessible(link, user)) continue;\n\n actions[link.name] = {\n path: link.path,\n method: link.method || undefined,\n kind: link.kind,\n contentType: link.contentType,\n service: link.service,\n };\n }\n\n this.serverTimingProvider.beginTiming(\"fetchRemoteLinks\");\n // TODO: remote links can be cached by user.roles\n const remoteResults = await Promise.all(\n this.remoteProvider\n .getRemotes()\n .filter((it) => it.proxy) // add only \"proxy\" remotes\n .map(async (remote) => {\n const registry = await remote.links(options);\n return { remote, registry };\n }),\n );\n\n for (const { remote, registry } of remoteResults) {\n const remotePrefix = registry.prefix ?? \"/api\";\n\n // Merge remote actions\n for (const [name, action] of Object.entries(registry.actions)) {\n let path = action.path.replace(remotePrefix, \"\");\n if (action.service) {\n path = `/${action.service}${path}`;\n }\n\n actions[name] = {\n path,\n method: action.method,\n contentType: action.contentType,\n service: remote.name,\n };\n }\n\n // Merge remote permissions\n if (registry.permissions) {\n permissions.push(...registry.permissions);\n }\n }\n\n this.serverTimingProvider.endTiming(\"fetchRemoteLinks\");\n\n return {\n prefix: this.serverApi.prefix,\n actions,\n permissions: permissions.length > 0 ? permissions : undefined,\n };\n }\n\n /**\n * Check if a link is accessible by the given user based on security rules.\n */\n protected isLinkAccessible(\n link: HttpClientLink,\n user?: UserAccountToken,\n ): boolean {\n const { securityProvider } = this;\n\n if (securityProvider && link.secured) {\n if (!user) return false;\n\n if (typeof link.secured === \"object\") {\n // issuer check\n if (\n link.secured.issuers?.length &&\n (!user.realm || !link.secured.issuers.includes(user.realm))\n ) {\n return false;\n }\n\n // role check\n if (link.secured.roles?.length) {\n const hasRole = link.secured.roles.some((role: string) =>\n user.roles?.includes(role),\n );\n if (!hasRole) return false;\n }\n\n // explicit permission check\n if (link.secured.permissions?.length) {\n for (const perm of link.secured.permissions) {\n const result = securityProvider.checkPermission(\n perm,\n ...(user.roles ?? []),\n );\n if (!result.isAuthorized) return false;\n }\n }\n }\n // link.secured === true → auth only, user is already checked above\n }\n\n return true;\n }\n}\n\nexport interface GetApiLinksOptions {\n user?: UserAccountToken;\n authorization?: string;\n}\n\ninterface RegistryCacheEntry {\n json: string;\n etag: string;\n}\n","import { $module } from \"alepha\";\nimport { AlephaServer } from \"alepha/server\";\nimport { apiLinksAtom } from \"./atoms/apiLinksAtom.ts\";\nimport { linkOptionsAtom } from \"./atoms/linkOptionsAtom.ts\";\nimport { $client } from \"./primitives/$client.ts\";\nimport { $remote } from \"./primitives/$remote.ts\";\nimport { LinkProvider } from \"./providers/LinkProvider.ts\";\nimport { RemotePrimitiveProvider } from \"./providers/RemotePrimitiveProvider.ts\";\nimport { ServerLinksProvider } from \"./providers/ServerLinksProvider.ts\";\nimport type { ApiRegistryResponse } from \"./schemas/apiLinksResponseSchema.ts\";\nimport { BatchCollector } from \"./services/BatchCollector.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./atoms/apiLinksAtom.ts\";\nexport * from \"./atoms/linkOptionsAtom.ts\";\nexport * from \"./primitives/$client.ts\";\nexport * from \"./primitives/$remote.ts\";\nexport * from \"./providers/LinkProvider.ts\";\nexport * from \"./providers/RemotePrimitiveProvider.ts\";\nexport * from \"./providers/ServerLinksProvider.ts\";\nexport * from \"./schemas/apiLinksResponseSchema.ts\";\nexport * from \"./services/BatchCollector.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface State {\n /**\n * API registry attached to the server request state.\n *\n * @see {@link ApiRegistryResponse}\n * @internal\n */\n \"alepha.server.request.apiLinks\"?: ApiRegistryResponse;\n\n /**\n * Configuration options for the links module.\n */\n \"alepha.server.links.options\": {\n batch: boolean;\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Type-safe API client with request deduplication.\n *\n * **Features:**\n * - Virtual HTTP client for type-safe API calls\n * - Remote action definitions\n * - Type inference from action schemas\n * - Request deduplication\n * - Automatic error handling\n *\n * @module alepha.server.links\n */\nexport const AlephaServerLinks = $module({\n name: \"alepha.server.links\",\n atoms: [apiLinksAtom, linkOptionsAtom],\n primitives: [$remote, $client],\n services: [\n AlephaServer,\n ServerLinksProvider,\n RemotePrimitiveProvider,\n LinkProvider,\n BatchCollector,\n ],\n});\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as alepha from "alepha";
|
|
1
|
+
import * as _$alepha from "alepha";
|
|
2
2
|
import { Alepha } from "alepha";
|
|
3
|
-
import * as alepha_server0 from "alepha/server";
|
|
3
|
+
import * as _$alepha_server0 from "alepha/server";
|
|
4
4
|
|
|
5
5
|
//#region ../../../../node_modules/prom-client/index.d.ts
|
|
6
6
|
// Type definitions for prom-client
|
|
@@ -522,10 +522,10 @@ declare class ServerMetricsProvider {
|
|
|
522
522
|
protected readonly alepha: Alepha;
|
|
523
523
|
protected httpRequestDuration?: Histogram<string>;
|
|
524
524
|
readonly options: ServerMetricsProviderOptions;
|
|
525
|
-
readonly metrics: alepha_server0.RoutePrimitive<alepha_server0.RequestConfigSchema>;
|
|
526
|
-
protected readonly onStart: alepha.HookPrimitive<"start">;
|
|
527
|
-
protected readonly onRequest: alepha.HookPrimitive<"server:onRequest">;
|
|
528
|
-
protected readonly onResponse: alepha.HookPrimitive<"server:onResponse">;
|
|
525
|
+
readonly metrics: _$alepha_server0.RoutePrimitive<_$alepha_server0.RequestConfigSchema>;
|
|
526
|
+
protected readonly onStart: _$alepha.HookPrimitive<"start">;
|
|
527
|
+
protected readonly onRequest: _$alepha.HookPrimitive<"server:onRequest">;
|
|
528
|
+
protected readonly onResponse: _$alepha.HookPrimitive<"server:onResponse">;
|
|
529
529
|
}
|
|
530
530
|
interface ServerMetricsProviderOptions {
|
|
531
531
|
prefix?: string;
|
|
@@ -545,7 +545,7 @@ interface ServerMetricsProviderOptions {
|
|
|
545
545
|
*
|
|
546
546
|
* @module alepha.server.metrics
|
|
547
547
|
*/
|
|
548
|
-
declare const AlephaServerMetrics: alepha.Service<alepha.Module>;
|
|
548
|
+
declare const AlephaServerMetrics: _$alepha.Service<_$alepha.Module>;
|
|
549
549
|
//#endregion
|
|
550
550
|
export { AlephaServerMetrics, ServerMetricsProvider, ServerMetricsProviderOptions };
|
|
551
551
|
//# sourceMappingURL=index.d.ts.map
|