@undefineds.co/xpod 0.1.7 → 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/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 -9
- package/dist/api/container/routes.js.map +1 -1
- package/dist/api/container/types.d.ts +8 -6
- package/dist/api/container/types.js.map +1 -1
- package/dist/api/handlers/AdminHandler.js +9 -9
- package/dist/api/handlers/AdminHandler.js.map +1 -1
- package/dist/api/handlers/ApiKeyHandler.js +0 -6
- package/dist/api/handlers/ApiKeyHandler.js.map +1 -1
- package/dist/api/handlers/EdgeNodeSignalHandler.d.ts +17 -0
- package/dist/api/handlers/EdgeNodeSignalHandler.js +171 -0
- package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -0
- package/dist/api/handlers/PodManagementHandler.d.ts +5 -4
- package/dist/api/handlers/PodManagementHandler.js +11 -10
- package/dist/api/handlers/PodManagementHandler.js.map +1 -1
- package/dist/api/handlers/ProvisionHandler.d.ts +42 -0
- package/dist/api/handlers/ProvisionHandler.js +161 -0
- package/dist/api/handlers/ProvisionHandler.js.map +1 -0
- package/dist/api/handlers/QuotaHandler.d.ts +7 -7
- package/dist/api/handlers/QuotaHandler.js +143 -73
- package/dist/api/handlers/QuotaHandler.js.map +1 -1
- package/dist/api/handlers/SubdomainClientHandler.js +2 -2
- package/dist/api/handlers/SubdomainClientHandler.js.map +1 -1
- package/dist/api/handlers/SubdomainHandler.js +13 -8
- package/dist/api/handlers/SubdomainHandler.js.map +1 -1
- package/dist/api/handlers/UsageHandler.d.ts +14 -0
- package/dist/api/handlers/UsageHandler.js +123 -0
- package/dist/api/handlers/UsageHandler.js.map +1 -0
- package/dist/api/handlers/index.d.ts +3 -1
- package/dist/api/handlers/index.js +3 -1
- package/dist/api/handlers/index.js.map +1 -1
- package/dist/api/main.js +18 -0
- package/dist/api/main.js.map +1 -1
- package/dist/api/middleware/OpenAuthMiddleware.d.ts +12 -0
- package/dist/api/middleware/OpenAuthMiddleware.js +27 -0
- package/dist/api/middleware/OpenAuthMiddleware.js.map +1 -0
- package/dist/api/runtime.d.ts +15 -0
- package/dist/api/runtime.js +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
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerDevRoutes = registerDevRoutes;
|
|
4
|
-
const node_crypto_1 = require("node:crypto");
|
|
5
|
-
const global_logger_factory_1 = require("global-logger-factory");
|
|
6
|
-
/**
|
|
7
|
-
* 开发模式专用 Handler
|
|
8
|
-
*
|
|
9
|
-
* 仅在 NODE_ENV=development 时启用,用于集成测试
|
|
10
|
-
*
|
|
11
|
-
* POST /dev/credentials - 创建测试用 client credentials
|
|
12
|
-
* POST /dev/nodes - 创建测试用 edge node
|
|
13
|
-
* POST /dev/setup - 一键创建 credentials + node(完整测试环境)
|
|
14
|
-
* DELETE /dev/cleanup/:testId - 清理测试数据
|
|
15
|
-
*/
|
|
16
|
-
function registerDevRoutes(server, options) {
|
|
17
|
-
const logger = (0, global_logger_factory_1.getLoggerFor)('DevHandler');
|
|
18
|
-
const { nodeRepo, credentialsStore } = options;
|
|
19
|
-
// 安全检查:仅开发模式可用
|
|
20
|
-
const isDev = process.env.NODE_ENV === 'development';
|
|
21
|
-
if (!isDev) {
|
|
22
|
-
logger.info('Dev routes disabled (not in development mode)');
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
logger.warn('⚠️ Dev routes enabled - DO NOT use in production!');
|
|
26
|
-
/**
|
|
27
|
-
* POST /dev/credentials
|
|
28
|
-
*
|
|
29
|
-
* 创建测试用的 client credentials
|
|
30
|
-
*
|
|
31
|
-
* Request body (optional):
|
|
32
|
-
* {
|
|
33
|
-
* "displayName": "Test Client",
|
|
34
|
-
* "testId": "my-test-run" // 用于后续清理
|
|
35
|
-
* }
|
|
36
|
-
*
|
|
37
|
-
* Response:
|
|
38
|
-
* {
|
|
39
|
-
* "clientId": "test-client-xxx",
|
|
40
|
-
* "clientSecret": "secret-xxx",
|
|
41
|
-
* "webId": "https://dev.local/test-xxx#me",
|
|
42
|
-
* "testId": "my-test-run"
|
|
43
|
-
* }
|
|
44
|
-
*/
|
|
45
|
-
server.post('/dev/credentials', async (request, response, _params) => {
|
|
46
|
-
const body = await readJsonBody(request);
|
|
47
|
-
const payload = body ?? {};
|
|
48
|
-
const testId = payload.testId ?? `test-${Date.now()}`;
|
|
49
|
-
const displayName = payload.displayName ?? `Dev Test ${testId}`;
|
|
50
|
-
// 生成 credentials
|
|
51
|
-
const clientId = `dev-client-${(0, node_crypto_1.randomUUID)().slice(0, 8)}`;
|
|
52
|
-
const clientSecret = (0, node_crypto_1.randomBytes)(32).toString('base64url');
|
|
53
|
-
const webId = `https://dev.local/${testId}#me`;
|
|
54
|
-
try {
|
|
55
|
-
// 存储到数据库
|
|
56
|
-
await credentialsStore.store({
|
|
57
|
-
clientId,
|
|
58
|
-
clientSecret,
|
|
59
|
-
webId,
|
|
60
|
-
accountId: webId,
|
|
61
|
-
displayName,
|
|
62
|
-
});
|
|
63
|
-
logger.info(`[DEV] Created credentials: ${clientId} for ${webId}`);
|
|
64
|
-
sendJson(response, 201, {
|
|
65
|
-
clientId,
|
|
66
|
-
clientSecret,
|
|
67
|
-
webId,
|
|
68
|
-
testId,
|
|
69
|
-
displayName,
|
|
70
|
-
message: 'Development credentials created. Use these for testing.',
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
logger.error(`[DEV] Failed to create credentials: ${error}`);
|
|
75
|
-
sendJson(response, 500, { error: 'Failed to create credentials' });
|
|
76
|
-
}
|
|
77
|
-
}, { public: true });
|
|
78
|
-
/**
|
|
79
|
-
* POST /dev/nodes
|
|
80
|
-
*
|
|
81
|
-
* 创建测试用的 edge node
|
|
82
|
-
*
|
|
83
|
-
* Request body (optional):
|
|
84
|
-
* {
|
|
85
|
-
* "displayName": "Test Node",
|
|
86
|
-
* "testId": "my-test-run",
|
|
87
|
-
* "ownerWebId": "https://dev.local/test-xxx#me" // 关联到指定用户
|
|
88
|
-
* }
|
|
89
|
-
*
|
|
90
|
-
* Response:
|
|
91
|
-
* {
|
|
92
|
-
* "nodeId": "uuid-xxx",
|
|
93
|
-
* "token": "node-token-xxx",
|
|
94
|
-
* "testId": "my-test-run"
|
|
95
|
-
* }
|
|
96
|
-
*/
|
|
97
|
-
server.post('/dev/nodes', async (request, response, _params) => {
|
|
98
|
-
const body = await readJsonBody(request);
|
|
99
|
-
const payload = body ?? {};
|
|
100
|
-
const testId = payload.testId ?? `test-${Date.now()}`;
|
|
101
|
-
const displayName = payload.displayName ?? `Dev Node ${testId}`;
|
|
102
|
-
const ownerWebId = payload.ownerWebId ?? `https://dev.local/${testId}#me`;
|
|
103
|
-
try {
|
|
104
|
-
// 创建节点
|
|
105
|
-
const result = await nodeRepo.createNode(displayName, ownerWebId);
|
|
106
|
-
logger.info(`[DEV] Created node: ${result.nodeId} for ${ownerWebId}`);
|
|
107
|
-
sendJson(response, 201, {
|
|
108
|
-
nodeId: result.nodeId,
|
|
109
|
-
token: result.token,
|
|
110
|
-
testId,
|
|
111
|
-
displayName,
|
|
112
|
-
ownerWebId,
|
|
113
|
-
createdAt: result.createdAt,
|
|
114
|
-
message: 'Development node created. Use nodeId + token for signaling.',
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
catch (error) {
|
|
118
|
-
logger.error(`[DEV] Failed to create node: ${error}`);
|
|
119
|
-
sendJson(response, 500, { error: 'Failed to create node' });
|
|
120
|
-
}
|
|
121
|
-
}, { public: true });
|
|
122
|
-
/**
|
|
123
|
-
* POST /dev/setup
|
|
124
|
-
*
|
|
125
|
-
* 一键创建完整测试环境:credentials + node
|
|
126
|
-
*
|
|
127
|
-
* Request body (optional):
|
|
128
|
-
* {
|
|
129
|
-
* "testId": "my-test-run",
|
|
130
|
-
* "displayName": "My Test"
|
|
131
|
-
* }
|
|
132
|
-
*
|
|
133
|
-
* Response:
|
|
134
|
-
* {
|
|
135
|
-
* "testId": "my-test-run",
|
|
136
|
-
* "credentials": { clientId, clientSecret, webId },
|
|
137
|
-
* "node": { nodeId, token },
|
|
138
|
-
* "signalingUrl": "ws://localhost:3001/ws/signaling",
|
|
139
|
-
* "env": { ... } // 可直接用于 .env 配置
|
|
140
|
-
* }
|
|
141
|
-
*/
|
|
142
|
-
server.post('/dev/setup', async (request, response, _params) => {
|
|
143
|
-
const body = await readJsonBody(request);
|
|
144
|
-
const payload = body ?? {};
|
|
145
|
-
const testId = payload.testId ?? `test-${Date.now()}`;
|
|
146
|
-
const displayName = payload.displayName ?? `Test ${testId}`;
|
|
147
|
-
// 1. 创建 credentials
|
|
148
|
-
const clientId = `dev-client-${(0, node_crypto_1.randomUUID)().slice(0, 8)}`;
|
|
149
|
-
const clientSecret = (0, node_crypto_1.randomBytes)(32).toString('base64url');
|
|
150
|
-
const webId = `https://dev.local/${testId}#me`;
|
|
151
|
-
// 2. 创建 node
|
|
152
|
-
try {
|
|
153
|
-
await credentialsStore.store({
|
|
154
|
-
clientId,
|
|
155
|
-
clientSecret,
|
|
156
|
-
webId,
|
|
157
|
-
accountId: webId,
|
|
158
|
-
displayName: `${displayName} Client`,
|
|
159
|
-
});
|
|
160
|
-
const nodeResult = await nodeRepo.createNode(`${displayName} Node`, webId);
|
|
161
|
-
// 生成符合 NodeTokenAuthenticator 格式的 token: username:secret
|
|
162
|
-
const formattedNodeToken = `${testId}:${nodeResult.token}`;
|
|
163
|
-
logger.info(`[DEV] Setup complete: credentials=${clientId}, node=${nodeResult.nodeId}`);
|
|
164
|
-
// 获取当前服务的基础 URL
|
|
165
|
-
const host = process.env.API_HOST ?? 'localhost';
|
|
166
|
-
const port = process.env.API_PORT ?? '3001';
|
|
167
|
-
const apiUrl = `http://${host === '0.0.0.0' ? 'localhost' : host}:${port}`;
|
|
168
|
-
sendJson(response, 201, {
|
|
169
|
-
testId,
|
|
170
|
-
credentials: {
|
|
171
|
-
clientId,
|
|
172
|
-
clientSecret,
|
|
173
|
-
webId,
|
|
174
|
-
},
|
|
175
|
-
node: {
|
|
176
|
-
nodeId: nodeResult.nodeId,
|
|
177
|
-
token: formattedNodeToken,
|
|
178
|
-
},
|
|
179
|
-
apiUrl,
|
|
180
|
-
// 可直接导出为环境变量
|
|
181
|
-
env: {
|
|
182
|
-
XPOD_CLIENT_ID: clientId,
|
|
183
|
-
XPOD_CLIENT_SECRET: clientSecret,
|
|
184
|
-
XPOD_NODE_ID: nodeResult.nodeId,
|
|
185
|
-
XPOD_NODE_TOKEN: formattedNodeToken,
|
|
186
|
-
},
|
|
187
|
-
message: 'Development environment ready. Copy env values to your .env file or use directly.',
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
catch (error) {
|
|
191
|
-
logger.error(`[DEV] Setup failed: ${error}`);
|
|
192
|
-
sendJson(response, 500, { error: 'Failed to setup test environment' });
|
|
193
|
-
}
|
|
194
|
-
}, { public: true });
|
|
195
|
-
/**
|
|
196
|
-
* DELETE /dev/cleanup/:testId
|
|
197
|
-
*
|
|
198
|
-
* 清理指定 testId 的测试数据
|
|
199
|
-
*/
|
|
200
|
-
server.delete('/dev/cleanup/:testId', async (request, response, params) => {
|
|
201
|
-
const testId = decodeURIComponent(params.testId);
|
|
202
|
-
const webId = `https://dev.local/${testId}#me`;
|
|
203
|
-
try {
|
|
204
|
-
// 清理 credentials
|
|
205
|
-
const keys = await credentialsStore.listByAccount(webId);
|
|
206
|
-
for (const key of keys) {
|
|
207
|
-
await credentialsStore.delete(key.clientId, webId);
|
|
208
|
-
}
|
|
209
|
-
// 清理 nodes
|
|
210
|
-
const nodes = await nodeRepo.listNodesByAccount(webId);
|
|
211
|
-
for (const node of nodes) {
|
|
212
|
-
await nodeRepo.deleteNode(node.nodeId);
|
|
213
|
-
}
|
|
214
|
-
logger.info(`[DEV] Cleaned up test: ${testId} (${keys.length} credentials, ${nodes.length} nodes)`);
|
|
215
|
-
sendJson(response, 200, {
|
|
216
|
-
testId,
|
|
217
|
-
deleted: {
|
|
218
|
-
credentials: keys.length,
|
|
219
|
-
nodes: nodes.length,
|
|
220
|
-
},
|
|
221
|
-
message: 'Test data cleaned up.',
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
catch (error) {
|
|
225
|
-
logger.error(`[DEV] Cleanup failed: ${error}`);
|
|
226
|
-
sendJson(response, 500, { error: 'Failed to cleanup test data' });
|
|
227
|
-
}
|
|
228
|
-
}, { public: true });
|
|
229
|
-
/**
|
|
230
|
-
* GET /dev/status
|
|
231
|
-
*
|
|
232
|
-
* 获取开发模式状态
|
|
233
|
-
*/
|
|
234
|
-
server.get('/dev/status', async (_request, response, _params) => {
|
|
235
|
-
sendJson(response, 200, {
|
|
236
|
-
mode: 'development',
|
|
237
|
-
enabled: true,
|
|
238
|
-
endpoints: [
|
|
239
|
-
'POST /dev/credentials - Create test credentials',
|
|
240
|
-
'POST /dev/nodes - Create test node',
|
|
241
|
-
'POST /dev/setup - One-click setup (credentials + node)',
|
|
242
|
-
'DELETE /dev/cleanup/:testId - Cleanup test data',
|
|
243
|
-
'GET /dev/status - This endpoint',
|
|
244
|
-
],
|
|
245
|
-
warning: 'These endpoints are for development only. Never expose in production!',
|
|
246
|
-
});
|
|
247
|
-
}, { public: true });
|
|
248
|
-
}
|
|
249
|
-
async function readJsonBody(request) {
|
|
250
|
-
return new Promise((resolve, reject) => {
|
|
251
|
-
let data = '';
|
|
252
|
-
request.setEncoding('utf8');
|
|
253
|
-
request.on('data', (chunk) => {
|
|
254
|
-
data += chunk;
|
|
255
|
-
});
|
|
256
|
-
request.on('end', () => {
|
|
257
|
-
if (!data) {
|
|
258
|
-
resolve(undefined);
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
try {
|
|
262
|
-
resolve(JSON.parse(data));
|
|
263
|
-
}
|
|
264
|
-
catch {
|
|
265
|
-
resolve(undefined);
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
request.on('error', reject);
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
function sendJson(response, status, data) {
|
|
272
|
-
response.statusCode = status;
|
|
273
|
-
response.setHeader('Content-Type', 'application/json');
|
|
274
|
-
response.end(JSON.stringify(data, null, 2));
|
|
275
|
-
}
|
|
276
|
-
//# sourceMappingURL=DevHandler.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DevHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/DevHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ServerResponse, IncomingMessage } from 'node:http';\nimport { randomBytes, randomUUID } from 'node:crypto';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { ApiServer } from '../ApiServer';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { DrizzleClientCredentialsStore } from '../store/DrizzleClientCredentialsStore';\n\nexport interface DevHandlerOptions {\n nodeRepo: EdgeNodeRepository;\n credentialsStore: DrizzleClientCredentialsStore;\n}\n\n/**\n * 开发模式专用 Handler\n *\n * 仅在 NODE_ENV=development 时启用,用于集成测试\n *\n * POST /dev/credentials - 创建测试用 client credentials\n * POST /dev/nodes - 创建测试用 edge node\n * POST /dev/setup - 一键创建 credentials + node(完整测试环境)\n * DELETE /dev/cleanup/:testId - 清理测试数据\n */\nexport function registerDevRoutes(server: ApiServer, options: DevHandlerOptions): void {\n const logger = getLoggerFor('DevHandler');\n const { nodeRepo, credentialsStore } = options;\n\n // 安全检查:仅开发模式可用\n const isDev = process.env.NODE_ENV === 'development';\n\n if (!isDev) {\n logger.info('Dev routes disabled (not in development mode)');\n return;\n }\n\n logger.warn('⚠️ Dev routes enabled - DO NOT use in production!');\n\n /**\n * POST /dev/credentials\n *\n * 创建测试用的 client credentials\n *\n * Request body (optional):\n * {\n * \"displayName\": \"Test Client\",\n * \"testId\": \"my-test-run\" // 用于后续清理\n * }\n *\n * Response:\n * {\n * \"clientId\": \"test-client-xxx\",\n * \"clientSecret\": \"secret-xxx\",\n * \"webId\": \"https://dev.local/test-xxx#me\",\n * \"testId\": \"my-test-run\"\n * }\n */\n server.post('/dev/credentials', async (request, response, _params) => {\n const body = await readJsonBody(request);\n const payload = (body as Record<string, unknown>) ?? {};\n\n const testId = (payload.testId as string) ?? `test-${Date.now()}`;\n const displayName = (payload.displayName as string) ?? `Dev Test ${testId}`;\n\n // 生成 credentials\n const clientId = `dev-client-${randomUUID().slice(0, 8)}`;\n const clientSecret = randomBytes(32).toString('base64url');\n const webId = `https://dev.local/${testId}#me`;\n\n try {\n // 存储到数据库\n await credentialsStore.store({\n clientId,\n clientSecret,\n webId,\n accountId: webId,\n displayName,\n });\n\n logger.info(`[DEV] Created credentials: ${clientId} for ${webId}`);\n\n sendJson(response, 201, {\n clientId,\n clientSecret,\n webId,\n testId,\n displayName,\n message: 'Development credentials created. Use these for testing.',\n });\n } catch (error) {\n logger.error(`[DEV] Failed to create credentials: ${error}`);\n sendJson(response, 500, { error: 'Failed to create credentials' });\n }\n }, { public: true });\n\n /**\n * POST /dev/nodes\n *\n * 创建测试用的 edge node\n *\n * Request body (optional):\n * {\n * \"displayName\": \"Test Node\",\n * \"testId\": \"my-test-run\",\n * \"ownerWebId\": \"https://dev.local/test-xxx#me\" // 关联到指定用户\n * }\n *\n * Response:\n * {\n * \"nodeId\": \"uuid-xxx\",\n * \"token\": \"node-token-xxx\",\n * \"testId\": \"my-test-run\"\n * }\n */\n server.post('/dev/nodes', async (request, response, _params) => {\n const body = await readJsonBody(request);\n const payload = (body as Record<string, unknown>) ?? {};\n\n const testId = (payload.testId as string) ?? `test-${Date.now()}`;\n const displayName = (payload.displayName as string) ?? `Dev Node ${testId}`;\n const ownerWebId = (payload.ownerWebId as string) ?? `https://dev.local/${testId}#me`;\n\n try {\n // 创建节点\n const result = await nodeRepo.createNode(displayName, ownerWebId);\n\n logger.info(`[DEV] Created node: ${result.nodeId} for ${ownerWebId}`);\n\n sendJson(response, 201, {\n nodeId: result.nodeId,\n token: result.token,\n testId,\n displayName,\n ownerWebId,\n createdAt: result.createdAt,\n message: 'Development node created. Use nodeId + token for signaling.',\n });\n } catch (error) {\n logger.error(`[DEV] Failed to create node: ${error}`);\n sendJson(response, 500, { error: 'Failed to create node' });\n }\n }, { public: true });\n\n /**\n * POST /dev/setup\n *\n * 一键创建完整测试环境:credentials + node\n *\n * Request body (optional):\n * {\n * \"testId\": \"my-test-run\",\n * \"displayName\": \"My Test\"\n * }\n *\n * Response:\n * {\n * \"testId\": \"my-test-run\",\n * \"credentials\": { clientId, clientSecret, webId },\n * \"node\": { nodeId, token },\n * \"signalingUrl\": \"ws://localhost:3001/ws/signaling\",\n * \"env\": { ... } // 可直接用于 .env 配置\n * }\n */\n server.post('/dev/setup', async (request, response, _params) => {\n const body = await readJsonBody(request);\n const payload = (body as Record<string, unknown>) ?? {};\n\n const testId = (payload.testId as string) ?? `test-${Date.now()}`;\n const displayName = (payload.displayName as string) ?? `Test ${testId}`;\n\n // 1. 创建 credentials\n const clientId = `dev-client-${randomUUID().slice(0, 8)}`;\n const clientSecret = randomBytes(32).toString('base64url');\n const webId = `https://dev.local/${testId}#me`;\n\n // 2. 创建 node\n try {\n await credentialsStore.store({\n clientId,\n clientSecret,\n webId,\n accountId: webId,\n displayName: `${displayName} Client`,\n });\n\n const nodeResult = await nodeRepo.createNode(`${displayName} Node`, webId);\n\n // 生成符合 NodeTokenAuthenticator 格式的 token: username:secret\n const formattedNodeToken = `${testId}:${nodeResult.token}`;\n\n logger.info(`[DEV] Setup complete: credentials=${clientId}, node=${nodeResult.nodeId}`);\n\n // 获取当前服务的基础 URL\n const host = process.env.API_HOST ?? 'localhost';\n const port = process.env.API_PORT ?? '3001';\n const apiUrl = `http://${host === '0.0.0.0' ? 'localhost' : host}:${port}`;\n\n sendJson(response, 201, {\n testId,\n credentials: {\n clientId,\n clientSecret,\n webId,\n },\n node: {\n nodeId: nodeResult.nodeId,\n token: formattedNodeToken,\n },\n apiUrl,\n // 可直接导出为环境变量\n env: {\n XPOD_CLIENT_ID: clientId,\n XPOD_CLIENT_SECRET: clientSecret,\n XPOD_NODE_ID: nodeResult.nodeId,\n XPOD_NODE_TOKEN: formattedNodeToken,\n },\n message: 'Development environment ready. Copy env values to your .env file or use directly.',\n });\n } catch (error) {\n logger.error(`[DEV] Setup failed: ${error}`);\n sendJson(response, 500, { error: 'Failed to setup test environment' });\n }\n }, { public: true });\n\n /**\n * DELETE /dev/cleanup/:testId\n *\n * 清理指定 testId 的测试数据\n */\n server.delete('/dev/cleanup/:testId', async (request, response, params) => {\n const testId = decodeURIComponent(params.testId);\n const webId = `https://dev.local/${testId}#me`;\n\n try {\n // 清理 credentials\n const keys = await credentialsStore.listByAccount(webId);\n for (const key of keys) {\n await credentialsStore.delete(key.clientId, webId);\n }\n\n // 清理 nodes\n const nodes = await nodeRepo.listNodesByAccount(webId);\n for (const node of nodes) {\n await nodeRepo.deleteNode(node.nodeId);\n }\n\n logger.info(`[DEV] Cleaned up test: ${testId} (${keys.length} credentials, ${nodes.length} nodes)`);\n\n sendJson(response, 200, {\n testId,\n deleted: {\n credentials: keys.length,\n nodes: nodes.length,\n },\n message: 'Test data cleaned up.',\n });\n } catch (error) {\n logger.error(`[DEV] Cleanup failed: ${error}`);\n sendJson(response, 500, { error: 'Failed to cleanup test data' });\n }\n }, { public: true });\n\n /**\n * GET /dev/status\n *\n * 获取开发模式状态\n */\n server.get('/dev/status', async (_request, response, _params) => {\n sendJson(response, 200, {\n mode: 'development',\n enabled: true,\n endpoints: [\n 'POST /dev/credentials - Create test credentials',\n 'POST /dev/nodes - Create test node',\n 'POST /dev/setup - One-click setup (credentials + node)',\n 'DELETE /dev/cleanup/:testId - Cleanup test data',\n 'GET /dev/status - This endpoint',\n ],\n warning: 'These endpoints are for development only. Never expose in production!',\n });\n }, { public: true });\n}\n\nasync function readJsonBody(request: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve(undefined);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch {\n resolve(undefined);\n }\n });\n request.on('error', reject);\n });\n}\n\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data, null, 2));\n}\n"]}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { ApiServer } from '../ApiServer';
|
|
2
|
-
import type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';
|
|
3
|
-
export interface SignalHandlerOptions {
|
|
4
|
-
repository: EdgeNodeRepository;
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Handler for edge node signaling API
|
|
8
|
-
*
|
|
9
|
-
* POST /v1/signal - Edge node heartbeat/signal
|
|
10
|
-
*
|
|
11
|
-
* Requires API authentication and a nodeId in the request body.
|
|
12
|
-
*/
|
|
13
|
-
export declare function registerSignalRoutes(server: ApiServer, options: SignalHandlerOptions): void;
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerSignalRoutes = registerSignalRoutes;
|
|
4
|
-
const global_logger_factory_1 = require("global-logger-factory");
|
|
5
|
-
const AuthContext_1 = require("../auth/AuthContext");
|
|
6
|
-
/**
|
|
7
|
-
* Handler for edge node signaling API
|
|
8
|
-
*
|
|
9
|
-
* POST /v1/signal - Edge node heartbeat/signal
|
|
10
|
-
*
|
|
11
|
-
* Requires API authentication and a nodeId in the request body.
|
|
12
|
-
*/
|
|
13
|
-
function registerSignalRoutes(server, options) {
|
|
14
|
-
const logger = (0, global_logger_factory_1.getLoggerFor)('SignalHandler');
|
|
15
|
-
const repo = options.repository;
|
|
16
|
-
// POST /v1/signal - authenticated via API key or Solid token
|
|
17
|
-
server.post('/v1/signal', async (request, response, _params) => {
|
|
18
|
-
const auth = request.auth;
|
|
19
|
-
const webId = auth ? (0, AuthContext_1.getWebId)(auth) : undefined;
|
|
20
|
-
if (!webId) {
|
|
21
|
-
sendJson(response, 400, { error: 'Cannot determine user' });
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
const body = await readJsonBody(request);
|
|
25
|
-
if (!body || typeof body !== 'object') {
|
|
26
|
-
sendJson(response, 400, { error: 'Request body must be a JSON object' });
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
const payload = body;
|
|
30
|
-
const nodeId = typeof payload.nodeId === 'string' ? payload.nodeId.trim() : '';
|
|
31
|
-
if (!nodeId) {
|
|
32
|
-
sendJson(response, 400, { error: 'nodeId is required' });
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
try {
|
|
36
|
-
const owner = await repo.getNodeOwner(nodeId);
|
|
37
|
-
if (!owner) {
|
|
38
|
-
sendJson(response, 404, { error: 'Node not found' });
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
if (owner !== webId) {
|
|
42
|
-
sendJson(response, 403, { error: 'Access denied' });
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
logger.error(`Failed to validate node access: ${error}`);
|
|
48
|
-
sendJson(response, 500, { error: 'Failed to validate node access' });
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const now = new Date();
|
|
52
|
-
try {
|
|
53
|
-
// Get current metadata to merge
|
|
54
|
-
const existing = await repo.getNodeMetadata(nodeId);
|
|
55
|
-
const metadata = mergeMetadata(existing?.metadata ?? {}, payload, now);
|
|
56
|
-
// Update heartbeat
|
|
57
|
-
await repo.updateNodeHeartbeat(nodeId, metadata, now);
|
|
58
|
-
// Update pods if provided
|
|
59
|
-
if (Array.isArray(payload.pods)) {
|
|
60
|
-
await repo.replaceNodePods(nodeId, payload.pods);
|
|
61
|
-
}
|
|
62
|
-
logger.debug(`Signal received from node ${nodeId}`);
|
|
63
|
-
sendJson(response, 200, {
|
|
64
|
-
status: 'ok',
|
|
65
|
-
nodeId,
|
|
66
|
-
lastSeen: now.toISOString(),
|
|
67
|
-
metadata,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
logger.error(`Signal handling error for node ${nodeId}: ${error}`);
|
|
72
|
-
sendJson(response, 500, { error: 'Failed to process signal' });
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
function mergeMetadata(previous, payload, now) {
|
|
77
|
-
const next = { ...previous };
|
|
78
|
-
next.lastHeartbeatAt = now.toISOString();
|
|
79
|
-
const copyIfPresent = (key) => {
|
|
80
|
-
if (payload[key] !== undefined) {
|
|
81
|
-
next[key] = payload[key];
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
copyIfPresent('baseUrl');
|
|
85
|
-
copyIfPresent('publicAddress');
|
|
86
|
-
copyIfPresent('hostname');
|
|
87
|
-
copyIfPresent('ipv4');
|
|
88
|
-
copyIfPresent('ipv6');
|
|
89
|
-
copyIfPresent('version');
|
|
90
|
-
copyIfPresent('status');
|
|
91
|
-
copyIfPresent('capabilities');
|
|
92
|
-
copyIfPresent('metrics');
|
|
93
|
-
return next;
|
|
94
|
-
}
|
|
95
|
-
async function readJsonBody(request) {
|
|
96
|
-
return new Promise((resolve, reject) => {
|
|
97
|
-
let data = '';
|
|
98
|
-
request.setEncoding('utf8');
|
|
99
|
-
request.on('data', (chunk) => {
|
|
100
|
-
data += chunk;
|
|
101
|
-
});
|
|
102
|
-
request.on('end', () => {
|
|
103
|
-
if (!data) {
|
|
104
|
-
resolve(undefined);
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
try {
|
|
108
|
-
resolve(JSON.parse(data));
|
|
109
|
-
}
|
|
110
|
-
catch {
|
|
111
|
-
resolve(undefined);
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
request.on('error', reject);
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
function sendJson(response, status, data) {
|
|
118
|
-
response.statusCode = status;
|
|
119
|
-
response.setHeader('Content-Type', 'application/json');
|
|
120
|
-
response.end(JSON.stringify(data));
|
|
121
|
-
}
|
|
122
|
-
//# sourceMappingURL=SignalHandler.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SignalHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/SignalHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ServerResponse } from 'node:http';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { AuthenticatedRequest } from '../middleware/AuthMiddleware';\nimport type { ApiServer } from '../ApiServer';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport { getWebId } from '../auth/AuthContext';\n\nexport interface SignalHandlerOptions {\n repository: EdgeNodeRepository;\n}\n\n/**\n * Handler for edge node signaling API\n *\n * POST /v1/signal - Edge node heartbeat/signal\n *\n * Requires API authentication and a nodeId in the request body.\n */\nexport function registerSignalRoutes(server: ApiServer, options: SignalHandlerOptions): void {\n const logger = getLoggerFor('SignalHandler');\n const repo = options.repository;\n\n // POST /v1/signal - authenticated via API key or Solid token\n server.post('/v1/signal', async (request, response, _params) => {\n const auth = request.auth;\n const webId = auth ? getWebId(auth) : undefined;\n if (!webId) {\n sendJson(response, 400, { error: 'Cannot determine user' });\n return;\n }\n const body = await readJsonBody(request);\n\n if (!body || typeof body !== 'object') {\n sendJson(response, 400, { error: 'Request body must be a JSON object' });\n return;\n }\n\n const payload = body as Record<string, unknown>;\n const nodeId = typeof payload.nodeId === 'string' ? payload.nodeId.trim() : '';\n if (!nodeId) {\n sendJson(response, 400, { error: 'nodeId is required' });\n return;\n }\n\n try {\n const owner = await repo.getNodeOwner(nodeId);\n if (!owner) {\n sendJson(response, 404, { error: 'Node not found' });\n return;\n }\n if (owner !== webId) {\n sendJson(response, 403, { error: 'Access denied' });\n return;\n }\n } catch (error) {\n logger.error(`Failed to validate node access: ${error}`);\n sendJson(response, 500, { error: 'Failed to validate node access' });\n return;\n }\n\n\n const now = new Date();\n\n try {\n // Get current metadata to merge\n const existing = await repo.getNodeMetadata(nodeId);\n const metadata = mergeMetadata(existing?.metadata ?? {}, payload, now);\n\n // Update heartbeat\n await repo.updateNodeHeartbeat(nodeId, metadata, now);\n\n // Update pods if provided\n if (Array.isArray(payload.pods)) {\n await repo.replaceNodePods(nodeId, payload.pods as string[]);\n }\n\n logger.debug(`Signal received from node ${nodeId}`);\n\n sendJson(response, 200, {\n status: 'ok',\n nodeId,\n lastSeen: now.toISOString(),\n metadata,\n });\n } catch (error) {\n logger.error(`Signal handling error for node ${nodeId}: ${error}`);\n sendJson(response, 500, { error: 'Failed to process signal' });\n }\n });\n}\n\nfunction mergeMetadata(\n previous: Record<string, unknown>,\n payload: Record<string, unknown>,\n now: Date,\n): Record<string, unknown> {\n const next: Record<string, unknown> = { ...previous };\n next.lastHeartbeatAt = now.toISOString();\n\n const copyIfPresent = (key: string) => {\n if (payload[key] !== undefined) {\n next[key] = payload[key];\n }\n };\n\n copyIfPresent('baseUrl');\n copyIfPresent('publicAddress');\n copyIfPresent('hostname');\n copyIfPresent('ipv4');\n copyIfPresent('ipv6');\n copyIfPresent('version');\n copyIfPresent('status');\n copyIfPresent('capabilities');\n copyIfPresent('metrics');\n\n return next;\n}\n\nasync function readJsonBody(request: AuthenticatedRequest): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let data = '';\n request.setEncoding('utf8');\n request.on('data', (chunk: string) => {\n data += chunk;\n });\n request.on('end', () => {\n if (!data) {\n resolve(undefined);\n return;\n }\n try {\n resolve(JSON.parse(data));\n } catch {\n resolve(undefined);\n }\n });\n request.on('error', reject);\n });\n}\n\nfunction sendJson(response: ServerResponse, status: number, data: unknown): void {\n response.statusCode = status;\n response.setHeader('Content-Type', 'application/json');\n response.end(JSON.stringify(data));\n}\n"]}
|
package/dist/gateway/Proxy.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { Supervisor } from './Supervisor';
|
|
2
|
-
export declare class GatewayProxy {
|
|
3
|
-
private port;
|
|
4
|
-
private supervisor;
|
|
5
|
-
private readonly logger;
|
|
6
|
-
private proxy;
|
|
7
|
-
private server;
|
|
8
|
-
private targets;
|
|
9
|
-
constructor(port: number, supervisor: Supervisor);
|
|
10
|
-
setTargets(targets: {
|
|
11
|
-
css?: string;
|
|
12
|
-
api?: string;
|
|
13
|
-
}): void;
|
|
14
|
-
start(): void;
|
|
15
|
-
stop(): Promise<void>;
|
|
16
|
-
private handleRequest;
|
|
17
|
-
private handleCorsPreflightRequest;
|
|
18
|
-
/**
|
|
19
|
-
* Add CORS headers matching CSS CorsHandler configuration
|
|
20
|
-
*/
|
|
21
|
-
private addCorsHeaders;
|
|
22
|
-
private handleInternalApi;
|
|
23
|
-
private isCssReady;
|
|
24
|
-
}
|