@undefineds.co/xpod 0.4.13 → 0.4.15
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/cloud.json +0 -3
- package/config/components-ignore.json +11 -7
- package/config/local.json +0 -3
- package/config/xpod.base.json +0 -24
- package/dist/api/ai-config/AiConfigStore.d.ts +2 -2
- package/dist/api/ai-config/AiConfigStore.js +4 -1
- package/dist/api/ai-gateway/auth/CallerPodAccess.d.ts +2 -5
- package/dist/api/ai-gateway/auth/CallerPodAccess.js +3 -42
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.d.ts +2 -1
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js +1 -1
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.d.ts +3 -8
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js +9 -32
- package/dist/api/ai-gateway/connect/index.d.ts +3 -3
- package/dist/api/ai-gateway/connect/index.js +9 -38
- package/dist/api/ai-gateway/errors.js +2 -1
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.d.ts +3 -3
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +7 -11
- package/dist/api/ai-gateway/pod/HostedPodRoute.d.ts +27 -0
- package/dist/api/ai-gateway/pod/HostedPodRoute.js +47 -0
- package/dist/api/ai-gateway/pod/OwnerPodAccess.d.ts +79 -0
- package/dist/api/ai-gateway/pod/OwnerPodAccess.js +192 -0
- package/dist/api/ai-gateway/pod/PodInterfaceKeyStore.d.ts +52 -0
- package/dist/api/ai-gateway/pod/PodInterfaceKeyStore.js +61 -0
- package/dist/api/ai-gateway/providers/ProviderRegistry.js +1 -1
- package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.d.ts +3 -3
- package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.js +7 -32
- 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/auth/ClientCredentialsAuthenticator.js +5 -28
- package/dist/api/auth/TokenEndpointRoute.d.ts +18 -0
- package/dist/api/auth/TokenEndpointRoute.js +36 -0
- package/dist/api/chatkit/pod-store.d.ts +4 -4
- package/dist/api/chatkit/pod-store.js +24 -95
- package/dist/api/container/common.js +36 -23
- package/dist/api/container/index.js +1 -0
- package/dist/api/container/local.js +88 -37
- package/dist/api/container/routes.js +41 -7
- package/dist/api/container/types.d.ts +4 -2
- package/dist/api/handlers/AdminHandler.d.ts +17 -1
- package/dist/api/handlers/AdminHandler.js +40 -3
- package/dist/api/handlers/AiGatewayManagementHandler.d.ts +6 -0
- package/dist/api/handlers/AiGatewayManagementHandler.js +17 -4
- package/dist/api/handlers/EdgeNodeSignalHandler.js +10 -2
- package/dist/api/handlers/NetworkSettingsHandler.d.ts +44 -5
- package/dist/api/handlers/NetworkSettingsHandler.js +46 -11
- package/dist/api/handlers/PodSettingsHandler.d.ts +3 -3
- package/dist/api/handlers/PodSettingsHandler.js +3 -3
- package/dist/api/handlers/ProvisionHandler.d.ts +35 -1
- package/dist/api/handlers/ProvisionHandler.js +53 -2
- package/dist/api/handlers/ReachabilityHandler.d.ts +6 -0
- package/dist/api/handlers/ReachabilityHandler.js +25 -6
- package/dist/api/network/NetworkEnvironmentConfigurationStore.d.ts +6 -1
- package/dist/api/network/NetworkEnvironmentConfigurationStore.js +72 -16
- package/dist/api/runtime.d.ts +18 -0
- package/dist/api/runtime.js +28 -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 +26 -1
- package/dist/cli/commands/start.js +69 -5
- package/dist/components/components.jsonld +1 -1
- package/dist/components/context.jsonld +35 -42
- package/dist/edge/EdgeNodeAgent.d.ts +16 -0
- package/dist/edge/EdgeNodeAgent.js +56 -1
- package/dist/edge/EdgeNodeAgent.jsonld +8 -0
- 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/edge/reachability/ReachabilitySessionService.js +4 -1
- package/dist/edge/reachability/RouteSetBuilder.d.ts +18 -1
- package/dist/edge/reachability/RouteSetBuilder.js +47 -0
- package/dist/edge/reachability/RouteSetBuilder.jsonld +29 -0
- package/dist/edge/reachability/types.d.ts +8 -2
- package/dist/http/SubgraphSparqlHttpHandler.d.ts +1 -25
- package/dist/http/SubgraphSparqlHttpHandler.js +0 -100
- package/dist/http/SubgraphSparqlHttpHandler.jsonld +0 -8
- package/dist/identity/drizzle/PodInterfaceKeyRepository.d.ts +33 -0
- package/dist/identity/drizzle/PodInterfaceKeyRepository.js +78 -0
- package/dist/identity/drizzle/db.d.ts +7 -0
- package/dist/identity/drizzle/db.js +30 -0
- package/dist/identity/drizzle/schema.pg.d.ts +9 -0
- package/dist/identity/drizzle/schema.pg.js +16 -1
- package/dist/identity/drizzle/schema.sqlite.d.ts +106 -0
- package/dist/identity/drizzle/schema.sqlite.js +16 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +9 -5
- package/dist/main.js +7 -0
- package/dist/runtime/GatewayAdminProxyAuth.d.ts +1 -16
- package/dist/runtime/GatewayAdminProxyAuth.js +2 -71
- package/dist/runtime/Proxy.d.ts +32 -1
- package/dist/runtime/Proxy.js +125 -31
- package/dist/runtime/bootstrap.d.ts +21 -0
- package/dist/runtime/bootstrap.js +45 -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 +6 -1
- package/dist/runtime/host/types.d.ts +6 -0
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +4 -1
- package/dist/runtime/js-runtime.js +10 -3
- package/dist/runtime/lifecycle.js +6 -4
- package/dist/runtime/port-finder.d.ts +26 -0
- package/dist/runtime/port-finder.js +64 -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/AutoTunnelProvider.d.ts +56 -0
- package/dist/tunnel/AutoTunnelProvider.js +181 -0
- 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/dist/tunnel/index.d.ts +1 -0
- package/dist/tunnel/index.js +3 -1
- 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 +8 -3
- 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/node_modules/@undefineds.co/solid-sdk/dist/access-route.cjs +230 -0
- package/node_modules/@undefineds.co/solid-sdk/dist/access-route.d.ts +76 -0
- package/node_modules/@undefineds.co/solid-sdk/dist/access-route.js +115 -0
- package/node_modules/@undefineds.co/solid-sdk/dist/index.cjs +89 -0
- package/node_modules/@undefineds.co/solid-sdk/dist/index.d.ts +1 -0
- package/node_modules/@undefineds.co/solid-sdk/dist/index.js +1 -0
- package/node_modules/@undefineds.co/solid-sdk/package.json +6 -1
- package/package.json +5 -6
- package/static/app/assets/inrupt-smoke.js +23 -23
- package/static/app/assets/main.css +1 -1
- package/static/auth-callback/assets/{AiConfigContext-DlFyEWy9.js → AiConfigContext-Bx0HCAW5.js} +1 -1
- package/static/auth-callback/assets/{AiConfigPage-CkYk-SFW.js → AiConfigPage-ChQImMbm.js} +1 -1
- package/static/auth-callback/assets/{DocumentProcessingPanel-CqIr3JqN.js → DocumentProcessingPanel-D830H4SH.js} +1 -1
- package/static/auth-callback/assets/{IndexLifecyclePanel-C1GKV3Vx.js → IndexLifecyclePanel-CnlkjMF8.js} +1 -1
- package/static/auth-callback/assets/{IndexSubjectPanel-ro9lC6XW.js → IndexSubjectPanel-CdEfg_CO.js} +1 -1
- package/static/auth-callback/assets/{ModelAssignmentsPanel-DxNdyKRJ.js → ModelAssignmentsPanel-D-8A8dZx.js} +1 -1
- package/static/auth-callback/assets/{ModelsPage-BVtWSPBU.js → ModelsPage-Cim7cubp.js} +3 -3
- package/static/auth-callback/assets/NetworkPage-CfK3x-pb.js +2 -0
- package/static/auth-callback/assets/{PaneListHeader-ByKw8ada.js → PaneListHeader-Bf_kEd4U.js} +1 -1
- package/static/auth-callback/assets/{SearchIndexingPanel-CulBKcYT.js → SearchIndexingPanel-4kD4RBEQ.js} +1 -1
- package/static/auth-callback/assets/{StatusSubjectPanel-VOcfrt8o.js → StatusSubjectPanel-Bw9AiTSf.js} +1 -1
- package/static/auth-callback/assets/{StatusWorkspace-Jsz6hAdE.js → StatusWorkspace-C-301H-0.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsPage-BFNvGAle.js → SystemSettingsPage-BbWn-eG6.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsSubjectPanel-DFRdrSfK.js → SystemSettingsSubjectPanel-DA4wvNSm.js} +1 -1
- package/static/auth-callback/assets/{XpodAiConnectionsPodStore-C6KpvHVg.js → XpodAiConnectionsPodStore-CohdyLoX.js} +1 -1
- package/static/auth-callback/assets/{activity-DnTlb9iM.js → activity-CCsb9Oam.js} +1 -1
- package/static/auth-callback/assets/ai-connections-DexTPyfC.js +1 -0
- package/static/auth-callback/assets/{auth-callback-D2UkK5Xj.js → auth-callback-Ds-c62W3.js} +5 -5
- package/static/auth-callback/assets/auth-callback-rk080mvG.css +1 -0
- package/static/auth-callback/assets/{badge-D7IJuuTM.js → badge-CQm5OyzR.js} +1 -1
- package/static/auth-callback/assets/{collection-runtime-wT1n4GS2.js → collection-runtime-DlAuU5TW.js} +1 -1
- package/static/auth-callback/assets/{dialog-DickLu5z.js → dialog-CnGzg5Ff.js} +1 -1
- package/static/auth-callback/assets/{download-kn8WnRu3.js → download-DwMONJvm.js} +1 -1
- package/static/auth-callback/assets/{external-link-B6B8jfSn.js → external-link-Bu5AGqCO.js} +1 -1
- package/static/auth-callback/assets/{index-DHF97YLP.js → index-B0T-1YO8.js} +1 -1
- package/static/auth-callback/assets/{index-Dz83EEHD.js → index-C8QZf_4W.js} +1 -1
- package/static/auth-callback/assets/index-DwIlrIDG.js +4 -0
- package/static/auth-callback/assets/{index-browser-CSghinyi.js → index-browser-lRsMcP_7.js} +1 -1
- package/static/auth-callback/assets/{key-round-ChkOx3E1.js → key-round-BDMtU57P.js} +1 -1
- package/static/auth-callback/assets/{rotate-ccw-B3hE-nyd.js → rotate-ccw-CoKIGCsQ.js} +1 -1
- package/static/auth-callback/assets/{skeleton-kEqR7tpI.js → skeleton-CPoSWHDr.js} +1 -1
- package/static/auth-callback/assets/{waypoints-D6Jo-SZa.js → waypoints-BeYHxqHv.js} +1 -1
- package/static/auth-callback/assets/{workspace-layout-BHwT_cHd.js → workspace-layout-xA5YxiK3.js} +1 -1
- package/static/auth-callback/auth-callback.html +2 -2
- package/static/dashboard/assets/{AiConfigContext-BfC3v-x2.js → AiConfigContext-rWx4TyiH.js} +1 -1
- package/static/dashboard/assets/{AiConfigPage-QNS3u7Ff.js → AiConfigPage-StVJpDFT.js} +1 -1
- package/static/dashboard/assets/{DocumentProcessingPanel-Dr4XLeT4.js → DocumentProcessingPanel-DJ5yul2O.js} +1 -1
- package/static/dashboard/assets/{IndexLifecyclePanel-KtM_gpeO.js → IndexLifecyclePanel-CpjtgezK.js} +1 -1
- package/static/dashboard/assets/{IndexSubjectPanel-DLaiKdLc.js → IndexSubjectPanel-BVKcot1_.js} +1 -1
- package/static/dashboard/assets/{ModelAssignmentsPanel-Bk7TvQRq.js → ModelAssignmentsPanel-BxVgWZPc.js} +1 -1
- package/static/dashboard/assets/{ModelsPage-Cci3vlos.js → ModelsPage-CECBwmeO.js} +3 -3
- package/static/dashboard/assets/NetworkPage-zQgFscEW.js +2 -0
- package/static/dashboard/assets/{PaneListHeader-qHME_s08.js → PaneListHeader-DIPe8pS6.js} +1 -1
- package/static/dashboard/assets/{SearchIndexingPanel-HZPKj8H9.js → SearchIndexingPanel-lalFJ3c8.js} +1 -1
- package/static/dashboard/assets/{StatusSubjectPanel-ij7IpI8d.js → StatusSubjectPanel-CpY_KU-G.js} +1 -1
- package/static/dashboard/assets/{StatusWorkspace-Cp02JcaN.js → StatusWorkspace-BwWCii3A.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsPage-BSeuvb8X.js → SystemSettingsPage-BKZxX-_n.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsSubjectPanel-CP4_luGS.js → SystemSettingsSubjectPanel-BZrqb2C5.js} +1 -1
- package/static/dashboard/assets/{XpodAiConnectionsPodStore-urO6zaHL.js → XpodAiConnectionsPodStore-Bbpx9dTN.js} +1 -1
- package/static/dashboard/assets/{activity-DxjgQNvr.js → activity-BJ15TLVP.js} +1 -1
- package/static/dashboard/assets/ai-connections-GG6qkTJt.js +1 -0
- package/static/dashboard/assets/{badge-53qCrRbl.js → badge-BBX5FlaB.js} +1 -1
- package/static/dashboard/assets/{collection-runtime-BPAmHG46.js → collection-runtime-UBbHBzdf.js} +1 -1
- package/static/dashboard/assets/{dashboard-BcT2ByXw.js → dashboard-7Y6BHyV9.js} +62 -62
- package/static/dashboard/assets/dashboard-rk080mvG.css +1 -0
- package/static/dashboard/assets/{dialog-B28YtNhS.js → dialog-QrOJ-hB0.js} +1 -1
- package/static/dashboard/assets/{download-DkLNceJ4.js → download-DK9x-VOP.js} +1 -1
- package/static/dashboard/assets/{external-link-D3TXnlo3.js → external-link-Cnkn87mJ.js} +1 -1
- package/static/dashboard/assets/index-B1z84it5.js +4 -0
- package/static/dashboard/assets/{index-CIiBu9mr.js → index-DzjauX3N.js} +1 -1
- package/static/dashboard/assets/{index-CFIenkeK.js → index-cIa8_efI.js} +1 -1
- package/static/dashboard/assets/{key-round-B5ccp6nx.js → key-round-BoS6UqKz.js} +1 -1
- package/static/dashboard/assets/{rotate-ccw-DUpfkNnk.js → rotate-ccw-BeWV76i0.js} +1 -1
- package/static/dashboard/assets/{skeleton-BRe19fO0.js → skeleton-CypcJL07.js} +1 -1
- package/static/dashboard/assets/{waypoints-BKDMxEvu.js → waypoints-zHOOqfhi.js} +1 -1
- package/static/dashboard/assets/{workspace-layout-ZTF7C16h.js → workspace-layout-DZ9JuxnM.js} +1 -1
- package/static/dashboard/dashboard.html +2 -2
- package/static/settings/assets/{AiConfigContext-DsyWgu2i.js → AiConfigContext-D3b1l_Kw.js} +1 -1
- package/static/settings/assets/{AiConfigPage-CSCBckKo.js → AiConfigPage-DYKw-atP.js} +1 -1
- package/static/settings/assets/{DocumentProcessingPanel-w9yQDbBe.js → DocumentProcessingPanel-DguRfsIV.js} +1 -1
- package/static/settings/assets/{IndexLifecyclePanel-CUUXI8mP.js → IndexLifecyclePanel-B85qJJA4.js} +1 -1
- package/static/settings/assets/{IndexSubjectPanel-BypAU5TJ.js → IndexSubjectPanel-CsN7IxaV.js} +1 -1
- package/static/settings/assets/{ModelAssignmentsPanel-BetgXw1G.js → ModelAssignmentsPanel-DEp9byI6.js} +1 -1
- package/static/settings/assets/{ModelsPage-DZpTlTZ3.js → ModelsPage-CzTnPs_G.js} +3 -3
- package/static/settings/assets/NetworkPage-BDVnmUU0.js +2 -0
- package/static/settings/assets/{PaneListHeader-BGOqGec4.js → PaneListHeader-Cpe39N76.js} +1 -1
- package/static/settings/assets/{SearchIndexingPanel-DYAbpZ_9.js → SearchIndexingPanel-DA9w8lLL.js} +1 -1
- package/static/settings/assets/{StatusSubjectPanel-CFgzeQ8Q.js → StatusSubjectPanel-BU0Aq0CS.js} +1 -1
- package/static/settings/assets/{StatusWorkspace-4Z6g4Jvv.js → StatusWorkspace-D1AC1i5N.js} +1 -1
- package/static/settings/assets/{SystemSettingsPage-C1tlrgvI.js → SystemSettingsPage-ChKvOioO.js} +1 -1
- package/static/settings/assets/{SystemSettingsSubjectPanel-CcURI-1L.js → SystemSettingsSubjectPanel-DyTpOnD2.js} +1 -1
- package/static/settings/assets/{XpodAiConnectionsPodStore-owBQc5nY.js → XpodAiConnectionsPodStore-VU5Bsz1a.js} +1 -1
- package/static/settings/assets/{activity-CtBc9cNy.js → activity-DGpLfsQB.js} +1 -1
- package/static/settings/assets/ai-connections-DexTPyfC.js +1 -0
- package/static/settings/assets/{badge--r-FDIhU.js → badge-_hCrrWRP.js} +1 -1
- package/static/settings/assets/{collection-runtime-CnhPmwAM.js → collection-runtime-E40TZ8Cl.js} +1 -1
- package/static/settings/assets/{dialog-B7ZRsjN7.js → dialog-DTr2JkHn.js} +1 -1
- package/static/settings/assets/{download-DgQ1F8QR.js → download-B_D21DDX.js} +1 -1
- package/static/settings/assets/{external-link-Bz7NckNO.js → external-link-BATYaM13.js} +1 -1
- package/static/settings/assets/index-BAlAVi-J.js +4 -0
- package/static/settings/assets/{index-CkGda_Pg.js → index-Ckh4h9jj.js} +1 -1
- package/static/settings/assets/{index-Vv-8Vslg.js → index-DOiwLF4B.js} +1 -1
- package/static/settings/assets/{index-browser-Dq7omlpY.js → index-browser-DFFWN3Kr.js} +1 -1
- package/static/settings/assets/{key-round-CvuhloKV.js → key-round-ZTVU_1O1.js} +1 -1
- package/static/settings/assets/{rotate-ccw-DgFKDaz7.js → rotate-ccw-DDdw8PTU.js} +1 -1
- package/static/settings/assets/{settings-BvqY7K96.js → settings-CyLnISOv.js} +62 -62
- package/static/settings/assets/settings-rk080mvG.css +1 -0
- package/static/settings/assets/{skeleton-D3OeFDF6.js → skeleton-DEzA3hc2.js} +1 -1
- package/static/settings/assets/{waypoints-C4WbspTb.js → waypoints-BSdfNvEb.js} +1 -1
- package/static/settings/assets/{workspace-layout-B9H1Tqrk.js → workspace-layout-BOQnl_3d.js} +1 -1
- package/static/settings/settings.html +2 -2
- package/dist/api/ai-gateway/pod/HostedPodDataAccess.d.ts +0 -31
- package/dist/api/ai-gateway/pod/HostedPodDataAccess.js +0 -330
- package/dist/http/InternalPodDataHttpHandler.d.ts +0 -57
- package/dist/http/InternalPodDataHttpHandler.js +0 -551
- package/dist/http/InternalPodDataHttpHandler.jsonld +0 -243
- 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/ai-connections-C6yaE6WQ.js +0 -1
- 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/ai-connections-CXp5gd1J.js +0 -1
- 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/ai-connections-C6yaE6WQ.js +0 -1
- 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
|
@@ -3,7 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.findGatewayIngressPort = findGatewayIngressPort;
|
|
6
7
|
exports.getFreePort = getFreePort;
|
|
8
|
+
exports.getEphemeralLoopbackPort = getEphemeralLoopbackPort;
|
|
9
|
+
exports.requireFreePortForWildcard = requireFreePortForWildcard;
|
|
7
10
|
exports.getFreePortForWildcard = getFreePortForWildcard;
|
|
8
11
|
const node_net_1 = __importDefault(require("node:net"));
|
|
9
12
|
const node_os_1 = __importDefault(require("node:os"));
|
|
@@ -97,6 +100,23 @@ async function canListen(port, host, timeoutMs = PORT_PROBE_TIMEOUT_MS) {
|
|
|
97
100
|
server.listen(port, host);
|
|
98
101
|
});
|
|
99
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* The port a remote tunnel forwards to: the Gateway's tunnel entry.
|
|
105
|
+
*
|
|
106
|
+
* It sits a few ports above the Gateway so it is predictable - the user copies this one number
|
|
107
|
+
* into a provider console and it survives restarts - while staying clear of the block a
|
|
108
|
+
* neighbouring runtime plans for its own services. When the neighbourhood is busy the caller
|
|
109
|
+
* gets an OS-assigned port instead of a stolen one; the runtime reports whichever it got.
|
|
110
|
+
*/
|
|
111
|
+
async function findGatewayIngressPort(gatewayPort) {
|
|
112
|
+
for (let offset = 3; offset < 10; offset += 1) {
|
|
113
|
+
const candidate = gatewayPort + offset;
|
|
114
|
+
if (await getFreePortForWildcard(candidate) === candidate) {
|
|
115
|
+
return candidate;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return await getEphemeralLoopbackPort();
|
|
119
|
+
}
|
|
100
120
|
async function getFreePort(basePort, host = '127.0.0.1', timeoutMs = PORT_PROBE_TIMEOUT_MS) {
|
|
101
121
|
for (let port = basePort; port <= HIGHEST_PORT; port++) {
|
|
102
122
|
if (await canListen(port, host, timeoutMs)) {
|
|
@@ -105,6 +125,32 @@ async function getFreePort(basePort, host = '127.0.0.1', timeoutMs = PORT_PROBE_
|
|
|
105
125
|
}
|
|
106
126
|
throw new Error(`No open port available from ${host}:${basePort} to ${host}:${HIGHEST_PORT}`);
|
|
107
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Loopback port handed out by the OS for a listener that must not collide with ports the
|
|
130
|
+
* embedding process plans for other services.
|
|
131
|
+
*
|
|
132
|
+
* Probing next to the ports this runtime already owns is not safe: a host that allocates
|
|
133
|
+
* `gateway + 10`/`gateway + 11` (the full integration matrix does) has already reserved
|
|
134
|
+
* the neighbour of our own `api` port for another runtime, and binding it steals that
|
|
135
|
+
* runtime's service.
|
|
136
|
+
*/
|
|
137
|
+
async function getEphemeralLoopbackPort() {
|
|
138
|
+
return await new Promise((resolve, reject) => {
|
|
139
|
+
const server = node_net_1.default.createServer();
|
|
140
|
+
server.once('error', reject);
|
|
141
|
+
server.listen(0, '127.0.0.1', () => {
|
|
142
|
+
const address = server.address();
|
|
143
|
+
const port = typeof address === 'object' && address ? address.port : 0;
|
|
144
|
+
server.close((error) => {
|
|
145
|
+
if (error) {
|
|
146
|
+
reject(error);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
resolve(port);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
}
|
|
108
154
|
function hasIpv6Address() {
|
|
109
155
|
return Object.values(node_os_1.default.networkInterfaces()).some((entries) => entries?.some((entry) => entry.family === 'IPv6'));
|
|
110
156
|
}
|
|
@@ -113,6 +159,24 @@ function hasIpv6Address() {
|
|
|
113
159
|
* CSS may bind `::` while the API binds `0.0.0.0`, so probing only localhost
|
|
114
160
|
* can miss an occupied port on the other address family.
|
|
115
161
|
*/
|
|
162
|
+
/**
|
|
163
|
+
* Takes exactly this port or fails.
|
|
164
|
+
*
|
|
165
|
+
* A port that a tunnel console forwards to cannot be substituted: `getFreePortForWildcard`
|
|
166
|
+
* scans upward, which would leave the runtime listening somewhere the tunnel never reaches.
|
|
167
|
+
*/
|
|
168
|
+
async function requireFreePortForWildcard(port, timeoutMs = PORT_PROBE_TIMEOUT_MS) {
|
|
169
|
+
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
170
|
+
throw new Error(`ingress port ${port} is not a valid port number`);
|
|
171
|
+
}
|
|
172
|
+
if (!await canListen(port, '0.0.0.0', timeoutMs)) {
|
|
173
|
+
throw new Error(`ingress port ${port} is already in use; free it or point the tunnel at another port`);
|
|
174
|
+
}
|
|
175
|
+
if (hasIpv6Address() && !await canListen(port, '::', timeoutMs)) {
|
|
176
|
+
throw new Error(`ingress port ${port} is already in use on IPv6; free it or point the tunnel at another port`);
|
|
177
|
+
}
|
|
178
|
+
return port;
|
|
179
|
+
}
|
|
116
180
|
async function getFreePortForWildcard(basePort, timeoutMs = PORT_PROBE_TIMEOUT_MS) {
|
|
117
181
|
const probeIpv6 = hasIpv6Address();
|
|
118
182
|
for (let port = basePort; port <= HIGHEST_PORT; port++) {
|
|
@@ -15,6 +15,7 @@ class NodeGatewayRuntimeRunner {
|
|
|
15
15
|
runtimeHost: options.runtimeHost,
|
|
16
16
|
internalAdminAuthSecret: options.internalAdminAuthSecret,
|
|
17
17
|
clientRemoteAddressResolver: options.clientRemoteAddressResolver,
|
|
18
|
+
ingressPort: options.ingressPort,
|
|
18
19
|
});
|
|
19
20
|
gateway.setTargets(options.targets);
|
|
20
21
|
await gateway.start();
|
|
@@ -33,6 +33,11 @@ export interface GatewayRuntimeRunnerStartOptions {
|
|
|
33
33
|
supervisor: Supervisor;
|
|
34
34
|
internalAdminAuthSecret: string;
|
|
35
35
|
clientRemoteAddressResolver?: (req: http.IncomingMessage) => string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Loopback-only ingress listener for remote forwarding paths (tunnels, P2P).
|
|
38
|
+
* Port transport only; socket transport has no remote ingress.
|
|
39
|
+
*/
|
|
40
|
+
ingressPort?: number;
|
|
36
41
|
targets: {
|
|
37
42
|
css: RuntimeConnectionTarget;
|
|
38
43
|
api: RuntimeConnectionTarget;
|
|
@@ -38,7 +38,7 @@ async function runLocalManagedClientP2PE2ESmoke(options = {}) {
|
|
|
38
38
|
const { token: serviceToken } = await serviceTokenRepo.createToken({
|
|
39
39
|
serviceType: 'cloud',
|
|
40
40
|
serviceId: 'managed-client-smoke',
|
|
41
|
-
scopes: ['
|
|
41
|
+
scopes: ['network:read', 'network:write'],
|
|
42
42
|
});
|
|
43
43
|
const signalApi = await startSignalApi({
|
|
44
44
|
nodeRepo,
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { TunnelConfig, TunnelProvider, TunnelSetupOptions, TunnelStatus } from './TunnelProvider';
|
|
2
|
+
/** One tunnel the auto provider may bring up, in the order it is worth trying. */
|
|
3
|
+
export interface AutoTunnelCandidate {
|
|
4
|
+
/** Provider or profile id, used in status and in the failure detail. */
|
|
5
|
+
id: string;
|
|
6
|
+
provider: TunnelProvider;
|
|
7
|
+
}
|
|
8
|
+
export interface AutoTunnelProviderOptions {
|
|
9
|
+
candidates: readonly AutoTunnelCandidate[];
|
|
10
|
+
/**
|
|
11
|
+
* How long one candidate gets to reach `proxy-ready` before the next one is
|
|
12
|
+
* tried. A candidate that is blocked (network policy, rejected credential)
|
|
13
|
+
* usually fails faster than this; the timeout only bounds the silent ones.
|
|
14
|
+
*/
|
|
15
|
+
readinessTimeoutMs?: number;
|
|
16
|
+
/** Poll interval while waiting for readiness. */
|
|
17
|
+
pollIntervalMs?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Brings up whichever tunnel actually works.
|
|
21
|
+
*
|
|
22
|
+
* An operator configures the providers they have credentials for; which of them
|
|
23
|
+
* can reach its control plane is a property of the network, not of the list. So
|
|
24
|
+
* the candidates are tried in order and the first one that publishes a proxy
|
|
25
|
+
* wins, with the losers stopped and their reasons kept for the failure report.
|
|
26
|
+
* An explicit selection never goes through here: the runtime registers that
|
|
27
|
+
* provider directly, so a closed or pinned tunnel cannot come back on its own.
|
|
28
|
+
*/
|
|
29
|
+
export declare class AutoTunnelProvider implements TunnelProvider {
|
|
30
|
+
readonly name = "auto";
|
|
31
|
+
private readonly logger;
|
|
32
|
+
private readonly candidates;
|
|
33
|
+
private readonly readinessTimeoutMs;
|
|
34
|
+
private readonly pollIntervalMs;
|
|
35
|
+
private configs;
|
|
36
|
+
private active?;
|
|
37
|
+
private started;
|
|
38
|
+
private status;
|
|
39
|
+
/** Why each candidate that did not win was dropped. */
|
|
40
|
+
private readonly attempts;
|
|
41
|
+
constructor(options: AutoTunnelProviderOptions);
|
|
42
|
+
setup(options: TunnelSetupOptions): Promise<TunnelConfig>;
|
|
43
|
+
start(config?: TunnelConfig): Promise<void>;
|
|
44
|
+
stop(): Promise<void>;
|
|
45
|
+
getStatus(): TunnelStatus;
|
|
46
|
+
getEndpoint(): string | undefined;
|
|
47
|
+
cleanup(config: TunnelConfig): Promise<void>;
|
|
48
|
+
/** Id of the candidate currently serving, once one is ready. */
|
|
49
|
+
getActiveId(): string | undefined;
|
|
50
|
+
/** The candidates that were tried, and why the ones that lost did. */
|
|
51
|
+
getAttempts(): readonly string[];
|
|
52
|
+
private waitForReady;
|
|
53
|
+
/** Stop a candidate that lost and stop counting it as started. */
|
|
54
|
+
private dropCandidate;
|
|
55
|
+
private stopLosers;
|
|
56
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AutoTunnelProvider = void 0;
|
|
4
|
+
const global_logger_factory_1 = require("global-logger-factory");
|
|
5
|
+
const TunnelLifecycle_1 = require("./TunnelLifecycle");
|
|
6
|
+
const DEFAULT_READINESS_TIMEOUT_MS = 30_000;
|
|
7
|
+
const DEFAULT_POLL_INTERVAL_MS = 250;
|
|
8
|
+
/**
|
|
9
|
+
* Brings up whichever tunnel actually works.
|
|
10
|
+
*
|
|
11
|
+
* An operator configures the providers they have credentials for; which of them
|
|
12
|
+
* can reach its control plane is a property of the network, not of the list. So
|
|
13
|
+
* the candidates are tried in order and the first one that publishes a proxy
|
|
14
|
+
* wins, with the losers stopped and their reasons kept for the failure report.
|
|
15
|
+
* An explicit selection never goes through here: the runtime registers that
|
|
16
|
+
* provider directly, so a closed or pinned tunnel cannot come back on its own.
|
|
17
|
+
*/
|
|
18
|
+
class AutoTunnelProvider {
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.name = 'auto';
|
|
21
|
+
this.logger = (0, global_logger_factory_1.getLoggerFor)(this);
|
|
22
|
+
this.configs = new Map();
|
|
23
|
+
this.started = [];
|
|
24
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('stopped');
|
|
25
|
+
/** Why each candidate that did not win was dropped. */
|
|
26
|
+
this.attempts = [];
|
|
27
|
+
this.candidates = options.candidates;
|
|
28
|
+
this.readinessTimeoutMs = options.readinessTimeoutMs ?? DEFAULT_READINESS_TIMEOUT_MS;
|
|
29
|
+
this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
30
|
+
}
|
|
31
|
+
async setup(options) {
|
|
32
|
+
this.configs = new Map();
|
|
33
|
+
for (const candidate of this.candidates) {
|
|
34
|
+
try {
|
|
35
|
+
this.configs.set(candidate.id, await candidate.provider.setup(options));
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
this.attempts.push(`${candidate.id}: ${describeError(error)}`);
|
|
39
|
+
this.logger.warn(`Tunnel candidate ${candidate.id} could not be prepared: ${describeError(error)}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// The driver round-trips this config back into `start`, which drives the
|
|
43
|
+
// candidates itself, so it only has to describe the requested origin.
|
|
44
|
+
const first = this.candidates[0];
|
|
45
|
+
const config = first ? this.configs.get(first.id) : undefined;
|
|
46
|
+
return config ?? {
|
|
47
|
+
subdomain: options.subdomain,
|
|
48
|
+
provider: 'cloudflare',
|
|
49
|
+
endpoint: '',
|
|
50
|
+
originUrl: `${options.localProtocol ?? 'http'}://127.0.0.1:${options.localPort}`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async start(config) {
|
|
54
|
+
void config;
|
|
55
|
+
for (const candidate of this.candidates) {
|
|
56
|
+
const candidateConfig = this.configs.get(candidate.id);
|
|
57
|
+
if (!candidateConfig) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('process-started', { endpoint: candidate.provider.getEndpoint() });
|
|
61
|
+
try {
|
|
62
|
+
this.started.push(candidate);
|
|
63
|
+
await candidate.provider.start(candidateConfig);
|
|
64
|
+
const ready = await this.waitForReady(candidate.provider);
|
|
65
|
+
if (ready) {
|
|
66
|
+
this.active = candidate;
|
|
67
|
+
this.status = withCandidate(candidate, candidate.provider.getStatus());
|
|
68
|
+
this.logger.info(`Tunnel ready through ${candidate.id}`);
|
|
69
|
+
await this.stopLosers(candidate);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
this.attempts.push(`${candidate.id}: ${describeStatus(candidate.provider.getStatus())}`);
|
|
73
|
+
this.logger.warn(`Tunnel candidate ${candidate.id} did not become ready; trying the next one`);
|
|
74
|
+
await this.dropCandidate(candidate);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
this.attempts.push(`${candidate.id}: ${describeError(error)}`);
|
|
78
|
+
this.logger.warn(`Tunnel candidate ${candidate.id} failed: ${describeError(error)}`);
|
|
79
|
+
await this.dropCandidate(candidate);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Nothing worked: report which candidates were tried and why, so a caller
|
|
83
|
+
// never has to guess whether the tunnel is off or merely unreachable.
|
|
84
|
+
const detail = this.attempts.length > 0
|
|
85
|
+
? this.attempts.join('; ')
|
|
86
|
+
: 'no tunnel provider is configured';
|
|
87
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('failed', { error: `no-tunnel-candidate-ready: ${detail}` });
|
|
88
|
+
}
|
|
89
|
+
async stop() {
|
|
90
|
+
const targets = this.started;
|
|
91
|
+
this.started = [];
|
|
92
|
+
this.active = undefined;
|
|
93
|
+
await Promise.all(targets.map(async (candidate) => {
|
|
94
|
+
await candidate.provider.stop().catch((error) => {
|
|
95
|
+
this.logger.warn(`Stopping tunnel candidate ${candidate.id} failed: ${describeError(error)}`);
|
|
96
|
+
});
|
|
97
|
+
}));
|
|
98
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('stopped');
|
|
99
|
+
}
|
|
100
|
+
getStatus() {
|
|
101
|
+
if (!this.active) {
|
|
102
|
+
return this.status;
|
|
103
|
+
}
|
|
104
|
+
const current = this.active.provider.getStatus();
|
|
105
|
+
// A tunnel that was ready and then died is still the active one, so its
|
|
106
|
+
// failure is what callers must see - never a stale "connected".
|
|
107
|
+
return withCandidate(this.active, current);
|
|
108
|
+
}
|
|
109
|
+
getEndpoint() {
|
|
110
|
+
return this.active?.provider.getEndpoint();
|
|
111
|
+
}
|
|
112
|
+
async cleanup(config) {
|
|
113
|
+
await Promise.all(this.candidates.map(async (candidate) => {
|
|
114
|
+
await candidate.provider.cleanup(config).catch((error) => {
|
|
115
|
+
this.logger.warn(`Cleaning up tunnel candidate ${candidate.id} failed: ${describeError(error)}`);
|
|
116
|
+
});
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
/** Id of the candidate currently serving, once one is ready. */
|
|
120
|
+
getActiveId() {
|
|
121
|
+
return this.active?.id;
|
|
122
|
+
}
|
|
123
|
+
/** The candidates that were tried, and why the ones that lost did. */
|
|
124
|
+
getAttempts() {
|
|
125
|
+
return this.attempts;
|
|
126
|
+
}
|
|
127
|
+
async waitForReady(provider) {
|
|
128
|
+
const deadline = Date.now() + this.readinessTimeoutMs;
|
|
129
|
+
while (Date.now() < deadline) {
|
|
130
|
+
const status = provider.getStatus();
|
|
131
|
+
if (status.stage === 'proxy-ready' || status.connected) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
if (status.stage === 'failed') {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
await delay(this.pollIntervalMs);
|
|
138
|
+
}
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
/** Stop a candidate that lost and stop counting it as started. */
|
|
142
|
+
async dropCandidate(candidate) {
|
|
143
|
+
await candidate.provider.stop().catch((error) => {
|
|
144
|
+
this.logger.warn(`Stopping tunnel candidate ${candidate.id} failed: ${describeError(error)}`);
|
|
145
|
+
});
|
|
146
|
+
this.started = this.started.filter((started) => started.id !== candidate.id);
|
|
147
|
+
}
|
|
148
|
+
async stopLosers(winner) {
|
|
149
|
+
await Promise.all(this.started
|
|
150
|
+
.filter((candidate) => candidate.id !== winner.id)
|
|
151
|
+
.map(async (candidate) => {
|
|
152
|
+
await candidate.provider.stop().catch(() => undefined);
|
|
153
|
+
}));
|
|
154
|
+
this.started = [winner];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
exports.AutoTunnelProvider = AutoTunnelProvider;
|
|
158
|
+
/**
|
|
159
|
+
* The winning candidate's own status, with its error text attributed to the
|
|
160
|
+
* profile id the operator configured rather than to the provider class name.
|
|
161
|
+
*/
|
|
162
|
+
function withCandidate(candidate, status) {
|
|
163
|
+
const stage = status.stage ?? (status.connected ? 'proxy-ready' : 'process-started');
|
|
164
|
+
const error = status.error ? `${candidate.id}: ${status.error}` : undefined;
|
|
165
|
+
return (0, TunnelLifecycle_1.createTunnelStatus)(stage, {
|
|
166
|
+
...status,
|
|
167
|
+
...(error ? { error } : {}),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function describeStatus(status) {
|
|
171
|
+
return status.error ?? status.stage ?? (status.connected ? 'connected' : 'unknown');
|
|
172
|
+
}
|
|
173
|
+
function describeError(error) {
|
|
174
|
+
return error instanceof Error ? error.message : String(error);
|
|
175
|
+
}
|
|
176
|
+
function delay(ms) {
|
|
177
|
+
return new Promise((resolve) => {
|
|
178
|
+
setTimeout(resolve, ms);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=AutoTunnelProvider.js.map
|
|
@@ -10,6 +10,8 @@ export interface LocalTunnelProviderOptions {
|
|
|
10
10
|
publicUrl?: string;
|
|
11
11
|
/** cloudflared 可执行文件路径 (默认 'cloudflared') */
|
|
12
12
|
cloudflaredPath?: string;
|
|
13
|
+
/** 等待代理发布的毫秒数;超时后状态为 failed,而不是"仍在连接" */
|
|
14
|
+
connectTimeoutMs?: number;
|
|
13
15
|
}
|
|
14
16
|
/**
|
|
15
17
|
* Local Tunnel Provider
|
|
@@ -28,6 +30,7 @@ export declare class LocalTunnelProvider implements TunnelProvider {
|
|
|
28
30
|
private readonly tunnelToken;
|
|
29
31
|
private readonly publicUrl?;
|
|
30
32
|
private readonly cloudflaredPath;
|
|
33
|
+
private readonly connectTimeoutMs;
|
|
31
34
|
private process;
|
|
32
35
|
private status;
|
|
33
36
|
private currentConfig;
|
|
@@ -46,6 +49,8 @@ export declare class LocalTunnelProvider implements TunnelProvider {
|
|
|
46
49
|
/**
|
|
47
50
|
* 解析并打印 cloudflared 日志
|
|
48
51
|
*/
|
|
52
|
+
/** Set when the dashboard's origin port and this runtime's ingress port disagree. */
|
|
53
|
+
private originMismatch?;
|
|
49
54
|
private logOutput;
|
|
50
55
|
/**
|
|
51
56
|
* 停止隧道
|
|
@@ -86,3 +91,13 @@ export declare class LocalTunnelProvider implements TunnelProvider {
|
|
|
86
91
|
*/
|
|
87
92
|
isManagedByUs(): boolean;
|
|
88
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* The origin a remotely-managed tunnel declares for its hostname.
|
|
96
|
+
*
|
|
97
|
+
* Both halves are reported: pointing the dashboard at `https://localhost:<port>` while this
|
|
98
|
+
* runtime serves plain HTTP there fails the TLS handshake, and the edge shows only a 502.
|
|
99
|
+
*/
|
|
100
|
+
export declare function readDashboardOrigin(output: string): {
|
|
101
|
+
scheme: string;
|
|
102
|
+
port: number;
|
|
103
|
+
} | undefined;
|
|
@@ -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;
|