@undefineds.co/xpod 0.4.14 → 0.4.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/cloud.json +0 -3
- package/config/local.json +0 -3
- package/config/xpod.base.json +0 -24
- package/dist/api/ai-config/AiConfigStore.d.ts +2 -2
- package/dist/api/ai-config/AiConfigStore.js +4 -1
- package/dist/api/ai-gateway/auth/CallerPodAccess.d.ts +2 -5
- package/dist/api/ai-gateway/auth/CallerPodAccess.js +3 -42
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.d.ts +2 -1
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js +1 -1
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.d.ts +3 -8
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js +9 -32
- package/dist/api/ai-gateway/connect/index.d.ts +3 -3
- package/dist/api/ai-gateway/connect/index.js +9 -38
- package/dist/api/ai-gateway/errors.js +2 -1
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.d.ts +3 -3
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +7 -11
- package/dist/api/ai-gateway/pod/HostedPodRoute.d.ts +27 -0
- package/dist/api/ai-gateway/pod/HostedPodRoute.js +47 -0
- package/dist/api/ai-gateway/pod/OwnerPodAccess.d.ts +79 -0
- package/dist/api/ai-gateway/pod/OwnerPodAccess.js +192 -0
- package/dist/api/ai-gateway/pod/PodInterfaceKeyStore.d.ts +52 -0
- package/dist/api/ai-gateway/pod/PodInterfaceKeyStore.js +61 -0
- package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.d.ts +3 -3
- package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.js +7 -32
- package/dist/api/auth/ClientCredentialsAuthenticator.js +5 -28
- package/dist/api/auth/TokenEndpointRoute.d.ts +18 -0
- package/dist/api/auth/TokenEndpointRoute.js +36 -0
- package/dist/api/chatkit/pod-store.d.ts +4 -4
- package/dist/api/chatkit/pod-store.js +24 -95
- package/dist/api/container/common.js +36 -23
- package/dist/api/container/local.js +62 -29
- package/dist/api/container/routes.js +39 -7
- package/dist/api/container/types.d.ts +2 -2
- package/dist/api/handlers/AiGatewayManagementHandler.d.ts +6 -0
- package/dist/api/handlers/AiGatewayManagementHandler.js +17 -4
- package/dist/api/handlers/NetworkSettingsHandler.d.ts +7 -0
- package/dist/api/handlers/NetworkSettingsHandler.js +7 -0
- package/dist/api/handlers/PodSettingsHandler.d.ts +3 -3
- package/dist/api/handlers/PodSettingsHandler.js +3 -3
- package/dist/api/handlers/ProvisionHandler.d.ts +29 -0
- package/dist/api/handlers/ProvisionHandler.js +46 -0
- package/dist/api/handlers/ReachabilityHandler.js +3 -1
- package/dist/api/runtime.d.ts +9 -0
- package/dist/api/runtime.js +16 -3
- package/dist/cli/commands/start.d.ts +9 -2
- package/dist/cli/commands/start.js +15 -17
- package/dist/components/components.jsonld +1 -1
- package/dist/components/context.jsonld +5 -42
- package/dist/edge/EdgeNodeAgent.d.ts +10 -0
- package/dist/edge/EdgeNodeAgent.js +55 -0
- package/dist/edge/EdgeNodeAgent.jsonld +8 -0
- package/dist/edge/reachability/ReachabilitySessionService.js +4 -1
- package/dist/edge/reachability/RouteSetBuilder.d.ts +18 -1
- package/dist/edge/reachability/RouteSetBuilder.js +47 -0
- package/dist/edge/reachability/RouteSetBuilder.jsonld +29 -0
- package/dist/edge/reachability/types.d.ts +8 -2
- package/dist/http/SubgraphSparqlHttpHandler.d.ts +1 -25
- package/dist/http/SubgraphSparqlHttpHandler.js +0 -100
- package/dist/http/SubgraphSparqlHttpHandler.jsonld +0 -8
- package/dist/identity/drizzle/PodInterfaceKeyRepository.d.ts +33 -0
- package/dist/identity/drizzle/PodInterfaceKeyRepository.js +78 -0
- package/dist/identity/drizzle/db.d.ts +7 -0
- package/dist/identity/drizzle/db.js +30 -0
- package/dist/identity/drizzle/schema.pg.d.ts +9 -0
- package/dist/identity/drizzle/schema.pg.js +16 -1
- package/dist/identity/drizzle/schema.sqlite.d.ts +106 -0
- package/dist/identity/drizzle/schema.sqlite.js +16 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +3 -5
- package/dist/runtime/GatewayAdminProxyAuth.d.ts +1 -16
- package/dist/runtime/GatewayAdminProxyAuth.js +2 -71
- package/dist/runtime/Proxy.d.ts +10 -1
- package/dist/runtime/Proxy.js +95 -28
- package/dist/runtime/bootstrap.d.ts +10 -0
- package/dist/runtime/bootstrap.js +24 -0
- package/dist/runtime/host/node/NodeRuntimeHost.js +5 -3
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +2 -3
- package/dist/runtime/js-runtime.js +10 -3
- package/dist/runtime/lifecycle.js +5 -4
- package/dist/runtime/port-finder.d.ts +9 -13
- package/dist/runtime/port-finder.js +18 -37
- package/dist/tunnel/AutoTunnelProvider.d.ts +56 -0
- package/dist/tunnel/AutoTunnelProvider.js +181 -0
- package/dist/tunnel/index.d.ts +1 -0
- package/dist/tunnel/index.js +3 -1
- package/node_modules/@undefineds.co/ai-connections/dist/error-wording.js +7 -2
- package/node_modules/@undefineds.co/solid-sdk/dist/access-route.cjs +230 -0
- package/node_modules/@undefineds.co/solid-sdk/dist/access-route.d.ts +76 -0
- package/node_modules/@undefineds.co/solid-sdk/dist/access-route.js +115 -0
- package/node_modules/@undefineds.co/solid-sdk/dist/index.cjs +89 -0
- package/node_modules/@undefineds.co/solid-sdk/dist/index.d.ts +1 -0
- package/node_modules/@undefineds.co/solid-sdk/dist/index.js +1 -0
- package/node_modules/@undefineds.co/solid-sdk/package.json +6 -1
- package/package.json +2 -2
- package/static/app/assets/inrupt-smoke.js +23 -23
- package/static/auth-callback/assets/{AiConfigContext-DCXpjzpj.js → AiConfigContext-Bx0HCAW5.js} +1 -1
- package/static/auth-callback/assets/{AiConfigPage-fe-xMIXa.js → AiConfigPage-ChQImMbm.js} +1 -1
- package/static/auth-callback/assets/{DocumentProcessingPanel-BGnkfMuU.js → DocumentProcessingPanel-D830H4SH.js} +1 -1
- package/static/auth-callback/assets/{IndexLifecyclePanel-42Jups0j.js → IndexLifecyclePanel-CnlkjMF8.js} +1 -1
- package/static/auth-callback/assets/{IndexSubjectPanel-CYyLOlQU.js → IndexSubjectPanel-CdEfg_CO.js} +1 -1
- package/static/auth-callback/assets/{ModelAssignmentsPanel-BOvUH4yr.js → ModelAssignmentsPanel-D-8A8dZx.js} +1 -1
- package/static/auth-callback/assets/{ModelsPage-DwyITxt7.js → ModelsPage-Cim7cubp.js} +3 -3
- package/static/auth-callback/assets/{NetworkPage-CG9RelJA.js → NetworkPage-CfK3x-pb.js} +2 -2
- package/static/auth-callback/assets/{PaneListHeader-yvd5ohs6.js → PaneListHeader-Bf_kEd4U.js} +1 -1
- package/static/auth-callback/assets/{SearchIndexingPanel-2_a6ezzj.js → SearchIndexingPanel-4kD4RBEQ.js} +1 -1
- package/static/auth-callback/assets/{StatusSubjectPanel-8qtVxnzC.js → StatusSubjectPanel-Bw9AiTSf.js} +1 -1
- package/static/auth-callback/assets/{StatusWorkspace-CBdRahCF.js → StatusWorkspace-C-301H-0.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsPage-BZJ6vWkg.js → SystemSettingsPage-BbWn-eG6.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsSubjectPanel-xm08UhXP.js → SystemSettingsSubjectPanel-DA4wvNSm.js} +1 -1
- package/static/auth-callback/assets/{XpodAiConnectionsPodStore-V6vgGfuw.js → XpodAiConnectionsPodStore-CohdyLoX.js} +1 -1
- package/static/auth-callback/assets/{activity-CeM7xly8.js → activity-CCsb9Oam.js} +1 -1
- package/static/auth-callback/assets/ai-connections-DexTPyfC.js +1 -0
- package/static/auth-callback/assets/{auth-callback-DTG8cSj7.js → auth-callback-Ds-c62W3.js} +5 -5
- package/static/auth-callback/assets/{badge-qJo2Zr4d.js → badge-CQm5OyzR.js} +1 -1
- package/static/auth-callback/assets/{collection-runtime-Bztsz31a.js → collection-runtime-DlAuU5TW.js} +1 -1
- package/static/auth-callback/assets/{dialog-D-h6x5x0.js → dialog-CnGzg5Ff.js} +1 -1
- package/static/auth-callback/assets/{download-C2ir4lmR.js → download-DwMONJvm.js} +1 -1
- package/static/auth-callback/assets/{external-link-THLDL4On.js → external-link-Bu5AGqCO.js} +1 -1
- package/static/auth-callback/assets/{index-BlVZb9A7.js → index-B0T-1YO8.js} +1 -1
- package/static/auth-callback/assets/{index-BRpv4yO3.js → index-C8QZf_4W.js} +1 -1
- package/static/auth-callback/assets/{index-D983R1FV.js → index-DwIlrIDG.js} +1 -1
- package/static/auth-callback/assets/{index-browser-3FvR0aaf.js → index-browser-lRsMcP_7.js} +1 -1
- package/static/auth-callback/assets/{key-round-C9U5j1Ly.js → key-round-BDMtU57P.js} +1 -1
- package/static/auth-callback/assets/{rotate-ccw-DP45cD4o.js → rotate-ccw-CoKIGCsQ.js} +1 -1
- package/static/auth-callback/assets/{skeleton-Dn4EiSCS.js → skeleton-CPoSWHDr.js} +1 -1
- package/static/auth-callback/assets/{waypoints-uqFQ3uEG.js → waypoints-BeYHxqHv.js} +1 -1
- package/static/auth-callback/assets/{workspace-layout-DLYK0Wwu.js → workspace-layout-xA5YxiK3.js} +1 -1
- package/static/auth-callback/auth-callback.html +1 -1
- package/static/dashboard/assets/{AiConfigContext-DJcMECNw.js → AiConfigContext-rWx4TyiH.js} +1 -1
- package/static/dashboard/assets/{AiConfigPage-BvE7dOTy.js → AiConfigPage-StVJpDFT.js} +1 -1
- package/static/dashboard/assets/{DocumentProcessingPanel-D9780krf.js → DocumentProcessingPanel-DJ5yul2O.js} +1 -1
- package/static/dashboard/assets/{IndexLifecyclePanel-SjsUcnbM.js → IndexLifecyclePanel-CpjtgezK.js} +1 -1
- package/static/dashboard/assets/{IndexSubjectPanel-C-ym2Tqi.js → IndexSubjectPanel-BVKcot1_.js} +1 -1
- package/static/dashboard/assets/{ModelAssignmentsPanel-BRjZ-arB.js → ModelAssignmentsPanel-BxVgWZPc.js} +1 -1
- package/static/dashboard/assets/{ModelsPage-BtTU6du3.js → ModelsPage-CECBwmeO.js} +3 -3
- package/static/dashboard/assets/{NetworkPage-CV9qpkDg.js → NetworkPage-zQgFscEW.js} +2 -2
- package/static/dashboard/assets/{PaneListHeader-KyPTTBsv.js → PaneListHeader-DIPe8pS6.js} +1 -1
- package/static/dashboard/assets/{SearchIndexingPanel-DolHGawg.js → SearchIndexingPanel-lalFJ3c8.js} +1 -1
- package/static/dashboard/assets/{StatusSubjectPanel-_YZvKiYi.js → StatusSubjectPanel-CpY_KU-G.js} +1 -1
- package/static/dashboard/assets/{StatusWorkspace-Dlbh_G40.js → StatusWorkspace-BwWCii3A.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsPage-Be7QSIoz.js → SystemSettingsPage-BKZxX-_n.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsSubjectPanel-DBp0gja7.js → SystemSettingsSubjectPanel-BZrqb2C5.js} +1 -1
- package/static/dashboard/assets/{XpodAiConnectionsPodStore-ClpSjzpP.js → XpodAiConnectionsPodStore-Bbpx9dTN.js} +1 -1
- package/static/dashboard/assets/{activity-lsNbTXJu.js → activity-BJ15TLVP.js} +1 -1
- package/static/dashboard/assets/ai-connections-GG6qkTJt.js +1 -0
- package/static/dashboard/assets/{badge-CVatKjaG.js → badge-BBX5FlaB.js} +1 -1
- package/static/dashboard/assets/{collection-runtime-Ec4UnY28.js → collection-runtime-UBbHBzdf.js} +1 -1
- package/static/dashboard/assets/{dashboard-BEzsRsvF.js → dashboard-7Y6BHyV9.js} +62 -62
- package/static/dashboard/assets/{dialog-BuyelQ4V.js → dialog-QrOJ-hB0.js} +1 -1
- package/static/dashboard/assets/{download-B4Nf678F.js → download-DK9x-VOP.js} +1 -1
- package/static/dashboard/assets/{external-link-PYv9CvKL.js → external-link-Cnkn87mJ.js} +1 -1
- package/static/dashboard/assets/{index-C9XPE-mI.js → index-B1z84it5.js} +1 -1
- package/static/dashboard/assets/{index-awr7ulur.js → index-DzjauX3N.js} +1 -1
- package/static/dashboard/assets/{index-Cx69bTNh.js → index-cIa8_efI.js} +1 -1
- package/static/dashboard/assets/{key-round-VsY80U1Z.js → key-round-BoS6UqKz.js} +1 -1
- package/static/dashboard/assets/{rotate-ccw-Cz1K4vE9.js → rotate-ccw-BeWV76i0.js} +1 -1
- package/static/dashboard/assets/{skeleton-BhNv_8tO.js → skeleton-CypcJL07.js} +1 -1
- package/static/dashboard/assets/{waypoints-DYS9XFYV.js → waypoints-zHOOqfhi.js} +1 -1
- package/static/dashboard/assets/{workspace-layout-OZJAFx5V.js → workspace-layout-DZ9JuxnM.js} +1 -1
- package/static/dashboard/dashboard.html +1 -1
- package/static/settings/assets/{AiConfigContext-B8JS3MXF.js → AiConfigContext-D3b1l_Kw.js} +1 -1
- package/static/settings/assets/{AiConfigPage-C3Zl8LUl.js → AiConfigPage-DYKw-atP.js} +1 -1
- package/static/settings/assets/{DocumentProcessingPanel-DpDZAQvf.js → DocumentProcessingPanel-DguRfsIV.js} +1 -1
- package/static/settings/assets/{IndexLifecyclePanel-Ec1XF88t.js → IndexLifecyclePanel-B85qJJA4.js} +1 -1
- package/static/settings/assets/{IndexSubjectPanel-BulT9BmO.js → IndexSubjectPanel-CsN7IxaV.js} +1 -1
- package/static/settings/assets/{ModelAssignmentsPanel-BcGSmYjb.js → ModelAssignmentsPanel-DEp9byI6.js} +1 -1
- package/static/settings/assets/{ModelsPage-CvTCKy1T.js → ModelsPage-CzTnPs_G.js} +3 -3
- package/static/settings/assets/{NetworkPage-DQF5u9Bn.js → NetworkPage-BDVnmUU0.js} +2 -2
- package/static/settings/assets/{PaneListHeader-D40hqcVl.js → PaneListHeader-Cpe39N76.js} +1 -1
- package/static/settings/assets/{SearchIndexingPanel-iCUPOx_0.js → SearchIndexingPanel-DA9w8lLL.js} +1 -1
- package/static/settings/assets/{StatusSubjectPanel-E--ZHSql.js → StatusSubjectPanel-BU0Aq0CS.js} +1 -1
- package/static/settings/assets/{StatusWorkspace-YjDAx1II.js → StatusWorkspace-D1AC1i5N.js} +1 -1
- package/static/settings/assets/{SystemSettingsPage-CDdV3mC9.js → SystemSettingsPage-ChKvOioO.js} +1 -1
- package/static/settings/assets/{SystemSettingsSubjectPanel-Br8WazDq.js → SystemSettingsSubjectPanel-DyTpOnD2.js} +1 -1
- package/static/settings/assets/{XpodAiConnectionsPodStore-CLr38P_Z.js → XpodAiConnectionsPodStore-VU5Bsz1a.js} +1 -1
- package/static/settings/assets/{activity-C5DAHHTE.js → activity-DGpLfsQB.js} +1 -1
- package/static/settings/assets/ai-connections-DexTPyfC.js +1 -0
- package/static/settings/assets/{badge-D8eIyxKt.js → badge-_hCrrWRP.js} +1 -1
- package/static/settings/assets/{collection-runtime-DLc9zil8.js → collection-runtime-E40TZ8Cl.js} +1 -1
- package/static/settings/assets/{dialog-CyuR7Va4.js → dialog-DTr2JkHn.js} +1 -1
- package/static/settings/assets/{download-c0oxZrCz.js → download-B_D21DDX.js} +1 -1
- package/static/settings/assets/{external-link-D3Z34fP_.js → external-link-BATYaM13.js} +1 -1
- package/static/settings/assets/{index-CSr3-2Cj.js → index-BAlAVi-J.js} +1 -1
- package/static/settings/assets/{index-ComidxAm.js → index-Ckh4h9jj.js} +1 -1
- package/static/settings/assets/{index-CKGbRFlc.js → index-DOiwLF4B.js} +1 -1
- package/static/settings/assets/{index-browser-CAscEbae.js → index-browser-DFFWN3Kr.js} +1 -1
- package/static/settings/assets/{key-round-DyjLmXuB.js → key-round-ZTVU_1O1.js} +1 -1
- package/static/settings/assets/{rotate-ccw-679HF_ec.js → rotate-ccw-DDdw8PTU.js} +1 -1
- package/static/settings/assets/{settings-DKknqu4C.js → settings-CyLnISOv.js} +62 -62
- package/static/settings/assets/{skeleton-CkopNkPB.js → skeleton-DEzA3hc2.js} +1 -1
- package/static/settings/assets/{waypoints-CrqfAftE.js → waypoints-BSdfNvEb.js} +1 -1
- package/static/settings/assets/{workspace-layout-UN6c4qTG.js → workspace-layout-BOQnl_3d.js} +1 -1
- package/static/settings/settings.html +1 -1
- package/dist/api/ai-gateway/pod/HostedPodDataAccess.d.ts +0 -31
- package/dist/api/ai-gateway/pod/HostedPodDataAccess.js +0 -330
- package/dist/http/InternalPodDataHttpHandler.d.ts +0 -57
- package/dist/http/InternalPodDataHttpHandler.js +0 -551
- package/dist/http/InternalPodDataHttpHandler.jsonld +0 -243
- package/static/auth-callback/assets/ai-connections-C6yaE6WQ.js +0 -1
- package/static/dashboard/assets/ai-connections-CXp5gd1J.js +0 -1
- package/static/settings/assets/ai-connections-C6yaE6WQ.js +0 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { createSolidLocalRouteFetch } from './local-route-fetch.js';
|
|
2
|
+
/**
|
|
3
|
+
* Pick the best route that actually answers: candidates are ordered by priority
|
|
4
|
+
* and probed in parallel, so a same-machine client lands on loopback while a
|
|
5
|
+
* remote one skips it without waiting for it to time out.
|
|
6
|
+
*/
|
|
7
|
+
export async function chooseAccessRoute(routeSet, options = {}) {
|
|
8
|
+
const candidates = usableRoutes(routeSet, options.managedClient ?? true, options.allowLocalOnlyRoutes ?? false);
|
|
9
|
+
if (candidates.length === 0) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const probe = options.probe ?? defaultProbe;
|
|
13
|
+
const timeoutMs = options.probeTimeoutMs ?? 1000;
|
|
14
|
+
const results = await Promise.all(candidates.map(async (route) => ({
|
|
15
|
+
route,
|
|
16
|
+
ok: await probeWithTimeout(route, probe, timeoutMs),
|
|
17
|
+
})));
|
|
18
|
+
return results.find((result) => result.ok)?.route ?? null;
|
|
19
|
+
}
|
|
20
|
+
export function usableRoutes(routeSet, managedClient, allowLocalOnlyRoutes) {
|
|
21
|
+
return routeSet.routes
|
|
22
|
+
.filter((route) => route.health !== 'unreachable')
|
|
23
|
+
.filter((route) => managedClient || !route.requiresManagedClient)
|
|
24
|
+
.filter((route) => allowLocalOnlyRoutes || route.visibility !== 'local-only')
|
|
25
|
+
.slice()
|
|
26
|
+
.sort((left, right) => left.priority - right.priority || left.id.localeCompare(right.id));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A fetch that keeps canonical URLs canonical while sending the request over the
|
|
30
|
+
* best route this client can use.
|
|
31
|
+
*
|
|
32
|
+
* Canonical identity is preserved end to end: the target URL is rewritten, the
|
|
33
|
+
* canonical host travels in the `x-xpod-canonical-*` headers, and the response
|
|
34
|
+
* reports its canonical URL again. When the chosen route stops answering, the
|
|
35
|
+
* routes are refreshed and the request is retried once against the new best one.
|
|
36
|
+
*/
|
|
37
|
+
export function createSolidAccessRouteFetch(options) {
|
|
38
|
+
const managedClient = options.managedClient ?? true;
|
|
39
|
+
let selected;
|
|
40
|
+
const selectRoute = async () => {
|
|
41
|
+
const routeSet = {
|
|
42
|
+
canonicalUrl: options.routes()[0]?.canonicalUrl ?? '',
|
|
43
|
+
routes: options.routes(),
|
|
44
|
+
};
|
|
45
|
+
const candidate = await chooseAccessRoute(routeSet, {
|
|
46
|
+
managedClient,
|
|
47
|
+
...(options.allowLocalOnlyRoutes === undefined
|
|
48
|
+
? {}
|
|
49
|
+
: { allowLocalOnlyRoutes: options.allowLocalOnlyRoutes }),
|
|
50
|
+
...(options.probeTimeoutMs === undefined ? {} : { probeTimeoutMs: options.probeTimeoutMs }),
|
|
51
|
+
...(options.probe === undefined ? {} : { probe: options.probe }),
|
|
52
|
+
});
|
|
53
|
+
selected = candidate ?? undefined;
|
|
54
|
+
return candidate;
|
|
55
|
+
};
|
|
56
|
+
const routeFor = async () => {
|
|
57
|
+
if (selected && options.routes().some((route) => route.id === selected?.id && route.targetUrl === selected?.targetUrl)) {
|
|
58
|
+
return selected;
|
|
59
|
+
}
|
|
60
|
+
return (await selectRoute()) ?? undefined;
|
|
61
|
+
};
|
|
62
|
+
const routedFetchFor = (route) => createSolidLocalRouteFetch({
|
|
63
|
+
fetch: options.fetch,
|
|
64
|
+
routes: () => [{
|
|
65
|
+
canonicalBaseUrl: route.canonicalUrl,
|
|
66
|
+
localBaseUrl: route.targetUrl,
|
|
67
|
+
}],
|
|
68
|
+
});
|
|
69
|
+
return async (input, init) => {
|
|
70
|
+
const route = await routeFor();
|
|
71
|
+
if (!route) {
|
|
72
|
+
return init === undefined
|
|
73
|
+
? options.fetch.call(globalThis, input)
|
|
74
|
+
: options.fetch.call(globalThis, input, init);
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
return await routedFetchFor(route)(input, init);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
// The route went away (laptop moved networks, tunnel restarted). Ask for
|
|
81
|
+
// the current set once and retry against whatever is best now.
|
|
82
|
+
selected = undefined;
|
|
83
|
+
await options.refreshRoutes?.();
|
|
84
|
+
const retryRoute = await selectRoute();
|
|
85
|
+
if (!retryRoute || retryRoute.id === route.id) {
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
return routedFetchFor(retryRoute)(input, init);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
async function probeWithTimeout(route, probe, timeoutMs) {
|
|
93
|
+
const controller = new AbortController();
|
|
94
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
95
|
+
try {
|
|
96
|
+
return await Promise.resolve(probe(route, controller.signal));
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
clearTimeout(timer);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async function defaultProbe(route, signal) {
|
|
106
|
+
if (!route.targetUrl.startsWith('http://') && !route.targetUrl.startsWith('https://')) {
|
|
107
|
+
// Non-HTTP routes (p2p sockets) report their own readiness.
|
|
108
|
+
return route.health === 'healthy';
|
|
109
|
+
}
|
|
110
|
+
const response = await fetch(new URL('/.well-known/solid', route.targetUrl), {
|
|
111
|
+
method: 'HEAD',
|
|
112
|
+
signal,
|
|
113
|
+
});
|
|
114
|
+
return response.ok || response.status === 401 || response.status === 403;
|
|
115
|
+
}
|
|
@@ -43,6 +43,7 @@ __export(exports_src, {
|
|
|
43
43
|
useSolidSessionSnapshot: () => useSolidSessionSnapshot,
|
|
44
44
|
useSolidRuntime: () => useSolidRuntime,
|
|
45
45
|
useLoginStore: () => useLoginStore,
|
|
46
|
+
usableRoutes: () => usableRoutes,
|
|
46
47
|
storageBindingMatches: () => storageBindingMatches,
|
|
47
48
|
resolveSolidLocalRouteUrl: () => resolveSolidLocalRouteUrl,
|
|
48
49
|
resolveSolidLocalRouteFromStatus: () => resolveSolidLocalRouteFromStatus,
|
|
@@ -57,8 +58,10 @@ __export(exports_src, {
|
|
|
57
58
|
createStorageSelectionState: () => createStorageSelectionState,
|
|
58
59
|
createSolidSessionRuntime: () => createSolidSessionRuntime,
|
|
59
60
|
createSolidLocalRouteFetch: () => createSolidLocalRouteFetch,
|
|
61
|
+
createSolidAccessRouteFetch: () => createSolidAccessRouteFetch,
|
|
60
62
|
createPodRuntime: () => createPodRuntime,
|
|
61
63
|
createLoginStore: () => createLoginStore,
|
|
64
|
+
chooseAccessRoute: () => chooseAccessRoute,
|
|
62
65
|
SolidRuntimeProvider: () => SolidRuntimeProvider,
|
|
63
66
|
SOLID_LOCAL_ROUTE_LOCAL_URL_HEADER: () => SOLID_LOCAL_ROUTE_LOCAL_URL_HEADER,
|
|
64
67
|
SOLID_LOCAL_ROUTE_CANONICAL_URL_HEADER: () => SOLID_LOCAL_ROUTE_CANONICAL_URL_HEADER,
|
|
@@ -1154,3 +1157,89 @@ function routedHeaders(input, init, canonicalUrl, localUrl) {
|
|
|
1154
1157
|
headers.set(SOLID_LOCAL_ROUTE_LOCAL_URL_HEADER, localUrl.toString());
|
|
1155
1158
|
return headers;
|
|
1156
1159
|
}
|
|
1160
|
+
// src/access-route.ts
|
|
1161
|
+
async function chooseAccessRoute(routeSet, options = {}) {
|
|
1162
|
+
const candidates = usableRoutes(routeSet, options.managedClient ?? true, options.allowLocalOnlyRoutes ?? false);
|
|
1163
|
+
if (candidates.length === 0) {
|
|
1164
|
+
return null;
|
|
1165
|
+
}
|
|
1166
|
+
const probe = options.probe ?? defaultProbe;
|
|
1167
|
+
const timeoutMs = options.probeTimeoutMs ?? 1000;
|
|
1168
|
+
const results = await Promise.all(candidates.map(async (route) => ({
|
|
1169
|
+
route,
|
|
1170
|
+
ok: await probeWithTimeout(route, probe, timeoutMs)
|
|
1171
|
+
})));
|
|
1172
|
+
return results.find((result) => result.ok)?.route ?? null;
|
|
1173
|
+
}
|
|
1174
|
+
function usableRoutes(routeSet, managedClient, allowLocalOnlyRoutes) {
|
|
1175
|
+
return routeSet.routes.filter((route) => route.health !== "unreachable").filter((route) => managedClient || !route.requiresManagedClient).filter((route) => allowLocalOnlyRoutes || route.visibility !== "local-only").slice().sort((left, right) => left.priority - right.priority || left.id.localeCompare(right.id));
|
|
1176
|
+
}
|
|
1177
|
+
function createSolidAccessRouteFetch(options) {
|
|
1178
|
+
const managedClient = options.managedClient ?? true;
|
|
1179
|
+
let selected;
|
|
1180
|
+
const selectRoute = async () => {
|
|
1181
|
+
const routeSet = {
|
|
1182
|
+
canonicalUrl: options.routes()[0]?.canonicalUrl ?? "",
|
|
1183
|
+
routes: options.routes()
|
|
1184
|
+
};
|
|
1185
|
+
const candidate = await chooseAccessRoute(routeSet, {
|
|
1186
|
+
managedClient,
|
|
1187
|
+
...options.allowLocalOnlyRoutes === undefined ? {} : { allowLocalOnlyRoutes: options.allowLocalOnlyRoutes },
|
|
1188
|
+
...options.probeTimeoutMs === undefined ? {} : { probeTimeoutMs: options.probeTimeoutMs },
|
|
1189
|
+
...options.probe === undefined ? {} : { probe: options.probe }
|
|
1190
|
+
});
|
|
1191
|
+
selected = candidate ?? undefined;
|
|
1192
|
+
return candidate;
|
|
1193
|
+
};
|
|
1194
|
+
const routeFor = async () => {
|
|
1195
|
+
if (selected && options.routes().some((route) => route.id === selected?.id && route.targetUrl === selected?.targetUrl)) {
|
|
1196
|
+
return selected;
|
|
1197
|
+
}
|
|
1198
|
+
return await selectRoute() ?? undefined;
|
|
1199
|
+
};
|
|
1200
|
+
const routedFetchFor = (route) => createSolidLocalRouteFetch({
|
|
1201
|
+
fetch: options.fetch,
|
|
1202
|
+
routes: () => [{
|
|
1203
|
+
canonicalBaseUrl: route.canonicalUrl,
|
|
1204
|
+
localBaseUrl: route.targetUrl
|
|
1205
|
+
}]
|
|
1206
|
+
});
|
|
1207
|
+
return async (input, init) => {
|
|
1208
|
+
const route = await routeFor();
|
|
1209
|
+
if (!route) {
|
|
1210
|
+
return init === undefined ? options.fetch.call(globalThis, input) : options.fetch.call(globalThis, input, init);
|
|
1211
|
+
}
|
|
1212
|
+
try {
|
|
1213
|
+
return await routedFetchFor(route)(input, init);
|
|
1214
|
+
} catch (error) {
|
|
1215
|
+
selected = undefined;
|
|
1216
|
+
await options.refreshRoutes?.();
|
|
1217
|
+
const retryRoute = await selectRoute();
|
|
1218
|
+
if (!retryRoute || retryRoute.id === route.id) {
|
|
1219
|
+
throw error;
|
|
1220
|
+
}
|
|
1221
|
+
return routedFetchFor(retryRoute)(input, init);
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
async function probeWithTimeout(route, probe, timeoutMs) {
|
|
1226
|
+
const controller = new AbortController;
|
|
1227
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
1228
|
+
try {
|
|
1229
|
+
return await Promise.resolve(probe(route, controller.signal));
|
|
1230
|
+
} catch {
|
|
1231
|
+
return false;
|
|
1232
|
+
} finally {
|
|
1233
|
+
clearTimeout(timer);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
async function defaultProbe(route, signal) {
|
|
1237
|
+
if (!route.targetUrl.startsWith("http://") && !route.targetUrl.startsWith("https://")) {
|
|
1238
|
+
return route.health === "healthy";
|
|
1239
|
+
}
|
|
1240
|
+
const response = await fetch(new URL("/.well-known/solid", route.targetUrl), {
|
|
1241
|
+
method: "HEAD",
|
|
1242
|
+
signal
|
|
1243
|
+
});
|
|
1244
|
+
return response.ok || response.status === 401 || response.status === 403;
|
|
1245
|
+
}
|
|
@@ -42,10 +42,15 @@
|
|
|
42
42
|
"types": "./dist/local-route-fetch.d.ts",
|
|
43
43
|
"import": "./dist/local-route-fetch.js",
|
|
44
44
|
"require": "./dist/local-route-fetch.cjs"
|
|
45
|
+
},
|
|
46
|
+
"./access-route": {
|
|
47
|
+
"types": "./dist/access-route.d.ts",
|
|
48
|
+
"import": "./dist/access-route.js",
|
|
49
|
+
"require": "./dist/access-route.cjs"
|
|
45
50
|
}
|
|
46
51
|
},
|
|
47
52
|
"scripts": {
|
|
48
|
-
"build": "rm -rf dist && tsc -p tsconfig.json && bun ../../scripts/fix-dist-js-imports.mjs dist && bun build src/index.ts --target=node --format=cjs --packages=external --outfile=dist/index.cjs && bun build src/local-route-fetch.ts --target=node --format=cjs --packages=external --outfile=dist/local-route-fetch.cjs",
|
|
53
|
+
"build": "rm -rf dist && tsc -p tsconfig.json && bun ../../scripts/fix-dist-js-imports.mjs dist && bun build src/index.ts --target=node --format=cjs --packages=external --outfile=dist/index.cjs && bun build src/local-route-fetch.ts --target=node --format=cjs --packages=external --outfile=dist/local-route-fetch.cjs && bun build src/access-route.ts --target=node --format=cjs --packages=external --outfile=dist/access-route.cjs",
|
|
49
54
|
"test": "vitest run test --config ../../vitest.packages.config.mts"
|
|
50
55
|
},
|
|
51
56
|
"dependencies": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@undefineds.co/xpod",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.15",
|
|
4
4
|
"description": "Xpod is an extended Community Solid Server, offering rich-feature, production-level Solid Pod and identity management.",
|
|
5
5
|
"repository": "https://github.com/undefinedsco/xpod",
|
|
6
6
|
"author": "developer@undefineds.co",
|
|
@@ -384,7 +384,7 @@
|
|
|
384
384
|
}
|
|
385
385
|
},
|
|
386
386
|
"optionalDependencies": {
|
|
387
|
-
"@undefineds.co/xpod-darwin-arm64": "0.4.
|
|
387
|
+
"@undefineds.co/xpod-darwin-arm64": "0.4.15"
|
|
388
388
|
},
|
|
389
389
|
"resolutions": {
|
|
390
390
|
"@inrupt/solid-client-authn-browser": "^3.1.1",
|