@undefineds.co/xpod 0.4.12 → 0.4.14

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 (272) hide show
  1. package/config/components-ignore.json +11 -7
  2. package/dist/acceptance/QleverSemanticConformance.js +7 -0
  3. package/dist/api/ai-gateway/providers/OfferingAuthorization.d.ts +6 -1
  4. package/dist/api/ai-gateway/providers/OfferingAuthorization.js +0 -3
  5. package/dist/api/ai-gateway/providers/ProviderRegistry.js +1 -1
  6. package/dist/api/container/index.js +1 -0
  7. package/dist/api/container/local.js +30 -12
  8. package/dist/api/container/routes.js +2 -0
  9. package/dist/api/container/types.d.ts +2 -0
  10. package/dist/api/handlers/AdminHandler.d.ts +17 -1
  11. package/dist/api/handlers/AdminHandler.js +40 -3
  12. package/dist/api/handlers/EdgeNodeSignalHandler.js +10 -2
  13. package/dist/api/handlers/NetworkSettingsHandler.d.ts +37 -5
  14. package/dist/api/handlers/NetworkSettingsHandler.js +39 -11
  15. package/dist/api/handlers/ProvisionHandler.d.ts +6 -1
  16. package/dist/api/handlers/ProvisionHandler.js +7 -2
  17. package/dist/api/handlers/ReachabilityHandler.d.ts +6 -0
  18. package/dist/api/handlers/ReachabilityHandler.js +22 -5
  19. package/dist/api/network/NetworkEnvironmentConfigurationStore.d.ts +6 -1
  20. package/dist/api/network/NetworkEnvironmentConfigurationStore.js +72 -16
  21. package/dist/api/runtime.d.ts +9 -0
  22. package/dist/api/runtime.js +15 -2
  23. package/dist/cli/commands/start.d.ts +19 -1
  24. package/dist/cli/commands/start.js +71 -5
  25. package/dist/components/context.jsonld +30 -0
  26. package/dist/edge/EdgeNodeAgent.d.ts +6 -0
  27. package/dist/edge/EdgeNodeAgent.js +1 -1
  28. package/dist/edge/EdgeNodeAgentInitializer.d.ts +2 -0
  29. package/dist/edge/EdgeNodeAgentInitializer.js +1 -0
  30. package/dist/edge/EdgeNodeAgentInitializer.jsonld +19 -0
  31. package/dist/edge/EdgeNodeDnsCoordinator.d.ts +11 -1
  32. package/dist/edge/EdgeNodeDnsCoordinator.js +12 -2
  33. package/dist/edge/EdgeNodeHealthProbeService.d.ts +15 -0
  34. package/dist/edge/EdgeNodeHealthProbeService.js +44 -12
  35. package/dist/edge/EdgeNodeHealthProbeService.jsonld +77 -0
  36. package/dist/edge/ProbeTargetGuard.d.ts +35 -0
  37. package/dist/edge/ProbeTargetGuard.js +142 -0
  38. package/dist/edge/reachability/NodeAccessResolver.d.ts +16 -0
  39. package/dist/edge/reachability/NodeAccessResolver.js +30 -0
  40. package/dist/index.d.ts +3 -1
  41. package/dist/index.js +9 -3
  42. package/dist/main.js +7 -0
  43. package/dist/runtime/Proxy.d.ts +22 -0
  44. package/dist/runtime/Proxy.js +34 -7
  45. package/dist/runtime/bootstrap.d.ts +11 -0
  46. package/dist/runtime/bootstrap.js +21 -1
  47. package/dist/runtime/css-process.d.ts +1 -0
  48. package/dist/runtime/css-process.js +1 -0
  49. package/dist/runtime/host/node/NodeRuntimeHost.js +4 -1
  50. package/dist/runtime/host/types.d.ts +6 -0
  51. package/dist/runtime/index.d.ts +1 -1
  52. package/dist/runtime/index.js +5 -1
  53. package/dist/runtime/lifecycle.js +1 -0
  54. package/dist/runtime/port-finder.d.ts +30 -0
  55. package/dist/runtime/port-finder.js +83 -0
  56. package/dist/runtime/runner/node/NodeGatewayRuntimeRunner.js +1 -0
  57. package/dist/runtime/runner/types.d.ts +5 -0
  58. package/dist/runtime/runtime-types.d.ts +1 -0
  59. package/dist/storage/rdf/PostgresRdfEngine.js +10 -4
  60. package/dist/storage/rdf/RdfAccessScope.js +15 -1
  61. package/dist/storage/rdf/RdfEngineRdfJsSource.js +10 -2
  62. package/dist/test-utils/local-managed-client-p2p-e2e-smoke.js +1 -1
  63. package/dist/tunnel/LocalTunnelProvider.d.ts +15 -0
  64. package/dist/tunnel/LocalTunnelProvider.js +87 -18
  65. package/dist/tunnel/LocalTunnelProvider.jsonld +27 -0
  66. package/dist/tunnel/NgrokTunnelProvider.d.ts +4 -0
  67. package/dist/tunnel/NgrokTunnelProvider.js +117 -43
  68. package/dist/tunnel/NgrokTunnelProvider.jsonld +4 -0
  69. package/dist/tunnel/SakuraFrpTunnelProvider.d.ts +65 -3
  70. package/dist/tunnel/SakuraFrpTunnelProvider.js +268 -25
  71. package/dist/tunnel/TunnelLifecycle.d.ts +14 -0
  72. package/dist/tunnel/TunnelLifecycle.js +34 -0
  73. package/dist/tunnel/TunnelProfiles.d.ts +33 -3
  74. package/dist/tunnel/TunnelProfiles.js +105 -78
  75. package/dist/tunnel/TunnelProvider.d.ts +15 -2
  76. package/dist/tunnel/TunnelProvider.jsonld +8 -0
  77. package/dist/tunnel/TunnelProviderCatalog.d.ts +62 -0
  78. package/dist/tunnel/TunnelProviderCatalog.js +130 -0
  79. package/node_modules/@undefineds.co/ai-connections/dist/AiApiKeyPool.d.ts +1 -1
  80. package/node_modules/@undefineds.co/ai-connections/dist/AiApiKeyPool.js +1 -1
  81. package/node_modules/@undefineds.co/ai-connections/dist/AiAuthorizationActions.d.ts +1 -1
  82. package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.d.ts +1 -1
  83. package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.js +3 -3
  84. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectDialog.d.ts +1 -1
  85. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +1 -1
  86. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.js +2 -2
  87. package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.d.ts +1 -1
  88. package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialRow.d.ts +1 -1
  89. package/node_modules/@undefineds.co/ai-connections/dist/AiCustomProviderDialog.d.ts +1 -1
  90. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeyRow.d.ts +1 -1
  91. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.d.ts +1 -1
  92. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayModelsSection.d.ts +1 -1
  93. package/node_modules/@undefineds.co/ai-connections/dist/AiOfferingDetails.d.ts +1 -1
  94. package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.d.ts +1 -1
  95. package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.d.ts +1 -1
  96. package/node_modules/@undefineds.co/ai-connections/dist/AiSortableCredentialList.d.ts +1 -1
  97. package/node_modules/@undefineds.co/ai-connections/dist/authorization-methods.d.ts +13 -11
  98. package/node_modules/@undefineds.co/ai-connections/dist/authorization-methods.js +16 -13
  99. package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.d.ts +1 -1
  100. package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.js +3 -3
  101. package/node_modules/@undefineds.co/ai-connections/dist/collections.d.ts +1 -1
  102. package/node_modules/@undefineds.co/ai-connections/dist/collections.js +3 -3
  103. package/node_modules/@undefineds.co/ai-connections/dist/{ai-connections-client.d.ts → contract/ai-connections-client.d.ts} +4 -2
  104. package/node_modules/@undefineds.co/ai-connections/dist/{ai-connections-client.js → contract/ai-connections-client.js} +4 -2
  105. package/node_modules/@undefineds.co/ai-connections/dist/{client → contract/client}/normalize.d.ts +17 -7
  106. package/node_modules/@undefineds.co/ai-connections/dist/{client → contract/client}/normalize.js +18 -213
  107. package/node_modules/@undefineds.co/ai-connections/dist/{client → contract/client}/request.js +3 -3
  108. package/node_modules/@undefineds.co/ai-connections/dist/{client → contract/client}/types.d.ts +11 -2
  109. package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/index.cjs +8 -8
  110. package/node_modules/@undefineds.co/ai-connections/dist/contract/index.d.ts +9 -0
  111. package/node_modules/@undefineds.co/ai-connections/dist/contract/index.js +9 -0
  112. package/node_modules/@undefineds.co/ai-connections/dist/{provider-catalog.cjs → contract/provider-catalog.cjs} +5 -28
  113. package/node_modules/@undefineds.co/ai-connections/dist/{provider-catalog.d.ts → contract/provider-catalog.d.ts} +9 -8
  114. package/node_modules/@undefineds.co/ai-connections/dist/{provider-catalog.js → contract/provider-catalog.js} +11 -31
  115. package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +1 -1
  116. package/node_modules/@undefineds.co/ai-connections/dist/controller.js +3 -2
  117. package/node_modules/@undefineds.co/ai-connections/dist/credential-labels.d.ts +1 -1
  118. package/node_modules/@undefineds.co/ai-connections/dist/display-wording.d.ts +20 -0
  119. package/node_modules/@undefineds.co/ai-connections/dist/display-wording.js +73 -0
  120. package/node_modules/@undefineds.co/ai-connections/dist/error-wording.d.ts +24 -0
  121. package/node_modules/@undefineds.co/ai-connections/dist/error-wording.js +253 -0
  122. package/node_modules/@undefineds.co/ai-connections/dist/gateway-endpoints.js +1 -1
  123. package/node_modules/@undefineds.co/ai-connections/dist/index.d.ts +2 -3
  124. package/node_modules/@undefineds.co/ai-connections/dist/index.js +2 -3
  125. package/node_modules/@undefineds.co/ai-connections/dist/offering-endpoints.d.ts +1 -1
  126. package/node_modules/@undefineds.co/ai-connections/dist/offering-label.d.ts +1 -1
  127. package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.d.ts +1 -1
  128. package/node_modules/@undefineds.co/ai-connections/dist/service-access.js +1 -1
  129. package/node_modules/@undefineds.co/ai-connections/dist/useAiConnectDialog.d.ts +1 -1
  130. package/node_modules/@undefineds.co/ai-connections/package.json +25 -18
  131. package/node_modules/@undefineds.co/shared-ui/dist/index.d.ts +4 -2
  132. package/node_modules/@undefineds.co/shared-ui/dist/index.js +4 -2
  133. package/node_modules/@undefineds.co/shared-ui/dist/login/LoginModal.d.ts +4 -1
  134. package/node_modules/@undefineds.co/shared-ui/dist/login/LoginModal.js +12 -6
  135. package/node_modules/@undefineds.co/shared-ui/dist/login/LoginView.d.ts +1 -1
  136. package/node_modules/@undefineds.co/shared-ui/dist/login/host-types.d.ts +7 -1
  137. package/node_modules/@undefineds.co/shared-ui/dist/login/login-branding.d.ts +6 -0
  138. package/node_modules/@undefineds.co/shared-ui/dist/login/login-branding.js +18 -0
  139. package/node_modules/@undefineds.co/shared-ui/dist/user-facing-errors.d.ts +14 -2
  140. package/node_modules/@undefineds.co/shared-ui/dist/user-facing-errors.js +26 -17
  141. package/node_modules/@undefineds.co/solid-sdk/dist/login-store.d.ts +3 -3
  142. package/node_modules/@undefineds.co/solid-sdk/dist/login-store.js +3 -3
  143. package/package.json +4 -3
  144. package/static/auth-callback/assets/{AiConfigContext-DnQs1ZpW.js → AiConfigContext-DCXpjzpj.js} +1 -1
  145. package/static/auth-callback/assets/{AiConfigPage-DOtvlxH0.js → AiConfigPage-fe-xMIXa.js} +1 -1
  146. package/static/auth-callback/assets/{DocumentProcessingPanel-BS2voQgL.js → DocumentProcessingPanel-BGnkfMuU.js} +1 -1
  147. package/static/auth-callback/assets/{IndexLifecyclePanel-Cvt0cJtN.js → IndexLifecyclePanel-42Jups0j.js} +1 -1
  148. package/static/auth-callback/assets/{IndexSubjectPanel-Dhf01GqF.js → IndexSubjectPanel-CYyLOlQU.js} +1 -1
  149. package/static/auth-callback/assets/{ModelAssignmentsPanel-BJutWaAF.js → ModelAssignmentsPanel-BOvUH4yr.js} +1 -1
  150. package/static/auth-callback/assets/{ModelsPage-BRS0sje3.js → ModelsPage-DwyITxt7.js} +6 -6
  151. package/static/auth-callback/assets/NetworkPage-CG9RelJA.js +2 -0
  152. package/static/auth-callback/assets/{PaneListHeader-QQeJGTp4.js → PaneListHeader-yvd5ohs6.js} +1 -1
  153. package/static/auth-callback/assets/{SearchIndexingPanel-MyNUSEwT.js → SearchIndexingPanel-2_a6ezzj.js} +1 -1
  154. package/static/auth-callback/assets/{StatusSubjectPanel-DQkEVsFs.js → StatusSubjectPanel-8qtVxnzC.js} +1 -1
  155. package/static/auth-callback/assets/{StatusWorkspace-Dkv63Uwk.js → StatusWorkspace-CBdRahCF.js} +1 -1
  156. package/static/auth-callback/assets/{SystemSettingsPage-TIsUfX5d.js → SystemSettingsPage-BZJ6vWkg.js} +1 -1
  157. package/static/auth-callback/assets/{SystemSettingsSubjectPanel-BJWEt2-7.js → SystemSettingsSubjectPanel-xm08UhXP.js} +1 -1
  158. package/static/auth-callback/assets/XpodAiConnectionsPodStore-V6vgGfuw.js +3 -0
  159. package/static/auth-callback/assets/{activity-5hNeNKnL.js → activity-CeM7xly8.js} +1 -1
  160. package/static/auth-callback/assets/ai-connections-C6yaE6WQ.js +1 -0
  161. package/static/auth-callback/assets/{auth-callback-CAFZ3R0B.js → auth-callback-DTG8cSj7.js} +3 -3
  162. package/static/auth-callback/assets/{badge-CAIPI0CB.js → badge-qJo2Zr4d.js} +1 -1
  163. package/static/auth-callback/assets/{collection-runtime-D9s7h9YA.js → collection-runtime-Bztsz31a.js} +1 -1
  164. package/static/auth-callback/assets/{dialog-BjA109aX.js → dialog-D-h6x5x0.js} +1 -1
  165. package/static/auth-callback/assets/{download-B3Up5W2G.js → download-C2ir4lmR.js} +1 -1
  166. package/static/auth-callback/assets/{external-link-BTXgSPzB.js → external-link-THLDL4On.js} +1 -1
  167. package/static/auth-callback/assets/{index-CirW4CJf.js → index-BRpv4yO3.js} +1 -1
  168. package/static/auth-callback/assets/{index-BppXlxcp.js → index-BlVZb9A7.js} +1 -1
  169. package/static/auth-callback/assets/index-D983R1FV.js +4 -0
  170. package/static/auth-callback/assets/{index-browser-DtU38ni3.js → index-browser-3FvR0aaf.js} +1 -1
  171. package/static/auth-callback/assets/{key-round-CQCOrZ7x.js → key-round-C9U5j1Ly.js} +1 -1
  172. package/static/auth-callback/assets/{rotate-ccw-C1zM2KtS.js → rotate-ccw-DP45cD4o.js} +1 -1
  173. package/static/auth-callback/assets/{skeleton-Cqp7_M9-.js → skeleton-Dn4EiSCS.js} +1 -1
  174. package/static/auth-callback/assets/{waypoints-Bj6gAUSQ.js → waypoints-uqFQ3uEG.js} +1 -1
  175. package/static/auth-callback/assets/{workspace-layout-DK8mDzrY.js → workspace-layout-DLYK0Wwu.js} +1 -1
  176. package/static/auth-callback/auth-callback.html +1 -1
  177. package/static/dashboard/assets/{AiConfigContext-BsE7MqX8.js → AiConfigContext-DJcMECNw.js} +1 -1
  178. package/static/dashboard/assets/{AiConfigPage-DvM-lRXa.js → AiConfigPage-BvE7dOTy.js} +1 -1
  179. package/static/dashboard/assets/{DocumentProcessingPanel-BPfdlfuf.js → DocumentProcessingPanel-D9780krf.js} +1 -1
  180. package/static/dashboard/assets/{IndexLifecyclePanel--m0AGxvh.js → IndexLifecyclePanel-SjsUcnbM.js} +1 -1
  181. package/static/dashboard/assets/{IndexSubjectPanel-Bb7m1k3d.js → IndexSubjectPanel-C-ym2Tqi.js} +1 -1
  182. package/static/dashboard/assets/{ModelAssignmentsPanel-BLi_zbMa.js → ModelAssignmentsPanel-BRjZ-arB.js} +1 -1
  183. package/static/dashboard/assets/{ModelsPage-CxdpgnfR.js → ModelsPage-BtTU6du3.js} +6 -6
  184. package/static/dashboard/assets/NetworkPage-CV9qpkDg.js +2 -0
  185. package/static/dashboard/assets/{PaneListHeader-BBCMei0r.js → PaneListHeader-KyPTTBsv.js} +1 -1
  186. package/static/dashboard/assets/{SearchIndexingPanel-Ck4Y-xjR.js → SearchIndexingPanel-DolHGawg.js} +1 -1
  187. package/static/dashboard/assets/{StatusSubjectPanel-D1KWfAXE.js → StatusSubjectPanel-_YZvKiYi.js} +1 -1
  188. package/static/dashboard/assets/{StatusWorkspace-JbA5gzXx.js → StatusWorkspace-Dlbh_G40.js} +1 -1
  189. package/static/dashboard/assets/{SystemSettingsPage-BbwQWsSR.js → SystemSettingsPage-Be7QSIoz.js} +1 -1
  190. package/static/dashboard/assets/{SystemSettingsSubjectPanel-N117nMt5.js → SystemSettingsSubjectPanel-DBp0gja7.js} +1 -1
  191. package/static/dashboard/assets/{XpodAiConnectionsPodStore-CdDOb4SV.js → XpodAiConnectionsPodStore-ClpSjzpP.js} +7 -7
  192. package/static/dashboard/assets/{activity-DX1I96o_.js → activity-lsNbTXJu.js} +1 -1
  193. package/static/dashboard/assets/ai-connections-CXp5gd1J.js +1 -0
  194. package/static/dashboard/assets/{badge-k2vhtDqH.js → badge-CVatKjaG.js} +1 -1
  195. package/static/dashboard/assets/{collection-runtime-BFQ8teQJ.js → collection-runtime-Ec4UnY28.js} +1 -1
  196. package/static/dashboard/assets/{dashboard-DWZ-fmCT.js → dashboard-BEzsRsvF.js} +2 -2
  197. package/static/dashboard/assets/{dialog-1CCw-iHT.js → dialog-BuyelQ4V.js} +1 -1
  198. package/static/dashboard/assets/{download-C6-SNY1q.js → download-B4Nf678F.js} +1 -1
  199. package/static/dashboard/assets/{external-link-BgPcZ_j2.js → external-link-PYv9CvKL.js} +1 -1
  200. package/static/dashboard/assets/index-C9XPE-mI.js +4 -0
  201. package/static/dashboard/assets/{index-D7A8U6Pt.js → index-Cx69bTNh.js} +1 -1
  202. package/static/dashboard/assets/{index-6LcIUIYO.js → index-awr7ulur.js} +1 -1
  203. package/static/dashboard/assets/{key-round-BOd7Jo0Q.js → key-round-VsY80U1Z.js} +1 -1
  204. package/static/dashboard/assets/{rotate-ccw-CCgJqsvx.js → rotate-ccw-Cz1K4vE9.js} +1 -1
  205. package/static/dashboard/assets/{skeleton-Bc7abAn5.js → skeleton-BhNv_8tO.js} +1 -1
  206. package/static/dashboard/assets/{waypoints-s-opmJxx.js → waypoints-DYS9XFYV.js} +1 -1
  207. package/static/dashboard/assets/{workspace-layout-DqIQeTBV.js → workspace-layout-OZJAFx5V.js} +1 -1
  208. package/static/dashboard/dashboard.html +1 -1
  209. package/static/settings/assets/{AiConfigContext-BB9KZySa.js → AiConfigContext-B8JS3MXF.js} +1 -1
  210. package/static/settings/assets/{AiConfigPage-DGSXUkLs.js → AiConfigPage-C3Zl8LUl.js} +1 -1
  211. package/static/settings/assets/{DocumentProcessingPanel-Da2Re6Rg.js → DocumentProcessingPanel-DpDZAQvf.js} +1 -1
  212. package/static/settings/assets/{IndexLifecyclePanel-BSZuIzgr.js → IndexLifecyclePanel-Ec1XF88t.js} +1 -1
  213. package/static/settings/assets/{IndexSubjectPanel-CFd0ay-r.js → IndexSubjectPanel-BulT9BmO.js} +1 -1
  214. package/static/settings/assets/{ModelAssignmentsPanel-CSAryvWJ.js → ModelAssignmentsPanel-BcGSmYjb.js} +1 -1
  215. package/static/settings/assets/{ModelsPage-BQwCwLHU.js → ModelsPage-CvTCKy1T.js} +6 -6
  216. package/static/settings/assets/NetworkPage-DQF5u9Bn.js +2 -0
  217. package/static/settings/assets/{PaneListHeader-Bjh3hRdQ.js → PaneListHeader-D40hqcVl.js} +1 -1
  218. package/static/settings/assets/{SearchIndexingPanel-MjKL5QLU.js → SearchIndexingPanel-iCUPOx_0.js} +1 -1
  219. package/static/settings/assets/{StatusSubjectPanel-Bvl6K4mx.js → StatusSubjectPanel-E--ZHSql.js} +1 -1
  220. package/static/settings/assets/{StatusWorkspace-B0NzrP--.js → StatusWorkspace-YjDAx1II.js} +1 -1
  221. package/static/settings/assets/{SystemSettingsPage-D2z6Z4FE.js → SystemSettingsPage-CDdV3mC9.js} +1 -1
  222. package/static/settings/assets/{SystemSettingsSubjectPanel-4sxma4X4.js → SystemSettingsSubjectPanel-Br8WazDq.js} +1 -1
  223. package/static/settings/assets/XpodAiConnectionsPodStore-CLr38P_Z.js +3 -0
  224. package/static/settings/assets/{activity-CgJJGpjx.js → activity-C5DAHHTE.js} +1 -1
  225. package/static/settings/assets/ai-connections-C6yaE6WQ.js +1 -0
  226. package/static/settings/assets/{badge-C4NypVyT.js → badge-D8eIyxKt.js} +1 -1
  227. package/static/settings/assets/{collection-runtime-CTLCDxAi.js → collection-runtime-DLc9zil8.js} +1 -1
  228. package/static/settings/assets/{dialog-Csq0vWUi.js → dialog-CyuR7Va4.js} +1 -1
  229. package/static/settings/assets/{download-DaLJJ-Wp.js → download-c0oxZrCz.js} +1 -1
  230. package/static/settings/assets/{external-link--w_iW5Au.js → external-link-D3Z34fP_.js} +1 -1
  231. package/static/settings/assets/{index-BukHiu4y.js → index-CKGbRFlc.js} +1 -1
  232. package/static/settings/assets/index-CSr3-2Cj.js +4 -0
  233. package/static/settings/assets/{index-COmVnZi2.js → index-ComidxAm.js} +1 -1
  234. package/static/settings/assets/{index-browser-BGpvHwD0.js → index-browser-CAscEbae.js} +1 -1
  235. package/static/settings/assets/{key-round-Bk4YRjBu.js → key-round-DyjLmXuB.js} +1 -1
  236. package/static/settings/assets/{rotate-ccw-TCabbqsr.js → rotate-ccw-679HF_ec.js} +1 -1
  237. package/static/settings/assets/{settings-CJWpdbNC.js → settings-DKknqu4C.js} +3 -3
  238. package/static/settings/assets/{skeleton-JDHYVe7t.js → skeleton-CkopNkPB.js} +1 -1
  239. package/static/settings/assets/{waypoints-DDvEl-MU.js → waypoints-CrqfAftE.js} +1 -1
  240. package/static/settings/assets/{workspace-layout-DV5QU30U.js → workspace-layout-UN6c4qTG.js} +1 -1
  241. package/static/settings/settings.html +1 -1
  242. package/static/auth-callback/assets/NetworkPage-B3qBfANA.js +0 -2
  243. package/static/auth-callback/assets/XpodAiConnectionsPodStore-BJiXm-PF.js +0 -3
  244. package/static/auth-callback/assets/ai-connections-CryuHGKW.js +0 -1
  245. package/static/auth-callback/assets/index-DlLYWOhw.js +0 -4
  246. package/static/dashboard/assets/NetworkPage-BAIPw-D_.js +0 -2
  247. package/static/dashboard/assets/ai-connections-DwCRqOQa.js +0 -1
  248. package/static/dashboard/assets/index-UD6QOE7H.js +0 -4
  249. package/static/settings/assets/NetworkPage-BKymvsQc.js +0 -2
  250. package/static/settings/assets/XpodAiConnectionsPodStore-BkNQ8fZx.js +0 -3
  251. package/static/settings/assets/ai-connections-CryuHGKW.js +0 -1
  252. package/static/settings/assets/index-B0mQa59b.js +0 -4
  253. /package/node_modules/@undefineds.co/ai-connections/dist/{client → contract/client}/request.d.ts +0 -0
  254. /package/node_modules/@undefineds.co/ai-connections/dist/{client → contract/client}/types.js +0 -0
  255. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/base-adapter.d.ts +0 -0
  256. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/base-adapter.js +0 -0
  257. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/codex.d.ts +0 -0
  258. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/codex.js +0 -0
  259. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/index.d.ts +0 -0
  260. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/index.js +0 -0
  261. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/json-env-adapter.d.ts +0 -0
  262. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/json-env-adapter.js +0 -0
  263. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/pi.d.ts +0 -0
  264. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/pi.js +0 -0
  265. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/transaction.d.ts +0 -0
  266. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/transaction.js +0 -0
  267. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/types.d.ts +0 -0
  268. /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/types.js +0 -0
  269. /package/node_modules/@undefineds.co/ai-connections/dist/{credential-storage.d.ts → contract/credential-storage.d.ts} +0 -0
  270. /package/node_modules/@undefineds.co/ai-connections/dist/{credential-storage.js → contract/credential-storage.js} +0 -0
  271. /package/node_modules/@undefineds.co/ai-connections/dist/{endpoint-urls.d.ts → contract/endpoint-urls.d.ts} +0 -0
  272. /package/node_modules/@undefineds.co/ai-connections/dist/{endpoint-urls.js → contract/endpoint-urls.js} +0 -0
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LocalTunnelProvider = void 0;
4
+ exports.readDashboardOrigin = readDashboardOrigin;
4
5
  const node_child_process_1 = require("node:child_process");
5
6
  const global_logger_factory_1 = require("global-logger-factory");
7
+ const TunnelLifecycle_1 = require("./TunnelLifecycle");
6
8
  /** cloudflared metrics 端口 */
7
9
  const CLOUDFLARED_METRICS_PORT = 33863;
8
10
  /**
@@ -31,6 +33,7 @@ class LocalTunnelProvider {
31
33
  this.tunnelToken = options.tunnelToken;
32
34
  this.publicUrl = normalizePublicEndpoint(options.publicUrl);
33
35
  this.cloudflaredPath = options.cloudflaredPath ?? 'cloudflared';
36
+ this.connectTimeoutMs = options.connectTimeoutMs ?? 30_000;
34
37
  }
35
38
  /**
36
39
  * Local 模式不需要 setup,直接返回基于 Token 的配置
@@ -71,7 +74,7 @@ class LocalTunnelProvider {
71
74
  throw new Error('Tunnel token is required');
72
75
  }
73
76
  this.logger.info('Starting cloudflared tunnel...');
74
- this.status = { running: true, connected: false };
77
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('process-started', { endpoint: this.status.endpoint });
75
78
  this.managedByUs = true;
76
79
  const args = [
77
80
  'tunnel',
@@ -92,10 +95,13 @@ class LocalTunnelProvider {
92
95
  if (output) {
93
96
  this.logOutput(output);
94
97
  }
95
- // 检测连接成功
96
- if (output.includes('Connection registered') || output.includes('Registered tunnel connection')) {
97
- this.status.connected = true;
98
- this.status.lastHeartbeat = new Date();
98
+ // 检测连接成功:只有连接注册成功才代表代理已发布
99
+ if (output.includes('Registered tunnel connection') || output.includes('Connection registered')) {
100
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('proxy-ready', {
101
+ endpoint: this.status.endpoint,
102
+ lastHeartbeat: new Date(),
103
+ error: this.status.error,
104
+ });
99
105
  this.logger.info('Tunnel connected successfully');
100
106
  }
101
107
  });
@@ -106,10 +112,31 @@ class LocalTunnelProvider {
106
112
  this.logOutput(output);
107
113
  // 检测连接成功
108
114
  if (output.includes('Registered tunnel connection') || output.includes('Connection registered')) {
109
- this.status.connected = true;
110
- this.status.lastHeartbeat = new Date();
115
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('proxy-ready', {
116
+ endpoint: this.status.endpoint,
117
+ lastHeartbeat: new Date(),
118
+ error: this.status.error ?? this.originMismatch,
119
+ });
111
120
  // logOutput 已经打印了信息,这里不需要重复打印
112
121
  }
122
+ // A remotely-managed tunnel forwards to the port the dashboard declares, which is
123
+ // not the port we dialled if the operator never matched them: naming that mismatch
124
+ // is the difference between "the entry is unreachable" and a fixable configuration.
125
+ const declared = readDashboardOrigin(output);
126
+ if (declared !== undefined) {
127
+ const dialled = this.currentConfig?.originUrl;
128
+ // Scheme matters as much as the port: an https service pointed at this plain-HTTP
129
+ // ingress listener fails the handshake, which the edge reports as a bare 502.
130
+ this.originMismatch = dialled && (declared.port !== readPort(dialled) || declared.scheme !== readScheme(dialled))
131
+ ? `origin-mismatch:dashboard=${declared.scheme}://localhost:${declared.port},runtime=${dialled}`
132
+ : undefined;
133
+ if (this.originMismatch) {
134
+ this.logger.warn(`The Cloudflare dashboard forwards this hostname to ${declared.scheme}://localhost:${declared.port}, but this runtime serves ${dialled}: set the dashboard service to that address`);
135
+ }
136
+ if (this.status.stage === 'proxy-ready') {
137
+ this.status.error = this.originMismatch ?? this.status.error;
138
+ }
139
+ }
113
140
  // 检测错误
114
141
  if (output.includes('ERR') || output.includes('failed')) {
115
142
  this.status.error = output;
@@ -118,24 +145,25 @@ class LocalTunnelProvider {
118
145
  });
119
146
  this.process.on('exit', (code) => {
120
147
  this.logger.info(`Process exited with code ${code}`);
121
- this.status = { running: false, connected: false };
148
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('failed', {
149
+ endpoint: this.status.endpoint,
150
+ error: this.status.error ?? (code === 0 ? 'cloudflared-exited' : `cloudflared exited with code ${code}`),
151
+ });
122
152
  this.process = null;
123
153
  this.managedByUs = false;
124
154
  });
125
155
  this.process.on('error', (error) => {
126
- this.logger.error(`Failed to start: ${error.message}`);
127
- this.status = { running: false, connected: false, error: error.message };
156
+ const described = (0, TunnelLifecycle_1.describeSpawnError)('cloudflare', this.cloudflaredPath, error);
157
+ this.logger.error(`Failed to start: ${described}`);
158
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('failed', { endpoint: this.status.endpoint, error: described });
128
159
  this.process = null;
129
160
  this.managedByUs = false;
130
161
  });
131
162
  this.currentConfig = actualConfig;
132
163
  this.status.endpoint = actualConfig.endpoint;
133
164
  // 等待连接建立
134
- await this.waitForConnection();
165
+ await this.waitForConnection(this.connectTimeoutMs);
135
166
  }
136
- /**
137
- * 解析并打印 cloudflared 日志
138
- */
139
167
  logOutput(raw) {
140
168
  const lines = raw.split('\n');
141
169
  for (const line of lines) {
@@ -174,7 +202,8 @@ class LocalTunnelProvider {
174
202
  async stop() {
175
203
  if (!this.managedByUs) {
176
204
  this.logger.info('Not managed by us, skipping stop');
177
- this.status = { running: false, connected: false };
205
+ // Keep the last error: stopping must not launder a failed tunnel into a clean one.
206
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('stopped', { endpoint: this.status.endpoint, error: this.status.error });
178
207
  return;
179
208
  }
180
209
  if (this.process) {
@@ -195,7 +224,7 @@ class LocalTunnelProvider {
195
224
  this.process = null;
196
225
  this.logger.info('Tunnel stopped');
197
226
  }
198
- this.status = { running: false, connected: false };
227
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('stopped', { endpoint: this.status.endpoint, error: this.status.error });
199
228
  this.managedByUs = false;
200
229
  }
201
230
  /**
@@ -280,8 +309,13 @@ class LocalTunnelProvider {
280
309
  }
281
310
  await new Promise((r) => setTimeout(r, 500));
282
311
  }
283
- // 超时不抛错,cloudflared 可能还在连接中
284
- this.logger.warn('Connection timeout, tunnel may still be connecting...');
312
+ // A timeout is a fact the caller has to see: the process exists but nothing is
313
+ // published yet, so the tunnel is not ready.
314
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('failed', {
315
+ endpoint: this.status.endpoint,
316
+ error: this.status.error ?? 'cloudflared-connect-timeout',
317
+ });
318
+ this.logger.warn('cloudflared did not register a tunnel connection before the timeout');
285
319
  }
286
320
  /**
287
321
  * 获取是否由我们管理
@@ -306,4 +340,39 @@ function normalizePublicEndpoint(value) {
306
340
  return value.trim();
307
341
  }
308
342
  }
343
+ /**
344
+ * The origin a remotely-managed tunnel declares for its hostname.
345
+ *
346
+ * Both halves are reported: pointing the dashboard at `https://localhost:<port>` while this
347
+ * runtime serves plain HTTP there fails the TLS handshake, and the edge shows only a 502.
348
+ */
349
+ function readDashboardOrigin(output) {
350
+ const match = /"service"\s*:\s*"(https?):\/\/(?:localhost|127\.0\.0\.1):(\d+)/iu.exec(output)
351
+ ?? /ingress[^\n]*service["']?\s*[:=]\s*["']?(https?):\/\/(?:localhost|127\.0\.0\.1):(\d+)/iu.exec(output);
352
+ if (!match) {
353
+ return undefined;
354
+ }
355
+ const port = Number.parseInt(match[2], 10);
356
+ return Number.isInteger(port) && port > 0 ? { scheme: match[1].toLowerCase(), port } : undefined;
357
+ }
358
+ function readPort(value) {
359
+ if (!value)
360
+ return undefined;
361
+ try {
362
+ return Number.parseInt(new URL(value).port, 10) || undefined;
363
+ }
364
+ catch {
365
+ return undefined;
366
+ }
367
+ }
368
+ function readScheme(value) {
369
+ if (!value)
370
+ return undefined;
371
+ try {
372
+ return new URL(value).protocol.replace(':', '');
373
+ }
374
+ catch {
375
+ return undefined;
376
+ }
377
+ }
309
378
  //# sourceMappingURL=LocalTunnelProvider.js.map
@@ -43,6 +43,19 @@
43
43
  ]
44
44
  },
45
45
  "comment": "cloudflared 可执行文件路径 (默认 'cloudflared')"
46
+ },
47
+ {
48
+ "@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider_options_connectTimeoutMs",
49
+ "range": {
50
+ "@type": "ParameterRangeUnion",
51
+ "parameterRangeElements": [
52
+ "xsd:number",
53
+ {
54
+ "@type": "ParameterRangeUndefined"
55
+ }
56
+ ]
57
+ },
58
+ "comment": "等待代理发布的毫秒数;超时后状态为 failed,而不是\"仍在连接\""
46
59
  }
47
60
  ],
48
61
  "memberFields": [
@@ -66,6 +79,10 @@
66
79
  "@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider__member_cloudflaredPath",
67
80
  "memberFieldName": "cloudflaredPath"
68
81
  },
82
+ {
83
+ "@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider__member_connectTimeoutMs",
84
+ "memberFieldName": "connectTimeoutMs"
85
+ },
69
86
  {
70
87
  "@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider__member_process",
71
88
  "memberFieldName": "process"
@@ -94,6 +111,10 @@
94
111
  "@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider__member_start",
95
112
  "memberFieldName": "start"
96
113
  },
114
+ {
115
+ "@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider__member_originMismatch",
116
+ "memberFieldName": "originMismatch"
117
+ },
97
118
  {
98
119
  "@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider__member_logOutput",
99
120
  "memberFieldName": "logOutput"
@@ -156,6 +177,12 @@
156
177
  "value": {
157
178
  "@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider_options_cloudflaredPath"
158
179
  }
180
+ },
181
+ {
182
+ "keyRaw": "connectTimeoutMs",
183
+ "value": {
184
+ "@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider_options_connectTimeoutMs"
185
+ }
159
186
  }
160
187
  ]
161
188
  }
@@ -31,6 +31,8 @@ export declare class NgrokTunnelProvider implements TunnelProvider {
31
31
  private status;
32
32
  private currentConfig;
33
33
  private managedByUs;
34
+ /** Origin this instance asked ngrok to expose; the agent answer must match it. */
35
+ private expectedLocalOrigin?;
34
36
  constructor(options?: NgrokTunnelProviderOptions);
35
37
  setup(options: TunnelSetupOptions): Promise<TunnelConfig>;
36
38
  start(config?: TunnelConfig): Promise<void>;
@@ -44,3 +46,5 @@ export declare class NgrokTunnelProvider implements TunnelProvider {
44
46
  private waitForConnection;
45
47
  private discoverEndpointFromAgentApi;
46
48
  }
49
+ /** Loopback endpoints belong to the agent itself, never to a published tunnel. */
50
+ export declare function isLocalAgentUrl(url: string): boolean;
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NgrokTunnelProvider = void 0;
4
+ exports.isLocalAgentUrl = isLocalAgentUrl;
4
5
  const node_child_process_1 = require("node:child_process");
5
6
  const global_logger_factory_1 = require("global-logger-factory");
7
+ const TunnelLifecycle_1 = require("./TunnelLifecycle");
6
8
  /**
7
9
  * Starts a user-owned ngrok agent for Local SP access.
8
10
  *
@@ -37,6 +39,7 @@ class NgrokTunnelProvider {
37
39
  endpoint: normalizeEndpointForConfig(this.configuredUrl) ?? '',
38
40
  originUrl,
39
41
  };
42
+ this.expectedLocalOrigin = originUrl;
40
43
  this.currentConfig = config;
41
44
  return config;
42
45
  }
@@ -59,11 +62,9 @@ class NgrokTunnelProvider {
59
62
  args.push('--url', endpointForCli);
60
63
  }
61
64
  args.push(actualConfig.originUrl);
62
- this.status = {
63
- running: true,
64
- connected: false,
65
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('process-started', {
65
66
  endpoint: normalizeEndpointForConfig(endpointForCli),
66
- };
67
+ });
67
68
  this.currentConfig = {
68
69
  ...actualConfig,
69
70
  endpoint: this.status.endpoint ?? actualConfig.endpoint,
@@ -81,23 +82,20 @@ class NgrokTunnelProvider {
81
82
  this.process.stderr?.on('data', (data) => this.handleOutput(data.toString()));
82
83
  this.process.on('exit', (code) => {
83
84
  this.logger.info(`ngrok exited with code ${code}`);
84
- this.status = {
85
- running: false,
86
- connected: false,
85
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('failed', {
87
86
  endpoint: this.status.endpoint,
88
- error: this.status.error ?? (code === 0 ? undefined : `ngrok exited with code ${code}`),
89
- };
87
+ error: this.status.error ?? (code === 0 ? 'ngrok-exited' : `ngrok exited with code ${code}`),
88
+ });
90
89
  this.process = null;
91
90
  this.managedByUs = false;
92
91
  });
93
92
  this.process.on('error', (error) => {
94
- this.logger.error(`Failed to start ngrok: ${error.message}`);
95
- this.status = {
96
- running: false,
97
- connected: false,
93
+ const described = (0, TunnelLifecycle_1.describeSpawnError)('ngrok', this.ngrokPath, error);
94
+ this.logger.error(`Failed to start ngrok: ${described}`);
95
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('failed', {
98
96
  endpoint: this.status.endpoint,
99
- error: error.message,
100
- };
97
+ error: described,
98
+ });
101
99
  this.process = null;
102
100
  this.managedByUs = false;
103
101
  });
@@ -105,7 +103,8 @@ class NgrokTunnelProvider {
105
103
  }
106
104
  async stop() {
107
105
  if (!this.managedByUs) {
108
- this.status = { running: false, connected: false, endpoint: this.status.endpoint };
106
+ // Keep the last error: stopping must not turn a failed tunnel into a clean one.
107
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('stopped', { endpoint: this.status.endpoint, error: this.status.error });
109
108
  return;
110
109
  }
111
110
  if (this.process) {
@@ -122,7 +121,7 @@ class NgrokTunnelProvider {
122
121
  });
123
122
  this.process = null;
124
123
  }
125
- this.status = { running: false, connected: false, endpoint: this.status.endpoint };
124
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('stopped', { endpoint: this.status.endpoint, error: this.status.error });
126
125
  this.managedByUs = false;
127
126
  }
128
127
  getStatus() {
@@ -158,17 +157,36 @@ class NgrokTunnelProvider {
158
157
  }
159
158
  }
160
159
  markConnected(endpoint) {
161
- const normalized = normalizeEndpointForConfig(endpoint);
162
- if (!normalized) {
160
+ // Readiness requires a process we still own: without one, any endpoint we just learned
161
+ // about (for example from the machine-wide agent API) belongs to someone else.
162
+ if (!this.process || !this.managedByUs) {
163
+ return;
164
+ }
165
+ const discovered = normalizeEndpointForConfig(endpoint);
166
+ const declared = normalizeEndpointForConfig(this.configuredUrl);
167
+ // A discovered entry has to be a real public endpoint: the local agent's own web
168
+ // interface is not one, and accepting it made a tunnel that published nothing look up.
169
+ if (!declared && (!discovered || isLocalAgentUrl(discovered))) {
163
170
  return;
164
171
  }
165
- this.status.connected = true;
166
- this.status.endpoint = normalized;
167
- this.status.lastHeartbeat = new Date();
172
+ const effective = declared ?? discovered;
173
+ if (!effective) {
174
+ return;
175
+ }
176
+ if (declared && discovered && normalizeOrigin(declared) !== normalizeOrigin(discovered)) {
177
+ // The operator declared one entry and ngrok published another; report the declared
178
+ // one but leave the discrepancy in the log for whoever has to explain reachability.
179
+ this.logger.warn(`ngrok published ${discovered} while ${declared} is declared; keeping the declared entry`);
180
+ }
181
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('proxy-ready', {
182
+ endpoint: effective,
183
+ lastHeartbeat: new Date(),
184
+ error: this.status.error,
185
+ });
168
186
  this.currentConfig = {
169
- ...(this.currentConfig ?? { subdomain: 'local', provider: 'ngrok', endpoint: normalized }),
187
+ ...(this.currentConfig ?? { subdomain: 'local', provider: 'ngrok', endpoint: effective }),
170
188
  provider: 'ngrok',
171
- endpoint: normalized,
189
+ endpoint: effective,
172
190
  };
173
191
  }
174
192
  async waitForConnection() {
@@ -180,49 +198,71 @@ class NgrokTunnelProvider {
180
198
  if (!this.status.running && this.status.error) {
181
199
  throw new Error(`ngrok failed to start: ${this.status.error}`);
182
200
  }
183
- const endpoint = await this.discoverEndpointFromAgentApi();
184
- if (endpoint) {
185
- this.markConnected(endpoint);
186
- return;
201
+ // The agent API is machine-wide: another instance's agent answers on the same port.
202
+ // Only consult it while this provider actually has a process, otherwise a provider
203
+ // that failed to start would adopt someone else's tunnel as its own.
204
+ if (this.process && this.managedByUs) {
205
+ const endpoint = await this.discoverEndpointFromAgentApi();
206
+ if (endpoint) {
207
+ this.markConnected(endpoint);
208
+ // Discovery may have been refused (foreign entry, no live process); only an
209
+ // actual readiness transition ends the wait.
210
+ if (this.status.connected) {
211
+ return;
212
+ }
213
+ }
187
214
  }
188
215
  await new Promise((resolve) => setTimeout(resolve, Math.min(250, Math.max(25, this.connectTimeoutMs))));
189
216
  }
190
217
  if (!this.status.running && this.status.error) {
191
218
  throw new Error(`ngrok failed to start: ${this.status.error}`);
192
219
  }
193
- if (this.status.endpoint) {
194
- this.logger.warn('ngrok connection was not confirmed before timeout; keeping configured endpoint as degraded.');
195
- this.status.connected = false;
196
- return;
197
- }
198
- throw new Error('ngrok connection timeout');
220
+ // A timeout must not be reported as a running tunnel that merely lacks a heartbeat:
221
+ // the endpoint is recorded, but the stage says nothing is serving yet.
222
+ this.status = (0, TunnelLifecycle_1.createTunnelStatus)('failed', {
223
+ endpoint: this.status.endpoint,
224
+ error: this.status.error ?? 'ngrok-connect-timeout',
225
+ });
226
+ throw new Error(`ngrok connection timeout${this.status.endpoint ? ` for ${this.status.endpoint}` : ''}`);
199
227
  }
200
228
  async discoverEndpointFromAgentApi() {
201
229
  const base = this.agentApiUrl.replace(/\/+$/u, '');
202
- return await readNgrokAgentEndpoint(`${base}/api/tunnels`)
203
- ?? await readNgrokAgentEndpoint(`${base}/api/endpoints`);
230
+ return await readNgrokAgentEndpoint(`${base}/api/tunnels`, this.expectedLocalOrigin)
231
+ ?? await readNgrokAgentEndpoint(`${base}/api/endpoints`, this.expectedLocalOrigin);
204
232
  }
205
233
  }
206
234
  exports.NgrokTunnelProvider = NgrokTunnelProvider;
207
- async function readNgrokAgentEndpoint(url) {
235
+ /** Loopback endpoints belong to the agent itself, never to a published tunnel. */
236
+ function isLocalAgentUrl(url) {
237
+ try {
238
+ const { hostname } = new URL(url);
239
+ const normalized = hostname.replace(/^\[/u, '').replace(/\]$/u, '').toLowerCase();
240
+ return normalized === 'localhost' || normalized === '::1' || normalized.startsWith('127.');
241
+ }
242
+ catch {
243
+ return true;
244
+ }
245
+ }
246
+ async function readNgrokAgentEndpoint(url, expectedLocalOrigin) {
208
247
  try {
209
248
  const response = await fetch(url);
210
249
  if (!response.ok) {
211
250
  return undefined;
212
251
  }
213
252
  const body = await response.json();
214
- return extractEndpointFromAgentBody(body);
253
+ return extractEndpointFromAgentBody(body, expectedLocalOrigin);
215
254
  }
216
255
  catch {
217
256
  return undefined;
218
257
  }
219
258
  }
220
- function extractEndpointFromAgentBody(body) {
259
+ function extractEndpointFromAgentBody(body, expectedLocalOrigin) {
221
260
  if (!body || typeof body !== 'object') {
222
261
  return undefined;
223
262
  }
224
263
  const record = body;
225
264
  const lists = [record.tunnels, record.endpoints].filter(Array.isArray);
265
+ const candidates = [];
226
266
  for (const list of lists) {
227
267
  for (const item of list) {
228
268
  if (!item || typeof item !== 'object') {
@@ -232,12 +272,44 @@ function extractEndpointFromAgentBody(body) {
232
272
  const publicUrl = typeof value.public_url === 'string' ? value.public_url : undefined;
233
273
  const url = typeof value.url === 'string' ? value.url : undefined;
234
274
  const endpoint = normalizeEndpointForConfig(publicUrl ?? url);
235
- if (endpoint?.startsWith('https://')) {
236
- return endpoint;
275
+ if (!endpoint?.startsWith('https://') || isLocalAgentUrl(endpoint)) {
276
+ continue;
237
277
  }
278
+ const config = value.config;
279
+ const address = config && typeof config === 'object'
280
+ ? config.addr
281
+ : undefined;
282
+ candidates.push({ endpoint, ...(typeof address === 'string' ? { address } : {}) });
238
283
  }
239
284
  }
240
- return undefined;
285
+ if (candidates.length === 0) {
286
+ return undefined;
287
+ }
288
+ if (!expectedLocalOrigin) {
289
+ return candidates[0].endpoint;
290
+ }
291
+ // An entry exposing our own origin is ours. When the agent reports no address at all we
292
+ // can only accept it if there is exactly one candidate, otherwise ownership is a guess.
293
+ const matched = candidates.find((candidate) => candidate.address
294
+ && normalizeOrigin(candidate.address) === normalizeOrigin(expectedLocalOrigin));
295
+ if (matched) {
296
+ return matched.endpoint;
297
+ }
298
+ return candidates.length === 1 && !candidates[0].address ? candidates[0].endpoint : undefined;
299
+ }
300
+ function normalizeOrigin(value) {
301
+ try {
302
+ const url = new URL(value);
303
+ const hostname = url.hostname.replace(/^\[/u, '').replace(/\]$/u, '').toLowerCase();
304
+ // `localhost`, `::1` and `127.x` are the same machine; agents spell them differently.
305
+ const host = hostname === 'localhost' || hostname === '::1' || hostname.startsWith('127.')
306
+ ? '127.0.0.1'
307
+ : hostname;
308
+ return `${url.protocol}//${host}:${url.port || (url.protocol === 'https:' ? '443' : '80')}`;
309
+ }
310
+ catch {
311
+ return value.trim().replace(/\/+$/u, '');
312
+ }
241
313
  }
242
314
  function extractEndpoint(output) {
243
315
  try {
@@ -261,10 +333,12 @@ function extractEndpointFromText(value) {
261
333
  }
262
334
  function isConnectionLine(output) {
263
335
  const lower = output.toLowerCase();
336
+ // A bare "started" is not evidence that a tunnel exists: the agent logs it for its own
337
+ // web interface as well.
264
338
  return lower.includes('started tunnel')
265
339
  || lower.includes('tunnel started')
266
340
  || lower.includes('client session established')
267
- || lower.includes('started');
341
+ || lower.includes('started tunnel session');
268
342
  }
269
343
  function extractError(output) {
270
344
  try {
@@ -124,6 +124,10 @@
124
124
  "@id": "undefineds:dist/tunnel/NgrokTunnelProvider.jsonld#NgrokTunnelProvider__member_managedByUs",
125
125
  "memberFieldName": "managedByUs"
126
126
  },
127
+ {
128
+ "@id": "undefineds:dist/tunnel/NgrokTunnelProvider.jsonld#NgrokTunnelProvider__member_expectedLocalOrigin",
129
+ "memberFieldName": "expectedLocalOrigin"
130
+ },
127
131
  {
128
132
  "@id": "undefineds:dist/tunnel/NgrokTunnelProvider.jsonld#NgrokTunnelProvider__member_constructor",
129
133
  "memberFieldName": "constructor"
@@ -4,21 +4,30 @@
4
4
  * 使用 SakuraFRP 提供隧道服务
5
5
  * 用于没有公网 IP 的 Local 节点
6
6
  *
7
- * 需要用户在 SakuraFRP 控制台创建隧道并获取 Token
7
+ * 凭据就是控制台「配置文件」里那串启动参数 (`<访问密钥>:<隧道ID>`)。公网入口
8
+ * **不由用户声明**:控制台只让用户选节点和本地端口,访问地址是平台分配的,因此
9
+ * provider 用同一个凭据向 SakuraFrp 开放 API 查询分配结果(节点地址 + 远程端口),
10
+ * 声明字段只作为 API 不可用时的可选兜底。
8
11
  */
9
12
  import type { TunnelProvider, TunnelConfig, TunnelSetupOptions, TunnelStatus } from './TunnelProvider';
10
13
  /**
11
14
  * SakuraFRP Tunnel Provider 配置
12
15
  */
13
16
  export interface SakuraFrpTunnelProviderOptions {
14
- /** SakuraFRP Token (从环境变量 SAKURA_TUNNEL_TOKEN 获取) */
17
+ /** SakuraFRP 启动参数 (`<访问密钥>:<隧道ID>[,<隧道ID>...]`),来自 SAKURA_TUNNEL_TOKEN */
15
18
  token: string;
16
- /** Active profile public endpoint, shown in status and DDNS diagnostics. */
19
+ /** Optional declared endpoint, used only when the provider cannot be asked. */
17
20
  publicUrl?: string;
18
21
  /** frpc 可执行文件路径 (默认 'frpc') */
19
22
  frpcPath?: string;
23
+ /** 等待代理发布的毫秒数;超时后状态为 failed */
24
+ connectTimeoutMs?: number;
20
25
  /** SakuraFRP 服务端地址 (如果需要自定义) */
21
26
  serverAddr?: string;
27
+ /** SakuraFrp open API base, where the assigned public entry can be read back. */
28
+ apiBaseUrl?: string;
29
+ /** Injection point for tests; defaults to the global fetch. */
30
+ fetchImpl?: typeof fetch;
22
31
  }
23
32
  /**
24
33
  * SakuraFRP Tunnel Provider
@@ -31,12 +40,49 @@ export declare class SakuraFrpTunnelProvider implements TunnelProvider {
31
40
  private readonly token;
32
41
  private readonly publicUrl?;
33
42
  private readonly frpcPath;
43
+ private readonly connectTimeoutMs;
34
44
  private readonly serverAddr?;
45
+ private readonly apiBaseUrl;
46
+ private readonly fetchImpl;
47
+ /** Endpoint the platform assigned, once discovery has answered. */
48
+ private discoveredEndpoint?;
49
+ /** Credential actually handed to frpc, completed from the platform answer when needed. */
50
+ private clientCredential?;
51
+ /** Why no browser-facing entry can be claimed, when the platform refuses plain HTTP. */
52
+ private discoveryBlockedReason?;
53
+ /** Whether the platform terminates TLS for this entry (auto HTTPS). */
54
+ private autoHttpsEnabled;
55
+ /** Entry the client itself printed, used when the platform API cannot name one. */
56
+ private logEndpoint?;
35
57
  private process;
36
58
  private status;
37
59
  private currentConfig;
38
60
  private managedByUs;
39
61
  constructor(options: SakuraFrpTunnelProviderOptions);
62
+ /**
63
+ * Reads back the entry the platform assigned to this tunnel.
64
+ *
65
+ * The console never asks for a domain: for a TCP tunnel it assigns a node host and a
66
+ * remote port, and for a bound tunnel it assigns the domain itself. Asking the provider
67
+ * is therefore the only honest way to learn the entry, and a failure to ask changes
68
+ * nothing except that the status stops short of naming an endpoint.
69
+ */
70
+ private discoverEndpoint;
71
+ /**
72
+ * Builds the parameter frpc needs, completing a bare access key with the tunnel it owns.
73
+ *
74
+ * `-f` accepts `<访问密钥>:<隧道ID>`; an operator who pasted only the access key would
75
+ * otherwise get `Bad fetch parameter` even though discovery can read the tunnel with that
76
+ * same key. Completion is only safe when the answer is unambiguous.
77
+ */
78
+ private resolveClientCredential;
79
+ private resolveNodeHost;
80
+ private fetchJson;
81
+ /**
82
+ * The endpoint to report: what the platform assigned, else what the client printed, else
83
+ * what was declared. Nothing is invented when no source names an entry.
84
+ */
85
+ private currentEndpoint;
40
86
  /**
41
87
  * Setup: 解析 Token 获取配置
42
88
  */
@@ -60,3 +106,19 @@ export declare class SakuraFrpTunnelProvider implements TunnelProvider {
60
106
  private waitForConnection;
61
107
  isManagedByUs(): boolean;
62
108
  }
109
+ /**
110
+ * The local port the SakuraFrp console told the tunnel to forward to.
111
+ *
112
+ * The console already owns this fact, and the provider reads the same API for the public
113
+ * entry, so the runtime must take the port from there instead of asking the operator to type
114
+ * it a second time.
115
+ */
116
+ export declare function resolveSakuraAssignedLocalPort(token: string | undefined, options?: {
117
+ apiBaseUrl?: string;
118
+ fetchImpl?: typeof fetch;
119
+ }): Promise<number | undefined>;
120
+ /** Splits the console's startup parameter into the access key and the tunnel ids. */
121
+ export declare function parseSakuraCredential(value: string | undefined): {
122
+ accessKey?: string;
123
+ tunnelIds: string[];
124
+ };