@undefineds.co/xpod 0.4.12 → 0.4.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/components-ignore.json +11 -7
- package/dist/acceptance/QleverSemanticConformance.js +7 -0
- package/dist/api/ai-gateway/providers/OfferingAuthorization.d.ts +6 -1
- package/dist/api/ai-gateway/providers/OfferingAuthorization.js +0 -3
- package/dist/api/ai-gateway/providers/ProviderRegistry.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/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/storage/rdf/PostgresRdfEngine.js +10 -4
- package/dist/storage/rdf/RdfAccessScope.js +15 -1
- package/dist/storage/rdf/RdfEngineRdfJsSource.js +10 -2
- 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 +3 -3
- 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/AiConnectionsPanel.js +2 -2
- 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 +13 -11
- package/node_modules/@undefineds.co/ai-connections/dist/authorization-methods.js +16 -13
- 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/dist/{ai-connections-client.d.ts → contract/ai-connections-client.d.ts} +4 -2
- package/node_modules/@undefineds.co/ai-connections/dist/{ai-connections-client.js → contract/ai-connections-client.js} +4 -2
- package/node_modules/@undefineds.co/ai-connections/dist/{client → contract/client}/normalize.d.ts +17 -7
- package/node_modules/@undefineds.co/ai-connections/dist/{client → contract/client}/normalize.js +18 -213
- package/node_modules/@undefineds.co/ai-connections/dist/{client → contract/client}/request.js +3 -3
- package/node_modules/@undefineds.co/ai-connections/dist/{client → contract/client}/types.d.ts +11 -2
- package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/index.cjs +8 -8
- package/node_modules/@undefineds.co/ai-connections/dist/contract/index.d.ts +9 -0
- package/node_modules/@undefineds.co/ai-connections/dist/contract/index.js +9 -0
- package/node_modules/@undefineds.co/ai-connections/dist/{provider-catalog.cjs → contract/provider-catalog.cjs} +5 -28
- package/node_modules/@undefineds.co/ai-connections/dist/{provider-catalog.d.ts → contract/provider-catalog.d.ts} +9 -8
- package/node_modules/@undefineds.co/ai-connections/dist/{provider-catalog.js → contract/provider-catalog.js} +11 -31
- package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/controller.js +3 -2
- 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 +20 -0
- package/node_modules/@undefineds.co/ai-connections/dist/display-wording.js +73 -0
- package/node_modules/@undefineds.co/ai-connections/dist/error-wording.d.ts +24 -0
- package/node_modules/@undefineds.co/ai-connections/dist/error-wording.js +253 -0
- package/node_modules/@undefineds.co/ai-connections/dist/gateway-endpoints.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/index.d.ts +2 -3
- package/node_modules/@undefineds.co/ai-connections/dist/index.js +2 -3
- 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 +25 -18
- package/node_modules/@undefineds.co/shared-ui/dist/index.d.ts +4 -2
- package/node_modules/@undefineds.co/shared-ui/dist/index.js +4 -2
- package/node_modules/@undefineds.co/shared-ui/dist/login/LoginModal.d.ts +4 -1
- package/node_modules/@undefineds.co/shared-ui/dist/login/LoginModal.js +12 -6
- package/node_modules/@undefineds.co/shared-ui/dist/login/LoginView.d.ts +1 -1
- package/node_modules/@undefineds.co/shared-ui/dist/login/host-types.d.ts +7 -1
- package/node_modules/@undefineds.co/shared-ui/dist/login/login-branding.d.ts +6 -0
- package/node_modules/@undefineds.co/shared-ui/dist/login/login-branding.js +18 -0
- package/node_modules/@undefineds.co/shared-ui/dist/user-facing-errors.d.ts +14 -2
- package/node_modules/@undefineds.co/shared-ui/dist/user-facing-errors.js +26 -17
- package/node_modules/@undefineds.co/solid-sdk/dist/login-store.d.ts +3 -3
- package/node_modules/@undefineds.co/solid-sdk/dist/login-store.js +3 -3
- package/package.json +4 -3
- package/static/auth-callback/assets/{AiConfigContext-DnQs1ZpW.js → AiConfigContext-DCXpjzpj.js} +1 -1
- package/static/auth-callback/assets/{AiConfigPage-DOtvlxH0.js → AiConfigPage-fe-xMIXa.js} +1 -1
- package/static/auth-callback/assets/{DocumentProcessingPanel-BS2voQgL.js → DocumentProcessingPanel-BGnkfMuU.js} +1 -1
- package/static/auth-callback/assets/{IndexLifecyclePanel-Cvt0cJtN.js → IndexLifecyclePanel-42Jups0j.js} +1 -1
- package/static/auth-callback/assets/{IndexSubjectPanel-Dhf01GqF.js → IndexSubjectPanel-CYyLOlQU.js} +1 -1
- package/static/auth-callback/assets/{ModelAssignmentsPanel-BJutWaAF.js → ModelAssignmentsPanel-BOvUH4yr.js} +1 -1
- package/static/auth-callback/assets/{ModelsPage-BRS0sje3.js → ModelsPage-DwyITxt7.js} +6 -6
- package/static/auth-callback/assets/NetworkPage-CG9RelJA.js +2 -0
- package/static/auth-callback/assets/{PaneListHeader-QQeJGTp4.js → PaneListHeader-yvd5ohs6.js} +1 -1
- package/static/auth-callback/assets/{SearchIndexingPanel-MyNUSEwT.js → SearchIndexingPanel-2_a6ezzj.js} +1 -1
- package/static/auth-callback/assets/{StatusSubjectPanel-DQkEVsFs.js → StatusSubjectPanel-8qtVxnzC.js} +1 -1
- package/static/auth-callback/assets/{StatusWorkspace-Dkv63Uwk.js → StatusWorkspace-CBdRahCF.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsPage-TIsUfX5d.js → SystemSettingsPage-BZJ6vWkg.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsSubjectPanel-BJWEt2-7.js → SystemSettingsSubjectPanel-xm08UhXP.js} +1 -1
- package/static/auth-callback/assets/XpodAiConnectionsPodStore-V6vgGfuw.js +3 -0
- package/static/auth-callback/assets/{activity-5hNeNKnL.js → activity-CeM7xly8.js} +1 -1
- package/static/auth-callback/assets/ai-connections-C6yaE6WQ.js +1 -0
- package/static/auth-callback/assets/{auth-callback-CAFZ3R0B.js → auth-callback-DTG8cSj7.js} +3 -3
- package/static/auth-callback/assets/{badge-CAIPI0CB.js → badge-qJo2Zr4d.js} +1 -1
- package/static/auth-callback/assets/{collection-runtime-D9s7h9YA.js → collection-runtime-Bztsz31a.js} +1 -1
- package/static/auth-callback/assets/{dialog-BjA109aX.js → dialog-D-h6x5x0.js} +1 -1
- package/static/auth-callback/assets/{download-B3Up5W2G.js → download-C2ir4lmR.js} +1 -1
- package/static/auth-callback/assets/{external-link-BTXgSPzB.js → external-link-THLDL4On.js} +1 -1
- package/static/auth-callback/assets/{index-CirW4CJf.js → index-BRpv4yO3.js} +1 -1
- package/static/auth-callback/assets/{index-BppXlxcp.js → index-BlVZb9A7.js} +1 -1
- package/static/auth-callback/assets/index-D983R1FV.js +4 -0
- package/static/auth-callback/assets/{index-browser-DtU38ni3.js → index-browser-3FvR0aaf.js} +1 -1
- package/static/auth-callback/assets/{key-round-CQCOrZ7x.js → key-round-C9U5j1Ly.js} +1 -1
- package/static/auth-callback/assets/{rotate-ccw-C1zM2KtS.js → rotate-ccw-DP45cD4o.js} +1 -1
- package/static/auth-callback/assets/{skeleton-Cqp7_M9-.js → skeleton-Dn4EiSCS.js} +1 -1
- package/static/auth-callback/assets/{waypoints-Bj6gAUSQ.js → waypoints-uqFQ3uEG.js} +1 -1
- package/static/auth-callback/assets/{workspace-layout-DK8mDzrY.js → workspace-layout-DLYK0Wwu.js} +1 -1
- package/static/auth-callback/auth-callback.html +1 -1
- package/static/dashboard/assets/{AiConfigContext-BsE7MqX8.js → AiConfigContext-DJcMECNw.js} +1 -1
- package/static/dashboard/assets/{AiConfigPage-DvM-lRXa.js → AiConfigPage-BvE7dOTy.js} +1 -1
- package/static/dashboard/assets/{DocumentProcessingPanel-BPfdlfuf.js → DocumentProcessingPanel-D9780krf.js} +1 -1
- package/static/dashboard/assets/{IndexLifecyclePanel--m0AGxvh.js → IndexLifecyclePanel-SjsUcnbM.js} +1 -1
- package/static/dashboard/assets/{IndexSubjectPanel-Bb7m1k3d.js → IndexSubjectPanel-C-ym2Tqi.js} +1 -1
- package/static/dashboard/assets/{ModelAssignmentsPanel-BLi_zbMa.js → ModelAssignmentsPanel-BRjZ-arB.js} +1 -1
- package/static/dashboard/assets/{ModelsPage-CxdpgnfR.js → ModelsPage-BtTU6du3.js} +6 -6
- package/static/dashboard/assets/NetworkPage-CV9qpkDg.js +2 -0
- package/static/dashboard/assets/{PaneListHeader-BBCMei0r.js → PaneListHeader-KyPTTBsv.js} +1 -1
- package/static/dashboard/assets/{SearchIndexingPanel-Ck4Y-xjR.js → SearchIndexingPanel-DolHGawg.js} +1 -1
- package/static/dashboard/assets/{StatusSubjectPanel-D1KWfAXE.js → StatusSubjectPanel-_YZvKiYi.js} +1 -1
- package/static/dashboard/assets/{StatusWorkspace-JbA5gzXx.js → StatusWorkspace-Dlbh_G40.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsPage-BbwQWsSR.js → SystemSettingsPage-Be7QSIoz.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsSubjectPanel-N117nMt5.js → SystemSettingsSubjectPanel-DBp0gja7.js} +1 -1
- package/static/dashboard/assets/{XpodAiConnectionsPodStore-CdDOb4SV.js → XpodAiConnectionsPodStore-ClpSjzpP.js} +7 -7
- package/static/dashboard/assets/{activity-DX1I96o_.js → activity-lsNbTXJu.js} +1 -1
- package/static/dashboard/assets/ai-connections-CXp5gd1J.js +1 -0
- package/static/dashboard/assets/{badge-k2vhtDqH.js → badge-CVatKjaG.js} +1 -1
- package/static/dashboard/assets/{collection-runtime-BFQ8teQJ.js → collection-runtime-Ec4UnY28.js} +1 -1
- package/static/dashboard/assets/{dashboard-DWZ-fmCT.js → dashboard-BEzsRsvF.js} +2 -2
- package/static/dashboard/assets/{dialog-1CCw-iHT.js → dialog-BuyelQ4V.js} +1 -1
- package/static/dashboard/assets/{download-C6-SNY1q.js → download-B4Nf678F.js} +1 -1
- package/static/dashboard/assets/{external-link-BgPcZ_j2.js → external-link-PYv9CvKL.js} +1 -1
- package/static/dashboard/assets/index-C9XPE-mI.js +4 -0
- package/static/dashboard/assets/{index-D7A8U6Pt.js → index-Cx69bTNh.js} +1 -1
- package/static/dashboard/assets/{index-6LcIUIYO.js → index-awr7ulur.js} +1 -1
- package/static/dashboard/assets/{key-round-BOd7Jo0Q.js → key-round-VsY80U1Z.js} +1 -1
- package/static/dashboard/assets/{rotate-ccw-CCgJqsvx.js → rotate-ccw-Cz1K4vE9.js} +1 -1
- package/static/dashboard/assets/{skeleton-Bc7abAn5.js → skeleton-BhNv_8tO.js} +1 -1
- package/static/dashboard/assets/{waypoints-s-opmJxx.js → waypoints-DYS9XFYV.js} +1 -1
- package/static/dashboard/assets/{workspace-layout-DqIQeTBV.js → workspace-layout-OZJAFx5V.js} +1 -1
- package/static/dashboard/dashboard.html +1 -1
- package/static/settings/assets/{AiConfigContext-BB9KZySa.js → AiConfigContext-B8JS3MXF.js} +1 -1
- package/static/settings/assets/{AiConfigPage-DGSXUkLs.js → AiConfigPage-C3Zl8LUl.js} +1 -1
- package/static/settings/assets/{DocumentProcessingPanel-Da2Re6Rg.js → DocumentProcessingPanel-DpDZAQvf.js} +1 -1
- package/static/settings/assets/{IndexLifecyclePanel-BSZuIzgr.js → IndexLifecyclePanel-Ec1XF88t.js} +1 -1
- package/static/settings/assets/{IndexSubjectPanel-CFd0ay-r.js → IndexSubjectPanel-BulT9BmO.js} +1 -1
- package/static/settings/assets/{ModelAssignmentsPanel-CSAryvWJ.js → ModelAssignmentsPanel-BcGSmYjb.js} +1 -1
- package/static/settings/assets/{ModelsPage-BQwCwLHU.js → ModelsPage-CvTCKy1T.js} +6 -6
- package/static/settings/assets/NetworkPage-DQF5u9Bn.js +2 -0
- package/static/settings/assets/{PaneListHeader-Bjh3hRdQ.js → PaneListHeader-D40hqcVl.js} +1 -1
- package/static/settings/assets/{SearchIndexingPanel-MjKL5QLU.js → SearchIndexingPanel-iCUPOx_0.js} +1 -1
- package/static/settings/assets/{StatusSubjectPanel-Bvl6K4mx.js → StatusSubjectPanel-E--ZHSql.js} +1 -1
- package/static/settings/assets/{StatusWorkspace-B0NzrP--.js → StatusWorkspace-YjDAx1II.js} +1 -1
- package/static/settings/assets/{SystemSettingsPage-D2z6Z4FE.js → SystemSettingsPage-CDdV3mC9.js} +1 -1
- package/static/settings/assets/{SystemSettingsSubjectPanel-4sxma4X4.js → SystemSettingsSubjectPanel-Br8WazDq.js} +1 -1
- package/static/settings/assets/XpodAiConnectionsPodStore-CLr38P_Z.js +3 -0
- package/static/settings/assets/{activity-CgJJGpjx.js → activity-C5DAHHTE.js} +1 -1
- package/static/settings/assets/ai-connections-C6yaE6WQ.js +1 -0
- package/static/settings/assets/{badge-C4NypVyT.js → badge-D8eIyxKt.js} +1 -1
- package/static/settings/assets/{collection-runtime-CTLCDxAi.js → collection-runtime-DLc9zil8.js} +1 -1
- package/static/settings/assets/{dialog-Csq0vWUi.js → dialog-CyuR7Va4.js} +1 -1
- package/static/settings/assets/{download-DaLJJ-Wp.js → download-c0oxZrCz.js} +1 -1
- package/static/settings/assets/{external-link--w_iW5Au.js → external-link-D3Z34fP_.js} +1 -1
- package/static/settings/assets/{index-BukHiu4y.js → index-CKGbRFlc.js} +1 -1
- package/static/settings/assets/index-CSr3-2Cj.js +4 -0
- package/static/settings/assets/{index-COmVnZi2.js → index-ComidxAm.js} +1 -1
- package/static/settings/assets/{index-browser-BGpvHwD0.js → index-browser-CAscEbae.js} +1 -1
- package/static/settings/assets/{key-round-Bk4YRjBu.js → key-round-DyjLmXuB.js} +1 -1
- package/static/settings/assets/{rotate-ccw-TCabbqsr.js → rotate-ccw-679HF_ec.js} +1 -1
- package/static/settings/assets/{settings-CJWpdbNC.js → settings-DKknqu4C.js} +3 -3
- package/static/settings/assets/{skeleton-JDHYVe7t.js → skeleton-CkopNkPB.js} +1 -1
- package/static/settings/assets/{waypoints-DDvEl-MU.js → waypoints-CrqfAftE.js} +1 -1
- package/static/settings/assets/{workspace-layout-DV5QU30U.js → workspace-layout-UN6c4qTG.js} +1 -1
- package/static/settings/settings.html +1 -1
- package/static/auth-callback/assets/NetworkPage-B3qBfANA.js +0 -2
- package/static/auth-callback/assets/XpodAiConnectionsPodStore-BJiXm-PF.js +0 -3
- package/static/auth-callback/assets/ai-connections-CryuHGKW.js +0 -1
- package/static/auth-callback/assets/index-DlLYWOhw.js +0 -4
- package/static/dashboard/assets/NetworkPage-BAIPw-D_.js +0 -2
- package/static/dashboard/assets/ai-connections-DwCRqOQa.js +0 -1
- package/static/dashboard/assets/index-UD6QOE7H.js +0 -4
- package/static/settings/assets/NetworkPage-BKymvsQc.js +0 -2
- package/static/settings/assets/XpodAiConnectionsPodStore-BkNQ8fZx.js +0 -3
- package/static/settings/assets/ai-connections-CryuHGKW.js +0 -1
- package/static/settings/assets/index-B0mQa59b.js +0 -4
- /package/node_modules/@undefineds.co/ai-connections/dist/{client → contract/client}/request.d.ts +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client → contract/client}/types.js +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/base-adapter.d.ts +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/base-adapter.js +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/codex.d.ts +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/codex.js +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/index.d.ts +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/index.js +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/json-env-adapter.d.ts +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/json-env-adapter.js +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/pi.d.ts +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/pi.js +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/transaction.d.ts +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/transaction.js +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/types.d.ts +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{client-config → contract/client-config}/types.js +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{credential-storage.d.ts → contract/credential-storage.d.ts} +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{credential-storage.js → contract/credential-storage.js} +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{endpoint-urls.d.ts → contract/endpoint-urls.d.ts} +0 -0
- /package/node_modules/@undefineds.co/ai-connections/dist/{endpoint-urls.js → contract/endpoint-urls.js} +0 -0
|
@@ -5,12 +5,20 @@
|
|
|
5
5
|
* 使用 SakuraFRP 提供隧道服务
|
|
6
6
|
* 用于没有公网 IP 的 Local 节点
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* 凭据就是控制台「配置文件」里那串启动参数 (`<访问密钥>:<隧道ID>`)。公网入口
|
|
9
|
+
* **不由用户声明**:控制台只让用户选节点和本地端口,访问地址是平台分配的,因此
|
|
10
|
+
* provider 用同一个凭据向 SakuraFrp 开放 API 查询分配结果(节点地址 + 远程端口),
|
|
11
|
+
* 声明字段只作为 API 不可用时的可选兜底。
|
|
9
12
|
*/
|
|
10
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
14
|
exports.SakuraFrpTunnelProvider = void 0;
|
|
15
|
+
exports.resolveSakuraAssignedLocalPort = resolveSakuraAssignedLocalPort;
|
|
16
|
+
exports.parseSakuraCredential = parseSakuraCredential;
|
|
12
17
|
const node_child_process_1 = require("node:child_process");
|
|
13
18
|
const global_logger_factory_1 = require("global-logger-factory");
|
|
19
|
+
const TunnelLifecycle_1 = require("./TunnelLifecycle");
|
|
20
|
+
/** Where SakuraFrp assigns each tunnel's public entry. */
|
|
21
|
+
const DEFAULT_SAKURA_API_BASE_URL = 'https://api.natfrp.com/v4';
|
|
14
22
|
/**
|
|
15
23
|
* SakuraFRP Tunnel Provider
|
|
16
24
|
*
|
|
@@ -20,6 +28,8 @@ class SakuraFrpTunnelProvider {
|
|
|
20
28
|
constructor(options) {
|
|
21
29
|
this.name = 'sakura-frp';
|
|
22
30
|
this.logger = (0, global_logger_factory_1.getLoggerFor)(this);
|
|
31
|
+
/** Whether the platform terminates TLS for this entry (auto HTTPS). */
|
|
32
|
+
this.autoHttpsEnabled = false;
|
|
23
33
|
this.process = null;
|
|
24
34
|
this.status = {
|
|
25
35
|
running: false,
|
|
@@ -30,7 +40,131 @@ class SakuraFrpTunnelProvider {
|
|
|
30
40
|
this.token = options.token;
|
|
31
41
|
this.publicUrl = normalizePublicEndpoint(options.publicUrl);
|
|
32
42
|
this.frpcPath = options.frpcPath ?? 'frpc';
|
|
43
|
+
this.connectTimeoutMs = options.connectTimeoutMs ?? 30_000;
|
|
33
44
|
this.serverAddr = options.serverAddr;
|
|
45
|
+
this.apiBaseUrl = (options.apiBaseUrl ?? DEFAULT_SAKURA_API_BASE_URL).replace(/\/+$/u, '');
|
|
46
|
+
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Reads back the entry the platform assigned to this tunnel.
|
|
50
|
+
*
|
|
51
|
+
* The console never asks for a domain: for a TCP tunnel it assigns a node host and a
|
|
52
|
+
* remote port, and for a bound tunnel it assigns the domain itself. Asking the provider
|
|
53
|
+
* is therefore the only honest way to learn the entry, and a failure to ask changes
|
|
54
|
+
* nothing except that the status stops short of naming an endpoint.
|
|
55
|
+
*/
|
|
56
|
+
async discoverEndpoint() {
|
|
57
|
+
const { accessKey, tunnelIds } = parseSakuraCredential(this.token);
|
|
58
|
+
if (!accessKey) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const tunnels = await this.fetchJson('/tunnels', accessKey);
|
|
63
|
+
if (!Array.isArray(tunnels)) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
const selected = tunnelIds.length > 0
|
|
67
|
+
? tunnels.filter((tunnel) => tunnelIds.includes(String(tunnel?.id ?? '')))
|
|
68
|
+
: tunnels;
|
|
69
|
+
const tunnel = selected[0];
|
|
70
|
+
if (!tunnel) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const remote = typeof tunnel.remote === 'string' ? tunnel.remote.trim() : '';
|
|
74
|
+
if (!remote) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
// Whether the platform terminates TLS is decided before any address lookup, because
|
|
78
|
+
// it also governs the entry the client prints in its own log.
|
|
79
|
+
this.autoHttpsEnabled = /auto_https\s*=\s*(auto|on|true)/iu.test(tunnel.extra ?? '')
|
|
80
|
+
|| tunnel.type === 'https';
|
|
81
|
+
// A bound domain arrives as the remote value itself; a TCP tunnel arrives as a
|
|
82
|
+
// remote port and needs the node's host to become an address.
|
|
83
|
+
if (/[a-z]/iu.test(remote) && !remote.startsWith(':')) {
|
|
84
|
+
return `https://${remote.replace(/^https?:\/\//u, '')}/`;
|
|
85
|
+
}
|
|
86
|
+
const nodeHost = await this.resolveNodeHost(tunnel.node, accessKey);
|
|
87
|
+
// A TCP tunnel without auto-HTTPS leaves the entry as plain HTTP. SakuraFrp refuses
|
|
88
|
+
// plain HTTP to a web service on its mainland nodes by policy ("网页(国内节点)必须"
|
|
89
|
+
// enable it, per their own auto-HTTPS guide), so claiming such a URL would be a
|
|
90
|
+
// reachability claim the platform itself rejects.
|
|
91
|
+
if (!this.autoHttpsEnabled) {
|
|
92
|
+
this.discoveryBlockedReason = nodeHost
|
|
93
|
+
? `sakura-auto-https-required: enable 自动 HTTPS in the SakuraFrp console for ${nodeHost}:${remote}`
|
|
94
|
+
: `sakura-auto-https-required: enable 自动 HTTPS in the SakuraFrp console for the entry on port ${remote}`;
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
if (!nodeHost) {
|
|
98
|
+
// No API host: the client's own log names the entry, and the reason is not a policy
|
|
99
|
+
// block, so leave discoveryBlockedReason unset and let the log answer.
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
return `https://${nodeHost}:${remote}/`;
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
this.logger.warn(`Could not read the assigned SakuraFrp endpoint: ${error.message}`);
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Builds the parameter frpc needs, completing a bare access key with the tunnel it owns.
|
|
111
|
+
*
|
|
112
|
+
* `-f` accepts `<访问密钥>:<隧道ID>`; an operator who pasted only the access key would
|
|
113
|
+
* otherwise get `Bad fetch parameter` even though discovery can read the tunnel with that
|
|
114
|
+
* same key. Completion is only safe when the answer is unambiguous.
|
|
115
|
+
*/
|
|
116
|
+
async resolveClientCredential() {
|
|
117
|
+
const { accessKey, tunnelIds } = parseSakuraCredential(this.token);
|
|
118
|
+
if (!accessKey || tunnelIds.length > 0) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const tunnels = await this.fetchJson('/tunnels', accessKey);
|
|
123
|
+
if (!Array.isArray(tunnels) || tunnels.length !== 1) {
|
|
124
|
+
if (Array.isArray(tunnels) && tunnels.length > 1) {
|
|
125
|
+
this.logger.warn(`SakuraFrp credential holds no tunnel id and the account has ${tunnels.length} tunnels; use the console startup parameter`);
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
const completed = `${accessKey}:${tunnels[0]?.id}`;
|
|
130
|
+
this.logger.info(`SakuraFrp credential completed with the single tunnel id ${tunnels[0]?.id}`);
|
|
131
|
+
return completed;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async resolveNodeHost(node, accessKey) {
|
|
138
|
+
if (node === undefined) {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
const nodes = await this.fetchJson('/nodes', accessKey);
|
|
142
|
+
const record = nodes?.[String(node)];
|
|
143
|
+
const host = record?.host?.trim();
|
|
144
|
+
if (!host) {
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
return host.replace(/^https?:\/\//u, '').replace(/\/+$/u, '');
|
|
148
|
+
}
|
|
149
|
+
async fetchJson(path, accessKey) {
|
|
150
|
+
const response = await this.fetchImpl(`${this.apiBaseUrl}${path}`, {
|
|
151
|
+
headers: { authorization: `Bearer ${accessKey}`, accept: 'application/json' },
|
|
152
|
+
signal: AbortSignal.timeout(10_000),
|
|
153
|
+
});
|
|
154
|
+
if (!response.ok) {
|
|
155
|
+
throw new Error(`${path} answered ${response.status}`);
|
|
156
|
+
}
|
|
157
|
+
return await response.json();
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* The endpoint to report: what the platform assigned, else what the client printed, else
|
|
161
|
+
* what was declared. Nothing is invented when no source names an entry.
|
|
162
|
+
*/
|
|
163
|
+
currentEndpoint() {
|
|
164
|
+
return normalizePublicEndpoint(this.discoveredEndpoint)
|
|
165
|
+
?? this.logEndpoint
|
|
166
|
+
?? this.publicUrl
|
|
167
|
+
?? this.status.endpoint;
|
|
34
168
|
}
|
|
35
169
|
/**
|
|
36
170
|
* Setup: 解析 Token 获取配置
|
|
@@ -40,7 +174,7 @@ class SakuraFrpTunnelProvider {
|
|
|
40
174
|
// 这里返回基本配置,实际配置由 frpc 从 Token 获取
|
|
41
175
|
const config = {
|
|
42
176
|
subdomain: 'sakura',
|
|
43
|
-
provider: '
|
|
177
|
+
provider: 'sakura_frp',
|
|
44
178
|
endpoint: this.publicUrl ?? '',
|
|
45
179
|
tunnelToken: this.token,
|
|
46
180
|
};
|
|
@@ -53,14 +187,30 @@ class SakuraFrpTunnelProvider {
|
|
|
53
187
|
async start(config) {
|
|
54
188
|
const actualConfig = config ?? {
|
|
55
189
|
subdomain: 'sakura',
|
|
56
|
-
provider: '
|
|
190
|
+
provider: 'sakura_frp',
|
|
57
191
|
endpoint: this.publicUrl ?? '',
|
|
58
192
|
tunnelToken: this.token,
|
|
59
193
|
};
|
|
60
|
-
//
|
|
194
|
+
// Ask the platform where this tunnel is reachable before claiming any endpoint.
|
|
195
|
+
// The same answer completes the client parameter: the console's access key alone is not
|
|
196
|
+
// enough for `frpc -f`, which needs `<访问密钥>:<隧道ID>`.
|
|
197
|
+
this.discoveryBlockedReason = undefined;
|
|
198
|
+
this.discoveredEndpoint = await this.discoverEndpoint();
|
|
199
|
+
this.clientCredential = await this.resolveClientCredential();
|
|
200
|
+
if (this.discoveredEndpoint) {
|
|
201
|
+
this.logger.info(`SakuraFrp assigned ${this.discoveredEndpoint}`);
|
|
202
|
+
}
|
|
203
|
+
else if (this.discoveryBlockedReason) {
|
|
204
|
+
this.logger.warn(this.discoveryBlockedReason);
|
|
205
|
+
}
|
|
206
|
+
// A foreign frpc is not ours to adopt: another instance's tunnel would be reported as
|
|
207
|
+
// this provider's readiness and its stop would kill a process we do not own.
|
|
61
208
|
if (this.isFrpcRunning()) {
|
|
62
|
-
this.logger.
|
|
63
|
-
this.status =
|
|
209
|
+
this.logger.warn('Another frpc process is already running; refusing to take it over');
|
|
210
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('failed', {
|
|
211
|
+
endpoint: this.currentEndpoint(),
|
|
212
|
+
error: 'frpc-already-running',
|
|
213
|
+
});
|
|
64
214
|
this.currentConfig = actualConfig;
|
|
65
215
|
this.managedByUs = false;
|
|
66
216
|
return;
|
|
@@ -69,12 +219,12 @@ class SakuraFrpTunnelProvider {
|
|
|
69
219
|
this.logger.info('Already running (managed by us)');
|
|
70
220
|
return;
|
|
71
221
|
}
|
|
72
|
-
const token = actualConfig.tunnelToken ?? this.token;
|
|
222
|
+
const token = this.clientCredential ?? actualConfig.tunnelToken ?? this.token;
|
|
73
223
|
if (!token) {
|
|
74
224
|
throw new Error('SakuraFRP token is required');
|
|
75
225
|
}
|
|
76
226
|
this.logger.info('Starting SakuraFRP tunnel...');
|
|
77
|
-
this.status =
|
|
227
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('process-started', { endpoint: this.currentEndpoint() });
|
|
78
228
|
this.managedByUs = true;
|
|
79
229
|
// SakuraFRP 使用 frpc 客户端
|
|
80
230
|
// 命令格式: frpc -f <token>
|
|
@@ -101,32 +251,67 @@ class SakuraFrpTunnelProvider {
|
|
|
101
251
|
});
|
|
102
252
|
this.process.on('exit', (code) => {
|
|
103
253
|
this.logger.info(`frpc exited with code ${code}`);
|
|
104
|
-
this.status =
|
|
254
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('failed', {
|
|
255
|
+
endpoint: this.currentEndpoint(),
|
|
256
|
+
error: this.status.error ?? (code === 0 ? 'frpc-exited' : `frpc exited with code ${code}`),
|
|
257
|
+
});
|
|
105
258
|
this.process = null;
|
|
106
259
|
this.managedByUs = false;
|
|
107
260
|
});
|
|
108
261
|
this.process.on('error', (error) => {
|
|
109
|
-
|
|
110
|
-
this.
|
|
262
|
+
const described = (0, TunnelLifecycle_1.describeSpawnError)('sakura-frp', this.frpcPath, error);
|
|
263
|
+
this.logger.error(`Failed to start frpc: ${described}`);
|
|
264
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('failed', { endpoint: this.currentEndpoint(), error: described });
|
|
111
265
|
this.process = null;
|
|
112
266
|
this.managedByUs = false;
|
|
113
267
|
});
|
|
114
268
|
this.currentConfig = actualConfig;
|
|
115
269
|
// 等待连接
|
|
116
|
-
await this.waitForConnection();
|
|
270
|
+
await this.waitForConnection(this.connectTimeoutMs);
|
|
117
271
|
}
|
|
118
272
|
checkConnectionStatus(output) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
273
|
+
const lower = output.toLowerCase();
|
|
274
|
+
// The vendor client logs Chinese and the upstream client logs English; both vocabularies
|
|
275
|
+
// must count, otherwise a healthy official tunnel never leaves control-connected.
|
|
276
|
+
const proxyReady = lower.includes('start proxy success')
|
|
277
|
+
|| lower.includes('tunnel running')
|
|
278
|
+
|| output.includes('隧道启动成功');
|
|
279
|
+
const controlConnected = lower.includes('login to server success')
|
|
280
|
+
|| output.includes('连接节点成功');
|
|
281
|
+
// The official client prints the assigned entry ("使用 >>host:port<< 连接你的隧道"), which
|
|
282
|
+
// is the only source for nodes whose API record publishes no host.
|
|
283
|
+
const assigned = /使用\s*>>([^<]+)<<|连接方式[::]?\s*([\w.-]+:\d+)/u.exec(output);
|
|
284
|
+
if (assigned && this.autoHttpsEnabled) {
|
|
285
|
+
const address = (assigned[1] ?? assigned[2]).trim().replace(/^https?:\/\//u, '');
|
|
286
|
+
this.logEndpoint = `https://${address.replace(/\/+$/u, '')}/`;
|
|
287
|
+
}
|
|
288
|
+
// 代理已发布才算就绪
|
|
289
|
+
if (proxyReady) {
|
|
290
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('proxy-ready', {
|
|
291
|
+
endpoint: this.currentEndpoint(),
|
|
292
|
+
lastHeartbeat: new Date(),
|
|
293
|
+
// The proxy is up, but an entry the platform refuses to serve is not an entry.
|
|
294
|
+
error: this.discoveryBlockedReason ?? this.status.error,
|
|
295
|
+
});
|
|
125
296
|
this.logger.info('SakuraFRP tunnel connected');
|
|
126
297
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
this.status
|
|
298
|
+
else if (controlConnected && this.status.stage !== 'proxy-ready') {
|
|
299
|
+
// 控制连接成功说明凭据可用,但代理还没起来
|
|
300
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('control-connected', {
|
|
301
|
+
endpoint: this.currentEndpoint(),
|
|
302
|
+
error: this.status.error,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
// 检测错误:代理启动失败必须撤销"已连接"
|
|
306
|
+
if (lower.includes('start proxy error') || lower.includes('start error')) {
|
|
307
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('failed', {
|
|
308
|
+
endpoint: this.currentEndpoint(),
|
|
309
|
+
error: output,
|
|
310
|
+
});
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (lower.includes('error') || lower.includes('failed')) {
|
|
314
|
+
this.status = { ...this.status, error: output };
|
|
130
315
|
}
|
|
131
316
|
}
|
|
132
317
|
/**
|
|
@@ -135,7 +320,7 @@ class SakuraFrpTunnelProvider {
|
|
|
135
320
|
async stop() {
|
|
136
321
|
if (!this.managedByUs) {
|
|
137
322
|
this.logger.info('Not managed by us, skipping stop');
|
|
138
|
-
this.status = {
|
|
323
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('stopped', { endpoint: this.status.endpoint, error: this.status.error });
|
|
139
324
|
return;
|
|
140
325
|
}
|
|
141
326
|
if (this.process) {
|
|
@@ -155,14 +340,14 @@ class SakuraFrpTunnelProvider {
|
|
|
155
340
|
this.process = null;
|
|
156
341
|
this.logger.info('SakuraFRP tunnel stopped');
|
|
157
342
|
}
|
|
158
|
-
this.status = {
|
|
343
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('stopped', { endpoint: this.status.endpoint, error: this.status.error });
|
|
159
344
|
this.managedByUs = false;
|
|
160
345
|
}
|
|
161
346
|
getStatus() {
|
|
162
347
|
return { ...this.status };
|
|
163
348
|
}
|
|
164
349
|
getEndpoint() {
|
|
165
|
-
return this.
|
|
350
|
+
return this.currentEndpoint();
|
|
166
351
|
}
|
|
167
352
|
async cleanup(_config) {
|
|
168
353
|
await this.stop();
|
|
@@ -198,13 +383,71 @@ class SakuraFrpTunnelProvider {
|
|
|
198
383
|
}
|
|
199
384
|
await new Promise((r) => setTimeout(r, 500));
|
|
200
385
|
}
|
|
201
|
-
|
|
386
|
+
// Timeout is a visible failure: frpc is running but no proxy was published.
|
|
387
|
+
this.status = (0, TunnelLifecycle_1.createTunnelStatus)('failed', {
|
|
388
|
+
endpoint: this.currentEndpoint(),
|
|
389
|
+
error: this.status.error ?? 'frpc-connect-timeout',
|
|
390
|
+
});
|
|
391
|
+
this.logger.warn('frpc did not publish a proxy before the timeout');
|
|
392
|
+
throw new Error('SakuraFRP connection timeout');
|
|
202
393
|
}
|
|
203
394
|
isManagedByUs() {
|
|
204
395
|
return this.managedByUs;
|
|
205
396
|
}
|
|
206
397
|
}
|
|
207
398
|
exports.SakuraFrpTunnelProvider = SakuraFrpTunnelProvider;
|
|
399
|
+
/**
|
|
400
|
+
* The local port the SakuraFrp console told the tunnel to forward to.
|
|
401
|
+
*
|
|
402
|
+
* The console already owns this fact, and the provider reads the same API for the public
|
|
403
|
+
* entry, so the runtime must take the port from there instead of asking the operator to type
|
|
404
|
+
* it a second time.
|
|
405
|
+
*/
|
|
406
|
+
async function resolveSakuraAssignedLocalPort(token, options = {}) {
|
|
407
|
+
const { accessKey, tunnelIds } = parseSakuraCredential(token);
|
|
408
|
+
if (!accessKey) {
|
|
409
|
+
return undefined;
|
|
410
|
+
}
|
|
411
|
+
const base = (options.apiBaseUrl ?? DEFAULT_SAKURA_API_BASE_URL).replace(/\/+$/u, '');
|
|
412
|
+
const doFetch = options.fetchImpl ?? fetch;
|
|
413
|
+
try {
|
|
414
|
+
const response = await doFetch(`${base}/tunnels`, {
|
|
415
|
+
headers: { authorization: `Bearer ${accessKey}`, accept: 'application/json' },
|
|
416
|
+
signal: AbortSignal.timeout(10_000),
|
|
417
|
+
});
|
|
418
|
+
if (!response.ok) {
|
|
419
|
+
return undefined;
|
|
420
|
+
}
|
|
421
|
+
const tunnels = await response.json();
|
|
422
|
+
if (!Array.isArray(tunnels)) {
|
|
423
|
+
return undefined;
|
|
424
|
+
}
|
|
425
|
+
const selected = tunnelIds.length > 0
|
|
426
|
+
? tunnels.find((tunnel) => tunnelIds.includes(String(tunnel?.id ?? '')))
|
|
427
|
+
: tunnels[0];
|
|
428
|
+
const port = Number(selected?.local_port);
|
|
429
|
+
return Number.isInteger(port) && port > 0 && port <= 65535 ? port : undefined;
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
return undefined;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/** Splits the console's startup parameter into the access key and the tunnel ids. */
|
|
436
|
+
function parseSakuraCredential(value) {
|
|
437
|
+
const raw = value?.trim();
|
|
438
|
+
if (!raw) {
|
|
439
|
+
return { tunnelIds: [] };
|
|
440
|
+
}
|
|
441
|
+
const separator = raw.indexOf(':');
|
|
442
|
+
if (separator < 0) {
|
|
443
|
+
// Older setups stored the bare access key; the platform then decides the tunnel.
|
|
444
|
+
return { accessKey: raw, tunnelIds: [] };
|
|
445
|
+
}
|
|
446
|
+
return {
|
|
447
|
+
accessKey: raw.slice(0, separator).trim() || undefined,
|
|
448
|
+
tunnelIds: raw.slice(separator + 1).split(',').map((id) => id.trim()).filter(Boolean),
|
|
449
|
+
};
|
|
450
|
+
}
|
|
208
451
|
function normalizePublicEndpoint(value) {
|
|
209
452
|
if (!value?.trim()) {
|
|
210
453
|
return undefined;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TunnelStage, TunnelStatus } from './TunnelProvider';
|
|
2
|
+
/**
|
|
3
|
+
* Tunnel readiness is a sequence, not a boolean.
|
|
4
|
+
*
|
|
5
|
+
* A provider process that started is not a control connection, a control connection is not
|
|
6
|
+
* a published proxy, and a published proxy is not proof that the Gateway is reachable from
|
|
7
|
+
* outside. These helpers keep every provider reporting the same four facts so the UI and
|
|
8
|
+
* the diagnostics never turn "we spawned something" into "the tunnel is up".
|
|
9
|
+
*/
|
|
10
|
+
export declare function createTunnelStatus(stage: TunnelStage, patch?: Partial<TunnelStatus>): TunnelStatus;
|
|
11
|
+
/** Keeps the previous error visible while a provider transitions through a restart. */
|
|
12
|
+
export declare function mergeTunnelError(previous: string | undefined, next: string | undefined): string | undefined;
|
|
13
|
+
/** Recognizes a missing client binary, which is a deployment fact, not a network failure. */
|
|
14
|
+
export declare function describeSpawnError(provider: string, binary: string, error: unknown): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createTunnelStatus = createTunnelStatus;
|
|
4
|
+
exports.mergeTunnelError = mergeTunnelError;
|
|
5
|
+
exports.describeSpawnError = describeSpawnError;
|
|
6
|
+
/**
|
|
7
|
+
* Tunnel readiness is a sequence, not a boolean.
|
|
8
|
+
*
|
|
9
|
+
* A provider process that started is not a control connection, a control connection is not
|
|
10
|
+
* a published proxy, and a published proxy is not proof that the Gateway is reachable from
|
|
11
|
+
* outside. These helpers keep every provider reporting the same four facts so the UI and
|
|
12
|
+
* the diagnostics never turn "we spawned something" into "the tunnel is up".
|
|
13
|
+
*/
|
|
14
|
+
function createTunnelStatus(stage, patch = {}) {
|
|
15
|
+
return {
|
|
16
|
+
running: stage !== 'stopped' && stage !== 'failed',
|
|
17
|
+
connected: stage === 'proxy-ready',
|
|
18
|
+
stage,
|
|
19
|
+
...patch,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** Keeps the previous error visible while a provider transitions through a restart. */
|
|
23
|
+
function mergeTunnelError(previous, next) {
|
|
24
|
+
return next ?? previous;
|
|
25
|
+
}
|
|
26
|
+
/** Recognizes a missing client binary, which is a deployment fact, not a network failure. */
|
|
27
|
+
function describeSpawnError(provider, binary, error) {
|
|
28
|
+
const code = typeof error === 'object' && error && 'code' in error ? String(error.code) : '';
|
|
29
|
+
if (code === 'ENOENT') {
|
|
30
|
+
return `binary-missing:${provider}:${binary}`;
|
|
31
|
+
}
|
|
32
|
+
return `spawn-failed:${provider}:${error?.message ?? String(error)}`;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=TunnelLifecycle.js.map
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { TUNNEL_PROVIDER_IDS, isTunnelProviderId, tunnelProfileCredentialEnvKey, tunnelProviderDescriptor, type ActiveTunnelProvider, type TunnelProviderId } from './TunnelProviderCatalog';
|
|
2
|
+
export { TUNNEL_PROVIDER_IDS };
|
|
1
3
|
export declare const TUNNEL_PROVIDER_VALUES: readonly ["ngrok", "cloudflare", "sakura_frp", "frp"];
|
|
2
|
-
export type TunnelProfileProvider =
|
|
3
|
-
export type ActiveTunnelProvider
|
|
4
|
+
export type TunnelProfileProvider = TunnelProviderId;
|
|
5
|
+
export type { ActiveTunnelProvider };
|
|
6
|
+
/** The canonical off value: an explicit "no tunnel" is a decision, not a missing value. */
|
|
7
|
+
export declare const TUNNEL_ACTIVE_PROFILE_NONE = "none";
|
|
4
8
|
export interface TunnelProfile {
|
|
5
9
|
id: string;
|
|
6
10
|
provider: TunnelProfileProvider;
|
|
@@ -8,6 +12,14 @@ export interface TunnelProfile {
|
|
|
8
12
|
publicUrl?: string;
|
|
9
13
|
credentialEnvKey?: string;
|
|
10
14
|
credentialConfigured?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Provider parameters as stored by the settings API.
|
|
17
|
+
*
|
|
18
|
+
* They are carried rather than dropped so the runtime never silently loses a value the
|
|
19
|
+
* API accepted, and so a provider that can honour one has it available; a parameter no
|
|
20
|
+
* provider consumes is reported by `unconsumedProfileParameters()` instead of vanishing.
|
|
21
|
+
*/
|
|
22
|
+
parameters?: Record<string, string>;
|
|
11
23
|
}
|
|
12
24
|
export interface TunnelProfileState {
|
|
13
25
|
profiles: TunnelProfile[];
|
|
@@ -15,8 +27,26 @@ export interface TunnelProfileState {
|
|
|
15
27
|
activeProfile?: TunnelProfile;
|
|
16
28
|
inactiveProfiles: TunnelProfile[];
|
|
17
29
|
activeProvider: ActiveTunnelProvider;
|
|
30
|
+
/** Why the requested profile is not active; missing when the state is unremarkable. */
|
|
31
|
+
activationError?: string;
|
|
18
32
|
}
|
|
19
33
|
type EnvLike = Record<string, string | undefined>;
|
|
34
|
+
/**
|
|
35
|
+
* Resolves the tunnel profile state for a runtime environment.
|
|
36
|
+
*
|
|
37
|
+
* Authority rules (they are what stops a closed tunnel from coming back):
|
|
38
|
+
* - `XPOD_TUNNEL_PROFILES` being **present** is authoritative — an empty list means "no
|
|
39
|
+
* profiles", never "fall back to the legacy keys".
|
|
40
|
+
* - `XPOD_TUNNEL_ACTIVE_PROFILE_ID` being **present** is authoritative — an empty value or
|
|
41
|
+
* `none` means "explicitly off" and suppresses the legacy provider and the auto-pick.
|
|
42
|
+
*/
|
|
20
43
|
export declare function resolveTunnelProfileState(env: EnvLike): TunnelProfileState;
|
|
21
44
|
export declare function selectActiveTunnelProfile(inputProfiles: readonly TunnelProfile[], activeProfileId?: string): TunnelProfileState;
|
|
22
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Parameters a profile declares that no provider implementation consumes.
|
|
47
|
+
*
|
|
48
|
+
* Reporting them is what keeps the settings form from collecting values with no effect:
|
|
49
|
+
* the fix is either to consume the parameter or to stop declaring the field.
|
|
50
|
+
*/
|
|
51
|
+
export declare function unconsumedProfileParameters(profile: Pick<TunnelProfile, 'parameters'>, consumed?: readonly string[]): string[];
|
|
52
|
+
export { isTunnelProviderId, tunnelProviderDescriptor, tunnelProfileCredentialEnvKey };
|