@undefineds.co/xpod 0.4.13 → 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.
- package/config/components-ignore.json +11 -7
- package/dist/api/ai-gateway/providers/ProviderRegistry.js +1 -1
- package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.d.ts +1 -1
- package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.js +1 -1
- package/dist/api/container/index.js +1 -0
- package/dist/api/container/local.js +30 -12
- package/dist/api/container/routes.js +2 -0
- package/dist/api/container/types.d.ts +2 -0
- package/dist/api/handlers/AdminHandler.d.ts +17 -1
- package/dist/api/handlers/AdminHandler.js +40 -3
- package/dist/api/handlers/EdgeNodeSignalHandler.js +10 -2
- package/dist/api/handlers/NetworkSettingsHandler.d.ts +37 -5
- package/dist/api/handlers/NetworkSettingsHandler.js +39 -11
- package/dist/api/handlers/ProvisionHandler.d.ts +6 -1
- package/dist/api/handlers/ProvisionHandler.js +7 -2
- package/dist/api/handlers/ReachabilityHandler.d.ts +6 -0
- package/dist/api/handlers/ReachabilityHandler.js +22 -5
- package/dist/api/network/NetworkEnvironmentConfigurationStore.d.ts +6 -1
- package/dist/api/network/NetworkEnvironmentConfigurationStore.js +72 -16
- package/dist/api/runtime.d.ts +9 -0
- package/dist/api/runtime.js +15 -2
- package/dist/api/service/AiClientConfigurationService.d.ts +1 -1
- package/dist/api/service/AiClientConfigurationService.js +1 -1
- package/dist/cli/commands/start.d.ts +19 -1
- package/dist/cli/commands/start.js +71 -5
- package/dist/components/context.jsonld +30 -0
- package/dist/edge/EdgeNodeAgent.d.ts +6 -0
- package/dist/edge/EdgeNodeAgent.js +1 -1
- package/dist/edge/EdgeNodeAgentInitializer.d.ts +2 -0
- package/dist/edge/EdgeNodeAgentInitializer.js +1 -0
- package/dist/edge/EdgeNodeAgentInitializer.jsonld +19 -0
- package/dist/edge/EdgeNodeDnsCoordinator.d.ts +11 -1
- package/dist/edge/EdgeNodeDnsCoordinator.js +12 -2
- package/dist/edge/EdgeNodeHealthProbeService.d.ts +15 -0
- package/dist/edge/EdgeNodeHealthProbeService.js +44 -12
- package/dist/edge/EdgeNodeHealthProbeService.jsonld +77 -0
- package/dist/edge/ProbeTargetGuard.d.ts +35 -0
- package/dist/edge/ProbeTargetGuard.js +142 -0
- package/dist/edge/reachability/NodeAccessResolver.d.ts +16 -0
- package/dist/edge/reachability/NodeAccessResolver.js +30 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +9 -3
- package/dist/main.js +7 -0
- package/dist/runtime/Proxy.d.ts +22 -0
- package/dist/runtime/Proxy.js +34 -7
- package/dist/runtime/bootstrap.d.ts +11 -0
- package/dist/runtime/bootstrap.js +21 -1
- package/dist/runtime/css-process.d.ts +1 -0
- package/dist/runtime/css-process.js +1 -0
- package/dist/runtime/host/node/NodeRuntimeHost.js +4 -1
- package/dist/runtime/host/types.d.ts +6 -0
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +5 -1
- package/dist/runtime/lifecycle.js +1 -0
- package/dist/runtime/port-finder.d.ts +30 -0
- package/dist/runtime/port-finder.js +83 -0
- package/dist/runtime/runner/node/NodeGatewayRuntimeRunner.js +1 -0
- package/dist/runtime/runner/types.d.ts +5 -0
- package/dist/runtime/runtime-types.d.ts +1 -0
- package/dist/test-utils/local-managed-client-p2p-e2e-smoke.js +1 -1
- package/dist/tunnel/LocalTunnelProvider.d.ts +15 -0
- package/dist/tunnel/LocalTunnelProvider.js +87 -18
- package/dist/tunnel/LocalTunnelProvider.jsonld +27 -0
- package/dist/tunnel/NgrokTunnelProvider.d.ts +4 -0
- package/dist/tunnel/NgrokTunnelProvider.js +117 -43
- package/dist/tunnel/NgrokTunnelProvider.jsonld +4 -0
- package/dist/tunnel/SakuraFrpTunnelProvider.d.ts +65 -3
- package/dist/tunnel/SakuraFrpTunnelProvider.js +268 -25
- package/dist/tunnel/TunnelLifecycle.d.ts +14 -0
- package/dist/tunnel/TunnelLifecycle.js +34 -0
- package/dist/tunnel/TunnelProfiles.d.ts +33 -3
- package/dist/tunnel/TunnelProfiles.js +105 -78
- package/dist/tunnel/TunnelProvider.d.ts +15 -2
- package/dist/tunnel/TunnelProvider.jsonld +8 -0
- package/dist/tunnel/TunnelProviderCatalog.d.ts +62 -0
- package/dist/tunnel/TunnelProviderCatalog.js +130 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiApiKeyPool.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiApiKeyPool.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiAuthorizationActions.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectDialog.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialRow.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiCustomProviderDialog.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeyRow.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayModelsSection.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiOfferingDetails.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiSortableCredentialList.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/authorization-methods.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.js +3 -3
- package/node_modules/@undefineds.co/ai-connections/dist/collections.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/collections.js +3 -3
- package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/ai-connections-client.d.ts +1 -1
- package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/ai-connections-client.js +1 -1
- package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/index.cjs +8 -8
- package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/index.d.ts +1 -1
- package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/index.js +1 -1
- package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/provider-catalog.cjs +3 -3
- package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/controller.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/credential-labels.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/display-wording.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/error-wording.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/error-wording.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/gateway-endpoints.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/offering-endpoints.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/offering-label.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/service-access.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/useAiConnectDialog.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/package.json +31 -1
- package/package.json +5 -6
- package/static/app/assets/main.css +1 -1
- package/static/auth-callback/assets/{AiConfigContext-DlFyEWy9.js → AiConfigContext-DCXpjzpj.js} +1 -1
- package/static/auth-callback/assets/{AiConfigPage-CkYk-SFW.js → AiConfigPage-fe-xMIXa.js} +1 -1
- package/static/auth-callback/assets/{DocumentProcessingPanel-CqIr3JqN.js → DocumentProcessingPanel-BGnkfMuU.js} +1 -1
- package/static/auth-callback/assets/{IndexLifecyclePanel-C1GKV3Vx.js → IndexLifecyclePanel-42Jups0j.js} +1 -1
- package/static/auth-callback/assets/{IndexSubjectPanel-ro9lC6XW.js → IndexSubjectPanel-CYyLOlQU.js} +1 -1
- package/static/auth-callback/assets/{ModelAssignmentsPanel-DxNdyKRJ.js → ModelAssignmentsPanel-BOvUH4yr.js} +1 -1
- package/static/auth-callback/assets/{ModelsPage-BVtWSPBU.js → ModelsPage-DwyITxt7.js} +3 -3
- package/static/auth-callback/assets/NetworkPage-CG9RelJA.js +2 -0
- package/static/auth-callback/assets/{PaneListHeader-ByKw8ada.js → PaneListHeader-yvd5ohs6.js} +1 -1
- package/static/auth-callback/assets/{SearchIndexingPanel-CulBKcYT.js → SearchIndexingPanel-2_a6ezzj.js} +1 -1
- package/static/auth-callback/assets/{StatusSubjectPanel-VOcfrt8o.js → StatusSubjectPanel-8qtVxnzC.js} +1 -1
- package/static/auth-callback/assets/{StatusWorkspace-Jsz6hAdE.js → StatusWorkspace-CBdRahCF.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsPage-BFNvGAle.js → SystemSettingsPage-BZJ6vWkg.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsSubjectPanel-DFRdrSfK.js → SystemSettingsSubjectPanel-xm08UhXP.js} +1 -1
- package/static/auth-callback/assets/{XpodAiConnectionsPodStore-C6KpvHVg.js → XpodAiConnectionsPodStore-V6vgGfuw.js} +1 -1
- package/static/auth-callback/assets/{activity-DnTlb9iM.js → activity-CeM7xly8.js} +1 -1
- package/static/auth-callback/assets/{auth-callback-D2UkK5Xj.js → auth-callback-DTG8cSj7.js} +3 -3
- package/static/auth-callback/assets/auth-callback-rk080mvG.css +1 -0
- package/static/auth-callback/assets/{badge-D7IJuuTM.js → badge-qJo2Zr4d.js} +1 -1
- package/static/auth-callback/assets/{collection-runtime-wT1n4GS2.js → collection-runtime-Bztsz31a.js} +1 -1
- package/static/auth-callback/assets/{dialog-DickLu5z.js → dialog-D-h6x5x0.js} +1 -1
- package/static/auth-callback/assets/{download-kn8WnRu3.js → download-C2ir4lmR.js} +1 -1
- package/static/auth-callback/assets/{external-link-B6B8jfSn.js → external-link-THLDL4On.js} +1 -1
- package/static/auth-callback/assets/{index-Dz83EEHD.js → index-BRpv4yO3.js} +1 -1
- package/static/auth-callback/assets/{index-DHF97YLP.js → index-BlVZb9A7.js} +1 -1
- package/static/auth-callback/assets/index-D983R1FV.js +4 -0
- package/static/auth-callback/assets/{index-browser-CSghinyi.js → index-browser-3FvR0aaf.js} +1 -1
- package/static/auth-callback/assets/{key-round-ChkOx3E1.js → key-round-C9U5j1Ly.js} +1 -1
- package/static/auth-callback/assets/{rotate-ccw-B3hE-nyd.js → rotate-ccw-DP45cD4o.js} +1 -1
- package/static/auth-callback/assets/{skeleton-kEqR7tpI.js → skeleton-Dn4EiSCS.js} +1 -1
- package/static/auth-callback/assets/{waypoints-D6Jo-SZa.js → waypoints-uqFQ3uEG.js} +1 -1
- package/static/auth-callback/assets/{workspace-layout-BHwT_cHd.js → workspace-layout-DLYK0Wwu.js} +1 -1
- package/static/auth-callback/auth-callback.html +2 -2
- package/static/dashboard/assets/{AiConfigContext-BfC3v-x2.js → AiConfigContext-DJcMECNw.js} +1 -1
- package/static/dashboard/assets/{AiConfigPage-QNS3u7Ff.js → AiConfigPage-BvE7dOTy.js} +1 -1
- package/static/dashboard/assets/{DocumentProcessingPanel-Dr4XLeT4.js → DocumentProcessingPanel-D9780krf.js} +1 -1
- package/static/dashboard/assets/{IndexLifecyclePanel-KtM_gpeO.js → IndexLifecyclePanel-SjsUcnbM.js} +1 -1
- package/static/dashboard/assets/{IndexSubjectPanel-DLaiKdLc.js → IndexSubjectPanel-C-ym2Tqi.js} +1 -1
- package/static/dashboard/assets/{ModelAssignmentsPanel-Bk7TvQRq.js → ModelAssignmentsPanel-BRjZ-arB.js} +1 -1
- package/static/dashboard/assets/{ModelsPage-Cci3vlos.js → ModelsPage-BtTU6du3.js} +3 -3
- package/static/dashboard/assets/NetworkPage-CV9qpkDg.js +2 -0
- package/static/dashboard/assets/{PaneListHeader-qHME_s08.js → PaneListHeader-KyPTTBsv.js} +1 -1
- package/static/dashboard/assets/{SearchIndexingPanel-HZPKj8H9.js → SearchIndexingPanel-DolHGawg.js} +1 -1
- package/static/dashboard/assets/{StatusSubjectPanel-ij7IpI8d.js → StatusSubjectPanel-_YZvKiYi.js} +1 -1
- package/static/dashboard/assets/{StatusWorkspace-Cp02JcaN.js → StatusWorkspace-Dlbh_G40.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsPage-BSeuvb8X.js → SystemSettingsPage-Be7QSIoz.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsSubjectPanel-CP4_luGS.js → SystemSettingsSubjectPanel-DBp0gja7.js} +1 -1
- package/static/dashboard/assets/{XpodAiConnectionsPodStore-urO6zaHL.js → XpodAiConnectionsPodStore-ClpSjzpP.js} +1 -1
- package/static/dashboard/assets/{activity-DxjgQNvr.js → activity-lsNbTXJu.js} +1 -1
- package/static/dashboard/assets/{badge-53qCrRbl.js → badge-CVatKjaG.js} +1 -1
- package/static/dashboard/assets/{collection-runtime-BPAmHG46.js → collection-runtime-Ec4UnY28.js} +1 -1
- package/static/dashboard/assets/{dashboard-BcT2ByXw.js → dashboard-BEzsRsvF.js} +2 -2
- package/static/dashboard/assets/dashboard-rk080mvG.css +1 -0
- package/static/dashboard/assets/{dialog-B28YtNhS.js → dialog-BuyelQ4V.js} +1 -1
- package/static/dashboard/assets/{download-DkLNceJ4.js → download-B4Nf678F.js} +1 -1
- package/static/dashboard/assets/{external-link-D3TXnlo3.js → external-link-PYv9CvKL.js} +1 -1
- package/static/dashboard/assets/index-C9XPE-mI.js +4 -0
- package/static/dashboard/assets/{index-CFIenkeK.js → index-Cx69bTNh.js} +1 -1
- package/static/dashboard/assets/{index-CIiBu9mr.js → index-awr7ulur.js} +1 -1
- package/static/dashboard/assets/{key-round-B5ccp6nx.js → key-round-VsY80U1Z.js} +1 -1
- package/static/dashboard/assets/{rotate-ccw-DUpfkNnk.js → rotate-ccw-Cz1K4vE9.js} +1 -1
- package/static/dashboard/assets/{skeleton-BRe19fO0.js → skeleton-BhNv_8tO.js} +1 -1
- package/static/dashboard/assets/{waypoints-BKDMxEvu.js → waypoints-DYS9XFYV.js} +1 -1
- package/static/dashboard/assets/{workspace-layout-ZTF7C16h.js → workspace-layout-OZJAFx5V.js} +1 -1
- package/static/dashboard/dashboard.html +2 -2
- package/static/settings/assets/{AiConfigContext-DsyWgu2i.js → AiConfigContext-B8JS3MXF.js} +1 -1
- package/static/settings/assets/{AiConfigPage-CSCBckKo.js → AiConfigPage-C3Zl8LUl.js} +1 -1
- package/static/settings/assets/{DocumentProcessingPanel-w9yQDbBe.js → DocumentProcessingPanel-DpDZAQvf.js} +1 -1
- package/static/settings/assets/{IndexLifecyclePanel-CUUXI8mP.js → IndexLifecyclePanel-Ec1XF88t.js} +1 -1
- package/static/settings/assets/{IndexSubjectPanel-BypAU5TJ.js → IndexSubjectPanel-BulT9BmO.js} +1 -1
- package/static/settings/assets/{ModelAssignmentsPanel-BetgXw1G.js → ModelAssignmentsPanel-BcGSmYjb.js} +1 -1
- package/static/settings/assets/{ModelsPage-DZpTlTZ3.js → ModelsPage-CvTCKy1T.js} +3 -3
- package/static/settings/assets/NetworkPage-DQF5u9Bn.js +2 -0
- package/static/settings/assets/{PaneListHeader-BGOqGec4.js → PaneListHeader-D40hqcVl.js} +1 -1
- package/static/settings/assets/{SearchIndexingPanel-DYAbpZ_9.js → SearchIndexingPanel-iCUPOx_0.js} +1 -1
- package/static/settings/assets/{StatusSubjectPanel-CFgzeQ8Q.js → StatusSubjectPanel-E--ZHSql.js} +1 -1
- package/static/settings/assets/{StatusWorkspace-4Z6g4Jvv.js → StatusWorkspace-YjDAx1II.js} +1 -1
- package/static/settings/assets/{SystemSettingsPage-C1tlrgvI.js → SystemSettingsPage-CDdV3mC9.js} +1 -1
- package/static/settings/assets/{SystemSettingsSubjectPanel-CcURI-1L.js → SystemSettingsSubjectPanel-Br8WazDq.js} +1 -1
- package/static/settings/assets/{XpodAiConnectionsPodStore-owBQc5nY.js → XpodAiConnectionsPodStore-CLr38P_Z.js} +1 -1
- package/static/settings/assets/{activity-CtBc9cNy.js → activity-C5DAHHTE.js} +1 -1
- package/static/settings/assets/{badge--r-FDIhU.js → badge-D8eIyxKt.js} +1 -1
- package/static/settings/assets/{collection-runtime-CnhPmwAM.js → collection-runtime-DLc9zil8.js} +1 -1
- package/static/settings/assets/{dialog-B7ZRsjN7.js → dialog-CyuR7Va4.js} +1 -1
- package/static/settings/assets/{download-DgQ1F8QR.js → download-c0oxZrCz.js} +1 -1
- package/static/settings/assets/{external-link-Bz7NckNO.js → external-link-D3Z34fP_.js} +1 -1
- package/static/settings/assets/{index-Vv-8Vslg.js → index-CKGbRFlc.js} +1 -1
- package/static/settings/assets/index-CSr3-2Cj.js +4 -0
- package/static/settings/assets/{index-CkGda_Pg.js → index-ComidxAm.js} +1 -1
- package/static/settings/assets/{index-browser-Dq7omlpY.js → index-browser-CAscEbae.js} +1 -1
- package/static/settings/assets/{key-round-CvuhloKV.js → key-round-DyjLmXuB.js} +1 -1
- package/static/settings/assets/{rotate-ccw-DgFKDaz7.js → rotate-ccw-679HF_ec.js} +1 -1
- package/static/settings/assets/{settings-BvqY7K96.js → settings-DKknqu4C.js} +3 -3
- package/static/settings/assets/settings-rk080mvG.css +1 -0
- package/static/settings/assets/{skeleton-D3OeFDF6.js → skeleton-CkopNkPB.js} +1 -1
- package/static/settings/assets/{waypoints-C4WbspTb.js → waypoints-CrqfAftE.js} +1 -1
- package/static/settings/assets/{workspace-layout-B9H1Tqrk.js → workspace-layout-UN6c4qTG.js} +1 -1
- package/static/settings/settings.html +2 -2
- package/node_modules/@undefineds.co/ai-connections-core/package.json +0 -61
- package/static/auth-callback/assets/NetworkPage-cEvxRMAl.js +0 -2
- package/static/auth-callback/assets/auth-callback-Cx9D_1qj.css +0 -1
- package/static/auth-callback/assets/index-Cu0EguPo.js +0 -4
- package/static/dashboard/assets/NetworkPage-Ot4G2dX5.js +0 -2
- package/static/dashboard/assets/dashboard-Cx9D_1qj.css +0 -1
- package/static/dashboard/assets/index-Gp3cLolR.js +0 -4
- package/static/settings/assets/NetworkPage-BVkasFGM.js +0 -2
- package/static/settings/assets/index-BdXwm8nh.js +0 -4
- package/static/settings/assets/settings-Cx9D_1qj.css +0 -1
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client/normalize.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client/normalize.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client/request.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client/request.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client/types.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client/types.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/base-adapter.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/base-adapter.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/codex.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/codex.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/index.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/index.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/json-env-adapter.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/json-env-adapter.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/pi.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/pi.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/transaction.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/transaction.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/types.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/types.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/credential-storage.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/credential-storage.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/endpoint-urls.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/endpoint-urls.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/provider-catalog.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/provider-catalog.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 =
|
|
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('
|
|
97
|
-
this.status
|
|
98
|
-
|
|
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
|
|
110
|
-
|
|
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 =
|
|
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
|
-
|
|
127
|
-
this.
|
|
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
|
-
|
|
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 = {
|
|
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
|
-
//
|
|
284
|
-
|
|
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 ?
|
|
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
|
-
|
|
95
|
-
this.
|
|
96
|
-
|
|
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:
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
162
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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:
|
|
187
|
+
...(this.currentConfig ?? { subdomain: 'local', provider: 'ngrok', endpoint: effective }),
|
|
170
188
|
provider: 'ngrok',
|
|
171
|
-
endpoint:
|
|
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
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
17
|
+
/** SakuraFRP 启动参数 (`<访问密钥>:<隧道ID>[,<隧道ID>...]`),来自 SAKURA_TUNNEL_TOKEN */
|
|
15
18
|
token: string;
|
|
16
|
-
/**
|
|
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
|
+
};
|