@undefineds.co/xpod 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +164 -3
- package/config/cli.json +9 -71
- package/config/cloud.json +34 -7
- package/config/local.json +6 -2
- package/config/resolver.json +11 -49
- package/config/runtime-open.json +22 -0
- package/config/xpod.base.json +32 -0
- package/config/xpod.cluster.json +2 -44
- package/config/xpod.json +5 -2
- package/dist/agents/AgentExecutorFactory.js +1 -1
- package/dist/agents/AgentExecutorFactory.js.map +1 -1
- package/dist/agents/AgentManager.js +1 -1
- package/dist/agents/AgentManager.js.map +1 -1
- package/dist/agents/config/agent-meta-schema.d.ts +7 -7
- package/dist/agents/config/agent-meta-schema.js +1 -1
- package/dist/agents/config/agent-meta-schema.js.map +1 -1
- package/dist/agents/config/resolve.js +1 -1
- package/dist/agents/config/resolve.js.map +1 -1
- package/dist/agents/schema/agent-config.d.ts +18 -18
- package/dist/agents/schema/agent-config.js +1 -1
- package/dist/agents/schema/agent-config.js.map +1 -1
- package/dist/agents/schema/tables.d.ts +8 -8
- package/dist/agents/schema/tables.js +1 -1
- package/dist/agents/schema/tables.js.map +1 -1
- package/dist/ai/schema/config.d.ts +7 -7
- package/dist/ai/schema/config.js +1 -1
- package/dist/ai/schema/config.js.map +1 -1
- package/dist/ai/schema/model.d.ts +13 -13
- package/dist/ai/schema/model.js +1 -1
- package/dist/ai/schema/model.js.map +1 -1
- package/dist/ai/schema/provider.d.ts +7 -7
- package/dist/ai/schema/provider.js +1 -1
- package/dist/ai/schema/provider.js.map +1 -1
- package/dist/ai/schema/vector-store.d.ts +17 -17
- package/dist/ai/schema/vector-store.js +1 -1
- package/dist/ai/schema/vector-store.js.map +1 -1
- package/dist/ai/service/CredentialReaderImpl.js +1 -1
- package/dist/ai/service/CredentialReaderImpl.js.map +1 -1
- package/dist/ai/service/DefaultAiConfigService.js.map +1 -1
- package/dist/api/ApiServer.d.ts +3 -1
- package/dist/api/ApiServer.js +14 -1
- package/dist/api/ApiServer.js.map +1 -1
- package/dist/api/auth/AuthContext.d.ts +12 -1
- package/dist/api/auth/AuthContext.js +18 -1
- package/dist/api/auth/AuthContext.js.map +1 -1
- package/dist/api/auth/ClientCredentialsAuthenticator.d.ts +0 -1
- package/dist/api/auth/ClientCredentialsAuthenticator.js.map +1 -1
- package/dist/api/auth/ServiceTokenAuthenticator.d.ts +18 -0
- package/dist/api/auth/ServiceTokenAuthenticator.js +50 -0
- package/dist/api/auth/ServiceTokenAuthenticator.js.map +1 -0
- package/dist/api/auth/index.d.ts +1 -0
- package/dist/api/auth/index.js +1 -0
- package/dist/api/auth/index.js.map +1 -1
- package/dist/api/chatkit/ai-provider.d.ts +0 -10
- package/dist/api/chatkit/ai-provider.js +11 -120
- package/dist/api/chatkit/ai-provider.js.map +1 -1
- package/dist/api/chatkit/default-agent.js +11 -8
- package/dist/api/chatkit/default-agent.js.map +1 -1
- package/dist/api/chatkit/pod-store.d.ts +6 -0
- package/dist/api/chatkit/pod-store.js +103 -36
- package/dist/api/chatkit/pod-store.js.map +1 -1
- package/dist/api/chatkit/schema.d.ts +32 -26
- package/dist/api/chatkit/schema.js +16 -8
- package/dist/api/chatkit/schema.js.map +1 -1
- package/dist/api/container/business-token.d.ts +9 -0
- package/dist/api/container/business-token.js +32 -0
- package/dist/api/container/business-token.js.map +1 -0
- package/dist/api/container/cloud.js +36 -12
- package/dist/api/container/cloud.js.map +1 -1
- package/dist/api/container/common.js +13 -5
- package/dist/api/container/common.js.map +1 -1
- package/dist/api/container/index.js +94 -14
- package/dist/api/container/index.js.map +1 -1
- package/dist/api/container/local.js +2 -1
- package/dist/api/container/local.js.map +1 -1
- package/dist/api/container/routes.js +81 -9
- package/dist/api/container/routes.js.map +1 -1
- package/dist/api/container/types.d.ts +8 -6
- package/dist/api/container/types.js.map +1 -1
- package/dist/api/handlers/AdminHandler.js +9 -9
- package/dist/api/handlers/AdminHandler.js.map +1 -1
- package/dist/api/handlers/ApiKeyHandler.js +0 -6
- package/dist/api/handlers/ApiKeyHandler.js.map +1 -1
- package/dist/api/handlers/EdgeNodeSignalHandler.d.ts +17 -0
- package/dist/api/handlers/EdgeNodeSignalHandler.js +171 -0
- package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -0
- package/dist/api/handlers/PodManagementHandler.d.ts +5 -4
- package/dist/api/handlers/PodManagementHandler.js +11 -10
- package/dist/api/handlers/PodManagementHandler.js.map +1 -1
- package/dist/api/handlers/ProvisionHandler.d.ts +42 -0
- package/dist/api/handlers/ProvisionHandler.js +161 -0
- package/dist/api/handlers/ProvisionHandler.js.map +1 -0
- package/dist/api/handlers/QuotaHandler.d.ts +7 -7
- package/dist/api/handlers/QuotaHandler.js +143 -73
- package/dist/api/handlers/QuotaHandler.js.map +1 -1
- package/dist/api/handlers/SubdomainClientHandler.js +2 -2
- package/dist/api/handlers/SubdomainClientHandler.js.map +1 -1
- package/dist/api/handlers/SubdomainHandler.js +13 -8
- package/dist/api/handlers/SubdomainHandler.js.map +1 -1
- package/dist/api/handlers/UsageHandler.d.ts +14 -0
- package/dist/api/handlers/UsageHandler.js +123 -0
- package/dist/api/handlers/UsageHandler.js.map +1 -0
- package/dist/api/handlers/index.d.ts +3 -1
- package/dist/api/handlers/index.js +3 -1
- package/dist/api/handlers/index.js.map +1 -1
- package/dist/api/main.js +18 -0
- package/dist/api/main.js.map +1 -1
- package/dist/api/middleware/OpenAuthMiddleware.d.ts +12 -0
- package/dist/api/middleware/OpenAuthMiddleware.js +27 -0
- package/dist/api/middleware/OpenAuthMiddleware.js.map +1 -0
- package/dist/api/runtime.d.ts +15 -0
- package/dist/api/runtime.js +125 -0
- package/dist/api/runtime.js.map +1 -0
- package/dist/api/service/VectorStoreService.js +1 -1
- package/dist/api/service/VectorStoreService.js.map +1 -1
- package/dist/api/service/VercelChatService.d.ts +16 -7
- package/dist/api/service/VercelChatService.js +98 -178
- package/dist/api/service/VercelChatService.js.map +1 -1
- package/dist/api/store/DrizzleClientCredentialsStore.d.ts +6 -11
- package/dist/api/store/DrizzleClientCredentialsStore.js +9 -39
- package/dist/api/store/DrizzleClientCredentialsStore.js.map +1 -1
- package/dist/authorization/AuthModeSelector.d.ts +10 -0
- package/dist/authorization/AuthModeSelector.js +27 -0
- package/dist/authorization/AuthModeSelector.js.map +1 -0
- package/dist/authorization/AuthModeSelector.jsonld +81 -0
- package/dist/cli/commands/account.d.ts +6 -0
- package/dist/cli/commands/account.js +119 -0
- package/dist/cli/commands/account.js.map +1 -0
- package/dist/cli/commands/auth.js +20 -29
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/backup.d.ts +15 -0
- package/dist/cli/commands/backup.js +286 -0
- package/dist/cli/commands/backup.js.map +1 -0
- package/dist/cli/commands/config.d.ts +34 -3
- package/dist/cli/commands/config.js +195 -258
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +6 -0
- package/dist/cli/commands/doctor.js +94 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/pod.d.ts +6 -0
- package/dist/cli/commands/pod.js +124 -0
- package/dist/cli/commands/pod.js.map +1 -0
- package/dist/cli/commands/start.js +28 -5
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/index.js +9 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/lib/credentials-store.d.ts +17 -0
- package/dist/cli/lib/credentials-store.js +73 -0
- package/dist/cli/lib/credentials-store.js.map +1 -0
- package/dist/cli/lib/css-account.d.ts +17 -0
- package/dist/cli/lib/css-account.js +56 -0
- package/dist/cli/lib/css-account.js.map +1 -1
- package/dist/cli/lib/pod-thread-store.d.ts +57 -0
- package/dist/cli/lib/pod-thread-store.js +310 -0
- package/dist/cli/lib/pod-thread-store.js.map +1 -0
- package/dist/cli/lib/solid-auth.d.ts +20 -0
- package/dist/cli/lib/solid-auth.js +70 -0
- package/dist/cli/lib/solid-auth.js.map +1 -0
- package/dist/components/components.jsonld +5 -8
- package/dist/components/context.jsonld +114 -244
- package/dist/credential/schema/tables.d.ts +14 -14
- package/dist/credential/schema/tables.js +1 -1
- package/dist/credential/schema/tables.js.map +1 -1
- package/dist/edge/EdgeNodeAgent.js +2 -2
- package/dist/edge/EdgeNodeAgent.js.map +1 -1
- package/dist/edge/EdgeNodeDnsCoordinator.d.ts +1 -7
- package/dist/edge/EdgeNodeDnsCoordinator.js +31 -41
- package/dist/edge/EdgeNodeDnsCoordinator.js.map +1 -1
- package/dist/edge/EdgeNodeDnsCoordinator.jsonld +1 -27
- package/dist/edge/EdgeNodeModeDetector.d.ts +1 -1
- package/dist/edge/EdgeNodeModeDetector.js +9 -11
- package/dist/edge/EdgeNodeModeDetector.js.map +1 -1
- package/dist/http/ClusterIngressRouter.js +3 -3
- package/dist/http/ClusterIngressRouter.js.map +1 -1
- package/dist/http/ClusterWebSocketConfigurator.js +2 -2
- package/dist/http/ClusterWebSocketConfigurator.js.map +1 -1
- package/dist/http/PodRoutingHttpHandler.js +2 -2
- package/dist/http/PodRoutingHttpHandler.js.map +1 -1
- package/dist/http/cluster/PodMigrationHttpHandler.d.ts +1 -1
- package/dist/http/cluster/PodMigrationHttpHandler.js +1 -1
- package/dist/http/cluster/PodMigrationHttpHandler.js.map +1 -1
- package/dist/identity/drizzle/EdgeNodeRepository.d.ts +37 -4
- package/dist/identity/drizzle/EdgeNodeRepository.js +120 -128
- package/dist/identity/drizzle/EdgeNodeRepository.js.map +1 -1
- package/dist/identity/drizzle/ServiceTokenRepository.d.ts +52 -0
- package/dist/identity/drizzle/ServiceTokenRepository.js +142 -0
- package/dist/identity/drizzle/ServiceTokenRepository.js.map +1 -0
- package/dist/identity/drizzle/db.d.ts +9 -0
- package/dist/identity/drizzle/db.js +235 -3
- package/dist/identity/drizzle/db.js.map +1 -1
- package/dist/identity/drizzle/schema.pg.d.ts +5 -0
- package/dist/identity/drizzle/schema.pg.js +49 -20
- package/dist/identity/drizzle/schema.pg.js.map +1 -1
- package/dist/identity/drizzle/schema.sqlite.d.ts +332 -57
- package/dist/identity/drizzle/schema.sqlite.js +48 -18
- package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
- package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js +6 -4
- package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js.map +1 -1
- package/dist/index.d.ts +6 -9
- package/dist/index.js +12 -14
- package/dist/index.js.map +1 -1
- package/dist/main.js +25 -8
- package/dist/main.js.map +1 -1
- package/dist/provision/ProvisionCodeCodec.d.ts +39 -0
- package/dist/provision/ProvisionCodeCodec.js +65 -0
- package/dist/provision/ProvisionCodeCodec.js.map +1 -0
- package/dist/provision/ProvisionCodeCodec.jsonld +47 -0
- package/dist/provision/ProvisionPodCreator.d.ts +20 -0
- package/dist/provision/ProvisionPodCreator.js +84 -0
- package/dist/provision/ProvisionPodCreator.js.map +1 -0
- package/dist/provision/ProvisionPodCreator.jsonld +118 -0
- package/dist/quota/DrizzleQuotaService.d.ts +17 -3
- package/dist/quota/DrizzleQuotaService.js +108 -8
- package/dist/quota/DrizzleQuotaService.js.map +1 -1
- package/dist/quota/DrizzleQuotaService.jsonld +33 -22
- package/dist/quota/NoopQuotaService.d.ts +7 -1
- package/dist/quota/NoopQuotaService.js +12 -0
- package/dist/quota/NoopQuotaService.js.map +1 -1
- package/dist/quota/NoopQuotaService.jsonld +24 -0
- package/dist/quota/QuotaService.d.ts +17 -0
- package/dist/quota/QuotaService.js +5 -0
- package/dist/quota/QuotaService.js.map +1 -1
- package/dist/quota/QuotaService.jsonld +50 -0
- package/dist/runtime/Proxy.d.ts +22 -4
- package/dist/runtime/Proxy.js +154 -35
- package/dist/runtime/Proxy.js.map +1 -1
- package/dist/runtime/XpodRuntime.d.ts +49 -0
- package/dist/runtime/XpodRuntime.js +374 -0
- package/dist/runtime/XpodRuntime.js.map +1 -0
- package/dist/runtime/env-utils.d.ts +2 -0
- package/dist/runtime/env-utils.js +55 -0
- package/dist/runtime/env-utils.js.map +1 -0
- package/dist/runtime/index.d.ts +4 -0
- package/dist/runtime/index.js +8 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/socket-fetch.d.ts +1 -0
- package/dist/runtime/socket-fetch.js +72 -0
- package/dist/runtime/socket-fetch.js.map +1 -0
- package/dist/runtime/socket-http.d.ts +1 -0
- package/dist/runtime/socket-http.js +142 -0
- package/dist/runtime/socket-http.js.map +1 -0
- package/dist/runtime/socket-utils.d.ts +2 -0
- package/dist/runtime/socket-utils.js +34 -0
- package/dist/runtime/socket-utils.js.map +1 -0
- package/dist/service/{EdgeNodeHeartbeatService.d.ts → EdgeNodeSignalClient.d.ts} +3 -3
- package/dist/service/{EdgeNodeHeartbeatService.js → EdgeNodeSignalClient.js} +4 -4
- package/dist/service/EdgeNodeSignalClient.js.map +1 -0
- package/dist/service/PodMigrationService.d.ts +1 -2
- package/dist/service/PodMigrationService.js +1 -2
- package/dist/service/PodMigrationService.js.map +1 -1
- package/dist/storage/SparqlUpdateResourceStore.js +1 -1
- package/dist/storage/SparqlUpdateResourceStore.js.map +1 -1
- package/dist/storage/accessors/MinioDataAccessor.d.ts +6 -0
- package/dist/storage/accessors/MinioDataAccessor.js +10 -0
- package/dist/storage/accessors/MinioDataAccessor.js.map +1 -1
- package/dist/storage/accessors/MinioDataAccessor.jsonld +4 -0
- package/dist/storage/accessors/MixDataAccessor.d.ts +2 -1
- package/dist/storage/accessors/MixDataAccessor.js +12 -1
- package/dist/storage/accessors/MixDataAccessor.js.map +1 -1
- package/dist/storage/accessors/MixDataAccessor.jsonld +19 -0
- package/dist/storage/locking/UrlAwareRedisLocker.d.ts +18 -0
- package/dist/storage/locking/UrlAwareRedisLocker.js +60 -0
- package/dist/storage/locking/UrlAwareRedisLocker.js.map +1 -0
- package/dist/storage/locking/UrlAwareRedisLocker.jsonld +123 -0
- package/dist/storage/quota/UsageRepository.d.ts +41 -8
- package/dist/storage/quota/UsageRepository.js +252 -50
- package/dist/storage/quota/UsageRepository.js.map +1 -1
- package/dist/storage/sparql/ComunicaQuintEngine.d.ts +9 -0
- package/dist/storage/sparql/ComunicaQuintEngine.js +50 -9
- package/dist/storage/sparql/ComunicaQuintEngine.js.map +1 -1
- package/dist/storage/sparql/QueryOptimizer.js +13 -1
- package/dist/storage/sparql/QueryOptimizer.js.map +1 -1
- package/dist/storage/sparql/QuintQuerySource.d.ts +14 -0
- package/dist/storage/sparql/QuintQuerySource.js +152 -1
- package/dist/storage/sparql/QuintQuerySource.js.map +1 -1
- package/dist/storage/sparql/SubgraphQueryEngine.d.ts +1 -0
- package/dist/storage/sparql/SubgraphQueryEngine.js +6 -2
- package/dist/storage/sparql/SubgraphQueryEngine.js.map +1 -1
- package/dist/storage/sparql/SubgraphQueryEngine.jsonld +4 -0
- package/dist/subdomain/SubdomainClient.d.ts +3 -3
- package/dist/subdomain/SubdomainClient.js +1 -1
- package/dist/subdomain/SubdomainClient.js.map +1 -1
- package/dist/subdomain/SubdomainService.d.ts +15 -16
- package/dist/subdomain/SubdomainService.js +80 -54
- package/dist/subdomain/SubdomainService.js.map +1 -1
- package/dist/subdomain/SubdomainService.jsonld +22 -26
- package/dist/supervisor/Supervisor.d.ts +7 -2
- package/dist/supervisor/Supervisor.js +33 -1
- package/dist/supervisor/Supervisor.js.map +1 -1
- package/dist/task/DrizzleTaskQueue.d.ts +1 -1
- package/dist/task/DrizzleTaskQueue.js +1 -1
- package/dist/task/DrizzleTaskQueue.js.map +1 -1
- package/dist/task/schema.d.ts +10 -10
- package/dist/task/schema.js +1 -1
- package/dist/task/schema.js.map +1 -1
- package/dist/test-utils/index.d.ts +4 -0
- package/dist/test-utils/index.js +8 -0
- package/dist/test-utils/index.js.map +1 -0
- package/dist/test-utils/no-auth-xpod.d.ts +11 -0
- package/dist/test-utils/no-auth-xpod.js +25 -0
- package/dist/test-utils/no-auth-xpod.js.map +1 -0
- package/dist/test-utils/seed-pod.d.ts +5 -0
- package/dist/test-utils/seed-pod.js +61 -0
- package/dist/test-utils/seed-pod.js.map +1 -0
- package/package.json +38 -10
- package/templates/identity/account/create-pod.html.ejs +110 -0
- package/templates/main.html.ejs +10 -0
- package/dist/api/handlers/DevHandler.d.ts +0 -18
- package/dist/api/handlers/DevHandler.js +0 -276
- package/dist/api/handlers/DevHandler.js.map +0 -1
- package/dist/api/handlers/SignalHandler.d.ts +0 -13
- package/dist/api/handlers/SignalHandler.js +0 -122
- package/dist/api/handlers/SignalHandler.js.map +0 -1
- package/dist/gateway/Proxy.d.ts +0 -24
- package/dist/gateway/Proxy.js +0 -209
- package/dist/gateway/Proxy.js.map +0 -1
- package/dist/gateway/Supervisor.d.ts +0 -2
- package/dist/gateway/Supervisor.js +0 -7
- package/dist/gateway/Supervisor.js.map +0 -1
- package/dist/gateway/port-finder.d.ts +0 -4
- package/dist/gateway/port-finder.js +0 -15
- package/dist/gateway/port-finder.js.map +0 -1
- package/dist/gateway/types.d.ts +0 -1
- package/dist/gateway/types.js +0 -3
- package/dist/gateway/types.js.map +0 -1
- package/dist/http/SignalInterceptHttpHandler.d.ts +0 -24
- package/dist/http/SignalInterceptHttpHandler.js +0 -47
- package/dist/http/SignalInterceptHttpHandler.js.map +0 -1
- package/dist/http/SignalInterceptHttpHandler.jsonld +0 -103
- package/dist/http/admin/EdgeNodeSignalHttpHandler.d.ts +0 -71
- package/dist/http/admin/EdgeNodeSignalHttpHandler.js +0 -674
- package/dist/http/admin/EdgeNodeSignalHttpHandler.js.map +0 -1
- package/dist/http/admin/EdgeNodeSignalHttpHandler.jsonld +0 -406
- package/dist/http/cluster/PodMigrationHttpHandler.jsonld +0 -169
- package/dist/quota/DefaultQuotaService.d.ts +0 -16
- package/dist/quota/DefaultQuotaService.js +0 -37
- package/dist/quota/DefaultQuotaService.js.map +0 -1
- package/dist/quota/DefaultQuotaService.jsonld +0 -85
- package/dist/service/EdgeNodeHeartbeatService.js.map +0 -1
- package/dist/service/PodMigrationService.jsonld +0 -76
- package/dist/storage/MigratableDataAccessor.d.ts +0 -63
- package/dist/storage/MigratableDataAccessor.js +0 -11
- package/dist/storage/MigratableDataAccessor.js.map +0 -1
- package/dist/storage/MigratableDataAccessor.jsonld +0 -60
- package/dist/storage/accessors/TieredMinioDataAccessor.d.ts +0 -150
- package/dist/storage/accessors/TieredMinioDataAccessor.js +0 -582
- package/dist/storage/accessors/TieredMinioDataAccessor.js.map +0 -1
- package/dist/storage/accessors/TieredMinioDataAccessor.jsonld +0 -333
- package/static/app/assets/index.css +0 -1
- package/static/app/assets/main.js +0 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PodManagementHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/PodManagementHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ServerResponse, IncomingMessage } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { ApiServer } from '../ApiServer';\n\nexport interface PodManagementHandlerOptions {\n /** Pod 存储根目录 */\n rootDir: string;\n /** 验证 IdP service token */\n verifyServiceToken: (token: string) => Promise<boolean>;\n /** 可选:限制允许的 pod 名称正则 */\n podNameRegex?: RegExp;\n}\n\nexport interface CreatePodRequest {\n /** Pod 名称(通常是用户名) */\n podName: string;\n /** 可选:初始资源 */\n initialResources?: Record<string, string>;\n}\n\nexport interface CreatePodResponse {\n success: boolean;\n podUrl: string;\n message: string;\n}\n\nexport interface DeletePodResponse {\n success: boolean;\n message: string;\n}\n\n/**\n * Pod Management Handler\n *\n * SP (Storage Provider) 端供 IdP 调用的 API。\n * 用于创建/删除 Pod 目录。\n *\n * 端点:\n * - POST /api/v1/pods - 创建 Pod\n * - DELETE /api/v1/pods/:podName - 删除 Pod\n *\n * 认证:\n * - 使用 IdP service token (Bearer)\n * - 验证 token 是否来自信任的 IdP\n */\nexport function registerPodManagementRoutes(\n server: ApiServer,\n options: PodManagementHandlerOptions\n): void {\n const logger = getLoggerFor('PodManagementHandler');\n const { rootDir, verifyServiceToken, podNameRegex = /^[a-zA-Z0-9_-]+$/ } = options;\n\n /**\n * 验证 service token\n */\n async function authenticate(request: IncomingMessage): Promise<boolean> {\n const authHeader = request.headers.authorization;\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return false;\n }\n const token = authHeader.slice(7);\n return verifyServiceToken(token);\n }\n\n /**\n * 验证 pod 名称\n */\n function validatePodName(podName: string): boolean {\n if (!podName || podName.length < 1 || podName.length > 64) {\n return false;\n }\n return podNameRegex.test(podName);\n }\n\n /**\n * POST /api/v1/pods\n *\n * 创建 Pod 目录\n *\n * Request:\n * Authorization: Bearer {service_token}\n * Content-Type: application/json\n * Body: { podName: \"alice\", initialResources?: {...} }\n *\n * Response:\n * 201: { success: true, podUrl: \"https://node1.pods.site/alice/\" }\n * 400: { error: \"Invalid pod name\" }\n * 401: { error: \"Unauthorized\" }\n * 409: { error: \"Pod already exists\" }\n */\n server.post('/api/v1/pods', async (request, response) => {\n // 1. 认证\n if (!await authenticate(request)) {\n sendJson(response, 401, { error: 'Unauthorized', message: 'Invalid or missing service token' });\n return;\n }\n\n // 2. 解析请求体\n let body: CreatePodRequest;\n try {\n body = await readJsonBody(request) as CreatePodRequest;\n } catch (error) {\n sendJson(response, 400, { error: 'Bad Request', message: 'Invalid JSON body' });\n return;\n }\n\n const { podName, initialResources } = body;\n\n // 3. 验证 pod 名称\n if (!validatePodName(podName)) {\n sendJson(response, 400, {\n error: 'Bad Request',\n message: `Invalid pod name: ${podName}. Must match ${podNameRegex.toString()}`\n });\n return;\n }\n\n // 4. 检查是否已存在\n const podPath = `${rootDir}/${podName}`;\n try {\n const exists = await fileExists(podPath);\n if (exists) {\n sendJson(response, 409, { error: 'Conflict', message: `Pod ${podName} already exists` });\n return;\n }\n } catch (error) {\n logger.error(`Error checking pod existence: ${(error as Error).message}`);\n sendJson(response, 500, { error: 'Internal Server Error', message: 'Failed to check pod existence' });\n return;\n }\n\n // 5. 创建 Pod 目录\n try {\n await createPodDirectory(podPath, initialResources);\n logger.info(`Created pod: ${podName} at ${podPath}`);\n\n // 构建 pod URL (基于请求的 host)\n const host = request.headers.host || 'localhost';\n const podUrl = `https://${host}/${podName}/`;\n\n sendJson(response, 201, {\n success: true,\n podUrl,\n message: `Pod ${podName} created successfully`\n });\n } catch (error) {\n logger.error(`Failed to create pod: ${(error as Error).message}`);\n sendJson(response, 500, { error: 'Internal Server Error', message: 'Failed to create pod' });\n }\n }, { public: true }); // Service token auth handled internally\n\n /**\n * DELETE /api/v1/pods/:podName\n *\n * 删除 Pod 目录\n *\n * Request:\n * Authorization: Bearer {service_token}\n *\n * Response:\n * 200: { success: true }\n * 401: { error: \"Unauthorized\" }\n * 404: { error: \"Pod not found\" }\n */\n server.delete('/api/v1/pods/:podName', async (request, response, params) => {\n // 1. 认证\n if (!await authenticate(request)) {\n sendJson(response, 401, { error: 'Unauthorized', message: 'Invalid or missing service token' });\n return;\n }\n\n const podName = decodeURIComponent(params.podName);\n\n // 2. 验证 pod 名称\n if (!validatePodName(podName)) {\n sendJson(response, 400, { error: 'Bad Request', message: `Invalid pod name: ${podName}` });\n return;\n }\n\n // 3. 检查是否存在\n const podPath = `${rootDir}/${podName}`;\n try {\n const exists = await fileExists(podPath);\n if (!exists) {\n sendJson(response, 404, { error: 'Not Found', message: `Pod ${podName} not found` });\n return;\n }\n } catch (error) {\n logger.error(`Error checking pod existence: ${(error as Error).message}`);\n sendJson(response, 500, { error: 'Internal Server Error', message: 'Failed to check pod existence' });\n return;\n }\n\n // 4. 删除 Pod 目录\n try {\n await deletePodDirectory(podPath);\n logger.info(`Deleted pod: ${podName}`);\n\n sendJson(response, 200, {\n success: true,\n message: `Pod ${podName} deleted successfully`\n });\n } catch (error) {\n logger.error(`Failed to delete pod: ${(error as Error).message}`);\n sendJson(response, 500, { error: 'Internal Server Error', message: 'Failed to delete pod' });\n }\n }, { public: true });\n\n /**\n * GET /api/v1/pods/:podName\n *\n * 获取 Pod 信息(存在性检查)\n */\n server.get('/api/v1/pods/:podName', async (request, response, params) => {\n // 1. 认证\n if (!await authenticate(request)) {\n sendJson(response, 401, { error: 'Unauthorized', message: 'Invalid or missing service token' });\n return;\n }\n\n const podName = decodeURIComponent(params.podName);\n const podPath = `${rootDir}/${podName}`;\n\n try {\n const exists = await fileExists(podPath);\n if (!exists) {\n sendJson(response, 404, { error: 'Not Found', message: `Pod ${podName} not found` });\n return;\n }\n\n const host = request.headers.host || 'localhost';\n const podUrl = `https://${host}/${podName}/`;\n\n sendJson(response, 200, {\n exists: true,\n podName,\n podUrl,\n storagePath: podPath\n });\n } catch (error) {\n logger.error(`Error getting pod info: ${(error as Error).message}`);\n sendJson(response, 500, { error: 'Internal Server Error', message: 'Failed to get pod info' });\n }\n }, { public: true });\n\n logger.info(`Pod management routes registered with rootDir: ${rootDir}`);\n}\n\n/**\n * 读取 JSON 请求体\n */\nasync function readJsonBody(request: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve({});\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch (error) {\n reject(error);\n }\n });\n request.on('error', reject);\n });\n}\n\n/**\n * 发送 JSON 响应\n */\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data));\n}\n\n/**\n * 检查文件/目录是否存在\n */\nasync function fileExists(path: string): Promise<boolean> {\n const { stat } = await import('node:fs/promises');\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * 创建 Pod 目录\n */\nasync function createPodDirectory(\n podPath: string,\n initialResources?: Record<string, string>\n): Promise<void> {\n const { mkdir, writeFile } = await import('node:fs/promises');\n const { join } = await import('node:path');\n\n // 创建目录\n await mkdir(podPath, { recursive: true });\n\n // 创建初始资源\n if (initialResources) {\n for (const [filename, content] of Object.entries(initialResources)) {\n const filePath = join(podPath, filename);\n await writeFile(filePath, content, 'utf8');\n }\n }\n}\n\n/**\n * 删除 Pod 目录\n */\nasync function deletePodDirectory(podPath: string): Promise<void> {\n const { rm } = await import('node:fs/promises');\n await rm(podPath, { recursive: true, force: true });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"PodManagementHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/PodManagementHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ServerResponse, IncomingMessage } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { ApiServer } from '../ApiServer';\n\nexport interface PodManagementHandlerOptions {\n /** Pod 存储根目录 */\n rootDir: string;\n /** 验证 IdP service token */\n verifyServiceToken: (token: string) => Promise<boolean>;\n /** 可选:限制允许的 pod 名称正则 */\n podNameRegex?: RegExp;\n}\n\nexport interface CreatePodRequest {\n /** Pod 名称(通常是用户名) */\n podName: string;\n /** 可选:初始资源 */\n initialResources?: Record<string, string>;\n}\n\nexport interface CreatePodResponse {\n success: boolean;\n podUrl: string;\n message: string;\n}\n\nexport interface DeletePodResponse {\n success: boolean;\n message: string;\n}\n\n/**\n * Pod Management Handler\n *\n * SP (Storage Provider) 端供 IdP 调用的 API。\n * 用于创建/删除/查询 Pod 目录。\n *\n * 端点 (Solid Storage Provision Protocol):\n * - POST /provision/pods - 创建 Pod\n * - GET /provision/pods/:podName - 查询 Pod\n * - DELETE /provision/pods/:podName - 删除 Pod\n *\n * 认证:\n * - 使用 IdP service token (Bearer)\n * - 验证 token 是否来自信任的 IdP\n */\nexport function registerPodManagementRoutes(\n server: ApiServer,\n options: PodManagementHandlerOptions\n): void {\n const logger = getLoggerFor('PodManagementHandler');\n const { rootDir, verifyServiceToken, podNameRegex = /^[a-zA-Z0-9_-]+$/ } = options;\n\n /**\n * 验证 service token\n */\n async function authenticate(request: IncomingMessage): Promise<boolean> {\n const authHeader = request.headers.authorization;\n if (!authHeader || !authHeader.startsWith('Bearer ')) {\n return false;\n }\n const token = authHeader.slice(7);\n return verifyServiceToken(token);\n }\n\n /**\n * 验证 pod 名称\n */\n function validatePodName(podName: string): boolean {\n if (!podName || podName.length < 1 || podName.length > 64) {\n return false;\n }\n return podNameRegex.test(podName);\n }\n\n /**\n * POST /provision/pods\n *\n * 创建 Pod 目录\n *\n * Request:\n * Authorization: Bearer {service_token}\n * Content-Type: application/json\n * Body: { podName: \"alice\", initialResources?: {...} }\n *\n * Response:\n * 201: { success: true, podUrl: \"https://node1.pods.site/alice/\" }\n * 400: { error: \"Invalid pod name\" }\n * 401: { error: \"Unauthorized\" }\n * 409: { error: \"Pod already exists\" }\n */\n server.post('/provision/pods', async (request, response) => {\n // 1. 认证\n if (!await authenticate(request)) {\n sendJson(response, 401, { error: 'Unauthorized', message: 'Invalid or missing service token' });\n return;\n }\n\n // 2. 解析请求体\n let body: CreatePodRequest;\n try {\n body = await readJsonBody(request) as CreatePodRequest;\n } catch (error) {\n sendJson(response, 400, { error: 'Bad Request', message: 'Invalid JSON body' });\n return;\n }\n\n const { podName, initialResources } = body;\n\n // 3. 验证 pod 名称\n if (!validatePodName(podName)) {\n sendJson(response, 400, {\n error: 'Bad Request',\n message: `Invalid pod name: ${podName}. Must match ${podNameRegex.toString()}`\n });\n return;\n }\n\n // 4. 检查是否已存在\n const podPath = `${rootDir}/${podName}`;\n try {\n const exists = await fileExists(podPath);\n if (exists) {\n sendJson(response, 409, { error: 'Conflict', message: `Pod ${podName} already exists` });\n return;\n }\n } catch (error) {\n logger.error(`Error checking pod existence: ${(error as Error).message}`);\n sendJson(response, 500, { error: 'Internal Server Error', message: 'Failed to check pod existence' });\n return;\n }\n\n // 5. 创建 Pod 目录\n try {\n await createPodDirectory(podPath, initialResources);\n logger.info(`Created pod: ${podName} at ${podPath}`);\n\n // 构建 pod URL (基于请求的 host)\n const host = request.headers.host || 'localhost';\n const podUrl = `https://${host}/${podName}/`;\n\n sendJson(response, 201, {\n success: true,\n podUrl,\n message: `Pod ${podName} created successfully`\n });\n } catch (error) {\n logger.error(`Failed to create pod: ${(error as Error).message}`);\n sendJson(response, 500, { error: 'Internal Server Error', message: 'Failed to create pod' });\n }\n }, { public: true }); // Service token auth handled internally\n\n /**\n * DELETE /provision/pods/:podName\n *\n * 删除 Pod 目录\n *\n * Request:\n * Authorization: Bearer {service_token}\n *\n * Response:\n * 200: { success: true }\n * 401: { error: \"Unauthorized\" }\n * 404: { error: \"Pod not found\" }\n */\n server.delete('/provision/pods/:podName', async (request, response, params) => {\n // 1. 认证\n if (!await authenticate(request)) {\n sendJson(response, 401, { error: 'Unauthorized', message: 'Invalid or missing service token' });\n return;\n }\n\n const podName = decodeURIComponent(params.podName);\n\n // 2. 验证 pod 名称\n if (!validatePodName(podName)) {\n sendJson(response, 400, { error: 'Bad Request', message: `Invalid pod name: ${podName}` });\n return;\n }\n\n // 3. 检查是否存在\n const podPath = `${rootDir}/${podName}`;\n try {\n const exists = await fileExists(podPath);\n if (!exists) {\n sendJson(response, 404, { error: 'Not Found', message: `Pod ${podName} not found` });\n return;\n }\n } catch (error) {\n logger.error(`Error checking pod existence: ${(error as Error).message}`);\n sendJson(response, 500, { error: 'Internal Server Error', message: 'Failed to check pod existence' });\n return;\n }\n\n // 4. 删除 Pod 目录\n try {\n await deletePodDirectory(podPath);\n logger.info(`Deleted pod: ${podName}`);\n\n sendJson(response, 200, {\n success: true,\n message: `Pod ${podName} deleted successfully`\n });\n } catch (error) {\n logger.error(`Failed to delete pod: ${(error as Error).message}`);\n sendJson(response, 500, { error: 'Internal Server Error', message: 'Failed to delete pod' });\n }\n }, { public: true });\n\n /**\n * GET /provision/pods/:podName\n *\n * 获取 Pod 信息(存在性检查)\n */\n server.get('/provision/pods/:podName', async (request, response, params) => {\n // 1. 认证\n if (!await authenticate(request)) {\n sendJson(response, 401, { error: 'Unauthorized', message: 'Invalid or missing service token' });\n return;\n }\n\n const podName = decodeURIComponent(params.podName);\n const podPath = `${rootDir}/${podName}`;\n\n try {\n const exists = await fileExists(podPath);\n if (!exists) {\n sendJson(response, 404, { error: 'Not Found', message: `Pod ${podName} not found` });\n return;\n }\n\n const host = request.headers.host || 'localhost';\n const podUrl = `https://${host}/${podName}/`;\n\n sendJson(response, 200, {\n exists: true,\n podName,\n podUrl,\n storagePath: podPath\n });\n } catch (error) {\n logger.error(`Error getting pod info: ${(error as Error).message}`);\n sendJson(response, 500, { error: 'Internal Server Error', message: 'Failed to get pod info' });\n }\n }, { public: true });\n\n logger.info(`Pod management routes registered with rootDir: ${rootDir}`);\n}\n\n/**\n * 读取 JSON 请求体\n */\nasync function readJsonBody(request: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve({});\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch (error) {\n reject(error);\n }\n });\n request.on('error', reject);\n });\n}\n\n/**\n * 发送 JSON 响应\n */\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data));\n}\n\n/**\n * 检查文件/目录是否存在\n */\nasync function fileExists(path: string): Promise<boolean> {\n const { stat } = await import('node:fs/promises');\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * 创建 Pod 目录\n */\nasync function createPodDirectory(\n podPath: string,\n initialResources?: Record<string, string>\n): Promise<void> {\n const { mkdir, writeFile } = await import('node:fs/promises');\n const { join } = await import('node:path');\n\n // 创建目录\n await mkdir(podPath, { recursive: true });\n\n // 创建初始资源\n if (initialResources) {\n for (const [filename, content] of Object.entries(initialResources)) {\n const filePath = join(podPath, filename);\n await writeFile(filePath, content, 'utf8');\n }\n }\n}\n\n/**\n * 删除 Pod 目录\n */\nasync function deletePodDirectory(podPath: string): Promise<void> {\n const { rm } = await import('node:fs/promises');\n await rm(podPath, { recursive: true, force: true });\n}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provision Handler
|
|
3
|
+
*
|
|
4
|
+
* Cloud 端的 SP 注册 API
|
|
5
|
+
*
|
|
6
|
+
* POST /provision/nodes - SP 注册(公开,无需认证)
|
|
7
|
+
* 返回 nodeId、nodeToken、serviceToken、provisionCode(自包含 JWT)
|
|
8
|
+
*
|
|
9
|
+
* provisionCode 是自包含 token,编码了 SP 的 publicUrl 和 serviceToken。
|
|
10
|
+
* CSS 侧的 ProvisionPodCreator 解码后直接回调 SP,不需要查数据库。
|
|
11
|
+
*
|
|
12
|
+
* GET /provision/status - Local 端 SP 状态查询(公开)
|
|
13
|
+
* 返回 SP 配置状态,供 Linx 查询
|
|
14
|
+
*/
|
|
15
|
+
import type { ApiServer } from '../ApiServer';
|
|
16
|
+
import type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';
|
|
17
|
+
export interface ProvisionHandlerOptions {
|
|
18
|
+
repository: EdgeNodeRepository;
|
|
19
|
+
/** Cloud baseUrl,用于派生 provisionCode 签名密钥 */
|
|
20
|
+
baseUrl: string;
|
|
21
|
+
/** 节点域名根域名,如 "undefineds.site" */
|
|
22
|
+
baseStorageDomain?: string;
|
|
23
|
+
/** provisionCode 有效期(秒),默认 24 小时 */
|
|
24
|
+
provisionCodeTtl?: number;
|
|
25
|
+
}
|
|
26
|
+
export declare function registerProvisionRoutes(server: ApiServer, options: ProvisionHandlerOptions): void;
|
|
27
|
+
/**
|
|
28
|
+
* Local 端 SP 状态查询路由
|
|
29
|
+
*/
|
|
30
|
+
export interface ProvisionStatusOptions {
|
|
31
|
+
/** Cloud API 端点 */
|
|
32
|
+
cloudUrl?: string;
|
|
33
|
+
/** 节点 ID */
|
|
34
|
+
nodeId?: string;
|
|
35
|
+
/** SP 子域名 */
|
|
36
|
+
spDomain?: string;
|
|
37
|
+
/** Cloud baseUrl,用于拼 provisionUrl */
|
|
38
|
+
cloudBaseUrl?: string;
|
|
39
|
+
/** provisionCode(可选,由环境变量传入) */
|
|
40
|
+
provisionCode?: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function registerProvisionStatusRoute(server: ApiServer, options: ProvisionStatusOptions): void;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Provision Handler
|
|
4
|
+
*
|
|
5
|
+
* Cloud 端的 SP 注册 API
|
|
6
|
+
*
|
|
7
|
+
* POST /provision/nodes - SP 注册(公开,无需认证)
|
|
8
|
+
* 返回 nodeId、nodeToken、serviceToken、provisionCode(自包含 JWT)
|
|
9
|
+
*
|
|
10
|
+
* provisionCode 是自包含 token,编码了 SP 的 publicUrl 和 serviceToken。
|
|
11
|
+
* CSS 侧的 ProvisionPodCreator 解码后直接回调 SP,不需要查数据库。
|
|
12
|
+
*
|
|
13
|
+
* GET /provision/status - Local 端 SP 状态查询(公开)
|
|
14
|
+
* 返回 SP 配置状态,供 Linx 查询
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.registerProvisionRoutes = registerProvisionRoutes;
|
|
18
|
+
exports.registerProvisionStatusRoute = registerProvisionStatusRoute;
|
|
19
|
+
const global_logger_factory_1 = require("global-logger-factory");
|
|
20
|
+
const ProvisionCodeCodec_1 = require("../../provision/ProvisionCodeCodec");
|
|
21
|
+
/** 默认 24 小时 */
|
|
22
|
+
const DEFAULT_TTL = 24 * 60 * 60;
|
|
23
|
+
function registerProvisionRoutes(server, options) {
|
|
24
|
+
const logger = (0, global_logger_factory_1.getLoggerFor)('ProvisionHandler');
|
|
25
|
+
const { repository, baseUrl, baseStorageDomain } = options;
|
|
26
|
+
const ttl = options.provisionCodeTtl ?? DEFAULT_TTL;
|
|
27
|
+
const codec = new ProvisionCodeCodec_1.ProvisionCodeCodec(baseUrl);
|
|
28
|
+
/**
|
|
29
|
+
* POST /provision/nodes
|
|
30
|
+
*
|
|
31
|
+
* SP 注册端点(公开,SP 启动时调用,此时用户可能还没有 Cloud 账号)
|
|
32
|
+
*
|
|
33
|
+
* Request:
|
|
34
|
+
* { publicUrl: string, nodeId?: string, displayName?: string, ipv4?: string, serviceToken?: string }
|
|
35
|
+
*
|
|
36
|
+
* Response 201:
|
|
37
|
+
* { nodeId, nodeToken, serviceToken, provisionCode, spDomain? }
|
|
38
|
+
*/
|
|
39
|
+
server.post('/provision/nodes', async (request, response) => {
|
|
40
|
+
let body;
|
|
41
|
+
try {
|
|
42
|
+
body = await readJsonBody(request) ?? {};
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
sendJson(response, 400, { error: 'Invalid JSON body' });
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (!body.publicUrl) {
|
|
49
|
+
sendJson(response, 400, { error: 'publicUrl is required' });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
new URL(body.publicUrl);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
sendJson(response, 400, { error: 'Invalid publicUrl format' });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const result = await repository.registerSpNode({
|
|
61
|
+
publicUrl: body.publicUrl,
|
|
62
|
+
displayName: body.displayName,
|
|
63
|
+
nodeId: body.nodeId,
|
|
64
|
+
serviceToken: body.serviceToken,
|
|
65
|
+
});
|
|
66
|
+
// 预分配子域名前缀(不创建 DNS 记录,延迟到心跳健康检查通过后)
|
|
67
|
+
// DB 只存前缀,完整 FQDN 由 DnsCoordinator 的 rootDomain 拼接
|
|
68
|
+
// 用 nodeId sanitize 后做前缀(去掉非 DNS 字符,截断到 63 字符)
|
|
69
|
+
const subdomainPrefix = baseStorageDomain
|
|
70
|
+
? result.nodeId.replace(/[^a-z0-9-]/gi, '').toLowerCase().slice(0, 63) || result.nodeId.split('-')[0]
|
|
71
|
+
: undefined;
|
|
72
|
+
const spDomain = subdomainPrefix
|
|
73
|
+
? `${subdomainPrefix}.${baseStorageDomain}`
|
|
74
|
+
: undefined;
|
|
75
|
+
// 如果提供了 ipv4,存入节点信息(供后续健康检查使用)
|
|
76
|
+
if (body.ipv4 || subdomainPrefix) {
|
|
77
|
+
await repository.updateNodeMode(result.nodeId, {
|
|
78
|
+
accessMode: 'direct',
|
|
79
|
+
ipv4: body.ipv4,
|
|
80
|
+
subdomain: subdomainPrefix,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
// 生成自包含 provisionCode(编码了 SP 信息,CSS 解码后直接回调 SP)
|
|
84
|
+
const provisionCode = codec.encode({
|
|
85
|
+
spUrl: body.publicUrl,
|
|
86
|
+
serviceToken: result.serviceToken,
|
|
87
|
+
nodeId: result.nodeId,
|
|
88
|
+
spDomain,
|
|
89
|
+
exp: Math.floor(Date.now() / 1000) + ttl,
|
|
90
|
+
});
|
|
91
|
+
logger.info(`Registered SP node ${result.nodeId} at ${body.publicUrl}${spDomain ? `, spDomain: ${spDomain}` : ''}`);
|
|
92
|
+
const responseBody = {
|
|
93
|
+
nodeId: result.nodeId,
|
|
94
|
+
nodeToken: result.nodeToken,
|
|
95
|
+
serviceToken: result.serviceToken,
|
|
96
|
+
provisionCode,
|
|
97
|
+
};
|
|
98
|
+
if (spDomain) {
|
|
99
|
+
responseBody.spDomain = spDomain;
|
|
100
|
+
}
|
|
101
|
+
sendJson(response, 201, responseBody);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
logger.error(`Failed to register SP node: ${error}`);
|
|
105
|
+
sendJson(response, 500, { error: 'Failed to register SP node' });
|
|
106
|
+
}
|
|
107
|
+
}, { public: true });
|
|
108
|
+
logger.info('Provision routes registered');
|
|
109
|
+
}
|
|
110
|
+
function registerProvisionStatusRoute(server, options) {
|
|
111
|
+
const logger = (0, global_logger_factory_1.getLoggerFor)('ProvisionStatusHandler');
|
|
112
|
+
server.get('/provision/status', async (_request, response) => {
|
|
113
|
+
const registered = Boolean(options.nodeId && options.cloudUrl);
|
|
114
|
+
const body = {
|
|
115
|
+
registered,
|
|
116
|
+
};
|
|
117
|
+
if (registered) {
|
|
118
|
+
body.cloudUrl = options.cloudUrl;
|
|
119
|
+
body.nodeId = options.nodeId;
|
|
120
|
+
if (options.spDomain) {
|
|
121
|
+
body.spDomain = options.spDomain;
|
|
122
|
+
}
|
|
123
|
+
if (options.cloudBaseUrl) {
|
|
124
|
+
const provisionUrl = options.provisionCode
|
|
125
|
+
? `${options.cloudBaseUrl.replace(/\/$/, '')}/.account/?provisionCode=${encodeURIComponent(options.provisionCode)}`
|
|
126
|
+
: `${options.cloudBaseUrl.replace(/\/$/, '')}/.account/`;
|
|
127
|
+
body.provisionUrl = provisionUrl;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
sendJson(response, 200, body);
|
|
131
|
+
}, { public: true });
|
|
132
|
+
logger.info('Provision status route registered');
|
|
133
|
+
}
|
|
134
|
+
async function readJsonBody(request) {
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
let data = '';
|
|
137
|
+
request.setEncoding('utf8');
|
|
138
|
+
request.on('data', (chunk) => {
|
|
139
|
+
data += chunk;
|
|
140
|
+
});
|
|
141
|
+
request.on('end', () => {
|
|
142
|
+
if (!data) {
|
|
143
|
+
resolve(undefined);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
resolve(JSON.parse(data));
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
reject(error);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
request.on('error', reject);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function sendJson(response, status, data) {
|
|
157
|
+
response.statusCode = status;
|
|
158
|
+
response.setHeader('Content-Type', 'application/json');
|
|
159
|
+
response.end(JSON.stringify(data));
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=ProvisionHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProvisionHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/ProvisionHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Provision Handler\n *\n * Cloud 端的 SP 注册 API\n *\n * POST /provision/nodes - SP 注册(公开,无需认证)\n * 返回 nodeId、nodeToken、serviceToken、provisionCode(自包含 JWT)\n *\n * provisionCode 是自包含 token,编码了 SP 的 publicUrl 和 serviceToken。\n * CSS 侧的 ProvisionPodCreator 解码后直接回调 SP,不需要查数据库。\n *\n * GET /provision/status - Local 端 SP 状态查询(公开)\n * 返回 SP 配置状态,供 Linx 查询\n */\n\nimport type { ServerResponse, IncomingMessage } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { ApiServer } from '../ApiServer';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport { ProvisionCodeCodec } from '../../provision/ProvisionCodeCodec';\n\nexport interface ProvisionHandlerOptions {\n repository: EdgeNodeRepository;\n /** Cloud baseUrl,用于派生 provisionCode 签名密钥 */\n baseUrl: string;\n /** 节点域名根域名,如 \"undefineds.site\" */\n baseStorageDomain?: string;\n /** provisionCode 有效期(秒),默认 24 小时 */\n provisionCodeTtl?: number;\n}\n\n/** 默认 24 小时 */\nconst DEFAULT_TTL = 24 * 60 * 60;\n\nexport function registerProvisionRoutes(\n server: ApiServer,\n options: ProvisionHandlerOptions,\n): void {\n const logger = getLoggerFor('ProvisionHandler');\n const { repository, baseUrl, baseStorageDomain } = options;\n const ttl = options.provisionCodeTtl ?? DEFAULT_TTL;\n const codec = new ProvisionCodeCodec(baseUrl);\n\n /**\n * POST /provision/nodes\n *\n * SP 注册端点(公开,SP 启动时调用,此时用户可能还没有 Cloud 账号)\n *\n * Request:\n * { publicUrl: string, nodeId?: string, displayName?: string, ipv4?: string, serviceToken?: string }\n *\n * Response 201:\n * { nodeId, nodeToken, serviceToken, provisionCode, spDomain? }\n */\n server.post('/provision/nodes', async (request, response) => {\n let body: { publicUrl?: string; nodeId?: string; displayName?: string; ipv4?: string; serviceToken?: string };\n try {\n body = await readJsonBody(request) as any ?? {};\n } catch {\n sendJson(response, 400, { error: 'Invalid JSON body' });\n return;\n }\n\n if (!body.publicUrl) {\n sendJson(response, 400, { error: 'publicUrl is required' });\n return;\n }\n\n try {\n new URL(body.publicUrl);\n } catch {\n sendJson(response, 400, { error: 'Invalid publicUrl format' });\n return;\n }\n\n try {\n const result = await repository.registerSpNode({\n publicUrl: body.publicUrl,\n displayName: body.displayName,\n nodeId: body.nodeId,\n serviceToken: body.serviceToken,\n });\n\n // 预分配子域名前缀(不创建 DNS 记录,延迟到心跳健康检查通过后)\n // DB 只存前缀,完整 FQDN 由 DnsCoordinator 的 rootDomain 拼接\n // 用 nodeId sanitize 后做前缀(去掉非 DNS 字符,截断到 63 字符)\n const subdomainPrefix = baseStorageDomain\n ? result.nodeId.replace(/[^a-z0-9-]/gi, '').toLowerCase().slice(0, 63) || result.nodeId.split('-')[0]\n : undefined;\n const spDomain = subdomainPrefix\n ? `${subdomainPrefix}.${baseStorageDomain}`\n : undefined;\n\n // 如果提供了 ipv4,存入节点信息(供后续健康检查使用)\n if (body.ipv4 || subdomainPrefix) {\n await repository.updateNodeMode(result.nodeId, {\n accessMode: 'direct',\n ipv4: body.ipv4,\n subdomain: subdomainPrefix,\n });\n }\n\n // 生成自包含 provisionCode(编码了 SP 信息,CSS 解码后直接回调 SP)\n const provisionCode = codec.encode({\n spUrl: body.publicUrl,\n serviceToken: result.serviceToken,\n nodeId: result.nodeId,\n spDomain,\n exp: Math.floor(Date.now() / 1000) + ttl,\n });\n\n logger.info(`Registered SP node ${result.nodeId} at ${body.publicUrl}${spDomain ? `, spDomain: ${spDomain}` : ''}`);\n\n const responseBody: Record<string, unknown> = {\n nodeId: result.nodeId,\n nodeToken: result.nodeToken,\n serviceToken: result.serviceToken,\n provisionCode,\n };\n if (spDomain) {\n responseBody.spDomain = spDomain;\n }\n\n sendJson(response, 201, responseBody);\n } catch (error) {\n logger.error(`Failed to register SP node: ${error}`);\n sendJson(response, 500, { error: 'Failed to register SP node' });\n }\n }, { public: true });\n\n logger.info('Provision routes registered');\n}\n\n/**\n * Local 端 SP 状态查询路由\n */\nexport interface ProvisionStatusOptions {\n /** Cloud API 端点 */\n cloudUrl?: string;\n /** 节点 ID */\n nodeId?: string;\n /** SP 子域名 */\n spDomain?: string;\n /** Cloud baseUrl,用于拼 provisionUrl */\n cloudBaseUrl?: string;\n /** provisionCode(可选,由环境变量传入) */\n provisionCode?: string;\n}\n\nexport function registerProvisionStatusRoute(\n server: ApiServer,\n options: ProvisionStatusOptions,\n): void {\n const logger = getLoggerFor('ProvisionStatusHandler');\n\n server.get('/provision/status', async (_request, response) => {\n const registered = Boolean(options.nodeId && options.cloudUrl);\n\n const body: Record<string, unknown> = {\n registered,\n };\n\n if (registered) {\n body.cloudUrl = options.cloudUrl;\n body.nodeId = options.nodeId;\n if (options.spDomain) {\n body.spDomain = options.spDomain;\n }\n if (options.cloudBaseUrl) {\n const provisionUrl = options.provisionCode\n ? `${options.cloudBaseUrl.replace(/\\/$/, '')}/.account/?provisionCode=${encodeURIComponent(options.provisionCode)}`\n : `${options.cloudBaseUrl.replace(/\\/$/, '')}/.account/`;\n body.provisionUrl = provisionUrl;\n }\n }\n\n sendJson(response, 200, body);\n }, { public: true });\n\n logger.info('Provision status route registered');\n}\n\nasync function readJsonBody(request: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve(undefined);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch (error) {\n reject(error);\n }\n });\n request.on('error', reject);\n });\n}\n\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data));\n}\n"]}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import type { ApiServer } from '../ApiServer';
|
|
2
2
|
import type { QuotaService } from '../../quota/QuotaService';
|
|
3
|
-
import type {
|
|
3
|
+
import type { UsageRepository } from '../../storage/quota/UsageRepository';
|
|
4
4
|
export interface QuotaHandlerOptions {
|
|
5
5
|
quotaService: QuotaService;
|
|
6
|
-
|
|
6
|
+
usageRepo: UsageRepository;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* Handler for quota management API
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Supports four resource types: storage, bandwidth, compute, token.
|
|
12
|
+
* Requires ServiceAuthContext with 'quota:write' scope for mutations.
|
|
13
13
|
*
|
|
14
|
-
* GET /v1/quota/accounts/:accountId - Get account quota
|
|
14
|
+
* GET /v1/quota/accounts/:accountId - Get account quota + usage
|
|
15
15
|
* PUT /v1/quota/accounts/:accountId - Set account quota
|
|
16
|
-
* DELETE /v1/quota/accounts/:accountId - Clear account quota
|
|
17
|
-
* GET /v1/quota/pods/:podId - Get pod quota
|
|
16
|
+
* DELETE /v1/quota/accounts/:accountId - Clear account quota (revert to defaults)
|
|
17
|
+
* GET /v1/quota/pods/:podId - Get pod quota + usage
|
|
18
18
|
* PUT /v1/quota/pods/:podId - Set pod quota
|
|
19
19
|
* DELETE /v1/quota/pods/:podId - Clear pod quota
|
|
20
20
|
*/
|