@undefineds.co/xpod 0.4.13 → 0.4.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/components-ignore.json +11 -7
- package/dist/api/ai-gateway/providers/ProviderRegistry.js +1 -1
- package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.d.ts +1 -1
- package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.js +1 -1
- package/dist/api/container/index.js +1 -0
- package/dist/api/container/local.js +30 -12
- package/dist/api/container/routes.js +2 -0
- package/dist/api/container/types.d.ts +2 -0
- package/dist/api/handlers/AdminHandler.d.ts +17 -1
- package/dist/api/handlers/AdminHandler.js +40 -3
- package/dist/api/handlers/EdgeNodeSignalHandler.js +10 -2
- package/dist/api/handlers/NetworkSettingsHandler.d.ts +37 -5
- package/dist/api/handlers/NetworkSettingsHandler.js +39 -11
- package/dist/api/handlers/ProvisionHandler.d.ts +6 -1
- package/dist/api/handlers/ProvisionHandler.js +7 -2
- package/dist/api/handlers/ReachabilityHandler.d.ts +6 -0
- package/dist/api/handlers/ReachabilityHandler.js +22 -5
- package/dist/api/network/NetworkEnvironmentConfigurationStore.d.ts +6 -1
- package/dist/api/network/NetworkEnvironmentConfigurationStore.js +72 -16
- package/dist/api/runtime.d.ts +9 -0
- package/dist/api/runtime.js +15 -2
- package/dist/api/service/AiClientConfigurationService.d.ts +1 -1
- package/dist/api/service/AiClientConfigurationService.js +1 -1
- package/dist/cli/commands/start.d.ts +19 -1
- package/dist/cli/commands/start.js +71 -5
- package/dist/components/context.jsonld +30 -0
- package/dist/edge/EdgeNodeAgent.d.ts +6 -0
- package/dist/edge/EdgeNodeAgent.js +1 -1
- package/dist/edge/EdgeNodeAgentInitializer.d.ts +2 -0
- package/dist/edge/EdgeNodeAgentInitializer.js +1 -0
- package/dist/edge/EdgeNodeAgentInitializer.jsonld +19 -0
- package/dist/edge/EdgeNodeDnsCoordinator.d.ts +11 -1
- package/dist/edge/EdgeNodeDnsCoordinator.js +12 -2
- package/dist/edge/EdgeNodeHealthProbeService.d.ts +15 -0
- package/dist/edge/EdgeNodeHealthProbeService.js +44 -12
- package/dist/edge/EdgeNodeHealthProbeService.jsonld +77 -0
- package/dist/edge/ProbeTargetGuard.d.ts +35 -0
- package/dist/edge/ProbeTargetGuard.js +142 -0
- package/dist/edge/reachability/NodeAccessResolver.d.ts +16 -0
- package/dist/edge/reachability/NodeAccessResolver.js +30 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +9 -3
- package/dist/main.js +7 -0
- package/dist/runtime/Proxy.d.ts +22 -0
- package/dist/runtime/Proxy.js +34 -7
- package/dist/runtime/bootstrap.d.ts +11 -0
- package/dist/runtime/bootstrap.js +21 -1
- package/dist/runtime/css-process.d.ts +1 -0
- package/dist/runtime/css-process.js +1 -0
- package/dist/runtime/host/node/NodeRuntimeHost.js +4 -1
- package/dist/runtime/host/types.d.ts +6 -0
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +5 -1
- package/dist/runtime/lifecycle.js +1 -0
- package/dist/runtime/port-finder.d.ts +30 -0
- package/dist/runtime/port-finder.js +83 -0
- package/dist/runtime/runner/node/NodeGatewayRuntimeRunner.js +1 -0
- package/dist/runtime/runner/types.d.ts +5 -0
- package/dist/runtime/runtime-types.d.ts +1 -0
- package/dist/test-utils/local-managed-client-p2p-e2e-smoke.js +1 -1
- package/dist/tunnel/LocalTunnelProvider.d.ts +15 -0
- package/dist/tunnel/LocalTunnelProvider.js +87 -18
- package/dist/tunnel/LocalTunnelProvider.jsonld +27 -0
- package/dist/tunnel/NgrokTunnelProvider.d.ts +4 -0
- package/dist/tunnel/NgrokTunnelProvider.js +117 -43
- package/dist/tunnel/NgrokTunnelProvider.jsonld +4 -0
- package/dist/tunnel/SakuraFrpTunnelProvider.d.ts +65 -3
- package/dist/tunnel/SakuraFrpTunnelProvider.js +268 -25
- package/dist/tunnel/TunnelLifecycle.d.ts +14 -0
- package/dist/tunnel/TunnelLifecycle.js +34 -0
- package/dist/tunnel/TunnelProfiles.d.ts +33 -3
- package/dist/tunnel/TunnelProfiles.js +105 -78
- package/dist/tunnel/TunnelProvider.d.ts +15 -2
- package/dist/tunnel/TunnelProvider.jsonld +8 -0
- package/dist/tunnel/TunnelProviderCatalog.d.ts +62 -0
- package/dist/tunnel/TunnelProviderCatalog.js +130 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiApiKeyPool.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiApiKeyPool.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiAuthorizationActions.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectDialog.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialRow.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiCustomProviderDialog.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeyRow.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayModelsSection.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiOfferingDetails.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiSortableCredentialList.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/authorization-methods.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/collection-runtime.js +3 -3
- package/node_modules/@undefineds.co/ai-connections/dist/collections.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/collections.js +3 -3
- package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/ai-connections-client.d.ts +1 -1
- package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/ai-connections-client.js +1 -1
- package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/index.cjs +8 -8
- package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/index.d.ts +1 -1
- package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/index.js +1 -1
- package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/provider-catalog.cjs +3 -3
- package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/controller.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/credential-labels.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/display-wording.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/error-wording.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/error-wording.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/gateway-endpoints.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/offering-endpoints.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/offering-label.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/service-access.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/useAiConnectDialog.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/package.json +31 -1
- package/package.json +5 -6
- package/static/app/assets/main.css +1 -1
- package/static/auth-callback/assets/{AiConfigContext-DlFyEWy9.js → AiConfigContext-DCXpjzpj.js} +1 -1
- package/static/auth-callback/assets/{AiConfigPage-CkYk-SFW.js → AiConfigPage-fe-xMIXa.js} +1 -1
- package/static/auth-callback/assets/{DocumentProcessingPanel-CqIr3JqN.js → DocumentProcessingPanel-BGnkfMuU.js} +1 -1
- package/static/auth-callback/assets/{IndexLifecyclePanel-C1GKV3Vx.js → IndexLifecyclePanel-42Jups0j.js} +1 -1
- package/static/auth-callback/assets/{IndexSubjectPanel-ro9lC6XW.js → IndexSubjectPanel-CYyLOlQU.js} +1 -1
- package/static/auth-callback/assets/{ModelAssignmentsPanel-DxNdyKRJ.js → ModelAssignmentsPanel-BOvUH4yr.js} +1 -1
- package/static/auth-callback/assets/{ModelsPage-BVtWSPBU.js → ModelsPage-DwyITxt7.js} +3 -3
- package/static/auth-callback/assets/NetworkPage-CG9RelJA.js +2 -0
- package/static/auth-callback/assets/{PaneListHeader-ByKw8ada.js → PaneListHeader-yvd5ohs6.js} +1 -1
- package/static/auth-callback/assets/{SearchIndexingPanel-CulBKcYT.js → SearchIndexingPanel-2_a6ezzj.js} +1 -1
- package/static/auth-callback/assets/{StatusSubjectPanel-VOcfrt8o.js → StatusSubjectPanel-8qtVxnzC.js} +1 -1
- package/static/auth-callback/assets/{StatusWorkspace-Jsz6hAdE.js → StatusWorkspace-CBdRahCF.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsPage-BFNvGAle.js → SystemSettingsPage-BZJ6vWkg.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsSubjectPanel-DFRdrSfK.js → SystemSettingsSubjectPanel-xm08UhXP.js} +1 -1
- package/static/auth-callback/assets/{XpodAiConnectionsPodStore-C6KpvHVg.js → XpodAiConnectionsPodStore-V6vgGfuw.js} +1 -1
- package/static/auth-callback/assets/{activity-DnTlb9iM.js → activity-CeM7xly8.js} +1 -1
- package/static/auth-callback/assets/{auth-callback-D2UkK5Xj.js → auth-callback-DTG8cSj7.js} +3 -3
- package/static/auth-callback/assets/auth-callback-rk080mvG.css +1 -0
- package/static/auth-callback/assets/{badge-D7IJuuTM.js → badge-qJo2Zr4d.js} +1 -1
- package/static/auth-callback/assets/{collection-runtime-wT1n4GS2.js → collection-runtime-Bztsz31a.js} +1 -1
- package/static/auth-callback/assets/{dialog-DickLu5z.js → dialog-D-h6x5x0.js} +1 -1
- package/static/auth-callback/assets/{download-kn8WnRu3.js → download-C2ir4lmR.js} +1 -1
- package/static/auth-callback/assets/{external-link-B6B8jfSn.js → external-link-THLDL4On.js} +1 -1
- package/static/auth-callback/assets/{index-Dz83EEHD.js → index-BRpv4yO3.js} +1 -1
- package/static/auth-callback/assets/{index-DHF97YLP.js → index-BlVZb9A7.js} +1 -1
- package/static/auth-callback/assets/index-D983R1FV.js +4 -0
- package/static/auth-callback/assets/{index-browser-CSghinyi.js → index-browser-3FvR0aaf.js} +1 -1
- package/static/auth-callback/assets/{key-round-ChkOx3E1.js → key-round-C9U5j1Ly.js} +1 -1
- package/static/auth-callback/assets/{rotate-ccw-B3hE-nyd.js → rotate-ccw-DP45cD4o.js} +1 -1
- package/static/auth-callback/assets/{skeleton-kEqR7tpI.js → skeleton-Dn4EiSCS.js} +1 -1
- package/static/auth-callback/assets/{waypoints-D6Jo-SZa.js → waypoints-uqFQ3uEG.js} +1 -1
- package/static/auth-callback/assets/{workspace-layout-BHwT_cHd.js → workspace-layout-DLYK0Wwu.js} +1 -1
- package/static/auth-callback/auth-callback.html +2 -2
- package/static/dashboard/assets/{AiConfigContext-BfC3v-x2.js → AiConfigContext-DJcMECNw.js} +1 -1
- package/static/dashboard/assets/{AiConfigPage-QNS3u7Ff.js → AiConfigPage-BvE7dOTy.js} +1 -1
- package/static/dashboard/assets/{DocumentProcessingPanel-Dr4XLeT4.js → DocumentProcessingPanel-D9780krf.js} +1 -1
- package/static/dashboard/assets/{IndexLifecyclePanel-KtM_gpeO.js → IndexLifecyclePanel-SjsUcnbM.js} +1 -1
- package/static/dashboard/assets/{IndexSubjectPanel-DLaiKdLc.js → IndexSubjectPanel-C-ym2Tqi.js} +1 -1
- package/static/dashboard/assets/{ModelAssignmentsPanel-Bk7TvQRq.js → ModelAssignmentsPanel-BRjZ-arB.js} +1 -1
- package/static/dashboard/assets/{ModelsPage-Cci3vlos.js → ModelsPage-BtTU6du3.js} +3 -3
- package/static/dashboard/assets/NetworkPage-CV9qpkDg.js +2 -0
- package/static/dashboard/assets/{PaneListHeader-qHME_s08.js → PaneListHeader-KyPTTBsv.js} +1 -1
- package/static/dashboard/assets/{SearchIndexingPanel-HZPKj8H9.js → SearchIndexingPanel-DolHGawg.js} +1 -1
- package/static/dashboard/assets/{StatusSubjectPanel-ij7IpI8d.js → StatusSubjectPanel-_YZvKiYi.js} +1 -1
- package/static/dashboard/assets/{StatusWorkspace-Cp02JcaN.js → StatusWorkspace-Dlbh_G40.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsPage-BSeuvb8X.js → SystemSettingsPage-Be7QSIoz.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsSubjectPanel-CP4_luGS.js → SystemSettingsSubjectPanel-DBp0gja7.js} +1 -1
- package/static/dashboard/assets/{XpodAiConnectionsPodStore-urO6zaHL.js → XpodAiConnectionsPodStore-ClpSjzpP.js} +1 -1
- package/static/dashboard/assets/{activity-DxjgQNvr.js → activity-lsNbTXJu.js} +1 -1
- package/static/dashboard/assets/{badge-53qCrRbl.js → badge-CVatKjaG.js} +1 -1
- package/static/dashboard/assets/{collection-runtime-BPAmHG46.js → collection-runtime-Ec4UnY28.js} +1 -1
- package/static/dashboard/assets/{dashboard-BcT2ByXw.js → dashboard-BEzsRsvF.js} +2 -2
- package/static/dashboard/assets/dashboard-rk080mvG.css +1 -0
- package/static/dashboard/assets/{dialog-B28YtNhS.js → dialog-BuyelQ4V.js} +1 -1
- package/static/dashboard/assets/{download-DkLNceJ4.js → download-B4Nf678F.js} +1 -1
- package/static/dashboard/assets/{external-link-D3TXnlo3.js → external-link-PYv9CvKL.js} +1 -1
- package/static/dashboard/assets/index-C9XPE-mI.js +4 -0
- package/static/dashboard/assets/{index-CFIenkeK.js → index-Cx69bTNh.js} +1 -1
- package/static/dashboard/assets/{index-CIiBu9mr.js → index-awr7ulur.js} +1 -1
- package/static/dashboard/assets/{key-round-B5ccp6nx.js → key-round-VsY80U1Z.js} +1 -1
- package/static/dashboard/assets/{rotate-ccw-DUpfkNnk.js → rotate-ccw-Cz1K4vE9.js} +1 -1
- package/static/dashboard/assets/{skeleton-BRe19fO0.js → skeleton-BhNv_8tO.js} +1 -1
- package/static/dashboard/assets/{waypoints-BKDMxEvu.js → waypoints-DYS9XFYV.js} +1 -1
- package/static/dashboard/assets/{workspace-layout-ZTF7C16h.js → workspace-layout-OZJAFx5V.js} +1 -1
- package/static/dashboard/dashboard.html +2 -2
- package/static/settings/assets/{AiConfigContext-DsyWgu2i.js → AiConfigContext-B8JS3MXF.js} +1 -1
- package/static/settings/assets/{AiConfigPage-CSCBckKo.js → AiConfigPage-C3Zl8LUl.js} +1 -1
- package/static/settings/assets/{DocumentProcessingPanel-w9yQDbBe.js → DocumentProcessingPanel-DpDZAQvf.js} +1 -1
- package/static/settings/assets/{IndexLifecyclePanel-CUUXI8mP.js → IndexLifecyclePanel-Ec1XF88t.js} +1 -1
- package/static/settings/assets/{IndexSubjectPanel-BypAU5TJ.js → IndexSubjectPanel-BulT9BmO.js} +1 -1
- package/static/settings/assets/{ModelAssignmentsPanel-BetgXw1G.js → ModelAssignmentsPanel-BcGSmYjb.js} +1 -1
- package/static/settings/assets/{ModelsPage-DZpTlTZ3.js → ModelsPage-CvTCKy1T.js} +3 -3
- package/static/settings/assets/NetworkPage-DQF5u9Bn.js +2 -0
- package/static/settings/assets/{PaneListHeader-BGOqGec4.js → PaneListHeader-D40hqcVl.js} +1 -1
- package/static/settings/assets/{SearchIndexingPanel-DYAbpZ_9.js → SearchIndexingPanel-iCUPOx_0.js} +1 -1
- package/static/settings/assets/{StatusSubjectPanel-CFgzeQ8Q.js → StatusSubjectPanel-E--ZHSql.js} +1 -1
- package/static/settings/assets/{StatusWorkspace-4Z6g4Jvv.js → StatusWorkspace-YjDAx1II.js} +1 -1
- package/static/settings/assets/{SystemSettingsPage-C1tlrgvI.js → SystemSettingsPage-CDdV3mC9.js} +1 -1
- package/static/settings/assets/{SystemSettingsSubjectPanel-CcURI-1L.js → SystemSettingsSubjectPanel-Br8WazDq.js} +1 -1
- package/static/settings/assets/{XpodAiConnectionsPodStore-owBQc5nY.js → XpodAiConnectionsPodStore-CLr38P_Z.js} +1 -1
- package/static/settings/assets/{activity-CtBc9cNy.js → activity-C5DAHHTE.js} +1 -1
- package/static/settings/assets/{badge--r-FDIhU.js → badge-D8eIyxKt.js} +1 -1
- package/static/settings/assets/{collection-runtime-CnhPmwAM.js → collection-runtime-DLc9zil8.js} +1 -1
- package/static/settings/assets/{dialog-B7ZRsjN7.js → dialog-CyuR7Va4.js} +1 -1
- package/static/settings/assets/{download-DgQ1F8QR.js → download-c0oxZrCz.js} +1 -1
- package/static/settings/assets/{external-link-Bz7NckNO.js → external-link-D3Z34fP_.js} +1 -1
- package/static/settings/assets/{index-Vv-8Vslg.js → index-CKGbRFlc.js} +1 -1
- package/static/settings/assets/index-CSr3-2Cj.js +4 -0
- package/static/settings/assets/{index-CkGda_Pg.js → index-ComidxAm.js} +1 -1
- package/static/settings/assets/{index-browser-Dq7omlpY.js → index-browser-CAscEbae.js} +1 -1
- package/static/settings/assets/{key-round-CvuhloKV.js → key-round-DyjLmXuB.js} +1 -1
- package/static/settings/assets/{rotate-ccw-DgFKDaz7.js → rotate-ccw-679HF_ec.js} +1 -1
- package/static/settings/assets/{settings-BvqY7K96.js → settings-DKknqu4C.js} +3 -3
- package/static/settings/assets/settings-rk080mvG.css +1 -0
- package/static/settings/assets/{skeleton-D3OeFDF6.js → skeleton-CkopNkPB.js} +1 -1
- package/static/settings/assets/{waypoints-C4WbspTb.js → waypoints-CrqfAftE.js} +1 -1
- package/static/settings/assets/{workspace-layout-B9H1Tqrk.js → workspace-layout-UN6c4qTG.js} +1 -1
- package/static/settings/settings.html +2 -2
- package/node_modules/@undefineds.co/ai-connections-core/package.json +0 -61
- package/static/auth-callback/assets/NetworkPage-cEvxRMAl.js +0 -2
- package/static/auth-callback/assets/auth-callback-Cx9D_1qj.css +0 -1
- package/static/auth-callback/assets/index-Cu0EguPo.js +0 -4
- package/static/dashboard/assets/NetworkPage-Ot4G2dX5.js +0 -2
- package/static/dashboard/assets/dashboard-Cx9D_1qj.css +0 -1
- package/static/dashboard/assets/index-Gp3cLolR.js +0 -4
- package/static/settings/assets/NetworkPage-BVkasFGM.js +0 -2
- package/static/settings/assets/index-BdXwm8nh.js +0 -4
- package/static/settings/assets/settings-Cx9D_1qj.css +0 -1
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client/normalize.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client/normalize.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client/request.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client/request.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client/types.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client/types.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/base-adapter.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/base-adapter.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/codex.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/codex.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/index.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/index.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/json-env-adapter.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/json-env-adapter.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/pi.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/pi.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/transaction.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/transaction.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/types.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/client-config/types.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/credential-storage.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/credential-storage.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/endpoint-urls.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/endpoint-urls.js +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/provider-catalog.d.ts +0 -0
- /package/node_modules/@undefineds.co/{ai-connections-core/dist → ai-connections/dist/contract}/provider-catalog.js +0 -0
|
@@ -42,7 +42,7 @@ function registerReachabilityRoutes(server, options) {
|
|
|
42
42
|
}
|
|
43
43
|
}, { optionalAuth: true });
|
|
44
44
|
server.post('/v1/signal/nodes/:nodeId/sessions', async (request, response, params) => {
|
|
45
|
-
const access = resolveSessionAccess(request, params.nodeId);
|
|
45
|
+
const access = await resolveSessionAccess(request, params.nodeId, options, 'node');
|
|
46
46
|
if (!access.allowed) {
|
|
47
47
|
sendJson(response, access.status, { error: access.error });
|
|
48
48
|
return;
|
|
@@ -119,7 +119,7 @@ function registerReachabilityRoutes(server, options) {
|
|
|
119
119
|
sendJson(response, 400, { error: 'kind must be p2p or relay' });
|
|
120
120
|
});
|
|
121
121
|
server.get('/v1/signal/nodes/:nodeId/sessions', async (request, response, params) => {
|
|
122
|
-
const access = resolveSessionAccess(request, params.nodeId);
|
|
122
|
+
const access = await resolveSessionAccess(request, params.nodeId, options, 'node');
|
|
123
123
|
if (!access.allowed) {
|
|
124
124
|
sendJson(response, access.status, { error: access.error });
|
|
125
125
|
return;
|
|
@@ -137,7 +137,7 @@ function registerReachabilityRoutes(server, options) {
|
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
139
|
server.get('/v1/signal/nodes/:nodeId/sessions/:sessionId', async (request, response, params) => {
|
|
140
|
-
const access = resolveSessionAccess(request, params.nodeId);
|
|
140
|
+
const access = await resolveSessionAccess(request, params.nodeId, options, 'session');
|
|
141
141
|
if (!access.allowed) {
|
|
142
142
|
sendJson(response, access.status, { error: access.error });
|
|
143
143
|
return;
|
|
@@ -155,7 +155,7 @@ function registerReachabilityRoutes(server, options) {
|
|
|
155
155
|
}
|
|
156
156
|
});
|
|
157
157
|
server.post('/v1/signal/nodes/:nodeId/sessions/:sessionId/candidates', async (request, response, params) => {
|
|
158
|
-
const access = resolveSessionAccess(request, params.nodeId);
|
|
158
|
+
const access = await resolveSessionAccess(request, params.nodeId, options, 'session');
|
|
159
159
|
if (!access.allowed) {
|
|
160
160
|
sendJson(response, access.status, { error: access.error });
|
|
161
161
|
return;
|
|
@@ -221,7 +221,7 @@ function resolveAccess(request, nodeId) {
|
|
|
221
221
|
}
|
|
222
222
|
return { allowed: true, audience: 'public' };
|
|
223
223
|
}
|
|
224
|
-
function resolveSessionAccess(request, nodeId) {
|
|
224
|
+
async function resolveSessionAccess(request, nodeId, options, target) {
|
|
225
225
|
const auth = request.auth;
|
|
226
226
|
if (!auth) {
|
|
227
227
|
return { allowed: false, status: 401, error: 'Authentication required' };
|
|
@@ -233,9 +233,26 @@ function resolveSessionAccess(request, nodeId) {
|
|
|
233
233
|
return { allowed: true, kind: 'node', nodeId: auth.nodeId };
|
|
234
234
|
}
|
|
235
235
|
if ((0, AuthContext_1.isServiceAuth)(auth)) {
|
|
236
|
+
// Service principals act for the deployment, so they must carry the scope that
|
|
237
|
+
// covers reachability sessions instead of being trusted by principal type alone.
|
|
238
|
+
if (!(0, AuthContext_1.hasScope)(auth, 'network:write')) {
|
|
239
|
+
return { allowed: false, status: 403, error: 'Creating a reachability session requires network:write' };
|
|
240
|
+
}
|
|
236
241
|
return { allowed: true, kind: 'service' };
|
|
237
242
|
}
|
|
238
243
|
if ((0, AuthContext_1.isSolidAuth)(auth)) {
|
|
244
|
+
// Node-wide operations need a resolvable relationship to the node (Pod ownership or
|
|
245
|
+
// an explicit grant): being logged in says nothing about this node. Operations on one
|
|
246
|
+
// session are gated by session ownership instead, so the owner keeps access to their
|
|
247
|
+
// own session even when node-wide discovery is not available to them.
|
|
248
|
+
if (target === 'node') {
|
|
249
|
+
const permitted = options.canAccessNode
|
|
250
|
+
? await options.canAccessNode(nodeId, auth.webId)
|
|
251
|
+
: false;
|
|
252
|
+
if (!permitted) {
|
|
253
|
+
return { allowed: false, status: 403, error: 'WebID is not authorized for this node' };
|
|
254
|
+
}
|
|
255
|
+
}
|
|
239
256
|
return { allowed: true, kind: 'solid', webId: auth.webId };
|
|
240
257
|
}
|
|
241
258
|
return { allowed: false, status: 403, error: 'Unsupported reachability session credentials' };
|
|
@@ -2,7 +2,12 @@ import type { NetworkConfigurationPatch, NetworkConfigurationStore, NetworkDesir
|
|
|
2
2
|
type Env = Record<string, string | undefined>;
|
|
3
3
|
export interface NetworkEnvironmentConfigurationStoreOptions {
|
|
4
4
|
read(): Env | Promise<Env>;
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Persists a patch. `removals` lists keys that must be deleted from the environment
|
|
7
|
+
* instead of overwritten — deleting a profile has to take its credential with it,
|
|
8
|
+
* otherwise the leftover secret rebuilds the tunnel the user just closed.
|
|
9
|
+
*/
|
|
10
|
+
write(patch: Record<string, string>, removals?: string[]): void | Promise<void>;
|
|
6
11
|
}
|
|
7
12
|
export declare class NetworkEnvironmentConfigurationStore implements NetworkConfigurationStore {
|
|
8
13
|
private readonly options;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NetworkEnvironmentConfigurationStore = void 0;
|
|
4
|
+
const TunnelProfiles_1 = require("../../tunnel/TunnelProfiles");
|
|
5
|
+
const TunnelProviderCatalog_1 = require("../../tunnel/TunnelProviderCatalog");
|
|
4
6
|
class NetworkEnvironmentConfigurationStore {
|
|
5
7
|
constructor(options) {
|
|
6
8
|
this.options = options;
|
|
@@ -10,9 +12,13 @@ class NetworkEnvironmentConfigurationStore {
|
|
|
10
12
|
}
|
|
11
13
|
async update(patch) {
|
|
12
14
|
const current = await this.options.read();
|
|
13
|
-
const envPatch = environmentPatch(patch, current);
|
|
14
|
-
await this.options.write(envPatch);
|
|
15
|
-
|
|
15
|
+
const { envPatch, removals } = environmentPatch(patch, current);
|
|
16
|
+
await this.options.write(envPatch, removals);
|
|
17
|
+
const next = { ...current, ...envPatch };
|
|
18
|
+
for (const key of removals) {
|
|
19
|
+
delete next[key];
|
|
20
|
+
}
|
|
21
|
+
return configurationFromEnv(next);
|
|
16
22
|
}
|
|
17
23
|
}
|
|
18
24
|
exports.NetworkEnvironmentConfigurationStore = NetworkEnvironmentConfigurationStore;
|
|
@@ -35,7 +41,12 @@ function configurationFromEnv(env) {
|
|
|
35
41
|
...(env.XPOD_HTTPS_KEY_PATH ? { certificateKeyPath: env.XPOD_HTTPS_KEY_PATH } : {}),
|
|
36
42
|
renewBeforeDays: positiveInteger(env.XPOD_ACME_RENEW_BEFORE_DAYS, 30),
|
|
37
43
|
},
|
|
38
|
-
tunnelProfiles: {
|
|
44
|
+
tunnelProfiles: {
|
|
45
|
+
activeProfileId: env.XPOD_TUNNEL_ACTIVE_PROFILE_ID !== undefined
|
|
46
|
+
? (env.XPOD_TUNNEL_ACTIVE_PROFILE_ID.trim() || TunnelProfiles_1.TUNNEL_ACTIVE_PROFILE_NONE)
|
|
47
|
+
: '',
|
|
48
|
+
profiles,
|
|
49
|
+
},
|
|
39
50
|
p2p: {
|
|
40
51
|
enabled: env.XPOD_P2P_ENABLED === 'true',
|
|
41
52
|
signalService: env.XPOD_P2P_SIGNAL_SERVICE ?? '',
|
|
@@ -45,6 +56,7 @@ function configurationFromEnv(env) {
|
|
|
45
56
|
}
|
|
46
57
|
function environmentPatch(patch, current) {
|
|
47
58
|
const output = {};
|
|
59
|
+
const removals = new Set();
|
|
48
60
|
if (patch.domainDns) {
|
|
49
61
|
assign(output, 'XPOD_DNS_DOMAIN', patch.domainDns.domain);
|
|
50
62
|
assign(output, 'XPOD_DDNS_ENABLED', boolString(patch.domainDns.ddnsEnabled));
|
|
@@ -57,8 +69,10 @@ function environmentPatch(patch, current) {
|
|
|
57
69
|
assign(output, 'XPOD_HTTPS_MODE', patch.https.enabled === undefined ? undefined : patch.https.enabled ? 'acme' : 'off');
|
|
58
70
|
assign(output, 'XPOD_ACME_EMAIL', patch.https.acmeEmail);
|
|
59
71
|
assign(output, 'XPOD_ACME_DOMAINS', patch.https.domains?.join(','));
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
// The runtime reads the ACME key names; the settings page used to write
|
|
73
|
+
// XPOD_HTTPS_* which nothing consumed.
|
|
74
|
+
assign(output, 'XPOD_ACME_CERTIFICATE_PATH', patch.https.certificatePath);
|
|
75
|
+
assign(output, 'XPOD_ACME_CERTIFICATE_KEY_PATH', patch.https.certificateKeyPath);
|
|
62
76
|
assign(output, 'XPOD_ACME_RENEW_BEFORE_DAYS', numberString(patch.https.renewBeforeDays));
|
|
63
77
|
}
|
|
64
78
|
if (patch.p2p) {
|
|
@@ -67,19 +81,38 @@ function environmentPatch(patch, current) {
|
|
|
67
81
|
assign(output, 'XPOD_P2P_FALLBACK_POLICY', patch.p2p.fallbackPolicy);
|
|
68
82
|
}
|
|
69
83
|
if (patch.tunnelProfiles) {
|
|
70
|
-
|
|
84
|
+
// An empty selection is the explicit off decision, stored as its own value so the
|
|
85
|
+
// runtime can tell it apart from "never configured".
|
|
86
|
+
assign(output, 'XPOD_TUNNEL_ACTIVE_PROFILE_ID', patch.tunnelProfiles.activeProfileId === ''
|
|
87
|
+
? TunnelProfiles_1.TUNNEL_ACTIVE_PROFILE_NONE
|
|
88
|
+
: patch.tunnelProfiles.activeProfileId);
|
|
71
89
|
if (patch.tunnelProfiles.profiles) {
|
|
72
|
-
const serialized = patch.tunnelProfiles.profiles.map(({ credential, ...profile }) =>
|
|
90
|
+
const serialized = patch.tunnelProfiles.profiles.map(({ credential, publicEndpoint, ...profile }) => ({
|
|
91
|
+
...profile,
|
|
92
|
+
// Canonical field name: the runtime reads publicUrl.
|
|
93
|
+
...(profile.publicUrl ?? publicEndpoint ? { publicUrl: profile.publicUrl ?? publicEndpoint } : {}),
|
|
94
|
+
}));
|
|
73
95
|
output.XPOD_TUNNEL_PROFILES = JSON.stringify(serialized);
|
|
74
|
-
for (const profile of patch.tunnelProfiles.profiles)
|
|
75
|
-
if (profile.credential !== undefined)
|
|
76
|
-
output[
|
|
96
|
+
for (const profile of patch.tunnelProfiles.profiles) {
|
|
97
|
+
if (profile.credential !== undefined && profile.credential !== '') {
|
|
98
|
+
output[(0, TunnelProfiles_1.tunnelProfileCredentialEnvKey)(profile.id)] = profile.credential;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Credentials of profiles that are gone must go with them.
|
|
102
|
+
for (const key of Object.keys(current)) {
|
|
103
|
+
if (!(0, TunnelProviderCatalog_1.isTunnelProfileCredentialEnvKey)(key)) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (!patch.tunnelProfiles.profiles.some((profile) => (0, TunnelProfiles_1.tunnelProfileCredentialEnvKey)(profile.id) === key)) {
|
|
107
|
+
removals.add(key);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
77
110
|
}
|
|
78
111
|
}
|
|
79
|
-
return output;
|
|
112
|
+
return { envPatch: output, removals: [...removals] };
|
|
80
113
|
}
|
|
81
114
|
function parseProfiles(raw, env) {
|
|
82
|
-
if (
|
|
115
|
+
if (raw === undefined)
|
|
83
116
|
return [];
|
|
84
117
|
try {
|
|
85
118
|
const values = JSON.parse(raw);
|
|
@@ -89,21 +122,44 @@ function parseProfiles(raw, env) {
|
|
|
89
122
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
90
123
|
return [];
|
|
91
124
|
const item = value;
|
|
92
|
-
if (typeof item.id !== 'string' || typeof item.label !== 'string' || !
|
|
125
|
+
if (typeof item.id !== 'string' || typeof item.label !== 'string' || !(0, TunnelProviderCatalog_1.isTunnelProviderId)(item.provider))
|
|
93
126
|
return [];
|
|
94
127
|
const provider = item.provider;
|
|
95
|
-
|
|
128
|
+
const publicUrl = firstString(item.publicUrl, item.publicEndpoint);
|
|
129
|
+
const credentialKey = resolveCredentialKey(item.id, provider, env);
|
|
130
|
+
return [{
|
|
131
|
+
id: item.id,
|
|
132
|
+
provider,
|
|
133
|
+
label: item.label,
|
|
134
|
+
...(publicUrl ? { publicUrl } : {}),
|
|
135
|
+
credentialConfigured: Boolean(env[credentialKey]),
|
|
136
|
+
...(plainStringRecord(item.parameters) ? { parameters: item.parameters } : {}),
|
|
137
|
+
}];
|
|
96
138
|
});
|
|
97
139
|
}
|
|
98
140
|
catch {
|
|
99
141
|
return [];
|
|
100
142
|
}
|
|
101
143
|
}
|
|
144
|
+
/** Profile-scoped credential first; a provider-global key still serves legacy setups. */
|
|
145
|
+
function resolveCredentialKey(profileId, provider, env) {
|
|
146
|
+
const scopedKey = (0, TunnelProfiles_1.tunnelProfileCredentialEnvKey)(profileId);
|
|
147
|
+
if (env[scopedKey])
|
|
148
|
+
return scopedKey;
|
|
149
|
+
const legacyKey = (0, TunnelProviderCatalog_1.tunnelProviderDescriptor)(provider)?.legacyCredentialEnvKey;
|
|
150
|
+
return legacyKey && env[legacyKey] ? legacyKey : scopedKey;
|
|
151
|
+
}
|
|
152
|
+
function firstString(...values) {
|
|
153
|
+
for (const value of values) {
|
|
154
|
+
if (typeof value === 'string' && value.trim())
|
|
155
|
+
return value.trim();
|
|
156
|
+
}
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
102
159
|
function splitList(value) { return value?.split(',').map((item) => item.trim()).filter(Boolean) ?? []; }
|
|
103
160
|
function positiveInteger(value, fallback) { const parsed = Number(value); return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback; }
|
|
104
161
|
function dnsCredential(env, provider) { return env[dnsCredentialKey(provider)]; }
|
|
105
162
|
function dnsCredentialKey(provider) { return provider === 'tencent' ? 'XPOD_TENCENT_DNS_TOKEN' : provider === 'cloudflare' ? 'CLOUDFLARE_API_TOKEN' : 'XPOD_DNS_PROVIDER_TOKEN'; }
|
|
106
|
-
function tunnelCredentialKey(provider) { return provider === 'ngrok' ? 'NGROK_AUTHTOKEN' : provider === 'cloudflare' ? 'CLOUDFLARE_TUNNEL_TOKEN' : 'FRP_TUNNEL_TOKEN'; }
|
|
107
163
|
function p2pFallback(value) { return value === 'never' || value === 'prefer-p2p' ? value : 'when-direct-unavailable'; }
|
|
108
164
|
function plainStringRecord(value) { return Boolean(value) && typeof value === 'object' && !Array.isArray(value) && Object.values(value).every((item) => typeof item === 'string'); }
|
|
109
165
|
function boolString(value) { return value === undefined ? undefined : String(value); }
|
package/dist/api/runtime.d.ts
CHANGED
|
@@ -18,4 +18,13 @@ export interface ApiServiceHandle {
|
|
|
18
18
|
stop: () => Promise<void>;
|
|
19
19
|
}
|
|
20
20
|
export declare function autoProvisionFirstRunLocal(config: ApiContainerConfig, logger: ReturnType<typeof getLoggerFor>): Promise<ApiContainerConfig>;
|
|
21
|
+
/**
|
|
22
|
+
* Port a managed tunnel forwards to.
|
|
23
|
+
*
|
|
24
|
+
* It must be the Gateway's ingress listener rather than the gateway port itself:
|
|
25
|
+
* a tunnel terminating on the gateway port reaches the Gateway from loopback and
|
|
26
|
+
* would let forwarded remote requests inherit local trust. Falls back to the
|
|
27
|
+
* historical gateway port only when no ingress listener was provisioned.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveTunnelIngressPort(env?: NodeJS.ProcessEnv): number;
|
|
21
30
|
export declare function startApiService(options?: StartApiServiceOptions): Promise<ApiServiceHandle>;
|
package/dist/api/runtime.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.autoProvisionFirstRunLocal = autoProvisionFirstRunLocal;
|
|
4
|
+
exports.resolveTunnelIngressPort = resolveTunnelIngressPort;
|
|
4
5
|
exports.startApiService = startApiService;
|
|
5
6
|
const awilix_1 = require("awilix");
|
|
6
7
|
const global_logger_factory_1 = require("global-logger-factory");
|
|
@@ -314,6 +315,19 @@ async function reconcileLocalOwnerRoles(container, config, logger) {
|
|
|
314
315
|
logger.error(`Failed to reconcile local owner roles: ${error}`);
|
|
315
316
|
}
|
|
316
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* Port a managed tunnel forwards to.
|
|
320
|
+
*
|
|
321
|
+
* It must be the Gateway's ingress listener rather than the gateway port itself:
|
|
322
|
+
* a tunnel terminating on the gateway port reaches the Gateway from loopback and
|
|
323
|
+
* would let forwarded remote requests inherit local trust. Falls back to the
|
|
324
|
+
* historical gateway port only when no ingress listener was provisioned.
|
|
325
|
+
*/
|
|
326
|
+
function resolveTunnelIngressPort(env = process.env) {
|
|
327
|
+
const raw = env.XPOD_GATEWAY_INGRESS_PORT ?? env.XPOD_MAIN_PORT ?? env.CSS_PORT ?? env.PORT ?? '3000';
|
|
328
|
+
const parsed = Number.parseInt(raw, 10);
|
|
329
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : 3000;
|
|
330
|
+
}
|
|
317
331
|
async function startBackgroundServices(container, logger) {
|
|
318
332
|
try {
|
|
319
333
|
const localNetworkManager = container.resolve('localNetworkManager', { allowUnregistered: true });
|
|
@@ -338,10 +352,9 @@ async function startBackgroundServices(container, logger) {
|
|
|
338
352
|
const localTunnelProvider = container.resolve('localTunnelProvider', { allowUnregistered: true });
|
|
339
353
|
if (localTunnelProvider) {
|
|
340
354
|
logger.info('Starting local tunnel provider...');
|
|
341
|
-
const localPort = Number.parseInt(process.env.XPOD_MAIN_PORT ?? process.env.CSS_PORT ?? process.env.PORT ?? '3000', 10);
|
|
342
355
|
const config = await localTunnelProvider.setup({
|
|
343
356
|
subdomain: 'local',
|
|
344
|
-
localPort:
|
|
357
|
+
localPort: resolveTunnelIngressPort(),
|
|
345
358
|
localProtocol: 'http',
|
|
346
359
|
});
|
|
347
360
|
await localTunnelProvider.start(config);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AiClientModelReference } from '@undefineds.co/ai-connections
|
|
1
|
+
import { type AiClientModelReference } from '@undefineds.co/ai-connections/client-config';
|
|
2
2
|
import type { AuthContext } from '../auth/AuthContext';
|
|
3
3
|
export type AiClientId = 'codex' | 'claude-code' | 'pi' | 'codebuddy';
|
|
4
4
|
export interface AiClientConfigurationCapabilityDescriptor {
|
|
@@ -10,7 +10,7 @@ const node_crypto_1 = require("node:crypto");
|
|
|
10
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
11
|
const node_fs_1 = require("node:fs");
|
|
12
12
|
const node_child_process_1 = require("node:child_process");
|
|
13
|
-
const client_config_1 = require("@undefineds.co/ai-connections
|
|
13
|
+
const client_config_1 = require("@undefineds.co/ai-connections/client-config");
|
|
14
14
|
const PLAN_SECRET_PLACEHOLDER = '[redacted]';
|
|
15
15
|
const MANUAL_INSTRUCTIONS = 'Manual client setup is available when this host cannot safely write local coding-client files.';
|
|
16
16
|
const CLIENT_LABELS = {
|
|
@@ -10,12 +10,30 @@ interface StartArgs {
|
|
|
10
10
|
seedConfig?: string;
|
|
11
11
|
}
|
|
12
12
|
export declare const startCommand: CommandModule<object, StartArgs>;
|
|
13
|
+
/**
|
|
14
|
+
* Where remote-forwarded traffic lands on this machine.
|
|
15
|
+
*
|
|
16
|
+
* Order: explicit `XPOD_GATEWAY_INGRESS_PORT` → the active SakuraFrp tunnel's assigned local
|
|
17
|
+
* port → an OS-assigned loopback port. The first two are strict, because a tunnel that
|
|
18
|
+
* forwards to a specific port cannot follow us somewhere else.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveIngressPort(config: {
|
|
21
|
+
tunnelProfiles?: Array<{
|
|
22
|
+
id: string;
|
|
23
|
+
provider: string;
|
|
24
|
+
credentialEnvKey?: string;
|
|
25
|
+
credentialConfigured?: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
tunnelActiveProfileId?: string;
|
|
28
|
+
}, mainPort: number): Promise<number>;
|
|
13
29
|
export declare function resolveCliOidcIssuer(env: Record<string, string | undefined>, provisionedIssuer?: string, edition?: string): string | undefined;
|
|
14
|
-
export declare function resolveManagedEdgeAgentConfig(config: Pick<ReturnType<typeof loadConfigFromEnv>, 'cloudApiEndpoint' | 'nodeId' | 'nodeToken'>, gatewayPort: number): {
|
|
30
|
+
export declare function resolveManagedEdgeAgentConfig(config: Pick<ReturnType<typeof loadConfigFromEnv>, 'cloudApiEndpoint' | 'nodeId' | 'nodeToken'>, gatewayPort: number, ingressPort?: number, runtimeEnv?: Record<string, string | undefined>): {
|
|
15
31
|
signalEndpoint: string;
|
|
16
32
|
nodeId: string;
|
|
17
33
|
nodeToken: string;
|
|
18
34
|
targetBaseUrl: string;
|
|
35
|
+
lanBaseUrl: string;
|
|
36
|
+
p2pEnabled: boolean;
|
|
19
37
|
} | undefined;
|
|
20
38
|
export declare function resolveChildDatabaseUrl(value: string, childCwd: string): string;
|
|
21
39
|
export declare function resolveCanonicalRuntimeBaseUrl(provisionedPublicUrl: string | undefined, configuredBaseUrl: string | undefined, localFallbackUrl: string): string;
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.startCommand = void 0;
|
|
7
|
+
exports.resolveIngressPort = resolveIngressPort;
|
|
7
8
|
exports.resolveCliOidcIssuer = resolveCliOidcIssuer;
|
|
8
9
|
exports.resolveManagedEdgeAgentConfig = resolveManagedEdgeAgentConfig;
|
|
9
10
|
exports.resolveChildDatabaseUrl = resolveChildDatabaseUrl;
|
|
@@ -15,6 +16,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
15
16
|
const global_logger_factory_1 = require("global-logger-factory");
|
|
16
17
|
const supervisor_1 = require("../../supervisor");
|
|
17
18
|
const runtime_1 = require("../../runtime");
|
|
19
|
+
const SakuraFrpTunnelProvider_1 = require("../../tunnel/SakuraFrpTunnelProvider");
|
|
18
20
|
const css_process_1 = require("../../runtime/css-process");
|
|
19
21
|
const oidc_issuer_1 = require("../../runtime/oidc-issuer");
|
|
20
22
|
const AuthMode_1 = require("../../authorization/AuthMode");
|
|
@@ -70,6 +72,10 @@ exports.startCommand = {
|
|
|
70
72
|
process.env[key] ??= value;
|
|
71
73
|
}
|
|
72
74
|
process.env.XPOD_ENV_FILE = envPath;
|
|
75
|
+
// The settings API persists to XPOD_ENV_PATH (falling back to `<cwd>/.env.local`).
|
|
76
|
+
// Without this, a deployment started with `-e custom.env` saved its configuration
|
|
77
|
+
// into a file the runtime never reads.
|
|
78
|
+
process.env.XPOD_ENV_PATH ??= envPath;
|
|
73
79
|
}
|
|
74
80
|
else if (argv.env || process.env.XPOD_ENV_FILE) {
|
|
75
81
|
console.warn(`Env file not found: ${envPath}`);
|
|
@@ -101,6 +107,19 @@ exports.startCommand = {
|
|
|
101
107
|
const cssPort = await (0, runtime_1.getFreePortForWildcard)(requestedCssPort);
|
|
102
108
|
const requestedApiPort = resolveServicePort(process.env.API_PORT, cssPort + 1, new Set([mainPort, cssPort]));
|
|
103
109
|
const apiPort = await (0, runtime_1.getFreePortForWildcard)(requestedApiPort);
|
|
110
|
+
// Remote forwarding (managed tunnels, P2P data plane) terminates on this machine, so
|
|
111
|
+
// its origin is a dedicated ingress port instead of the gateway port: the Gateway
|
|
112
|
+
// never treats requests accepted there as local. An explicit override is honoured;
|
|
113
|
+
// otherwise the OS assigns a loopback port, because neighbouring ports may already
|
|
114
|
+
// belong to another service this deployment planned.
|
|
115
|
+
// The port is a fact of whichever tunnel forwards to us: an explicit override pins it,
|
|
116
|
+
// and the SakuraFrp console's own 本地端口 is read back from the provider, so the
|
|
117
|
+
// operator never types the same number twice. Only an unmanaged ingress is ephemeral.
|
|
118
|
+
// A pinned port is taken as-is: silently moving it would leave the tunnel pointing at a
|
|
119
|
+
// port nobody listens on.
|
|
120
|
+
const ingressPort = await resolveIngressPort(provisionedConfig, mainPort);
|
|
121
|
+
// Published so the API can tell the operator which address a tunnel must forward to.
|
|
122
|
+
process.env.XPOD_GATEWAY_INGRESS_PORT = String(ingressPort);
|
|
104
123
|
const runtimeRoot = path_1.default.join(process.cwd(), '.xpod/runtime/legacy-css');
|
|
105
124
|
const identityDbUrl = resolveChildDatabaseUrl(process.env.CSS_IDENTITY_DB_URL ?? process.env.DATABASE_URL ?? 'sqlite:./data/identity.sqlite', runtimeRoot);
|
|
106
125
|
process.env.CSS_IDENTITY_DB_URL = identityDbUrl;
|
|
@@ -135,7 +154,7 @@ exports.startCommand = {
|
|
|
135
154
|
authMode,
|
|
136
155
|
externalOidcIssuer,
|
|
137
156
|
});
|
|
138
|
-
const managedEdge = resolveManagedEdgeAgentConfig(provisionedConfig, mainPort);
|
|
157
|
+
const managedEdge = resolveManagedEdgeAgentConfig(provisionedConfig, mainPort, ingressPort, process.env);
|
|
139
158
|
const cssArgs = (0, css_process_1.buildCssArgs)({
|
|
140
159
|
cssBinary: '__internal-css',
|
|
141
160
|
configPath: cssRuntimeConfig.configPath,
|
|
@@ -169,6 +188,7 @@ exports.startCommand = {
|
|
|
169
188
|
apiPort,
|
|
170
189
|
mainPort,
|
|
171
190
|
cssPort,
|
|
191
|
+
ingressPort,
|
|
172
192
|
baseUrl,
|
|
173
193
|
rdfIndexPath,
|
|
174
194
|
authMode,
|
|
@@ -180,6 +200,7 @@ exports.startCommand = {
|
|
|
180
200
|
exitOnStop: true,
|
|
181
201
|
baseUrl,
|
|
182
202
|
internalAdminAuthSecret: gatewayAdminProxyAuthSecret,
|
|
203
|
+
ingressPort,
|
|
183
204
|
});
|
|
184
205
|
proxy.setTargets({
|
|
185
206
|
css: `http://localhost:${cssPort}`,
|
|
@@ -195,8 +216,9 @@ exports.startCommand = {
|
|
|
195
216
|
nodeToken: managedEdge.nodeToken,
|
|
196
217
|
baseUrl,
|
|
197
218
|
p2p: {
|
|
198
|
-
enabled:
|
|
219
|
+
enabled: managedEdge.p2pEnabled,
|
|
199
220
|
targetBaseUrl: managedEdge.targetBaseUrl,
|
|
221
|
+
lanBaseUrl: managedEdge.lanBaseUrl,
|
|
200
222
|
},
|
|
201
223
|
});
|
|
202
224
|
}
|
|
@@ -210,20 +232,64 @@ exports.startCommand = {
|
|
|
210
232
|
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
211
233
|
},
|
|
212
234
|
};
|
|
235
|
+
/**
|
|
236
|
+
* Where remote-forwarded traffic lands on this machine.
|
|
237
|
+
*
|
|
238
|
+
* Order: explicit `XPOD_GATEWAY_INGRESS_PORT` → the active SakuraFrp tunnel's assigned local
|
|
239
|
+
* port → an OS-assigned loopback port. The first two are strict, because a tunnel that
|
|
240
|
+
* forwards to a specific port cannot follow us somewhere else.
|
|
241
|
+
*/
|
|
242
|
+
async function resolveIngressPort(config, mainPort) {
|
|
243
|
+
const explicit = process.env.XPOD_GATEWAY_INGRESS_PORT?.trim();
|
|
244
|
+
if (explicit) {
|
|
245
|
+
return await (0, runtime_1.requireFreePortForWildcard)(Number.parseInt(explicit, 10));
|
|
246
|
+
}
|
|
247
|
+
const active = config.tunnelProfiles?.find((profile) => profile.id === config.tunnelActiveProfileId)
|
|
248
|
+
?? config.tunnelProfiles?.find((profile) => profile.provider === 'sakura_frp');
|
|
249
|
+
if (active?.provider === 'sakura_frp') {
|
|
250
|
+
const credential = active.credentialEnvKey
|
|
251
|
+
? process.env[active.credentialEnvKey] ?? process.env.SAKURA_TUNNEL_TOKEN
|
|
252
|
+
: process.env.SAKURA_TUNNEL_TOKEN;
|
|
253
|
+
const assigned = await (0, SakuraFrpTunnelProvider_1.resolveSakuraAssignedLocalPort)(credential);
|
|
254
|
+
if (assigned && assigned !== mainPort) {
|
|
255
|
+
return await (0, runtime_1.requireFreePortForWildcard)(assigned);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// The operator copies this address into a provider console, so it has to survive
|
|
259
|
+
// restarts instead of being a fresh OS-assigned port every time.
|
|
260
|
+
const stateFile = path_1.default.join(process.cwd(), '.xpod', 'runtime', 'ingress-port');
|
|
261
|
+
const stable = await (0, runtime_1.resolveStableLoopbackPort)(stateFile);
|
|
262
|
+
if (stable.changed) {
|
|
263
|
+
(0, global_logger_factory_1.getLoggerFor)('XpodStart').warn(`The ingress port changed to ${stable.port}; update the tunnel console if it still forwards to the previous port`);
|
|
264
|
+
}
|
|
265
|
+
return stable.port;
|
|
266
|
+
}
|
|
213
267
|
function resolveCliOidcIssuer(env, provisionedIssuer, edition) {
|
|
214
268
|
return (0, oidc_issuer_1.resolveExternalOidcIssuer)(env)
|
|
215
269
|
?? (0, oidc_issuer_1.resolveExternalOidcIssuer)({ SOLID_OIDC_ISSUER: provisionedIssuer })
|
|
216
270
|
?? (edition === 'local' ? oidc_issuer_1.DEFAULT_LOCAL_OIDC_ISSUER : undefined);
|
|
217
271
|
}
|
|
218
|
-
function resolveManagedEdgeAgentConfig(config, gatewayPort) {
|
|
272
|
+
function resolveManagedEdgeAgentConfig(config, gatewayPort, ingressPort, runtimeEnv = {}) {
|
|
219
273
|
if (!config.cloudApiEndpoint || !config.nodeId || !config.nodeToken) {
|
|
220
274
|
return undefined;
|
|
221
275
|
}
|
|
276
|
+
const gatewayBaseUrl = `http://127.0.0.1:${gatewayPort}/`;
|
|
277
|
+
// The settings page owns these two decisions; the managed node identity only supplies
|
|
278
|
+
// the signal endpoint they run against.
|
|
279
|
+
const declaredSignalService = runtimeEnv.XPOD_P2P_SIGNAL_SERVICE?.trim();
|
|
280
|
+
const p2pDisabled = runtimeEnv.XPOD_P2P_ENABLED?.trim().toLowerCase() === 'false';
|
|
222
281
|
return {
|
|
223
|
-
signalEndpoint:
|
|
282
|
+
signalEndpoint: declaredSignalService
|
|
283
|
+
|| new URL('/v1/signal', config.cloudApiEndpoint).toString(),
|
|
224
284
|
nodeId: config.nodeId,
|
|
225
285
|
nodeToken: config.nodeToken,
|
|
226
|
-
|
|
286
|
+
// Forwarded peer traffic enters through the ingress listener, which never counts
|
|
287
|
+
// as local. LAN clients keep addressing the gateway listener, which they can reach.
|
|
288
|
+
targetBaseUrl: ingressPort === undefined ? gatewayBaseUrl : `http://127.0.0.1:${ingressPort}/`,
|
|
289
|
+
lanBaseUrl: gatewayBaseUrl,
|
|
290
|
+
// Peer-to-peer transport is off by default unless the deployment asked for it; an
|
|
291
|
+
// explicit false must actually stop it.
|
|
292
|
+
p2pEnabled: !p2pDisabled && runtimeEnv.XPOD_P2P_ENABLED?.trim().toLowerCase() === 'true',
|
|
227
293
|
};
|
|
228
294
|
}
|
|
229
295
|
function resolveChildDatabaseUrl(value, childCwd) {
|
|
@@ -1967,6 +1967,15 @@
|
|
|
1967
1967
|
"options_locations": {
|
|
1968
1968
|
"@id": "undefineds:dist/edge/EdgeNodeHealthProbeService.jsonld#EdgeNodeHealthProbeService_options_locations"
|
|
1969
1969
|
},
|
|
1970
|
+
"options_resolveAddresses": {
|
|
1971
|
+
"@id": "undefineds:dist/edge/EdgeNodeHealthProbeService.jsonld#EdgeNodeHealthProbeService_options_resolveAddresses"
|
|
1972
|
+
},
|
|
1973
|
+
"options_headRequest": {
|
|
1974
|
+
"@id": "undefineds:dist/edge/EdgeNodeHealthProbeService.jsonld#EdgeNodeHealthProbeService_options_headRequest"
|
|
1975
|
+
},
|
|
1976
|
+
"options_maxRedirects": {
|
|
1977
|
+
"@id": "undefineds:dist/edge/EdgeNodeHealthProbeService.jsonld#EdgeNodeHealthProbeService_options_maxRedirects"
|
|
1978
|
+
},
|
|
1970
1979
|
"repository": {
|
|
1971
1980
|
"@id": "undefineds:dist/edge/EdgeNodeHealthProbeService.jsonld#EdgeNodeHealthProbeService_options_repository"
|
|
1972
1981
|
},
|
|
@@ -1981,6 +1990,15 @@
|
|
|
1981
1990
|
},
|
|
1982
1991
|
"locations": {
|
|
1983
1992
|
"@id": "undefineds:dist/edge/EdgeNodeHealthProbeService.jsonld#EdgeNodeHealthProbeService_options_locations"
|
|
1993
|
+
},
|
|
1994
|
+
"resolveAddresses": {
|
|
1995
|
+
"@id": "undefineds:dist/edge/EdgeNodeHealthProbeService.jsonld#EdgeNodeHealthProbeService_options_resolveAddresses"
|
|
1996
|
+
},
|
|
1997
|
+
"headRequest": {
|
|
1998
|
+
"@id": "undefineds:dist/edge/EdgeNodeHealthProbeService.jsonld#EdgeNodeHealthProbeService_options_headRequest"
|
|
1999
|
+
},
|
|
2000
|
+
"maxRedirects": {
|
|
2001
|
+
"@id": "undefineds:dist/edge/EdgeNodeHealthProbeService.jsonld#EdgeNodeHealthProbeService_options_maxRedirects"
|
|
1984
2002
|
}
|
|
1985
2003
|
}
|
|
1986
2004
|
},
|
|
@@ -2029,6 +2047,9 @@
|
|
|
2029
2047
|
"options_p2pTargetBaseUrl": {
|
|
2030
2048
|
"@id": "undefineds:dist/edge/EdgeNodeAgentInitializer.jsonld#EdgeNodeAgentInitializer_options_p2pTargetBaseUrl"
|
|
2031
2049
|
},
|
|
2050
|
+
"options_p2pLanBaseUrl": {
|
|
2051
|
+
"@id": "undefineds:dist/edge/EdgeNodeAgentInitializer.jsonld#EdgeNodeAgentInitializer_options_p2pLanBaseUrl"
|
|
2052
|
+
},
|
|
2032
2053
|
"options_p2pLabel": {
|
|
2033
2054
|
"@id": "undefineds:dist/edge/EdgeNodeAgentInitializer.jsonld#EdgeNodeAgentInitializer_options_p2pLabel"
|
|
2034
2055
|
},
|
|
@@ -2118,6 +2139,9 @@
|
|
|
2118
2139
|
"p2pTargetBaseUrl": {
|
|
2119
2140
|
"@id": "undefineds:dist/edge/EdgeNodeAgentInitializer.jsonld#EdgeNodeAgentInitializer_options_p2pTargetBaseUrl"
|
|
2120
2141
|
},
|
|
2142
|
+
"p2pLanBaseUrl": {
|
|
2143
|
+
"@id": "undefineds:dist/edge/EdgeNodeAgentInitializer.jsonld#EdgeNodeAgentInitializer_options_p2pLanBaseUrl"
|
|
2144
|
+
},
|
|
2121
2145
|
"p2pLabel": {
|
|
2122
2146
|
"@id": "undefineds:dist/edge/EdgeNodeAgentInitializer.jsonld#EdgeNodeAgentInitializer_options_p2pLabel"
|
|
2123
2147
|
},
|
|
@@ -2959,6 +2983,9 @@
|
|
|
2959
2983
|
"options_cloudflaredPath": {
|
|
2960
2984
|
"@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider_options_cloudflaredPath"
|
|
2961
2985
|
},
|
|
2986
|
+
"options_connectTimeoutMs": {
|
|
2987
|
+
"@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider_options_connectTimeoutMs"
|
|
2988
|
+
},
|
|
2962
2989
|
"tunnelToken": {
|
|
2963
2990
|
"@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider_options_tunnelToken"
|
|
2964
2991
|
},
|
|
@@ -2967,6 +2994,9 @@
|
|
|
2967
2994
|
},
|
|
2968
2995
|
"cloudflaredPath": {
|
|
2969
2996
|
"@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider_options_cloudflaredPath"
|
|
2997
|
+
},
|
|
2998
|
+
"connectTimeoutMs": {
|
|
2999
|
+
"@id": "undefineds:dist/tunnel/LocalTunnelProvider.jsonld#LocalTunnelProvider_options_connectTimeoutMs"
|
|
2970
3000
|
}
|
|
2971
3001
|
}
|
|
2972
3002
|
},
|
|
@@ -47,6 +47,12 @@ export interface EdgeNodeAgentOptions {
|
|
|
47
47
|
p2p?: {
|
|
48
48
|
enabled?: boolean | string;
|
|
49
49
|
targetBaseUrl: string | URL;
|
|
50
|
+
/**
|
|
51
|
+
* Address this node advertises as its LAN route. Defaults to `targetBaseUrl`,
|
|
52
|
+
* and must be set when the forwarding target is a loopback-only listener that
|
|
53
|
+
* other devices on the LAN cannot reach.
|
|
54
|
+
*/
|
|
55
|
+
lanBaseUrl?: string | URL;
|
|
50
56
|
label?: string;
|
|
51
57
|
host?: string;
|
|
52
58
|
address?: string;
|
|
@@ -244,7 +244,7 @@ class EdgeNodeAgent {
|
|
|
244
244
|
if (!p2p || this.normalizeBoolean(p2p.enabled) === false) {
|
|
245
245
|
return [];
|
|
246
246
|
}
|
|
247
|
-
const endpoint = this.resolveLanGatewayEndpoint(p2p.targetBaseUrl);
|
|
247
|
+
const endpoint = this.resolveLanGatewayEndpoint(p2p.lanBaseUrl ?? p2p.targetBaseUrl);
|
|
248
248
|
if (!endpoint) {
|
|
249
249
|
return [];
|
|
250
250
|
}
|
|
@@ -16,6 +16,8 @@ export interface EdgeNodeAgentInitializerOptions {
|
|
|
16
16
|
intervalMs?: number | string;
|
|
17
17
|
p2pEnabled?: boolean | string;
|
|
18
18
|
p2pTargetBaseUrl?: string;
|
|
19
|
+
/** LAN-facing address; defaults to `p2pTargetBaseUrl` inside the agent. */
|
|
20
|
+
p2pLanBaseUrl?: string;
|
|
19
21
|
p2pLabel?: string;
|
|
20
22
|
p2pAcceptIntervalMs?: number | string;
|
|
21
23
|
p2pConnectTimeoutMs?: number | string;
|
|
@@ -86,6 +86,7 @@ class EdgeNodeAgentInitializer extends community_server_1.Initializer {
|
|
|
86
86
|
p2p: {
|
|
87
87
|
enabled: true,
|
|
88
88
|
targetBaseUrl: options.p2pTargetBaseUrl,
|
|
89
|
+
...(options.p2pLanBaseUrl ? { lanBaseUrl: options.p2pLanBaseUrl } : {}),
|
|
89
90
|
label: options.p2pLabel,
|
|
90
91
|
acceptIntervalMs: this.normalizePositiveInteger(options.p2pAcceptIntervalMs),
|
|
91
92
|
connectTimeoutMs: this.normalizePositiveInteger(options.p2pConnectTimeoutMs),
|
|
@@ -185,6 +185,19 @@
|
|
|
185
185
|
]
|
|
186
186
|
}
|
|
187
187
|
},
|
|
188
|
+
{
|
|
189
|
+
"@id": "undefineds:dist/edge/EdgeNodeAgentInitializer.jsonld#EdgeNodeAgentInitializer_options_p2pLanBaseUrl",
|
|
190
|
+
"range": {
|
|
191
|
+
"@type": "ParameterRangeUnion",
|
|
192
|
+
"parameterRangeElements": [
|
|
193
|
+
"xsd:string",
|
|
194
|
+
{
|
|
195
|
+
"@type": "ParameterRangeUndefined"
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
},
|
|
199
|
+
"comment": "LAN-facing address; defaults to `p2pTargetBaseUrl` inside the agent."
|
|
200
|
+
},
|
|
188
201
|
{
|
|
189
202
|
"@id": "undefineds:dist/edge/EdgeNodeAgentInitializer.jsonld#EdgeNodeAgentInitializer_options_p2pLabel",
|
|
190
203
|
"range": {
|
|
@@ -555,6 +568,12 @@
|
|
|
555
568
|
"@id": "undefineds:dist/edge/EdgeNodeAgentInitializer.jsonld#EdgeNodeAgentInitializer_options_p2pTargetBaseUrl"
|
|
556
569
|
}
|
|
557
570
|
},
|
|
571
|
+
{
|
|
572
|
+
"keyRaw": "p2pLanBaseUrl",
|
|
573
|
+
"value": {
|
|
574
|
+
"@id": "undefineds:dist/edge/EdgeNodeAgentInitializer.jsonld#EdgeNodeAgentInitializer_options_p2pLanBaseUrl"
|
|
575
|
+
}
|
|
576
|
+
},
|
|
558
577
|
{
|
|
559
578
|
"keyRaw": "p2pLabel",
|
|
560
579
|
"value": {
|