@undefineds.co/xpod 0.1.6 → 0.2.0-preview.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -2
- 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/api/ApiServer.js +1 -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.js +19 -3
- package/dist/api/chatkit/pod-store.js.map +1 -1
- package/dist/api/chatkit/schema.d.ts +9 -3
- package/dist/api/chatkit/schema.js +14 -6
- 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 +12 -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 -15
- 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 +104 -0
- package/dist/api/runtime.js.map +1 -0
- 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/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 +143 -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 +208 -1
- 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/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 +23 -5
- 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
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.startApiService = startApiService;
|
|
4
|
+
const awilix_1 = require("awilix");
|
|
5
|
+
const global_logger_factory_1 = require("global-logger-factory");
|
|
6
|
+
const ConfigurableLoggerFactory_1 = require("../logging/ConfigurableLoggerFactory");
|
|
7
|
+
const container_1 = require("./container");
|
|
8
|
+
const routes_1 = require("./container/routes");
|
|
9
|
+
const OpenAuthMiddleware_1 = require("./middleware/OpenAuthMiddleware");
|
|
10
|
+
function initApiLogger() {
|
|
11
|
+
const loggerFactory = new ConfigurableLoggerFactory_1.ConfigurableLoggerFactory(process.env.CSS_LOGGING_LEVEL || 'info', {
|
|
12
|
+
fileName: './logs/xpod-%DATE%.log',
|
|
13
|
+
showLocation: true,
|
|
14
|
+
});
|
|
15
|
+
(0, global_logger_factory_1.setGlobalLoggerFactory)(loggerFactory);
|
|
16
|
+
}
|
|
17
|
+
async function startBackgroundServices(container, logger) {
|
|
18
|
+
try {
|
|
19
|
+
const localNetworkManager = container.resolve('localNetworkManager', { allowUnregistered: true });
|
|
20
|
+
if (localNetworkManager) {
|
|
21
|
+
localNetworkManager.start();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
logger.error(`Failed to initialize LocalNetworkManager: ${error}`);
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const ddnsManager = container.resolve('ddnsManager', { allowUnregistered: true });
|
|
29
|
+
if (ddnsManager) {
|
|
30
|
+
await ddnsManager.start();
|
|
31
|
+
logger.info('DDNS Manager started');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
logger.error(`Failed to initialize DdnsManager: ${error}`);
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const localNetworkManager = container.resolve('localNetworkManager', { allowUnregistered: true });
|
|
39
|
+
const localTunnelProvider = container.resolve('localTunnelProvider', { allowUnregistered: true });
|
|
40
|
+
if (!localNetworkManager && localTunnelProvider) {
|
|
41
|
+
logger.info('Starting Cloudflare Tunnel (standalone mode)...');
|
|
42
|
+
await localTunnelProvider.start();
|
|
43
|
+
logger.info('Cloudflare Tunnel started');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
logger.error(`Failed to start Cloudflare Tunnel: ${error}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function stopBackgroundServices(container) {
|
|
51
|
+
try {
|
|
52
|
+
const ddnsManager = container.resolve('ddnsManager', { allowUnregistered: true });
|
|
53
|
+
ddnsManager?.stop();
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// ignore shutdown errors
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const localNetworkManager = container.resolve('localNetworkManager', { allowUnregistered: true });
|
|
60
|
+
await localNetworkManager?.stop();
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// ignore shutdown errors
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const localTunnelProvider = container.resolve('localTunnelProvider', { allowUnregistered: true });
|
|
67
|
+
await localTunnelProvider?.stop();
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// ignore shutdown errors
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function startApiService(options = {}) {
|
|
74
|
+
if (options.initializeLogger !== false) {
|
|
75
|
+
initApiLogger();
|
|
76
|
+
}
|
|
77
|
+
const config = options.config ?? (0, container_1.loadConfigFromEnv)();
|
|
78
|
+
const logger = (0, global_logger_factory_1.getLoggerFor)('ApiRuntime');
|
|
79
|
+
if (!config.databaseUrl) {
|
|
80
|
+
throw new Error('CSS_IDENTITY_DB_URL or DATABASE_URL environment variable is required');
|
|
81
|
+
}
|
|
82
|
+
logger.info(`Starting API Service (edition: ${config.edition})...`);
|
|
83
|
+
const container = (0, container_1.createApiContainer)(config);
|
|
84
|
+
if (options.open) {
|
|
85
|
+
container.register({
|
|
86
|
+
authMiddleware: (0, awilix_1.asValue)(new OpenAuthMiddleware_1.OpenAuthMiddleware({ context: options.authContext })),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
(0, routes_1.registerRoutes)(container);
|
|
90
|
+
await startBackgroundServices(container, logger);
|
|
91
|
+
const server = container.resolve('apiServer');
|
|
92
|
+
await server.start();
|
|
93
|
+
logger.info(`API Service active on ${config.socketPath ? `unix://${config.socketPath}` : `${config.host}:${config.port}`}`);
|
|
94
|
+
return {
|
|
95
|
+
config,
|
|
96
|
+
container,
|
|
97
|
+
stop: async () => {
|
|
98
|
+
logger.info('Stopping API Service...');
|
|
99
|
+
await stopBackgroundServices(container);
|
|
100
|
+
await server.stop();
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/api/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { asValue, type AwilixContainer } from 'awilix';\nimport { setGlobalLoggerFactory, getLoggerFor } from 'global-logger-factory';\nimport { ConfigurableLoggerFactory } from '../logging/ConfigurableLoggerFactory';\nimport { createApiContainer, loadConfigFromEnv, type ApiContainerConfig, type ApiContainerCradle } from './container';\nimport { registerRoutes } from './container/routes';\nimport type { AuthContext } from './auth/AuthContext';\nimport { OpenAuthMiddleware } from './middleware/OpenAuthMiddleware';\n\nexport interface StartApiServiceOptions {\n config?: ApiContainerConfig;\n open?: boolean;\n authContext?: AuthContext;\n initializeLogger?: boolean;\n}\n\nexport interface ApiServiceHandle {\n config: ApiContainerConfig;\n container: AwilixContainer<ApiContainerCradle>;\n stop: () => Promise<void>;\n}\n\nfunction initApiLogger(): void {\n const loggerFactory = new ConfigurableLoggerFactory(process.env.CSS_LOGGING_LEVEL || 'info', {\n fileName: './logs/xpod-%DATE%.log',\n showLocation: true,\n });\n setGlobalLoggerFactory(loggerFactory);\n}\n\nasync function startBackgroundServices(\n container: AwilixContainer<ApiContainerCradle>,\n logger: ReturnType<typeof getLoggerFor>,\n): Promise<void> {\n try {\n const localNetworkManager = container.resolve('localNetworkManager', { allowUnregistered: true }) as any;\n if (localNetworkManager) {\n localNetworkManager.start();\n }\n } catch (error) {\n logger.error(`Failed to initialize LocalNetworkManager: ${error}`);\n }\n\n try {\n const ddnsManager = container.resolve('ddnsManager', { allowUnregistered: true }) as any;\n if (ddnsManager) {\n await ddnsManager.start();\n logger.info('DDNS Manager started');\n }\n } catch (error) {\n logger.error(`Failed to initialize DdnsManager: ${error}`);\n }\n\n try {\n const localNetworkManager = container.resolve('localNetworkManager', { allowUnregistered: true });\n const localTunnelProvider = container.resolve('localTunnelProvider', { allowUnregistered: true }) as any;\n\n if (!localNetworkManager && localTunnelProvider) {\n logger.info('Starting Cloudflare Tunnel (standalone mode)...');\n await localTunnelProvider.start();\n logger.info('Cloudflare Tunnel started');\n }\n } catch (error) {\n logger.error(`Failed to start Cloudflare Tunnel: ${error}`);\n }\n}\n\nasync function stopBackgroundServices(container: AwilixContainer<ApiContainerCradle>): Promise<void> {\n try {\n const ddnsManager = container.resolve('ddnsManager', { allowUnregistered: true }) as any;\n ddnsManager?.stop();\n } catch {\n // ignore shutdown errors\n }\n\n try {\n const localNetworkManager = container.resolve('localNetworkManager', { allowUnregistered: true });\n await localNetworkManager?.stop();\n } catch {\n // ignore shutdown errors\n }\n\n try {\n const localTunnelProvider = container.resolve('localTunnelProvider', { allowUnregistered: true }) as any;\n await localTunnelProvider?.stop();\n } catch {\n // ignore shutdown errors\n }\n}\n\nexport async function startApiService(options: StartApiServiceOptions = {}): Promise<ApiServiceHandle> {\n if (options.initializeLogger !== false) {\n initApiLogger();\n }\n\n const config = options.config ?? loadConfigFromEnv();\n const logger = getLoggerFor('ApiRuntime');\n\n if (!config.databaseUrl) {\n throw new Error('CSS_IDENTITY_DB_URL or DATABASE_URL environment variable is required');\n }\n\n logger.info(`Starting API Service (edition: ${config.edition})...`);\n\n const container = createApiContainer(config);\n\n if (options.open) {\n container.register({\n authMiddleware: asValue(new OpenAuthMiddleware({ context: options.authContext })),\n });\n }\n\n registerRoutes(container);\n await startBackgroundServices(container, logger);\n\n const server = container.resolve('apiServer');\n await server.start();\n logger.info(`API Service active on ${config.socketPath ? `unix://${config.socketPath}` : `${config.host}:${config.port}`}`);\n\n return {\n config,\n container,\n stop: async(): Promise<void> => {\n logger.info('Stopping API Service...');\n await stopBackgroundServices(container);\n await server.stop();\n },\n };\n}\n"]}
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import type { ChatCompletionRequest, ChatCompletionResponse } from '../handlers/ChatHandler';
|
|
2
2
|
import type { PodChatKitStore } from '../chatkit/pod-store';
|
|
3
3
|
import { type AuthContext } from '../auth/AuthContext';
|
|
4
|
+
import type { UsageRepository } from '../../storage/quota/UsageRepository';
|
|
5
|
+
import type { QuotaService } from '../../quota/QuotaService';
|
|
4
6
|
export declare class VercelChatService {
|
|
5
7
|
private readonly store;
|
|
6
8
|
private readonly logger;
|
|
9
|
+
private usageRepo?;
|
|
10
|
+
private quotaService?;
|
|
7
11
|
constructor(store: PodChatKitStore);
|
|
12
|
+
/**
|
|
13
|
+
* Set optional usage tracking dependencies (injected after construction)
|
|
14
|
+
*/
|
|
15
|
+
setUsageTracking(usageRepo: UsageRepository, quotaService: QuotaService): void;
|
|
8
16
|
/**
|
|
9
17
|
* Create a StoreContext from AuthContext for Pod operations
|
|
10
18
|
*/
|
|
@@ -17,16 +25,9 @@ export declare class VercelChatService {
|
|
|
17
25
|
messages(body: any, auth: AuthContext): Promise<any>;
|
|
18
26
|
private responsesViaCompletions;
|
|
19
27
|
private messagesViaCompletions;
|
|
20
|
-
private responsesWithDefaultAgent;
|
|
21
|
-
private messagesWithDefaultAgent;
|
|
22
28
|
private extractPromptFromResponsesBody;
|
|
23
29
|
private extractPromptFromMessagesBody;
|
|
24
30
|
listModels(_auth?: AuthContext): Promise<any[]>;
|
|
25
|
-
private completeWithDefaultAgent;
|
|
26
|
-
private streamWithDefaultAgent;
|
|
27
|
-
private buildDefaultAgentContext;
|
|
28
|
-
private getPodBaseUrlFromWebId;
|
|
29
|
-
private getSolidToken;
|
|
30
31
|
private mapFinishReason;
|
|
31
32
|
/**
|
|
32
33
|
* Handle API errors and update credential status accordingly
|
|
@@ -36,4 +37,12 @@ export declare class VercelChatService {
|
|
|
36
37
|
* Parse error to extract status code and retry-after header
|
|
37
38
|
*/
|
|
38
39
|
private parseApiError;
|
|
40
|
+
/**
|
|
41
|
+
* Check if account has remaining token quota
|
|
42
|
+
*/
|
|
43
|
+
private checkTokenQuota;
|
|
44
|
+
/**
|
|
45
|
+
* Record token usage (fire-and-forget)
|
|
46
|
+
*/
|
|
47
|
+
private recordTokenUsage;
|
|
39
48
|
}
|
|
@@ -6,7 +6,6 @@ const ai_1 = require("ai");
|
|
|
6
6
|
const global_logger_factory_1 = require("global-logger-factory");
|
|
7
7
|
const undici_1 = require("undici");
|
|
8
8
|
const AuthContext_1 = require("../auth/AuthContext");
|
|
9
|
-
const default_agent_1 = require("../chatkit/default-agent");
|
|
10
9
|
const types_1 = require("../../credential/schema/types");
|
|
11
10
|
const provider_registry_1 = require("./provider-registry");
|
|
12
11
|
// Create a proxy-aware fetch function
|
|
@@ -20,6 +19,13 @@ class VercelChatService {
|
|
|
20
19
|
this.logger = (0, global_logger_factory_1.getLoggerFor)(this);
|
|
21
20
|
this.logger.info('Initializing VercelChatService with Pod-based config support');
|
|
22
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Set optional usage tracking dependencies (injected after construction)
|
|
24
|
+
*/
|
|
25
|
+
setUsageTracking(usageRepo, quotaService) {
|
|
26
|
+
this.usageRepo = usageRepo;
|
|
27
|
+
this.quotaService = quotaService;
|
|
28
|
+
}
|
|
23
29
|
/**
|
|
24
30
|
* Create a StoreContext from AuthContext for Pod operations
|
|
25
31
|
*/
|
|
@@ -39,26 +45,26 @@ class VercelChatService {
|
|
|
39
45
|
this.logger.warn(`Failed to get Pod config, falling back to defaults: ${error}`);
|
|
40
46
|
config = undefined;
|
|
41
47
|
}
|
|
42
|
-
// Priority: Pod config >
|
|
48
|
+
// Priority: Pod config > Platform Provider
|
|
43
49
|
if (config?.apiKey) {
|
|
44
50
|
const baseURL = config.baseUrl || (0, provider_registry_1.getDefaultBaseUrl)();
|
|
45
51
|
const proxy = config.proxyUrl;
|
|
46
52
|
this.logger.info(`Provider config: baseURL=${baseURL}, proxy=${proxy || 'none'} (source=pod)`);
|
|
47
53
|
return { baseURL, apiKey: config.apiKey, proxy, credentialId: config.credentialId };
|
|
48
54
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
this.logger.info(`Provider config: baseURL=${
|
|
53
|
-
return { baseURL, apiKey: process.env.DEFAULT_API_KEY, proxy: undefined, credentialId: undefined };
|
|
55
|
+
// 平台 Provider
|
|
56
|
+
const platformBase = process.env.DEFAULT_API_BASE;
|
|
57
|
+
if (platformBase) {
|
|
58
|
+
this.logger.info(`Provider config: baseURL=${platformBase}, proxy=none (source=platform)`);
|
|
59
|
+
return { baseURL: platformBase, apiKey: process.env.DEFAULT_API_KEY || '', proxy: undefined, credentialId: undefined };
|
|
54
60
|
}
|
|
55
|
-
this.logger.warn('No AI provider config found in Pod or
|
|
61
|
+
this.logger.warn('No AI provider config found in Pod or DEFAULT_API_BASE');
|
|
56
62
|
return null;
|
|
57
63
|
}
|
|
58
64
|
async getProvider(context) {
|
|
59
65
|
const providerConfig = await this.getProviderConfig(context);
|
|
60
66
|
if (!providerConfig) {
|
|
61
|
-
const err = new Error('No AI provider configured. Please configure Pod AI provider or
|
|
67
|
+
const err = new Error('No AI provider configured. Please configure Pod AI provider or set DEFAULT_API_BASE.');
|
|
62
68
|
err.code = 'model_not_configured';
|
|
63
69
|
throw err;
|
|
64
70
|
}
|
|
@@ -75,7 +81,14 @@ class VercelChatService {
|
|
|
75
81
|
const context = this.createStoreContext(auth);
|
|
76
82
|
const config = await this.getProviderConfig(context);
|
|
77
83
|
if (!config) {
|
|
78
|
-
|
|
84
|
+
const err = new Error('No AI provider configured. Please configure Pod AI provider or set DEFAULT_API_BASE.');
|
|
85
|
+
err.code = 'model_not_configured';
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
// Token quota check
|
|
89
|
+
const accountId = (0, AuthContext_1.getAccountId)(auth);
|
|
90
|
+
if (accountId) {
|
|
91
|
+
await this.checkTokenQuota(accountId);
|
|
79
92
|
}
|
|
80
93
|
try {
|
|
81
94
|
const provider = await this.getProvider(context);
|
|
@@ -95,6 +108,11 @@ class VercelChatService {
|
|
|
95
108
|
this.logger.debug(`Failed to record credential success: ${err}`);
|
|
96
109
|
});
|
|
97
110
|
}
|
|
111
|
+
// Record token usage
|
|
112
|
+
const totalTokens = result.usage?.totalTokens ?? 0;
|
|
113
|
+
if (accountId && totalTokens > 0) {
|
|
114
|
+
this.recordTokenUsage(accountId, String(context.userId), totalTokens);
|
|
115
|
+
}
|
|
98
116
|
return {
|
|
99
117
|
id: `chatcmpl-${Date.now()}`,
|
|
100
118
|
object: 'chat.completion',
|
|
@@ -131,7 +149,9 @@ class VercelChatService {
|
|
|
131
149
|
const context = this.createStoreContext(auth);
|
|
132
150
|
const config = await this.getProviderConfig(context);
|
|
133
151
|
if (!config) {
|
|
134
|
-
|
|
152
|
+
const err = new Error('No AI provider configured. Please configure Pod AI provider or set DEFAULT_API_BASE.');
|
|
153
|
+
err.code = 'model_not_configured';
|
|
154
|
+
throw err;
|
|
135
155
|
}
|
|
136
156
|
const provider = await this.getProvider(context);
|
|
137
157
|
const coreMessages = messages.map((m) => ({
|
|
@@ -151,7 +171,9 @@ class VercelChatService {
|
|
|
151
171
|
const accountId = (0, AuthContext_1.getAccountId)(auth);
|
|
152
172
|
const providerConfig = await this.getProviderConfig(context);
|
|
153
173
|
if (!providerConfig) {
|
|
154
|
-
|
|
174
|
+
const err = new Error('No AI provider configured. Please configure Pod AI provider or set DEFAULT_API_BASE.');
|
|
175
|
+
err.code = 'model_not_configured';
|
|
176
|
+
throw err;
|
|
155
177
|
}
|
|
156
178
|
const { baseURL } = providerConfig;
|
|
157
179
|
// Only OpenAI natively supports /v1/responses; all others go through Chat Completions
|
|
@@ -202,7 +224,9 @@ class VercelChatService {
|
|
|
202
224
|
const accountId = (0, AuthContext_1.getAccountId)(auth);
|
|
203
225
|
const providerConfig = await this.getProviderConfig(context);
|
|
204
226
|
if (!providerConfig) {
|
|
205
|
-
|
|
227
|
+
const err = new Error('No AI provider configured. Please configure Pod AI provider or set DEFAULT_API_BASE.');
|
|
228
|
+
err.code = 'model_not_configured';
|
|
229
|
+
throw err;
|
|
206
230
|
}
|
|
207
231
|
const { baseURL } = providerConfig;
|
|
208
232
|
// Only Anthropic natively supports /v1/messages; all others go through Chat Completions
|
|
@@ -336,57 +360,6 @@ class VercelChatService {
|
|
|
336
360
|
},
|
|
337
361
|
};
|
|
338
362
|
}
|
|
339
|
-
async responsesWithDefaultAgent(body, auth) {
|
|
340
|
-
const prompt = this.extractPromptFromResponsesBody(body);
|
|
341
|
-
const result = await (0, default_agent_1.runDefaultAgent)(prompt, this.buildDefaultAgentContext(auth));
|
|
342
|
-
if (!result.success) {
|
|
343
|
-
const err = new Error(result.error || 'Default Agent is not available');
|
|
344
|
-
err.code = 'model_not_configured';
|
|
345
|
-
throw err;
|
|
346
|
-
}
|
|
347
|
-
const outputText = result.content;
|
|
348
|
-
const now = Math.floor(Date.now() / 1000);
|
|
349
|
-
return {
|
|
350
|
-
id: `resp_${Date.now()}`,
|
|
351
|
-
object: 'response',
|
|
352
|
-
created: now,
|
|
353
|
-
status: 'completed',
|
|
354
|
-
model: body?.model || process.env.DEFAULT_MODEL || 'stepfun/step-3.5-flash:free',
|
|
355
|
-
output: [{
|
|
356
|
-
type: 'message',
|
|
357
|
-
role: 'assistant',
|
|
358
|
-
content: [{ type: 'output_text', text: outputText }],
|
|
359
|
-
}],
|
|
360
|
-
usage: {
|
|
361
|
-
input_tokens: prompt.length,
|
|
362
|
-
output_tokens: outputText.length,
|
|
363
|
-
total_tokens: prompt.length + outputText.length,
|
|
364
|
-
},
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
async messagesWithDefaultAgent(body, auth) {
|
|
368
|
-
const prompt = this.extractPromptFromMessagesBody(body);
|
|
369
|
-
const result = await (0, default_agent_1.runDefaultAgent)(prompt, this.buildDefaultAgentContext(auth));
|
|
370
|
-
if (!result.success) {
|
|
371
|
-
const err = new Error(result.error || 'Default Agent is not available');
|
|
372
|
-
err.code = 'model_not_configured';
|
|
373
|
-
throw err;
|
|
374
|
-
}
|
|
375
|
-
const text = result.content;
|
|
376
|
-
return {
|
|
377
|
-
id: `msg_${Date.now()}`,
|
|
378
|
-
type: 'message',
|
|
379
|
-
role: 'assistant',
|
|
380
|
-
model: body?.model || process.env.DEFAULT_MODEL || 'stepfun/step-3.5-flash:free',
|
|
381
|
-
content: [{ type: 'text', text }],
|
|
382
|
-
stop_reason: 'end_turn',
|
|
383
|
-
stop_sequence: null,
|
|
384
|
-
usage: {
|
|
385
|
-
input_tokens: prompt.length,
|
|
386
|
-
output_tokens: text.length,
|
|
387
|
-
},
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
363
|
extractPromptFromResponsesBody(body) {
|
|
391
364
|
if (!body || typeof body !== 'object') {
|
|
392
365
|
return '';
|
|
@@ -444,126 +417,34 @@ class VercelChatService {
|
|
|
444
417
|
return '';
|
|
445
418
|
}
|
|
446
419
|
async listModels(_auth) {
|
|
447
|
-
|
|
448
|
-
//
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
}
|
|
464
|
-
async completeWithDefaultAgent(messages, auth, requestedModel) {
|
|
465
|
-
const agentContext = this.buildDefaultAgentContext(auth);
|
|
466
|
-
const prompt = messages.filter((m) => m.role === 'user').pop()?.content || '';
|
|
467
|
-
const result = await (0, default_agent_1.runDefaultAgent)(prompt, agentContext);
|
|
468
|
-
if (!result.success) {
|
|
469
|
-
const err = new Error(result.error || 'Default Agent is not available');
|
|
470
|
-
err.code = 'model_not_configured';
|
|
471
|
-
throw err;
|
|
472
|
-
}
|
|
473
|
-
const completionTokens = result.content.length;
|
|
474
|
-
return {
|
|
475
|
-
id: `chatcmpl-${Date.now()}`,
|
|
476
|
-
object: 'chat.completion',
|
|
477
|
-
created: Math.floor(Date.now() / 1000),
|
|
478
|
-
model: requestedModel,
|
|
479
|
-
choices: [{
|
|
480
|
-
index: 0,
|
|
481
|
-
message: { role: 'assistant', content: result.content },
|
|
482
|
-
finish_reason: 'stop',
|
|
483
|
-
}],
|
|
484
|
-
usage: {
|
|
485
|
-
prompt_tokens: prompt.length,
|
|
486
|
-
completion_tokens: completionTokens,
|
|
487
|
-
total_tokens: prompt.length + completionTokens,
|
|
488
|
-
},
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
async streamWithDefaultAgent(messages, auth, _requestedModel) {
|
|
492
|
-
const agentContext = this.buildDefaultAgentContext(auth);
|
|
493
|
-
const prompt = messages.filter((m) => m.role === 'user').pop()?.content || '';
|
|
494
|
-
const encoder = new TextEncoder();
|
|
495
|
-
const stream = new ReadableStream({
|
|
496
|
-
start: async (controller) => {
|
|
497
|
-
try {
|
|
498
|
-
for await (const chunk of (0, default_agent_1.streamDefaultAgent)(prompt, agentContext)) {
|
|
499
|
-
controller.enqueue(encoder.encode(chunk));
|
|
420
|
+
const models = [];
|
|
421
|
+
// 平台 Provider 模型(从 DEFAULT_API_BASE 获取)
|
|
422
|
+
const platformBase = process.env.DEFAULT_API_BASE;
|
|
423
|
+
const platformKey = process.env.DEFAULT_API_KEY;
|
|
424
|
+
if (platformBase) {
|
|
425
|
+
try {
|
|
426
|
+
const url = platformBase.replace(/\/$/, '') + '/models';
|
|
427
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
428
|
+
if (platformKey) {
|
|
429
|
+
headers['Authorization'] = `Bearer ${platformKey}`;
|
|
430
|
+
}
|
|
431
|
+
const resp = await fetch(url, { headers });
|
|
432
|
+
if (resp.ok) {
|
|
433
|
+
const data = await resp.json();
|
|
434
|
+
if (data.data) {
|
|
435
|
+
models.push(...data.data);
|
|
500
436
|
}
|
|
501
|
-
controller.close();
|
|
502
437
|
}
|
|
503
|
-
|
|
504
|
-
|
|
438
|
+
else {
|
|
439
|
+
this.logger.warn(`Failed to fetch platform models: ${resp.status}`);
|
|
505
440
|
}
|
|
506
|
-
},
|
|
507
|
-
});
|
|
508
|
-
return {
|
|
509
|
-
toTextStreamResponse: () => new Response(stream, {
|
|
510
|
-
status: 200,
|
|
511
|
-
headers: {
|
|
512
|
-
'Content-Type': 'text/plain; charset=utf-8',
|
|
513
|
-
'X-Vercel-AI-Data-Stream': 'v1',
|
|
514
|
-
},
|
|
515
|
-
}),
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
buildDefaultAgentContext(auth) {
|
|
519
|
-
if (!(0, default_agent_1.isDefaultAgentAvailable)()) {
|
|
520
|
-
const err = new Error('No AI provider configured. Please configure Pod AI provider or DEFAULT_API_KEY');
|
|
521
|
-
err.code = 'model_not_configured';
|
|
522
|
-
throw err;
|
|
523
|
-
}
|
|
524
|
-
const webId = (0, AuthContext_1.getWebId)(auth);
|
|
525
|
-
if (!webId) {
|
|
526
|
-
const err = new Error('No WebID in auth context');
|
|
527
|
-
err.code = 'model_not_configured';
|
|
528
|
-
throw err;
|
|
529
|
-
}
|
|
530
|
-
const solidToken = this.getSolidToken(auth);
|
|
531
|
-
if (!solidToken) {
|
|
532
|
-
const err = new Error('No Solid token available for Default Agent');
|
|
533
|
-
err.code = 'model_not_configured';
|
|
534
|
-
throw err;
|
|
535
|
-
}
|
|
536
|
-
return {
|
|
537
|
-
solidToken,
|
|
538
|
-
podBaseUrl: this.getPodBaseUrlFromWebId(webId),
|
|
539
|
-
webId,
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
getPodBaseUrlFromWebId(webId) {
|
|
543
|
-
const url = new URL(webId);
|
|
544
|
-
if (url.pathname.endsWith('/profile/card')) {
|
|
545
|
-
const podPath = url.pathname.replace('/profile/card', '');
|
|
546
|
-
return `${url.protocol}//${url.host}${podPath}/`;
|
|
547
|
-
}
|
|
548
|
-
return `${url.protocol}//${url.host}/`;
|
|
549
|
-
}
|
|
550
|
-
getSolidToken(auth) {
|
|
551
|
-
const candidate = auth;
|
|
552
|
-
if (typeof candidate.token === 'string') {
|
|
553
|
-
return candidate.token;
|
|
554
|
-
}
|
|
555
|
-
if (typeof candidate.accessToken === 'string') {
|
|
556
|
-
return candidate.accessToken;
|
|
557
|
-
}
|
|
558
|
-
if (candidate.credentials && typeof candidate.credentials === 'object') {
|
|
559
|
-
if (typeof candidate.credentials.accessToken === 'string') {
|
|
560
|
-
return candidate.credentials.accessToken;
|
|
561
441
|
}
|
|
562
|
-
|
|
563
|
-
|
|
442
|
+
catch (error) {
|
|
443
|
+
this.logger.warn(`Failed to fetch platform models: ${error}`);
|
|
564
444
|
}
|
|
565
445
|
}
|
|
566
|
-
|
|
446
|
+
// TODO: 合并用户 Pod Providers 的模型
|
|
447
|
+
return models;
|
|
567
448
|
}
|
|
568
449
|
mapFinishReason(reason) {
|
|
569
450
|
return reason;
|
|
@@ -623,6 +504,45 @@ class VercelChatService {
|
|
|
623
504
|
}
|
|
624
505
|
return { statusCode: 0 };
|
|
625
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Check if account has remaining token quota
|
|
509
|
+
*/
|
|
510
|
+
async checkTokenQuota(accountId) {
|
|
511
|
+
if (!this.quotaService || !this.usageRepo) {
|
|
512
|
+
return; // No quota enforcement if not configured
|
|
513
|
+
}
|
|
514
|
+
try {
|
|
515
|
+
const quota = await this.quotaService.getAccountQuota(accountId);
|
|
516
|
+
if (!quota.tokenLimitMonthly) {
|
|
517
|
+
return; // No limit set
|
|
518
|
+
}
|
|
519
|
+
const usage = await this.usageRepo.getAccountUsage(accountId);
|
|
520
|
+
const tokensUsed = usage?.tokensUsed ?? 0;
|
|
521
|
+
if (tokensUsed >= quota.tokenLimitMonthly) {
|
|
522
|
+
const err = new Error('Token quota exceeded for this month');
|
|
523
|
+
err.code = 'quota_exceeded';
|
|
524
|
+
throw err;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
catch (error) {
|
|
528
|
+
if (error.code === 'quota_exceeded') {
|
|
529
|
+
throw error;
|
|
530
|
+
}
|
|
531
|
+
// Log but don't block on quota check errors
|
|
532
|
+
this.logger.warn(`Token quota check failed: ${error}`);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Record token usage (fire-and-forget)
|
|
537
|
+
*/
|
|
538
|
+
recordTokenUsage(accountId, podId, tokens) {
|
|
539
|
+
if (!this.usageRepo) {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
this.usageRepo.incrementTokenUsage(accountId, podId, tokens).catch((err) => {
|
|
543
|
+
this.logger.warn(`Failed to record token usage: ${err}`);
|
|
544
|
+
});
|
|
545
|
+
}
|
|
626
546
|
}
|
|
627
547
|
exports.VercelChatService = VercelChatService;
|
|
628
548
|
//# sourceMappingURL=VercelChatService.js.map
|