@undefineds.co/xpod 0.1.7 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (350) hide show
  1. package/README.md +164 -3
  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/agents/AgentExecutorFactory.js +1 -1
  11. package/dist/agents/AgentExecutorFactory.js.map +1 -1
  12. package/dist/agents/AgentManager.js +1 -1
  13. package/dist/agents/AgentManager.js.map +1 -1
  14. package/dist/agents/config/agent-meta-schema.d.ts +7 -7
  15. package/dist/agents/config/agent-meta-schema.js +1 -1
  16. package/dist/agents/config/agent-meta-schema.js.map +1 -1
  17. package/dist/agents/config/resolve.js +1 -1
  18. package/dist/agents/config/resolve.js.map +1 -1
  19. package/dist/agents/schema/agent-config.d.ts +18 -18
  20. package/dist/agents/schema/agent-config.js +1 -1
  21. package/dist/agents/schema/agent-config.js.map +1 -1
  22. package/dist/agents/schema/tables.d.ts +8 -8
  23. package/dist/agents/schema/tables.js +1 -1
  24. package/dist/agents/schema/tables.js.map +1 -1
  25. package/dist/ai/schema/config.d.ts +7 -7
  26. package/dist/ai/schema/config.js +1 -1
  27. package/dist/ai/schema/config.js.map +1 -1
  28. package/dist/ai/schema/model.d.ts +13 -13
  29. package/dist/ai/schema/model.js +1 -1
  30. package/dist/ai/schema/model.js.map +1 -1
  31. package/dist/ai/schema/provider.d.ts +7 -7
  32. package/dist/ai/schema/provider.js +1 -1
  33. package/dist/ai/schema/provider.js.map +1 -1
  34. package/dist/ai/schema/vector-store.d.ts +17 -17
  35. package/dist/ai/schema/vector-store.js +1 -1
  36. package/dist/ai/schema/vector-store.js.map +1 -1
  37. package/dist/ai/service/CredentialReaderImpl.js +1 -1
  38. package/dist/ai/service/CredentialReaderImpl.js.map +1 -1
  39. package/dist/ai/service/DefaultAiConfigService.js.map +1 -1
  40. package/dist/api/ApiServer.d.ts +3 -1
  41. package/dist/api/ApiServer.js +14 -1
  42. package/dist/api/ApiServer.js.map +1 -1
  43. package/dist/api/auth/AuthContext.d.ts +12 -1
  44. package/dist/api/auth/AuthContext.js +18 -1
  45. package/dist/api/auth/AuthContext.js.map +1 -1
  46. package/dist/api/auth/ClientCredentialsAuthenticator.d.ts +0 -1
  47. package/dist/api/auth/ClientCredentialsAuthenticator.js.map +1 -1
  48. package/dist/api/auth/ServiceTokenAuthenticator.d.ts +18 -0
  49. package/dist/api/auth/ServiceTokenAuthenticator.js +50 -0
  50. package/dist/api/auth/ServiceTokenAuthenticator.js.map +1 -0
  51. package/dist/api/auth/index.d.ts +1 -0
  52. package/dist/api/auth/index.js +1 -0
  53. package/dist/api/auth/index.js.map +1 -1
  54. package/dist/api/chatkit/ai-provider.d.ts +0 -10
  55. package/dist/api/chatkit/ai-provider.js +11 -120
  56. package/dist/api/chatkit/ai-provider.js.map +1 -1
  57. package/dist/api/chatkit/default-agent.js +11 -8
  58. package/dist/api/chatkit/default-agent.js.map +1 -1
  59. package/dist/api/chatkit/pod-store.d.ts +6 -0
  60. package/dist/api/chatkit/pod-store.js +103 -36
  61. package/dist/api/chatkit/pod-store.js.map +1 -1
  62. package/dist/api/chatkit/schema.d.ts +32 -26
  63. package/dist/api/chatkit/schema.js +16 -8
  64. package/dist/api/chatkit/schema.js.map +1 -1
  65. package/dist/api/container/business-token.d.ts +9 -0
  66. package/dist/api/container/business-token.js +32 -0
  67. package/dist/api/container/business-token.js.map +1 -0
  68. package/dist/api/container/cloud.js +36 -12
  69. package/dist/api/container/cloud.js.map +1 -1
  70. package/dist/api/container/common.js +13 -5
  71. package/dist/api/container/common.js.map +1 -1
  72. package/dist/api/container/index.js +94 -14
  73. package/dist/api/container/index.js.map +1 -1
  74. package/dist/api/container/local.js +2 -1
  75. package/dist/api/container/local.js.map +1 -1
  76. package/dist/api/container/routes.js +81 -9
  77. package/dist/api/container/routes.js.map +1 -1
  78. package/dist/api/container/types.d.ts +8 -6
  79. package/dist/api/container/types.js.map +1 -1
  80. package/dist/api/handlers/AdminHandler.js +9 -9
  81. package/dist/api/handlers/AdminHandler.js.map +1 -1
  82. package/dist/api/handlers/ApiKeyHandler.js +0 -6
  83. package/dist/api/handlers/ApiKeyHandler.js.map +1 -1
  84. package/dist/api/handlers/EdgeNodeSignalHandler.d.ts +17 -0
  85. package/dist/api/handlers/EdgeNodeSignalHandler.js +171 -0
  86. package/dist/api/handlers/EdgeNodeSignalHandler.js.map +1 -0
  87. package/dist/api/handlers/PodManagementHandler.d.ts +5 -4
  88. package/dist/api/handlers/PodManagementHandler.js +11 -10
  89. package/dist/api/handlers/PodManagementHandler.js.map +1 -1
  90. package/dist/api/handlers/ProvisionHandler.d.ts +42 -0
  91. package/dist/api/handlers/ProvisionHandler.js +161 -0
  92. package/dist/api/handlers/ProvisionHandler.js.map +1 -0
  93. package/dist/api/handlers/QuotaHandler.d.ts +7 -7
  94. package/dist/api/handlers/QuotaHandler.js +143 -73
  95. package/dist/api/handlers/QuotaHandler.js.map +1 -1
  96. package/dist/api/handlers/SubdomainClientHandler.js +2 -2
  97. package/dist/api/handlers/SubdomainClientHandler.js.map +1 -1
  98. package/dist/api/handlers/SubdomainHandler.js +13 -8
  99. package/dist/api/handlers/SubdomainHandler.js.map +1 -1
  100. package/dist/api/handlers/UsageHandler.d.ts +14 -0
  101. package/dist/api/handlers/UsageHandler.js +123 -0
  102. package/dist/api/handlers/UsageHandler.js.map +1 -0
  103. package/dist/api/handlers/index.d.ts +3 -1
  104. package/dist/api/handlers/index.js +3 -1
  105. package/dist/api/handlers/index.js.map +1 -1
  106. package/dist/api/main.js +18 -0
  107. package/dist/api/main.js.map +1 -1
  108. package/dist/api/middleware/OpenAuthMiddleware.d.ts +12 -0
  109. package/dist/api/middleware/OpenAuthMiddleware.js +27 -0
  110. package/dist/api/middleware/OpenAuthMiddleware.js.map +1 -0
  111. package/dist/api/runtime.d.ts +15 -0
  112. package/dist/api/runtime.js +125 -0
  113. package/dist/api/runtime.js.map +1 -0
  114. package/dist/api/service/VectorStoreService.js +1 -1
  115. package/dist/api/service/VectorStoreService.js.map +1 -1
  116. package/dist/api/service/VercelChatService.d.ts +16 -7
  117. package/dist/api/service/VercelChatService.js +98 -178
  118. package/dist/api/service/VercelChatService.js.map +1 -1
  119. package/dist/api/store/DrizzleClientCredentialsStore.d.ts +6 -11
  120. package/dist/api/store/DrizzleClientCredentialsStore.js +9 -39
  121. package/dist/api/store/DrizzleClientCredentialsStore.js.map +1 -1
  122. package/dist/authorization/AuthModeSelector.d.ts +10 -0
  123. package/dist/authorization/AuthModeSelector.js +27 -0
  124. package/dist/authorization/AuthModeSelector.js.map +1 -0
  125. package/dist/authorization/AuthModeSelector.jsonld +81 -0
  126. package/dist/cli/commands/account.d.ts +6 -0
  127. package/dist/cli/commands/account.js +119 -0
  128. package/dist/cli/commands/account.js.map +1 -0
  129. package/dist/cli/commands/auth.js +20 -29
  130. package/dist/cli/commands/auth.js.map +1 -1
  131. package/dist/cli/commands/backup.d.ts +15 -0
  132. package/dist/cli/commands/backup.js +286 -0
  133. package/dist/cli/commands/backup.js.map +1 -0
  134. package/dist/cli/commands/config.d.ts +34 -3
  135. package/dist/cli/commands/config.js +195 -258
  136. package/dist/cli/commands/config.js.map +1 -1
  137. package/dist/cli/commands/doctor.d.ts +6 -0
  138. package/dist/cli/commands/doctor.js +94 -0
  139. package/dist/cli/commands/doctor.js.map +1 -0
  140. package/dist/cli/commands/pod.d.ts +6 -0
  141. package/dist/cli/commands/pod.js +124 -0
  142. package/dist/cli/commands/pod.js.map +1 -0
  143. package/dist/cli/commands/start.js +28 -5
  144. package/dist/cli/commands/start.js.map +1 -1
  145. package/dist/cli/index.js +9 -0
  146. package/dist/cli/index.js.map +1 -1
  147. package/dist/cli/lib/credentials-store.d.ts +17 -0
  148. package/dist/cli/lib/credentials-store.js +73 -0
  149. package/dist/cli/lib/credentials-store.js.map +1 -0
  150. package/dist/cli/lib/css-account.d.ts +17 -0
  151. package/dist/cli/lib/css-account.js +56 -0
  152. package/dist/cli/lib/css-account.js.map +1 -1
  153. package/dist/cli/lib/pod-thread-store.d.ts +57 -0
  154. package/dist/cli/lib/pod-thread-store.js +310 -0
  155. package/dist/cli/lib/pod-thread-store.js.map +1 -0
  156. package/dist/cli/lib/solid-auth.d.ts +20 -0
  157. package/dist/cli/lib/solid-auth.js +70 -0
  158. package/dist/cli/lib/solid-auth.js.map +1 -0
  159. package/dist/components/components.jsonld +5 -8
  160. package/dist/components/context.jsonld +114 -244
  161. package/dist/credential/schema/tables.d.ts +14 -14
  162. package/dist/credential/schema/tables.js +1 -1
  163. package/dist/credential/schema/tables.js.map +1 -1
  164. package/dist/edge/EdgeNodeAgent.js +2 -2
  165. package/dist/edge/EdgeNodeAgent.js.map +1 -1
  166. package/dist/edge/EdgeNodeDnsCoordinator.d.ts +1 -7
  167. package/dist/edge/EdgeNodeDnsCoordinator.js +31 -41
  168. package/dist/edge/EdgeNodeDnsCoordinator.js.map +1 -1
  169. package/dist/edge/EdgeNodeDnsCoordinator.jsonld +1 -27
  170. package/dist/edge/EdgeNodeModeDetector.d.ts +1 -1
  171. package/dist/edge/EdgeNodeModeDetector.js +9 -11
  172. package/dist/edge/EdgeNodeModeDetector.js.map +1 -1
  173. package/dist/http/ClusterIngressRouter.js +3 -3
  174. package/dist/http/ClusterIngressRouter.js.map +1 -1
  175. package/dist/http/ClusterWebSocketConfigurator.js +2 -2
  176. package/dist/http/ClusterWebSocketConfigurator.js.map +1 -1
  177. package/dist/http/PodRoutingHttpHandler.js +2 -2
  178. package/dist/http/PodRoutingHttpHandler.js.map +1 -1
  179. package/dist/http/cluster/PodMigrationHttpHandler.d.ts +1 -1
  180. package/dist/http/cluster/PodMigrationHttpHandler.js +1 -1
  181. package/dist/http/cluster/PodMigrationHttpHandler.js.map +1 -1
  182. package/dist/identity/drizzle/EdgeNodeRepository.d.ts +37 -4
  183. package/dist/identity/drizzle/EdgeNodeRepository.js +120 -128
  184. package/dist/identity/drizzle/EdgeNodeRepository.js.map +1 -1
  185. package/dist/identity/drizzle/ServiceTokenRepository.d.ts +52 -0
  186. package/dist/identity/drizzle/ServiceTokenRepository.js +142 -0
  187. package/dist/identity/drizzle/ServiceTokenRepository.js.map +1 -0
  188. package/dist/identity/drizzle/db.d.ts +9 -0
  189. package/dist/identity/drizzle/db.js +235 -3
  190. package/dist/identity/drizzle/db.js.map +1 -1
  191. package/dist/identity/drizzle/schema.pg.d.ts +5 -0
  192. package/dist/identity/drizzle/schema.pg.js +49 -20
  193. package/dist/identity/drizzle/schema.pg.js.map +1 -1
  194. package/dist/identity/drizzle/schema.sqlite.d.ts +332 -57
  195. package/dist/identity/drizzle/schema.sqlite.js +48 -18
  196. package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
  197. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js +6 -4
  198. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js.map +1 -1
  199. package/dist/index.d.ts +6 -9
  200. package/dist/index.js +12 -14
  201. package/dist/index.js.map +1 -1
  202. package/dist/main.js +25 -8
  203. package/dist/main.js.map +1 -1
  204. package/dist/provision/ProvisionCodeCodec.d.ts +39 -0
  205. package/dist/provision/ProvisionCodeCodec.js +65 -0
  206. package/dist/provision/ProvisionCodeCodec.js.map +1 -0
  207. package/dist/provision/ProvisionCodeCodec.jsonld +47 -0
  208. package/dist/provision/ProvisionPodCreator.d.ts +20 -0
  209. package/dist/provision/ProvisionPodCreator.js +84 -0
  210. package/dist/provision/ProvisionPodCreator.js.map +1 -0
  211. package/dist/provision/ProvisionPodCreator.jsonld +118 -0
  212. package/dist/quota/DrizzleQuotaService.d.ts +17 -3
  213. package/dist/quota/DrizzleQuotaService.js +108 -8
  214. package/dist/quota/DrizzleQuotaService.js.map +1 -1
  215. package/dist/quota/DrizzleQuotaService.jsonld +33 -22
  216. package/dist/quota/NoopQuotaService.d.ts +7 -1
  217. package/dist/quota/NoopQuotaService.js +12 -0
  218. package/dist/quota/NoopQuotaService.js.map +1 -1
  219. package/dist/quota/NoopQuotaService.jsonld +24 -0
  220. package/dist/quota/QuotaService.d.ts +17 -0
  221. package/dist/quota/QuotaService.js +5 -0
  222. package/dist/quota/QuotaService.js.map +1 -1
  223. package/dist/quota/QuotaService.jsonld +50 -0
  224. package/dist/runtime/Proxy.d.ts +22 -4
  225. package/dist/runtime/Proxy.js +154 -35
  226. package/dist/runtime/Proxy.js.map +1 -1
  227. package/dist/runtime/XpodRuntime.d.ts +49 -0
  228. package/dist/runtime/XpodRuntime.js +374 -0
  229. package/dist/runtime/XpodRuntime.js.map +1 -0
  230. package/dist/runtime/env-utils.d.ts +2 -0
  231. package/dist/runtime/env-utils.js +55 -0
  232. package/dist/runtime/env-utils.js.map +1 -0
  233. package/dist/runtime/index.d.ts +4 -0
  234. package/dist/runtime/index.js +8 -1
  235. package/dist/runtime/index.js.map +1 -1
  236. package/dist/runtime/socket-fetch.d.ts +1 -0
  237. package/dist/runtime/socket-fetch.js +72 -0
  238. package/dist/runtime/socket-fetch.js.map +1 -0
  239. package/dist/runtime/socket-http.d.ts +1 -0
  240. package/dist/runtime/socket-http.js +142 -0
  241. package/dist/runtime/socket-http.js.map +1 -0
  242. package/dist/runtime/socket-utils.d.ts +2 -0
  243. package/dist/runtime/socket-utils.js +34 -0
  244. package/dist/runtime/socket-utils.js.map +1 -0
  245. package/dist/service/{EdgeNodeHeartbeatService.d.ts → EdgeNodeSignalClient.d.ts} +3 -3
  246. package/dist/service/{EdgeNodeHeartbeatService.js → EdgeNodeSignalClient.js} +4 -4
  247. package/dist/service/EdgeNodeSignalClient.js.map +1 -0
  248. package/dist/service/PodMigrationService.d.ts +1 -2
  249. package/dist/service/PodMigrationService.js +1 -2
  250. package/dist/service/PodMigrationService.js.map +1 -1
  251. package/dist/storage/SparqlUpdateResourceStore.js +1 -1
  252. package/dist/storage/SparqlUpdateResourceStore.js.map +1 -1
  253. package/dist/storage/accessors/MinioDataAccessor.d.ts +6 -0
  254. package/dist/storage/accessors/MinioDataAccessor.js +10 -0
  255. package/dist/storage/accessors/MinioDataAccessor.js.map +1 -1
  256. package/dist/storage/accessors/MinioDataAccessor.jsonld +4 -0
  257. package/dist/storage/accessors/MixDataAccessor.d.ts +2 -1
  258. package/dist/storage/accessors/MixDataAccessor.js +12 -1
  259. package/dist/storage/accessors/MixDataAccessor.js.map +1 -1
  260. package/dist/storage/accessors/MixDataAccessor.jsonld +19 -0
  261. package/dist/storage/locking/UrlAwareRedisLocker.d.ts +18 -0
  262. package/dist/storage/locking/UrlAwareRedisLocker.js +60 -0
  263. package/dist/storage/locking/UrlAwareRedisLocker.js.map +1 -0
  264. package/dist/storage/locking/UrlAwareRedisLocker.jsonld +123 -0
  265. package/dist/storage/quota/UsageRepository.d.ts +41 -8
  266. package/dist/storage/quota/UsageRepository.js +252 -50
  267. package/dist/storage/quota/UsageRepository.js.map +1 -1
  268. package/dist/storage/sparql/ComunicaQuintEngine.d.ts +9 -0
  269. package/dist/storage/sparql/ComunicaQuintEngine.js +50 -9
  270. package/dist/storage/sparql/ComunicaQuintEngine.js.map +1 -1
  271. package/dist/storage/sparql/QueryOptimizer.js +13 -1
  272. package/dist/storage/sparql/QueryOptimizer.js.map +1 -1
  273. package/dist/storage/sparql/QuintQuerySource.d.ts +14 -0
  274. package/dist/storage/sparql/QuintQuerySource.js +152 -1
  275. package/dist/storage/sparql/QuintQuerySource.js.map +1 -1
  276. package/dist/storage/sparql/SubgraphQueryEngine.d.ts +1 -0
  277. package/dist/storage/sparql/SubgraphQueryEngine.js +6 -2
  278. package/dist/storage/sparql/SubgraphQueryEngine.js.map +1 -1
  279. package/dist/storage/sparql/SubgraphQueryEngine.jsonld +4 -0
  280. package/dist/subdomain/SubdomainClient.d.ts +3 -3
  281. package/dist/subdomain/SubdomainClient.js +1 -1
  282. package/dist/subdomain/SubdomainClient.js.map +1 -1
  283. package/dist/subdomain/SubdomainService.d.ts +15 -16
  284. package/dist/subdomain/SubdomainService.js +80 -54
  285. package/dist/subdomain/SubdomainService.js.map +1 -1
  286. package/dist/subdomain/SubdomainService.jsonld +22 -26
  287. package/dist/supervisor/Supervisor.d.ts +7 -2
  288. package/dist/supervisor/Supervisor.js +33 -1
  289. package/dist/supervisor/Supervisor.js.map +1 -1
  290. package/dist/task/DrizzleTaskQueue.d.ts +1 -1
  291. package/dist/task/DrizzleTaskQueue.js +1 -1
  292. package/dist/task/DrizzleTaskQueue.js.map +1 -1
  293. package/dist/task/schema.d.ts +10 -10
  294. package/dist/task/schema.js +1 -1
  295. package/dist/task/schema.js.map +1 -1
  296. package/dist/test-utils/index.d.ts +4 -0
  297. package/dist/test-utils/index.js +8 -0
  298. package/dist/test-utils/index.js.map +1 -0
  299. package/dist/test-utils/no-auth-xpod.d.ts +11 -0
  300. package/dist/test-utils/no-auth-xpod.js +25 -0
  301. package/dist/test-utils/no-auth-xpod.js.map +1 -0
  302. package/dist/test-utils/seed-pod.d.ts +5 -0
  303. package/dist/test-utils/seed-pod.js +61 -0
  304. package/dist/test-utils/seed-pod.js.map +1 -0
  305. package/package.json +38 -10
  306. package/templates/identity/account/create-pod.html.ejs +110 -0
  307. package/templates/main.html.ejs +10 -0
  308. package/dist/api/handlers/DevHandler.d.ts +0 -18
  309. package/dist/api/handlers/DevHandler.js +0 -276
  310. package/dist/api/handlers/DevHandler.js.map +0 -1
  311. package/dist/api/handlers/SignalHandler.d.ts +0 -13
  312. package/dist/api/handlers/SignalHandler.js +0 -122
  313. package/dist/api/handlers/SignalHandler.js.map +0 -1
  314. package/dist/gateway/Proxy.d.ts +0 -24
  315. package/dist/gateway/Proxy.js +0 -209
  316. package/dist/gateway/Proxy.js.map +0 -1
  317. package/dist/gateway/Supervisor.d.ts +0 -2
  318. package/dist/gateway/Supervisor.js +0 -7
  319. package/dist/gateway/Supervisor.js.map +0 -1
  320. package/dist/gateway/port-finder.d.ts +0 -4
  321. package/dist/gateway/port-finder.js +0 -15
  322. package/dist/gateway/port-finder.js.map +0 -1
  323. package/dist/gateway/types.d.ts +0 -1
  324. package/dist/gateway/types.js +0 -3
  325. package/dist/gateway/types.js.map +0 -1
  326. package/dist/http/SignalInterceptHttpHandler.d.ts +0 -24
  327. package/dist/http/SignalInterceptHttpHandler.js +0 -47
  328. package/dist/http/SignalInterceptHttpHandler.js.map +0 -1
  329. package/dist/http/SignalInterceptHttpHandler.jsonld +0 -103
  330. package/dist/http/admin/EdgeNodeSignalHttpHandler.d.ts +0 -71
  331. package/dist/http/admin/EdgeNodeSignalHttpHandler.js +0 -674
  332. package/dist/http/admin/EdgeNodeSignalHttpHandler.js.map +0 -1
  333. package/dist/http/admin/EdgeNodeSignalHttpHandler.jsonld +0 -406
  334. package/dist/http/cluster/PodMigrationHttpHandler.jsonld +0 -169
  335. package/dist/quota/DefaultQuotaService.d.ts +0 -16
  336. package/dist/quota/DefaultQuotaService.js +0 -37
  337. package/dist/quota/DefaultQuotaService.js.map +0 -1
  338. package/dist/quota/DefaultQuotaService.jsonld +0 -85
  339. package/dist/service/EdgeNodeHeartbeatService.js.map +0 -1
  340. package/dist/service/PodMigrationService.jsonld +0 -76
  341. package/dist/storage/MigratableDataAccessor.d.ts +0 -63
  342. package/dist/storage/MigratableDataAccessor.js +0 -11
  343. package/dist/storage/MigratableDataAccessor.js.map +0 -1
  344. package/dist/storage/MigratableDataAccessor.jsonld +0 -60
  345. package/dist/storage/accessors/TieredMinioDataAccessor.d.ts +0 -150
  346. package/dist/storage/accessors/TieredMinioDataAccessor.js +0 -582
  347. package/dist/storage/accessors/TieredMinioDataAccessor.js.map +0 -1
  348. package/dist/storage/accessors/TieredMinioDataAccessor.jsonld +0 -333
  349. package/static/app/assets/index.css +0 -1
  350. package/static/app/assets/main.js +0 -11
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/api/container/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * API Container 入口\n *\n * 使用 Awilix 进行依赖注入,根据 edition 注册不同服务\n */\n\nimport { createContainer, asValue, InjectionMode, type AwilixContainer } from 'awilix';\nimport type { ApiContainerCradle, ApiContainerConfig } from './types';\nimport { registerCommonServices } from './common';\nimport { registerCloudServices } from './cloud';\nimport { registerLocalServices } from './local';\n\nexport type { ApiContainerCradle, ApiContainerConfig } from './types';\n\nfunction ensureTrailingSlash(url: string): string {\n return url.endsWith('/') ? url : `${url}/`;\n}\n\nfunction resolveCssTokenEndpoint(): string {\n if (process.env.CSS_TOKEN_ENDPOINT) {\n return process.env.CSS_TOKEN_ENDPOINT;\n }\n\n if (process.env.CSS_BASE_URL) {\n return `${ensureTrailingSlash(process.env.CSS_BASE_URL)}.oidc/token`;\n }\n\n return 'http://localhost:3000/.oidc/token';\n}\n\n/**\n * 创建 API 容器\n */\nexport function createApiContainer(config: ApiContainerConfig): AwilixContainer<ApiContainerCradle> {\n const container = createContainer<ApiContainerCradle>({\n injectionMode: InjectionMode.PROXY,\n strict: true,\n });\n\n // 注册配置\n container.register({\n config: asValue(config),\n });\n\n // 注册共享服务\n registerCommonServices(container);\n\n // 根据 edition 注册专属服务\n if (config.edition === 'cloud') {\n registerCloudServices(container);\n } else {\n registerLocalServices(container);\n }\n\n return container;\n}\n\n/**\n * 从环境变量读取配置\n */\nexport function loadConfigFromEnv(): ApiContainerConfig {\n const edition = (process.env.XPOD_EDITION ?? 'local') as 'cloud' | 'local';\n\n // Port auto-increment: API_PORT = CSS_PORT + 1 if not explicitly set\n const cssPort = parseInt(process.env.CSS_PORT ?? '3000', 10);\n const apiPort = process.env.API_PORT\n ? parseInt(process.env.API_PORT, 10)\n : cssPort + 1;\n\n return {\n edition,\n port: apiPort,\n host: process.env.API_HOST ?? '0.0.0.0',\n databaseUrl: process.env.CSS_IDENTITY_DB_URL ?? process.env.DATABASE_URL ?? '',\n corsOrigins: process.env.CORS_ORIGINS?.split(',').map(s => s.trim()) ?? ['*'],\n encryptionKey: process.env.XPOD_ENCRYPTION_KEY ?? 'default-dev-key-change-me',\n cssTokenEndpoint: resolveCssTokenEndpoint(),\n\n // 子域名配置 (cloud 模式)\n subdomain: {\n enabled: process.env.XPOD_SUBDOMAIN_ENABLED === 'true',\n baseDomain: ((): string | undefined => {\n if (!process.env.CSS_BASE_URL) return undefined;\n try {\n return new URL(process.env.CSS_BASE_URL).hostname;\n } catch {\n return undefined;\n }\n })(),\n ddnsDomain: process.env.XPOD_DDNS_DOMAIN || 'undefineds.xyz',\n cloudflareAccountId: process.env.CLOUDFLARE_ACCOUNT_ID,\n cloudflareApiToken: process.env.CLOUDFLARE_API_TOKEN,\n tencentDnsSecretId: process.env.TENCENT_DNS_SECRET_ID,\n tencentDnsSecretKey: process.env.TENCENT_DNS_SECRET_KEY,\n },\n\n // Local 托管式:连接 Cloud\n cloudApiEndpoint: process.env.XPOD_CLOUD_API_ENDPOINT,\n nodeId: process.env.XPOD_NODE_ID,\n nodeToken: process.env.XPOD_NODE_TOKEN,\n\n // OIDC Issuer (Local 托管式使用 Cloud IdP)\n // 如果配置了 XPOD_NODE_TOKEN,默认使用 Cloud IdP\n oidcIssuer: process.env.XPOD_OIDC_ISSUER ?? process.env.CSS_OIDC_ISSUER ?? (\n process.env.XPOD_NODE_TOKEN\n ? (process.env.XPOD_CLOUD_API_ENDPOINT ?? 'https://id.undefineds.co')\n : undefined\n ),\n\n // 隧道配置\n cloudflareTunnelToken: process.env.CLOUDFLARE_TUNNEL_TOKEN,\n // Prefer SAKURA_TUNNEL_TOKEN; keep SAKURA_TOKEN for backward compatibility.\n sakuraTunnelToken: process.env.SAKURA_TUNNEL_TOKEN ?? process.env.SAKURA_TOKEN,\n\n // Edge 节点管理 (cloud 模式)\n edgeNodesEnabled: process.env.XPOD_EDGE_NODES_ENABLED === 'true',\n };\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/api/container/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * API Container 入口\n *\n * 使用 Awilix 进行依赖注入,根据 edition 注册不同服务\n */\n\nimport { createContainer, asValue, InjectionMode, type AwilixContainer } from 'awilix';\nimport { randomUUID, createHash } from 'node:crypto';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { ApiContainerCradle, ApiContainerConfig } from './types';\nimport { registerCommonServices } from './common';\nimport { registerCloudServices } from './cloud';\nimport { registerLocalServices } from './local';\nimport { registerBusinessToken } from './business-token';\n\nexport type { ApiContainerCradle, ApiContainerConfig } from './types';\n\nfunction ensureTrailingSlash(url: string): string {\n return url.endsWith('/') ? url : `${url}/`;\n}\n\nfunction resolveCssTokenEndpoint(): string {\n if (process.env.CSS_TOKEN_ENDPOINT) {\n return process.env.CSS_TOKEN_ENDPOINT;\n }\n\n if (process.env.CSS_BASE_URL) {\n return `${ensureTrailingSlash(process.env.CSS_BASE_URL)}.oidc/token`;\n }\n\n return 'http://localhost:3000/.oidc/token';\n}\n\n/**\n * 创建 API 容器\n */\nexport function createApiContainer(config: ApiContainerConfig): AwilixContainer<ApiContainerCradle> {\n const container = createContainer<ApiContainerCradle>({\n injectionMode: InjectionMode.PROXY,\n strict: true,\n });\n\n // 注册配置\n container.register({\n config: asValue(config),\n });\n\n // 注册共享服务\n registerCommonServices(container);\n\n // 根据 edition 注册专属服务\n if (config.edition === 'cloud') {\n registerCloudServices(container);\n } else {\n registerLocalServices(container);\n }\n\n // 注册 Business Token (如果配置了 XPOD_BUSINESS_TOKEN)\n registerBusinessToken(container);\n\n return container;\n}\n\n/**\n * 从环境变量读取配置\n */\nexport function loadConfigFromEnv(): ApiContainerConfig {\n const edition = (process.env.XPOD_EDITION ?? 'local') as 'cloud' | 'local';\n\n // Port auto-increment: API_PORT = CSS_PORT + 1 if not explicitly set\n const cssPort = parseInt(process.env.CSS_PORT ?? '3000', 10);\n const apiPort = process.env.API_PORT\n ? parseInt(process.env.API_PORT, 10)\n : cssPort + 1;\n\n return {\n edition,\n port: apiPort,\n host: process.env.API_HOST ?? '0.0.0.0',\n socketPath: process.env.API_SOCKET_PATH,\n databaseUrl: process.env.CSS_IDENTITY_DB_URL ?? process.env.DATABASE_URL ?? '',\n corsOrigins: process.env.CORS_ORIGINS?.split(',').map(s => s.trim()) ?? ['*'],\n cssTokenEndpoint: resolveCssTokenEndpoint(),\n\n // 子域名配置 (cloud 模式)\n subdomain: {\n baseStorageDomain: process.env.CSS_BASE_STORAGE_DOMAIN,\n cloudflareAccountId: process.env.CLOUDFLARE_ACCOUNT_ID,\n cloudflareApiToken: process.env.CLOUDFLARE_API_TOKEN,\n tencentDnsSecretId: process.env.TENCENT_DNS_SECRET_ID,\n tencentDnsSecretKey: process.env.TENCENT_DNS_SECRET_KEY,\n },\n\n // Local 托管式:连接 Cloud\n cloudApiEndpoint: process.env.XPOD_CLOUD_API_ENDPOINT,\n nodeId: loadOrGenerateDeviceId(process.env.XPOD_NODE_ID),\n nodeToken: process.env.XPOD_NODE_TOKEN,\n\n // OIDC Issuer (Local 托管式使用 Cloud IdP)\n // 如果配置了 XPOD_NODE_TOKEN,默认使用 Cloud IdP\n oidcIssuer: process.env.XPOD_OIDC_ISSUER ?? process.env.CSS_OIDC_ISSUER ?? (\n process.env.XPOD_NODE_TOKEN\n ? (process.env.XPOD_CLOUD_API_ENDPOINT ?? 'https://id.undefineds.co')\n : undefined\n ),\n\n // 隧道配置\n cloudflareTunnelToken: process.env.CLOUDFLARE_TUNNEL_TOKEN,\n // Prefer SAKURA_TUNNEL_TOKEN; keep SAKURA_TOKEN for backward compatibility.\n sakuraTunnelToken: process.env.SAKURA_TUNNEL_TOKEN ?? process.env.SAKURA_TOKEN,\n\n // Edge 节点管理 (cloud 模式)\n edgeNodesEnabled: process.env.XPOD_EDGE_NODES_ENABLED === 'true',\n };\n}\n\n/**\n * 获取设备首个非内部网卡的 MAC 地址。\n * 返回小写冒号分隔格式,如 \"aa:bb:cc:dd:ee:ff\"。\n * 容器/虚拟机中可能拿不到稳定 MAC,此时返回 undefined。\n */\nfunction getFirstMacAddress(): string | undefined {\n const interfaces = os.networkInterfaces();\n for (const name of Object.keys(interfaces)) {\n for (const iface of interfaces[name] ?? []) {\n if (!iface.internal && iface.mac && iface.mac !== '00:00:00:00:00:00') {\n return iface.mac.toLowerCase();\n }\n }\n }\n return undefined;\n}\n\n/**\n * 读取或生成设备 ID(持久化到 data/.device-id)。\n *\n * 优先级:\n * 1. 环境变量 XPOD_NODE_ID\n * 2. 已持久化的 data/.device-id\n * 3. 基于 MAC 地址的 SHA-256 哈希(截取前 32 位 hex)\n * 4. 随机 UUID(容器/虚拟机无稳定 MAC 时兜底)\n *\n * 生成后写入 data/.device-id,后续启动直接读取,保证同一设备 ID 稳定。\n */\nfunction loadOrGenerateDeviceId(envNodeId?: string): string | undefined {\n if (envNodeId) {\n return envNodeId;\n }\n\n const rootDir = process.env.CSS_ROOT_FILE_PATH || './data';\n const deviceIdPath = path.join(rootDir, '.device-id');\n\n // 尝试从文件读取\n try {\n if (fs.existsSync(deviceIdPath)) {\n const content = fs.readFileSync(deviceIdPath, 'utf-8').trim();\n if (content) {\n return content;\n }\n }\n } catch {\n // 读取失败,继续生成\n }\n\n // 优先用 MAC 哈希,拿不到则 UUID 兜底\n const mac = getFirstMacAddress();\n const deviceId = mac\n ? createHash('sha256').update(mac).digest('hex').slice(0, 32)\n : randomUUID();\n\n try {\n if (!fs.existsSync(rootDir)) {\n fs.mkdirSync(rootDir, { recursive: true });\n }\n fs.writeFileSync(deviceIdPath, deviceId, 'utf-8');\n } catch {\n // 写入失败不阻塞启动\n }\n\n return deviceId;\n}\n"]}
@@ -96,7 +96,7 @@ function registerLocalServices(container) {
96
96
  });
97
97
  }).singleton(),
98
98
  // Subdomain Service (Keep for API support)
99
- subdomainService: (0, awilix_1.asFunction)(({ dnsProvider, localTunnelProvider }) => {
99
+ subdomainService: (0, awilix_1.asFunction)(({ dnsProvider, localTunnelProvider, nodeRepo }) => {
100
100
  // 如果没有配置 Tunnel Token,使用一个 Mock Provider
101
101
  const tunnelProvider = localTunnelProvider ?? {
102
102
  name: 'noop',
@@ -111,6 +111,7 @@ function registerLocalServices(container) {
111
111
  baseDomain: baseDomain,
112
112
  dnsProvider: dnsProvider,
113
113
  tunnelProvider,
114
+ edgeNodeRepo: nodeRepo,
114
115
  });
115
116
  }).singleton(),
116
117
  });
@@ -1 +1 @@
1
- {"version":3,"file":"local.js","sourceRoot":"","sources":["../../../src/api/container/local.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Local 模式服务注册\n *\n * Local 模式有两种配置:\n * - 托管式 (managed): 配置 XPOD_NODE_TOKEN,自动连接 Cloud 获取身份服务和 DDNS\n * - 独立式 (standalone): 不配置 XPOD_NODE_TOKEN,用户自己配置 CSS_BASE_URL 和 IdP\n */\n\nimport { asFunction, type AwilixContainer } from 'awilix';\nimport type { ApiContainerCradle, ApiContainerConfig } from './types';\n\nimport { SubdomainClient } from '../../subdomain/SubdomainClient';\nimport { LocalTunnelProvider } from '../../tunnel/LocalTunnelProvider';\nimport { SakuraFrpTunnelProvider } from '../../tunnel/SakuraFrpTunnelProvider';\nimport { CloudflareDnsProvider } from '../../dns/cloudflare/CloudflareDnsProvider';\nimport { SubdomainService } from '../../subdomain/SubdomainService';\nimport { EdgeNodeDnsCoordinator } from '../../edge/EdgeNodeDnsCoordinator';\nimport { EdgeNodeCapabilityDetector } from '../../edge/EdgeNodeCapabilityDetector';\nimport { LocalNetworkManager } from '../../edge/LocalNetworkManager';\nimport { DdnsManager } from '../../edge/DdnsManager';\nimport type { TunnelProvider, TunnelStatus } from '../../tunnel/TunnelProvider';\n\n/**\n * 注册 Local 模式专属服务\n */\nexport function registerLocalServices(\n container: AwilixContainer<ApiContainerCradle>,\n): void {\n const config = container.resolve('config') as ApiContainerConfig;\n\n const {\n cloudApiEndpoint,\n nodeId,\n nodeToken,\n cloudflareTunnelToken,\n sakuraTunnelToken,\n subdomain: subdomainConfig,\n } = config;\n\n // 1. 注册 Tunnel Provider (优先 Cloudflare,其次 SakuraFRP)\n if (cloudflareTunnelToken) {\n container.register({\n localTunnelProvider: asFunction(() => {\n return new LocalTunnelProvider({\n tunnelToken: cloudflareTunnelToken,\n });\n }).singleton(),\n });\n console.log('[Local] Tunnel provider registered (CLOUDFLARE_TUNNEL_TOKEN configured)');\n } else if (sakuraTunnelToken) {\n container.register({\n localTunnelProvider: asFunction(() => {\n return new SakuraFrpTunnelProvider({\n token: sakuraTunnelToken,\n });\n }).singleton(),\n });\n console.log('[Local] Tunnel provider registered (SAKURA_TUNNEL_TOKEN configured)');\n }\n\n // 2. 自适应 DNS 管理 (Self-Hosted DNS)\n // 如果配置了 Cloudflare API Token 和 Base Domain,启用本地 DNS 管理\n const apiToken = subdomainConfig?.cloudflareApiToken;\n\n // 在 Local 模式下,强制使用 CSS_BASE_URL 作为域名来源\n // 简化用户配置心智\n let baseDomain: string | undefined;\n if (process.env.CSS_BASE_URL) {\n try {\n const url = new URL(process.env.CSS_BASE_URL);\n baseDomain = url.hostname;\n } catch {\n console.warn('[Local] Invalid CSS_BASE_URL, cannot derive domain for DNS management');\n }\n }\n\n // DEBUG: 打印变量状态\n console.log(`[Local] Debug: apiToken=${apiToken ? '***' : 'undefined'}, baseDomain=${baseDomain}, CSS_BASE_URL=${process.env.CSS_BASE_URL}`);\n\n if (apiToken && baseDomain) {\n console.log('[Local] Self-hosted DNS mode detected (IPv6 Ready)');\n\n container.register({\n // DNS Provider\n dnsProvider: asFunction(() => {\n return new CloudflareDnsProvider({\n apiToken: apiToken!,\n });\n }).singleton(),\n\n // DNS Coordinator (DnsMaintainer)\n dnsCoordinator: asFunction(({ dnsProvider }: ApiContainerCradle) => {\n return new EdgeNodeDnsCoordinator({\n provider: dnsProvider!,\n rootDomain: baseDomain,\n });\n }).singleton(),\n\n // Network Detector\n capabilityDetector: asFunction(() => {\n return new EdgeNodeCapabilityDetector({\n dynamicDetection: { enableNetworkDetection: true },\n });\n }).singleton(),\n\n // Local Network Manager (Orchestrator)\n localNetworkManager: asFunction(({ capabilityDetector, dnsCoordinator, localTunnelProvider }: ApiContainerCradle) => {\n // Tunnel 应该指向 Gateway 端口 (通常是 3000),而不是 API Server 端口 (3004)\n const mainPort = parseInt(process.env.XPOD_MAIN_PORT || '3000', 10);\n return new LocalNetworkManager({\n detector: capabilityDetector!,\n dnsCoordinator: dnsCoordinator!,\n tunnelProvider: localTunnelProvider,\n localPort: mainPort,\n });\n }).singleton(),\n\n // Subdomain Service (Keep for API support)\n subdomainService: asFunction(({ dnsProvider, localTunnelProvider }: ApiContainerCradle) => {\n // 如果没有配置 Tunnel Token,使用一个 Mock Provider\n const tunnelProvider = localTunnelProvider ?? {\n name: 'noop',\n setup: async () => { throw new Error('Tunnel not configured'); },\n start: async () => { throw new Error('Tunnel not configured'); },\n stop: async () => {},\n cleanup: async () => {},\n getStatus: () => ({ running: false, connected: false } as TunnelStatus),\n getEndpoint: () => undefined,\n } as TunnelProvider;\n\n return new SubdomainService({\n baseDomain: baseDomain!,\n dnsProvider: dnsProvider!,\n tunnelProvider,\n });\n }).singleton(),\n });\n console.log(`[Local] Local DNS maintenance services registered for: ${baseDomain}`);\n // 继续进行后续逻辑,不要 return,因为用户可能既用了自管 DNS 又开启了 Managed Client\n }\n\n // 独立式:没有配置 Node Token,用户自己管理域名和 IdP\n if (!nodeToken) {\n console.log('[Local] Standalone mode (no XPOD_NODE_TOKEN)');\n console.log('[Local] User manages DNS and IdP externally');\n if (cloudflareTunnelToken) {\n console.log('[Local] Will start cloudflared with provided CLOUDFLARE_TUNNEL_TOKEN');\n }\n return;\n }\n\n // 托管式:有 Node Token,连接 Cloud\n // Cloud API endpoint 可以从 Token 解析或使用默认值\n const effectiveCloudApiEndpoint = cloudApiEndpoint || 'https://pods.undefineds.co';\n\n // 从 Node Token 解析用户名作为子域名 (格式: username:secret)\n const subdomain = parseSubdomainFromToken(nodeToken);\n\n container.register({\n subdomainClient: asFunction(() => {\n return new SubdomainClient({\n cloudApiEndpoint: effectiveCloudApiEndpoint,\n nodeId: nodeId || 'auto', // 可以从 Token 解析\n nodeToken: nodeToken!,\n });\n }).singleton(),\n\n // 注册网络检测器 (如果尚未注册)\n capabilityDetector: asFunction(() => {\n return new EdgeNodeCapabilityDetector({\n dynamicDetection: { enableNetworkDetection: true },\n });\n }).singleton(),\n\n // DDNS Manager: 自动分配和更新 DDNS\n ddnsManager: asFunction(({ subdomainClient, capabilityDetector }: ApiContainerCradle) => {\n return new DdnsManager({\n client: subdomainClient!,\n detector: capabilityDetector!,\n subdomain: subdomain || nodeId || 'auto',\n autoAllocate: true,\n });\n }).singleton(),\n });\n\n console.log('[Local] Managed mode, SubdomainClient and DdnsManager registered');\n console.log(`[Local] Cloud API endpoint: ${effectiveCloudApiEndpoint}`);\n if (subdomain) {\n console.log(`[Local] DDNS subdomain: ${subdomain}`);\n }\n if (config.oidcIssuer) {\n console.log(`[Local] Using Cloud IdP: ${config.oidcIssuer}`);\n }\n\n if (!cloudflareTunnelToken && !sakuraTunnelToken) {\n console.log('[Local] Note: No tunnel token configured, assuming direct network access');\n }\n}\n\n/**\n * 从 Node Token 解析子域名/用户名\n * Token 格式: username:secret 或 base64 编码\n */\nfunction parseSubdomainFromToken(token: string): string | undefined {\n // 尝试直接解析 username:secret 格式\n if (token.includes(':')) {\n const [username] = token.split(':');\n if (username && /^[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/.test(username)) {\n return username;\n }\n }\n\n // 尝试 base64 解码\n try {\n const decoded = Buffer.from(token, 'base64').toString('utf8');\n if (decoded.includes(':')) {\n const [username] = decoded.split(':');\n if (username && /^[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/.test(username)) {\n return username;\n }\n }\n } catch {\n // ignore\n }\n\n return undefined;\n}\n"]}
1
+ {"version":3,"file":"local.js","sourceRoot":"","sources":["../../../src/api/container/local.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAmBH,sDA6KC;AA9LD,mCAA0D;AAG1D,qEAAkE;AAClE,0EAAuE;AACvE,kFAA+E;AAC/E,sFAAmF;AACnF,uEAAoE;AACpE,8EAA2E;AAC3E,sFAAmF;AACnF,wEAAqE;AACrE,wDAAqD;AAGrD;;GAEG;AACH,SAAgB,qBAAqB,CACnC,SAA8C;IAE9C,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAuB,CAAC;IAEjE,MAAM,EACJ,gBAAgB,EAChB,MAAM,EACN,SAAS,EACT,qBAAqB,EACrB,iBAAiB,EACjB,SAAS,EAAE,eAAe,GAC3B,GAAG,MAAM,CAAC;IAEX,qDAAqD;IACrD,IAAI,qBAAqB,EAAE,CAAC;QAC1B,SAAS,CAAC,QAAQ,CAAC;YACjB,mBAAmB,EAAE,IAAA,mBAAU,EAAC,GAAG,EAAE;gBACnC,OAAO,IAAI,yCAAmB,CAAC;oBAC7B,WAAW,EAAE,qBAAqB;iBACnC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC,SAAS,EAAE;SACf,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAC;IACzF,CAAC;SAAM,IAAI,iBAAiB,EAAE,CAAC;QAC7B,SAAS,CAAC,QAAQ,CAAC;YACjB,mBAAmB,EAAE,IAAA,mBAAU,EAAC,GAAG,EAAE;gBACnC,OAAO,IAAI,iDAAuB,CAAC;oBACjC,KAAK,EAAE,iBAAiB;iBACzB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC,SAAS,EAAE;SACf,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAC;IACrF,CAAC;IAED,kCAAkC;IAClC,uDAAuD;IACvD,MAAM,QAAQ,GAAG,eAAe,EAAE,kBAAkB,CAAC;IAErD,uCAAuC;IACvC,WAAW;IACX,IAAI,UAA8B,CAAC;IACnC,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAC9C,UAAU,GAAG,GAAG,CAAC,QAAQ,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,uEAAuE,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IAED,gBAAgB;IAChB,OAAO,CAAC,GAAG,CAAC,2BAA2B,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,gBAAgB,UAAU,kBAAkB,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;IAE7I,IAAI,QAAQ,IAAI,UAAU,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;QAElE,SAAS,CAAC,QAAQ,CAAC;YACjB,eAAe;YACf,WAAW,EAAE,IAAA,mBAAU,EAAC,GAAG,EAAE;gBAC3B,OAAO,IAAI,6CAAqB,CAAC;oBAC/B,QAAQ,EAAE,QAAS;iBACpB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC,SAAS,EAAE;YAEd,kCAAkC;YAClC,cAAc,EAAE,IAAA,mBAAU,EAAC,CAAC,EAAE,WAAW,EAAsB,EAAE,EAAE;gBACjE,OAAO,IAAI,+CAAsB,CAAC;oBAChC,QAAQ,EAAE,WAAY;oBACtB,UAAU,EAAE,UAAU;iBACvB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC,SAAS,EAAE;YAEd,mBAAmB;YACnB,kBAAkB,EAAE,IAAA,mBAAU,EAAC,GAAG,EAAE;gBAClC,OAAO,IAAI,uDAA0B,CAAC;oBACpC,gBAAgB,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAE;iBACnD,CAAC,CAAC;YACL,CAAC,CAAC,CAAC,SAAS,EAAE;YAEd,uCAAuC;YACvC,mBAAmB,EAAE,IAAA,mBAAU,EAAC,CAAC,EAAE,kBAAkB,EAAE,cAAc,EAAE,mBAAmB,EAAsB,EAAE,EAAE;gBAClH,6DAA6D;gBAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;gBACpE,OAAO,IAAI,yCAAmB,CAAC;oBAC7B,QAAQ,EAAE,kBAAmB;oBAC7B,cAAc,EAAE,cAAe;oBAC/B,cAAc,EAAE,mBAAmB;oBACnC,SAAS,EAAE,QAAQ;iBACpB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC,SAAS,EAAE;YAEd,2CAA2C;YAC3C,gBAAgB,EAAE,IAAA,mBAAU,EAAC,CAAC,EAAE,WAAW,EAAE,mBAAmB,EAAE,QAAQ,EAAsB,EAAE,EAAE;gBAClG,yCAAyC;gBACzC,MAAM,cAAc,GAAG,mBAAmB,IAAI;oBAC5C,IAAI,EAAE,MAAM;oBACZ,KAAK,EAAE,KAAK,IAAI,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;oBAChE,KAAK,EAAE,KAAK,IAAI,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;oBAChE,IAAI,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;oBACpB,OAAO,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;oBACvB,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAmB,CAAA;oBACvE,WAAW,EAAE,GAAG,EAAE,CAAC,SAAS;iBACX,CAAC;gBAEpB,OAAO,IAAI,mCAAgB,CAAC;oBAC1B,UAAU,EAAE,UAAW;oBACvB,WAAW,EAAE,WAAY;oBACzB,cAAc;oBACd,YAAY,EAAE,QAAQ;iBACvB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC,SAAS,EAAE;SACf,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,0DAA0D,UAAU,EAAE,CAAC,CAAC;QACpF,yDAAyD;IAC3D,CAAC;IAED,oCAAoC;IACpC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;QAC5D,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;QAC3D,IAAI,qBAAqB,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,sEAAsE,CAAC,CAAC;QACtF,CAAC;QACD,OAAO;IACT,CAAC;IAED,4BAA4B;IAC5B,wCAAwC;IACxC,MAAM,yBAAyB,GAAG,gBAAgB,IAAI,4BAA4B,CAAC;IAEnF,gDAAgD;IAChD,MAAM,SAAS,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;IAErD,SAAS,CAAC,QAAQ,CAAC;QACjB,eAAe,EAAE,IAAA,mBAAU,EAAC,GAAG,EAAE;YAC/B,OAAO,IAAI,iCAAe,CAAC;gBACzB,gBAAgB,EAAE,yBAAyB;gBAC3C,MAAM,EAAE,MAAM,IAAI,MAAM,EAAE,eAAe;gBACzC,SAAS,EAAE,SAAU;aACtB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC,SAAS,EAAE;QAEd,mBAAmB;QACnB,kBAAkB,EAAE,IAAA,mBAAU,EAAC,GAAG,EAAE;YAClC,OAAO,IAAI,uDAA0B,CAAC;gBACpC,gBAAgB,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAE;aACnD,CAAC,CAAC;QACL,CAAC,CAAC,CAAC,SAAS,EAAE;QAEd,6BAA6B;QAC7B,WAAW,EAAE,IAAA,mBAAU,EAAC,CAAC,EAAE,eAAe,EAAE,kBAAkB,EAAsB,EAAE,EAAE;YACtF,OAAO,IAAI,yBAAW,CAAC;gBACrB,MAAM,EAAE,eAAgB;gBACxB,QAAQ,EAAE,kBAAmB;gBAC7B,SAAS,EAAE,SAAS,IAAI,MAAM,IAAI,MAAM;gBACxC,YAAY,EAAE,IAAI;aACnB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC,SAAS,EAAE;KACf,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,+BAA+B,yBAAyB,EAAE,CAAC,CAAC;IACxE,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,2BAA2B,SAAS,EAAE,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,4BAA4B,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,IAAI,CAAC,qBAAqB,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,0EAA0E,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,uBAAuB,CAAC,KAAa;IAC5C,4BAA4B;IAC5B,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,QAAQ,IAAI,mCAAmC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnE,OAAO,QAAQ,CAAC;QAClB,CAAC;IACH,CAAC;IAED,eAAe;IACf,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC9D,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACtC,IAAI,QAAQ,IAAI,mCAAmC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACnE,OAAO,QAAQ,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["/**\n * Local 模式服务注册\n *\n * Local 模式有两种配置:\n * - 托管式 (managed): 配置 XPOD_NODE_TOKEN,自动连接 Cloud 获取身份服务和 DDNS\n * - 独立式 (standalone): 不配置 XPOD_NODE_TOKEN,用户自己配置 CSS_BASE_URL 和 IdP\n */\n\nimport { asFunction, type AwilixContainer } from 'awilix';\nimport type { ApiContainerCradle, ApiContainerConfig } from './types';\n\nimport { SubdomainClient } from '../../subdomain/SubdomainClient';\nimport { LocalTunnelProvider } from '../../tunnel/LocalTunnelProvider';\nimport { SakuraFrpTunnelProvider } from '../../tunnel/SakuraFrpTunnelProvider';\nimport { CloudflareDnsProvider } from '../../dns/cloudflare/CloudflareDnsProvider';\nimport { SubdomainService } from '../../subdomain/SubdomainService';\nimport { EdgeNodeDnsCoordinator } from '../../edge/EdgeNodeDnsCoordinator';\nimport { EdgeNodeCapabilityDetector } from '../../edge/EdgeNodeCapabilityDetector';\nimport { LocalNetworkManager } from '../../edge/LocalNetworkManager';\nimport { DdnsManager } from '../../edge/DdnsManager';\nimport type { TunnelProvider, TunnelStatus } from '../../tunnel/TunnelProvider';\n\n/**\n * 注册 Local 模式专属服务\n */\nexport function registerLocalServices(\n container: AwilixContainer<ApiContainerCradle>,\n): void {\n const config = container.resolve('config') as ApiContainerConfig;\n\n const {\n cloudApiEndpoint,\n nodeId,\n nodeToken,\n cloudflareTunnelToken,\n sakuraTunnelToken,\n subdomain: subdomainConfig,\n } = config;\n\n // 1. 注册 Tunnel Provider (优先 Cloudflare,其次 SakuraFRP)\n if (cloudflareTunnelToken) {\n container.register({\n localTunnelProvider: asFunction(() => {\n return new LocalTunnelProvider({\n tunnelToken: cloudflareTunnelToken,\n });\n }).singleton(),\n });\n console.log('[Local] Tunnel provider registered (CLOUDFLARE_TUNNEL_TOKEN configured)');\n } else if (sakuraTunnelToken) {\n container.register({\n localTunnelProvider: asFunction(() => {\n return new SakuraFrpTunnelProvider({\n token: sakuraTunnelToken,\n });\n }).singleton(),\n });\n console.log('[Local] Tunnel provider registered (SAKURA_TUNNEL_TOKEN configured)');\n }\n\n // 2. 自适应 DNS 管理 (Self-Hosted DNS)\n // 如果配置了 Cloudflare API Token 和 Base Domain,启用本地 DNS 管理\n const apiToken = subdomainConfig?.cloudflareApiToken;\n\n // 在 Local 模式下,强制使用 CSS_BASE_URL 作为域名来源\n // 简化用户配置心智\n let baseDomain: string | undefined;\n if (process.env.CSS_BASE_URL) {\n try {\n const url = new URL(process.env.CSS_BASE_URL);\n baseDomain = url.hostname;\n } catch {\n console.warn('[Local] Invalid CSS_BASE_URL, cannot derive domain for DNS management');\n }\n }\n\n // DEBUG: 打印变量状态\n console.log(`[Local] Debug: apiToken=${apiToken ? '***' : 'undefined'}, baseDomain=${baseDomain}, CSS_BASE_URL=${process.env.CSS_BASE_URL}`);\n\n if (apiToken && baseDomain) {\n console.log('[Local] Self-hosted DNS mode detected (IPv6 Ready)');\n\n container.register({\n // DNS Provider\n dnsProvider: asFunction(() => {\n return new CloudflareDnsProvider({\n apiToken: apiToken!,\n });\n }).singleton(),\n\n // DNS Coordinator (DnsMaintainer)\n dnsCoordinator: asFunction(({ dnsProvider }: ApiContainerCradle) => {\n return new EdgeNodeDnsCoordinator({\n provider: dnsProvider!,\n rootDomain: baseDomain,\n });\n }).singleton(),\n\n // Network Detector\n capabilityDetector: asFunction(() => {\n return new EdgeNodeCapabilityDetector({\n dynamicDetection: { enableNetworkDetection: true },\n });\n }).singleton(),\n\n // Local Network Manager (Orchestrator)\n localNetworkManager: asFunction(({ capabilityDetector, dnsCoordinator, localTunnelProvider }: ApiContainerCradle) => {\n // Tunnel 应该指向 Gateway 端口 (通常是 3000),而不是 API Server 端口 (3004)\n const mainPort = parseInt(process.env.XPOD_MAIN_PORT || '3000', 10);\n return new LocalNetworkManager({\n detector: capabilityDetector!,\n dnsCoordinator: dnsCoordinator!,\n tunnelProvider: localTunnelProvider,\n localPort: mainPort,\n });\n }).singleton(),\n\n // Subdomain Service (Keep for API support)\n subdomainService: asFunction(({ dnsProvider, localTunnelProvider, nodeRepo }: ApiContainerCradle) => {\n // 如果没有配置 Tunnel Token,使用一个 Mock Provider\n const tunnelProvider = localTunnelProvider ?? {\n name: 'noop',\n setup: async () => { throw new Error('Tunnel not configured'); },\n start: async () => { throw new Error('Tunnel not configured'); },\n stop: async () => {},\n cleanup: async () => {},\n getStatus: () => ({ running: false, connected: false } as TunnelStatus),\n getEndpoint: () => undefined,\n } as TunnelProvider;\n\n return new SubdomainService({\n baseDomain: baseDomain!,\n dnsProvider: dnsProvider!,\n tunnelProvider,\n edgeNodeRepo: nodeRepo,\n });\n }).singleton(),\n });\n console.log(`[Local] Local DNS maintenance services registered for: ${baseDomain}`);\n // 继续进行后续逻辑,不要 return,因为用户可能既用了自管 DNS 又开启了 Managed Client\n }\n\n // 独立式:没有配置 Node Token,用户自己管理域名和 IdP\n if (!nodeToken) {\n console.log('[Local] Standalone mode (no XPOD_NODE_TOKEN)');\n console.log('[Local] User manages DNS and IdP externally');\n if (cloudflareTunnelToken) {\n console.log('[Local] Will start cloudflared with provided CLOUDFLARE_TUNNEL_TOKEN');\n }\n return;\n }\n\n // 托管式:有 Node Token,连接 Cloud\n // Cloud API endpoint 可以从 Token 解析或使用默认值\n const effectiveCloudApiEndpoint = cloudApiEndpoint || 'https://pods.undefineds.co';\n\n // 从 Node Token 解析用户名作为子域名 (格式: username:secret)\n const subdomain = parseSubdomainFromToken(nodeToken);\n\n container.register({\n subdomainClient: asFunction(() => {\n return new SubdomainClient({\n cloudApiEndpoint: effectiveCloudApiEndpoint,\n nodeId: nodeId || 'auto', // 可以从 Token 解析\n nodeToken: nodeToken!,\n });\n }).singleton(),\n\n // 注册网络检测器 (如果尚未注册)\n capabilityDetector: asFunction(() => {\n return new EdgeNodeCapabilityDetector({\n dynamicDetection: { enableNetworkDetection: true },\n });\n }).singleton(),\n\n // DDNS Manager: 自动分配和更新 DDNS\n ddnsManager: asFunction(({ subdomainClient, capabilityDetector }: ApiContainerCradle) => {\n return new DdnsManager({\n client: subdomainClient!,\n detector: capabilityDetector!,\n subdomain: subdomain || nodeId || 'auto',\n autoAllocate: true,\n });\n }).singleton(),\n });\n\n console.log('[Local] Managed mode, SubdomainClient and DdnsManager registered');\n console.log(`[Local] Cloud API endpoint: ${effectiveCloudApiEndpoint}`);\n if (subdomain) {\n console.log(`[Local] DDNS subdomain: ${subdomain}`);\n }\n if (config.oidcIssuer) {\n console.log(`[Local] Using Cloud IdP: ${config.oidcIssuer}`);\n }\n\n if (!cloudflareTunnelToken && !sakuraTunnelToken) {\n console.log('[Local] Note: No tunnel token configured, assuming direct network access');\n }\n}\n\n/**\n * 从 Node Token 解析子域名/用户名\n * Token 格式: username:secret 或 base64 编码\n */\nfunction parseSubdomainFromToken(token: string): string | undefined {\n // 尝试直接解析 username:secret 格式\n if (token.includes(':')) {\n const [username] = token.split(':');\n if (username && /^[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/.test(username)) {\n return username;\n }\n }\n\n // 尝试 base64 解码\n try {\n const decoded = Buffer.from(token, 'base64').toString('utf8');\n if (decoded.includes(':')) {\n const [username] = decoded.split(':');\n if (username && /^[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/.test(username)) {\n return username;\n }\n }\n } catch {\n // ignore\n }\n\n return undefined;\n}\n"]}
@@ -29,7 +29,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
29
29
  };
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
31
  exports.registerRoutes = registerRoutes;
32
- const SignalHandler_1 = require("../handlers/SignalHandler");
32
+ const EdgeNodeSignalHandler_1 = require("../handlers/EdgeNodeSignalHandler");
33
33
  const NodeHandler_1 = require("../handlers/NodeHandler");
34
34
  const ChatHandler_1 = require("../handlers/ChatHandler");
35
35
  const ApiKeyHandler_1 = require("../handlers/ApiKeyHandler");
@@ -42,6 +42,12 @@ const ChatKitV1Handler_1 = require("../handlers/ChatKitV1Handler");
42
42
  const DashboardHandler_1 = require("../handlers/DashboardHandler");
43
43
  const AdminHandler_1 = require("../handlers/AdminHandler");
44
44
  const AdminDdnsHandler_1 = require("../handlers/AdminDdnsHandler");
45
+ const ProvisionHandler_1 = require("../handlers/ProvisionHandler");
46
+ const PodManagementHandler_1 = require("../handlers/PodManagementHandler");
47
+ const QuotaHandler_1 = require("../handlers/QuotaHandler");
48
+ const UsageHandler_1 = require("../handlers/UsageHandler");
49
+ const UsageRepository_1 = require("../../storage/quota/UsageRepository");
50
+ const DrizzleQuotaService_1 = require("../../quota/DrizzleQuotaService");
45
51
  const path = __importStar(require("node:path"));
46
52
  const runtime_1 = require("../../runtime");
47
53
  /**
@@ -89,12 +95,28 @@ function registerSharedRoutes(container, server) {
89
95
  const chatService = container.resolve('chatService');
90
96
  const chatKitService = container.resolve('chatKitService');
91
97
  const chatKitStore = container.resolve('chatKitStore');
92
- (0, SignalHandler_1.registerSignalRoutes)(server, { repository: nodeRepo });
98
+ const config = container.resolve('config');
99
+ (0, EdgeNodeSignalHandler_1.registerEdgeNodeSignalRoutes)(server, {
100
+ repository: nodeRepo,
101
+ dnsCoordinator: container.resolve('dnsCoordinator', { allowUnregistered: true }),
102
+ healthProbeService: container.resolve('healthProbeService', { allowUnregistered: true }),
103
+ });
93
104
  (0, NodeHandler_1.registerNodeRoutes)(server, { repository: nodeRepo });
94
105
  (0, ApiKeyHandler_1.registerApiKeyRoutes)(server, { store: apiKeyStore });
95
106
  (0, ChatHandler_1.registerChatRoutes)(server, { chatService });
96
107
  (0, ChatKitHandler_1.registerChatKitRoutes)(server, { chatKitService });
97
108
  (0, ChatKitV1Handler_1.registerChatKitV1Routes)(server, { store: chatKitStore });
109
+ // Quota & Usage API (Business 对接)
110
+ try {
111
+ const quotaService = new DrizzleQuotaService_1.DrizzleQuotaService({ identityDbUrl: config.databaseUrl });
112
+ const usageRepo = new UsageRepository_1.UsageRepository(container.resolve('db'));
113
+ (0, QuotaHandler_1.registerQuotaRoutes)(server, { quotaService, usageRepo });
114
+ (0, UsageHandler_1.registerUsageRoutes)(server, { usageRepo });
115
+ console.log('[Shared] Quota & Usage routes registered');
116
+ }
117
+ catch (error) {
118
+ console.log(`[Shared] Quota & Usage routes not registered: ${error}`);
119
+ }
98
120
  }
99
121
  /**
100
122
  * Cloud 模式专属路由
@@ -128,18 +150,35 @@ function registerCloudRoutes(container, server) {
128
150
  const dnsProvider = container.resolve('dnsProvider', { allowUnregistered: true });
129
151
  const config = container.resolve('config');
130
152
  if (ddnsRepo) {
131
- const ddnsDomain = config.subdomain?.ddnsDomain || 'undefineds.xyz';
132
- (0, DdnsHandler_1.registerDdnsRoutes)(server, {
133
- ddnsRepo: ddnsRepo,
134
- dnsProvider: dnsProvider,
135
- defaultDomain: ddnsDomain,
136
- });
137
- console.log(`[Cloud] DDNS routes registered (domain: ${ddnsDomain})`);
153
+ const baseStorageDomain = config.subdomain?.baseStorageDomain;
154
+ if (baseStorageDomain) {
155
+ (0, DdnsHandler_1.registerDdnsRoutes)(server, {
156
+ ddnsRepo: ddnsRepo,
157
+ dnsProvider: dnsProvider,
158
+ defaultDomain: baseStorageDomain,
159
+ });
160
+ console.log(`[Cloud] DDNS routes registered (domain: ${baseStorageDomain})`);
161
+ }
162
+ else {
163
+ console.log('[Cloud] DDNS routes not registered (no CSS_BASE_STORAGE_DOMAIN)');
164
+ }
138
165
  }
139
166
  }
140
167
  catch {
141
168
  console.log('[Cloud] DDNS routes not registered (repo not available)');
142
169
  }
170
+ // SP Provision API (SP 注册)
171
+ try {
172
+ const nodeRepo = container.resolve('nodeRepo');
173
+ const config = container.resolve('config');
174
+ const baseUrl = process.env.CSS_BASE_URL || 'http://localhost:3000/';
175
+ const baseStorageDomain = config.subdomain?.baseStorageDomain;
176
+ (0, ProvisionHandler_1.registerProvisionRoutes)(server, { repository: nodeRepo, baseUrl, baseStorageDomain });
177
+ console.log(`[Cloud] Provision routes registered${baseStorageDomain ? ` (baseStorageDomain: ${baseStorageDomain})` : ''}`);
178
+ }
179
+ catch {
180
+ console.log('[Cloud] Provision routes not registered (dependencies not available)');
181
+ }
143
182
  }
144
183
  /**
145
184
  * Local 模式专属路由
@@ -166,5 +205,38 @@ function registerLocalRoutes(container, server) {
166
205
  catch {
167
206
  console.log('[Local] Subdomain client routes not registered (client not available)');
168
207
  }
208
+ // Pod Provision API (SP 端,供 Cloud 回调创建 Pod)
209
+ try {
210
+ // rootDir: CSS 数据目录,默认 ./data
211
+ const rootDir = process.env.CSS_ROOT_FILE_PATH || './data';
212
+ // serviceToken 验证:从 SP 配置中读取
213
+ const expectedServiceToken = process.env.XPOD_SERVICE_TOKEN;
214
+ if (expectedServiceToken) {
215
+ (0, PodManagementHandler_1.registerPodManagementRoutes)(server, {
216
+ rootDir,
217
+ verifyServiceToken: async (token) => token === expectedServiceToken,
218
+ });
219
+ console.log('[Local] Pod provision routes registered (/provision/pods)');
220
+ }
221
+ else {
222
+ console.log('[Local] Pod provision routes not registered (XPOD_SERVICE_TOKEN not configured)');
223
+ }
224
+ }
225
+ catch (error) {
226
+ console.log(`[Local] Pod provision routes not registered: ${error}`);
227
+ }
228
+ // SP 状态查询 (供 Linx 查询 SP 配置状态)
229
+ try {
230
+ const config = container.resolve('config');
231
+ (0, ProvisionHandler_1.registerProvisionStatusRoute)(server, {
232
+ cloudUrl: config.cloudApiEndpoint,
233
+ nodeId: config.nodeId,
234
+ cloudBaseUrl: config.oidcIssuer || config.cloudApiEndpoint,
235
+ });
236
+ console.log('[Local] Provision status route registered (/provision/status)');
237
+ }
238
+ catch (error) {
239
+ console.log(`[Local] Provision status route not registered: ${error}`);
240
+ }
169
241
  }
170
242
  //# sourceMappingURL=routes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/api/container/routes.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;;;;;;;;;;AA2BH,wCAgBC;AArCD,6DAAiE;AACjE,yDAA6D;AAC7D,yDAA6D;AAC7D,6DAAiE;AACjE,mEAAuE;AACvE,+EAAmF;AACnF,yEAA6E;AAC7E,yDAA6D;AAC7D,+DAAmE;AACnE,mEAAuE;AACvE,mEAAuE;AACvE,2DAA+D;AAC/D,mEAAuE;AAGvE,gDAAkC;AAClC,2CAA6C;AAE7C;;GAEG;AACH,SAAgB,cAAc,CAAC,SAA8C;IAC3E,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,WAAW,CAAc,CAAC;IAC3D,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAuB,CAAC;IAEjE,WAAW;IACX,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAE7B,OAAO;IACP,oBAAoB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAExC,oBAAoB;IACpB,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QAC/B,mBAAmB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACN,mBAAmB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAAC,MAAiB;IAC7C,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QACxC,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;QACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAClD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC5C,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAErB,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QACvC,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;QACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAClD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IAC/C,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAErB,iBAAiB;IACjB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,sBAAY,EAAE,kBAAkB,CAAC,CAAC;IACjE,IAAA,0CAAuB,EAAC,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAC3B,SAA8C,EAC9C,MAAiB;IAEjB,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,CAAuB,CAAC;IACrE,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,aAAa,CAAkC,CAAC;IACtF,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACrD,MAAM,cAAc,GAAG,SAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC3D,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACvD,IAAA,oCAAoB,EAAC,MAAM,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;IACvD,IAAA,gCAAkB,EAAC,MAAM,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;IACrD,IAAA,oCAAoB,EAAC,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IACrD,IAAA,gCAAkB,EAAC,MAAM,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;IAC5C,IAAA,sCAAqB,EAAC,MAAM,EAAE,EAAE,cAAc,EAAE,CAAC,CAAC;IAClD,IAAA,0CAAuB,EAAC,MAAM,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAC1B,SAA8C,EAC9C,MAAiB;IAEjB,kCAAkC;IAClC,IAAI,CAAC;QACH,MAAM,gBAAgB,GAAG,SAAS,CAAC,OAAO,CAAC,kBAAkB,CAA2C,CAAC;QACzG,IAAI,gBAAgB,EAAE,CAAC;YACrB,IAAA,0CAAuB,EAAC,MAAM,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC;YACtD,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC;IACjF,CAAC;IAED,qBAAqB;IACrB,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;QACvF,IAAI,WAAW,EAAE,CAAC;YAChB,IAAA,gDAA0B,EAAC,MAAM,EAAE,EAAE,WAAW,EAAE,WAAkB,EAAE,CAAC,CAAC;YACxE,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;IAClF,CAAC;IAED,UAAU;IACV,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5E,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;QAClF,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAuB,CAAC;QAEjE,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,EAAE,UAAU,IAAI,gBAAgB,CAAC;YACpE,IAAA,gCAAkB,EAAC,MAAM,EAAE;gBACzB,QAAQ,EAAE,QAAe;gBACzB,WAAW,EAAE,WAAkB;gBAC/B,aAAa,EAAE,UAAU;aAC1B,CAAC,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,2CAA2C,UAAU,GAAG,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAC1B,SAA8C,EAC9C,MAAiB;IAEjB,sBAAsB;IACtB,IAAA,kCAAmB,EAAC,MAAM,CAAC,CAAC;IAE5B,6BAA6B;IAC7B,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAQ,CAAC;QACzF,IAAA,0CAAuB,EAAC,MAAM,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;IAED,2CAA2C;IAC3C,IAAI,CAAC;QACH,MAAM,eAAe,GAAG,SAAS,CAAC,OAAO,CAAC,iBAAiB,CAA0C,CAAC;QACtG,IAAI,eAAe,EAAE,CAAC;YACpB,IAAA,sDAA6B,EAAC,MAAM,EAAE,EAAE,eAAe,EAAE,CAAC,CAAC;YAC3D,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;IACvF,CAAC;AACH,CAAC","sourcesContent":["/**\n * 路由注册\n *\n * 根据容器中的服务注册 API 路由\n */\n\nimport type { AwilixContainer } from 'awilix';\nimport type { ApiContainerCradle, ApiContainerConfig } from './types';\nimport type { ApiServer } from '../ApiServer';\n\nimport { registerSignalRoutes } from '../handlers/SignalHandler';\nimport { registerNodeRoutes } from '../handlers/NodeHandler';\nimport { registerChatRoutes } from '../handlers/ChatHandler';\nimport { registerApiKeyRoutes } from '../handlers/ApiKeyHandler';\nimport { registerSubdomainRoutes } from '../handlers/SubdomainHandler';\nimport { registerSubdomainClientRoutes } from '../handlers/SubdomainClientHandler';\nimport { registerWebIdProfileRoutes } from '../handlers/WebIdProfileHandler';\nimport { registerDdnsRoutes } from '../handlers/DdnsHandler';\nimport { registerChatKitRoutes } from '../handlers/ChatKitHandler';\nimport { registerChatKitV1Routes } from '../handlers/ChatKitV1Handler';\nimport { registerDashboardRoutes } from '../handlers/DashboardHandler';\nimport { registerAdminRoutes } from '../handlers/AdminHandler';\nimport { registerAdminDdnsRoutes } from '../handlers/AdminDdnsHandler';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { DrizzleClientCredentialsStore } from '../store/DrizzleClientCredentialsStore';\nimport * as path from 'node:path';\nimport { PACKAGE_ROOT } from '../../runtime';\n\n/**\n * 注册所有 API 路由\n */\nexport function registerRoutes(container: AwilixContainer<ApiContainerCradle>): void {\n const server = container.resolve('apiServer') as ApiServer;\n const config = container.resolve('config') as ApiContainerConfig;\n\n // 公共健康检查端点\n registerHealthRoutes(server);\n\n // 共享路由\n registerSharedRoutes(container, server);\n\n // 根据 edition 注册专属路由\n if (config.edition === 'cloud') {\n registerCloudRoutes(container, server);\n } else {\n registerLocalRoutes(container, server);\n }\n}\n\n/**\n * 健康检查路由\n */\nfunction registerHealthRoutes(server: ApiServer): void {\n server.get('/health', async (_req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ status: 'ok' }));\n }, { public: true });\n\n server.get('/ready', async (_req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ status: 'ready' }));\n }, { public: true });\n\n // Dashboard 静态资源\n const staticDir = path.resolve(PACKAGE_ROOT, 'static/dashboard');\n registerDashboardRoutes(server, { staticDir });\n}\n\n/**\n * 共享路由 (cloud 和 local 都有)\n */\nfunction registerSharedRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n const nodeRepo = container.resolve('nodeRepo') as EdgeNodeRepository;\n const apiKeyStore = container.resolve('apiKeyStore') as DrizzleClientCredentialsStore;\n const chatService = container.resolve('chatService');\n const chatKitService = container.resolve('chatKitService');\n const chatKitStore = container.resolve('chatKitStore');\n registerSignalRoutes(server, { repository: nodeRepo });\n registerNodeRoutes(server, { repository: nodeRepo });\n registerApiKeyRoutes(server, { store: apiKeyStore });\n registerChatRoutes(server, { chatService });\n registerChatKitRoutes(server, { chatKitService });\n registerChatKitV1Routes(server, { store: chatKitStore });\n}\n\n/**\n * Cloud 模式专属路由\n */\nfunction registerCloudRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n // 子域名管理 API (需要 SubdomainService)\n try {\n const subdomainService = container.resolve('subdomainService') as ApiContainerCradle['subdomainService'];\n if (subdomainService) {\n registerSubdomainRoutes(server, { subdomainService });\n console.log('[Cloud] Subdomain routes registered');\n }\n } catch {\n console.log('[Cloud] Subdomain routes not registered (service not available)');\n }\n\n // WebID Profile 托管服务\n try {\n const profileRepo = container.resolve('webIdProfileRepo', { allowUnregistered: true });\n if (profileRepo) {\n registerWebIdProfileRoutes(server, { profileRepo: profileRepo as any });\n console.log('[Cloud] WebID Profile routes registered');\n }\n } catch {\n console.log('[Cloud] WebID Profile routes not registered (repo not available)');\n }\n\n // DDNS 服务\n try {\n const ddnsRepo = container.resolve('ddnsRepo', { allowUnregistered: true });\n const dnsProvider = container.resolve('dnsProvider', { allowUnregistered: true });\n const config = container.resolve('config') as ApiContainerConfig;\n\n if (ddnsRepo) {\n const ddnsDomain = config.subdomain?.ddnsDomain || 'undefineds.xyz';\n registerDdnsRoutes(server, {\n ddnsRepo: ddnsRepo as any,\n dnsProvider: dnsProvider as any,\n defaultDomain: ddnsDomain,\n });\n console.log(`[Cloud] DDNS routes registered (domain: ${ddnsDomain})`);\n }\n } catch {\n console.log('[Cloud] DDNS routes not registered (repo not available)');\n }\n}\n\n/**\n * Local 模式专属路由\n */\nfunction registerLocalRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n // Admin API (配置管理、重启)\n registerAdminRoutes(server);\n\n // DDNS status (托管式 Local 模式)\n try {\n const ddnsManager = container.resolve('ddnsManager', { allowUnregistered: true }) as any;\n registerAdminDdnsRoutes(server, { ddnsManager });\n } catch {\n // ignore\n }\n\n // 子域名客户端 API (通过 SubdomainClient 调用 Cloud)\n try {\n const subdomainClient = container.resolve('subdomainClient') as ApiContainerCradle['subdomainClient'];\n if (subdomainClient) {\n registerSubdomainClientRoutes(server, { subdomainClient });\n console.log('[Local] Subdomain client routes registered');\n }\n } catch {\n console.log('[Local] Subdomain client routes not registered (client not available)');\n }\n}\n"]}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/api/container/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 路由注册\n *\n * 根据容器中的服务注册 API 路由\n */\n\nimport type { AwilixContainer } from 'awilix';\nimport type { ApiContainerCradle, ApiContainerConfig } from './types';\nimport type { ApiServer } from '../ApiServer';\n\nimport { registerEdgeNodeSignalRoutes } from '../handlers/EdgeNodeSignalHandler';\nimport { registerNodeRoutes } from '../handlers/NodeHandler';\nimport { registerChatRoutes } from '../handlers/ChatHandler';\nimport { registerApiKeyRoutes } from '../handlers/ApiKeyHandler';\nimport { registerSubdomainRoutes } from '../handlers/SubdomainHandler';\nimport { registerSubdomainClientRoutes } from '../handlers/SubdomainClientHandler';\nimport { registerWebIdProfileRoutes } from '../handlers/WebIdProfileHandler';\nimport { registerDdnsRoutes } from '../handlers/DdnsHandler';\nimport { registerChatKitRoutes } from '../handlers/ChatKitHandler';\nimport { registerChatKitV1Routes } from '../handlers/ChatKitV1Handler';\nimport { registerDashboardRoutes } from '../handlers/DashboardHandler';\nimport { registerAdminRoutes } from '../handlers/AdminHandler';\nimport { registerAdminDdnsRoutes } from '../handlers/AdminDdnsHandler';\nimport { registerProvisionRoutes, registerProvisionStatusRoute } from '../handlers/ProvisionHandler';\nimport { registerPodManagementRoutes } from '../handlers/PodManagementHandler';\nimport { registerQuotaRoutes } from '../handlers/QuotaHandler';\nimport { registerUsageRoutes } from '../handlers/UsageHandler';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { DrizzleClientCredentialsStore } from '../store/DrizzleClientCredentialsStore';\nimport { UsageRepository } from '../../storage/quota/UsageRepository';\nimport { DrizzleQuotaService } from '../../quota/DrizzleQuotaService';\nimport * as path from 'node:path';\nimport { PACKAGE_ROOT } from '../../runtime';\n\n/**\n * 注册所有 API 路由\n */\nexport function registerRoutes(container: AwilixContainer<ApiContainerCradle>): void {\n const server = container.resolve('apiServer') as ApiServer;\n const config = container.resolve('config') as ApiContainerConfig;\n\n // 公共健康检查端点\n registerHealthRoutes(server);\n\n // 共享路由\n registerSharedRoutes(container, server);\n\n // 根据 edition 注册专属路由\n if (config.edition === 'cloud') {\n registerCloudRoutes(container, server);\n } else {\n registerLocalRoutes(container, server);\n }\n}\n\n/**\n * 健康检查路由\n */\nfunction registerHealthRoutes(server: ApiServer): void {\n server.get('/health', async (_req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ status: 'ok' }));\n }, { public: true });\n\n server.get('/ready', async (_req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify({ status: 'ready' }));\n }, { public: true });\n\n // Dashboard 静态资源\n const staticDir = path.resolve(PACKAGE_ROOT, 'static/dashboard');\n registerDashboardRoutes(server, { staticDir });\n}\n\n/**\n * 共享路由 (cloud 和 local 都有)\n */\nfunction registerSharedRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n const nodeRepo = container.resolve('nodeRepo') as EdgeNodeRepository;\n const apiKeyStore = container.resolve('apiKeyStore') as DrizzleClientCredentialsStore;\n const chatService = container.resolve('chatService');\n const chatKitService = container.resolve('chatKitService');\n const chatKitStore = container.resolve('chatKitStore');\n const config = container.resolve('config') as ApiContainerConfig;\n\n registerEdgeNodeSignalRoutes(server, {\n repository: nodeRepo,\n dnsCoordinator: container.resolve('dnsCoordinator', { allowUnregistered: true }) as any,\n healthProbeService: container.resolve('healthProbeService', { allowUnregistered: true }) as any,\n });\n registerNodeRoutes(server, { repository: nodeRepo });\n registerApiKeyRoutes(server, { store: apiKeyStore });\n registerChatRoutes(server, { chatService });\n registerChatKitRoutes(server, { chatKitService });\n registerChatKitV1Routes(server, { store: chatKitStore });\n\n // Quota & Usage API (Business 对接)\n try {\n const quotaService = new DrizzleQuotaService({ identityDbUrl: config.databaseUrl });\n const usageRepo = new UsageRepository(container.resolve('db'));\n registerQuotaRoutes(server, { quotaService, usageRepo });\n registerUsageRoutes(server, { usageRepo });\n console.log('[Shared] Quota & Usage routes registered');\n } catch (error) {\n console.log(`[Shared] Quota & Usage routes not registered: ${error}`);\n }\n}\n\n/**\n * Cloud 模式专属路由\n */\nfunction registerCloudRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n // 子域名管理 API (需要 SubdomainService)\n try {\n const subdomainService = container.resolve('subdomainService') as ApiContainerCradle['subdomainService'];\n if (subdomainService) {\n registerSubdomainRoutes(server, { subdomainService });\n console.log('[Cloud] Subdomain routes registered');\n }\n } catch {\n console.log('[Cloud] Subdomain routes not registered (service not available)');\n }\n\n // WebID Profile 托管服务\n try {\n const profileRepo = container.resolve('webIdProfileRepo', { allowUnregistered: true });\n if (profileRepo) {\n registerWebIdProfileRoutes(server, { profileRepo: profileRepo as any });\n console.log('[Cloud] WebID Profile routes registered');\n }\n } catch {\n console.log('[Cloud] WebID Profile routes not registered (repo not available)');\n }\n\n // DDNS 服务\n try {\n const ddnsRepo = container.resolve('ddnsRepo', { allowUnregistered: true });\n const dnsProvider = container.resolve('dnsProvider', { allowUnregistered: true });\n const config = container.resolve('config') as ApiContainerConfig;\n\n if (ddnsRepo) {\n const baseStorageDomain = config.subdomain?.baseStorageDomain;\n if (baseStorageDomain) {\n registerDdnsRoutes(server, {\n ddnsRepo: ddnsRepo as any,\n dnsProvider: dnsProvider as any,\n defaultDomain: baseStorageDomain,\n });\n console.log(`[Cloud] DDNS routes registered (domain: ${baseStorageDomain})`);\n } else {\n console.log('[Cloud] DDNS routes not registered (no CSS_BASE_STORAGE_DOMAIN)');\n }\n }\n } catch {\n console.log('[Cloud] DDNS routes not registered (repo not available)');\n }\n\n // SP Provision API (SP 注册)\n try {\n const nodeRepo = container.resolve('nodeRepo') as EdgeNodeRepository;\n const config = container.resolve('config') as ApiContainerConfig;\n const baseUrl = process.env.CSS_BASE_URL || 'http://localhost:3000/';\n const baseStorageDomain = config.subdomain?.baseStorageDomain;\n registerProvisionRoutes(server, { repository: nodeRepo, baseUrl, baseStorageDomain });\n console.log(`[Cloud] Provision routes registered${baseStorageDomain ? ` (baseStorageDomain: ${baseStorageDomain})` : ''}`);\n } catch {\n console.log('[Cloud] Provision routes not registered (dependencies not available)');\n }\n}\n\n/**\n * Local 模式专属路由\n */\nfunction registerLocalRoutes(\n container: AwilixContainer<ApiContainerCradle>,\n server: ApiServer,\n): void {\n // Admin API (配置管理、重启)\n registerAdminRoutes(server);\n\n // DDNS status (托管式 Local 模式)\n try {\n const ddnsManager = container.resolve('ddnsManager', { allowUnregistered: true }) as any;\n registerAdminDdnsRoutes(server, { ddnsManager });\n } catch {\n // ignore\n }\n\n // 子域名客户端 API (通过 SubdomainClient 调用 Cloud)\n try {\n const subdomainClient = container.resolve('subdomainClient') as ApiContainerCradle['subdomainClient'];\n if (subdomainClient) {\n registerSubdomainClientRoutes(server, { subdomainClient });\n console.log('[Local] Subdomain client routes registered');\n }\n } catch {\n console.log('[Local] Subdomain client routes not registered (client not available)');\n }\n\n // Pod Provision API (SP 端,供 Cloud 回调创建 Pod)\n try {\n // rootDir: CSS 数据目录,默认 ./data\n const rootDir = process.env.CSS_ROOT_FILE_PATH || './data';\n // serviceToken 验证:从 SP 配置中读取\n const expectedServiceToken = process.env.XPOD_SERVICE_TOKEN;\n\n if (expectedServiceToken) {\n registerPodManagementRoutes(server, {\n rootDir,\n verifyServiceToken: async (token: string) => token === expectedServiceToken,\n });\n console.log('[Local] Pod provision routes registered (/provision/pods)');\n } else {\n console.log('[Local] Pod provision routes not registered (XPOD_SERVICE_TOKEN not configured)');\n }\n } catch (error) {\n console.log(`[Local] Pod provision routes not registered: ${error}`);\n }\n\n // SP 状态查询 (供 Linx 查询 SP 配置状态)\n try {\n const config = container.resolve('config') as ApiContainerConfig;\n registerProvisionStatusRoute(server, {\n cloudUrl: config.cloudApiEndpoint,\n nodeId: config.nodeId,\n cloudBaseUrl: config.oidcIssuer || config.cloudApiEndpoint,\n });\n console.log('[Local] Provision status route registered (/provision/status)');\n } catch (error) {\n console.log(`[Local] Provision status route not registered: ${error}`);\n }\n}\n"]}
@@ -7,6 +7,7 @@ import type { ApiServer } from '../ApiServer';
7
7
  import type { AuthMiddleware } from '../middleware/AuthMiddleware';
8
8
  import type { Authenticator } from '../auth/Authenticator';
9
9
  import type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';
10
+ import type { ServiceTokenRepository } from '../../identity/drizzle/ServiceTokenRepository';
10
11
  import type { DrizzleClientCredentialsStore } from '../store/DrizzleClientCredentialsStore';
11
12
  import type { VercelChatService } from '../service/VercelChatService';
12
13
  import type { SubdomainService } from '../../subdomain/SubdomainService';
@@ -29,20 +30,18 @@ export interface ApiContainerConfig {
29
30
  port: number;
30
31
  /** API Server 主机 */
31
32
  host: string;
33
+ /** API Server Unix socket 路径 */
34
+ socketPath?: string;
32
35
  /** 数据库连接 URL */
33
36
  databaseUrl: string;
34
37
  /** CORS 允许的源 */
35
38
  corsOrigins: string[];
36
- /** 加密密钥 */
37
- encryptionKey: string;
38
39
  /** CSS Token 端点 */
39
40
  cssTokenEndpoint: string;
40
41
  /** 子域名功能配置 (cloud 模式) */
41
42
  subdomain?: {
42
- enabled: boolean;
43
- baseDomain?: string;
44
- /** DDNS 服务使用的域名 (如 undefineds.xyz) */
45
- ddnsDomain?: string;
43
+ /** 节点域名根域名 (如 undefineds.site),有值即启用子域名功能 */
44
+ baseStorageDomain?: string;
46
45
  cloudflareAccountId?: string;
47
46
  cloudflareApiToken?: string;
48
47
  tencentDnsSecretId?: string;
@@ -64,6 +63,7 @@ export interface ApiContainerConfig {
64
63
  edgeNodesEnabled?: boolean;
65
64
  }
66
65
  import { EdgeNodeDnsCoordinator } from '../../edge/EdgeNodeDnsCoordinator';
66
+ import { EdgeNodeHealthProbeService } from '../../edge/EdgeNodeHealthProbeService';
67
67
  import { EdgeNodeCapabilityDetector } from '../../edge/EdgeNodeCapabilityDetector';
68
68
  import { LocalNetworkManager } from '../../edge/LocalNetworkManager';
69
69
  import { DdnsManager } from '../../edge/DdnsManager';
@@ -77,6 +77,7 @@ export interface ApiContainerCradle {
77
77
  authMiddleware: AuthMiddleware;
78
78
  authenticator: Authenticator;
79
79
  nodeRepo: EdgeNodeRepository;
80
+ serviceTokenRepo: ServiceTokenRepository;
80
81
  apiKeyStore: DrizzleClientCredentialsStore;
81
82
  chatService: VercelChatService;
82
83
  chatKitStore: PodChatKitStore;
@@ -86,6 +87,7 @@ export interface ApiContainerCradle {
86
87
  ddnsRepo?: DdnsRepository;
87
88
  dnsProvider?: DnsProvider;
88
89
  dnsCoordinator?: EdgeNodeDnsCoordinator;
90
+ healthProbeService?: EdgeNodeHealthProbeService;
89
91
  capabilityDetector?: EdgeNodeCapabilityDetector;
90
92
  localNetworkManager?: LocalNetworkManager;
91
93
  tunnelProvider?: TunnelProvider;
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/api/container/types.ts"],"names":[],"mappings":";AAAA;;;;GAIG","sourcesContent":["/**\n * API Container 依赖类型定义\n *\n * 定义容器中注册的所有服务接口\n */\n\nimport type { ApiServer } from '../ApiServer';\nimport type { AuthMiddleware } from '../middleware/AuthMiddleware';\nimport type { Authenticator } from '../auth/Authenticator';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { DrizzleClientCredentialsStore } from '../store/DrizzleClientCredentialsStore';\nimport type { VercelChatService } from '../service/VercelChatService';\nimport type { SubdomainService } from '../../subdomain/SubdomainService';\nimport type { SubdomainClient } from '../../subdomain/SubdomainClient';\nimport type { DnsProvider } from '../../dns/DnsProvider';\nimport type { TunnelProvider } from '../../tunnel/TunnelProvider';\nimport type { IdentityDatabase } from '../../identity/drizzle/db';\nimport type { WebIdProfileRepository } from '../../identity/drizzle/WebIdProfileRepository';\nimport type { DdnsRepository } from '../../identity/drizzle/DdnsRepository';\nimport type { ChatKitService, AiProvider } from '../chatkit';\nimport type { StoreContext } from '../chatkit/store';\nimport type { PodChatKitStore } from '../chatkit/pod-store';\n\n/**\n * 容器配置\n */\nexport interface ApiContainerConfig {\n /** 运行模式: cloud 持有密钥, local 调用远程 */\n edition: 'cloud' | 'local';\n\n /** API Server 端口 */\n port: number;\n\n /** API Server 主机 */\n host: string;\n\n /** 数据库连接 URL */\n databaseUrl: string;\n\n /** CORS 允许的源 */\n corsOrigins: string[];\n\n /** 加密密钥 */\n encryptionKey: string;\n\n /** CSS Token 端点 */\n cssTokenEndpoint: string;\n\n /** 子域名功能配置 (cloud 模式) */\n subdomain?: {\n enabled: boolean;\n baseDomain?: string;\n /** DDNS 服务使用的域名 (如 undefineds.xyz) */\n ddnsDomain?: string;\n cloudflareAccountId?: string;\n cloudflareApiToken?: string;\n tencentDnsSecretId?: string;\n tencentDnsSecretKey?: string;\n };\n\n /** Cloud API 端点 (local 托管式,调用 cloud 的子域名 API) */\n cloudApiEndpoint?: string;\n\n /** 节点 ID (local 托管式) */\n nodeId?: string;\n\n /** 节点 Token (local 托管式,调用 Cloud API 的认证) */\n nodeToken?: string;\n\n /** OIDC Issuer URL (local 托管式,使用 Cloud IdP) */\n oidcIssuer?: string;\n\n /** Cloudflare Tunnel Token (local 托管式/自管式,启动 cloudflared) */\n cloudflareTunnelToken?: string;\n\n /** SakuraFRP Tunnel Token (SAKURA_TUNNEL_TOKEN;local 托管式/自管式,启动 frpc) */\n sakuraTunnelToken?: string;\n\n /** 是否接受 Edge 节点注册 (cloud 模式) */\n edgeNodesEnabled?: boolean;\n}\n\nimport { EdgeNodeDnsCoordinator } from '../../edge/EdgeNodeDnsCoordinator';\nimport { EdgeNodeCapabilityDetector } from '../../edge/EdgeNodeCapabilityDetector';\nimport { LocalNetworkManager } from '../../edge/LocalNetworkManager';\nimport { DdnsManager } from '../../edge/DdnsManager';\n\n/**\n * 容器中注册的所有服务\n */\nexport interface ApiContainerCradle {\n // 配置\n config: ApiContainerConfig;\n\n // 核心服务\n db: IdentityDatabase;\n apiServer: ApiServer;\n authMiddleware: AuthMiddleware;\n authenticator: Authenticator;\n\n // 仓库\n nodeRepo: EdgeNodeRepository;\n apiKeyStore: DrizzleClientCredentialsStore;\n\n // 业务服务\n chatService: VercelChatService;\n\n // ChatKit 服务 (OpenAI ChatKit 协议)\n chatKitStore: PodChatKitStore;\n chatKitAiProvider: AiProvider;\n chatKitService: ChatKitService<StoreContext>;\n\n // Cloud 模式: 身份服务\n webIdProfileRepo?: WebIdProfileRepository;\n ddnsRepo?: DdnsRepository;\n\n // 子域名相关 (可选,按 edition 注册)\n // Cloud 模式 或 Local 自管模式\n dnsProvider?: DnsProvider;\n dnsCoordinator?: EdgeNodeDnsCoordinator;\n capabilityDetector?: EdgeNodeCapabilityDetector;\n localNetworkManager?: LocalNetworkManager;\n\n tunnelProvider?: TunnelProvider;\n subdomainService?: SubdomainService;\n // Local 托管式\n subdomainClient?: SubdomainClient;\n // Local 托管式 DDNS 管理\n ddnsManager?: DdnsManager;\n // Local 托管式/自管式 (启动 cloudflared)\n localTunnelProvider?: TunnelProvider;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/api/container/types.ts"],"names":[],"mappings":";AAAA;;;;GAIG","sourcesContent":["/**\n * API Container 依赖类型定义\n *\n * 定义容器中注册的所有服务接口\n */\n\nimport type { ApiServer } from '../ApiServer';\nimport type { AuthMiddleware } from '../middleware/AuthMiddleware';\nimport type { Authenticator } from '../auth/Authenticator';\nimport type { EdgeNodeRepository } from '../../identity/drizzle/EdgeNodeRepository';\nimport type { ServiceTokenRepository } from '../../identity/drizzle/ServiceTokenRepository';\nimport type { DrizzleClientCredentialsStore } from '../store/DrizzleClientCredentialsStore';\nimport type { VercelChatService } from '../service/VercelChatService';\nimport type { SubdomainService } from '../../subdomain/SubdomainService';\nimport type { SubdomainClient } from '../../subdomain/SubdomainClient';\nimport type { DnsProvider } from '../../dns/DnsProvider';\nimport type { TunnelProvider } from '../../tunnel/TunnelProvider';\nimport type { IdentityDatabase } from '../../identity/drizzle/db';\nimport type { WebIdProfileRepository } from '../../identity/drizzle/WebIdProfileRepository';\nimport type { DdnsRepository } from '../../identity/drizzle/DdnsRepository';\nimport type { ChatKitService, AiProvider } from '../chatkit';\nimport type { StoreContext } from '../chatkit/store';\nimport type { PodChatKitStore } from '../chatkit/pod-store';\n\n/**\n * 容器配置\n */\nexport interface ApiContainerConfig {\n /** 运行模式: cloud 持有密钥, local 调用远程 */\n edition: 'cloud' | 'local';\n\n /** API Server 端口 */\n port: number;\n\n /** API Server 主机 */\n host: string;\n\n /** API Server Unix socket 路径 */\n socketPath?: string;\n\n /** 数据库连接 URL */\n databaseUrl: string;\n\n /** CORS 允许的源 */\n corsOrigins: string[];\n\n /** CSS Token 端点 */\n cssTokenEndpoint: string;\n\n /** 子域名功能配置 (cloud 模式) */\n subdomain?: {\n /** 节点域名根域名 (如 undefineds.site),有值即启用子域名功能 */\n baseStorageDomain?: string;\n cloudflareAccountId?: string;\n cloudflareApiToken?: string;\n tencentDnsSecretId?: string;\n tencentDnsSecretKey?: string;\n };\n\n /** Cloud API 端点 (local 托管式,调用 cloud 的子域名 API) */\n cloudApiEndpoint?: string;\n\n /** 节点 ID (local 托管式) */\n nodeId?: string;\n\n /** 节点 Token (local 托管式,调用 Cloud API 的认证) */\n nodeToken?: string;\n\n /** OIDC Issuer URL (local 托管式,使用 Cloud IdP) */\n oidcIssuer?: string;\n\n /** Cloudflare Tunnel Token (local 托管式/自管式,启动 cloudflared) */\n cloudflareTunnelToken?: string;\n\n /** SakuraFRP Tunnel Token (SAKURA_TUNNEL_TOKEN;local 托管式/自管式,启动 frpc) */\n sakuraTunnelToken?: string;\n\n /** 是否接受 Edge 节点注册 (cloud 模式) */\n edgeNodesEnabled?: boolean;\n}\n\nimport { EdgeNodeDnsCoordinator } from '../../edge/EdgeNodeDnsCoordinator';\nimport { EdgeNodeHealthProbeService } from '../../edge/EdgeNodeHealthProbeService';\nimport { EdgeNodeCapabilityDetector } from '../../edge/EdgeNodeCapabilityDetector';\nimport { LocalNetworkManager } from '../../edge/LocalNetworkManager';\nimport { DdnsManager } from '../../edge/DdnsManager';\n\n/**\n * 容器中注册的所有服务\n */\nexport interface ApiContainerCradle {\n // 配置\n config: ApiContainerConfig;\n\n // 核心服务\n db: IdentityDatabase;\n apiServer: ApiServer;\n authMiddleware: AuthMiddleware;\n authenticator: Authenticator;\n\n // 仓库\n nodeRepo: EdgeNodeRepository;\n serviceTokenRepo: ServiceTokenRepository;\n apiKeyStore: DrizzleClientCredentialsStore;\n\n // 业务服务\n chatService: VercelChatService;\n\n // ChatKit 服务 (OpenAI ChatKit 协议)\n chatKitStore: PodChatKitStore;\n chatKitAiProvider: AiProvider;\n chatKitService: ChatKitService<StoreContext>;\n\n // Cloud 模式: 身份服务\n webIdProfileRepo?: WebIdProfileRepository;\n ddnsRepo?: DdnsRepository;\n\n // 子域名相关 (可选,按 edition 注册)\n // Cloud 模式 或 Local 自管模式\n dnsProvider?: DnsProvider;\n dnsCoordinator?: EdgeNodeDnsCoordinator;\n healthProbeService?: EdgeNodeHealthProbeService;\n capabilityDetector?: EdgeNodeCapabilityDetector;\n localNetworkManager?: LocalNetworkManager;\n\n tunnelProvider?: TunnelProvider;\n subdomainService?: SubdomainService;\n // Local 托管式\n subdomainClient?: SubdomainClient;\n // Local 托管式 DDNS 管理\n ddnsManager?: DdnsManager;\n // Local 托管式/自管式 (启动 cloudflared)\n localTunnelProvider?: TunnelProvider;\n}\n"]}
@@ -377,7 +377,7 @@ function registerAdminRoutes(server) {
377
377
  }
378
378
  };
379
379
  // GET /api/admin/public-ip - Detect outbound public IP and compare with CSS_BASE_URL
380
- const publicIpHandler = async (req, res) => {
380
+ const ipv4Handler = async (req, res) => {
381
381
  try {
382
382
  const envFilePath = getEnvFilePath();
383
383
  const env = readEnvFile(envFilePath);
@@ -387,7 +387,7 @@ function registerAdminRoutes(server) {
387
387
  if (!baseUrl) {
388
388
  sendJson(res, 200, {
389
389
  status: 'unknown',
390
- publicIp: ip,
390
+ ipv4: ip,
391
391
  baseUrl,
392
392
  detail: ip ? '未配置 Base URL,无法判断是否可直连。' : '未配置 Base URL,且无法获取公网 IP。',
393
393
  });
@@ -400,7 +400,7 @@ function registerAdminRoutes(server) {
400
400
  catch {
401
401
  sendJson(res, 200, {
402
402
  status: 'unknown',
403
- publicIp: ip,
403
+ ipv4: ip,
404
404
  baseUrl,
405
405
  detail: 'Base URL 格式不合法,无法判断。',
406
406
  });
@@ -409,7 +409,7 @@ function registerAdminRoutes(server) {
409
409
  if (isPrivateIp(hostname)) {
410
410
  sendJson(res, 200, {
411
411
  status: 'fail',
412
- publicIp: ip,
412
+ ipv4: ip,
413
413
  baseUrl,
414
414
  detail: 'Base URL 为本地/内网地址,默认不可直连。',
415
415
  });
@@ -421,7 +421,7 @@ function registerAdminRoutes(server) {
421
421
  if (!ip) {
422
422
  sendJson(res, 200, {
423
423
  status: 'unknown',
424
- publicIp: null,
424
+ ipv4: null,
425
425
  baseUrl,
426
426
  detail: '无法获取公网出口 IP,无法比对。',
427
427
  });
@@ -430,7 +430,7 @@ function registerAdminRoutes(server) {
430
430
  const ok = hostname === ip;
431
431
  sendJson(res, 200, {
432
432
  status: ok ? 'pass' : 'fail',
433
- publicIp: ip,
433
+ ipv4: ip,
434
434
  baseUrl,
435
435
  detail: ok
436
436
  ? 'Base URL IP 与公网出口 IP 一致,默认可直连。'
@@ -442,7 +442,7 @@ function registerAdminRoutes(server) {
442
442
  if (!ip) {
443
443
  sendJson(res, 200, {
444
444
  status: 'unknown',
445
- publicIp: null,
445
+ ipv4: null,
446
446
  baseUrl,
447
447
  detail: '已配置域名,但无法获取公网出口 IP,无法进一步判断。',
448
448
  });
@@ -450,7 +450,7 @@ function registerAdminRoutes(server) {
450
450
  }
451
451
  sendJson(res, 200, {
452
452
  status: 'pass',
453
- publicIp: ip,
453
+ ipv4: ip,
454
454
  baseUrl,
455
455
  detail: '已配置域名,默认可直连(仍需确保端口映射/防火墙放行)。',
456
456
  });
@@ -463,7 +463,7 @@ function registerAdminRoutes(server) {
463
463
  // Register routes - public for now (TODO: add auth for production)
464
464
  server.get('/api/admin/status', statusHandler, { public: true });
465
465
  server.get('/api/admin/config', getConfigHandler, { public: true });
466
- server.get('/api/admin/public-ip', publicIpHandler, { public: true });
466
+ server.get('/api/admin/public-ip', ipv4Handler, { public: true });
467
467
  server.put('/api/admin/config', updateConfigHandler, { public: true });
468
468
  server.post('/api/admin/restart', restartHandler, { public: true });
469
469
  server.get('/api/admin/logs', getLogsHandler, { public: true });