@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.
- package/dist/api/ApiServer.js +4 -0
- package/dist/api/ai-gateway/AiGatewayService.d.ts +55 -0
- package/dist/api/ai-gateway/AiGatewayService.js +145 -6
- package/dist/api/ai-gateway/auth/AiConnectionsInvocationKeyIssuer.js +5 -3
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.d.ts +16 -49
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js +6 -71
- package/dist/api/ai-gateway/auth/InvocationTokenAuthenticator.js +1 -0
- package/dist/api/ai-gateway/auth/InvocationTokenCodec.d.ts +4 -0
- package/dist/api/ai-gateway/auth/InvocationTokenCodec.js +8 -1
- package/dist/api/ai-gateway/connect/FileSessionImportAdapter.d.ts +3 -0
- package/dist/api/ai-gateway/connect/FileSessionImportAdapter.js +23 -3
- package/dist/api/ai-gateway/connect/SessionImportProfiles.d.ts +9 -1
- package/dist/api/ai-gateway/connect/SessionImportProfiles.js +4 -3
- package/dist/api/ai-gateway/connect/index.d.ts +40 -0
- package/dist/api/ai-gateway/connect/index.js +194 -4
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +1 -1
- package/dist/api/ai-gateway/pod/OwnerPodAccess.js +5 -0
- package/dist/api/ai-gateway/pod/PodBaseUrlResolver.d.ts +11 -2
- package/dist/api/ai-gateway/pod/PodBaseUrlResolver.js +72 -10
- package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.js +1 -1
- package/dist/api/ai-gateway/routing/ModelRouter.d.ts +7 -0
- package/dist/api/ai-gateway/routing/ModelRouter.js +13 -10
- package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.d.ts +1 -5
- package/dist/api/ai-gateway/service-access/AiConnectionsServiceAccess.js +8 -63
- package/dist/api/auth/AuthContext.d.ts +4 -0
- package/dist/api/auth/ClientCredentialsAuthenticator.js +11 -5
- package/dist/api/auth/SolidSessionFactory.d.ts +50 -4
- package/dist/api/auth/SolidSessionFactory.js +114 -4
- package/dist/api/chatkit/pod-store.d.ts +8 -1
- package/dist/api/chatkit/pod-store.js +54 -3
- package/dist/api/container/common.js +34 -60
- package/dist/api/container/index.js +0 -3
- package/dist/api/container/routes.js +1 -8
- package/dist/api/container/types.d.ts +2 -9
- package/dist/api/container/types.js +0 -5
- package/dist/api/handlers/AiGatewayManagementHandler.d.ts +4 -12
- package/dist/api/handlers/AiGatewayManagementHandler.js +18 -258
- package/dist/api/middleware/AuthMiddleware.js +29 -1
- package/dist/api/runs/PiAgentRuntimeDriver.js +6 -1
- package/dist/cli/index.js +2 -1
- package/dist/identity/oidc/PodOwnershipResolver.js +16 -6
- package/dist/runtime/ingress-port.d.ts +9 -2
- package/dist/runtime/ingress-port.js +7 -2
- package/dist/runtime/local-secret-file.d.ts +1 -1
- package/dist/runtime/runner/node/CommunitySolidServerCssRunner.d.ts +3 -1
- package/dist/runtime/runner/node/CommunitySolidServerCssRunner.js +31 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +3 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.js +96 -67
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.d.ts +2 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.js +2 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeyRow.d.ts +1 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeyRow.js +2 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.js +81 -23
- package/node_modules/@undefineds.co/ai-connections/dist/AiOfferingDetails.d.ts +2 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiOfferingDetails.js +2 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.d.ts +2 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.js +2 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderHeader.js +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/contract/client/fingerprint.d.ts +1 -0
- package/node_modules/@undefineds.co/ai-connections/dist/contract/client/fingerprint.js +7 -0
- package/node_modules/@undefineds.co/ai-connections/dist/contract/client/normalize.d.ts +1 -2
- package/node_modules/@undefineds.co/ai-connections/dist/contract/client/normalize.js +0 -33
- package/node_modules/@undefineds.co/ai-connections/dist/contract/client/request.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connections/dist/contract/client/request.js +68 -22
- package/node_modules/@undefineds.co/ai-connections/dist/contract/client/types.d.ts +37 -10
- package/node_modules/@undefineds.co/ai-connections/dist/controller.js +5 -54
- package/node_modules/@undefineds.co/ai-connections/dist/error-wording.js +7 -2
- package/node_modules/@undefineds.co/ai-connections/dist/service-access-resources.cjs +405 -0
- package/node_modules/@undefineds.co/ai-connections/dist/service-access-resources.d.ts +14 -0
- package/node_modules/@undefineds.co/ai-connections/dist/service-access-resources.js +36 -0
- package/node_modules/@undefineds.co/ai-connections/dist/service-access.js +5 -26
- package/node_modules/@undefineds.co/ai-connections/package.json +10 -2
- package/node_modules/@undefineds.co/extension-sdk/dist/solid-permissions.js +131 -13
- package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +7 -1
- package/node_modules/@undefineds.co/extension-sdk/package.json +1 -1
- package/node_modules/@undefineds.co/pod-collections/dist/index.cjs +38 -5
- package/node_modules/@undefineds.co/pod-collections/dist/mapping.d.ts +8 -0
- package/node_modules/@undefineds.co/pod-collections/dist/mapping.js +34 -0
- package/node_modules/@undefineds.co/pod-collections/dist/mutations.d.ts +2 -1
- package/node_modules/@undefineds.co/pod-collections/dist/mutations.js +6 -4
- package/node_modules/@undefineds.co/pod-collections/dist/sync.js +4 -3
- package/node_modules/@undefineds.co/pod-collections/package.json +1 -1
- package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/IdpChrome.d.ts +1 -1
- package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/IdpChrome.js +2 -2
- package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/IdpViews.js +2 -2
- package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/PodSignInFrame.d.ts +3 -3
- package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/PodSignInFrame.js +5 -5
- package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/parts.d.ts +5 -5
- package/node_modules/@undefineds.co/shared-ui/dist/pod-sign-in/parts.js +5 -5
- package/node_modules/@undefineds.co/shared-ui/dist/theme.css +32 -5
- package/node_modules/@undefineds.co/shared-ui/package.json +1 -1
- package/package.json +2 -2
- package/static/app/assets/main.css +1 -1
- package/static/app/assets/main.js +18 -18
- package/static/dashboard/assets/{AccountAuthBoundary-Dv52SZc6.js → AccountAuthBoundary-CuqXFEW4.js} +1 -1
- package/static/dashboard/assets/{DesktopOidcCallback-DaT_Rumf.js → DesktopOidcCallback-7i-yOvPW.js} +1 -1
- package/static/dashboard/assets/DevicePages-D1m_BNtX.js +2 -0
- package/static/dashboard/assets/ModelsPage-0qWGa5Y6.js +12 -0
- package/static/dashboard/assets/{PaneListHeader-DtvnRmFq.js → PaneListHeader-uWdPgJ0E.js} +1 -1
- package/static/dashboard/assets/{PodDeletionAuthorizationPanel-BJk_8rJq.js → PodDeletionAuthorizationPanel-C22bhZeD.js} +3 -3
- package/static/dashboard/assets/{PodPage-C4gzEspV.js → PodPage-Dyo3yCb-.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsPage-HaNrP1H1.js → SystemSettingsPage-CeX-oG_a.js} +1 -1
- package/static/dashboard/assets/{TasksPage-BdO5K2L7.js → TasksPage-B0EoyRYT.js} +1 -1
- package/static/dashboard/assets/{WebDesktopEntry-Cj9_ZfJU.js → WebDesktopEntry-DT44RrTa.js} +1 -1
- package/static/dashboard/assets/XpodAiConnectionsPodStore-EXCqZPmb.js +3 -0
- package/static/dashboard/assets/XpodShellApp-BEzi4f1j.css +1 -0
- package/static/dashboard/assets/XpodShellApp-DAFsxamX.js +4 -0
- package/static/dashboard/assets/{account-session-DlcKNG7k.js → account-session-rRAOF7nF.js} +1 -1
- package/static/dashboard/assets/{button-wslF55uZ.js → button-WVnQUNG-.js} +1 -1
- package/static/dashboard/assets/{collection-runtime-uxxgEu13.js → collection-runtime-BAJQ8Qub.js} +1 -1
- package/static/dashboard/assets/{createLucideIcon-BJQl82Qk.js → createLucideIcon-BWelSi3L.js} +1 -1
- package/static/dashboard/assets/dashboard-hSOBxPcP.css +1 -0
- package/static/dashboard/assets/{dashboard-Or0gnkou.js → dashboard-vmne1ZE0.js} +2 -2
- package/static/dashboard/assets/{index-BqFeOML9.js → index-HDQQ8asz.js} +1 -1
- package/static/dashboard/assets/{index-DgKn1twH.js → index-gtv-MAHl.js} +1 -1
- package/static/dashboard/assets/{label-CS6Sx6Zb.js → label-tKuCTJm2.js} +1 -1
- package/static/dashboard/assets/{list-UyhlCFKk.js → list-CKq3KHke.js} +1 -1
- package/static/dashboard/assets/{nav-item-style-CW1Nnorq.js → nav-item-style-B2gI7c52.js} +1 -1
- package/static/dashboard/assets/pod-collections-host-BqOAkacM.js +8 -0
- package/static/dashboard/assets/{safe-continuation-ClWAhcma.js → safe-continuation-BsKjDpAA.js} +1 -1
- package/static/dashboard/assets/{section-header-CEIEcco-.js → section-header-DM0JU-wk.js} +1 -1
- package/static/dashboard/assets/{setting-row-CaYv3dfF.js → setting-row-XiH7UjWy.js} +1 -1
- package/static/dashboard/assets/{xpod-remembered-login-BUF9fin1.js → xpod-remembered-login-nv1g1sfC.js} +4 -4
- package/static/dashboard/dashboard.html +2 -2
- package/static/settings/assets/{AccountAuthBoundary-Chqd38oU.js → AccountAuthBoundary-DAUR0omy.js} +1 -1
- package/static/settings/assets/{DesktopOidcCallback-VUrOSM_q.js → DesktopOidcCallback-BNZAZMWY.js} +1 -1
- package/static/settings/assets/DevicePages-BO9SrXRp.js +2 -0
- package/static/settings/assets/ModelsPage-DREEXdf3.js +12 -0
- package/static/settings/assets/{PaneListHeader-B5RkRqr4.js → PaneListHeader-CeUH0JjQ.js} +1 -1
- package/static/settings/assets/{PodDeletionAuthorizationPanel-DPM-5Izt.js → PodDeletionAuthorizationPanel-Ch4--l4b.js} +3 -3
- package/static/settings/assets/{PodPage-CxND6wwc.js → PodPage-CqJBj3GJ.js} +1 -1
- package/static/settings/assets/{SystemSettingsPage-C8EdMkW7.js → SystemSettingsPage-2LSjpqUa.js} +1 -1
- package/static/settings/assets/{TasksPage-DuqptEm8.js → TasksPage-DA5IRxlP.js} +1 -1
- package/static/settings/assets/{WebDesktopEntry-BRcyktkv.js → WebDesktopEntry-BVelF1q0.js} +1 -1
- package/static/settings/assets/XpodAiConnectionsPodStore-O5-2qBsx.js +3 -0
- package/static/settings/assets/XpodShellApp-BEzi4f1j.css +1 -0
- package/static/settings/assets/XpodShellApp-D1b3kqD0.js +4 -0
- package/static/settings/assets/XpodThemeProvider-hSOBxPcP.css +1 -0
- package/static/settings/assets/{XpodThemeProvider-DK3pIdRG.js → XpodThemeProvider-rUdAw66p.js} +2 -2
- package/static/settings/assets/{account-session-DJOZ03xr.js → account-session-BD1q8D_o.js} +1 -1
- package/static/settings/assets/auth-callback-PWS7okI8.js +1 -0
- package/static/settings/assets/{button-D3yW-2o1.js → button-ZJYFB218.js} +1 -1
- package/static/settings/assets/{collection-runtime-DfGo25mh.js → collection-runtime-C2FHCCXJ.js} +1 -1
- package/static/settings/assets/{createLucideIcon-CacwLsmB.js → createLucideIcon-B2wXvYTD.js} +1 -1
- package/static/settings/assets/{index-r5KRYsKC.js → index-JFAkaKZH.js} +1 -1
- package/static/settings/assets/{label-MJjUmvzG.js → label-BLrTAmGy.js} +1 -1
- package/static/settings/assets/{list-Ce-5k1MX.js → list-Cm96vvJO.js} +1 -1
- package/static/settings/assets/{nav-item-style-ZUbL8KOZ.js → nav-item-style-C2upI7sr.js} +1 -1
- package/static/settings/assets/pod-collections-host-BqOAkacM.js +8 -0
- package/static/settings/assets/{safe-continuation-vlBZFSlU.js → safe-continuation-CYaRj3rj.js} +1 -1
- package/static/settings/assets/{section-header-DGJdEvQw.js → section-header-BviL5H8E.js} +1 -1
- package/static/settings/assets/{setting-row-C7tuFiho.js → setting-row-BYikj0YO.js} +1 -1
- package/static/settings/assets/{settings-CyQPih1O.js → settings-CpoDG_Qr.js} +1 -1
- package/static/settings/assets/{xpod-remembered-login-D-TzzT5K.js → xpod-remembered-login-BJ4QUSXy.js} +4 -4
- package/static/settings/auth-callback.html +3 -3
- package/static/settings/settings.html +3 -3
- package/dist/api/ai-gateway/auth/GatewayApiKey.d.ts +0 -28
- package/dist/api/ai-gateway/auth/GatewayApiKey.js +0 -162
- package/dist/api/ai-gateway/auth/GatewayKeyLocatorCodec.d.ts +0 -26
- package/dist/api/ai-gateway/auth/GatewayKeyLocatorCodec.js +0 -97
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.d.ts +0 -67
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js +0 -340
- package/dist/runtime/gateway-locator-secret.d.ts +0 -5
- package/dist/runtime/gateway-locator-secret.js +0 -30
- package/static/dashboard/assets/DevicePages-HjclpIVm.js +0 -2
- package/static/dashboard/assets/ModelsPage-Be2TPd-x.js +0 -11
- package/static/dashboard/assets/XpodAiConnectionsPodStore-B7gmXBmC.js +0 -3
- package/static/dashboard/assets/XpodShellApp-Bwom2xL3.css +0 -1
- package/static/dashboard/assets/XpodShellApp-D_KY4nCW.js +0 -4
- package/static/dashboard/assets/dashboard-CbJ-JkrI.css +0 -1
- package/static/dashboard/assets/pod-collections-host-DjK2xf-b.js +0 -8
- package/static/settings/assets/DevicePages-C6qwvWwu.js +0 -2
- package/static/settings/assets/ModelsPage-Ry_dObRQ.js +0 -11
- package/static/settings/assets/XpodAiConnectionsPodStore-CyA_BJVC.js +0 -3
- package/static/settings/assets/XpodShellApp-Bwom2xL3.css +0 -1
- package/static/settings/assets/XpodShellApp-CsivHJl0.js +0 -4
- package/static/settings/assets/XpodThemeProvider-CbJ-JkrI.css +0 -1
- package/static/settings/assets/auth-callback-GIBYEz_7.js +0 -1
- 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
|
|
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:
|
|
57
|
+
? await options.aiConnectionInvocationKeyIssuer.issue({ auth: boundAuth })
|
|
44
58
|
: undefined;
|
|
45
|
-
const aiClientConfiguration = await withAiClientConfigurationInvocation(options.aiClientConfiguration ?? (0, AiClientConfigurationService_1.unavailableAiClientConfigurationCapability)(), options.aiConnectionInvocationKeyIssuer,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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)
|
|
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
|
-
|
|
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
|
|
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)
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
132
|
-
|
|
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 = '
|
|
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
|
|
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;
|