@undefineds.co/xpod 0.3.70 → 0.3.71-rc.13
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 +3 -0
- package/config/local.json +3 -0
- package/config/resolver.json +7 -0
- package/config/xpod.base.json +20 -0
- package/dist/agents/ClaudeExecutor.js +1 -1
- package/dist/agents/ClaudeExecutor.js.map +1 -1
- package/dist/agents/types.d.ts +5 -5
- package/dist/agents/types.js.map +1 -1
- package/dist/api/ai-gateway/AiGatewayService.d.ts +5 -16
- package/dist/api/ai-gateway/AiGatewayService.js +13 -35
- package/dist/api/ai-gateway/AiGatewayService.js.map +1 -1
- package/dist/api/ai-gateway/auth/AiConnectionInvocationKeyIssuer.d.ts +3 -2
- package/dist/api/ai-gateway/auth/AiConnectionInvocationKeyIssuer.js +37 -12
- package/dist/api/ai-gateway/auth/AiConnectionInvocationKeyIssuer.js.map +1 -1
- package/dist/api/ai-gateway/auth/GatewayPrincipal.d.ts +2 -16
- package/dist/api/ai-gateway/auth/GatewayPrincipal.js +3 -33
- package/dist/api/ai-gateway/auth/GatewayPrincipal.js.map +1 -1
- package/dist/api/ai-gateway/auth/InvocationTokenAuthenticator.d.ts +23 -0
- package/dist/api/ai-gateway/auth/InvocationTokenAuthenticator.js +81 -0
- package/dist/api/ai-gateway/auth/InvocationTokenAuthenticator.js.map +1 -0
- package/dist/api/ai-gateway/auth/InvocationTokenCodec.d.ts +7 -4
- package/dist/api/ai-gateway/auth/InvocationTokenCodec.js.map +1 -1
- package/dist/api/ai-gateway/connect/index.d.ts +7 -26
- package/dist/api/ai-gateway/connect/index.js +40 -67
- package/dist/api/ai-gateway/connect/index.js.map +1 -1
- package/dist/api/ai-gateway/credentials/PlaintextCredentialPayload.d.ts +17 -0
- package/dist/api/ai-gateway/credentials/PlaintextCredentialPayload.js +65 -0
- package/dist/api/ai-gateway/credentials/PlaintextCredentialPayload.js.map +1 -0
- package/dist/api/ai-gateway/pod/HostedPodDataAccess.d.ts +24 -0
- package/dist/api/ai-gateway/pod/HostedPodDataAccess.js +149 -0
- package/dist/api/ai-gateway/pod/HostedPodDataAccess.js.map +1 -0
- package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.d.ts +13 -5
- package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.js +16 -19
- package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.js.map +1 -1
- package/dist/api/ai-gateway/service-access/AiConnectionServiceAccess.d.ts +1 -1
- package/dist/api/ai-gateway/service-access/AiConnectionServiceAccess.js +0 -2
- package/dist/api/ai-gateway/service-access/AiConnectionServiceAccess.js.map +1 -1
- package/dist/api/auth/AuthContext.d.ts +1 -12
- package/dist/api/auth/AuthContext.js +0 -11
- package/dist/api/auth/AuthContext.js.map +1 -1
- package/dist/api/auth/ClientCredentialsAuthenticator.js +4 -11
- package/dist/api/auth/ClientCredentialsAuthenticator.js.map +1 -1
- package/dist/api/chatkit/default-agent.d.ts +2 -2
- package/dist/api/chatkit/default-agent.js +4 -4
- package/dist/api/chatkit/default-agent.js.map +1 -1
- package/dist/api/chatkit/runtime/AcpAgentRuntime.js +1 -1
- package/dist/api/chatkit/runtime/AcpAgentRuntime.js.map +1 -1
- package/dist/api/container/common.js +28 -69
- package/dist/api/container/common.js.map +1 -1
- package/dist/api/container/index.js +5 -6
- package/dist/api/container/index.js.map +1 -1
- package/dist/api/container/routes.js +2 -5
- package/dist/api/container/routes.js.map +1 -1
- package/dist/api/container/types.d.ts +8 -10
- package/dist/api/container/types.js.map +1 -1
- package/dist/api/handlers/AiClientConfigurationHandler.js +3 -3
- package/dist/api/handlers/AiClientConfigurationHandler.js.map +1 -1
- package/dist/api/handlers/AiGatewayHandler.js +2 -2
- package/dist/api/handlers/AiGatewayHandler.js.map +1 -1
- package/dist/api/handlers/AiGatewayManagementHandler.d.ts +2 -10
- package/dist/api/handlers/AiGatewayManagementHandler.js +4 -154
- package/dist/api/handlers/AiGatewayManagementHandler.js.map +1 -1
- package/dist/api/handlers/NetworkSettingsHandler.js +0 -3
- package/dist/api/handlers/NetworkSettingsHandler.js.map +1 -1
- package/dist/api/handlers/PodSettingsHandler.d.ts +5 -2
- package/dist/api/handlers/PodSettingsHandler.js +3 -3
- package/dist/api/handlers/PodSettingsHandler.js.map +1 -1
- package/dist/api/runs/AgentRuntimeTypes.d.ts +3 -3
- package/dist/api/runs/AgentRuntimeTypes.js +10 -10
- package/dist/api/runs/AgentRuntimeTypes.js.map +1 -1
- package/dist/api/runs/InngestRunExecutionBackend.d.ts +15 -9
- package/dist/api/runs/InngestRunExecutionBackend.js +25 -10
- package/dist/api/runs/InngestRunExecutionBackend.js.map +1 -1
- package/dist/api/runs/PiAgentRuntimeDriver.js +2 -2
- package/dist/api/runs/PiAgentRuntimeDriver.js.map +1 -1
- package/dist/api/runs/RunStateCenter.js +1 -1
- package/dist/api/runs/RunStateCenter.js.map +1 -1
- package/dist/api/service/AiClientConfigurationService.d.ts +2 -2
- package/dist/api/service/AiClientConfigurationService.js +11 -11
- package/dist/api/service/AiClientConfigurationService.js.map +1 -1
- package/dist/api/tasks/InngestTaskScheduler.d.ts +16 -10
- package/dist/api/tasks/InngestTaskScheduler.js +24 -12
- package/dist/api/tasks/InngestTaskScheduler.js.map +1 -1
- package/dist/cli/commands/start.js +7 -7
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/components/components.jsonld +1 -0
- package/dist/components/context.jsonld +36 -0
- package/dist/http/InternalPodDataHttpHandler.d.ts +32 -0
- package/dist/http/InternalPodDataHttpHandler.js +258 -0
- package/dist/http/InternalPodDataHttpHandler.js.map +1 -0
- package/dist/http/InternalPodDataHttpHandler.jsonld +201 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/main.js +13 -13
- package/dist/main.js.map +1 -1
- package/dist/runtime/GatewayAdminProxyAuth.d.ts +15 -1
- package/dist/runtime/GatewayAdminProxyAuth.js +57 -2
- package/dist/runtime/GatewayAdminProxyAuth.js.map +1 -1
- package/dist/runtime/bootstrap.js +3 -0
- package/dist/runtime/bootstrap.js.map +1 -1
- package/dist/runtime/css-process.d.ts +1 -1
- package/dist/runtime/css-process.js +4 -1
- package/dist/runtime/css-process.js.map +1 -1
- package/dist/runtime/runner/node/CommunitySolidServerCssRunner.d.ts +2 -0
- package/dist/runtime/runner/node/CommunitySolidServerCssRunner.js +50 -0
- package/dist/runtime/runner/node/CommunitySolidServerCssRunner.js.map +1 -1
- package/node_modules/@undefineds.co/ai-connection/dist/AiClientConfigurationSection.d.ts +5 -5
- package/node_modules/@undefineds.co/ai-connection/dist/AiClientConfigurationSection.js +7 -7
- package/node_modules/@undefineds.co/ai-connection/dist/AiConnectionMain.js +1 -1
- package/node_modules/@undefineds.co/ai-connection/dist/AiConnectionPanel.d.ts +3 -1
- package/node_modules/@undefineds.co/ai-connection/dist/AiConnectionPanel.js +74 -60
- package/node_modules/@undefineds.co/ai-connection/dist/ai-connection-client.d.ts +0 -21
- package/node_modules/@undefineds.co/ai-connection/dist/ai-connection-client.js +0 -41
- package/node_modules/@undefineds.co/ai-connection/dist/client-config/base-adapter.d.ts +1 -0
- package/node_modules/@undefineds.co/ai-connection/dist/client-config/base-adapter.js +7 -2
- package/node_modules/@undefineds.co/ai-connection/dist/client-config/codex.js +3 -3
- package/node_modules/@undefineds.co/ai-connection/dist/client-config/index.cjs +15 -9
- package/node_modules/@undefineds.co/ai-connection/dist/client-config/json-env-adapter.js +4 -4
- package/node_modules/@undefineds.co/ai-connection/dist/client-config/pi.js +3 -3
- package/node_modules/@undefineds.co/ai-connection/dist/client-config/types.d.ts +1 -1
- package/node_modules/@undefineds.co/ai-connection/dist/controller.d.ts +2 -1
- package/node_modules/@undefineds.co/ai-connection/dist/controller.js +1 -0
- package/node_modules/@undefineds.co/ai-connection/dist/service-access.js +0 -1
- package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +22 -1
- package/package.json +3 -3
- package/static/app/assets/main.js +7 -7
- package/static/dashboard/assets/NetworkPage-CXjiUMR1.js +2 -0
- package/static/dashboard/assets/{PaneListHeader-57nvMwH6.js → PaneListHeader-BSipfl0W.js} +1 -1
- package/static/dashboard/assets/PodPage-Bd3Xhmp-.js +2 -0
- package/static/dashboard/assets/ServicesPage-CI3jWZGe.js +1 -0
- package/static/dashboard/assets/{card-B9Zjf_2p.js → card-z5BV5hTo.js} +1 -1
- package/static/dashboard/assets/{dashboard-8C6o666W.js → dashboard-CSrqAv2L.js} +2 -2
- package/static/dashboard/assets/{database-DPh9wDY9.js → database-Ct5ZPe6L.js} +1 -1
- package/static/dashboard/assets/{external-link-VbMQvVMz.js → external-link-B7wD1hkm.js} +1 -1
- package/static/dashboard/assets/index-tOBaUnM1.js +44 -0
- package/static/dashboard/assets/{refresh-cw-BxVxNxNr.js → refresh-cw-CFDZPaE8.js} +1 -1
- package/static/dashboard/assets/{services-status-context-DKmJ7ISr.js → services-status-context-DN1Icg4A.js} +1 -1
- package/static/dashboard/dashboard.html +1 -1
- package/static/settings/assets/ModelsPage-03NPWzoX.js +1 -0
- package/static/settings/assets/{PaneListHeader-Bgaze006.js → PaneListHeader-DMD8OJef.js} +1 -1
- package/static/settings/assets/PodPage-DT4EMYhL.js +2 -0
- package/static/settings/assets/ServicesPage-CJ0ub6IH.js +1 -0
- package/static/settings/assets/SettingsPage-BkR7ZK18.js +41 -0
- package/static/settings/assets/{card-B_bXSIn-.js → card-Cjsia0_V.js} +1 -1
- package/static/settings/assets/{services-status-context-DiX-AbrP.js → services-status-context-CkuKmH5h.js} +1 -1
- package/static/settings/assets/{settings-B30oMfZq.js → settings-Cyyv6-SD.js} +2 -2
- package/static/settings/assets/{workspace-layout-Dv1Yn9Ci.js → workspace-layout-B47luv6r.js} +1 -1
- package/static/settings/settings.html +1 -1
- package/dist/api/ai-gateway/auth/ClientCredentialsInternalPodAccessTokenProvider.d.ts +0 -25
- package/dist/api/ai-gateway/auth/ClientCredentialsInternalPodAccessTokenProvider.js +0 -91
- package/dist/api/ai-gateway/auth/ClientCredentialsInternalPodAccessTokenProvider.js.map +0 -1
- 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/GatewayApiKey.js.map +0 -1
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.d.ts +0 -56
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js +0 -143
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js.map +0 -1
- 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/GatewayKeyLocatorCodec.js.map +0 -1
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.d.ts +0 -54
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js +0 -152
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js.map +0 -1
- package/static/dashboard/assets/NetworkPage-Brt79fuQ.js +0 -2
- package/static/dashboard/assets/PodPage-CM6do1vB.js +0 -2
- package/static/dashboard/assets/ServicesPage-BUNxGJRz.js +0 -1
- package/static/dashboard/assets/index-RfiFckzb.js +0 -51
- package/static/settings/assets/ModelsPage-D_IH7AH3.js +0 -1
- package/static/settings/assets/PodPage-Cy1VNObw.js +0 -2
- package/static/settings/assets/ServicesPage-BsFaxVWC.js +0 -1
- package/static/settings/assets/SettingsPage-UafNWE_p.js +0 -48
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HostedPodDataAccess = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const node_net_1 = require("node:net");
|
|
6
|
+
const AiConnectionServiceAccess_1 = require("../service-access/AiConnectionServiceAccess");
|
|
7
|
+
const GatewayAdminProxyAuth_1 = require("../../../runtime/GatewayAdminProxyAuth");
|
|
8
|
+
const INTERNAL_POD_DATA_PATH = '/.internal/pod-data';
|
|
9
|
+
const STRIPPED_CALLER_HEADERS = new Set([
|
|
10
|
+
'authorization',
|
|
11
|
+
'dpop',
|
|
12
|
+
'cookie',
|
|
13
|
+
]);
|
|
14
|
+
class HostedPodDataAccess {
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.cssBaseUrl = new URL(options.cssBaseUrl);
|
|
17
|
+
if (!isLoopbackHostname(this.cssBaseUrl.hostname)) {
|
|
18
|
+
throw new Error('hosted_pod_css_loopback_required');
|
|
19
|
+
}
|
|
20
|
+
this.gatewayAdminProxyAuthSecret = options.gatewayAdminProxyAuthSecret ?? process.env.XPOD_GATEWAY_ADMIN_PROXY_AUTH_SECRET;
|
|
21
|
+
this.fetch = options.fetch ?? fetch;
|
|
22
|
+
this.now = options.now ?? Date.now;
|
|
23
|
+
this.nonce = options.nonce ?? node_crypto_1.randomUUID;
|
|
24
|
+
}
|
|
25
|
+
async getTrustedFetch(owner, auth) {
|
|
26
|
+
return async (input, init) => {
|
|
27
|
+
const request = new Request(input, init);
|
|
28
|
+
const method = normalizeMethod(request.method);
|
|
29
|
+
const resourceUrl = normalizeResourceUrl(request.url);
|
|
30
|
+
const authorization = this.authorize({ owner, auth, method, resourceUrl });
|
|
31
|
+
const loopbackUrl = new URL(INTERNAL_POD_DATA_PATH, this.cssBaseUrl);
|
|
32
|
+
const headers = this.headersForLoopback(request.headers, {
|
|
33
|
+
ownerWebId: owner,
|
|
34
|
+
method,
|
|
35
|
+
resourceUrl,
|
|
36
|
+
principalKind: authorization.principalKind,
|
|
37
|
+
scopes: [method === 'GET' ? 'ai:credentials:read' : 'ai:credentials:write'],
|
|
38
|
+
});
|
|
39
|
+
return this.fetch(loopbackUrl, {
|
|
40
|
+
method,
|
|
41
|
+
headers,
|
|
42
|
+
body: request.body,
|
|
43
|
+
signal: init?.signal ?? request.signal,
|
|
44
|
+
...(request.body ? { duplex: 'half' } : {}),
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
authorize(input) {
|
|
49
|
+
this.assertHostedAllowedResource(input.owner, input.resourceUrl);
|
|
50
|
+
if (!input.auth) {
|
|
51
|
+
throw new Error('hosted_pod_auth_required');
|
|
52
|
+
}
|
|
53
|
+
if (input.auth.type !== 'solid') {
|
|
54
|
+
throw new Error('hosted_pod_solid_principal_required');
|
|
55
|
+
}
|
|
56
|
+
if (input.auth.webId !== input.owner) {
|
|
57
|
+
throw new Error('hosted_pod_owner_mismatch');
|
|
58
|
+
}
|
|
59
|
+
return { principalKind: 'solid-user' };
|
|
60
|
+
}
|
|
61
|
+
assertHostedAllowedResource(owner, resourceUrl) {
|
|
62
|
+
const resource = parseUrl(resourceUrl, 'hosted_pod_resource_url_invalid');
|
|
63
|
+
const ownerUrl = parseUrl(owner, 'hosted_pod_owner_url_invalid');
|
|
64
|
+
const podRoot = hostedPodRootFromOwner(ownerUrl);
|
|
65
|
+
if (!podRoot || resource.origin !== podRoot.origin || !resource.pathname.startsWith(podRoot.pathname)) {
|
|
66
|
+
throw new Error('hosted_pod_remote_resource');
|
|
67
|
+
}
|
|
68
|
+
if (resource.hash || resource.search) {
|
|
69
|
+
throw new Error('hosted_pod_resource_not_allowed');
|
|
70
|
+
}
|
|
71
|
+
const allowed = (0, AiConnectionServiceAccess_1.createAiConnectionServiceAccess)({
|
|
72
|
+
ownerWebId: owner,
|
|
73
|
+
serviceWebId: owner,
|
|
74
|
+
}).resources.map((entry) => entry.url);
|
|
75
|
+
if (!allowed.includes(resource.href)) {
|
|
76
|
+
throw new Error('hosted_pod_resource_not_allowed');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
headersForLoopback(headers, intent) {
|
|
80
|
+
const next = new Headers();
|
|
81
|
+
headers.forEach((value, key) => {
|
|
82
|
+
const normalized = key.toLowerCase();
|
|
83
|
+
if (STRIPPED_CALLER_HEADERS.has(normalized)
|
|
84
|
+
|| GatewayAdminProxyAuth_1.GATEWAY_ADMIN_PROXY_HEADERS.includes(normalized)
|
|
85
|
+
|| normalized.startsWith('x-xpod-admin-proxy-')) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
next.set(key, value);
|
|
89
|
+
});
|
|
90
|
+
if (!this.gatewayAdminProxyAuthSecret) {
|
|
91
|
+
throw new Error('XPOD_GATEWAY_ADMIN_PROXY_AUTH_SECRET is required for hosted Pod data access');
|
|
92
|
+
}
|
|
93
|
+
const marker = (0, GatewayAdminProxyAuth_1.createGatewayAdminProxyHeaders)({
|
|
94
|
+
secret: this.gatewayAdminProxyAuthSecret,
|
|
95
|
+
method: intent.method,
|
|
96
|
+
url: INTERNAL_POD_DATA_PATH,
|
|
97
|
+
originalClientLoopback: true,
|
|
98
|
+
issuedAt: this.now(),
|
|
99
|
+
nonce: this.nonce(),
|
|
100
|
+
intent,
|
|
101
|
+
});
|
|
102
|
+
for (const [key, value] of Object.entries(marker)) {
|
|
103
|
+
if (value !== undefined) {
|
|
104
|
+
next.set(key, Array.isArray(value) ? value.join(', ') : String(value));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return next;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.HostedPodDataAccess = HostedPodDataAccess;
|
|
111
|
+
function normalizeMethod(method) {
|
|
112
|
+
const upper = (method ?? 'GET').toUpperCase();
|
|
113
|
+
if (upper === 'GET' || upper === 'PUT' || upper === 'PATCH' || upper === 'DELETE') {
|
|
114
|
+
return upper;
|
|
115
|
+
}
|
|
116
|
+
throw new Error('hosted_pod_method_not_allowed');
|
|
117
|
+
}
|
|
118
|
+
function normalizeResourceUrl(value) {
|
|
119
|
+
return new URL(value).href;
|
|
120
|
+
}
|
|
121
|
+
function parseUrl(value, errorCode) {
|
|
122
|
+
try {
|
|
123
|
+
return new URL(value);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
throw new Error(errorCode);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function hostedPodRootFromOwner(ownerUrl) {
|
|
130
|
+
if (ownerUrl.hash !== '#me' || !ownerUrl.pathname.endsWith('/profile/card')) {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
const podPath = ownerUrl.pathname.slice(0, -'profile/card'.length);
|
|
134
|
+
if (!podPath || !podPath.endsWith('/')) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
return new URL(podPath, ownerUrl.origin);
|
|
138
|
+
}
|
|
139
|
+
function isLoopbackHostname(hostname) {
|
|
140
|
+
const normalized = hostname.replace(/^\[|\]$/gu, '').toLowerCase();
|
|
141
|
+
if (normalized === 'localhost') {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
if ((0, node_net_1.isIP)(normalized) === 4) {
|
|
145
|
+
return normalized.startsWith('127.');
|
|
146
|
+
}
|
|
147
|
+
return normalized === '::1';
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=HostedPodDataAccess.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HostedPodDataAccess.js","sourceRoot":"","sources":["../../../../src/api/ai-gateway/pod/HostedPodDataAccess.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { isIP } from 'node:net';\nimport { createAiConnectionServiceAccess } from '../service-access/AiConnectionServiceAccess';\nimport type { AuthContext, SolidAuthContext } from '../../auth/AuthContext';\nimport {\n createGatewayAdminProxyHeaders,\n GATEWAY_ADMIN_PROXY_HEADERS,\n type GatewayAdminProxyIntent,\n} from '../../../runtime/GatewayAdminProxyAuth';\n\nexport interface InternalPodAccessTokenProvider {\n getTrustedFetch(owner: string, auth?: InternalPodAccessAuthContext): Promise<typeof fetch | undefined>;\n}\n\nexport type InternalPodAccessAuthContext = AuthContext | undefined;\n\nexport interface HostedPodDataAccessOptions {\n cssBaseUrl: string;\n gatewayAdminProxyAuthSecret?: string;\n fetch?: typeof fetch;\n now?: () => number;\n nonce?: () => string;\n}\n\ntype InternalPodDataMethod = 'GET' | 'PUT' | 'PATCH' | 'DELETE';\n\nconst INTERNAL_POD_DATA_PATH = '/.internal/pod-data';\nconst STRIPPED_CALLER_HEADERS = new Set([\n 'authorization',\n 'dpop',\n 'cookie',\n]);\n\nexport class HostedPodDataAccess implements InternalPodAccessTokenProvider {\n private readonly cssBaseUrl: URL;\n private readonly gatewayAdminProxyAuthSecret?: string;\n private readonly fetch: typeof fetch;\n private readonly now: () => number;\n private readonly nonce: () => string;\n\n public constructor(options: HostedPodDataAccessOptions) {\n this.cssBaseUrl = new URL(options.cssBaseUrl);\n if (!isLoopbackHostname(this.cssBaseUrl.hostname)) {\n throw new Error('hosted_pod_css_loopback_required');\n }\n this.gatewayAdminProxyAuthSecret = options.gatewayAdminProxyAuthSecret ?? process.env.XPOD_GATEWAY_ADMIN_PROXY_AUTH_SECRET;\n this.fetch = options.fetch ?? fetch;\n this.now = options.now ?? Date.now;\n this.nonce = options.nonce ?? randomUUID;\n }\n\n public async getTrustedFetch(owner: string, auth?: InternalPodAccessAuthContext): Promise<typeof fetch | undefined> {\n return async (input, init) => {\n const request = new Request(input, init);\n const method = normalizeMethod(request.method);\n const resourceUrl = normalizeResourceUrl(request.url);\n const authorization = this.authorize({ owner, auth, method, resourceUrl });\n const loopbackUrl = new URL(INTERNAL_POD_DATA_PATH, this.cssBaseUrl);\n const headers = this.headersForLoopback(request.headers, {\n ownerWebId: owner,\n method,\n resourceUrl,\n principalKind: authorization.principalKind,\n scopes: [method === 'GET' ? 'ai:credentials:read' : 'ai:credentials:write'],\n });\n\n return this.fetch(loopbackUrl, {\n method,\n headers,\n body: request.body,\n signal: init?.signal ?? request.signal,\n ...(request.body ? { duplex: 'half' } : {}),\n } as RequestInit);\n };\n }\n\n private authorize(input: {\n owner: string;\n auth?: InternalPodAccessAuthContext;\n method: InternalPodDataMethod;\n resourceUrl: string;\n }): { principalKind: GatewayAdminProxyIntent['principalKind'] } {\n this.assertHostedAllowedResource(input.owner, input.resourceUrl);\n\n if (!input.auth) {\n throw new Error('hosted_pod_auth_required');\n }\n if (input.auth.type !== 'solid') {\n throw new Error('hosted_pod_solid_principal_required');\n }\n if (input.auth.webId !== input.owner) {\n throw new Error('hosted_pod_owner_mismatch');\n }\n return { principalKind: 'solid-user' };\n }\n\n private assertHostedAllowedResource(owner: string, resourceUrl: string): void {\n const resource = parseUrl(resourceUrl, 'hosted_pod_resource_url_invalid');\n const ownerUrl = parseUrl(owner, 'hosted_pod_owner_url_invalid');\n const podRoot = hostedPodRootFromOwner(ownerUrl);\n if (!podRoot || resource.origin !== podRoot.origin || !resource.pathname.startsWith(podRoot.pathname)) {\n throw new Error('hosted_pod_remote_resource');\n }\n if (resource.hash || resource.search) {\n throw new Error('hosted_pod_resource_not_allowed');\n }\n\n const allowed = createAiConnectionServiceAccess({\n ownerWebId: owner,\n serviceWebId: owner,\n }).resources.map((entry) => entry.url);\n if (!allowed.includes(resource.href)) {\n throw new Error('hosted_pod_resource_not_allowed');\n }\n }\n\n private headersForLoopback(headers: Headers, intent: GatewayAdminProxyIntent): Headers {\n const next = new Headers();\n headers.forEach((value, key) => {\n const normalized = key.toLowerCase();\n if (\n STRIPPED_CALLER_HEADERS.has(normalized)\n || GATEWAY_ADMIN_PROXY_HEADERS.includes(normalized as typeof GATEWAY_ADMIN_PROXY_HEADERS[number])\n || normalized.startsWith('x-xpod-admin-proxy-')\n ) {\n return;\n }\n next.set(key, value);\n });\n\n if (!this.gatewayAdminProxyAuthSecret) {\n throw new Error('XPOD_GATEWAY_ADMIN_PROXY_AUTH_SECRET is required for hosted Pod data access');\n }\n const marker = createGatewayAdminProxyHeaders({\n secret: this.gatewayAdminProxyAuthSecret,\n method: intent.method,\n url: INTERNAL_POD_DATA_PATH,\n originalClientLoopback: true,\n issuedAt: this.now(),\n nonce: this.nonce(),\n intent,\n });\n for (const [key, value] of Object.entries(marker)) {\n if (value !== undefined) {\n next.set(key, Array.isArray(value) ? value.join(', ') : String(value));\n }\n }\n return next;\n }\n}\n\nfunction normalizeMethod(method: string | undefined): InternalPodDataMethod {\n const upper = (method ?? 'GET').toUpperCase();\n if (upper === 'GET' || upper === 'PUT' || upper === 'PATCH' || upper === 'DELETE') {\n return upper;\n }\n throw new Error('hosted_pod_method_not_allowed');\n}\n\nfunction normalizeResourceUrl(value: string): string {\n return new URL(value).href;\n}\n\nfunction parseUrl(value: string, errorCode: string): URL {\n try {\n return new URL(value);\n } catch {\n throw new Error(errorCode);\n }\n}\n\nfunction hostedPodRootFromOwner(ownerUrl: URL): URL | undefined {\n if (ownerUrl.hash !== '#me' || !ownerUrl.pathname.endsWith('/profile/card')) {\n return undefined;\n }\n const podPath = ownerUrl.pathname.slice(0, -'profile/card'.length);\n if (!podPath || !podPath.endsWith('/')) {\n return undefined;\n }\n return new URL(podPath, ownerUrl.origin);\n}\n\nfunction isLoopbackHostname(hostname: string): boolean {\n const normalized = hostname.replace(/^\\[|\\]$/gu, '').toLowerCase();\n if (normalized === 'localhost') {\n return true;\n }\n if (isIP(normalized) === 4) {\n return normalized.startsWith('127.');\n }\n return normalized === '::1';\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { quotaSnapshotResource, type QuotaSnapshotRow } from '@undefineds.co/models';
|
|
2
2
|
import type { AuthContext } from '../../auth/AuthContext';
|
|
3
|
-
import type { GatewayDeployment } from '../auth/
|
|
4
|
-
import type { InternalPodAccessTokenProvider } from '../
|
|
3
|
+
import type { GatewayDeployment } from '../auth/InvocationTokenCodec';
|
|
4
|
+
import type { InternalPodAccessTokenProvider } from '../pod/HostedPodDataAccess';
|
|
5
5
|
import type { ConnectCredentialRecord, PodCredentialRepository } from '../connect';
|
|
6
|
-
import type {
|
|
6
|
+
import type { ProviderSecret } from '../credentials/CredentialVault';
|
|
7
7
|
export type QuotaSnapshotStatus = 'available' | 'unsupported' | 'error';
|
|
8
8
|
export interface QuotaWindow {
|
|
9
9
|
name: string;
|
|
@@ -49,18 +49,21 @@ export interface QuotaSnapshotRepository {
|
|
|
49
49
|
provider: string;
|
|
50
50
|
credentialIri: string;
|
|
51
51
|
now: Date;
|
|
52
|
+
auth?: AuthContext;
|
|
52
53
|
}): Promise<NormalizedQuotaSnapshot | undefined>;
|
|
53
54
|
findLatest(input: {
|
|
54
55
|
webId: string;
|
|
55
56
|
deployment: GatewayDeployment;
|
|
56
57
|
provider: string;
|
|
57
58
|
credentialIri: string;
|
|
59
|
+
auth?: AuthContext;
|
|
58
60
|
}): Promise<NormalizedQuotaSnapshot | undefined>;
|
|
59
61
|
upsert(input: {
|
|
60
62
|
webId: string;
|
|
61
63
|
deployment: GatewayDeployment;
|
|
62
64
|
provider: string;
|
|
63
65
|
snapshot: NormalizedQuotaSnapshot;
|
|
66
|
+
auth?: AuthContext;
|
|
64
67
|
}): Promise<NormalizedQuotaSnapshot>;
|
|
65
68
|
}
|
|
66
69
|
export interface ProviderQuotaStatusInput {
|
|
@@ -71,10 +74,10 @@ export interface ProviderQuotaStatusInput {
|
|
|
71
74
|
refresh?: boolean;
|
|
72
75
|
now?: Date;
|
|
73
76
|
signal?: AbortSignal;
|
|
77
|
+
auth?: AuthContext;
|
|
74
78
|
}
|
|
75
79
|
export interface ProviderQuotaServiceOptions {
|
|
76
80
|
repository: QuotaSnapshotRepository;
|
|
77
|
-
vault: CredentialVault;
|
|
78
81
|
adapters: ProviderQuotaAdapter[];
|
|
79
82
|
credentialRepository?: PodCredentialRepository;
|
|
80
83
|
credentials?: QuotaCredentialRecord[];
|
|
@@ -82,7 +85,6 @@ export interface ProviderQuotaServiceOptions {
|
|
|
82
85
|
}
|
|
83
86
|
export declare class ProviderQuotaService {
|
|
84
87
|
private readonly repository;
|
|
85
|
-
private readonly vault;
|
|
86
88
|
private readonly adapters;
|
|
87
89
|
private readonly credentialRepository?;
|
|
88
90
|
private readonly credentials;
|
|
@@ -107,18 +109,21 @@ export declare class InMemoryQuotaSnapshotRepository implements QuotaSnapshotRep
|
|
|
107
109
|
provider: string;
|
|
108
110
|
credentialIri: string;
|
|
109
111
|
now: Date;
|
|
112
|
+
auth?: AuthContext;
|
|
110
113
|
}): Promise<NormalizedQuotaSnapshot | undefined>;
|
|
111
114
|
findLatest(input: {
|
|
112
115
|
webId: string;
|
|
113
116
|
deployment: GatewayDeployment;
|
|
114
117
|
provider: string;
|
|
115
118
|
credentialIri: string;
|
|
119
|
+
auth?: AuthContext;
|
|
116
120
|
}): Promise<NormalizedQuotaSnapshot | undefined>;
|
|
117
121
|
upsert(input: {
|
|
118
122
|
webId: string;
|
|
119
123
|
deployment: GatewayDeployment;
|
|
120
124
|
provider: string;
|
|
121
125
|
snapshot: NormalizedQuotaSnapshot;
|
|
126
|
+
auth?: AuthContext;
|
|
122
127
|
}): Promise<NormalizedQuotaSnapshot>;
|
|
123
128
|
}
|
|
124
129
|
type QuotaSnapshotDb = {
|
|
@@ -158,18 +163,21 @@ export declare class PodQuotaSnapshotRepository implements QuotaSnapshotReposito
|
|
|
158
163
|
provider: string;
|
|
159
164
|
credentialIri: string;
|
|
160
165
|
now: Date;
|
|
166
|
+
auth?: AuthContext;
|
|
161
167
|
}): Promise<NormalizedQuotaSnapshot | undefined>;
|
|
162
168
|
findLatest(input: {
|
|
163
169
|
webId: string;
|
|
164
170
|
deployment: GatewayDeployment;
|
|
165
171
|
provider: string;
|
|
166
172
|
credentialIri: string;
|
|
173
|
+
auth?: AuthContext;
|
|
167
174
|
}): Promise<NormalizedQuotaSnapshot | undefined>;
|
|
168
175
|
upsert(input: {
|
|
169
176
|
webId: string;
|
|
170
177
|
deployment: GatewayDeployment;
|
|
171
178
|
provider: string;
|
|
172
179
|
snapshot: NormalizedQuotaSnapshot;
|
|
180
|
+
auth?: AuthContext;
|
|
173
181
|
}): Promise<NormalizedQuotaSnapshot>;
|
|
174
182
|
private dbForOwner;
|
|
175
183
|
private resolveTrustedFetch;
|
|
@@ -10,12 +10,12 @@ exports.decimalAmount = decimalAmount;
|
|
|
10
10
|
exports.normalizeProvider = normalizeProvider;
|
|
11
11
|
const drizzle_solid_1 = require("@undefineds.co/drizzle-solid");
|
|
12
12
|
const models_1 = require("@undefineds.co/models");
|
|
13
|
+
const PlaintextCredentialPayload_1 = require("../credentials/PlaintextCredentialPayload");
|
|
13
14
|
class ProviderQuotaService {
|
|
14
15
|
constructor(options) {
|
|
15
16
|
this.adapters = new Map();
|
|
16
17
|
this.inFlightRefreshes = new Map();
|
|
17
18
|
this.repository = options.repository;
|
|
18
|
-
this.vault = options.vault;
|
|
19
19
|
this.credentialRepository = options.credentialRepository;
|
|
20
20
|
this.credentials = options.credentials ?? [];
|
|
21
21
|
this.now = options.now ?? (() => new Date());
|
|
@@ -55,6 +55,7 @@ class ProviderQuotaService {
|
|
|
55
55
|
deployment: input.deployment,
|
|
56
56
|
provider,
|
|
57
57
|
credentialIri: input.credentialIri,
|
|
58
|
+
auth: input.auth,
|
|
58
59
|
});
|
|
59
60
|
if (!input.refresh) {
|
|
60
61
|
const cached = await this.repository.findFresh({
|
|
@@ -63,6 +64,7 @@ class ProviderQuotaService {
|
|
|
63
64
|
provider,
|
|
64
65
|
credentialIri: credential.credentialIri,
|
|
65
66
|
now,
|
|
67
|
+
auth: input.auth,
|
|
66
68
|
});
|
|
67
69
|
if (cached) {
|
|
68
70
|
return { ...cached, stale: false };
|
|
@@ -72,6 +74,7 @@ class ProviderQuotaService {
|
|
|
72
74
|
deployment: input.deployment,
|
|
73
75
|
provider,
|
|
74
76
|
credentialIri: credential.credentialIri,
|
|
77
|
+
auth: input.auth,
|
|
75
78
|
});
|
|
76
79
|
if (latest) {
|
|
77
80
|
return { ...latest, stale: true };
|
|
@@ -99,6 +102,7 @@ class ProviderQuotaService {
|
|
|
99
102
|
adapter,
|
|
100
103
|
now,
|
|
101
104
|
signal: input.signal,
|
|
105
|
+
auth: input.auth,
|
|
102
106
|
}).finally(() => {
|
|
103
107
|
this.inFlightRefreshes.delete(refreshKey);
|
|
104
108
|
});
|
|
@@ -111,6 +115,7 @@ class ProviderQuotaService {
|
|
|
111
115
|
deployment: input.input.deployment,
|
|
112
116
|
provider: input.provider,
|
|
113
117
|
credentialIri: input.input.credentialIri,
|
|
118
|
+
auth: input.input.auth,
|
|
114
119
|
});
|
|
115
120
|
const adapter = this.adapters.get(input.provider);
|
|
116
121
|
if (!adapter) {
|
|
@@ -124,21 +129,11 @@ class ProviderQuotaService {
|
|
|
124
129
|
adapter,
|
|
125
130
|
now: input.now,
|
|
126
131
|
signal: input.input.signal,
|
|
132
|
+
auth: input.input.auth,
|
|
127
133
|
});
|
|
128
134
|
}
|
|
129
135
|
async fetchAndCache(input) {
|
|
130
|
-
const secret =
|
|
131
|
-
if (this.vault.needsRewrap?.(input.credential.encryptedSecret)
|
|
132
|
-
&& this.credentialRepository?.rewrapCredential) {
|
|
133
|
-
const rewrapped = await this.vault.rewrap({ webId: input.webId }, input.credential.encryptedSecret);
|
|
134
|
-
await this.credentialRepository.rewrapCredential({
|
|
135
|
-
webId: input.webId,
|
|
136
|
-
deployment: input.deployment,
|
|
137
|
-
credentialId: input.credential.id,
|
|
138
|
-
expectedVersion: input.credential.version,
|
|
139
|
-
encryptedSecret: rewrapped,
|
|
140
|
-
});
|
|
141
|
-
}
|
|
136
|
+
const secret = (0, PlaintextCredentialPayload_1.decodePlaintextCredential)(input.credential);
|
|
142
137
|
let snapshot;
|
|
143
138
|
try {
|
|
144
139
|
snapshot = await input.adapter.fetch({
|
|
@@ -164,6 +159,7 @@ class ProviderQuotaService {
|
|
|
164
159
|
deployment: input.deployment,
|
|
165
160
|
provider: input.provider,
|
|
166
161
|
snapshot,
|
|
162
|
+
auth: input.auth,
|
|
167
163
|
});
|
|
168
164
|
}
|
|
169
165
|
async resolveCredential(input) {
|
|
@@ -178,6 +174,7 @@ class ProviderQuotaService {
|
|
|
178
174
|
webId: input.webId,
|
|
179
175
|
deployment: input.deployment,
|
|
180
176
|
provider: input.provider,
|
|
177
|
+
auth: input.auth,
|
|
181
178
|
});
|
|
182
179
|
if (active
|
|
183
180
|
&& (!input.credentialIri || active.credentialIri === input.credentialIri)) {
|
|
@@ -239,7 +236,7 @@ class PodQuotaSnapshotRepository {
|
|
|
239
236
|
this.dbFactory = options.dbFactory ?? createDefaultQuotaSnapshotDb;
|
|
240
237
|
}
|
|
241
238
|
async findFresh(input) {
|
|
242
|
-
const db = await this.dbForOwner(input.webId);
|
|
239
|
+
const db = await this.dbForOwner(input.webId, input.auth);
|
|
243
240
|
const row = await models_1.aiGatewayRepository.findFreshQuotaSnapshot(db, {
|
|
244
241
|
owner: input.webId,
|
|
245
242
|
deployment: input.deployment,
|
|
@@ -250,7 +247,7 @@ class PodQuotaSnapshotRepository {
|
|
|
250
247
|
return row ? snapshotFromRow(row, false) : undefined;
|
|
251
248
|
}
|
|
252
249
|
async findLatest(input) {
|
|
253
|
-
const db = await this.dbForOwner(input.webId);
|
|
250
|
+
const db = await this.dbForOwner(input.webId, input.auth);
|
|
254
251
|
const row = await models_1.aiGatewayRepository.findLatestQuotaSnapshot(db, {
|
|
255
252
|
owner: input.webId,
|
|
256
253
|
deployment: input.deployment,
|
|
@@ -260,7 +257,7 @@ class PodQuotaSnapshotRepository {
|
|
|
260
257
|
return row ? snapshotFromRow(row, true) : undefined;
|
|
261
258
|
}
|
|
262
259
|
async upsert(input) {
|
|
263
|
-
const db = await this.dbForOwner(input.webId);
|
|
260
|
+
const db = await this.dbForOwner(input.webId, input.auth);
|
|
264
261
|
const snapshot = sanitizeSnapshot({
|
|
265
262
|
...input.snapshot,
|
|
266
263
|
id: input.snapshot.id ?? (0, models_1.quotaSnapshotId)({
|
|
@@ -286,13 +283,13 @@ class PodQuotaSnapshotRepository {
|
|
|
286
283
|
return { ...snapshot, stale: false };
|
|
287
284
|
}
|
|
288
285
|
async dbForOwner(owner, auth) {
|
|
289
|
-
const trustedFetch = await this.resolveTrustedFetch(owner);
|
|
286
|
+
const trustedFetch = await this.resolveTrustedFetch(owner, auth);
|
|
290
287
|
const db = await this.dbFactory({ owner, auth, fetch: trustedFetch });
|
|
291
288
|
await db.init?.(models_1.quotaSnapshotResource);
|
|
292
289
|
return db;
|
|
293
290
|
}
|
|
294
|
-
async resolveTrustedFetch(owner) {
|
|
295
|
-
const trustedFetch = await this.internalPodAccess?.getTrustedFetch(owner);
|
|
291
|
+
async resolveTrustedFetch(owner, auth) {
|
|
292
|
+
const trustedFetch = await this.internalPodAccess?.getTrustedFetch(owner, auth);
|
|
296
293
|
if (!trustedFetch) {
|
|
297
294
|
throw new Error('AI Connection service identity is not configured');
|
|
298
295
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProviderQuotaAdapter.js","sourceRoot":"","sources":["../../../../src/api/ai-gateway/quota/ProviderQuotaAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { drizzle } from '@undefineds.co/drizzle-solid';\nimport {\n aiGatewayRepository,\n quotaSnapshotId as buildQuotaSnapshotId,\n quotaSnapshotResource,\n type QuotaSnapshotRow,\n} from '@undefineds.co/models';\nimport type { AuthContext } from '../../auth/AuthContext';\nimport type { GatewayDeployment } from '../auth/GatewayApiKey';\nimport type { InternalPodAccessTokenProvider } from '../auth/PodGatewayAccessKeyRepository';\nimport type { ConnectCredentialRecord, PodCredentialRepository } from '../connect';\nimport type { CredentialVault, ProviderSecret } from '../credentials/CredentialVault';\n\nexport type QuotaSnapshotStatus = 'available' | 'unsupported' | 'error';\n\nexport interface QuotaWindow {\n name: string;\n used?: number;\n usedExact?: string;\n limit?: number;\n limitExact?: string;\n remaining?: number;\n remainingExact?: string;\n displayApprox?: boolean;\n currency?: string;\n resetsAt?: string;\n}\n\nexport interface NormalizedQuotaSnapshot {\n id?: string;\n credential: string;\n status: QuotaSnapshotStatus;\n balance?: number;\n windows: QuotaWindow[];\n observedAt: string;\n expiresAt: string;\n source: string;\n stale?: boolean;\n metadata?: Record<string, unknown>;\n}\n\nexport interface QuotaCredentialRecord extends ConnectCredentialRecord {\n baseUrl?: string;\n}\n\nexport interface ProviderQuotaFetchInput {\n credential: QuotaCredentialRecord;\n secret: ProviderSecret;\n now: Date;\n signal?: AbortSignal;\n}\n\nexport interface ProviderQuotaAdapter {\n readonly provider: string;\n fetch(input: ProviderQuotaFetchInput): Promise<NormalizedQuotaSnapshot>;\n}\n\nexport interface QuotaSnapshotRepository {\n findFresh(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n now: Date;\n }): Promise<NormalizedQuotaSnapshot | undefined>;\n findLatest(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n }): Promise<NormalizedQuotaSnapshot | undefined>;\n upsert(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n snapshot: NormalizedQuotaSnapshot;\n }): Promise<NormalizedQuotaSnapshot>;\n}\n\nexport interface ProviderQuotaStatusInput {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri?: string;\n refresh?: boolean;\n now?: Date;\n signal?: AbortSignal;\n}\n\nexport interface ProviderQuotaServiceOptions {\n repository: QuotaSnapshotRepository;\n vault: CredentialVault;\n adapters: ProviderQuotaAdapter[];\n credentialRepository?: PodCredentialRepository;\n credentials?: QuotaCredentialRecord[];\n now?: () => Date;\n}\n\nexport class ProviderQuotaService {\n private readonly repository: QuotaSnapshotRepository;\n private readonly vault: CredentialVault;\n private readonly adapters = new Map<string, ProviderQuotaAdapter>();\n private readonly credentialRepository?: PodCredentialRepository;\n private readonly credentials: QuotaCredentialRecord[];\n private readonly now: () => Date;\n private readonly inFlightRefreshes = new Map<string, Promise<NormalizedQuotaSnapshot>>();\n\n public constructor(options: ProviderQuotaServiceOptions) {\n this.repository = options.repository;\n this.vault = options.vault;\n this.credentialRepository = options.credentialRepository;\n this.credentials = options.credentials ?? [];\n this.now = options.now ?? (() => new Date());\n for (const adapter of options.adapters) {\n this.adapters.set(normalizeProvider(adapter.provider), adapter);\n }\n }\n\n public async status(input: ProviderQuotaStatusInput): Promise<NormalizedQuotaSnapshot> {\n const provider = normalizeProvider(input.provider);\n const now = input.now ?? this.now();\n if (input.refresh && input.credentialIri) {\n const refreshKey = quotaRefreshKey({\n webId: input.webId,\n deployment: input.deployment,\n provider,\n credentialIri: input.credentialIri,\n });\n const inFlight = this.inFlightRefreshes.get(refreshKey);\n if (inFlight) {\n return inFlight;\n }\n const refresh = this.refreshAndCache({\n input,\n provider,\n now,\n }).finally(() => {\n this.inFlightRefreshes.delete(refreshKey);\n });\n this.inFlightRefreshes.set(refreshKey, refresh);\n return refresh;\n }\n\n return this.statusAfterImplicitCredentialResolution(input, provider, now);\n }\n\n private async statusAfterImplicitCredentialResolution(\n input: ProviderQuotaStatusInput,\n provider: string,\n now: Date,\n ): Promise<NormalizedQuotaSnapshot> {\n const credential = await this.resolveCredential({\n webId: input.webId,\n deployment: input.deployment,\n provider,\n credentialIri: input.credentialIri,\n });\n\n if (!input.refresh) {\n const cached = await this.repository.findFresh({\n webId: input.webId,\n deployment: input.deployment,\n provider,\n credentialIri: credential.credentialIri,\n now,\n });\n if (cached) {\n return { ...cached, stale: false };\n }\n const latest = await this.repository.findLatest({\n webId: input.webId,\n deployment: input.deployment,\n provider,\n credentialIri: credential.credentialIri,\n });\n if (latest) {\n return { ...latest, stale: true };\n }\n }\n\n const adapter = this.adapters.get(provider);\n if (!adapter) {\n throw new Error(`quota_adapter_not_found:${provider}`);\n }\n const refreshKey = quotaRefreshKey({\n webId: input.webId,\n deployment: input.deployment,\n provider,\n credentialIri: credential.credentialIri,\n });\n const inFlight = this.inFlightRefreshes.get(refreshKey);\n if (inFlight) {\n return inFlight;\n }\n\n const refresh = this.fetchAndCache({\n webId: input.webId,\n deployment: input.deployment,\n provider,\n credential,\n adapter,\n now,\n signal: input.signal,\n }).finally(() => {\n this.inFlightRefreshes.delete(refreshKey);\n });\n this.inFlightRefreshes.set(refreshKey, refresh);\n return refresh;\n }\n\n private async refreshAndCache(input: {\n input: ProviderQuotaStatusInput;\n provider: string;\n now: Date;\n }): Promise<NormalizedQuotaSnapshot> {\n const credential = await this.resolveCredential({\n webId: input.input.webId,\n deployment: input.input.deployment,\n provider: input.provider,\n credentialIri: input.input.credentialIri,\n });\n const adapter = this.adapters.get(input.provider);\n if (!adapter) {\n throw new Error(`quota_adapter_not_found:${input.provider}`);\n }\n return this.fetchAndCache({\n webId: input.input.webId,\n deployment: input.input.deployment,\n provider: input.provider,\n credential,\n adapter,\n now: input.now,\n signal: input.input.signal,\n });\n }\n\n private async fetchAndCache(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credential: QuotaCredentialRecord;\n adapter: ProviderQuotaAdapter;\n now: Date;\n signal?: AbortSignal;\n }): Promise<NormalizedQuotaSnapshot> {\n const secret = await this.vault.open(\n { webId: input.webId },\n input.credential.credentialIri,\n input.provider,\n input.credential.encryptedSecret,\n );\n if (\n this.vault.needsRewrap?.(input.credential.encryptedSecret)\n && this.credentialRepository?.rewrapCredential\n ) {\n const rewrapped = await this.vault.rewrap(\n { webId: input.webId },\n input.credential.encryptedSecret,\n );\n await this.credentialRepository.rewrapCredential({\n webId: input.webId,\n deployment: input.deployment,\n credentialId: input.credential.id,\n expectedVersion: input.credential.version,\n encryptedSecret: rewrapped,\n });\n }\n let snapshot: NormalizedQuotaSnapshot;\n try {\n snapshot = await input.adapter.fetch({\n credential: input.credential,\n secret,\n now: input.now,\n signal: input.signal,\n });\n } catch (error) {\n if (isAbortError(error)) {\n throw error;\n }\n snapshot = errorQuotaSnapshot({\n credential: input.credential.credentialIri,\n source: quotaErrorSource(input.provider),\n now: input.now,\n metadata: { reason: 'provider_quota_unavailable' },\n });\n }\n return this.repository.upsert({\n webId: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n snapshot,\n });\n }\n\n private async resolveCredential(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri?: string;\n }): Promise<QuotaCredentialRecord> {\n const listed = this.credentials.find((candidate) =>\n candidate.webId === input.webId\n && candidate.deployment === input.deployment\n && normalizeProvider(candidate.provider) === input.provider\n && (!input.credentialIri || candidate.credentialIri === input.credentialIri));\n if (listed) {\n return listed;\n }\n\n const active = await this.credentialRepository?.getActiveCredential({\n webId: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n });\n if (\n active\n && (!input.credentialIri || active.credentialIri === input.credentialIri)\n ) {\n return active as QuotaCredentialRecord;\n }\n throw new Error('quota_credential_not_found');\n }\n}\n\nexport class InMemoryQuotaSnapshotRepository implements QuotaSnapshotRepository {\n public readonly rows: Array<NormalizedQuotaSnapshot & {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n }> = [];\n\n public async findFresh(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n now: Date;\n }): Promise<NormalizedQuotaSnapshot | undefined> {\n const latest = await this.findLatest(input);\n if (!latest || new Date(latest.expiresAt).getTime() <= input.now.getTime()) {\n return undefined;\n }\n return latest;\n }\n\n public async findLatest(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n }): Promise<NormalizedQuotaSnapshot | undefined> {\n const row = this.rows\n .filter((candidate) =>\n candidate.webId === input.webId\n && candidate.deployment === input.deployment\n && normalizeProvider(candidate.provider) === normalizeProvider(input.provider)\n && candidate.credential === input.credentialIri)\n .sort((a, b) => new Date(b.observedAt).getTime() - new Date(a.observedAt).getTime())[0];\n return row ? publicSnapshot(row) : undefined;\n }\n\n public async upsert(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n snapshot: NormalizedQuotaSnapshot;\n }): Promise<NormalizedQuotaSnapshot> {\n const id = input.snapshot.id ?? buildQuotaSnapshotId({\n owner: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n credential: input.snapshot.credential,\n });\n const next = {\n ...sanitizeSnapshot(input.snapshot),\n id,\n webId: input.webId,\n deployment: input.deployment,\n provider: normalizeProvider(input.provider),\n stale: false,\n };\n const index = this.rows.findIndex((row) => row.id === id);\n if (index === -1) {\n this.rows.push(next);\n } else {\n this.rows[index] = next;\n }\n return publicSnapshot(next);\n }\n}\n\ntype QuotaSnapshotDb = {\n init?: (...resources: unknown[]) => Promise<void>;\n select(): {\n from(resource: typeof quotaSnapshotResource): {\n where(condition: unknown): { execute(): Promise<QuotaSnapshotRow[]> };\n };\n };\n findById<TRow>(resource: typeof quotaSnapshotResource, id: string): Promise<TRow | null>;\n findByIri<TRow>(resource: typeof quotaSnapshotResource, iri: string): Promise<TRow | null>;\n updateById<TRow>(resource: typeof quotaSnapshotResource, id: string, patch: unknown): Promise<TRow | null>;\n updateByIri<TRow>(resource: typeof quotaSnapshotResource, iri: string, patch: unknown): Promise<TRow | null>;\n insert(resource: typeof quotaSnapshotResource): {\n values(value: unknown): { execute(): Promise<QuotaSnapshotRow[]> };\n };\n};\n\nexport interface PodQuotaSnapshotRepositoryOptions {\n internalPodAccess?: InternalPodAccessTokenProvider;\n dbFactory?: (input: {\n owner: string;\n auth?: AuthContext;\n fetch: typeof fetch;\n }) => Promise<QuotaSnapshotDb>;\n}\n\nexport class PodQuotaSnapshotRepository implements QuotaSnapshotRepository {\n private readonly dbFactory: NonNullable<PodQuotaSnapshotRepositoryOptions['dbFactory']>;\n private readonly internalPodAccess?: InternalPodAccessTokenProvider;\n\n public constructor(options: PodQuotaSnapshotRepositoryOptions = {}) {\n this.internalPodAccess = options.internalPodAccess;\n this.dbFactory = options.dbFactory ?? createDefaultQuotaSnapshotDb;\n }\n\n public async findFresh(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n now: Date;\n }): Promise<NormalizedQuotaSnapshot | undefined> {\n const db = await this.dbForOwner(input.webId);\n const row = await aiGatewayRepository.findFreshQuotaSnapshot(db as never, {\n owner: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n credential: input.credentialIri,\n now: input.now,\n });\n return row ? snapshotFromRow(row, false) : undefined;\n }\n\n public async findLatest(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n }): Promise<NormalizedQuotaSnapshot | undefined> {\n const db = await this.dbForOwner(input.webId);\n const row = await aiGatewayRepository.findLatestQuotaSnapshot(db as never, {\n owner: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n credential: input.credentialIri,\n });\n return row ? snapshotFromRow(row, true) : undefined;\n }\n\n public async upsert(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n snapshot: NormalizedQuotaSnapshot;\n }): Promise<NormalizedQuotaSnapshot> {\n const db = await this.dbForOwner(input.webId);\n const snapshot = sanitizeSnapshot({\n ...input.snapshot,\n id: input.snapshot.id ?? buildQuotaSnapshotId({\n owner: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n credential: input.snapshot.credential,\n }),\n });\n await aiGatewayRepository.upsertQuotaSnapshot(db as never, {\n id: snapshot.id!,\n owner: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n credential: snapshot.credential,\n status: snapshot.status,\n balance: snapshot.balance,\n windows: JSON.stringify(snapshot.windows),\n observedAt: new Date(snapshot.observedAt),\n expiresAt: new Date(snapshot.expiresAt),\n source: snapshot.source,\n } as never);\n return { ...snapshot, stale: false };\n }\n\n private async dbForOwner(owner: string, auth?: AuthContext): Promise<QuotaSnapshotDb> {\n const trustedFetch = await this.resolveTrustedFetch(owner);\n const db = await this.dbFactory({ owner, auth, fetch: trustedFetch });\n await db.init?.(quotaSnapshotResource);\n return db;\n }\n\n private async resolveTrustedFetch(owner: string): Promise<typeof fetch> {\n const trustedFetch = await this.internalPodAccess?.getTrustedFetch(owner);\n if (!trustedFetch) {\n throw new Error('AI Connection service identity is not configured');\n }\n return async (input, init) => {\n const response = await trustedFetch(input, init);\n if (response.status === 403) {\n throw new Error('service_access_missing');\n }\n return response;\n };\n }\n}\n\nexport function unsupportedQuotaSnapshot(\n input: {\n credential: string;\n source: string;\n now: Date;\n ttlMs?: number;\n metadata?: Record<string, unknown>;\n },\n): NormalizedQuotaSnapshot {\n return {\n credential: input.credential,\n status: 'unsupported',\n windows: [],\n observedAt: input.now.toISOString(),\n expiresAt: new Date(input.now.getTime() + (input.ttlMs ?? 60 * 60_000)).toISOString(),\n source: input.source,\n metadata: input.metadata,\n };\n}\n\nexport function errorQuotaSnapshot(\n input: {\n credential: string;\n source: string;\n now: Date;\n status?: number;\n retryAfter?: string | null;\n ttlMs?: number;\n metadata?: Record<string, unknown>;\n },\n): NormalizedQuotaSnapshot {\n return {\n credential: input.credential,\n status: 'error',\n windows: [],\n observedAt: input.now.toISOString(),\n expiresAt: new Date(input.now.getTime() + (input.ttlMs ?? 5 * 60_000)).toISOString(),\n source: input.source,\n metadata: {\n ...input.metadata,\n ...(input.status ? { providerStatusCode: input.status } : {}),\n ...(input.status === 429 ? {\n cooldown: {\n reason: 'rate_limited',\n ...(retryAfterSeconds(input.retryAfter) !== undefined ? { retryAfterSeconds: retryAfterSeconds(input.retryAfter) } : {}),\n },\n } : {}),\n },\n };\n}\n\nexport function apiKeyFromSecret(secret: ProviderSecret): string | undefined {\n const apiKey = secret.apiKey;\n return typeof apiKey === 'string' && apiKey.trim() ? apiKey : undefined;\n}\n\nexport async function fetchJsonWithBearer(input: {\n fetch: typeof fetch;\n url: string;\n apiKey: string;\n signal?: AbortSignal;\n}): Promise<{ ok: true; body: unknown } | { ok: false; status: number; retryAfter?: string | null }> {\n const headers = new Headers();\n headers.set('Authorization', `Bearer ${input.apiKey}`);\n const response = await input.fetch(input.url, {\n method: 'GET',\n headers,\n signal: input.signal,\n });\n if (!response.ok) {\n await response.text().catch(() => '');\n return {\n ok: false,\n status: response.status,\n retryAfter: response.headers.get('Retry-After') ?? response.headers.get('retry-after'),\n };\n }\n return { ok: true, body: await response.json() };\n}\n\nexport function numeric(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\n\nexport function decimalAmount(value: unknown): {\n exact?: string;\n numeric?: number;\n displayApprox?: boolean;\n} {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return {\n exact: String(value),\n numeric: value,\n ...(Number.isSafeInteger(value) ? {} : { displayApprox: true }),\n };\n }\n if (typeof value !== 'string') {\n return {};\n }\n const exact = value.trim();\n if (!exact) {\n return {};\n }\n const parsed = Number(exact);\n if (!Number.isFinite(parsed) || Math.abs(parsed) > Number.MAX_SAFE_INTEGER) {\n return { exact };\n }\n return {\n exact,\n numeric: parsed,\n ...(/[.eE]/u.test(exact) ? { displayApprox: true } : {}),\n };\n}\n\nexport function normalizeProvider(provider: string): string {\n return provider.trim().toLowerCase();\n}\n\nfunction retryAfterSeconds(value: string | null | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n const seconds = Number(value);\n if (Number.isFinite(seconds)) {\n return seconds;\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return undefined;\n }\n return Math.max(0, Math.ceil((date.getTime() - Date.now()) / 1000));\n}\n\nfunction quotaRefreshKey(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n}): string {\n return JSON.stringify([\n input.webId,\n input.deployment,\n normalizeProvider(input.provider),\n input.credentialIri,\n ]);\n}\n\nfunction quotaErrorSource(provider: string): string {\n switch (normalizeProvider(provider)) {\n case 'kimi':\n return 'kimi:/v1/users/me/balance';\n case 'deepseek':\n return 'deepseek:/user/balance';\n case 'openai':\n return 'openai:no-credential-quota-api';\n case 'anthropic':\n return 'anthropic:no-credential-quota-api';\n case 'bailian':\n return 'bailian:console-only';\n default:\n return `${normalizeProvider(provider)}:quota`;\n }\n}\n\nfunction isAbortError(error: unknown): boolean {\n return Boolean(\n error\n && typeof error === 'object'\n && 'name' in error\n && (error as { name?: unknown }).name === 'AbortError',\n );\n}\n\nfunction sanitizeSnapshot(snapshot: NormalizedQuotaSnapshot): NormalizedQuotaSnapshot {\n return {\n ...snapshot,\n windows: snapshot.windows.map((window) => ({ ...window })),\n metadata: snapshot.metadata ? sanitizeMetadata(snapshot.metadata) : undefined,\n };\n}\n\nfunction sanitizeMetadata(metadata: Record<string, unknown>): Record<string, unknown> {\n return JSON.parse(JSON.stringify(metadata, (_key, value) => {\n if (typeof value === 'string' && /secret|sk-|api[_-]?key/i.test(value)) {\n return '[redacted]';\n }\n return value;\n })) as Record<string, unknown>;\n}\n\nfunction publicSnapshot(snapshot: NormalizedQuotaSnapshot): NormalizedQuotaSnapshot {\n return sanitizeSnapshot(snapshot);\n}\n\nfunction snapshotFromRow(row: QuotaSnapshotRow, stale: boolean): NormalizedQuotaSnapshot {\n return sanitizeSnapshot({\n id: String(row.id),\n credential: String(row.credential),\n status: row.status === 'available' || row.status === 'unsupported' ? row.status : 'error',\n balance: typeof row.balance === 'number' ? row.balance : undefined,\n windows: parseWindows(row.windows),\n observedAt: toIso(row.observedAt),\n expiresAt: toIso(row.expiresAt),\n source: typeof row.source === 'string' ? row.source : '',\n stale,\n });\n}\n\nfunction parseWindows(value: unknown): QuotaWindow[] {\n if (typeof value !== 'string') {\n return [];\n }\n try {\n const parsed = JSON.parse(value);\n return Array.isArray(parsed)\n ? parsed.filter((item) => item && typeof item === 'object' && typeof item.name === 'string')\n : [];\n } catch {\n return [];\n }\n}\n\nfunction toIso(value: unknown): string {\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (typeof value === 'string' || typeof value === 'number') {\n const parsed = new Date(value);\n if (!Number.isNaN(parsed.getTime())) {\n return parsed.toISOString();\n }\n }\n return new Date(0).toISOString();\n}\n\nfunction createDefaultQuotaSnapshotDb(input: {\n owner: string;\n auth?: AuthContext;\n fetch: typeof fetch;\n}): Promise<QuotaSnapshotDb> {\n return Promise.resolve(drizzle(\n {\n fetch: input.fetch,\n info: { webId: input.owner, isLoggedIn: true },\n } as any,\n {\n schema: {\n quotaSnapshot: quotaSnapshotResource,\n },\n },\n ) as unknown as QuotaSnapshotDb);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ProviderQuotaAdapter.js","sourceRoot":"","sources":["../../../../src/api/ai-gateway/quota/ProviderQuotaAdapter.ts"],"names":[],"mappings":"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","sourcesContent":["import { drizzle } from '@undefineds.co/drizzle-solid';\nimport {\n aiGatewayRepository,\n quotaSnapshotId as buildQuotaSnapshotId,\n quotaSnapshotResource,\n type QuotaSnapshotRow,\n} from '@undefineds.co/models';\nimport type { AuthContext } from '../../auth/AuthContext';\nimport type { GatewayDeployment } from '../auth/InvocationTokenCodec';\nimport type { InternalPodAccessTokenProvider } from '../pod/HostedPodDataAccess';\nimport type { ConnectCredentialRecord, PodCredentialRepository } from '../connect';\nimport type { ProviderSecret } from '../credentials/CredentialVault';\nimport { decodePlaintextCredential } from '../credentials/PlaintextCredentialPayload';\n\nexport type QuotaSnapshotStatus = 'available' | 'unsupported' | 'error';\n\nexport interface QuotaWindow {\n name: string;\n used?: number;\n usedExact?: string;\n limit?: number;\n limitExact?: string;\n remaining?: number;\n remainingExact?: string;\n displayApprox?: boolean;\n currency?: string;\n resetsAt?: string;\n}\n\nexport interface NormalizedQuotaSnapshot {\n id?: string;\n credential: string;\n status: QuotaSnapshotStatus;\n balance?: number;\n windows: QuotaWindow[];\n observedAt: string;\n expiresAt: string;\n source: string;\n stale?: boolean;\n metadata?: Record<string, unknown>;\n}\n\nexport interface QuotaCredentialRecord extends ConnectCredentialRecord {\n baseUrl?: string;\n}\n\nexport interface ProviderQuotaFetchInput {\n credential: QuotaCredentialRecord;\n secret: ProviderSecret;\n now: Date;\n signal?: AbortSignal;\n}\n\nexport interface ProviderQuotaAdapter {\n readonly provider: string;\n fetch(input: ProviderQuotaFetchInput): Promise<NormalizedQuotaSnapshot>;\n}\n\nexport interface QuotaSnapshotRepository {\n findFresh(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n now: Date;\n auth?: AuthContext;\n }): Promise<NormalizedQuotaSnapshot | undefined>;\n findLatest(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n auth?: AuthContext;\n }): Promise<NormalizedQuotaSnapshot | undefined>;\n upsert(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n snapshot: NormalizedQuotaSnapshot;\n auth?: AuthContext;\n }): Promise<NormalizedQuotaSnapshot>;\n}\n\nexport interface ProviderQuotaStatusInput {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri?: string;\n refresh?: boolean;\n now?: Date;\n signal?: AbortSignal;\n auth?: AuthContext;\n}\n\nexport interface ProviderQuotaServiceOptions {\n repository: QuotaSnapshotRepository;\n adapters: ProviderQuotaAdapter[];\n credentialRepository?: PodCredentialRepository;\n credentials?: QuotaCredentialRecord[];\n now?: () => Date;\n}\n\nexport class ProviderQuotaService {\n private readonly repository: QuotaSnapshotRepository;\n private readonly adapters = new Map<string, ProviderQuotaAdapter>();\n private readonly credentialRepository?: PodCredentialRepository;\n private readonly credentials: QuotaCredentialRecord[];\n private readonly now: () => Date;\n private readonly inFlightRefreshes = new Map<string, Promise<NormalizedQuotaSnapshot>>();\n\n public constructor(options: ProviderQuotaServiceOptions) {\n this.repository = options.repository;\n this.credentialRepository = options.credentialRepository;\n this.credentials = options.credentials ?? [];\n this.now = options.now ?? (() => new Date());\n for (const adapter of options.adapters) {\n this.adapters.set(normalizeProvider(adapter.provider), adapter);\n }\n }\n\n public async status(input: ProviderQuotaStatusInput): Promise<NormalizedQuotaSnapshot> {\n const provider = normalizeProvider(input.provider);\n const now = input.now ?? this.now();\n if (input.refresh && input.credentialIri) {\n const refreshKey = quotaRefreshKey({\n webId: input.webId,\n deployment: input.deployment,\n provider,\n credentialIri: input.credentialIri,\n });\n const inFlight = this.inFlightRefreshes.get(refreshKey);\n if (inFlight) {\n return inFlight;\n }\n const refresh = this.refreshAndCache({\n input,\n provider,\n now,\n }).finally(() => {\n this.inFlightRefreshes.delete(refreshKey);\n });\n this.inFlightRefreshes.set(refreshKey, refresh);\n return refresh;\n }\n\n return this.statusAfterImplicitCredentialResolution(input, provider, now);\n }\n\n private async statusAfterImplicitCredentialResolution(\n input: ProviderQuotaStatusInput,\n provider: string,\n now: Date,\n ): Promise<NormalizedQuotaSnapshot> {\n const credential = await this.resolveCredential({\n webId: input.webId,\n deployment: input.deployment,\n provider,\n credentialIri: input.credentialIri,\n auth: input.auth,\n });\n\n if (!input.refresh) {\n const cached = await this.repository.findFresh({\n webId: input.webId,\n deployment: input.deployment,\n provider,\n credentialIri: credential.credentialIri,\n now,\n auth: input.auth,\n });\n if (cached) {\n return { ...cached, stale: false };\n }\n const latest = await this.repository.findLatest({\n webId: input.webId,\n deployment: input.deployment,\n provider,\n credentialIri: credential.credentialIri,\n auth: input.auth,\n });\n if (latest) {\n return { ...latest, stale: true };\n }\n }\n\n const adapter = this.adapters.get(provider);\n if (!adapter) {\n throw new Error(`quota_adapter_not_found:${provider}`);\n }\n const refreshKey = quotaRefreshKey({\n webId: input.webId,\n deployment: input.deployment,\n provider,\n credentialIri: credential.credentialIri,\n });\n const inFlight = this.inFlightRefreshes.get(refreshKey);\n if (inFlight) {\n return inFlight;\n }\n\n const refresh = this.fetchAndCache({\n webId: input.webId,\n deployment: input.deployment,\n provider,\n credential,\n adapter,\n now,\n signal: input.signal,\n auth: input.auth,\n }).finally(() => {\n this.inFlightRefreshes.delete(refreshKey);\n });\n this.inFlightRefreshes.set(refreshKey, refresh);\n return refresh;\n }\n\n private async refreshAndCache(input: {\n input: ProviderQuotaStatusInput;\n provider: string;\n now: Date;\n }): Promise<NormalizedQuotaSnapshot> {\n const credential = await this.resolveCredential({\n webId: input.input.webId,\n deployment: input.input.deployment,\n provider: input.provider,\n credentialIri: input.input.credentialIri,\n auth: input.input.auth,\n });\n const adapter = this.adapters.get(input.provider);\n if (!adapter) {\n throw new Error(`quota_adapter_not_found:${input.provider}`);\n }\n return this.fetchAndCache({\n webId: input.input.webId,\n deployment: input.input.deployment,\n provider: input.provider,\n credential,\n adapter,\n now: input.now,\n signal: input.input.signal,\n auth: input.input.auth,\n });\n }\n\n private async fetchAndCache(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credential: QuotaCredentialRecord;\n adapter: ProviderQuotaAdapter;\n now: Date;\n signal?: AbortSignal;\n auth?: AuthContext;\n }): Promise<NormalizedQuotaSnapshot> {\n const secret = decodePlaintextCredential(input.credential);\n let snapshot: NormalizedQuotaSnapshot;\n try {\n snapshot = await input.adapter.fetch({\n credential: input.credential,\n secret,\n now: input.now,\n signal: input.signal,\n });\n } catch (error) {\n if (isAbortError(error)) {\n throw error;\n }\n snapshot = errorQuotaSnapshot({\n credential: input.credential.credentialIri,\n source: quotaErrorSource(input.provider),\n now: input.now,\n metadata: { reason: 'provider_quota_unavailable' },\n });\n }\n return this.repository.upsert({\n webId: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n snapshot,\n auth: input.auth,\n });\n }\n\n private async resolveCredential(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri?: string;\n auth?: AuthContext;\n }): Promise<QuotaCredentialRecord> {\n const listed = this.credentials.find((candidate) =>\n candidate.webId === input.webId\n && candidate.deployment === input.deployment\n && normalizeProvider(candidate.provider) === input.provider\n && (!input.credentialIri || candidate.credentialIri === input.credentialIri));\n if (listed) {\n return listed;\n }\n\n const active = await this.credentialRepository?.getActiveCredential({\n webId: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n auth: input.auth,\n });\n if (\n active\n && (!input.credentialIri || active.credentialIri === input.credentialIri)\n ) {\n return active as QuotaCredentialRecord;\n }\n throw new Error('quota_credential_not_found');\n }\n}\n\nexport class InMemoryQuotaSnapshotRepository implements QuotaSnapshotRepository {\n public readonly rows: Array<NormalizedQuotaSnapshot & {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n }> = [];\n\n public async findFresh(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n now: Date;\n auth?: AuthContext;\n }): Promise<NormalizedQuotaSnapshot | undefined> {\n const latest = await this.findLatest(input);\n if (!latest || new Date(latest.expiresAt).getTime() <= input.now.getTime()) {\n return undefined;\n }\n return latest;\n }\n\n public async findLatest(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n auth?: AuthContext;\n }): Promise<NormalizedQuotaSnapshot | undefined> {\n const row = this.rows\n .filter((candidate) =>\n candidate.webId === input.webId\n && candidate.deployment === input.deployment\n && normalizeProvider(candidate.provider) === normalizeProvider(input.provider)\n && candidate.credential === input.credentialIri)\n .sort((a, b) => new Date(b.observedAt).getTime() - new Date(a.observedAt).getTime())[0];\n return row ? publicSnapshot(row) : undefined;\n }\n\n public async upsert(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n snapshot: NormalizedQuotaSnapshot;\n auth?: AuthContext;\n }): Promise<NormalizedQuotaSnapshot> {\n const id = input.snapshot.id ?? buildQuotaSnapshotId({\n owner: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n credential: input.snapshot.credential,\n });\n const next = {\n ...sanitizeSnapshot(input.snapshot),\n id,\n webId: input.webId,\n deployment: input.deployment,\n provider: normalizeProvider(input.provider),\n stale: false,\n };\n const index = this.rows.findIndex((row) => row.id === id);\n if (index === -1) {\n this.rows.push(next);\n } else {\n this.rows[index] = next;\n }\n return publicSnapshot(next);\n }\n}\n\ntype QuotaSnapshotDb = {\n init?: (...resources: unknown[]) => Promise<void>;\n select(): {\n from(resource: typeof quotaSnapshotResource): {\n where(condition: unknown): { execute(): Promise<QuotaSnapshotRow[]> };\n };\n };\n findById<TRow>(resource: typeof quotaSnapshotResource, id: string): Promise<TRow | null>;\n findByIri<TRow>(resource: typeof quotaSnapshotResource, iri: string): Promise<TRow | null>;\n updateById<TRow>(resource: typeof quotaSnapshotResource, id: string, patch: unknown): Promise<TRow | null>;\n updateByIri<TRow>(resource: typeof quotaSnapshotResource, iri: string, patch: unknown): Promise<TRow | null>;\n insert(resource: typeof quotaSnapshotResource): {\n values(value: unknown): { execute(): Promise<QuotaSnapshotRow[]> };\n };\n};\n\nexport interface PodQuotaSnapshotRepositoryOptions {\n internalPodAccess?: InternalPodAccessTokenProvider;\n dbFactory?: (input: {\n owner: string;\n auth?: AuthContext;\n fetch: typeof fetch;\n }) => Promise<QuotaSnapshotDb>;\n}\n\nexport class PodQuotaSnapshotRepository implements QuotaSnapshotRepository {\n private readonly dbFactory: NonNullable<PodQuotaSnapshotRepositoryOptions['dbFactory']>;\n private readonly internalPodAccess?: InternalPodAccessTokenProvider;\n\n public constructor(options: PodQuotaSnapshotRepositoryOptions = {}) {\n this.internalPodAccess = options.internalPodAccess;\n this.dbFactory = options.dbFactory ?? createDefaultQuotaSnapshotDb;\n }\n\n public async findFresh(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n now: Date;\n auth?: AuthContext;\n }): Promise<NormalizedQuotaSnapshot | undefined> {\n const db = await this.dbForOwner(input.webId, input.auth);\n const row = await aiGatewayRepository.findFreshQuotaSnapshot(db as never, {\n owner: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n credential: input.credentialIri,\n now: input.now,\n });\n return row ? snapshotFromRow(row, false) : undefined;\n }\n\n public async findLatest(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n auth?: AuthContext;\n }): Promise<NormalizedQuotaSnapshot | undefined> {\n const db = await this.dbForOwner(input.webId, input.auth);\n const row = await aiGatewayRepository.findLatestQuotaSnapshot(db as never, {\n owner: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n credential: input.credentialIri,\n });\n return row ? snapshotFromRow(row, true) : undefined;\n }\n\n public async upsert(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n snapshot: NormalizedQuotaSnapshot;\n auth?: AuthContext;\n }): Promise<NormalizedQuotaSnapshot> {\n const db = await this.dbForOwner(input.webId, input.auth);\n const snapshot = sanitizeSnapshot({\n ...input.snapshot,\n id: input.snapshot.id ?? buildQuotaSnapshotId({\n owner: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n credential: input.snapshot.credential,\n }),\n });\n await aiGatewayRepository.upsertQuotaSnapshot(db as never, {\n id: snapshot.id!,\n owner: input.webId,\n deployment: input.deployment,\n provider: input.provider,\n credential: snapshot.credential,\n status: snapshot.status,\n balance: snapshot.balance,\n windows: JSON.stringify(snapshot.windows),\n observedAt: new Date(snapshot.observedAt),\n expiresAt: new Date(snapshot.expiresAt),\n source: snapshot.source,\n } as never);\n return { ...snapshot, stale: false };\n }\n\n private async dbForOwner(owner: string, auth?: AuthContext): Promise<QuotaSnapshotDb> {\n const trustedFetch = await this.resolveTrustedFetch(owner, auth);\n const db = await this.dbFactory({ owner, auth, fetch: trustedFetch });\n await db.init?.(quotaSnapshotResource);\n return db;\n }\n\n private async resolveTrustedFetch(owner: string, auth?: AuthContext): Promise<typeof fetch> {\n const trustedFetch = await this.internalPodAccess?.getTrustedFetch(owner, auth);\n if (!trustedFetch) {\n throw new Error('AI Connection service identity is not configured');\n }\n return async (input, init) => {\n const response = await trustedFetch(input, init);\n if (response.status === 403) {\n throw new Error('service_access_missing');\n }\n return response;\n };\n }\n}\n\nexport function unsupportedQuotaSnapshot(\n input: {\n credential: string;\n source: string;\n now: Date;\n ttlMs?: number;\n metadata?: Record<string, unknown>;\n },\n): NormalizedQuotaSnapshot {\n return {\n credential: input.credential,\n status: 'unsupported',\n windows: [],\n observedAt: input.now.toISOString(),\n expiresAt: new Date(input.now.getTime() + (input.ttlMs ?? 60 * 60_000)).toISOString(),\n source: input.source,\n metadata: input.metadata,\n };\n}\n\nexport function errorQuotaSnapshot(\n input: {\n credential: string;\n source: string;\n now: Date;\n status?: number;\n retryAfter?: string | null;\n ttlMs?: number;\n metadata?: Record<string, unknown>;\n },\n): NormalizedQuotaSnapshot {\n return {\n credential: input.credential,\n status: 'error',\n windows: [],\n observedAt: input.now.toISOString(),\n expiresAt: new Date(input.now.getTime() + (input.ttlMs ?? 5 * 60_000)).toISOString(),\n source: input.source,\n metadata: {\n ...input.metadata,\n ...(input.status ? { providerStatusCode: input.status } : {}),\n ...(input.status === 429 ? {\n cooldown: {\n reason: 'rate_limited',\n ...(retryAfterSeconds(input.retryAfter) !== undefined ? { retryAfterSeconds: retryAfterSeconds(input.retryAfter) } : {}),\n },\n } : {}),\n },\n };\n}\n\nexport function apiKeyFromSecret(secret: ProviderSecret): string | undefined {\n const apiKey = secret.apiKey;\n return typeof apiKey === 'string' && apiKey.trim() ? apiKey : undefined;\n}\n\nexport async function fetchJsonWithBearer(input: {\n fetch: typeof fetch;\n url: string;\n apiKey: string;\n signal?: AbortSignal;\n}): Promise<{ ok: true; body: unknown } | { ok: false; status: number; retryAfter?: string | null }> {\n const headers = new Headers();\n headers.set('Authorization', `Bearer ${input.apiKey}`);\n const response = await input.fetch(input.url, {\n method: 'GET',\n headers,\n signal: input.signal,\n });\n if (!response.ok) {\n await response.text().catch(() => '');\n return {\n ok: false,\n status: response.status,\n retryAfter: response.headers.get('Retry-After') ?? response.headers.get('retry-after'),\n };\n }\n return { ok: true, body: await response.json() };\n}\n\nexport function numeric(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\n\nexport function decimalAmount(value: unknown): {\n exact?: string;\n numeric?: number;\n displayApprox?: boolean;\n} {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return {\n exact: String(value),\n numeric: value,\n ...(Number.isSafeInteger(value) ? {} : { displayApprox: true }),\n };\n }\n if (typeof value !== 'string') {\n return {};\n }\n const exact = value.trim();\n if (!exact) {\n return {};\n }\n const parsed = Number(exact);\n if (!Number.isFinite(parsed) || Math.abs(parsed) > Number.MAX_SAFE_INTEGER) {\n return { exact };\n }\n return {\n exact,\n numeric: parsed,\n ...(/[.eE]/u.test(exact) ? { displayApprox: true } : {}),\n };\n}\n\nexport function normalizeProvider(provider: string): string {\n return provider.trim().toLowerCase();\n}\n\nfunction retryAfterSeconds(value: string | null | undefined): number | undefined {\n if (!value) {\n return undefined;\n }\n const seconds = Number(value);\n if (Number.isFinite(seconds)) {\n return seconds;\n }\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return undefined;\n }\n return Math.max(0, Math.ceil((date.getTime() - Date.now()) / 1000));\n}\n\nfunction quotaRefreshKey(input: {\n webId: string;\n deployment: GatewayDeployment;\n provider: string;\n credentialIri: string;\n}): string {\n return JSON.stringify([\n input.webId,\n input.deployment,\n normalizeProvider(input.provider),\n input.credentialIri,\n ]);\n}\n\nfunction quotaErrorSource(provider: string): string {\n switch (normalizeProvider(provider)) {\n case 'kimi':\n return 'kimi:/v1/users/me/balance';\n case 'deepseek':\n return 'deepseek:/user/balance';\n case 'openai':\n return 'openai:no-credential-quota-api';\n case 'anthropic':\n return 'anthropic:no-credential-quota-api';\n case 'bailian':\n return 'bailian:console-only';\n default:\n return `${normalizeProvider(provider)}:quota`;\n }\n}\n\nfunction isAbortError(error: unknown): boolean {\n return Boolean(\n error\n && typeof error === 'object'\n && 'name' in error\n && (error as { name?: unknown }).name === 'AbortError',\n );\n}\n\nfunction sanitizeSnapshot(snapshot: NormalizedQuotaSnapshot): NormalizedQuotaSnapshot {\n return {\n ...snapshot,\n windows: snapshot.windows.map((window) => ({ ...window })),\n metadata: snapshot.metadata ? sanitizeMetadata(snapshot.metadata) : undefined,\n };\n}\n\nfunction sanitizeMetadata(metadata: Record<string, unknown>): Record<string, unknown> {\n return JSON.parse(JSON.stringify(metadata, (_key, value) => {\n if (typeof value === 'string' && /secret|sk-|api[_-]?key/i.test(value)) {\n return '[redacted]';\n }\n return value;\n })) as Record<string, unknown>;\n}\n\nfunction publicSnapshot(snapshot: NormalizedQuotaSnapshot): NormalizedQuotaSnapshot {\n return sanitizeSnapshot(snapshot);\n}\n\nfunction snapshotFromRow(row: QuotaSnapshotRow, stale: boolean): NormalizedQuotaSnapshot {\n return sanitizeSnapshot({\n id: String(row.id),\n credential: String(row.credential),\n status: row.status === 'available' || row.status === 'unsupported' ? row.status : 'error',\n balance: typeof row.balance === 'number' ? row.balance : undefined,\n windows: parseWindows(row.windows),\n observedAt: toIso(row.observedAt),\n expiresAt: toIso(row.expiresAt),\n source: typeof row.source === 'string' ? row.source : '',\n stale,\n });\n}\n\nfunction parseWindows(value: unknown): QuotaWindow[] {\n if (typeof value !== 'string') {\n return [];\n }\n try {\n const parsed = JSON.parse(value);\n return Array.isArray(parsed)\n ? parsed.filter((item) => item && typeof item === 'object' && typeof item.name === 'string')\n : [];\n } catch {\n return [];\n }\n}\n\nfunction toIso(value: unknown): string {\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (typeof value === 'string' || typeof value === 'number') {\n const parsed = new Date(value);\n if (!Number.isNaN(parsed.getTime())) {\n return parsed.toISOString();\n }\n }\n return new Date(0).toISOString();\n}\n\nfunction createDefaultQuotaSnapshotDb(input: {\n owner: string;\n auth?: AuthContext;\n fetch: typeof fetch;\n}): Promise<QuotaSnapshotDb> {\n return Promise.resolve(drizzle(\n {\n fetch: input.fetch,\n info: { webId: input.owner, isLoggedIn: true },\n } as any,\n {\n schema: {\n quotaSnapshot: quotaSnapshotResource,\n },\n },\n ) as unknown as QuotaSnapshotDb);\n}\n"]}
|
|
@@ -8,7 +8,7 @@ export interface AiConnectionServiceAccessDescriptor {
|
|
|
8
8
|
resources: AiConnectionServiceAccessResource[];
|
|
9
9
|
}
|
|
10
10
|
export interface AiConnectionServiceAccessResource {
|
|
11
|
-
id: 'providerCredentials' | 'providerDefinitions' | '
|
|
11
|
+
id: 'providerCredentials' | 'providerDefinitions' | 'quotaSnapshots';
|
|
12
12
|
url: string;
|
|
13
13
|
mediaType: 'text/turtle';
|
|
14
14
|
access: {
|
|
@@ -8,7 +8,6 @@ exports.AI_CONNECTION_APPLET_ID = 'co.undefineds.ai-connection';
|
|
|
8
8
|
const declaredResourceBases = new WeakMap([
|
|
9
9
|
[models_1.credentialResource, declaredResourceBase(models_1.credentialResource)],
|
|
10
10
|
[models_1.aiProviderResource, declaredResourceBase(models_1.aiProviderResource)],
|
|
11
|
-
[models_1.gatewayAccessKeyResource, declaredResourceBase(models_1.gatewayAccessKeyResource)],
|
|
12
11
|
[models_1.quotaSnapshotResource, declaredResourceBase(models_1.quotaSnapshotResource)],
|
|
13
12
|
]);
|
|
14
13
|
function createAiConnectionServiceAccess(input) {
|
|
@@ -21,7 +20,6 @@ function createAiConnectionServiceAccess(input) {
|
|
|
21
20
|
resources: [
|
|
22
21
|
['providerCredentials', resourceUrl(input.ownerWebId, models_1.credentialResource)],
|
|
23
22
|
['providerDefinitions', resourceUrl(input.ownerWebId, models_1.aiProviderResource)],
|
|
24
|
-
['gatewayAccessKeys', resourceUrl(input.ownerWebId, models_1.gatewayAccessKeyResource)],
|
|
25
23
|
['quotaSnapshots', resourceUrl(input.ownerWebId, models_1.quotaSnapshotResource)],
|
|
26
24
|
].map(([id, url]) => ({
|
|
27
25
|
id,
|