@undefineds.co/xpod 0.4.29 → 0.4.30

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 (179) hide show
  1. package/dist/api/ApiServer.js +4 -0
  2. package/dist/api/ai-gateway/AiGatewayService.d.ts +55 -0
  3. package/dist/api/ai-gateway/AiGatewayService.js +145 -6
  4. package/dist/api/ai-gateway/auth/AiConnectionsInvocationKeyIssuer.js +5 -3
  5. package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.d.ts +16 -49
  6. package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js +6 -71
  7. package/dist/api/ai-gateway/auth/InvocationTokenAuthenticator.js +1 -0
  8. package/dist/api/ai-gateway/auth/InvocationTokenCodec.d.ts +4 -0
  9. package/dist/api/ai-gateway/auth/InvocationTokenCodec.js +8 -1
  10. package/dist/api/ai-gateway/connect/FileSessionImportAdapter.d.ts +3 -0
  11. package/dist/api/ai-gateway/connect/FileSessionImportAdapter.js +23 -3
  12. package/dist/api/ai-gateway/connect/SessionImportProfiles.d.ts +9 -1
  13. package/dist/api/ai-gateway/connect/SessionImportProfiles.js +4 -3
  14. package/dist/api/ai-gateway/connect/index.d.ts +40 -0
  15. package/dist/api/ai-gateway/connect/index.js +194 -4
  16. package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +1 -1
  17. package/dist/api/ai-gateway/pod/OwnerPodAccess.js +5 -0
  18. package/dist/api/ai-gateway/pod/PodBaseUrlResolver.d.ts +11 -2
  19. package/dist/api/ai-gateway/pod/PodBaseUrlResolver.js +72 -10
  20. package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.js +1 -1
  21. package/dist/api/ai-gateway/routing/ModelRouter.d.ts +7 -0
  22. package/dist/api/ai-gateway/routing/ModelRouter.js +13 -10
  23. package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.d.ts +1 -5
  24. package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.js +8 -63
  25. package/dist/api/auth/AuthContext.d.ts +4 -0
  26. package/dist/api/auth/ClientCredentialsAuthenticator.js +11 -5
  27. package/dist/api/auth/SolidSessionFactory.d.ts +50 -4
  28. package/dist/api/auth/SolidSessionFactory.js +114 -4
  29. package/dist/api/chatkit/pod-store.d.ts +8 -1
  30. package/dist/api/chatkit/pod-store.js +54 -3
  31. package/dist/api/container/common.js +34 -60
  32. package/dist/api/container/index.js +0 -3
  33. package/dist/api/container/routes.js +1 -8
  34. package/dist/api/container/types.d.ts +2 -9
  35. package/dist/api/container/types.js +0 -5
  36. package/dist/api/handlers/AiGatewayManagementHandler.d.ts +4 -12
  37. package/dist/api/handlers/AiGatewayManagementHandler.js +18 -258
  38. package/dist/api/middleware/AuthMiddleware.js +29 -1
  39. package/dist/api/runs/PiAgentRuntimeDriver.js +6 -1
  40. package/dist/cli/index.js +2 -1
  41. package/dist/identity/oidc/PodOwnershipResolver.js +16 -6
  42. package/dist/runtime/ingress-port.d.ts +9 -2
  43. package/dist/runtime/ingress-port.js +7 -2
  44. package/dist/runtime/local-secret-file.d.ts +1 -1
  45. package/dist/runtime/runner/node/CommunitySolidServerCssRunner.d.ts +3 -1
  46. package/dist/runtime/runner/node/CommunitySolidServerCssRunner.js +31 -1
  47. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +3 -1
  48. package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.js +96 -67
  49. package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.d.ts +2 -1
  50. package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.js +2 -2
  51. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeyRow.d.ts +1 -2
  52. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeyRow.js +2 -2
  53. package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.js +81 -23
  54. package/node_modules/@undefineds.co/ai-connections/dist/AiOfferingDetails.d.ts +2 -1
  55. package/node_modules/@undefineds.co/ai-connections/dist/AiOfferingDetails.js +2 -2
  56. package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.d.ts +2 -1
  57. package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.js +2 -2
  58. package/node_modules/@undefineds.co/ai-connections/dist/AiProviderHeader.js +1 -1
  59. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/fingerprint.d.ts +1 -0
  60. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/fingerprint.js +7 -0
  61. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/normalize.d.ts +1 -2
  62. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/normalize.js +0 -33
  63. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/request.d.ts +1 -1
  64. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/request.js +68 -22
  65. package/node_modules/@undefineds.co/ai-connections/dist/contract/client/types.d.ts +37 -10
  66. package/node_modules/@undefineds.co/ai-connections/dist/controller.js +5 -54
  67. package/node_modules/@undefineds.co/ai-connections/dist/error-wording.js +7 -2
  68. package/node_modules/@undefineds.co/ai-connections/dist/service-access-resources.cjs +405 -0
  69. package/node_modules/@undefineds.co/ai-connections/dist/service-access-resources.d.ts +14 -0
  70. package/node_modules/@undefineds.co/ai-connections/dist/service-access-resources.js +36 -0
  71. package/node_modules/@undefineds.co/ai-connections/dist/service-access.js +5 -26
  72. package/node_modules/@undefineds.co/ai-connections/package.json +10 -2
  73. package/node_modules/@undefineds.co/extension-sdk/dist/solid-permissions.js +131 -13
  74. package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +7 -1
  75. package/node_modules/@undefineds.co/extension-sdk/package.json +1 -1
  76. package/node_modules/@undefineds.co/pod-collections/dist/index.cjs +38 -5
  77. package/node_modules/@undefineds.co/pod-collections/dist/mapping.d.ts +8 -0
  78. package/node_modules/@undefineds.co/pod-collections/dist/mapping.js +34 -0
  79. package/node_modules/@undefineds.co/pod-collections/dist/mutations.d.ts +2 -1
  80. package/node_modules/@undefineds.co/pod-collections/dist/mutations.js +6 -4
  81. package/node_modules/@undefineds.co/pod-collections/dist/sync.js +4 -3
  82. package/node_modules/@undefineds.co/pod-collections/package.json +1 -1
  83. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/IdpChrome.d.ts +1 -1
  84. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/IdpChrome.js +2 -2
  85. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/IdpViews.js +2 -2
  86. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/PodSignInFrame.d.ts +3 -3
  87. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/PodSignInFrame.js +5 -5
  88. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/parts.d.ts +5 -5
  89. package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/parts.js +5 -5
  90. package/node_modules/@undefineds.co/shared-ui/dist/theme.css +32 -5
  91. package/node_modules/@undefineds.co/shared-ui/package.json +1 -1
  92. package/package.json +2 -2
  93. package/static/app/assets/main.css +1 -1
  94. package/static/app/assets/main.js +18 -18
  95. package/static/dashboard/assets/{AccountAuthBoundary-Dv52SZc6.js → AccountAuthBoundary-CuqXFEW4.js} +1 -1
  96. package/static/dashboard/assets/{DesktopOidcCallback-DaT_Rumf.js → DesktopOidcCallback-7i-yOvPW.js} +1 -1
  97. package/static/dashboard/assets/DevicePages-D1m_BNtX.js +2 -0
  98. package/static/dashboard/assets/ModelsPage-0qWGa5Y6.js +12 -0
  99. package/static/dashboard/assets/{PaneListHeader-DtvnRmFq.js → PaneListHeader-uWdPgJ0E.js} +1 -1
  100. package/static/dashboard/assets/{PodDeletionAuthorizationPanel-BJk_8rJq.js → PodDeletionAuthorizationPanel-C22bhZeD.js} +3 -3
  101. package/static/dashboard/assets/{PodPage-C4gzEspV.js → PodPage-Dyo3yCb-.js} +1 -1
  102. package/static/dashboard/assets/{SystemSettingsPage-HaNrP1H1.js → SystemSettingsPage-CeX-oG_a.js} +1 -1
  103. package/static/dashboard/assets/{TasksPage-BdO5K2L7.js → TasksPage-B0EoyRYT.js} +1 -1
  104. package/static/dashboard/assets/{WebDesktopEntry-Cj9_ZfJU.js → WebDesktopEntry-DT44RrTa.js} +1 -1
  105. package/static/dashboard/assets/XpodAiConnectionsPodStore-EXCqZPmb.js +3 -0
  106. package/static/dashboard/assets/XpodShellApp-BEzi4f1j.css +1 -0
  107. package/static/dashboard/assets/XpodShellApp-DAFsxamX.js +4 -0
  108. package/static/dashboard/assets/{account-session-DlcKNG7k.js → account-session-rRAOF7nF.js} +1 -1
  109. package/static/dashboard/assets/{button-wslF55uZ.js → button-WVnQUNG-.js} +1 -1
  110. package/static/dashboard/assets/{collection-runtime-uxxgEu13.js → collection-runtime-BAJQ8Qub.js} +1 -1
  111. package/static/dashboard/assets/{createLucideIcon-BJQl82Qk.js → createLucideIcon-BWelSi3L.js} +1 -1
  112. package/static/dashboard/assets/dashboard-hSOBxPcP.css +1 -0
  113. package/static/dashboard/assets/{dashboard-Or0gnkou.js → dashboard-vmne1ZE0.js} +2 -2
  114. package/static/dashboard/assets/{index-BqFeOML9.js → index-HDQQ8asz.js} +1 -1
  115. package/static/dashboard/assets/{index-DgKn1twH.js → index-gtv-MAHl.js} +1 -1
  116. package/static/dashboard/assets/{label-CS6Sx6Zb.js → label-tKuCTJm2.js} +1 -1
  117. package/static/dashboard/assets/{list-UyhlCFKk.js → list-CKq3KHke.js} +1 -1
  118. package/static/dashboard/assets/{nav-item-style-CW1Nnorq.js → nav-item-style-B2gI7c52.js} +1 -1
  119. package/static/dashboard/assets/pod-collections-host-BqOAkacM.js +8 -0
  120. package/static/dashboard/assets/{safe-continuation-ClWAhcma.js → safe-continuation-BsKjDpAA.js} +1 -1
  121. package/static/dashboard/assets/{section-header-CEIEcco-.js → section-header-DM0JU-wk.js} +1 -1
  122. package/static/dashboard/assets/{setting-row-CaYv3dfF.js → setting-row-XiH7UjWy.js} +1 -1
  123. package/static/dashboard/assets/{xpod-remembered-login-BUF9fin1.js → xpod-remembered-login-nv1g1sfC.js} +4 -4
  124. package/static/dashboard/dashboard.html +2 -2
  125. package/static/settings/assets/{AccountAuthBoundary-Chqd38oU.js → AccountAuthBoundary-DAUR0omy.js} +1 -1
  126. package/static/settings/assets/{DesktopOidcCallback-VUrOSM_q.js → DesktopOidcCallback-BNZAZMWY.js} +1 -1
  127. package/static/settings/assets/DevicePages-BO9SrXRp.js +2 -0
  128. package/static/settings/assets/ModelsPage-DREEXdf3.js +12 -0
  129. package/static/settings/assets/{PaneListHeader-B5RkRqr4.js → PaneListHeader-CeUH0JjQ.js} +1 -1
  130. package/static/settings/assets/{PodDeletionAuthorizationPanel-DPM-5Izt.js → PodDeletionAuthorizationPanel-Ch4--l4b.js} +3 -3
  131. package/static/settings/assets/{PodPage-CxND6wwc.js → PodPage-CqJBj3GJ.js} +1 -1
  132. package/static/settings/assets/{SystemSettingsPage-C8EdMkW7.js → SystemSettingsPage-2LSjpqUa.js} +1 -1
  133. package/static/settings/assets/{TasksPage-DuqptEm8.js → TasksPage-DA5IRxlP.js} +1 -1
  134. package/static/settings/assets/{WebDesktopEntry-BRcyktkv.js → WebDesktopEntry-BVelF1q0.js} +1 -1
  135. package/static/settings/assets/XpodAiConnectionsPodStore-O5-2qBsx.js +3 -0
  136. package/static/settings/assets/XpodShellApp-BEzi4f1j.css +1 -0
  137. package/static/settings/assets/XpodShellApp-D1b3kqD0.js +4 -0
  138. package/static/settings/assets/XpodThemeProvider-hSOBxPcP.css +1 -0
  139. package/static/settings/assets/{XpodThemeProvider-DK3pIdRG.js → XpodThemeProvider-rUdAw66p.js} +2 -2
  140. package/static/settings/assets/{account-session-DJOZ03xr.js → account-session-BD1q8D_o.js} +1 -1
  141. package/static/settings/assets/auth-callback-PWS7okI8.js +1 -0
  142. package/static/settings/assets/{button-D3yW-2o1.js → button-ZJYFB218.js} +1 -1
  143. package/static/settings/assets/{collection-runtime-DfGo25mh.js → collection-runtime-C2FHCCXJ.js} +1 -1
  144. package/static/settings/assets/{createLucideIcon-CacwLsmB.js → createLucideIcon-B2wXvYTD.js} +1 -1
  145. package/static/settings/assets/{index-r5KRYsKC.js → index-JFAkaKZH.js} +1 -1
  146. package/static/settings/assets/{label-MJjUmvzG.js → label-BLrTAmGy.js} +1 -1
  147. package/static/settings/assets/{list-Ce-5k1MX.js → list-Cm96vvJO.js} +1 -1
  148. package/static/settings/assets/{nav-item-style-ZUbL8KOZ.js → nav-item-style-C2upI7sr.js} +1 -1
  149. package/static/settings/assets/pod-collections-host-BqOAkacM.js +8 -0
  150. package/static/settings/assets/{safe-continuation-vlBZFSlU.js → safe-continuation-CYaRj3rj.js} +1 -1
  151. package/static/settings/assets/{section-header-DGJdEvQw.js → section-header-BviL5H8E.js} +1 -1
  152. package/static/settings/assets/{setting-row-C7tuFiho.js → setting-row-BYikj0YO.js} +1 -1
  153. package/static/settings/assets/{settings-CyQPih1O.js → settings-CpoDG_Qr.js} +1 -1
  154. package/static/settings/assets/{xpod-remembered-login-D-TzzT5K.js → xpod-remembered-login-BJ4QUSXy.js} +4 -4
  155. package/static/settings/auth-callback.html +3 -3
  156. package/static/settings/settings.html +3 -3
  157. package/dist/api/ai-gateway/auth/GatewayApiKey.d.ts +0 -28
  158. package/dist/api/ai-gateway/auth/GatewayApiKey.js +0 -162
  159. package/dist/api/ai-gateway/auth/GatewayKeyLocatorCodec.d.ts +0 -26
  160. package/dist/api/ai-gateway/auth/GatewayKeyLocatorCodec.js +0 -97
  161. package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.d.ts +0 -67
  162. package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js +0 -340
  163. package/dist/runtime/gateway-locator-secret.d.ts +0 -5
  164. package/dist/runtime/gateway-locator-secret.js +0 -30
  165. package/static/dashboard/assets/DevicePages-HjclpIVm.js +0 -2
  166. package/static/dashboard/assets/ModelsPage-Be2TPd-x.js +0 -11
  167. package/static/dashboard/assets/XpodAiConnectionsPodStore-B7gmXBmC.js +0 -3
  168. package/static/dashboard/assets/XpodShellApp-Bwom2xL3.css +0 -1
  169. package/static/dashboard/assets/XpodShellApp-D_KY4nCW.js +0 -4
  170. package/static/dashboard/assets/dashboard-CbJ-JkrI.css +0 -1
  171. package/static/dashboard/assets/pod-collections-host-DjK2xf-b.js +0 -8
  172. package/static/settings/assets/DevicePages-C6qwvWwu.js +0 -2
  173. package/static/settings/assets/ModelsPage-Ry_dObRQ.js +0 -11
  174. package/static/settings/assets/XpodAiConnectionsPodStore-CyA_BJVC.js +0 -3
  175. package/static/settings/assets/XpodShellApp-Bwom2xL3.css +0 -1
  176. package/static/settings/assets/XpodShellApp-CsivHJl0.js +0 -4
  177. package/static/settings/assets/XpodThemeProvider-CbJ-JkrI.css +0 -1
  178. package/static/settings/assets/auth-callback-GIBYEz_7.js +0 -1
  179. package/static/settings/assets/pod-collections-host-DjK2xf-b.js +0 -8
@@ -1,13 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.registerAiGatewayManagementRoutes = registerAiGatewayManagementRoutes;
4
- const node_crypto_1 = require("node:crypto");
4
+ const PodBaseUrlResolver_1 = require("../ai-gateway/pod/PodBaseUrlResolver");
5
5
  const global_logger_factory_1 = require("global-logger-factory");
6
6
  const readBoundedJsonBody_1 = require("../http/readBoundedJsonBody");
7
7
  const GatewayPrincipal_1 = require("../ai-gateway/auth/GatewayPrincipal");
8
8
  const models_1 = require("../ai-gateway/models");
9
9
  const AiConnectionsServiceAccess_1 = require("../ai-gateway/service-access/AiConnectionsServiceAccess");
10
- const OwnerPodAccess_1 = require("../ai-gateway/pod/OwnerPodAccess");
11
10
  const PodAccessFailureResponse_1 = require("./PodAccessFailureResponse");
12
11
  const AiClientConfigurationService_1 = require("../service/AiClientConfigurationService");
13
12
  const errors_1 = require("../ai-gateway/errors");
@@ -35,14 +34,29 @@ function registerAiGatewayManagementRoutes(server, options) {
35
34
  logger.warn('Local AI Connection service identity is unavailable; using the authenticated WebID for this interactive request');
36
35
  }
37
36
  }
37
+ const selectedPod = request.headers['x-xpod-pod-url'];
38
+ if (Array.isArray(selectedPod)) {
39
+ throw new errors_1.GatewayProtocolError('Provide exactly one X-Xpod-Pod-Url', { status: 400 });
40
+ }
41
+ if (!options.podBaseUrlResolver)
42
+ throw new Error('Pod storage binding resolver is unavailable');
43
+ const podBaseUrl = await (0, PodBaseUrlResolver_1.resolveOwnerPodBaseUrl)(request.auth.webId, options.podBaseUrlResolver, {
44
+ ...request.auth,
45
+ ...(selectedPod ? { requestedPodUrl: selectedPod } : {}),
46
+ });
47
+ if (!podBaseUrl) {
48
+ throw new errors_1.GatewayProtocolError('No owned Pod storage binding is available', { status: 404, code: 'service_access_missing' });
49
+ }
38
50
  const descriptor = (0, AiConnectionsServiceAccess_1.createAiConnectionsServiceAccess)({
39
51
  ownerWebId: request.auth.webId,
40
52
  serviceWebId: service.webId,
53
+ podBaseUrl,
41
54
  });
55
+ const boundAuth = { ...request.auth, authorizedPodUrl: podBaseUrl };
42
56
  const invocation = options.aiConnectionInvocationKeyIssuer
43
- ? await options.aiConnectionInvocationKeyIssuer.issue({ auth: request.auth })
57
+ ? await options.aiConnectionInvocationKeyIssuer.issue({ auth: boundAuth })
44
58
  : undefined;
45
- const aiClientConfiguration = await withAiClientConfigurationInvocation(options.aiClientConfiguration ?? (0, AiClientConfigurationService_1.unavailableAiClientConfigurationCapability)(), options.aiConnectionInvocationKeyIssuer, request.auth);
59
+ const aiClientConfiguration = await withAiClientConfigurationInvocation(options.aiClientConfiguration ?? (0, AiClientConfigurationService_1.unavailableAiClientConfigurationCapability)(), options.aiConnectionInvocationKeyIssuer, boundAuth);
46
60
  logger.debug(`Issuing AI Connection service access for ${request.auth.webId}; invocation=${Boolean(invocation)}`);
47
61
  sendJson(response, 200, {
48
62
  ...descriptor,
@@ -54,172 +68,6 @@ function registerAiGatewayManagementRoutes(server, options) {
54
68
  sendAiConnectionsServiceAccessError(response, error);
55
69
  }
56
70
  });
57
- server.get('/api/ai/gateway/keys', async (request, response) => {
58
- if (!authorizeGatewayKeyManagement(request, response)) {
59
- return;
60
- }
61
- const repository = requireGatewayAccessKeyRepository(options, response);
62
- if (!repository) {
63
- return;
64
- }
65
- try {
66
- const auth = request.auth;
67
- const owner = (0, GatewayPrincipal_1.ownerWebIdForGatewayKeyManagement)(auth, undefined);
68
- if (!owner) {
69
- sendJson(response, 403, { error: 'Gateway API key management requires an owner WebID' });
70
- return;
71
- }
72
- const records = await repository.listByOwner(owner, { auth });
73
- // Issued credentials keep no copy of the wrapper, so the list can only
74
- // report where each one is in effect.
75
- sendJson(response, 200, {
76
- data: records.map((record) => publicGatewayAccessKeyRecord(record, false)),
77
- });
78
- }
79
- catch (error) {
80
- sendGatewayAccessKeyError(response, error);
81
- }
82
- });
83
- server.post('/api/ai/gateway/keys', async (request, response) => {
84
- if (!authorizeGatewayKeyManagement(request, response)) {
85
- return;
86
- }
87
- const repository = requireGatewayAccessKeyRepository(options, response);
88
- if (!repository) {
89
- return;
90
- }
91
- const body = await readJsonObject(request, response, jsonBodyLimitBytes);
92
- if (!body) {
93
- return;
94
- }
95
- try {
96
- const auth = request.auth;
97
- const owner = auth.type === 'solid' ? (0, GatewayPrincipal_1.ownerWebIdForGatewayKeyManagement)(auth, undefined) : undefined;
98
- if (!owner) {
99
- sendJson(response, 403, { error: 'Gateway API key management requires an owner WebID' });
100
- return;
101
- }
102
- const apiKey = typeof body.apiKey === 'string' ? body.apiKey : '';
103
- if (!validClientCredentialWrapper(apiKey)) {
104
- sendJson(response, 400, { error: 'A CSS client credential wrapper is required' });
105
- return;
106
- }
107
- if (!options.validateClientCredential || !repository.createKeyId) {
108
- sendJson(response, 503, { error: 'CSS credential registration is unavailable' });
109
- return;
110
- }
111
- const verified = await options.validateClientCredential(apiKey);
112
- if (!verified.success || verified.context?.type !== 'solid') {
113
- sendJson(response, verified.category === 'service_unavailable' ? 503 : 401, {
114
- error: 'CSS client credential verification failed',
115
- });
116
- return;
117
- }
118
- if (verified.context.webId !== owner) {
119
- sendJson(response, 403, { error: 'CSS client credential belongs to another WebID' });
120
- return;
121
- }
122
- // Registering an application is about that application's own credential - where it is in
123
- // effect, and how to revoke it. Background Pod access is a separate, explicit grant the user
124
- // makes where they manage index/embedding work (`POST /api/ai/task-credentials`), so nothing
125
- // about it is written here.
126
- const name = normalizeOptionalString(body.name) ?? 'Xpod API Key';
127
- const keyId = repository.createKeyId(owner, options.deployment);
128
- const createdAt = new Date();
129
- const record = await repository.create({
130
- id: keyId,
131
- kind: 'client-credentials',
132
- owner,
133
- secretHash: '',
134
- deployment: options.deployment,
135
- scopes: [],
136
- createdAt,
137
- name,
138
- // The CSS label is the OIDC client id inside the wrapper; keeping it is
139
- // what lets a later destroy find the credential at CSS.
140
- clientCredentialId: verified.context.clientId,
141
- appliedTo: normalizeOptionalString(body.appliedTo),
142
- appliedOn: normalizeOptionalString(body.appliedOn),
143
- }, { auth });
144
- sendJson(response, 201, {
145
- // The only time the wrapper leaves Xpod: the caller applies it now.
146
- key: apiKey,
147
- record: publicGatewayAccessKeyRecord(record, false, apiKey),
148
- });
149
- }
150
- catch (error) {
151
- sendGatewayAccessKeyError(response, error);
152
- }
153
- });
154
- server.patch('/api/ai/gateway/keys/:keyId', async (request, response, params) => {
155
- if (!authorizeGatewayKeyManagement(request, response)) {
156
- return;
157
- }
158
- const repository = requireGatewayAccessKeyRepository(options, response);
159
- if (!repository) {
160
- return;
161
- }
162
- const body = await readJsonObject(request, response, jsonBodyLimitBytes);
163
- if (!body) {
164
- return;
165
- }
166
- if (typeof body.enabled !== 'boolean') {
167
- sendJson(response, 400, { error: 'enabled must be a boolean' });
168
- return;
169
- }
170
- try {
171
- const record = await ownedGatewayAccessKey(repository, params.keyId, request.auth);
172
- if (!record) {
173
- sendJson(response, 404, { error: 'Gateway API Key not found' });
174
- return;
175
- }
176
- if (record.kind === 'client-credentials') {
177
- sendJson(response, 409, { error: 'CSS client credentials cannot be suspended through Pod metadata' });
178
- return;
179
- }
180
- const updated = await repository.setEnabled(record.id, body.enabled, new Date(), { auth: request.auth });
181
- if (!updated) {
182
- sendJson(response, 404, { error: 'Gateway API Key not found' });
183
- return;
184
- }
185
- const plaintext = await repository.revealPlaintext(updated.id, { auth: request.auth });
186
- sendJson(response, 200, {
187
- record: publicGatewayAccessKeyRecord(updated, Boolean(plaintext)),
188
- });
189
- }
190
- catch (error) {
191
- sendGatewayAccessKeyError(response, error);
192
- }
193
- });
194
- server.delete('/api/ai/gateway/keys/:keyId', async (request, response, params) => {
195
- if (!authorizeGatewayKeyManagement(request, response)) {
196
- return;
197
- }
198
- const repository = requireGatewayAccessKeyRepository(options, response);
199
- if (!repository) {
200
- return;
201
- }
202
- try {
203
- const record = await ownedGatewayAccessKey(repository, params.keyId, request.auth);
204
- if (!record) {
205
- sendJson(response, 404, { error: 'Gateway API Key not found' });
206
- return;
207
- }
208
- // This removes the saved client configuration only. The Account host
209
- // revokes CSS credentials before requesting this companion cleanup.
210
- await repository.delete(record.id, { auth: request.auth });
211
- if (record.clientCredentialId) {
212
- options.invalidateClientCredential?.(record.clientCredentialId);
213
- }
214
- sendJson(response, 200, {
215
- deleted: true,
216
- record: publicGatewayAccessKeyRecord(record, false),
217
- });
218
- }
219
- catch (error) {
220
- sendGatewayAccessKeyError(response, error);
221
- }
222
- });
223
71
  server.get('/api/ai/connections/authorization-methods', async (request, response) => {
224
72
  if (!authorizeProviderConnect(request, response))
225
73
  return;
@@ -980,9 +828,6 @@ function authorizeManagementCaller(request, response, options) {
980
828
  }
981
829
  return true;
982
830
  }
983
- if (options.allowServiceGatewayKeyManagement && (0, GatewayPrincipal_1.canManageGatewayKeys)(auth)) {
984
- return true;
985
- }
986
831
  sendJson(response, 403, { error: options.nonSolidPrincipalError });
987
832
  return false;
988
833
  }
@@ -1015,20 +860,6 @@ function authorizeProviderModels(request, response) {
1015
860
  nonSolidPrincipalError: 'Provider model management requires the current Solid identity',
1016
861
  });
1017
862
  }
1018
- function authorizeGatewayKeyManagement(request, response) {
1019
- return authorizeManagementCaller(request, response, {
1020
- gatewayKeyPrincipalError: 'Gateway API keys cannot manage Gateway API keys',
1021
- nonSolidPrincipalError: 'Gateway API key management requires the current Solid identity',
1022
- allowServiceGatewayKeyManagement: true,
1023
- });
1024
- }
1025
- function requireGatewayAccessKeyRepository(options, response) {
1026
- if (!options.gatewayAccessKeyRepository) {
1027
- sendJson(response, 503, { error: 'Gateway API Key repository is not configured' });
1028
- return undefined;
1029
- }
1030
- return options.gatewayAccessKeyRepository;
1031
- }
1032
863
  function requireConnectService(options, response) {
1033
864
  if (!options.connectService) {
1034
865
  sendJson(response, 503, { error: 'AI provider Connect service is not configured' });
@@ -1149,55 +980,6 @@ function normalizeCustomModelInput(body) {
1149
980
  ...(capabilities.length > 0 ? { capabilities } : {}),
1150
981
  };
1151
982
  }
1152
- function validClientCredentialWrapper(value) {
1153
- if (!value.startsWith('sk-'))
1154
- return false;
1155
- const encoded = value.slice(3);
1156
- const decoded = Buffer.from(encoded, 'base64').toString('utf8');
1157
- return Buffer.from(decoded, 'utf8').toString('base64') === encoded
1158
- && /^[^\s\x00-\x1f\x7f:]+:[^\s\x00-\x1f\x7f]+$/u.test(decoded);
1159
- }
1160
- async function ownedGatewayAccessKey(repository, keyId, auth) {
1161
- if (!keyId) {
1162
- return undefined;
1163
- }
1164
- const record = await repository.findById(keyId, { auth });
1165
- if (!record) {
1166
- return undefined;
1167
- }
1168
- const owner = (0, GatewayPrincipal_1.ownerWebIdForGatewayKeyManagement)(auth, record.owner);
1169
- return owner && owner === record.owner ? record : undefined;
1170
- }
1171
- function publicGatewayAccessKeyRecord(record, plaintextAvailable, plaintext) {
1172
- const suffix = plaintext?.slice(-8) ?? record.plaintext?.slice(-8) ?? record.id.slice(-8);
1173
- const enabled = !record.disabledAt && !record.revokedAt;
1174
- return {
1175
- id: record.id,
1176
- ...(record.kind ? { kind: record.kind } : {}),
1177
- ...(record.credentialResource ? { credentialResource: record.credentialResource } : {}),
1178
- ...(plaintext ? { fingerprint: (0, node_crypto_1.createHash)('sha256').update(plaintext).digest('hex') } : {}),
1179
- owner: record.owner,
1180
- deployment: record.deployment,
1181
- scopes: record.scopes,
1182
- createdAt: record.createdAt.toISOString(),
1183
- ...(record.expiresAt ? { expiresAt: record.expiresAt.toISOString() } : {}),
1184
- ...(record.lastUsedAt ? { lastUsedAt: record.lastUsedAt.toISOString() } : {}),
1185
- ...(record.disabledAt ? { disabledAt: record.disabledAt.toISOString() } : {}),
1186
- ...(record.revokedAt ? { revokedAt: record.revokedAt.toISOString() } : {}),
1187
- ...(record.name ? { name: record.name } : {}),
1188
- // The CSS client id is what a later destroy needs; the applied state says
1189
- // where the wrapper was written.
1190
- ...(record.clientCredentialId ? { clientCredentialId: record.clientCredentialId } : {}),
1191
- ...(record.status ? { status: record.status } : {}),
1192
- ...(record.appliedTo ? { appliedTo: record.appliedTo } : {}),
1193
- ...(record.appliedOn ? { appliedOn: record.appliedOn } : {}),
1194
- ...(record.appliedAt ? { appliedAt: record.appliedAt.toISOString() } : {}),
1195
- enabled,
1196
- plaintextAvailable,
1197
- suffix,
1198
- maskedHint: `••••••••${suffix}`,
1199
- };
1200
- }
1201
983
  function normalizeCredentialPatch(body) {
1202
984
  const patch = {};
1203
985
  if (Object.prototype.hasOwnProperty.call(body, 'apiKey')) {
@@ -1357,28 +1139,6 @@ function sendCredentialPoolError(response, error) {
1357
1139
  logger.error(`Provider credential pool operation failed: ${message}`);
1358
1140
  sendJson(response, 500, { error: 'Provider credential pool operation failed' });
1359
1141
  }
1360
- function sendGatewayAccessKeyError(response, error) {
1361
- const message = error instanceof Error ? error.message : String(error);
1362
- if ((0, OwnerPodAccess_1.isPodAccessFailure)(message)) {
1363
- logger.warn(`Gateway API Key operation refused: ${(0, AiClientConfigurationService_1.redactSecretText)(message)}`);
1364
- sendJson(response, 403, { error: 'service_access_missing' });
1365
- return;
1366
- }
1367
- if (message === 'caller_owner_mismatch') {
1368
- sendJson(response, 403, { error: 'Gateway API Key owner mismatch' });
1369
- return;
1370
- }
1371
- if (message === 'caller_pod_access_unavailable') {
1372
- sendJson(response, 401, { error: 'Authentication required' });
1373
- return;
1374
- }
1375
- if (message === 'gateway_key_secret_write_failed') {
1376
- sendJson(response, 500, { error: 'Gateway API Key secret could not be saved' });
1377
- return;
1378
- }
1379
- logger.error(`Gateway API Key operation failed: ${(0, AiClientConfigurationService_1.redactSecretText)(message)}`);
1380
- sendJson(response, 500, { error: 'Gateway API Key operation failed' });
1381
- }
1382
1142
  function sendLegacyProviderConnectError(response, error) {
1383
1143
  // A Pod this caller cannot open has to answer with the code callers already act on
1384
1144
  // (`service_access_missing`), not as an internal failure: the retry with the caller's own
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AuthMiddleware = void 0;
4
+ const PodBaseUrlResolver_1 = require("../ai-gateway/pod/PodBaseUrlResolver");
4
5
  const global_logger_factory_1 = require("global-logger-factory");
5
6
  /**
6
7
  * Middleware that handles authentication for API requests
@@ -39,7 +40,34 @@ class AuthMiddleware {
39
40
  return false;
40
41
  }
41
42
  // Attach auth context to request
42
- request.auth = result.context;
43
+ const requestedPodUrl = request.headers['x-xpod-pod-url'];
44
+ if (Array.isArray(requestedPodUrl)) {
45
+ response.statusCode = 400;
46
+ response.setHeader('Content-Type', 'application/json');
47
+ response.end(JSON.stringify({ error: 'invalid_request', message: 'Provide exactly one X-Xpod-Pod-Url' }));
48
+ return false;
49
+ }
50
+ if (requestedPodUrl !== undefined) {
51
+ try {
52
+ (0, PodBaseUrlResolver_1.normalizeVerifiedPodRoot)(requestedPodUrl);
53
+ }
54
+ catch {
55
+ response.statusCode = 400;
56
+ response.setHeader('Content-Type', 'application/json');
57
+ response.end(JSON.stringify({ error: 'invalid_request', message: 'Invalid X-Xpod-Pod-Url' }));
58
+ return false;
59
+ }
60
+ }
61
+ if (requestedPodUrl !== undefined && result.context?.type === 'solid'
62
+ && (result.context.viaGatewayApiKey || result.context.internalInvocation)
63
+ && !result.context.authorizedPodUrl) {
64
+ // The existing browser fetch reacquires an invocation on 401 using its Solid session.
65
+ this.sendUnauthorized(response, 'A Pod-bound invocation is required');
66
+ return false;
67
+ }
68
+ request.auth = result.context?.type === 'solid' && requestedPodUrl !== undefined
69
+ ? { ...result.context, requestedPodUrl }
70
+ : result.context;
43
71
  return true;
44
72
  }
45
73
  sendUnauthorized(response, message) {
@@ -960,7 +960,12 @@ class PiAgentRuntimeDriver {
960
960
  // Keep a native dynamic import so the CommonJS build can lazily load pi's
961
961
  // ESM-only package instead of requiring it during CSS component discovery.
962
962
  const nativeImport = new Function('specifier', 'return import(specifier)');
963
- PiAgentRuntimeDriver.sdkPromise = nativeImport('@mariozechner/pi-coding-agent');
963
+ // Compiled Bun cannot resolve this bare specifier in its extracted runtime
964
+ // (the Components.js adapter has the same constraint). Use the staged ESM
965
+ // entry directly; ordinary JS installs can still resolve a hoisted package.
966
+ const stagedEntry = path.join(package_root_1.PACKAGE_ROOT, 'node_modules', '@mariozechner/pi-coding-agent', 'dist', 'index.js');
967
+ PiAgentRuntimeDriver.sdkPromise = nativeImport(fs.existsSync(stagedEntry)
968
+ ? (0, node_url_1.pathToFileURL)(stagedEntry).href : '@mariozechner/pi-coding-agent');
964
969
  return PiAgentRuntimeDriver.sdkPromise;
965
970
  }
966
971
  }
package/dist/cli/index.js CHANGED
@@ -120,7 +120,8 @@ async function main() {
120
120
  : await Promise.resolve().then(() => __importStar(require('@solid/community-server')));
121
121
  ensureBunCommunitySolidServerJwkCompat(css);
122
122
  const { AppRunner } = css;
123
- await new AppRunner().runCli(process.argv);
123
+ const { createPackageRootPreferredAppRunner } = await Promise.resolve().then(() => __importStar(require('../runtime/runner/node/CommunitySolidServerCssRunner')));
124
+ await createPackageRootPreferredAppRunner(AppRunner, package_root_1.PACKAGE_ROOT).runCli(process.argv);
124
125
  return;
125
126
  }
126
127
  const wantsRootHelp = argv.length === 0 || argv[0] === 'help' || argv[0] === '--help' || argv[0] === '-h';
@@ -63,7 +63,7 @@ class CssPodOwnershipResolver {
63
63
  return [];
64
64
  }
65
65
  const entries = [];
66
- const resolvedWebIds = new Set();
66
+ const resolvedBindings = new Set();
67
67
  for (const pod of pods ?? []) {
68
68
  if (!pod || typeof pod.id !== 'string' || typeof pod.baseUrl !== 'string' || pod.baseUrl.length === 0) {
69
69
  continue;
@@ -81,16 +81,19 @@ class CssPodOwnershipResolver {
81
81
  }
82
82
  for (const owner of owners ?? []) {
83
83
  const webId = owner?.webId;
84
- if (!isWebIdString(webId) || !candidates.has(webId) || resolvedWebIds.has(webId)) {
84
+ if (!isWebIdString(webId) || !candidates.has(webId)) {
85
85
  continue;
86
86
  }
87
87
  const storageUrl = ensureTrailingSlash(pod.baseUrl);
88
+ const bindingKey = ownedBindingKey(webId, storageUrl);
89
+ if (resolvedBindings.has(bindingKey))
90
+ continue;
88
91
  entries.push({
89
92
  webId,
90
93
  storageUrl,
91
94
  storageMode: deriveStorageMode(webId, storageUrl),
92
95
  });
93
- resolvedWebIds.add(webId);
96
+ resolvedBindings.add(bindingKey);
94
97
  }
95
98
  }
96
99
  return entries;
@@ -156,7 +159,7 @@ class CssPodOwnershipResolver {
156
159
  return [];
157
160
  }
158
161
  const allowedWebIds = new Set(candidates);
159
- const resolvedWebIds = new Set();
162
+ const resolvedBindings = new Set();
160
163
  const entries = [];
161
164
  for (const entry of body.entries) {
162
165
  if (!isRecord(entry)
@@ -166,7 +169,7 @@ class CssPodOwnershipResolver {
166
169
  this.warnRemoteFailure();
167
170
  return [];
168
171
  }
169
- if (!allowedWebIds.has(entry.webId) || resolvedWebIds.has(entry.webId)) {
172
+ if (!allowedWebIds.has(entry.webId)) {
170
173
  continue;
171
174
  }
172
175
  const podUrl = entry.podUrl;
@@ -175,12 +178,15 @@ class CssPodOwnershipResolver {
175
178
  continue;
176
179
  }
177
180
  const storageUrl = ensureTrailingSlash(entry.storageUrl);
181
+ const bindingKey = ownedBindingKey(entry.webId, storageUrl);
182
+ if (resolvedBindings.has(bindingKey))
183
+ continue;
178
184
  entries.push({
179
185
  webId: entry.webId,
180
186
  storageUrl,
181
187
  storageMode: deriveStorageMode(entry.webId, storageUrl),
182
188
  });
183
- resolvedWebIds.add(entry.webId);
189
+ resolvedBindings.add(bindingKey);
184
190
  }
185
191
  return entries;
186
192
  }
@@ -248,6 +254,10 @@ function hasManagedRoute(target) {
248
254
  && target.routeAccessTokenExp
249
255
  && target.nodeId);
250
256
  }
257
+ /** Exact verified identity/storage pair; URI delimiters never collapse distinct bindings. */
258
+ function ownedBindingKey(webId, storageUrl) {
259
+ return JSON.stringify([webId, storageUrl]);
260
+ }
251
261
  /**
252
262
  * Derives the same cloud/local/custom classification used by scoped consent.
253
263
  */
@@ -9,7 +9,10 @@ import { type DeclaredOriginReadResult } from '../tunnel/TunnelDeclaredOrigin';
9
9
  * `GET /v4/tunnels` `local_port`; the Cloudflare dashboard's remote configuration read
10
10
  * back through the connector) — adopted when it is free, so the operator does not have to
11
11
  * edit the console to match the runtime;
12
- * 3. `findGatewayIngressPort(gatewayPort)` — the predictable, dynamic gateway+3..+9 entry.
12
+ * 3. `findGatewayIngressPort(gatewayPort, reservedPorts)` — the predictable, dynamic
13
+ * gateway+3..+9 entry. It skips the gateway/CSS/API ports this run serves itself, because
14
+ * the tunnel entry is the one port an operator copies into a provider console: a number a
15
+ * sibling service binds later must never be the address a tunnel forwards to.
13
16
  *
14
17
  * Both strict sources are strict about *being taken*: a port somebody else holds fails the
15
18
  * start with the occupant named (pid, command line, cwd). Nothing here signals a process, and
@@ -49,7 +52,11 @@ export interface IngressPortLogger {
49
52
  warn(message: string): void;
50
53
  }
51
54
  export interface IngressPortDeps {
52
- findDefaultPort(mainPort: number): Promise<number>;
55
+ /**
56
+ * The dynamic gateway-derived entry. `excluded` carries this run's own service ports so the
57
+ * default scan cannot hand back a port a sibling service is about to bind.
58
+ */
59
+ findDefaultPort(mainPort: number, excluded: ReadonlySet<number>): Promise<number>;
53
60
  isFree(port: number): Promise<boolean>;
54
61
  identifyOccupants(port: number): string;
55
62
  readDeclaredOrigin(profile: IngressProfileLike, options: {
@@ -128,8 +128,13 @@ async function resolveIngressPort(request) {
128
128
  + 'instead, and the tunnel provider will report its own failure. '
129
129
  + 'Pin XPOD_GATEWAY_INGRESS_PORT to decide the entry explicitly');
130
130
  }
131
- const port = await deps.findDefaultPort(request.mainPort);
132
- deps.logger.info(`Tunnel entry ${port} chosen from the gateway port ${request.mainPort} (gateway+3..+9, first free port)`);
131
+ // The dynamic entry is the only source derived from a *planned* neighbourhood, so it is the
132
+ // only one that has to be told which of those numbers this run has already claimed. Without
133
+ // it the scan can pick the API port that has been chosen but not bound yet, and the Gateway
134
+ // then proxies its own API traffic into its tunnel ingress in a loop.
135
+ const port = await deps.findDefaultPort(request.mainPort, reservedPorts);
136
+ deps.logger.info(`Tunnel entry ${port} chosen from the gateway port ${request.mainPort} `
137
+ + '(gateway+3..+9, first free port outside this runtime\'s own service ports)');
133
138
  return { port, source: 'gateway-default', inactiveDeclarations };
134
139
  }
135
140
  /** A strict port is taken as-is or not at all; the occupant is named, never signalled. */
@@ -1,4 +1,4 @@
1
- export type LocalSecretPurpose = 'gateway-locator-secret' | 'secret-cell-root-key';
1
+ export type LocalSecretPurpose = 'secret-cell-root-key';
2
2
  export declare function localSecretPathForDatabase(databasePath: string, purpose: LocalSecretPurpose): string;
3
3
  /** Publish complete private key files without replacing an existing identity. */
4
4
  export declare function readOrCreateLocalSecret(options: {
@@ -1,7 +1,9 @@
1
- import type { App } from '@solid/community-server';
1
+ import type { App, AppRunner } from '@solid/community-server';
2
2
  import { type IModuleState } from 'componentsjs';
3
3
  import type { CssRuntimeRunner, CssRuntimeRunnerStartOptions } from '../types';
4
4
  export declare function createPackageRootPreferredModuleState(packageRoot: string): Promise<IModuleState>;
5
+ /** Keep CSS's CLI parsing and startup while supplying the extracted dependency state. */
6
+ export declare function createPackageRootPreferredAppRunner(Runner: typeof AppRunner, packageRoot: string): AppRunner;
5
7
  export declare class CommunitySolidServerCssRunner implements CssRuntimeRunner {
6
8
  readonly name = "community-solid-server";
7
9
  start(options: CssRuntimeRunnerStartOptions): Promise<App>;
@@ -28,16 +28,46 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.communitySolidServerCssRunner = exports.CommunitySolidServerCssRunner = void 0;
30
30
  exports.createPackageRootPreferredModuleState = createPackageRootPreferredModuleState;
31
+ exports.createPackageRootPreferredAppRunner = createPackageRootPreferredAppRunner;
31
32
  const ensureSupportedBun_1 = require("../../compat/ensureSupportedBun");
32
33
  const node_path_1 = __importDefault(require("node:path"));
33
34
  const node_fs_1 = __importDefault(require("node:fs"));
34
35
  const componentsjs_1 = require("componentsjs");
35
36
  const ensureBunUndiciCompat_1 = require("../../compat/ensureBunUndiciCompat");
37
+ /** The compiled archive owns its complete Components.js dependency tree. */
38
+ class ExtractedPackageModuleStateBuilder extends componentsjs_1.ModuleStateBuilder {
39
+ buildNodeModuleImportPaths(mainModulePath) {
40
+ return [mainModulePath];
41
+ }
42
+ }
36
43
  async function createPackageRootPreferredModuleState(packageRoot) {
37
- const moduleState = await new componentsjs_1.ModuleStateBuilder().buildModuleState(require, packageRoot);
44
+ const extracted = process.env.XPOD_BUN_SINGLE_RUNTIME === '1';
45
+ const builder = extracted ? new ExtractedPackageModuleStateBuilder() : new componentsjs_1.ModuleStateBuilder();
46
+ const moduleState = await builder.buildModuleState(require, packageRoot);
47
+ if (extracted && moduleState.nodeModulePaths.some(directory => {
48
+ const relative = node_path_1.default.relative(moduleState.mainModulePath, directory);
49
+ return relative === '..' || relative.startsWith(`..${node_path_1.default.sep}`) || node_path_1.default.isAbsolute(relative);
50
+ })) {
51
+ throw new Error('Extracted Components dependency is outside its packaged runtime');
52
+ }
38
53
  preferMainPackageComponents(moduleState);
39
54
  return moduleState;
40
55
  }
56
+ /** Keep CSS's CLI parsing and startup while supplying the extracted dependency state. */
57
+ function createPackageRootPreferredAppRunner(Runner, packageRoot) {
58
+ if (process.env.XPOD_BUN_SINGLE_RUNTIME !== '1') {
59
+ return new Runner();
60
+ }
61
+ return new class extends Runner {
62
+ async create(input = {}) {
63
+ const moduleState = await createPackageRootPreferredModuleState(packageRoot);
64
+ return super.create({
65
+ ...input,
66
+ loaderProperties: { ...input.loaderProperties, mainModulePath: packageRoot, moduleState },
67
+ });
68
+ }
69
+ }();
70
+ }
41
71
  function preferMainPackageComponents(moduleState) {
42
72
  const packageRoot = moduleState.mainModulePath;
43
73
  const packageJson = moduleState.packageJsons[packageRoot];
@@ -7,6 +7,8 @@ export interface AiConnectionsPanelProps {
7
7
  onAuthorizeService?: () => Promise<void>;
8
8
  /** Disable when the embedding application already renders shared-ui Toaster. */
9
9
  renderToaster?: boolean;
10
+ /** Reveals read-only interface addresses (design §4.1); off by default. */
11
+ developerMode?: boolean;
10
12
  openExternal?: (url: string) => void | Promise<void>;
11
13
  clientConfigurationBridge?: AiClientConfigurationBridge;
12
14
  selectedSection?: AiConnectionsWorkspaceSection;
@@ -33,4 +35,4 @@ export interface AiConnectionsPanelProps {
33
35
  */
34
36
  liveCredentialRows?: readonly CredentialRow[];
35
37
  }
36
- export declare function AiConnectionsPanel({ client, onAuthorizeService, renderToaster, openExternal, clientConfigurationBridge, selectedSection, selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput, providerProducts, providerLoadError, providerLoading, onProviderStateChange, onModelSelectionChange, liveRevision, liveCredentialRows, }: AiConnectionsPanelProps): import("react").JSX.Element;
38
+ export declare function AiConnectionsPanel({ client, onAuthorizeService, renderToaster, developerMode, openExternal, clientConfigurationBridge, selectedSection, selectedProvider, selectedCredentialId, providerSummaries: providerSummariesInput, providerProducts, providerLoadError, providerLoading, onProviderStateChange, onModelSelectionChange, liveRevision, liveCredentialRows, }: AiConnectionsPanelProps): import("react").JSX.Element;