@undefineds.co/xpod 0.4.14 → 0.4.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/config/cloud.json +0 -3
  2. package/config/local.json +0 -3
  3. package/config/xpod.base.json +0 -24
  4. package/dist/api/ai-config/AiConfigStore.d.ts +2 -2
  5. package/dist/api/ai-config/AiConfigStore.js +4 -1
  6. package/dist/api/ai-gateway/auth/CallerPodAccess.d.ts +2 -5
  7. package/dist/api/ai-gateway/auth/CallerPodAccess.js +3 -42
  8. package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.d.ts +2 -1
  9. package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js +1 -1
  10. package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.d.ts +3 -8
  11. package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js +9 -32
  12. package/dist/api/ai-gateway/connect/index.d.ts +3 -3
  13. package/dist/api/ai-gateway/connect/index.js +9 -38
  14. package/dist/api/ai-gateway/errors.js +2 -1
  15. package/dist/api/ai-gateway/models/PodModelSelectionRepository.d.ts +3 -3
  16. package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +7 -11
  17. package/dist/api/ai-gateway/pod/HostedPodRoute.d.ts +27 -0
  18. package/dist/api/ai-gateway/pod/HostedPodRoute.js +47 -0
  19. package/dist/api/ai-gateway/pod/OwnerPodAccess.d.ts +79 -0
  20. package/dist/api/ai-gateway/pod/OwnerPodAccess.js +192 -0
  21. package/dist/api/ai-gateway/pod/PodInterfaceKeyStore.d.ts +52 -0
  22. package/dist/api/ai-gateway/pod/PodInterfaceKeyStore.js +61 -0
  23. package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.d.ts +3 -3
  24. package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.js +7 -32
  25. package/dist/api/auth/ClientCredentialsAuthenticator.js +5 -28
  26. package/dist/api/auth/TokenEndpointRoute.d.ts +18 -0
  27. package/dist/api/auth/TokenEndpointRoute.js +36 -0
  28. package/dist/api/chatkit/pod-store.d.ts +4 -4
  29. package/dist/api/chatkit/pod-store.js +24 -95
  30. package/dist/api/container/common.js +36 -23
  31. package/dist/api/container/local.js +62 -29
  32. package/dist/api/container/routes.js +39 -7
  33. package/dist/api/container/types.d.ts +2 -2
  34. package/dist/api/handlers/AiGatewayManagementHandler.d.ts +6 -0
  35. package/dist/api/handlers/AiGatewayManagementHandler.js +17 -4
  36. package/dist/api/handlers/NetworkSettingsHandler.d.ts +7 -0
  37. package/dist/api/handlers/NetworkSettingsHandler.js +7 -0
  38. package/dist/api/handlers/PodSettingsHandler.d.ts +3 -3
  39. package/dist/api/handlers/PodSettingsHandler.js +3 -3
  40. package/dist/api/handlers/ProvisionHandler.d.ts +29 -0
  41. package/dist/api/handlers/ProvisionHandler.js +46 -0
  42. package/dist/api/handlers/ReachabilityHandler.js +3 -1
  43. package/dist/api/runtime.d.ts +9 -0
  44. package/dist/api/runtime.js +16 -3
  45. package/dist/cli/commands/start.d.ts +9 -2
  46. package/dist/cli/commands/start.js +15 -17
  47. package/dist/components/components.jsonld +1 -1
  48. package/dist/components/context.jsonld +5 -42
  49. package/dist/edge/EdgeNodeAgent.d.ts +10 -0
  50. package/dist/edge/EdgeNodeAgent.js +55 -0
  51. package/dist/edge/EdgeNodeAgent.jsonld +8 -0
  52. package/dist/edge/reachability/ReachabilitySessionService.js +4 -1
  53. package/dist/edge/reachability/RouteSetBuilder.d.ts +18 -1
  54. package/dist/edge/reachability/RouteSetBuilder.js +47 -0
  55. package/dist/edge/reachability/RouteSetBuilder.jsonld +29 -0
  56. package/dist/edge/reachability/types.d.ts +8 -2
  57. package/dist/http/SubgraphSparqlHttpHandler.d.ts +1 -25
  58. package/dist/http/SubgraphSparqlHttpHandler.js +0 -100
  59. package/dist/http/SubgraphSparqlHttpHandler.jsonld +0 -8
  60. package/dist/identity/drizzle/PodInterfaceKeyRepository.d.ts +33 -0
  61. package/dist/identity/drizzle/PodInterfaceKeyRepository.js +78 -0
  62. package/dist/identity/drizzle/db.d.ts +7 -0
  63. package/dist/identity/drizzle/db.js +30 -0
  64. package/dist/identity/drizzle/schema.pg.d.ts +9 -0
  65. package/dist/identity/drizzle/schema.pg.js +16 -1
  66. package/dist/identity/drizzle/schema.sqlite.d.ts +106 -0
  67. package/dist/identity/drizzle/schema.sqlite.js +16 -1
  68. package/dist/index.d.ts +1 -2
  69. package/dist/index.js +3 -5
  70. package/dist/runtime/GatewayAdminProxyAuth.d.ts +1 -16
  71. package/dist/runtime/GatewayAdminProxyAuth.js +2 -71
  72. package/dist/runtime/Proxy.d.ts +10 -1
  73. package/dist/runtime/Proxy.js +95 -28
  74. package/dist/runtime/bootstrap.d.ts +10 -0
  75. package/dist/runtime/bootstrap.js +24 -0
  76. package/dist/runtime/host/node/NodeRuntimeHost.js +5 -3
  77. package/dist/runtime/index.d.ts +1 -1
  78. package/dist/runtime/index.js +2 -3
  79. package/dist/runtime/js-runtime.js +10 -3
  80. package/dist/runtime/lifecycle.js +5 -4
  81. package/dist/runtime/port-finder.d.ts +9 -13
  82. package/dist/runtime/port-finder.js +18 -37
  83. package/dist/tunnel/AutoTunnelProvider.d.ts +56 -0
  84. package/dist/tunnel/AutoTunnelProvider.js +181 -0
  85. package/dist/tunnel/index.d.ts +1 -0
  86. package/dist/tunnel/index.js +3 -1
  87. package/node_modules/@undefineds.co/ai-connections/dist/error-wording.js +7 -2
  88. package/node_modules/@undefineds.co/solid-sdk/dist/access-route.cjs +230 -0
  89. package/node_modules/@undefineds.co/solid-sdk/dist/access-route.d.ts +76 -0
  90. package/node_modules/@undefineds.co/solid-sdk/dist/access-route.js +115 -0
  91. package/node_modules/@undefineds.co/solid-sdk/dist/index.cjs +89 -0
  92. package/node_modules/@undefineds.co/solid-sdk/dist/index.d.ts +1 -0
  93. package/node_modules/@undefineds.co/solid-sdk/dist/index.js +1 -0
  94. package/node_modules/@undefineds.co/solid-sdk/package.json +6 -1
  95. package/package.json +2 -2
  96. package/static/app/assets/inrupt-smoke.js +23 -23
  97. package/static/auth-callback/assets/{AiConfigContext-DCXpjzpj.js → AiConfigContext-Bx0HCAW5.js} +1 -1
  98. package/static/auth-callback/assets/{AiConfigPage-fe-xMIXa.js → AiConfigPage-ChQImMbm.js} +1 -1
  99. package/static/auth-callback/assets/{DocumentProcessingPanel-BGnkfMuU.js → DocumentProcessingPanel-D830H4SH.js} +1 -1
  100. package/static/auth-callback/assets/{IndexLifecyclePanel-42Jups0j.js → IndexLifecyclePanel-CnlkjMF8.js} +1 -1
  101. package/static/auth-callback/assets/{IndexSubjectPanel-CYyLOlQU.js → IndexSubjectPanel-CdEfg_CO.js} +1 -1
  102. package/static/auth-callback/assets/{ModelAssignmentsPanel-BOvUH4yr.js → ModelAssignmentsPanel-D-8A8dZx.js} +1 -1
  103. package/static/auth-callback/assets/{ModelsPage-DwyITxt7.js → ModelsPage-Cim7cubp.js} +3 -3
  104. package/static/auth-callback/assets/{NetworkPage-CG9RelJA.js → NetworkPage-CfK3x-pb.js} +2 -2
  105. package/static/auth-callback/assets/{PaneListHeader-yvd5ohs6.js → PaneListHeader-Bf_kEd4U.js} +1 -1
  106. package/static/auth-callback/assets/{SearchIndexingPanel-2_a6ezzj.js → SearchIndexingPanel-4kD4RBEQ.js} +1 -1
  107. package/static/auth-callback/assets/{StatusSubjectPanel-8qtVxnzC.js → StatusSubjectPanel-Bw9AiTSf.js} +1 -1
  108. package/static/auth-callback/assets/{StatusWorkspace-CBdRahCF.js → StatusWorkspace-C-301H-0.js} +1 -1
  109. package/static/auth-callback/assets/{SystemSettingsPage-BZJ6vWkg.js → SystemSettingsPage-BbWn-eG6.js} +1 -1
  110. package/static/auth-callback/assets/{SystemSettingsSubjectPanel-xm08UhXP.js → SystemSettingsSubjectPanel-DA4wvNSm.js} +1 -1
  111. package/static/auth-callback/assets/{XpodAiConnectionsPodStore-V6vgGfuw.js → XpodAiConnectionsPodStore-CohdyLoX.js} +1 -1
  112. package/static/auth-callback/assets/{activity-CeM7xly8.js → activity-CCsb9Oam.js} +1 -1
  113. package/static/auth-callback/assets/ai-connections-DexTPyfC.js +1 -0
  114. package/static/auth-callback/assets/{auth-callback-DTG8cSj7.js → auth-callback-Ds-c62W3.js} +5 -5
  115. package/static/auth-callback/assets/{badge-qJo2Zr4d.js → badge-CQm5OyzR.js} +1 -1
  116. package/static/auth-callback/assets/{collection-runtime-Bztsz31a.js → collection-runtime-DlAuU5TW.js} +1 -1
  117. package/static/auth-callback/assets/{dialog-D-h6x5x0.js → dialog-CnGzg5Ff.js} +1 -1
  118. package/static/auth-callback/assets/{download-C2ir4lmR.js → download-DwMONJvm.js} +1 -1
  119. package/static/auth-callback/assets/{external-link-THLDL4On.js → external-link-Bu5AGqCO.js} +1 -1
  120. package/static/auth-callback/assets/{index-BlVZb9A7.js → index-B0T-1YO8.js} +1 -1
  121. package/static/auth-callback/assets/{index-BRpv4yO3.js → index-C8QZf_4W.js} +1 -1
  122. package/static/auth-callback/assets/{index-D983R1FV.js → index-DwIlrIDG.js} +1 -1
  123. package/static/auth-callback/assets/{index-browser-3FvR0aaf.js → index-browser-lRsMcP_7.js} +1 -1
  124. package/static/auth-callback/assets/{key-round-C9U5j1Ly.js → key-round-BDMtU57P.js} +1 -1
  125. package/static/auth-callback/assets/{rotate-ccw-DP45cD4o.js → rotate-ccw-CoKIGCsQ.js} +1 -1
  126. package/static/auth-callback/assets/{skeleton-Dn4EiSCS.js → skeleton-CPoSWHDr.js} +1 -1
  127. package/static/auth-callback/assets/{waypoints-uqFQ3uEG.js → waypoints-BeYHxqHv.js} +1 -1
  128. package/static/auth-callback/assets/{workspace-layout-DLYK0Wwu.js → workspace-layout-xA5YxiK3.js} +1 -1
  129. package/static/auth-callback/auth-callback.html +1 -1
  130. package/static/dashboard/assets/{AiConfigContext-DJcMECNw.js → AiConfigContext-rWx4TyiH.js} +1 -1
  131. package/static/dashboard/assets/{AiConfigPage-BvE7dOTy.js → AiConfigPage-StVJpDFT.js} +1 -1
  132. package/static/dashboard/assets/{DocumentProcessingPanel-D9780krf.js → DocumentProcessingPanel-DJ5yul2O.js} +1 -1
  133. package/static/dashboard/assets/{IndexLifecyclePanel-SjsUcnbM.js → IndexLifecyclePanel-CpjtgezK.js} +1 -1
  134. package/static/dashboard/assets/{IndexSubjectPanel-C-ym2Tqi.js → IndexSubjectPanel-BVKcot1_.js} +1 -1
  135. package/static/dashboard/assets/{ModelAssignmentsPanel-BRjZ-arB.js → ModelAssignmentsPanel-BxVgWZPc.js} +1 -1
  136. package/static/dashboard/assets/{ModelsPage-BtTU6du3.js → ModelsPage-CECBwmeO.js} +3 -3
  137. package/static/dashboard/assets/{NetworkPage-CV9qpkDg.js → NetworkPage-zQgFscEW.js} +2 -2
  138. package/static/dashboard/assets/{PaneListHeader-KyPTTBsv.js → PaneListHeader-DIPe8pS6.js} +1 -1
  139. package/static/dashboard/assets/{SearchIndexingPanel-DolHGawg.js → SearchIndexingPanel-lalFJ3c8.js} +1 -1
  140. package/static/dashboard/assets/{StatusSubjectPanel-_YZvKiYi.js → StatusSubjectPanel-CpY_KU-G.js} +1 -1
  141. package/static/dashboard/assets/{StatusWorkspace-Dlbh_G40.js → StatusWorkspace-BwWCii3A.js} +1 -1
  142. package/static/dashboard/assets/{SystemSettingsPage-Be7QSIoz.js → SystemSettingsPage-BKZxX-_n.js} +1 -1
  143. package/static/dashboard/assets/{SystemSettingsSubjectPanel-DBp0gja7.js → SystemSettingsSubjectPanel-BZrqb2C5.js} +1 -1
  144. package/static/dashboard/assets/{XpodAiConnectionsPodStore-ClpSjzpP.js → XpodAiConnectionsPodStore-Bbpx9dTN.js} +1 -1
  145. package/static/dashboard/assets/{activity-lsNbTXJu.js → activity-BJ15TLVP.js} +1 -1
  146. package/static/dashboard/assets/ai-connections-GG6qkTJt.js +1 -0
  147. package/static/dashboard/assets/{badge-CVatKjaG.js → badge-BBX5FlaB.js} +1 -1
  148. package/static/dashboard/assets/{collection-runtime-Ec4UnY28.js → collection-runtime-UBbHBzdf.js} +1 -1
  149. package/static/dashboard/assets/{dashboard-BEzsRsvF.js → dashboard-7Y6BHyV9.js} +62 -62
  150. package/static/dashboard/assets/{dialog-BuyelQ4V.js → dialog-QrOJ-hB0.js} +1 -1
  151. package/static/dashboard/assets/{download-B4Nf678F.js → download-DK9x-VOP.js} +1 -1
  152. package/static/dashboard/assets/{external-link-PYv9CvKL.js → external-link-Cnkn87mJ.js} +1 -1
  153. package/static/dashboard/assets/{index-C9XPE-mI.js → index-B1z84it5.js} +1 -1
  154. package/static/dashboard/assets/{index-awr7ulur.js → index-DzjauX3N.js} +1 -1
  155. package/static/dashboard/assets/{index-Cx69bTNh.js → index-cIa8_efI.js} +1 -1
  156. package/static/dashboard/assets/{key-round-VsY80U1Z.js → key-round-BoS6UqKz.js} +1 -1
  157. package/static/dashboard/assets/{rotate-ccw-Cz1K4vE9.js → rotate-ccw-BeWV76i0.js} +1 -1
  158. package/static/dashboard/assets/{skeleton-BhNv_8tO.js → skeleton-CypcJL07.js} +1 -1
  159. package/static/dashboard/assets/{waypoints-DYS9XFYV.js → waypoints-zHOOqfhi.js} +1 -1
  160. package/static/dashboard/assets/{workspace-layout-OZJAFx5V.js → workspace-layout-DZ9JuxnM.js} +1 -1
  161. package/static/dashboard/dashboard.html +1 -1
  162. package/static/settings/assets/{AiConfigContext-B8JS3MXF.js → AiConfigContext-D3b1l_Kw.js} +1 -1
  163. package/static/settings/assets/{AiConfigPage-C3Zl8LUl.js → AiConfigPage-DYKw-atP.js} +1 -1
  164. package/static/settings/assets/{DocumentProcessingPanel-DpDZAQvf.js → DocumentProcessingPanel-DguRfsIV.js} +1 -1
  165. package/static/settings/assets/{IndexLifecyclePanel-Ec1XF88t.js → IndexLifecyclePanel-B85qJJA4.js} +1 -1
  166. package/static/settings/assets/{IndexSubjectPanel-BulT9BmO.js → IndexSubjectPanel-CsN7IxaV.js} +1 -1
  167. package/static/settings/assets/{ModelAssignmentsPanel-BcGSmYjb.js → ModelAssignmentsPanel-DEp9byI6.js} +1 -1
  168. package/static/settings/assets/{ModelsPage-CvTCKy1T.js → ModelsPage-CzTnPs_G.js} +3 -3
  169. package/static/settings/assets/{NetworkPage-DQF5u9Bn.js → NetworkPage-BDVnmUU0.js} +2 -2
  170. package/static/settings/assets/{PaneListHeader-D40hqcVl.js → PaneListHeader-Cpe39N76.js} +1 -1
  171. package/static/settings/assets/{SearchIndexingPanel-iCUPOx_0.js → SearchIndexingPanel-DA9w8lLL.js} +1 -1
  172. package/static/settings/assets/{StatusSubjectPanel-E--ZHSql.js → StatusSubjectPanel-BU0Aq0CS.js} +1 -1
  173. package/static/settings/assets/{StatusWorkspace-YjDAx1II.js → StatusWorkspace-D1AC1i5N.js} +1 -1
  174. package/static/settings/assets/{SystemSettingsPage-CDdV3mC9.js → SystemSettingsPage-ChKvOioO.js} +1 -1
  175. package/static/settings/assets/{SystemSettingsSubjectPanel-Br8WazDq.js → SystemSettingsSubjectPanel-DyTpOnD2.js} +1 -1
  176. package/static/settings/assets/{XpodAiConnectionsPodStore-CLr38P_Z.js → XpodAiConnectionsPodStore-VU5Bsz1a.js} +1 -1
  177. package/static/settings/assets/{activity-C5DAHHTE.js → activity-DGpLfsQB.js} +1 -1
  178. package/static/settings/assets/ai-connections-DexTPyfC.js +1 -0
  179. package/static/settings/assets/{badge-D8eIyxKt.js → badge-_hCrrWRP.js} +1 -1
  180. package/static/settings/assets/{collection-runtime-DLc9zil8.js → collection-runtime-E40TZ8Cl.js} +1 -1
  181. package/static/settings/assets/{dialog-CyuR7Va4.js → dialog-DTr2JkHn.js} +1 -1
  182. package/static/settings/assets/{download-c0oxZrCz.js → download-B_D21DDX.js} +1 -1
  183. package/static/settings/assets/{external-link-D3Z34fP_.js → external-link-BATYaM13.js} +1 -1
  184. package/static/settings/assets/{index-CSr3-2Cj.js → index-BAlAVi-J.js} +1 -1
  185. package/static/settings/assets/{index-ComidxAm.js → index-Ckh4h9jj.js} +1 -1
  186. package/static/settings/assets/{index-CKGbRFlc.js → index-DOiwLF4B.js} +1 -1
  187. package/static/settings/assets/{index-browser-CAscEbae.js → index-browser-DFFWN3Kr.js} +1 -1
  188. package/static/settings/assets/{key-round-DyjLmXuB.js → key-round-ZTVU_1O1.js} +1 -1
  189. package/static/settings/assets/{rotate-ccw-679HF_ec.js → rotate-ccw-DDdw8PTU.js} +1 -1
  190. package/static/settings/assets/{settings-DKknqu4C.js → settings-CyLnISOv.js} +62 -62
  191. package/static/settings/assets/{skeleton-CkopNkPB.js → skeleton-DEzA3hc2.js} +1 -1
  192. package/static/settings/assets/{waypoints-CrqfAftE.js → waypoints-BSdfNvEb.js} +1 -1
  193. package/static/settings/assets/{workspace-layout-UN6c4qTG.js → workspace-layout-BOQnl_3d.js} +1 -1
  194. package/static/settings/settings.html +1 -1
  195. package/dist/api/ai-gateway/pod/HostedPodDataAccess.d.ts +0 -31
  196. package/dist/api/ai-gateway/pod/HostedPodDataAccess.js +0 -330
  197. package/dist/http/InternalPodDataHttpHandler.d.ts +0 -57
  198. package/dist/http/InternalPodDataHttpHandler.js +0 -551
  199. package/dist/http/InternalPodDataHttpHandler.jsonld +0 -243
  200. package/static/auth-callback/assets/ai-connections-C6yaE6WQ.js +0 -1
  201. package/static/dashboard/assets/ai-connections-CXp5gd1J.js +0 -1
  202. package/static/settings/assets/ai-connections-C6yaE6WQ.js +0 -1
@@ -1,24 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GATEWAY_ADMIN_PROXY_HEADERS = exports.GATEWAY_ADMIN_PROXY_NONCE_HEADER = exports.GATEWAY_ADMIN_PROXY_INTENT_HEADER = exports.GATEWAY_ADMIN_PROXY_SIGNATURE_HEADER = exports.GATEWAY_ADMIN_PROXY_TIMESTAMP_HEADER = exports.GATEWAY_ADMIN_PROXY_LOOPBACK_HEADER = void 0;
3
+ exports.GATEWAY_ADMIN_PROXY_HEADERS = exports.GATEWAY_ADMIN_PROXY_NONCE_HEADER = exports.GATEWAY_ADMIN_PROXY_SIGNATURE_HEADER = exports.GATEWAY_ADMIN_PROXY_TIMESTAMP_HEADER = exports.GATEWAY_ADMIN_PROXY_LOOPBACK_HEADER = void 0;
4
4
  exports.createGatewayAdminProxyAuthSecret = createGatewayAdminProxyAuthSecret;
5
5
  exports.createGatewayAdminProxyHeaders = createGatewayAdminProxyHeaders;
6
6
  exports.stripGatewayAdminProxyHeaders = stripGatewayAdminProxyHeaders;
7
7
  exports.isLoopbackRemoteAddress = isLoopbackRemoteAddress;
8
8
  exports.verifyGatewayAdminProxyHeaders = verifyGatewayAdminProxyHeaders;
9
- exports.canonicalGatewayAdminProxyIntent = canonicalGatewayAdminProxyIntent;
10
9
  const node_crypto_1 = require("node:crypto");
11
10
  const node_net_1 = require("node:net");
12
11
  exports.GATEWAY_ADMIN_PROXY_LOOPBACK_HEADER = 'x-xpod-admin-proxy-loopback';
13
12
  exports.GATEWAY_ADMIN_PROXY_TIMESTAMP_HEADER = 'x-xpod-admin-proxy-timestamp';
14
13
  exports.GATEWAY_ADMIN_PROXY_SIGNATURE_HEADER = 'x-xpod-admin-proxy-signature';
15
- exports.GATEWAY_ADMIN_PROXY_INTENT_HEADER = 'x-xpod-admin-proxy-intent';
16
14
  exports.GATEWAY_ADMIN_PROXY_NONCE_HEADER = 'x-xpod-admin-proxy-nonce';
17
15
  exports.GATEWAY_ADMIN_PROXY_HEADERS = [
18
16
  exports.GATEWAY_ADMIN_PROXY_LOOPBACK_HEADER,
19
17
  exports.GATEWAY_ADMIN_PROXY_TIMESTAMP_HEADER,
20
18
  exports.GATEWAY_ADMIN_PROXY_SIGNATURE_HEADER,
21
- exports.GATEWAY_ADMIN_PROXY_INTENT_HEADER,
22
19
  exports.GATEWAY_ADMIN_PROXY_NONCE_HEADER,
23
20
  ];
24
21
  const MAX_CLOCK_SKEW_MS = 60_000;
@@ -28,12 +25,10 @@ function createGatewayAdminProxyAuthSecret() {
28
25
  function createGatewayAdminProxyHeaders(input) {
29
26
  const issuedAt = input.issuedAt ?? Date.now();
30
27
  const loopback = input.originalClientLoopback ? '1' : '0';
31
- const intent = input.intent ? canonicalGatewayAdminProxyIntent(input.intent) : undefined;
32
28
  return {
33
29
  [exports.GATEWAY_ADMIN_PROXY_LOOPBACK_HEADER]: loopback,
34
30
  [exports.GATEWAY_ADMIN_PROXY_TIMESTAMP_HEADER]: String(issuedAt),
35
31
  ...(input.nonce ? { [exports.GATEWAY_ADMIN_PROXY_NONCE_HEADER]: input.nonce } : {}),
36
- ...(intent ? { [exports.GATEWAY_ADMIN_PROXY_INTENT_HEADER]: intent } : {}),
37
32
  [exports.GATEWAY_ADMIN_PROXY_SIGNATURE_HEADER]: signGatewayAdminProxyMarker({
38
33
  secret: input.secret,
39
34
  method: input.method,
@@ -41,7 +36,6 @@ function createGatewayAdminProxyHeaders(input) {
41
36
  loopback,
42
37
  issuedAt,
43
38
  nonce: input.nonce,
44
- intent,
45
39
  }),
46
40
  };
47
41
  }
@@ -66,7 +60,6 @@ function verifyGatewayAdminProxyHeaders(input) {
66
60
  const timestamp = firstHeader(input.headers[exports.GATEWAY_ADMIN_PROXY_TIMESTAMP_HEADER]);
67
61
  const signature = firstHeader(input.headers[exports.GATEWAY_ADMIN_PROXY_SIGNATURE_HEADER]);
68
62
  const nonce = firstHeader(input.headers[exports.GATEWAY_ADMIN_PROXY_NONCE_HEADER]);
69
- const intentHeader = firstHeader(input.headers[exports.GATEWAY_ADMIN_PROXY_INTENT_HEADER]);
70
63
  const present = loopback !== undefined || timestamp !== undefined || signature !== undefined;
71
64
  if (!present) {
72
65
  return { present: false, valid: false, originalClientLoopback: false };
@@ -87,10 +80,6 @@ function verifyGatewayAdminProxyHeaders(input) {
87
80
  if (Math.abs((input.now ?? Date.now()) - issuedAt) > MAX_CLOCK_SKEW_MS) {
88
81
  return { present: true, valid: false, originalClientLoopback: loopback === '1', reason: 'expired_marker' };
89
82
  }
90
- const intent = parseGatewayAdminProxyIntent(intentHeader);
91
- if (intentHeader !== undefined && !intent) {
92
- return { present: true, valid: false, originalClientLoopback: loopback === '1', reason: 'invalid_intent' };
93
- }
94
83
  const expected = signGatewayAdminProxyMarker({
95
84
  secret: input.secret,
96
85
  method: input.method,
@@ -98,12 +87,11 @@ function verifyGatewayAdminProxyHeaders(input) {
98
87
  loopback,
99
88
  issuedAt,
100
89
  nonce,
101
- intent: intentHeader,
102
90
  });
103
91
  if (!safeEqual(signature, expected)) {
104
92
  return { present: true, valid: false, originalClientLoopback: loopback === '1', reason: 'bad_signature' };
105
93
  }
106
- return { present: true, valid: true, originalClientLoopback: loopback === '1', nonce, intent };
94
+ return { present: true, valid: true, originalClientLoopback: loopback === '1', nonce };
107
95
  }
108
96
  function signGatewayAdminProxyMarker(input) {
109
97
  const payload = [
@@ -113,66 +101,9 @@ function signGatewayAdminProxyMarker(input) {
113
101
  input.loopback,
114
102
  String(input.issuedAt),
115
103
  input.nonce ?? '',
116
- input.intent ?? '',
117
104
  ].join('\n');
118
105
  return (0, node_crypto_1.createHmac)('sha256', input.secret).update(payload).digest('base64url');
119
106
  }
120
- function canonicalGatewayAdminProxyIntent(intent) {
121
- return JSON.stringify({
122
- ownerWebId: intent.ownerWebId,
123
- ...(intent.podBaseUrl ? { podBaseUrl: intent.podBaseUrl } : {}),
124
- method: intent.method,
125
- resourceUrl: intent.resourceUrl,
126
- principalKind: intent.principalKind,
127
- scopes: [...intent.scopes].sort(),
128
- ...(intent.bodyDigest ? { bodyDigest: intent.bodyDigest } : {}),
129
- });
130
- }
131
- function parseGatewayAdminProxyIntent(value) {
132
- if (!value) {
133
- return undefined;
134
- }
135
- try {
136
- const parsed = JSON.parse(value);
137
- if (typeof parsed.ownerWebId !== 'string' ||
138
- typeof parsed.resourceUrl !== 'string' ||
139
- (parsed.podBaseUrl !== undefined && !isHttpUrl(parsed.podBaseUrl)) ||
140
- (parsed.method !== 'GET' && parsed.method !== 'HEAD' && parsed.method !== 'POST' && parsed.method !== 'PUT' && parsed.method !== 'PATCH' && parsed.method !== 'DELETE') ||
141
- (parsed.principalKind !== 'solid-user' && parsed.principalKind !== 'gateway-key-verifier') ||
142
- !Array.isArray(parsed.scopes) ||
143
- !parsed.scopes.every((scope) => typeof scope === 'string') ||
144
- (parsed.bodyDigest !== undefined && !isSha256Hex(parsed.bodyDigest)) ||
145
- (parsed.method === 'POST' && !isSha256Hex(parsed.bodyDigest))) {
146
- return undefined;
147
- }
148
- return {
149
- ownerWebId: parsed.ownerWebId,
150
- ...(parsed.podBaseUrl ? { podBaseUrl: parsed.podBaseUrl } : {}),
151
- method: parsed.method,
152
- resourceUrl: parsed.resourceUrl,
153
- principalKind: parsed.principalKind,
154
- scopes: parsed.scopes,
155
- ...(parsed.bodyDigest ? { bodyDigest: parsed.bodyDigest } : {}),
156
- };
157
- }
158
- catch {
159
- return undefined;
160
- }
161
- }
162
- function isHttpUrl(value) {
163
- if (typeof value !== 'string')
164
- return false;
165
- try {
166
- const url = new URL(value);
167
- return url.protocol === 'http:' || url.protocol === 'https:';
168
- }
169
- catch {
170
- return false;
171
- }
172
- }
173
- function isSha256Hex(value) {
174
- return typeof value === 'string' && /^[a-f0-9]{64}$/u.test(value);
175
- }
176
107
  function safeEqual(actual, expected) {
177
108
  const actualBuffer = Buffer.from(actual);
178
109
  const expectedBuffer = Buffer.from(expected);
@@ -73,7 +73,6 @@ export declare class GatewayProxy {
73
73
  private shouldRouteToApi;
74
74
  private pathnameFromRequestUrl;
75
75
  private applyInternalAdminProxyHeaders;
76
- private verifiedInternalPodProxyHeaders;
77
76
  private isApiHost;
78
77
  private configuredApiHosts;
79
78
  private hostsFromUrlList;
@@ -94,6 +93,15 @@ export declare class GatewayProxy {
94
93
  * Add CORS headers matching CSS CorsHandler configuration
95
94
  */
96
95
  private addCorsHeaders;
96
+ /**
97
+ * Whether this request carries operator authority.
98
+ *
99
+ * `/service/*` exposes logs and service control, so a caller that only reached the Gateway
100
+ * through a tunnel must not get it - whatever address it presents. A local caller counts, and
101
+ * so does a signed gateway admin proxy header, which is how the same machine proves it is the
102
+ * operator through a local forwarder.
103
+ */
104
+ private hasOperatorAuthority;
97
105
  private handleInternalApi;
98
106
  private isCssReady;
99
107
  private normalizeTarget;
@@ -125,3 +133,4 @@ export interface GatewayProxyOptions {
125
133
  */
126
134
  ingressPort?: number;
127
135
  }
136
+ export declare function forwardedFromOutside(req: http.IncomingMessage): boolean;
@@ -4,8 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.GatewayProxy = void 0;
7
+ exports.forwardedFromOutside = forwardedFromOutside;
7
8
  const http_proxy_1 = __importDefault(require("http-proxy"));
8
9
  const http_1 = __importDefault(require("http"));
10
+ const node_net_1 = require("node:net");
9
11
  const global_logger_factory_1 = require("global-logger-factory");
10
12
  const NodeRuntimeHost_1 = require("./host/node/NodeRuntimeHost");
11
13
  const GatewayAdminProxyAuth_1 = require("./GatewayAdminProxyAuth");
@@ -214,15 +216,15 @@ class GatewayProxy {
214
216
  const pathname = url.split('?')[0];
215
217
  const origin = req.headers.origin;
216
218
  const originalRemoteAddress = this.clientRemoteAddressResolver?.(req) ?? req.socket.remoteAddress;
217
- // A loopback peer address only proves the connection came from this machine. Managed
218
- // tunnels and the P2P data plane terminate here too, so anything that arrived through
219
- // a remote forwarding path is never local, whatever its peer address or headers say.
220
- const originalClientLoopback = !untrustedIngress && (0, GatewayAdminProxyAuth_1.isLoopbackRemoteAddress)(originalRemoteAddress);
221
- const internalPodProxyHeaders = this.verifiedInternalPodProxyHeaders(req, originalClientLoopback);
219
+ // A loopback peer address only proves the connection came from this machine: tunnels and
220
+ // the P2P data plane terminate here too. Forwarded-for is what separates them - a local
221
+ // dev proxy forwards this machine's address, while a provider edge appends the address it
222
+ // saw, so a request whose right-most forwarder is not loopback came from outside and is
223
+ // never local, whatever its peer address or headers say.
224
+ const originalClientLoopback = !untrustedIngress
225
+ && !forwardedFromOutside(req)
226
+ && (0, GatewayAdminProxyAuth_1.isLoopbackRemoteAddress)(originalRemoteAddress);
222
227
  (0, GatewayAdminProxyAuth_1.stripGatewayAdminProxyHeaders)(req.headers);
223
- if (internalPodProxyHeaders) {
224
- Object.assign(req.headers, internalPodProxyHeaders);
225
- }
226
228
  // Store public host for routing before any CSS canonical-host rewrites.
227
229
  // External gateways pass the original domain through X-Forwarded-Host;
228
230
  // direct/local requests use Host.
@@ -302,7 +304,7 @@ class GatewayProxy {
302
304
  if (origin) {
303
305
  this.addCorsHeaders(res, origin);
304
306
  }
305
- void this.handleInternalApi(req, res);
307
+ void this.handleInternalApi(req, res, this.hasOperatorAuthority(req, originalClientLoopback));
306
308
  return;
307
309
  }
308
310
  // 2. API Server Routing.
@@ -387,24 +389,6 @@ class GatewayProxy {
387
389
  originalClientLoopback,
388
390
  }));
389
391
  }
390
- verifiedInternalPodProxyHeaders(req, originalClientLoopback) {
391
- if (!originalClientLoopback || req.url !== '/.internal/pod-data') {
392
- return undefined;
393
- }
394
- const verification = (0, GatewayAdminProxyAuth_1.verifyGatewayAdminProxyHeaders)({
395
- headers: req.headers,
396
- secret: this.internalAdminAuthSecret,
397
- method: req.method,
398
- url: req.url,
399
- });
400
- if (!verification.valid || !verification.originalClientLoopback || !verification.intent || !verification.nonce) {
401
- return undefined;
402
- }
403
- return Object.fromEntries(GatewayAdminProxyAuth_1.GATEWAY_ADMIN_PROXY_HEADERS.flatMap((header) => {
404
- const value = req.headers[header];
405
- return value === undefined ? [] : [[header, value]];
406
- }));
407
- }
408
392
  isApiHost(hostHeader) {
409
393
  const host = this.normalizeHost(hostHeader);
410
394
  if (!host) {
@@ -579,11 +563,35 @@ class GatewayProxy {
579
563
  res.setHeader('Access-Control-Allow-Headers', CORS_CONFIG.allowedHeaders.join(', '));
580
564
  res.setHeader('Access-Control-Expose-Headers', CORS_CONFIG.exposedHeaders.join(', '));
581
565
  }
582
- async handleInternalApi(req, res) {
566
+ /**
567
+ * Whether this request carries operator authority.
568
+ *
569
+ * `/service/*` exposes logs and service control, so a caller that only reached the Gateway
570
+ * through a tunnel must not get it - whatever address it presents. A local caller counts, and
571
+ * so does a signed gateway admin proxy header, which is how the same machine proves it is the
572
+ * operator through a local forwarder.
573
+ */
574
+ hasOperatorAuthority(req, originalClientLoopback) {
575
+ if (originalClientLoopback) {
576
+ return true;
577
+ }
578
+ if (!this.internalAdminAuthSecret) {
579
+ return false;
580
+ }
581
+ const verification = (0, GatewayAdminProxyAuth_1.verifyGatewayAdminProxyHeaders)({
582
+ headers: req.headers,
583
+ secret: this.internalAdminAuthSecret,
584
+ method: req.method,
585
+ url: req.url,
586
+ });
587
+ return verification.valid;
588
+ }
589
+ async handleInternalApi(req, res, operatorAuthorized) {
583
590
  try {
584
591
  const reqUrl = req.url ?? '/';
585
592
  const parsed = new URL(reqUrl, 'http://localhost');
586
593
  const pathname = parsed.pathname;
594
+ // Status is the entry probe every client uses, and it carries no secrets.
587
595
  if (pathname === '/service/status') {
588
596
  const status = this.supervisor.getAllStatus();
589
597
  const cssReady = await this.isCssReady();
@@ -593,6 +601,10 @@ class GatewayProxy {
593
601
  return;
594
602
  }
595
603
  if (pathname === '/service/logs') {
604
+ if (!operatorAuthorized) {
605
+ sendOperatorRequired(res);
606
+ return;
607
+ }
596
608
  const level = parsed.searchParams.get('level') ?? undefined;
597
609
  const source = parsed.searchParams.get('source') ?? undefined;
598
610
  const limitValue = parsed.searchParams.get('limit');
@@ -608,6 +620,10 @@ class GatewayProxy {
608
620
  }
609
621
  const restartMatch = /^\/service\/restart\/([^/]+)$/.exec(pathname);
610
622
  if (restartMatch && req.method === 'POST') {
623
+ if (!operatorAuthorized) {
624
+ sendOperatorRequired(res);
625
+ return;
626
+ }
611
627
  const service = decodeURIComponent(restartMatch[1]);
612
628
  if (service === 'gateway') {
613
629
  res.writeHead(409, { 'Content-Type': 'application/json' });
@@ -630,6 +646,10 @@ class GatewayProxy {
630
646
  return;
631
647
  }
632
648
  if (pathname === '/service/stop' && req.method === 'POST') {
649
+ if (!operatorAuthorized) {
650
+ sendOperatorRequired(res);
651
+ return;
652
+ }
633
653
  res.writeHead(200, { 'Content-Type': 'application/json' });
634
654
  res.end(JSON.stringify({ ok: true }));
635
655
  setImmediate(() => {
@@ -682,4 +702,51 @@ exports.GatewayProxy = GatewayProxy;
682
702
  function isBunRuntime() {
683
703
  return typeof globalThis.Bun !== 'undefined';
684
704
  }
705
+ /**
706
+ * Whether the client-address headers say this request travelled through a forwarder outside
707
+ * this machine.
708
+ *
709
+ * This is the fallback behind the structural gate (the Gateway's tunnel entry listener): a
710
+ * tunnel pointed at the Gateway port by mistake still must not inherit local trust. Only
711
+ * headers that carry a client *address* count - `x-forwarded-for`, `x-real-ip` and the
712
+ * `for=` part of `Forwarded`. `x-forwarded-host`/`x-forwarded-proto` do not: a local dev proxy
713
+ * sets them for local browsers too, so treating them as evidence would lock the operator out
714
+ * of their own admin surface.
715
+ *
716
+ * The right-most value is the address the last forwarder saw - the one our own handlers append
717
+ * (`ClusterIngressRouter`, `EdgeNodeProxyHttpHandler`, `PodRoutingHttpHandler`) - so a client
718
+ * cannot look local by sending its own. An unreadable value is treated as remote.
719
+ */
720
+ /** Service control and logs are for the operator, not for whoever reached the entry. */
721
+ function sendOperatorRequired(res) {
722
+ res.writeHead(403, { 'Content-Type': 'application/json' });
723
+ res.end(JSON.stringify({ error: 'Operator access required' }));
724
+ }
725
+ function forwardedFromOutside(req) {
726
+ const evidence = [
727
+ ...splitHeaderList(req.headers['x-forwarded-for']),
728
+ ...splitHeaderList(req.headers['x-real-ip']),
729
+ ...forwardedForParameters(req.headers.forwarded),
730
+ ];
731
+ const last = evidence.at(-1);
732
+ if (last === undefined) {
733
+ return false;
734
+ }
735
+ return (0, node_net_1.isIP)(last) === 0 || !(0, GatewayAdminProxyAuth_1.isLoopbackRemoteAddress)(last);
736
+ }
737
+ function splitHeaderList(raw) {
738
+ const value = Array.isArray(raw) ? raw.join(',') : raw;
739
+ return value?.split(',').map((entry) => entry.trim()).filter(Boolean) ?? [];
740
+ }
741
+ /** The `for=` values of an RFC 7239 `Forwarded` header, in order. */
742
+ function forwardedForParameters(raw) {
743
+ const value = Array.isArray(raw) ? raw.join(',') : raw;
744
+ if (!value) {
745
+ return [];
746
+ }
747
+ return value.split(/[;,]/u)
748
+ .map((part) => /^\s*for\s*=\s*(.+)$/iu.exec(part.trim())?.[1])
749
+ .filter((entry) => Boolean(entry))
750
+ .map((entry) => entry.replace(/^"|"$/gu, '').replace(/^\[|\]$/gu, ''));
751
+ }
685
752
  //# sourceMappingURL=Proxy.js.map
@@ -25,6 +25,16 @@ export interface RuntimeBootstrapState {
25
25
  ports: XpodRuntimePorts;
26
26
  sockets: XpodRuntimeSockets;
27
27
  }
28
+ /**
29
+ * Address that a co-located runtime service must be reached on when it was bound
30
+ * to `bindHost`. Wildcard binds are not connectable on every platform, so they
31
+ * map to their loopback counterpart; any other value (including a hostname such
32
+ * as `localhost`, which may resolve to IPv6 only) is used as-is, because the
33
+ * gateway must connect to the very address the service actually bound.
34
+ */
35
+ export declare function connectHostForBindHost(bindHost?: string): string;
36
+ /** Loopback URL for a runtime service bound to `bindHost`. */
37
+ export declare function localServiceUrl(bindHost: string | undefined, port: number): string;
28
38
  export declare function cssAuthModeConfigImports(authMode: AuthMode): string[];
29
39
  export declare function resolveRuntimeBootstrap(id: string, options: XpodRuntimeOptions, host: RuntimeHost, platform?: RuntimePlatform): Promise<RuntimeBootstrapState>;
30
40
  export declare function buildRuntimeEnv(state: RuntimeBootstrapState, options: XpodRuntimeOptions, envFromFile?: Record<string, string | undefined>): Record<string, string | undefined>;
@@ -3,6 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.connectHostForBindHost = connectHostForBindHost;
7
+ exports.localServiceUrl = localServiceUrl;
6
8
  exports.cssAuthModeConfigImports = cssAuthModeConfigImports;
7
9
  exports.resolveRuntimeBootstrap = resolveRuntimeBootstrap;
8
10
  exports.buildRuntimeEnv = buildRuntimeEnv;
@@ -35,6 +37,28 @@ function ensureTrailingSlash(url) {
35
37
  function publicHostForBindHost(bindHost) {
36
38
  return bindHost === '127.0.0.1' || bindHost === '::1' ? 'localhost' : bindHost;
37
39
  }
40
+ /**
41
+ * Address that a co-located runtime service must be reached on when it was bound
42
+ * to `bindHost`. Wildcard binds are not connectable on every platform, so they
43
+ * map to their loopback counterpart; any other value (including a hostname such
44
+ * as `localhost`, which may resolve to IPv6 only) is used as-is, because the
45
+ * gateway must connect to the very address the service actually bound.
46
+ */
47
+ function connectHostForBindHost(bindHost) {
48
+ const host = bindHost ?? '127.0.0.1';
49
+ if (host === '0.0.0.0') {
50
+ return '127.0.0.1';
51
+ }
52
+ if (host === '::' || host === '[::]' || host === '::0') {
53
+ return '::1';
54
+ }
55
+ return host;
56
+ }
57
+ /** Loopback URL for a runtime service bound to `bindHost`. */
58
+ function localServiceUrl(bindHost, port) {
59
+ const host = connectHostForBindHost(bindHost);
60
+ return `http://${host.includes(':') ? `[${host}]` : host}:${port}`;
61
+ }
38
62
  function normalizeWindowsAbsolutePath(filePath) {
39
63
  return filePath.replace(/^[\\/]+(?=[A-Za-z]:[\\/])/, '');
40
64
  }
@@ -23,9 +23,11 @@ class NodeRuntimeHost {
23
23
  const gateway = options.gatewayPort ?? await (0, port_finder_1.getFreePort)(options.basePort ?? 5600);
24
24
  const css = options.cssPort ?? await (0, port_finder_1.getFreePort)(gateway + 1);
25
25
  const api = options.apiPort ?? await (0, port_finder_1.getFreePort)(css + 1);
26
- // The ingress listener is an internal detail of this runtime, so it takes an
27
- // OS-assigned port instead of claiming the neighbour of a planned service port.
28
- const ingress = options.ingressPort ?? await (0, port_finder_1.getEphemeralLoopbackPort)();
26
+ // Tunnels (and the P2P data plane) terminate here, and this listener never treats a
27
+ // caller as local whatever headers it carries - that is the gate. Its port is the one
28
+ // number the user copies into a provider console, so it is predictable rather than
29
+ // random, and it is what the runtime reports as the tunnel origin.
30
+ const ingress = options.ingressPort ?? await (0, port_finder_1.findGatewayIngressPort)(gateway);
29
31
  return { gateway, css, api, ingress };
30
32
  }
31
33
  createListenEndpoint(options) {
@@ -10,7 +10,7 @@ export { createOpenAuthContext, registerManagedRuntimeServices, startApiRuntime,
10
10
  export type { RuntimeServices } from './lifecycle';
11
11
  export { GatewayProxy } from './Proxy';
12
12
  export { createGatewayAdminProxyAuthSecret } from './GatewayAdminProxyAuth';
13
- export { getEphemeralLoopbackPort, getFreePort, getFreePortForWildcard, readPortFile, requireFreePortForWildcard, resolveStableLoopbackPort } from './port-finder';
13
+ export { findGatewayIngressPort, getEphemeralLoopbackPort, getFreePort, getFreePortForWildcard, requireFreePortForWildcard } from './port-finder';
14
14
  export { ensureTrailingSlash, INVALID_CONFIGURATION_PREFIX, validateBaseUrl } from './base-url';
15
15
  export type { ValidateBaseUrlOptions } from './base-url';
16
16
  export { applyEnv, loadEnvFile } from './env-utils';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.startXpodRuntime = exports.nodeGatewayRuntimeRunner = exports.NodeGatewayRuntimeRunner = exports.nodeApiRuntimeRunner = exports.NodeApiRuntimeRunner = exports.communitySolidServerCssRunner = exports.CommunitySolidServerCssRunner = exports.registerSocketOriginShims = exports.registerSocketFetchOrigin = exports.nodeRuntimePlatform = exports.NodeRuntimePlatform = exports.nodeRuntimeHost = exports.NodeRuntimeHost = exports.resolveXpodEnvPath = exports.defaultXpodEnvPath = exports.loadEnvFile = exports.applyEnv = exports.validateBaseUrl = exports.INVALID_CONFIGURATION_PREFIX = exports.ensureTrailingSlash = exports.resolveStableLoopbackPort = exports.requireFreePortForWildcard = exports.readPortFile = exports.getFreePortForWildcard = exports.getFreePort = exports.getEphemeralLoopbackPort = exports.createGatewayAdminProxyAuthSecret = exports.GatewayProxy = exports.stopRuntimeServices = exports.startGatewayRuntime = exports.startCssRuntime = exports.startApiRuntime = exports.registerManagedRuntimeServices = exports.createOpenAuthContext = exports.createRuntimeEnvironmentSession = exports.nodeRuntimeDriver = exports.NodeRuntimeDriver = exports.resolveRuntimeBootstrap = exports.initRuntimeLogger = exports.createCssRuntimeConfig = exports.buildRuntimeShorthand = exports.buildRuntimeEnv = exports.ensureBunUndiciCompat = exports.findPackageRoot = exports.PACKAGE_ROOT = void 0;
3
+ exports.startXpodRuntime = exports.nodeGatewayRuntimeRunner = exports.NodeGatewayRuntimeRunner = exports.nodeApiRuntimeRunner = exports.NodeApiRuntimeRunner = exports.communitySolidServerCssRunner = exports.CommunitySolidServerCssRunner = exports.registerSocketOriginShims = exports.registerSocketFetchOrigin = exports.nodeRuntimePlatform = exports.NodeRuntimePlatform = exports.nodeRuntimeHost = exports.NodeRuntimeHost = exports.resolveXpodEnvPath = exports.defaultXpodEnvPath = exports.loadEnvFile = exports.applyEnv = exports.validateBaseUrl = exports.INVALID_CONFIGURATION_PREFIX = exports.ensureTrailingSlash = exports.requireFreePortForWildcard = exports.getFreePortForWildcard = exports.getFreePort = exports.getEphemeralLoopbackPort = exports.findGatewayIngressPort = exports.createGatewayAdminProxyAuthSecret = exports.GatewayProxy = exports.stopRuntimeServices = exports.startGatewayRuntime = exports.startCssRuntime = exports.startApiRuntime = exports.registerManagedRuntimeServices = exports.createOpenAuthContext = exports.createRuntimeEnvironmentSession = exports.nodeRuntimeDriver = exports.NodeRuntimeDriver = exports.resolveRuntimeBootstrap = exports.initRuntimeLogger = exports.createCssRuntimeConfig = exports.buildRuntimeShorthand = exports.buildRuntimeEnv = exports.ensureBunUndiciCompat = exports.findPackageRoot = exports.PACKAGE_ROOT = void 0;
4
4
  require("./configure-drizzle-solid");
5
5
  var package_root_1 = require("./package-root");
6
6
  Object.defineProperty(exports, "PACKAGE_ROOT", { enumerable: true, get: function () { return package_root_1.PACKAGE_ROOT; } });
@@ -30,12 +30,11 @@ Object.defineProperty(exports, "GatewayProxy", { enumerable: true, get: function
30
30
  var GatewayAdminProxyAuth_1 = require("./GatewayAdminProxyAuth");
31
31
  Object.defineProperty(exports, "createGatewayAdminProxyAuthSecret", { enumerable: true, get: function () { return GatewayAdminProxyAuth_1.createGatewayAdminProxyAuthSecret; } });
32
32
  var port_finder_1 = require("./port-finder");
33
+ Object.defineProperty(exports, "findGatewayIngressPort", { enumerable: true, get: function () { return port_finder_1.findGatewayIngressPort; } });
33
34
  Object.defineProperty(exports, "getEphemeralLoopbackPort", { enumerable: true, get: function () { return port_finder_1.getEphemeralLoopbackPort; } });
34
35
  Object.defineProperty(exports, "getFreePort", { enumerable: true, get: function () { return port_finder_1.getFreePort; } });
35
36
  Object.defineProperty(exports, "getFreePortForWildcard", { enumerable: true, get: function () { return port_finder_1.getFreePortForWildcard; } });
36
- Object.defineProperty(exports, "readPortFile", { enumerable: true, get: function () { return port_finder_1.readPortFile; } });
37
37
  Object.defineProperty(exports, "requireFreePortForWildcard", { enumerable: true, get: function () { return port_finder_1.requireFreePortForWildcard; } });
38
- Object.defineProperty(exports, "resolveStableLoopbackPort", { enumerable: true, get: function () { return port_finder_1.resolveStableLoopbackPort; } });
39
38
  var base_url_1 = require("./base-url");
40
39
  Object.defineProperty(exports, "ensureTrailingSlash", { enumerable: true, get: function () { return base_url_1.ensureTrailingSlash; } });
41
40
  Object.defineProperty(exports, "INVALID_CONFIGURATION_PREFIX", { enumerable: true, get: function () { return base_url_1.INVALID_CONFIGURATION_PREFIX; } });
@@ -19,8 +19,15 @@ function findBunExecutable() {
19
19
  return result.status === 0 ? result.stdout.trim() || undefined : undefined;
20
20
  }
21
21
  function jsEntrypointArgs(entrypoint, isBun) {
22
- return !isBun && entrypoint.endsWith('.ts')
23
- ? ['-r', require.resolve('ts-node/register/transpile-only'), entrypoint]
24
- : [entrypoint];
22
+ if (!isBun) {
23
+ return entrypoint.endsWith('.ts')
24
+ ? ['-r', require.resolve('ts-node/register/transpile-only'), entrypoint]
25
+ : [entrypoint];
26
+ }
27
+ // A child service runs on the environment its parent decided for it. Without this, Bun loads
28
+ // whichever .env files happen to sit in the child's cwd, so a checkout's developer env files
29
+ // leak into a runtime that was started standalone (`bun run local` already loads them once, for
30
+ // the parent, on purpose).
31
+ return ['--no-env-file', entrypoint];
25
32
  }
26
33
  //# sourceMappingURL=js-runtime.js.map
@@ -7,6 +7,7 @@ exports.startApiRuntime = startApiRuntime;
7
7
  exports.startGatewayRuntime = startGatewayRuntime;
8
8
  exports.stopRuntimeServices = stopRuntimeServices;
9
9
  const package_root_1 = require("./package-root");
10
+ const bootstrap_1 = require("./bootstrap");
10
11
  const RedisClientLifecycle_1 = require("../storage/redis/RedisClientLifecycle");
11
12
  const DEFAULT_SERVICE_STOP_TIMEOUT_MS = 5_000;
12
13
  async function stopWithTimeout(name, stop, timeoutMs) {
@@ -80,7 +81,7 @@ async function startCssRuntime({ state, host, runtimeShorthand, supervisor, crea
80
81
  }
81
82
  else {
82
83
  await host.waitForPortReady(state.ports.css, '127.0.0.1');
83
- supervisor.addLog('css', 'info', `CSS started (http://127.0.0.1:${state.ports.css})`);
84
+ supervisor.addLog('css', 'info', `CSS started (${(0, bootstrap_1.localServiceUrl)(state.bindHost, state.ports.css)})`);
84
85
  }
85
86
  supervisor.setStatus('css', 'running', { startTime: Date.now() });
86
87
  return cssApp;
@@ -92,7 +93,7 @@ async function startApiRuntime({ state, host, supervisor, authContext, apiRunner
92
93
  authContext: createOpenAuthContext(state.canonicalBaseUrl ?? state.baseUrl, authContext),
93
94
  runtimeHost: host,
94
95
  });
95
- supervisor.addLog('api', 'info', `API started (${state.transport === 'socket' ? `unix://${state.sockets.api}` : `http://127.0.0.1:${state.ports.api}`})`);
96
+ supervisor.addLog('api', 'info', `API started (${state.transport === 'socket' ? `unix://${state.sockets.api}` : (0, bootstrap_1.localServiceUrl)(state.bindHost, state.ports.api)})`);
96
97
  supervisor.setStatus('api', 'running', { startTime: Date.now() });
97
98
  return apiService;
98
99
  }
@@ -110,8 +111,8 @@ async function startGatewayRuntime({ state, host, supervisor, shutdownHandler, g
110
111
  clientRemoteAddressResolver,
111
112
  ingressPort: state.ports.ingress,
112
113
  targets: {
113
- css: state.transport === 'socket' ? { socketPath: state.sockets.css } : { url: `http://127.0.0.1:${state.ports.css}` },
114
- api: state.transport === 'socket' ? { socketPath: state.sockets.api } : { url: `http://127.0.0.1:${state.ports.api}` },
114
+ css: state.transport === 'socket' ? { socketPath: state.sockets.css } : { url: (0, bootstrap_1.localServiceUrl)(state.bindHost, state.ports.css) },
115
+ api: state.transport === 'socket' ? { socketPath: state.sockets.api } : { url: (0, bootstrap_1.localServiceUrl)(state.bindHost, state.ports.api) },
115
116
  },
116
117
  });
117
118
  supervisor.addLog('xpod', 'info', `Gateway started (${state.transport === 'socket' ? `unix://${state.sockets.gateway}` : state.baseUrl})`);
@@ -1,3 +1,12 @@
1
+ /**
2
+ * The port a remote tunnel forwards to: the Gateway's tunnel entry.
3
+ *
4
+ * It sits a few ports above the Gateway so it is predictable - the user copies this one number
5
+ * into a provider console and it survives restarts - while staying clear of the block a
6
+ * neighbouring runtime plans for its own services. When the neighbourhood is busy the caller
7
+ * gets an OS-assigned port instead of a stolen one; the runtime reports whichever it got.
8
+ */
9
+ export declare function findGatewayIngressPort(gatewayPort: number): Promise<number>;
1
10
  export declare function getFreePort(basePort: number, host?: string, timeoutMs?: number): Promise<number>;
2
11
  /**
3
12
  * Loopback port handed out by the OS for a listener that must not collide with ports the
@@ -9,19 +18,6 @@ export declare function getFreePort(basePort: number, host?: string, timeoutMs?:
9
18
  * runtime's service.
10
19
  */
11
20
  export declare function getEphemeralLoopbackPort(): Promise<number>;
12
- /**
13
- * The ingress port this deployment should keep using.
14
- *
15
- * Remote tunnels forward to a port the operator typed into a provider console, so an
16
- * OS-assigned port would invalidate that copy on every restart. The port is remembered in
17
- * the runtime state directory; if something else took it meanwhile, a new one is chosen and
18
- * persisted — the caller reports the change so the stale console value can be corrected.
19
- */
20
- export declare function resolveStableLoopbackPort(stateFile: string): Promise<{
21
- port: number;
22
- changed: boolean;
23
- }>;
24
- export declare function readPortFile(stateFile: string): number | undefined;
25
21
  /**
26
22
  * Allocates a port for child services that bind wildcard addresses.
27
23
  * CSS may bind `::` while the API binds `0.0.0.0`, so probing only localhost
@@ -3,16 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.findGatewayIngressPort = findGatewayIngressPort;
6
7
  exports.getFreePort = getFreePort;
7
8
  exports.getEphemeralLoopbackPort = getEphemeralLoopbackPort;
8
- exports.resolveStableLoopbackPort = resolveStableLoopbackPort;
9
- exports.readPortFile = readPortFile;
10
9
  exports.requireFreePortForWildcard = requireFreePortForWildcard;
11
10
  exports.getFreePortForWildcard = getFreePortForWildcard;
12
11
  const node_net_1 = __importDefault(require("node:net"));
13
12
  const node_os_1 = __importDefault(require("node:os"));
14
- const node_fs_1 = require("node:fs");
15
- const node_path_1 = require("node:path");
16
13
  const HIGHEST_PORT = 65_535;
17
14
  const PORT_PROBE_TIMEOUT_MS = 1_000;
18
15
  const RETRYABLE_PORT_ERRORS = new Set([
@@ -103,6 +100,23 @@ async function canListen(port, host, timeoutMs = PORT_PROBE_TIMEOUT_MS) {
103
100
  server.listen(port, host);
104
101
  });
105
102
  }
103
+ /**
104
+ * The port a remote tunnel forwards to: the Gateway's tunnel entry.
105
+ *
106
+ * It sits a few ports above the Gateway so it is predictable - the user copies this one number
107
+ * into a provider console and it survives restarts - while staying clear of the block a
108
+ * neighbouring runtime plans for its own services. When the neighbourhood is busy the caller
109
+ * gets an OS-assigned port instead of a stolen one; the runtime reports whichever it got.
110
+ */
111
+ async function findGatewayIngressPort(gatewayPort) {
112
+ for (let offset = 3; offset < 10; offset += 1) {
113
+ const candidate = gatewayPort + offset;
114
+ if (await getFreePortForWildcard(candidate) === candidate) {
115
+ return candidate;
116
+ }
117
+ }
118
+ return await getEphemeralLoopbackPort();
119
+ }
106
120
  async function getFreePort(basePort, host = '127.0.0.1', timeoutMs = PORT_PROBE_TIMEOUT_MS) {
107
121
  for (let port = basePort; port <= HIGHEST_PORT; port++) {
108
122
  if (await canListen(port, host, timeoutMs)) {
@@ -137,39 +151,6 @@ async function getEphemeralLoopbackPort() {
137
151
  });
138
152
  });
139
153
  }
140
- /**
141
- * The ingress port this deployment should keep using.
142
- *
143
- * Remote tunnels forward to a port the operator typed into a provider console, so an
144
- * OS-assigned port would invalidate that copy on every restart. The port is remembered in
145
- * the runtime state directory; if something else took it meanwhile, a new one is chosen and
146
- * persisted — the caller reports the change so the stale console value can be corrected.
147
- */
148
- async function resolveStableLoopbackPort(stateFile) {
149
- const remembered = readPortFile(stateFile);
150
- if (remembered !== undefined && await canListen(remembered, '127.0.0.1')) {
151
- return { port: remembered, changed: false };
152
- }
153
- const port = await getEphemeralLoopbackPort();
154
- try {
155
- (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(stateFile), { recursive: true });
156
- (0, node_fs_1.writeFileSync)(stateFile, `${port}\n`);
157
- }
158
- catch {
159
- // A deployment without a writable state directory still gets a working port; it just
160
- // cannot promise the same one next time.
161
- }
162
- return { port, changed: remembered !== undefined };
163
- }
164
- function readPortFile(stateFile) {
165
- try {
166
- const port = Number.parseInt((0, node_fs_1.readFileSync)(stateFile, 'utf8').trim(), 10);
167
- return Number.isInteger(port) && port > 0 && port <= 65535 ? port : undefined;
168
- }
169
- catch {
170
- return undefined;
171
- }
172
- }
173
154
  function hasIpv6Address() {
174
155
  return Object.values(node_os_1.default.networkInterfaces()).some((entries) => entries?.some((entry) => entry.family === 'IPv6'));
175
156
  }