@undefineds.co/xpod 0.2.2 → 0.2.4
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 +8 -0
- package/dist/api/container/common.js +24 -0
- package/dist/api/container/common.js.map +1 -1
- package/dist/api/container/routes.js +3 -0
- package/dist/api/container/routes.js.map +1 -1
- package/dist/api/container/types.d.ts +5 -0
- package/dist/api/container/types.js.map +1 -1
- package/dist/api/service/VercelChatService.d.ts +8 -5
- package/dist/api/service/VercelChatService.js +75 -64
- package/dist/api/service/VercelChatService.js.map +1 -1
- package/dist/components/components.jsonld +1 -0
- package/dist/components/context.jsonld +54 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/quota/DrizzleQuotaService.d.ts +6 -2
- package/dist/quota/DrizzleQuotaService.js +27 -11
- package/dist/quota/DrizzleQuotaService.js.map +1 -1
- package/dist/quota/DrizzleQuotaService.jsonld +27 -1
- package/dist/quota/EntitlementProvider.d.ts +30 -0
- package/dist/quota/EntitlementProvider.js +118 -0
- package/dist/quota/EntitlementProvider.js.map +1 -0
- package/dist/quota/EntitlementProvider.jsonld +173 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -128,6 +128,14 @@ cp example.env .env.cloud
|
|
|
128
128
|
bun run cloud
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
+
## Hosted Preview and Support
|
|
132
|
+
|
|
133
|
+
- `xpod` Cloud 当前按 `hosted preview` 提供免费账号基线,不承诺正式订阅套餐
|
|
134
|
+
- 免费账号额度直接由 `XPOD_DEFAULT_*` 控制,不通过 `billing plan` 下发
|
|
135
|
+
- 当前支持方式是手工捐款与 supporter 认领,不是自动开通的资源升级档
|
|
136
|
+
- supporter 记录只表达支持关系与非资源权益,不会自动提高存储、带宽或模型额度
|
|
137
|
+
- 对外口径与支持说明可放在 `https://undefineds.co/zh-CN/support/` 与 `https://undefineds.co/en/support/`
|
|
138
|
+
|
|
131
139
|
## Library Mode
|
|
132
140
|
|
|
133
141
|
If you want the full Xpod stack inside your own process, import it as a library instead of spawning the CLI.
|
|
@@ -18,8 +18,19 @@ const ServiceTokenAuthenticator_1 = require("../auth/ServiceTokenAuthenticator")
|
|
|
18
18
|
const MultiAuthenticator_1 = require("../auth/MultiAuthenticator");
|
|
19
19
|
const AuthMiddleware_1 = require("../middleware/AuthMiddleware");
|
|
20
20
|
const VercelChatService_1 = require("../service/VercelChatService");
|
|
21
|
+
const VectorService_1 = require("../service/VectorService");
|
|
21
22
|
const ApiServer_1 = require("../ApiServer");
|
|
22
23
|
const chatkit_1 = require("../chatkit");
|
|
24
|
+
const service_1 = require("../../ai/service");
|
|
25
|
+
function resolveCssServiceBaseUrl() {
|
|
26
|
+
if (process.env.CSS_INTERNAL_URL) {
|
|
27
|
+
return process.env.CSS_INTERNAL_URL;
|
|
28
|
+
}
|
|
29
|
+
if (process.env.CSS_BASE_URL) {
|
|
30
|
+
return process.env.CSS_BASE_URL;
|
|
31
|
+
}
|
|
32
|
+
return 'http://localhost:3000/';
|
|
33
|
+
}
|
|
23
34
|
/**
|
|
24
35
|
* 注册共享服务到容器
|
|
25
36
|
*/
|
|
@@ -81,6 +92,19 @@ function registerCommonServices(container) {
|
|
|
81
92
|
enablePtyRuntime: config.edition === 'local',
|
|
82
93
|
});
|
|
83
94
|
}).singleton(),
|
|
95
|
+
providerRegistry: (0, awilix_1.asFunction)(() => {
|
|
96
|
+
return new service_1.ProviderRegistryImpl();
|
|
97
|
+
}).singleton(),
|
|
98
|
+
embeddingService: (0, awilix_1.asFunction)(({ providerRegistry }) => {
|
|
99
|
+
return new service_1.EmbeddingServiceImpl(providerRegistry);
|
|
100
|
+
}).singleton(),
|
|
101
|
+
vectorService: (0, awilix_1.asFunction)(({ chatKitStore, embeddingService }) => {
|
|
102
|
+
return new VectorService_1.VectorService({
|
|
103
|
+
cssBaseUrl: resolveCssServiceBaseUrl(),
|
|
104
|
+
store: chatKitStore,
|
|
105
|
+
embeddingService,
|
|
106
|
+
});
|
|
107
|
+
}).singleton(),
|
|
84
108
|
// 业务服务
|
|
85
109
|
chatService: (0, awilix_1.asFunction)(({ chatKitStore }) => {
|
|
86
110
|
return new VercelChatService_1.VercelChatService(chatKitStore);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../../src/api/container/common.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../../src/api/container/common.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 共享服务注册\n *\n * cloud 和 local 模式都需要的服务\n */\n\nimport { asFunction, type AwilixContainer } from 'awilix';\nimport type { ApiContainerCradle } from './types';\n\nimport { getIdentityDatabase } from '../../identity/drizzle/db';\nimport { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport { ServiceTokenRepository } from '../../identity/drizzle/ServiceTokenRepository';\nimport { DrizzleClientCredentialsStore } from '../store/DrizzleClientCredentialsStore';\nimport { SolidTokenAuthenticator } from '../auth/SolidTokenAuthenticator';\nimport { ClientCredentialsAuthenticator } from '../auth/ClientCredentialsAuthenticator';\nimport { NodeTokenAuthenticator } from '../auth/NodeTokenAuthenticator';\nimport { ServiceTokenAuthenticator } from '../auth/ServiceTokenAuthenticator';\nimport { MultiAuthenticator } from '../auth/MultiAuthenticator';\nimport { AuthMiddleware } from '../middleware/AuthMiddleware';\nimport { VercelChatService } from '../service/VercelChatService';\nimport { VectorService } from '../service/VectorService';\nimport { ApiServer } from '../ApiServer';\nimport { ChatKitService, PodChatKitStore, VercelAiProvider } from '../chatkit';\nimport { EmbeddingServiceImpl, ProviderRegistryImpl } from '../../ai/service';\n\nfunction resolveCssServiceBaseUrl(): string {\n if (process.env.CSS_INTERNAL_URL) {\n return process.env.CSS_INTERNAL_URL;\n }\n\n if (process.env.CSS_BASE_URL) {\n return process.env.CSS_BASE_URL;\n }\n\n return 'http://localhost:3000/';\n}\n\n/**\n * 注册共享服务到容器\n */\nexport function registerCommonServices(\n container: AwilixContainer<ApiContainerCradle>,\n): void {\n container.register({\n // 数据库\n db: asFunction(({ config }: ApiContainerCradle) => {\n return getIdentityDatabase(config.databaseUrl);\n }).singleton(),\n\n // 仓库\n nodeRepo: asFunction(({ db }: ApiContainerCradle) => {\n return new EdgeNodeRepository(db);\n }).singleton(),\n\n apiKeyStore: asFunction(({ db, config }: ApiContainerCradle) => {\n return new DrizzleClientCredentialsStore({\n db,\n isSqlite: config.databaseUrl.startsWith('sqlite:'),\n });\n }).singleton(),\n\n // 认证\n serviceTokenRepo: asFunction(({ db }: ApiContainerCradle) => {\n return new ServiceTokenRepository(db);\n }).singleton(),\n\n authenticator: asFunction(({ nodeRepo, serviceTokenRepo, config }: ApiContainerCradle) => {\n const solidAuthenticator = new SolidTokenAuthenticator({\n resolveAccountId: async (webId) => webId,\n });\n\n const clientCredAuthenticator = new ClientCredentialsAuthenticator({\n tokenEndpoint: config.cssTokenEndpoint,\n });\n\n const nodeTokenAuthenticator = new NodeTokenAuthenticator({\n repository: nodeRepo,\n });\n\n const serviceTokenAuthenticator = new ServiceTokenAuthenticator({\n repository: serviceTokenRepo,\n });\n\n return new MultiAuthenticator({\n // Order: Solid DPoP → Service Token → Node Token → Client Credentials\n // ServiceTokenAuthenticator handles 'svc-' prefix, so no ambiguity\n authenticators: [solidAuthenticator, serviceTokenAuthenticator, nodeTokenAuthenticator, clientCredAuthenticator],\n });\n }).singleton(),\n\n authMiddleware: asFunction(({ authenticator }: ApiContainerCradle) => {\n return new AuthMiddleware({ authenticator });\n }).singleton(),\n\n // ChatKit 存储与服务\n chatKitStore: asFunction(({ config }: ApiContainerCradle) => {\n return new PodChatKitStore({\n tokenEndpoint: config.cssTokenEndpoint,\n });\n }).singleton(),\n\n chatKitAiProvider: asFunction(({ chatKitStore }: ApiContainerCradle) => {\n return new VercelAiProvider({ store: chatKitStore });\n }).singleton(),\n\n chatKitService: asFunction(({ chatKitStore, chatKitAiProvider, config }: ApiContainerCradle) => {\n return new ChatKitService({\n store: chatKitStore,\n aiProvider: chatKitAiProvider,\n enablePtyRuntime: config.edition === 'local',\n });\n }).singleton(),\n\n providerRegistry: asFunction(() => {\n return new ProviderRegistryImpl();\n }).singleton(),\n\n embeddingService: asFunction(({ providerRegistry }: ApiContainerCradle) => {\n return new EmbeddingServiceImpl(providerRegistry);\n }).singleton(),\n\n vectorService: asFunction(({ chatKitStore, embeddingService }: ApiContainerCradle) => {\n return new VectorService({\n cssBaseUrl: resolveCssServiceBaseUrl(),\n store: chatKitStore,\n embeddingService,\n });\n }).singleton(),\n\n // 业务服务\n chatService: asFunction(({ chatKitStore }: ApiContainerCradle) => {\n return new VercelChatService(chatKitStore);\n }).singleton(),\n\n\n // API Server\n apiServer: asFunction(({ config, authMiddleware }: ApiContainerCradle) => {\n return new ApiServer({\n port: config.port,\n host: config.host,\n socketPath: config.socketPath,\n runtimeHost: config.runtimeHost,\n authMiddleware,\n corsOrigins: config.corsOrigins,\n });\n }).singleton(),\n });\n}\n"]}
|
|
@@ -39,6 +39,7 @@ const WebIdProfileHandler_1 = require("../handlers/WebIdProfileHandler");
|
|
|
39
39
|
const DdnsHandler_1 = require("../handlers/DdnsHandler");
|
|
40
40
|
const ChatKitHandler_1 = require("../handlers/ChatKitHandler");
|
|
41
41
|
const ChatKitV1Handler_1 = require("../handlers/ChatKitV1Handler");
|
|
42
|
+
const VectorHandler_1 = require("../handlers/VectorHandler");
|
|
42
43
|
const DashboardHandler_1 = require("../handlers/DashboardHandler");
|
|
43
44
|
const AdminHandler_1 = require("../handlers/AdminHandler");
|
|
44
45
|
const AdminDdnsHandler_1 = require("../handlers/AdminDdnsHandler");
|
|
@@ -95,6 +96,7 @@ function registerSharedRoutes(container, server) {
|
|
|
95
96
|
const chatService = container.resolve('chatService');
|
|
96
97
|
const chatKitService = container.resolve('chatKitService');
|
|
97
98
|
const chatKitStore = container.resolve('chatKitStore');
|
|
99
|
+
const vectorService = container.resolve('vectorService');
|
|
98
100
|
const config = container.resolve('config');
|
|
99
101
|
(0, EdgeNodeSignalHandler_1.registerEdgeNodeSignalRoutes)(server, {
|
|
100
102
|
repository: nodeRepo,
|
|
@@ -106,6 +108,7 @@ function registerSharedRoutes(container, server) {
|
|
|
106
108
|
(0, ChatHandler_1.registerChatRoutes)(server, { chatService });
|
|
107
109
|
(0, ChatKitHandler_1.registerChatKitRoutes)(server, { chatKitService });
|
|
108
110
|
(0, ChatKitV1Handler_1.registerChatKitV1Routes)(server, { store: chatKitStore });
|
|
111
|
+
(0, VectorHandler_1.registerVectorRoutes)(server, { vectorService });
|
|
109
112
|
// Quota & Usage API (Business 对接)
|
|
110
113
|
try {
|
|
111
114
|
const quotaService = new DrizzleQuotaService_1.DrizzleQuotaService({ identityDbUrl: config.databaseUrl });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/api/container/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 路由注册\n *\n * 根据容器中的服务注册 API 路由\n */\n\nimport type { AwilixContainer } from 'awilix';\nimport type { ApiContainerCradle, ApiContainerConfig } from './types';\nimport type { ApiServer } from '../ApiServer';\n\nimport { registerEdgeNodeSignalRoutes } from '../handlers/EdgeNodeSignalHandler';\nimport { registerNodeRoutes } from '../handlers/NodeHandler';\nimport { registerChatRoutes } from '../handlers/ChatHandler';\nimport { registerApiKeyRoutes } from '../handlers/ApiKeyHandler';\nimport { registerSubdomainRoutes } from '../handlers/SubdomainHandler';\nimport { registerSubdomainClientRoutes } from '../handlers/SubdomainClientHandler';\nimport { registerWebIdProfileRoutes } from '../handlers/WebIdProfileHandler';\nimport { registerDdnsRoutes } from '../handlers/DdnsHandler';\nimport { registerChatKitRoutes } from '../handlers/ChatKitHandler';\nimport { registerChatKitV1Routes } from '../handlers/ChatKitV1Handler';\nimport { registerDashboardRoutes } from '../handlers/DashboardHandler';\nimport { registerAdminRoutes } from '../handlers/AdminHandler';\nimport { registerAdminDdnsRoutes } from '../handlers/AdminDdnsHandler';\nimport { registerProvisionRoutes, registerProvisionStatusRoute } from '../handlers/ProvisionHandler';\nimport { registerPodManagementRoutes } from '../handlers/PodManagementHandler';\nimport { registerQuotaRoutes } from '../handlers/QuotaHandler';\nimport { registerUsageRoutes } from '../handlers/UsageHandler';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { DrizzleClientCredentialsStore } from '../store/DrizzleClientCredentialsStore';\nimport { UsageRepository } from '../../storage/quota/UsageRepository';\nimport { DrizzleQuotaService } from '../../quota/DrizzleQuotaService';\nimport * as path from 'node:path';\nimport { PACKAGE_ROOT } from '../../runtime';\n\n/**\n * 注册所有 API 路由\n */\nexport function registerRoutes(container: AwilixContainer<ApiContainerCradle>): void {\n const server = container.resolve('apiServer') as ApiServer;\n const config = container.resolve('config') as ApiContainerConfig;\n\n // 公共健康检查端点\n registerHealthRoutes(server);\n\n // 共享路由\n registerSharedRoutes(container, server);\n\n // 根据 edition 注册专属路由\n if (config.edition === 'cloud') {\n registerCloudRoutes(container, server);\n } else {\n registerLocalRoutes(container, server);\n }\n}\n\n/**\n * 健康检查路由\n */\nfunction registerHealthRoutes(server: ApiServer): void {\n server.get('/health', async (_req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ status: 'ok' }));\n }, { public: true });\n\n server.get('/ready', async (_req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ status: 'ready' }));\n }, { public: true });\n\n // Dashboard 静态资源\n const staticDir = path.resolve(PACKAGE_ROOT, 'static/dashboard');\n registerDashboardRoutes(server, { staticDir });\n}\n\n/**\n * 共享路由 (cloud 和 local 都有)\n */\nfunction registerSharedRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n const nodeRepo = container.resolve('nodeRepo') as EdgeNodeRepository;\n const apiKeyStore = container.resolve('apiKeyStore') as DrizzleClientCredentialsStore;\n const chatService = container.resolve('chatService');\n const chatKitService = container.resolve('chatKitService');\n const chatKitStore = container.resolve('chatKitStore');\n const config = container.resolve('config') as ApiContainerConfig;\n\n registerEdgeNodeSignalRoutes(server, {\n repository: nodeRepo,\n dnsCoordinator: container.resolve('dnsCoordinator', { allowUnregistered: true }) as any,\n healthProbeService: container.resolve('healthProbeService', { allowUnregistered: true }) as any,\n });\n registerNodeRoutes(server, { repository: nodeRepo });\n registerApiKeyRoutes(server, { store: apiKeyStore });\n registerChatRoutes(server, { chatService });\n registerChatKitRoutes(server, { chatKitService });\n registerChatKitV1Routes(server, { store: chatKitStore });\n\n // Quota & Usage API (Business 对接)\n try {\n const quotaService = new DrizzleQuotaService({ identityDbUrl: config.databaseUrl });\n const usageRepo = new UsageRepository(container.resolve('db'));\n registerQuotaRoutes(server, { quotaService, usageRepo });\n registerUsageRoutes(server, { usageRepo });\n console.log('[Shared] Quota & Usage routes registered');\n } catch (error) {\n console.log(`[Shared] Quota & Usage routes not registered: ${error}`);\n }\n}\n\n/**\n * Cloud 模式专属路由\n */\nfunction registerCloudRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n // 子域名管理 API (需要 SubdomainService)\n try {\n const subdomainService = container.resolve('subdomainService') as ApiContainerCradle['subdomainService'];\n if (subdomainService) {\n registerSubdomainRoutes(server, { subdomainService });\n console.log('[Cloud] Subdomain routes registered');\n }\n } catch {\n console.log('[Cloud] Subdomain routes not registered (service not available)');\n }\n\n // WebID Profile 托管服务\n try {\n const profileRepo = container.resolve('webIdProfileRepo', { allowUnregistered: true });\n if (profileRepo) {\n registerWebIdProfileRoutes(server, { profileRepo: profileRepo as any });\n console.log('[Cloud] WebID Profile routes registered');\n }\n } catch {\n console.log('[Cloud] WebID Profile routes not registered (repo not available)');\n }\n\n // DDNS 服务\n try {\n const ddnsRepo = container.resolve('ddnsRepo', { allowUnregistered: true });\n const dnsProvider = container.resolve('dnsProvider', { allowUnregistered: true });\n const config = container.resolve('config') as ApiContainerConfig;\n\n if (ddnsRepo) {\n const baseStorageDomain = config.subdomain?.baseStorageDomain;\n if (baseStorageDomain) {\n registerDdnsRoutes(server, {\n ddnsRepo: ddnsRepo as any,\n dnsProvider: dnsProvider as any,\n defaultDomain: baseStorageDomain,\n });\n console.log(`[Cloud] DDNS routes registered (domain: ${baseStorageDomain})`);\n } else {\n console.log('[Cloud] DDNS routes not registered (no CSS_BASE_STORAGE_DOMAIN)');\n }\n }\n } catch {\n console.log('[Cloud] DDNS routes not registered (repo not available)');\n }\n\n // SP Provision API (SP 注册)\n try {\n const nodeRepo = container.resolve('nodeRepo') as EdgeNodeRepository;\n const config = container.resolve('config') as ApiContainerConfig;\n const baseUrl = process.env.CSS_BASE_URL || 'http://localhost:3000/';\n const baseStorageDomain = config.subdomain?.baseStorageDomain;\n registerProvisionRoutes(server, { repository: nodeRepo, baseUrl, baseStorageDomain });\n console.log(`[Cloud] Provision routes registered${baseStorageDomain ? ` (baseStorageDomain: ${baseStorageDomain})` : ''}`);\n } catch {\n console.log('[Cloud] Provision routes not registered (dependencies not available)');\n }\n}\n\n/**\n * Local 模式专属路由\n */\nfunction registerLocalRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n // Admin API (配置管理、重启)\n registerAdminRoutes(server);\n\n // DDNS status (托管式 Local 模式)\n try {\n const ddnsManager = container.resolve('ddnsManager', { allowUnregistered: true }) as any;\n registerAdminDdnsRoutes(server, { ddnsManager });\n } catch {\n // ignore\n }\n\n // 子域名客户端 API (通过 SubdomainClient 调用 Cloud)\n try {\n const subdomainClient = container.resolve('subdomainClient') as ApiContainerCradle['subdomainClient'];\n if (subdomainClient) {\n registerSubdomainClientRoutes(server, { subdomainClient });\n console.log('[Local] Subdomain client routes registered');\n }\n } catch {\n console.log('[Local] Subdomain client routes not registered (client not available)');\n }\n\n // Pod Provision API (SP 端,供 Cloud 回调创建 Pod)\n try {\n // rootDir: CSS 数据目录,默认 ./data\n const rootDir = process.env.CSS_ROOT_FILE_PATH || './data';\n // serviceToken 验证:从 SP 配置中读取\n const expectedServiceToken = process.env.XPOD_SERVICE_TOKEN;\n\n if (expectedServiceToken) {\n registerPodManagementRoutes(server, {\n rootDir,\n verifyServiceToken: async (token: string) => token === expectedServiceToken,\n });\n console.log('[Local] Pod provision routes registered (/provision/pods)');\n } else {\n console.log('[Local] Pod provision routes not registered (XPOD_SERVICE_TOKEN not configured)');\n }\n } catch (error) {\n console.log(`[Local] Pod provision routes not registered: ${error}`);\n }\n\n // SP 状态查询 (供 Linx 查询 SP 配置状态)\n try {\n const config = container.resolve('config') as ApiContainerConfig;\n registerProvisionStatusRoute(server, {\n cloudUrl: config.cloudApiEndpoint,\n nodeId: config.nodeId,\n cloudBaseUrl: config.oidcIssuer || config.cloudApiEndpoint,\n });\n console.log('[Local] Provision status route registered (/provision/status)');\n } catch (error) {\n console.log(`[Local] Provision status route not registered: ${error}`);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/api/container/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 路由注册\n *\n * 根据容器中的服务注册 API 路由\n */\n\nimport type { AwilixContainer } from 'awilix';\nimport type { ApiContainerCradle, ApiContainerConfig } from './types';\nimport type { ApiServer } from '../ApiServer';\n\nimport { registerEdgeNodeSignalRoutes } from '../handlers/EdgeNodeSignalHandler';\nimport { registerNodeRoutes } from '../handlers/NodeHandler';\nimport { registerChatRoutes } from '../handlers/ChatHandler';\nimport { registerApiKeyRoutes } from '../handlers/ApiKeyHandler';\nimport { registerSubdomainRoutes } from '../handlers/SubdomainHandler';\nimport { registerSubdomainClientRoutes } from '../handlers/SubdomainClientHandler';\nimport { registerWebIdProfileRoutes } from '../handlers/WebIdProfileHandler';\nimport { registerDdnsRoutes } from '../handlers/DdnsHandler';\nimport { registerChatKitRoutes } from '../handlers/ChatKitHandler';\nimport { registerChatKitV1Routes } from '../handlers/ChatKitV1Handler';\nimport { registerVectorRoutes } from '../handlers/VectorHandler';\nimport { registerDashboardRoutes } from '../handlers/DashboardHandler';\nimport { registerAdminRoutes } from '../handlers/AdminHandler';\nimport { registerAdminDdnsRoutes } from '../handlers/AdminDdnsHandler';\nimport { registerProvisionRoutes, registerProvisionStatusRoute } from '../handlers/ProvisionHandler';\nimport { registerPodManagementRoutes } from '../handlers/PodManagementHandler';\nimport { registerQuotaRoutes } from '../handlers/QuotaHandler';\nimport { registerUsageRoutes } from '../handlers/UsageHandler';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { DrizzleClientCredentialsStore } from '../store/DrizzleClientCredentialsStore';\nimport { UsageRepository } from '../../storage/quota/UsageRepository';\nimport { DrizzleQuotaService } from '../../quota/DrizzleQuotaService';\nimport * as path from 'node:path';\nimport { PACKAGE_ROOT } from '../../runtime';\n\n/**\n * 注册所有 API 路由\n */\nexport function registerRoutes(container: AwilixContainer<ApiContainerCradle>): void {\n const server = container.resolve('apiServer') as ApiServer;\n const config = container.resolve('config') as ApiContainerConfig;\n\n // 公共健康检查端点\n registerHealthRoutes(server);\n\n // 共享路由\n registerSharedRoutes(container, server);\n\n // 根据 edition 注册专属路由\n if (config.edition === 'cloud') {\n registerCloudRoutes(container, server);\n } else {\n registerLocalRoutes(container, server);\n }\n}\n\n/**\n * 健康检查路由\n */\nfunction registerHealthRoutes(server: ApiServer): void {\n server.get('/health', async (_req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ status: 'ok' }));\n }, { public: true });\n\n server.get('/ready', async (_req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ status: 'ready' }));\n }, { public: true });\n\n // Dashboard 静态资源\n const staticDir = path.resolve(PACKAGE_ROOT, 'static/dashboard');\n registerDashboardRoutes(server, { staticDir });\n}\n\n/**\n * 共享路由 (cloud 和 local 都有)\n */\nfunction registerSharedRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n const nodeRepo = container.resolve('nodeRepo') as EdgeNodeRepository;\n const apiKeyStore = container.resolve('apiKeyStore') as DrizzleClientCredentialsStore;\n const chatService = container.resolve('chatService');\n const chatKitService = container.resolve('chatKitService');\n const chatKitStore = container.resolve('chatKitStore');\n const vectorService = container.resolve('vectorService');\n const config = container.resolve('config') as ApiContainerConfig;\n\n registerEdgeNodeSignalRoutes(server, {\n repository: nodeRepo,\n dnsCoordinator: container.resolve('dnsCoordinator', { allowUnregistered: true }) as any,\n healthProbeService: container.resolve('healthProbeService', { allowUnregistered: true }) as any,\n });\n registerNodeRoutes(server, { repository: nodeRepo });\n registerApiKeyRoutes(server, { store: apiKeyStore });\n registerChatRoutes(server, { chatService });\n registerChatKitRoutes(server, { chatKitService });\n registerChatKitV1Routes(server, { store: chatKitStore });\n registerVectorRoutes(server, { vectorService });\n\n // Quota & Usage API (Business 对接)\n try {\n const quotaService = new DrizzleQuotaService({ identityDbUrl: config.databaseUrl });\n const usageRepo = new UsageRepository(container.resolve('db'));\n registerQuotaRoutes(server, { quotaService, usageRepo });\n registerUsageRoutes(server, { usageRepo });\n console.log('[Shared] Quota & Usage routes registered');\n } catch (error) {\n console.log(`[Shared] Quota & Usage routes not registered: ${error}`);\n }\n}\n\n/**\n * Cloud 模式专属路由\n */\nfunction registerCloudRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n // 子域名管理 API (需要 SubdomainService)\n try {\n const subdomainService = container.resolve('subdomainService') as ApiContainerCradle['subdomainService'];\n if (subdomainService) {\n registerSubdomainRoutes(server, { subdomainService });\n console.log('[Cloud] Subdomain routes registered');\n }\n } catch {\n console.log('[Cloud] Subdomain routes not registered (service not available)');\n }\n\n // WebID Profile 托管服务\n try {\n const profileRepo = container.resolve('webIdProfileRepo', { allowUnregistered: true });\n if (profileRepo) {\n registerWebIdProfileRoutes(server, { profileRepo: profileRepo as any });\n console.log('[Cloud] WebID Profile routes registered');\n }\n } catch {\n console.log('[Cloud] WebID Profile routes not registered (repo not available)');\n }\n\n // DDNS 服务\n try {\n const ddnsRepo = container.resolve('ddnsRepo', { allowUnregistered: true });\n const dnsProvider = container.resolve('dnsProvider', { allowUnregistered: true });\n const config = container.resolve('config') as ApiContainerConfig;\n\n if (ddnsRepo) {\n const baseStorageDomain = config.subdomain?.baseStorageDomain;\n if (baseStorageDomain) {\n registerDdnsRoutes(server, {\n ddnsRepo: ddnsRepo as any,\n dnsProvider: dnsProvider as any,\n defaultDomain: baseStorageDomain,\n });\n console.log(`[Cloud] DDNS routes registered (domain: ${baseStorageDomain})`);\n } else {\n console.log('[Cloud] DDNS routes not registered (no CSS_BASE_STORAGE_DOMAIN)');\n }\n }\n } catch {\n console.log('[Cloud] DDNS routes not registered (repo not available)');\n }\n\n // SP Provision API (SP 注册)\n try {\n const nodeRepo = container.resolve('nodeRepo') as EdgeNodeRepository;\n const config = container.resolve('config') as ApiContainerConfig;\n const baseUrl = process.env.CSS_BASE_URL || 'http://localhost:3000/';\n const baseStorageDomain = config.subdomain?.baseStorageDomain;\n registerProvisionRoutes(server, { repository: nodeRepo, baseUrl, baseStorageDomain });\n console.log(`[Cloud] Provision routes registered${baseStorageDomain ? ` (baseStorageDomain: ${baseStorageDomain})` : ''}`);\n } catch {\n console.log('[Cloud] Provision routes not registered (dependencies not available)');\n }\n}\n\n/**\n * Local 模式专属路由\n */\nfunction registerLocalRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n // Admin API (配置管理、重启)\n registerAdminRoutes(server);\n\n // DDNS status (托管式 Local 模式)\n try {\n const ddnsManager = container.resolve('ddnsManager', { allowUnregistered: true }) as any;\n registerAdminDdnsRoutes(server, { ddnsManager });\n } catch {\n // ignore\n }\n\n // 子域名客户端 API (通过 SubdomainClient 调用 Cloud)\n try {\n const subdomainClient = container.resolve('subdomainClient') as ApiContainerCradle['subdomainClient'];\n if (subdomainClient) {\n registerSubdomainClientRoutes(server, { subdomainClient });\n console.log('[Local] Subdomain client routes registered');\n }\n } catch {\n console.log('[Local] Subdomain client routes not registered (client not available)');\n }\n\n // Pod Provision API (SP 端,供 Cloud 回调创建 Pod)\n try {\n // rootDir: CSS 数据目录,默认 ./data\n const rootDir = process.env.CSS_ROOT_FILE_PATH || './data';\n // serviceToken 验证:从 SP 配置中读取\n const expectedServiceToken = process.env.XPOD_SERVICE_TOKEN;\n\n if (expectedServiceToken) {\n registerPodManagementRoutes(server, {\n rootDir,\n verifyServiceToken: async (token: string) => token === expectedServiceToken,\n });\n console.log('[Local] Pod provision routes registered (/provision/pods)');\n } else {\n console.log('[Local] Pod provision routes not registered (XPOD_SERVICE_TOKEN not configured)');\n }\n } catch (error) {\n console.log(`[Local] Pod provision routes not registered: ${error}`);\n }\n\n // SP 状态查询 (供 Linx 查询 SP 配置状态)\n try {\n const config = container.resolve('config') as ApiContainerConfig;\n registerProvisionStatusRoute(server, {\n cloudUrl: config.cloudApiEndpoint,\n nodeId: config.nodeId,\n cloudBaseUrl: config.oidcIssuer || config.cloudApiEndpoint,\n });\n console.log('[Local] Provision status route registered (/provision/status)');\n } catch (error) {\n console.log(`[Local] Provision status route not registered: ${error}`);\n }\n}\n"]}
|
|
@@ -21,6 +21,8 @@ import type { ChatKitService, AiProvider } from '../chatkit';
|
|
|
21
21
|
import type { StoreContext } from '../chatkit/store';
|
|
22
22
|
import type { PodChatKitStore } from '../chatkit/pod-store';
|
|
23
23
|
import type { RuntimeHost } from '../../runtime/host/types';
|
|
24
|
+
import type { ProviderRegistry, EmbeddingService } from '../../ai/service';
|
|
25
|
+
import type { VectorService } from '../service/VectorService';
|
|
24
26
|
/**
|
|
25
27
|
* 容器配置
|
|
26
28
|
*/
|
|
@@ -86,6 +88,9 @@ export interface ApiContainerCradle {
|
|
|
86
88
|
chatKitStore: PodChatKitStore;
|
|
87
89
|
chatKitAiProvider: AiProvider;
|
|
88
90
|
chatKitService: ChatKitService<StoreContext>;
|
|
91
|
+
providerRegistry: ProviderRegistry;
|
|
92
|
+
embeddingService: EmbeddingService;
|
|
93
|
+
vectorService: VectorService;
|
|
89
94
|
webIdProfileRepo?: WebIdProfileRepository;
|
|
90
95
|
ddnsRepo?: DdnsRepository;
|
|
91
96
|
dnsProvider?: DnsProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/api/container/types.ts"],"names":[],"mappings":";AAAA;;;;GAIG","sourcesContent":["/**\n * API Container 依赖类型定义\n *\n * 定义容器中注册的所有服务接口\n */\n\nimport type { ApiServer } from '../ApiServer';\nimport type { AuthMiddleware } from '../middleware/AuthMiddleware';\nimport type { Authenticator } from '../auth/Authenticator';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { ServiceTokenRepository } from '../../identity/drizzle/ServiceTokenRepository';\nimport type { DrizzleClientCredentialsStore } from '../store/DrizzleClientCredentialsStore';\nimport type { VercelChatService } from '../service/VercelChatService';\nimport type { SubdomainService } from '../../subdomain/SubdomainService';\nimport type { SubdomainClient } from '../../subdomain/SubdomainClient';\nimport type { DnsProvider } from '../../dns/DnsProvider';\nimport type { TunnelProvider } from '../../tunnel/TunnelProvider';\nimport type { IdentityDatabase } from '../../identity/drizzle/db';\nimport type { WebIdProfileRepository } from '../../identity/drizzle/WebIdProfileRepository';\nimport type { DdnsRepository } from '../../identity/drizzle/DdnsRepository';\nimport type { ChatKitService, AiProvider } from '../chatkit';\nimport type { StoreContext } from '../chatkit/store';\nimport type { PodChatKitStore } from '../chatkit/pod-store';\nimport type { RuntimeHost } from '../../runtime/host/types';\n\n/**\n * 容器配置\n */\nexport interface ApiContainerConfig {\n /** 运行模式: cloud 持有密钥, local 调用远程 */\n edition: 'cloud' | 'local';\n\n /** API Server 端口 */\n port: number;\n\n /** API Server 主机 */\n host: string;\n\n /** API Server Unix socket 路径 */\n socketPath?: string;\n\n /** Runtime host implementation */\n runtimeHost?: RuntimeHost;\n /** 数据库连接 URL */\n databaseUrl: string;\n\n /** CORS 允许的源 */\n corsOrigins: string[];\n\n /** CSS Token 端点 */\n cssTokenEndpoint: string;\n\n /** 子域名功能配置 (cloud 模式) */\n subdomain?: {\n /** 节点域名根域名 (如 undefineds.site),有值即启用子域名功能 */\n baseStorageDomain?: string;\n cloudflareAccountId?: string;\n cloudflareApiToken?: string;\n tencentDnsSecretId?: string;\n tencentDnsSecretKey?: string;\n };\n\n /** Cloud API 端点 (local 托管式,调用 cloud 的子域名 API) */\n cloudApiEndpoint?: string;\n\n /** 节点 ID (local 托管式) */\n nodeId?: string;\n\n /** 节点 Token (local 托管式,调用 Cloud API 的认证) */\n nodeToken?: string;\n\n /** OIDC Issuer URL (local 托管式,使用 Cloud IdP) */\n oidcIssuer?: string;\n\n /** Cloudflare Tunnel Token (local 托管式/自管式,启动 cloudflared) */\n cloudflareTunnelToken?: string;\n\n /** SakuraFRP Tunnel Token (SAKURA_TUNNEL_TOKEN;local 托管式/自管式,启动 frpc) */\n sakuraTunnelToken?: string;\n\n /** 是否接受 Edge 节点注册 (cloud 模式) */\n edgeNodesEnabled?: boolean;\n}\n\nimport { EdgeNodeDnsCoordinator } from '../../edge/EdgeNodeDnsCoordinator';\nimport { EdgeNodeHealthProbeService } from '../../edge/EdgeNodeHealthProbeService';\nimport { EdgeNodeCapabilityDetector } from '../../edge/EdgeNodeCapabilityDetector';\nimport { LocalNetworkManager } from '../../edge/LocalNetworkManager';\nimport { DdnsManager } from '../../edge/DdnsManager';\n\n/**\n * 容器中注册的所有服务\n */\nexport interface ApiContainerCradle {\n // 配置\n config: ApiContainerConfig;\n\n // 核心服务\n db: IdentityDatabase;\n apiServer: ApiServer;\n authMiddleware: AuthMiddleware;\n authenticator: Authenticator;\n\n // 仓库\n nodeRepo: EdgeNodeRepository;\n serviceTokenRepo: ServiceTokenRepository;\n apiKeyStore: DrizzleClientCredentialsStore;\n\n // 业务服务\n chatService: VercelChatService;\n\n // ChatKit 服务 (OpenAI ChatKit 协议)\n chatKitStore: PodChatKitStore;\n chatKitAiProvider: AiProvider;\n chatKitService: ChatKitService<StoreContext>;\n\n // Cloud 模式: 身份服务\n webIdProfileRepo?: WebIdProfileRepository;\n ddnsRepo?: DdnsRepository;\n\n // 子域名相关 (可选,按 edition 注册)\n // Cloud 模式 或 Local 自管模式\n dnsProvider?: DnsProvider;\n dnsCoordinator?: EdgeNodeDnsCoordinator;\n healthProbeService?: EdgeNodeHealthProbeService;\n capabilityDetector?: EdgeNodeCapabilityDetector;\n localNetworkManager?: LocalNetworkManager;\n\n tunnelProvider?: TunnelProvider;\n subdomainService?: SubdomainService;\n // Local 托管式\n subdomainClient?: SubdomainClient;\n // Local 托管式 DDNS 管理\n ddnsManager?: DdnsManager;\n // Local 托管式/自管式 (启动 cloudflared)\n localTunnelProvider?: TunnelProvider;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/api/container/types.ts"],"names":[],"mappings":";AAAA;;;;GAIG","sourcesContent":["/**\n * API Container 依赖类型定义\n *\n * 定义容器中注册的所有服务接口\n */\n\nimport type { ApiServer } from '../ApiServer';\nimport type { AuthMiddleware } from '../middleware/AuthMiddleware';\nimport type { Authenticator } from '../auth/Authenticator';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { ServiceTokenRepository } from '../../identity/drizzle/ServiceTokenRepository';\nimport type { DrizzleClientCredentialsStore } from '../store/DrizzleClientCredentialsStore';\nimport type { VercelChatService } from '../service/VercelChatService';\nimport type { SubdomainService } from '../../subdomain/SubdomainService';\nimport type { SubdomainClient } from '../../subdomain/SubdomainClient';\nimport type { DnsProvider } from '../../dns/DnsProvider';\nimport type { TunnelProvider } from '../../tunnel/TunnelProvider';\nimport type { IdentityDatabase } from '../../identity/drizzle/db';\nimport type { WebIdProfileRepository } from '../../identity/drizzle/WebIdProfileRepository';\nimport type { DdnsRepository } from '../../identity/drizzle/DdnsRepository';\nimport type { ChatKitService, AiProvider } from '../chatkit';\nimport type { StoreContext } from '../chatkit/store';\nimport type { PodChatKitStore } from '../chatkit/pod-store';\nimport type { RuntimeHost } from '../../runtime/host/types';\nimport type { ProviderRegistry, EmbeddingService } from '../../ai/service';\nimport type { VectorService } from '../service/VectorService';\n\n/**\n * 容器配置\n */\nexport interface ApiContainerConfig {\n /** 运行模式: cloud 持有密钥, local 调用远程 */\n edition: 'cloud' | 'local';\n\n /** API Server 端口 */\n port: number;\n\n /** API Server 主机 */\n host: string;\n\n /** API Server Unix socket 路径 */\n socketPath?: string;\n\n /** Runtime host implementation */\n runtimeHost?: RuntimeHost;\n /** 数据库连接 URL */\n databaseUrl: string;\n\n /** CORS 允许的源 */\n corsOrigins: string[];\n\n /** CSS Token 端点 */\n cssTokenEndpoint: string;\n\n /** 子域名功能配置 (cloud 模式) */\n subdomain?: {\n /** 节点域名根域名 (如 undefineds.site),有值即启用子域名功能 */\n baseStorageDomain?: string;\n cloudflareAccountId?: string;\n cloudflareApiToken?: string;\n tencentDnsSecretId?: string;\n tencentDnsSecretKey?: string;\n };\n\n /** Cloud API 端点 (local 托管式,调用 cloud 的子域名 API) */\n cloudApiEndpoint?: string;\n\n /** 节点 ID (local 托管式) */\n nodeId?: string;\n\n /** 节点 Token (local 托管式,调用 Cloud API 的认证) */\n nodeToken?: string;\n\n /** OIDC Issuer URL (local 托管式,使用 Cloud IdP) */\n oidcIssuer?: string;\n\n /** Cloudflare Tunnel Token (local 托管式/自管式,启动 cloudflared) */\n cloudflareTunnelToken?: string;\n\n /** SakuraFRP Tunnel Token (SAKURA_TUNNEL_TOKEN;local 托管式/自管式,启动 frpc) */\n sakuraTunnelToken?: string;\n\n /** 是否接受 Edge 节点注册 (cloud 模式) */\n edgeNodesEnabled?: boolean;\n}\n\nimport { EdgeNodeDnsCoordinator } from '../../edge/EdgeNodeDnsCoordinator';\nimport { EdgeNodeHealthProbeService } from '../../edge/EdgeNodeHealthProbeService';\nimport { EdgeNodeCapabilityDetector } from '../../edge/EdgeNodeCapabilityDetector';\nimport { LocalNetworkManager } from '../../edge/LocalNetworkManager';\nimport { DdnsManager } from '../../edge/DdnsManager';\n\n/**\n * 容器中注册的所有服务\n */\nexport interface ApiContainerCradle {\n // 配置\n config: ApiContainerConfig;\n\n // 核心服务\n db: IdentityDatabase;\n apiServer: ApiServer;\n authMiddleware: AuthMiddleware;\n authenticator: Authenticator;\n\n // 仓库\n nodeRepo: EdgeNodeRepository;\n serviceTokenRepo: ServiceTokenRepository;\n apiKeyStore: DrizzleClientCredentialsStore;\n\n // 业务服务\n chatService: VercelChatService;\n\n // ChatKit 服务 (OpenAI ChatKit 协议)\n chatKitStore: PodChatKitStore;\n chatKitAiProvider: AiProvider;\n chatKitService: ChatKitService<StoreContext>;\n providerRegistry: ProviderRegistry;\n embeddingService: EmbeddingService;\n vectorService: VectorService;\n\n // Cloud 模式: 身份服务\n webIdProfileRepo?: WebIdProfileRepository;\n ddnsRepo?: DdnsRepository;\n\n // 子域名相关 (可选,按 edition 注册)\n // Cloud 模式 或 Local 自管模式\n dnsProvider?: DnsProvider;\n dnsCoordinator?: EdgeNodeDnsCoordinator;\n healthProbeService?: EdgeNodeHealthProbeService;\n capabilityDetector?: EdgeNodeCapabilityDetector;\n localNetworkManager?: LocalNetworkManager;\n\n tunnelProvider?: TunnelProvider;\n subdomainService?: SubdomainService;\n // Local 托管式\n subdomainClient?: SubdomainClient;\n // Local 托管式 DDNS 管理\n ddnsManager?: DdnsManager;\n // Local 托管式/自管式 (启动 cloudflared)\n localTunnelProvider?: TunnelProvider;\n}\n"]}
|
|
@@ -5,9 +5,12 @@ import type { UsageRepository } from '../../storage/quota/UsageRepository';
|
|
|
5
5
|
import type { QuotaService } from '../../quota/QuotaService';
|
|
6
6
|
export declare class VercelChatService {
|
|
7
7
|
private readonly store;
|
|
8
|
+
private static readonly AI_GATEWAY_MODEL_CACHE_TTL_MS;
|
|
8
9
|
private readonly logger;
|
|
9
10
|
private usageRepo?;
|
|
10
11
|
private quotaService?;
|
|
12
|
+
private aiGatewayModelCache;
|
|
13
|
+
private aiGatewayModelCachePromise;
|
|
11
14
|
constructor(store: PodChatKitStore);
|
|
12
15
|
/**
|
|
13
16
|
* Set optional usage tracking dependencies (injected after construction)
|
|
@@ -18,13 +21,13 @@ export declare class VercelChatService {
|
|
|
18
21
|
*/
|
|
19
22
|
private createStoreContext;
|
|
20
23
|
private getAiGatewayBaseUrl;
|
|
21
|
-
private getAiGatewayEntryModels;
|
|
22
24
|
private getAiGatewayTimeoutMs;
|
|
25
|
+
private getAiGatewayApiKey;
|
|
26
|
+
private toModelId;
|
|
27
|
+
private isAiGatewayModelCacheFresh;
|
|
28
|
+
private getAiGatewayModelCache;
|
|
23
29
|
private shouldUseAiGateway;
|
|
24
30
|
private buildAiGatewayUrl;
|
|
25
|
-
private getForwardedAccessToken;
|
|
26
|
-
private getForwardedTokenType;
|
|
27
|
-
private getForwardedDpopProof;
|
|
28
31
|
private createAiGatewayAbortSignal;
|
|
29
32
|
private sendAiGatewayRequest;
|
|
30
33
|
private forwardAiGatewayJson;
|
|
@@ -45,7 +48,7 @@ export declare class VercelChatService {
|
|
|
45
48
|
private messagesViaCompletions;
|
|
46
49
|
private extractPromptFromResponsesBody;
|
|
47
50
|
private extractPromptFromMessagesBody;
|
|
48
|
-
listModels(
|
|
51
|
+
listModels(_auth?: AuthContext): Promise<any[]>;
|
|
49
52
|
private mapFinishReason;
|
|
50
53
|
/**
|
|
51
54
|
* Handle API errors and update credential status accordingly
|
|
@@ -17,6 +17,8 @@ class VercelChatService {
|
|
|
17
17
|
constructor(store) {
|
|
18
18
|
this.store = store;
|
|
19
19
|
this.logger = (0, global_logger_factory_1.getLoggerFor)(this);
|
|
20
|
+
this.aiGatewayModelCache = null;
|
|
21
|
+
this.aiGatewayModelCachePromise = null;
|
|
20
22
|
this.logger.info('Initializing VercelChatService with Pod-based config support');
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
@@ -39,12 +41,6 @@ class VercelChatService {
|
|
|
39
41
|
const raw = process.env.XPOD_AI_GATEWAY_BASE_URL?.trim();
|
|
40
42
|
return raw ? raw.replace(/\/$/, '') : null;
|
|
41
43
|
}
|
|
42
|
-
getAiGatewayEntryModels() {
|
|
43
|
-
return new Set((process.env.XPOD_AI_GATEWAY_ENTRY_MODELS ?? '')
|
|
44
|
-
.split(',')
|
|
45
|
-
.map((value) => value.trim())
|
|
46
|
-
.filter(Boolean));
|
|
47
|
-
}
|
|
48
44
|
getAiGatewayTimeoutMs() {
|
|
49
45
|
const raw = process.env.XPOD_AI_GATEWAY_TIMEOUT_MS?.trim();
|
|
50
46
|
if (!raw) {
|
|
@@ -53,11 +49,63 @@ class VercelChatService {
|
|
|
53
49
|
const parsed = Number(raw);
|
|
54
50
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : 30_000;
|
|
55
51
|
}
|
|
56
|
-
|
|
52
|
+
getAiGatewayApiKey() {
|
|
53
|
+
const raw = process.env.XPOD_AI_GATEWAY_API_KEY?.trim()
|
|
54
|
+
?? process.env.AI_GATEWAY_SERVICE_API_KEY?.trim();
|
|
55
|
+
return raw || null;
|
|
56
|
+
}
|
|
57
|
+
toModelId(model) {
|
|
58
|
+
return typeof model?.id === 'string' ? model.id : JSON.stringify(model);
|
|
59
|
+
}
|
|
60
|
+
isAiGatewayModelCacheFresh() {
|
|
61
|
+
return !!this.aiGatewayModelCache
|
|
62
|
+
&& Date.now() - this.aiGatewayModelCache.fetchedAt < VercelChatService.AI_GATEWAY_MODEL_CACHE_TTL_MS;
|
|
63
|
+
}
|
|
64
|
+
async getAiGatewayModelCache() {
|
|
65
|
+
if (!this.getAiGatewayBaseUrl()) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
if (this.isAiGatewayModelCacheFresh()) {
|
|
69
|
+
return this.aiGatewayModelCache;
|
|
70
|
+
}
|
|
71
|
+
if (this.aiGatewayModelCachePromise) {
|
|
72
|
+
return this.aiGatewayModelCachePromise;
|
|
73
|
+
}
|
|
74
|
+
this.aiGatewayModelCachePromise = (async () => {
|
|
75
|
+
const response = await this.sendAiGatewayRequest('/v1/models', 'GET', undefined, {
|
|
76
|
+
'Accept': 'application/json',
|
|
77
|
+
});
|
|
78
|
+
const data = await response.json();
|
|
79
|
+
const items = Array.isArray(data.data) ? data.data : [];
|
|
80
|
+
const cache = {
|
|
81
|
+
fetchedAt: Date.now(),
|
|
82
|
+
items,
|
|
83
|
+
modelIds: new Set(items.map((item) => this.toModelId(item))),
|
|
84
|
+
};
|
|
85
|
+
this.aiGatewayModelCache = cache;
|
|
86
|
+
return cache;
|
|
87
|
+
})();
|
|
88
|
+
try {
|
|
89
|
+
return await this.aiGatewayModelCachePromise;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
if (this.aiGatewayModelCache) {
|
|
93
|
+
this.logger.warn(`Failed to refresh ai-gateway models, using stale cache: ${error}`);
|
|
94
|
+
return this.aiGatewayModelCache;
|
|
95
|
+
}
|
|
96
|
+
this.logger.warn(`Failed to fetch ai-gateway models: ${error}`);
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
this.aiGatewayModelCachePromise = null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async shouldUseAiGateway(model) {
|
|
57
104
|
if (!model || !this.getAiGatewayBaseUrl()) {
|
|
58
105
|
return false;
|
|
59
106
|
}
|
|
60
|
-
|
|
107
|
+
const cache = await this.getAiGatewayModelCache();
|
|
108
|
+
return cache?.modelIds.has(model) ?? false;
|
|
61
109
|
}
|
|
62
110
|
buildAiGatewayUrl(path) {
|
|
63
111
|
const baseUrl = this.getAiGatewayBaseUrl();
|
|
@@ -70,46 +118,19 @@ class VercelChatService {
|
|
|
70
118
|
}
|
|
71
119
|
return `${baseUrl}${normalizedPath}`;
|
|
72
120
|
}
|
|
73
|
-
getForwardedAccessToken(auth) {
|
|
74
|
-
if (auth.type !== 'solid') {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
const rawToken = auth.accessToken ?? auth.token;
|
|
78
|
-
return rawToken?.trim() || null;
|
|
79
|
-
}
|
|
80
|
-
getForwardedTokenType(auth) {
|
|
81
|
-
if (auth.type !== 'solid') {
|
|
82
|
-
return 'Bearer';
|
|
83
|
-
}
|
|
84
|
-
return auth.tokenType ?? 'Bearer';
|
|
85
|
-
}
|
|
86
|
-
getForwardedDpopProof(auth) {
|
|
87
|
-
if (auth.type !== 'solid') {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
return auth.dpopProof?.trim() || null;
|
|
91
|
-
}
|
|
92
121
|
createAiGatewayAbortSignal() {
|
|
93
122
|
const abortSignal = AbortSignal;
|
|
94
123
|
return typeof abortSignal.timeout === 'function'
|
|
95
124
|
? abortSignal.timeout(this.getAiGatewayTimeoutMs())
|
|
96
125
|
: undefined;
|
|
97
126
|
}
|
|
98
|
-
async sendAiGatewayRequest(path,
|
|
99
|
-
const
|
|
100
|
-
if (!
|
|
101
|
-
throw new Error('
|
|
102
|
-
}
|
|
103
|
-
const tokenType = this.getForwardedTokenType(auth);
|
|
104
|
-
const dpopProof = this.getForwardedDpopProof(auth);
|
|
105
|
-
if (tokenType === 'DPoP' && !dpopProof) {
|
|
106
|
-
throw new Error('DPoP token forwarding requires dpopProof in auth context');
|
|
127
|
+
async sendAiGatewayRequest(path, method, body, headers) {
|
|
128
|
+
const apiKey = this.getAiGatewayApiKey();
|
|
129
|
+
if (!apiKey) {
|
|
130
|
+
throw new Error('XPOD_AI_GATEWAY_API_KEY is not configured');
|
|
107
131
|
}
|
|
108
132
|
const requestHeaders = new Headers(headers);
|
|
109
|
-
requestHeaders.set('Authorization',
|
|
110
|
-
if (tokenType === 'DPoP' && dpopProof) {
|
|
111
|
-
requestHeaders.set('DPoP', dpopProof);
|
|
112
|
-
}
|
|
133
|
+
requestHeaders.set('Authorization', `Bearer ${apiKey}`);
|
|
113
134
|
if (body !== undefined && !requestHeaders.has('Content-Type')) {
|
|
114
135
|
requestHeaders.set('Content-Type', 'application/json');
|
|
115
136
|
}
|
|
@@ -130,14 +151,14 @@ class VercelChatService {
|
|
|
130
151
|
}
|
|
131
152
|
return response;
|
|
132
153
|
}
|
|
133
|
-
async forwardAiGatewayJson(path, body,
|
|
134
|
-
const response = await this.sendAiGatewayRequest(path,
|
|
154
|
+
async forwardAiGatewayJson(path, body, _auth) {
|
|
155
|
+
const response = await this.sendAiGatewayRequest(path, 'POST', body, {
|
|
135
156
|
'Accept': 'application/json',
|
|
136
157
|
});
|
|
137
158
|
return response.json();
|
|
138
159
|
}
|
|
139
|
-
async forwardAiGatewayStream(path, body,
|
|
140
|
-
const response = await this.sendAiGatewayRequest(path,
|
|
160
|
+
async forwardAiGatewayStream(path, body, _auth) {
|
|
161
|
+
const response = await this.sendAiGatewayRequest(path, 'POST', body, {
|
|
141
162
|
'Accept': 'text/event-stream',
|
|
142
163
|
});
|
|
143
164
|
return {
|
|
@@ -294,7 +315,7 @@ class VercelChatService {
|
|
|
294
315
|
if (accountId) {
|
|
295
316
|
await this.checkTokenQuota(accountId);
|
|
296
317
|
}
|
|
297
|
-
if (this.shouldUseAiGateway(model)) {
|
|
318
|
+
if (await this.shouldUseAiGateway(model)) {
|
|
298
319
|
this.logger.info(`Forwarding chat completion for model ${model} to ai-gateway`);
|
|
299
320
|
const result = await this.forwardAiGatewayJson('/v1/chat/completions', request, auth);
|
|
300
321
|
this.recordForwardedUsage(accountId, String(context.userId), result);
|
|
@@ -363,7 +384,7 @@ class VercelChatService {
|
|
|
363
384
|
async stream(request, auth) {
|
|
364
385
|
const { model, messages, temperature, max_tokens } = request;
|
|
365
386
|
const context = this.createStoreContext(auth);
|
|
366
|
-
if (this.shouldUseAiGateway(model)) {
|
|
387
|
+
if (await this.shouldUseAiGateway(model)) {
|
|
367
388
|
this.logger.info(`Forwarding chat stream for model ${model} to ai-gateway`);
|
|
368
389
|
return this.forwardAiGatewayStream('/v1/chat/completions', request, auth);
|
|
369
390
|
}
|
|
@@ -389,7 +410,7 @@ class VercelChatService {
|
|
|
389
410
|
const context = this.createStoreContext(auth);
|
|
390
411
|
const displayName = (0, AuthContext_1.getDisplayName)(auth) || context.userId;
|
|
391
412
|
const accountId = (0, AuthContext_1.getAccountId)(auth);
|
|
392
|
-
if (this.shouldUseAiGateway(body?.model)) {
|
|
413
|
+
if (await this.shouldUseAiGateway(body?.model)) {
|
|
393
414
|
this.logger.info(`Forwarding responses request for model ${body?.model} to ai-gateway for ${displayName} (acc: ${accountId})`);
|
|
394
415
|
const result = await this.forwardAiGatewayJson('/v1/responses', body, auth);
|
|
395
416
|
this.recordForwardedUsage(accountId, String(context.userId), result);
|
|
@@ -448,7 +469,7 @@ class VercelChatService {
|
|
|
448
469
|
const context = this.createStoreContext(auth);
|
|
449
470
|
const displayName = (0, AuthContext_1.getDisplayName)(auth) || context.userId;
|
|
450
471
|
const accountId = (0, AuthContext_1.getAccountId)(auth);
|
|
451
|
-
if (this.shouldUseAiGateway(body?.model)) {
|
|
472
|
+
if (await this.shouldUseAiGateway(body?.model)) {
|
|
452
473
|
this.logger.info(`Forwarding messages request for model ${body?.model} to ai-gateway for ${displayName} (acc: ${accountId})`);
|
|
453
474
|
const completionBody = this.buildChatCompletionsBodyFromMessages(body);
|
|
454
475
|
const completion = await this.forwardAiGatewayJson('/v1/chat/completions', completionBody, auth);
|
|
@@ -650,12 +671,12 @@ class VercelChatService {
|
|
|
650
671
|
}
|
|
651
672
|
return '';
|
|
652
673
|
}
|
|
653
|
-
async listModels(
|
|
674
|
+
async listModels(_auth) {
|
|
654
675
|
const models = [];
|
|
655
676
|
const seenModelIds = new Set();
|
|
656
677
|
const pushModels = (items) => {
|
|
657
678
|
for (const model of items) {
|
|
658
|
-
const modelId =
|
|
679
|
+
const modelId = this.toModelId(model);
|
|
659
680
|
if (seenModelIds.has(modelId)) {
|
|
660
681
|
continue;
|
|
661
682
|
}
|
|
@@ -663,20 +684,9 @@ class VercelChatService {
|
|
|
663
684
|
models.push(model);
|
|
664
685
|
}
|
|
665
686
|
};
|
|
666
|
-
const
|
|
667
|
-
if (
|
|
668
|
-
|
|
669
|
-
const response = await this.sendAiGatewayRequest('/v1/models', auth, 'GET', undefined, {
|
|
670
|
-
'Accept': 'application/json',
|
|
671
|
-
});
|
|
672
|
-
const data = await response.json();
|
|
673
|
-
if (Array.isArray(data.data)) {
|
|
674
|
-
pushModels(data.data);
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
catch (error) {
|
|
678
|
-
this.logger.warn(`Failed to fetch ai-gateway models: ${error}`);
|
|
679
|
-
}
|
|
687
|
+
const aiGatewayCache = await this.getAiGatewayModelCache();
|
|
688
|
+
if (aiGatewayCache) {
|
|
689
|
+
pushModels(aiGatewayCache.items);
|
|
680
690
|
}
|
|
681
691
|
// 平台 Provider 模型(从 DEFAULT_API_BASE 获取)
|
|
682
692
|
const platformBase = process.env.DEFAULT_API_BASE;
|
|
@@ -805,4 +815,5 @@ class VercelChatService {
|
|
|
805
815
|
}
|
|
806
816
|
}
|
|
807
817
|
exports.VercelChatService = VercelChatService;
|
|
818
|
+
VercelChatService.AI_GATEWAY_MODEL_CACHE_TTL_MS = 30_000;
|
|
808
819
|
//# sourceMappingURL=VercelChatService.js.map
|