@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.
Files changed (305) hide show
  1. package/README.md +141 -2
  2. package/config/cli.json +9 -71
  3. package/config/cloud.json +34 -7
  4. package/config/local.json +6 -2
  5. package/config/resolver.json +11 -49
  6. package/config/runtime-open.json +22 -0
  7. package/config/xpod.base.json +32 -0
  8. package/config/xpod.cluster.json +2 -44
  9. package/config/xpod.json +5 -2
  10. package/dist/api/auth/AuthContext.d.ts +12 -1
  11. package/dist/api/auth/AuthContext.js +18 -1
  12. package/dist/api/auth/AuthContext.js.map +1 -1
  13. package/dist/api/auth/ClientCredentialsAuthenticator.d.ts +0 -1
  14. package/dist/api/auth/ClientCredentialsAuthenticator.js.map +1 -1
  15. package/dist/api/auth/ServiceTokenAuthenticator.d.ts +18 -0
  16. package/dist/api/auth/ServiceTokenAuthenticator.js +50 -0
  17. package/dist/api/auth/ServiceTokenAuthenticator.js.map +1 -0
  18. package/dist/api/auth/index.d.ts +1 -0
  19. package/dist/api/auth/index.js +1 -0
  20. package/dist/api/auth/index.js.map +1 -1
  21. package/dist/api/chatkit/ai-provider.d.ts +0 -10
  22. package/dist/api/chatkit/ai-provider.js +11 -120
  23. package/dist/api/chatkit/ai-provider.js.map +1 -1
  24. package/dist/api/chatkit/default-agent.js +11 -8
  25. package/dist/api/chatkit/default-agent.js.map +1 -1
  26. package/dist/api/chatkit/pod-store.js +19 -3
  27. package/dist/api/chatkit/pod-store.js.map +1 -1
  28. package/dist/api/chatkit/schema.d.ts +9 -3
  29. package/dist/api/chatkit/schema.js +14 -6
  30. package/dist/api/chatkit/schema.js.map +1 -1
  31. package/dist/api/container/business-token.d.ts +9 -0
  32. package/dist/api/container/business-token.js +32 -0
  33. package/dist/api/container/business-token.js.map +1 -0
  34. package/dist/api/container/cloud.js +36 -12
  35. package/dist/api/container/cloud.js.map +1 -1
  36. package/dist/api/container/common.js +12 -5
  37. package/dist/api/container/common.js.map +1 -1
  38. package/dist/api/container/index.js +94 -14
  39. package/dist/api/container/index.js.map +1 -1
  40. package/dist/api/container/local.js +2 -1
  41. package/dist/api/container/local.js.map +1 -1
  42. package/dist/api/container/routes.js +81 -9
  43. package/dist/api/container/routes.js.map +1 -1
  44. package/dist/api/container/types.d.ts +8 -6
  45. package/dist/api/container/types.js.map +1 -1
  46. package/dist/api/handlers/AdminHandler.js +9 -9
  47. package/dist/api/handlers/AdminHandler.js.map +1 -1
  48. package/dist/api/handlers/ApiKeyHandler.js +0 -6
  49. package/dist/api/handlers/ApiKeyHandler.js.map +1 -1
  50. package/dist/api/handlers/EdgeNodeSignalHandler.d.ts +17 -0
  51. package/dist/api/handlers/EdgeNodeSignalHandler.js +171 -0
  52. package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -0
  53. package/dist/api/handlers/PodManagementHandler.d.ts +5 -4
  54. package/dist/api/handlers/PodManagementHandler.js +11 -10
  55. package/dist/api/handlers/PodManagementHandler.js.map +1 -1
  56. package/dist/api/handlers/ProvisionHandler.d.ts +42 -0
  57. package/dist/api/handlers/ProvisionHandler.js +161 -0
  58. package/dist/api/handlers/ProvisionHandler.js.map +1 -0
  59. package/dist/api/handlers/QuotaHandler.d.ts +7 -7
  60. package/dist/api/handlers/QuotaHandler.js +143 -73
  61. package/dist/api/handlers/QuotaHandler.js.map +1 -1
  62. package/dist/api/handlers/SubdomainClientHandler.js +2 -2
  63. package/dist/api/handlers/SubdomainClientHandler.js.map +1 -1
  64. package/dist/api/handlers/SubdomainHandler.js +13 -8
  65. package/dist/api/handlers/SubdomainHandler.js.map +1 -1
  66. package/dist/api/handlers/UsageHandler.d.ts +14 -0
  67. package/dist/api/handlers/UsageHandler.js +123 -0
  68. package/dist/api/handlers/UsageHandler.js.map +1 -0
  69. package/dist/api/handlers/index.d.ts +3 -1
  70. package/dist/api/handlers/index.js +3 -1
  71. package/dist/api/handlers/index.js.map +1 -1
  72. package/dist/api/main.js +18 -0
  73. package/dist/api/main.js.map +1 -1
  74. package/dist/api/middleware/OpenAuthMiddleware.d.ts +12 -0
  75. package/dist/api/middleware/OpenAuthMiddleware.js +27 -0
  76. package/dist/api/middleware/OpenAuthMiddleware.js.map +1 -0
  77. package/dist/api/runtime.d.ts +15 -0
  78. package/dist/api/runtime.js +104 -0
  79. package/dist/api/runtime.js.map +1 -0
  80. package/dist/api/service/VercelChatService.d.ts +16 -7
  81. package/dist/api/service/VercelChatService.js +98 -178
  82. package/dist/api/service/VercelChatService.js.map +1 -1
  83. package/dist/api/store/DrizzleClientCredentialsStore.d.ts +6 -11
  84. package/dist/api/store/DrizzleClientCredentialsStore.js +9 -39
  85. package/dist/api/store/DrizzleClientCredentialsStore.js.map +1 -1
  86. package/dist/authorization/AuthModeSelector.d.ts +10 -0
  87. package/dist/authorization/AuthModeSelector.js +27 -0
  88. package/dist/authorization/AuthModeSelector.js.map +1 -0
  89. package/dist/authorization/AuthModeSelector.jsonld +81 -0
  90. package/dist/cli/commands/account.d.ts +6 -0
  91. package/dist/cli/commands/account.js +119 -0
  92. package/dist/cli/commands/account.js.map +1 -0
  93. package/dist/cli/commands/auth.js +20 -29
  94. package/dist/cli/commands/auth.js.map +1 -1
  95. package/dist/cli/commands/backup.d.ts +15 -0
  96. package/dist/cli/commands/backup.js +286 -0
  97. package/dist/cli/commands/backup.js.map +1 -0
  98. package/dist/cli/commands/config.d.ts +34 -3
  99. package/dist/cli/commands/config.js +195 -258
  100. package/dist/cli/commands/config.js.map +1 -1
  101. package/dist/cli/commands/doctor.d.ts +6 -0
  102. package/dist/cli/commands/doctor.js +94 -0
  103. package/dist/cli/commands/doctor.js.map +1 -0
  104. package/dist/cli/commands/pod.d.ts +6 -0
  105. package/dist/cli/commands/pod.js +124 -0
  106. package/dist/cli/commands/pod.js.map +1 -0
  107. package/dist/cli/commands/start.js +28 -5
  108. package/dist/cli/commands/start.js.map +1 -1
  109. package/dist/cli/index.js +9 -0
  110. package/dist/cli/index.js.map +1 -1
  111. package/dist/cli/lib/credentials-store.d.ts +17 -0
  112. package/dist/cli/lib/credentials-store.js +73 -0
  113. package/dist/cli/lib/credentials-store.js.map +1 -0
  114. package/dist/cli/lib/css-account.d.ts +17 -0
  115. package/dist/cli/lib/css-account.js +56 -0
  116. package/dist/cli/lib/css-account.js.map +1 -1
  117. package/dist/cli/lib/pod-thread-store.d.ts +57 -0
  118. package/dist/cli/lib/pod-thread-store.js +310 -0
  119. package/dist/cli/lib/pod-thread-store.js.map +1 -0
  120. package/dist/cli/lib/solid-auth.d.ts +20 -0
  121. package/dist/cli/lib/solid-auth.js +70 -0
  122. package/dist/cli/lib/solid-auth.js.map +1 -0
  123. package/dist/components/components.jsonld +5 -8
  124. package/dist/components/context.jsonld +114 -244
  125. package/dist/edge/EdgeNodeAgent.js +2 -2
  126. package/dist/edge/EdgeNodeAgent.js.map +1 -1
  127. package/dist/edge/EdgeNodeDnsCoordinator.d.ts +1 -7
  128. package/dist/edge/EdgeNodeDnsCoordinator.js +31 -41
  129. package/dist/edge/EdgeNodeDnsCoordinator.js.map +1 -1
  130. package/dist/edge/EdgeNodeDnsCoordinator.jsonld +1 -27
  131. package/dist/edge/EdgeNodeModeDetector.d.ts +1 -1
  132. package/dist/edge/EdgeNodeModeDetector.js +9 -11
  133. package/dist/edge/EdgeNodeModeDetector.js.map +1 -1
  134. package/dist/http/ClusterIngressRouter.js +3 -3
  135. package/dist/http/ClusterIngressRouter.js.map +1 -1
  136. package/dist/http/ClusterWebSocketConfigurator.js +2 -2
  137. package/dist/http/ClusterWebSocketConfigurator.js.map +1 -1
  138. package/dist/http/PodRoutingHttpHandler.js +2 -2
  139. package/dist/http/PodRoutingHttpHandler.js.map +1 -1
  140. package/dist/http/cluster/PodMigrationHttpHandler.d.ts +1 -1
  141. package/dist/http/cluster/PodMigrationHttpHandler.js +1 -1
  142. package/dist/http/cluster/PodMigrationHttpHandler.js.map +1 -1
  143. package/dist/identity/drizzle/EdgeNodeRepository.d.ts +37 -4
  144. package/dist/identity/drizzle/EdgeNodeRepository.js +120 -128
  145. package/dist/identity/drizzle/EdgeNodeRepository.js.map +1 -1
  146. package/dist/identity/drizzle/ServiceTokenRepository.d.ts +52 -0
  147. package/dist/identity/drizzle/ServiceTokenRepository.js +143 -0
  148. package/dist/identity/drizzle/ServiceTokenRepository.js.map +1 -0
  149. package/dist/identity/drizzle/db.d.ts +9 -0
  150. package/dist/identity/drizzle/db.js +208 -1
  151. package/dist/identity/drizzle/db.js.map +1 -1
  152. package/dist/identity/drizzle/schema.pg.d.ts +5 -0
  153. package/dist/identity/drizzle/schema.pg.js +49 -20
  154. package/dist/identity/drizzle/schema.pg.js.map +1 -1
  155. package/dist/identity/drizzle/schema.sqlite.d.ts +332 -57
  156. package/dist/identity/drizzle/schema.sqlite.js +48 -18
  157. package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
  158. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js +6 -4
  159. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js.map +1 -1
  160. package/dist/index.d.ts +6 -9
  161. package/dist/index.js +12 -14
  162. package/dist/index.js.map +1 -1
  163. package/dist/main.js +25 -8
  164. package/dist/main.js.map +1 -1
  165. package/dist/provision/ProvisionCodeCodec.d.ts +39 -0
  166. package/dist/provision/ProvisionCodeCodec.js +65 -0
  167. package/dist/provision/ProvisionCodeCodec.js.map +1 -0
  168. package/dist/provision/ProvisionCodeCodec.jsonld +47 -0
  169. package/dist/provision/ProvisionPodCreator.d.ts +20 -0
  170. package/dist/provision/ProvisionPodCreator.js +84 -0
  171. package/dist/provision/ProvisionPodCreator.js.map +1 -0
  172. package/dist/provision/ProvisionPodCreator.jsonld +118 -0
  173. package/dist/quota/DrizzleQuotaService.d.ts +17 -3
  174. package/dist/quota/DrizzleQuotaService.js +108 -8
  175. package/dist/quota/DrizzleQuotaService.js.map +1 -1
  176. package/dist/quota/DrizzleQuotaService.jsonld +33 -22
  177. package/dist/quota/NoopQuotaService.d.ts +7 -1
  178. package/dist/quota/NoopQuotaService.js +12 -0
  179. package/dist/quota/NoopQuotaService.js.map +1 -1
  180. package/dist/quota/NoopQuotaService.jsonld +24 -0
  181. package/dist/quota/QuotaService.d.ts +17 -0
  182. package/dist/quota/QuotaService.js +5 -0
  183. package/dist/quota/QuotaService.js.map +1 -1
  184. package/dist/quota/QuotaService.jsonld +50 -0
  185. package/dist/runtime/Proxy.d.ts +22 -4
  186. package/dist/runtime/Proxy.js +154 -35
  187. package/dist/runtime/Proxy.js.map +1 -1
  188. package/dist/runtime/XpodRuntime.d.ts +49 -0
  189. package/dist/runtime/XpodRuntime.js +374 -0
  190. package/dist/runtime/XpodRuntime.js.map +1 -0
  191. package/dist/runtime/env-utils.d.ts +2 -0
  192. package/dist/runtime/env-utils.js +55 -0
  193. package/dist/runtime/env-utils.js.map +1 -0
  194. package/dist/runtime/index.d.ts +4 -0
  195. package/dist/runtime/index.js +8 -1
  196. package/dist/runtime/index.js.map +1 -1
  197. package/dist/runtime/socket-fetch.d.ts +1 -0
  198. package/dist/runtime/socket-fetch.js +72 -0
  199. package/dist/runtime/socket-fetch.js.map +1 -0
  200. package/dist/runtime/socket-http.d.ts +1 -0
  201. package/dist/runtime/socket-http.js +142 -0
  202. package/dist/runtime/socket-http.js.map +1 -0
  203. package/dist/runtime/socket-utils.d.ts +2 -0
  204. package/dist/runtime/socket-utils.js +34 -0
  205. package/dist/runtime/socket-utils.js.map +1 -0
  206. package/dist/service/{EdgeNodeHeartbeatService.d.ts → EdgeNodeSignalClient.d.ts} +3 -3
  207. package/dist/service/{EdgeNodeHeartbeatService.js → EdgeNodeSignalClient.js} +4 -4
  208. package/dist/service/EdgeNodeSignalClient.js.map +1 -0
  209. package/dist/service/PodMigrationService.d.ts +1 -2
  210. package/dist/service/PodMigrationService.js +1 -2
  211. package/dist/service/PodMigrationService.js.map +1 -1
  212. package/dist/storage/SparqlUpdateResourceStore.js +1 -1
  213. package/dist/storage/SparqlUpdateResourceStore.js.map +1 -1
  214. package/dist/storage/accessors/MinioDataAccessor.d.ts +6 -0
  215. package/dist/storage/accessors/MinioDataAccessor.js +10 -0
  216. package/dist/storage/accessors/MinioDataAccessor.js.map +1 -1
  217. package/dist/storage/accessors/MinioDataAccessor.jsonld +4 -0
  218. package/dist/storage/accessors/MixDataAccessor.d.ts +2 -1
  219. package/dist/storage/accessors/MixDataAccessor.js +12 -1
  220. package/dist/storage/accessors/MixDataAccessor.js.map +1 -1
  221. package/dist/storage/accessors/MixDataAccessor.jsonld +19 -0
  222. package/dist/storage/locking/UrlAwareRedisLocker.d.ts +18 -0
  223. package/dist/storage/locking/UrlAwareRedisLocker.js +60 -0
  224. package/dist/storage/locking/UrlAwareRedisLocker.js.map +1 -0
  225. package/dist/storage/locking/UrlAwareRedisLocker.jsonld +123 -0
  226. package/dist/storage/quota/UsageRepository.d.ts +41 -8
  227. package/dist/storage/quota/UsageRepository.js +252 -50
  228. package/dist/storage/quota/UsageRepository.js.map +1 -1
  229. package/dist/storage/sparql/ComunicaQuintEngine.d.ts +9 -0
  230. package/dist/storage/sparql/ComunicaQuintEngine.js +50 -9
  231. package/dist/storage/sparql/ComunicaQuintEngine.js.map +1 -1
  232. package/dist/storage/sparql/QueryOptimizer.js +13 -1
  233. package/dist/storage/sparql/QueryOptimizer.js.map +1 -1
  234. package/dist/storage/sparql/QuintQuerySource.d.ts +14 -0
  235. package/dist/storage/sparql/QuintQuerySource.js +152 -1
  236. package/dist/storage/sparql/QuintQuerySource.js.map +1 -1
  237. package/dist/storage/sparql/SubgraphQueryEngine.d.ts +1 -0
  238. package/dist/storage/sparql/SubgraphQueryEngine.js +6 -2
  239. package/dist/storage/sparql/SubgraphQueryEngine.js.map +1 -1
  240. package/dist/storage/sparql/SubgraphQueryEngine.jsonld +4 -0
  241. package/dist/subdomain/SubdomainClient.d.ts +3 -3
  242. package/dist/subdomain/SubdomainClient.js +1 -1
  243. package/dist/subdomain/SubdomainClient.js.map +1 -1
  244. package/dist/subdomain/SubdomainService.d.ts +15 -16
  245. package/dist/subdomain/SubdomainService.js +80 -54
  246. package/dist/subdomain/SubdomainService.js.map +1 -1
  247. package/dist/subdomain/SubdomainService.jsonld +22 -26
  248. package/dist/supervisor/Supervisor.d.ts +7 -2
  249. package/dist/supervisor/Supervisor.js +33 -1
  250. package/dist/supervisor/Supervisor.js.map +1 -1
  251. package/dist/test-utils/index.d.ts +4 -0
  252. package/dist/test-utils/index.js +8 -0
  253. package/dist/test-utils/index.js.map +1 -0
  254. package/dist/test-utils/no-auth-xpod.d.ts +11 -0
  255. package/dist/test-utils/no-auth-xpod.js +25 -0
  256. package/dist/test-utils/no-auth-xpod.js.map +1 -0
  257. package/dist/test-utils/seed-pod.d.ts +5 -0
  258. package/dist/test-utils/seed-pod.js +61 -0
  259. package/dist/test-utils/seed-pod.js.map +1 -0
  260. package/package.json +23 -5
  261. package/templates/identity/account/create-pod.html.ejs +110 -0
  262. package/templates/main.html.ejs +10 -0
  263. package/dist/api/handlers/DevHandler.d.ts +0 -18
  264. package/dist/api/handlers/DevHandler.js +0 -276
  265. package/dist/api/handlers/DevHandler.js.map +0 -1
  266. package/dist/api/handlers/SignalHandler.d.ts +0 -13
  267. package/dist/api/handlers/SignalHandler.js +0 -122
  268. package/dist/api/handlers/SignalHandler.js.map +0 -1
  269. package/dist/gateway/Proxy.d.ts +0 -24
  270. package/dist/gateway/Proxy.js +0 -209
  271. package/dist/gateway/Proxy.js.map +0 -1
  272. package/dist/gateway/Supervisor.d.ts +0 -2
  273. package/dist/gateway/Supervisor.js +0 -7
  274. package/dist/gateway/Supervisor.js.map +0 -1
  275. package/dist/gateway/port-finder.d.ts +0 -4
  276. package/dist/gateway/port-finder.js +0 -15
  277. package/dist/gateway/port-finder.js.map +0 -1
  278. package/dist/gateway/types.d.ts +0 -1
  279. package/dist/gateway/types.js +0 -3
  280. package/dist/gateway/types.js.map +0 -1
  281. package/dist/http/SignalInterceptHttpHandler.d.ts +0 -24
  282. package/dist/http/SignalInterceptHttpHandler.js +0 -47
  283. package/dist/http/SignalInterceptHttpHandler.js.map +0 -1
  284. package/dist/http/SignalInterceptHttpHandler.jsonld +0 -103
  285. package/dist/http/admin/EdgeNodeSignalHttpHandler.d.ts +0 -71
  286. package/dist/http/admin/EdgeNodeSignalHttpHandler.js +0 -674
  287. package/dist/http/admin/EdgeNodeSignalHttpHandler.js.map +0 -1
  288. package/dist/http/admin/EdgeNodeSignalHttpHandler.jsonld +0 -406
  289. package/dist/http/cluster/PodMigrationHttpHandler.jsonld +0 -169
  290. package/dist/quota/DefaultQuotaService.d.ts +0 -16
  291. package/dist/quota/DefaultQuotaService.js +0 -37
  292. package/dist/quota/DefaultQuotaService.js.map +0 -1
  293. package/dist/quota/DefaultQuotaService.jsonld +0 -85
  294. package/dist/service/EdgeNodeHeartbeatService.js.map +0 -1
  295. package/dist/service/PodMigrationService.jsonld +0 -76
  296. package/dist/storage/MigratableDataAccessor.d.ts +0 -63
  297. package/dist/storage/MigratableDataAccessor.js +0 -11
  298. package/dist/storage/MigratableDataAccessor.js.map +0 -1
  299. package/dist/storage/MigratableDataAccessor.jsonld +0 -60
  300. package/dist/storage/accessors/TieredMinioDataAccessor.d.ts +0 -150
  301. package/dist/storage/accessors/TieredMinioDataAccessor.js +0 -582
  302. package/dist/storage/accessors/TieredMinioDataAccessor.js.map +0 -1
  303. package/dist/storage/accessors/TieredMinioDataAccessor.jsonld +0 -333
  304. package/static/app/assets/index.css +0 -1
  305. 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"]}
@@ -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
- }