@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.
Files changed (172) hide show
  1. package/config/cloud.json +3 -0
  2. package/config/local.json +3 -0
  3. package/config/resolver.json +7 -0
  4. package/config/xpod.base.json +20 -0
  5. package/dist/agents/ClaudeExecutor.js +1 -1
  6. package/dist/agents/ClaudeExecutor.js.map +1 -1
  7. package/dist/agents/types.d.ts +5 -5
  8. package/dist/agents/types.js.map +1 -1
  9. package/dist/api/ai-gateway/AiGatewayService.d.ts +5 -16
  10. package/dist/api/ai-gateway/AiGatewayService.js +13 -35
  11. package/dist/api/ai-gateway/AiGatewayService.js.map +1 -1
  12. package/dist/api/ai-gateway/auth/AiConnectionInvocationKeyIssuer.d.ts +3 -2
  13. package/dist/api/ai-gateway/auth/AiConnectionInvocationKeyIssuer.js +37 -12
  14. package/dist/api/ai-gateway/auth/AiConnectionInvocationKeyIssuer.js.map +1 -1
  15. package/dist/api/ai-gateway/auth/GatewayPrincipal.d.ts +2 -16
  16. package/dist/api/ai-gateway/auth/GatewayPrincipal.js +3 -33
  17. package/dist/api/ai-gateway/auth/GatewayPrincipal.js.map +1 -1
  18. package/dist/api/ai-gateway/auth/InvocationTokenAuthenticator.d.ts +23 -0
  19. package/dist/api/ai-gateway/auth/InvocationTokenAuthenticator.js +81 -0
  20. package/dist/api/ai-gateway/auth/InvocationTokenAuthenticator.js.map +1 -0
  21. package/dist/api/ai-gateway/auth/InvocationTokenCodec.d.ts +7 -4
  22. package/dist/api/ai-gateway/auth/InvocationTokenCodec.js.map +1 -1
  23. package/dist/api/ai-gateway/connect/index.d.ts +7 -26
  24. package/dist/api/ai-gateway/connect/index.js +40 -67
  25. package/dist/api/ai-gateway/connect/index.js.map +1 -1
  26. package/dist/api/ai-gateway/credentials/PlaintextCredentialPayload.d.ts +17 -0
  27. package/dist/api/ai-gateway/credentials/PlaintextCredentialPayload.js +65 -0
  28. package/dist/api/ai-gateway/credentials/PlaintextCredentialPayload.js.map +1 -0
  29. package/dist/api/ai-gateway/pod/HostedPodDataAccess.d.ts +24 -0
  30. package/dist/api/ai-gateway/pod/HostedPodDataAccess.js +149 -0
  31. package/dist/api/ai-gateway/pod/HostedPodDataAccess.js.map +1 -0
  32. package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.d.ts +13 -5
  33. package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.js +16 -19
  34. package/dist/api/ai-gateway/quota/ProviderQuotaAdapter.js.map +1 -1
  35. package/dist/api/ai-gateway/service-access/AiConnectionServiceAccess.d.ts +1 -1
  36. package/dist/api/ai-gateway/service-access/AiConnectionServiceAccess.js +0 -2
  37. package/dist/api/ai-gateway/service-access/AiConnectionServiceAccess.js.map +1 -1
  38. package/dist/api/auth/AuthContext.d.ts +1 -12
  39. package/dist/api/auth/AuthContext.js +0 -11
  40. package/dist/api/auth/AuthContext.js.map +1 -1
  41. package/dist/api/auth/ClientCredentialsAuthenticator.js +4 -11
  42. package/dist/api/auth/ClientCredentialsAuthenticator.js.map +1 -1
  43. package/dist/api/chatkit/default-agent.d.ts +2 -2
  44. package/dist/api/chatkit/default-agent.js +4 -4
  45. package/dist/api/chatkit/default-agent.js.map +1 -1
  46. package/dist/api/chatkit/runtime/AcpAgentRuntime.js +1 -1
  47. package/dist/api/chatkit/runtime/AcpAgentRuntime.js.map +1 -1
  48. package/dist/api/container/common.js +28 -69
  49. package/dist/api/container/common.js.map +1 -1
  50. package/dist/api/container/index.js +5 -6
  51. package/dist/api/container/index.js.map +1 -1
  52. package/dist/api/container/routes.js +2 -5
  53. package/dist/api/container/routes.js.map +1 -1
  54. package/dist/api/container/types.d.ts +8 -10
  55. package/dist/api/container/types.js.map +1 -1
  56. package/dist/api/handlers/AiClientConfigurationHandler.js +3 -3
  57. package/dist/api/handlers/AiClientConfigurationHandler.js.map +1 -1
  58. package/dist/api/handlers/AiGatewayHandler.js +2 -2
  59. package/dist/api/handlers/AiGatewayHandler.js.map +1 -1
  60. package/dist/api/handlers/AiGatewayManagementHandler.d.ts +2 -10
  61. package/dist/api/handlers/AiGatewayManagementHandler.js +4 -154
  62. package/dist/api/handlers/AiGatewayManagementHandler.js.map +1 -1
  63. package/dist/api/handlers/NetworkSettingsHandler.js +0 -3
  64. package/dist/api/handlers/NetworkSettingsHandler.js.map +1 -1
  65. package/dist/api/handlers/PodSettingsHandler.d.ts +5 -2
  66. package/dist/api/handlers/PodSettingsHandler.js +3 -3
  67. package/dist/api/handlers/PodSettingsHandler.js.map +1 -1
  68. package/dist/api/runs/AgentRuntimeTypes.d.ts +3 -3
  69. package/dist/api/runs/AgentRuntimeTypes.js +10 -10
  70. package/dist/api/runs/AgentRuntimeTypes.js.map +1 -1
  71. package/dist/api/runs/InngestRunExecutionBackend.d.ts +15 -9
  72. package/dist/api/runs/InngestRunExecutionBackend.js +25 -10
  73. package/dist/api/runs/InngestRunExecutionBackend.js.map +1 -1
  74. package/dist/api/runs/PiAgentRuntimeDriver.js +2 -2
  75. package/dist/api/runs/PiAgentRuntimeDriver.js.map +1 -1
  76. package/dist/api/runs/RunStateCenter.js +1 -1
  77. package/dist/api/runs/RunStateCenter.js.map +1 -1
  78. package/dist/api/service/AiClientConfigurationService.d.ts +2 -2
  79. package/dist/api/service/AiClientConfigurationService.js +11 -11
  80. package/dist/api/service/AiClientConfigurationService.js.map +1 -1
  81. package/dist/api/tasks/InngestTaskScheduler.d.ts +16 -10
  82. package/dist/api/tasks/InngestTaskScheduler.js +24 -12
  83. package/dist/api/tasks/InngestTaskScheduler.js.map +1 -1
  84. package/dist/cli/commands/start.js +7 -7
  85. package/dist/cli/commands/start.js.map +1 -1
  86. package/dist/components/components.jsonld +1 -0
  87. package/dist/components/context.jsonld +36 -0
  88. package/dist/http/InternalPodDataHttpHandler.d.ts +32 -0
  89. package/dist/http/InternalPodDataHttpHandler.js +258 -0
  90. package/dist/http/InternalPodDataHttpHandler.js.map +1 -0
  91. package/dist/http/InternalPodDataHttpHandler.jsonld +201 -0
  92. package/dist/index.d.ts +2 -1
  93. package/dist/index.js +4 -2
  94. package/dist/index.js.map +1 -1
  95. package/dist/main.js +13 -13
  96. package/dist/main.js.map +1 -1
  97. package/dist/runtime/GatewayAdminProxyAuth.d.ts +15 -1
  98. package/dist/runtime/GatewayAdminProxyAuth.js +57 -2
  99. package/dist/runtime/GatewayAdminProxyAuth.js.map +1 -1
  100. package/dist/runtime/bootstrap.js +3 -0
  101. package/dist/runtime/bootstrap.js.map +1 -1
  102. package/dist/runtime/css-process.d.ts +1 -1
  103. package/dist/runtime/css-process.js +4 -1
  104. package/dist/runtime/css-process.js.map +1 -1
  105. package/dist/runtime/runner/node/CommunitySolidServerCssRunner.d.ts +2 -0
  106. package/dist/runtime/runner/node/CommunitySolidServerCssRunner.js +50 -0
  107. package/dist/runtime/runner/node/CommunitySolidServerCssRunner.js.map +1 -1
  108. package/node_modules/@undefineds.co/ai-connection/dist/AiClientConfigurationSection.d.ts +5 -5
  109. package/node_modules/@undefineds.co/ai-connection/dist/AiClientConfigurationSection.js +7 -7
  110. package/node_modules/@undefineds.co/ai-connection/dist/AiConnectionMain.js +1 -1
  111. package/node_modules/@undefineds.co/ai-connection/dist/AiConnectionPanel.d.ts +3 -1
  112. package/node_modules/@undefineds.co/ai-connection/dist/AiConnectionPanel.js +74 -60
  113. package/node_modules/@undefineds.co/ai-connection/dist/ai-connection-client.d.ts +0 -21
  114. package/node_modules/@undefineds.co/ai-connection/dist/ai-connection-client.js +0 -41
  115. package/node_modules/@undefineds.co/ai-connection/dist/client-config/base-adapter.d.ts +1 -0
  116. package/node_modules/@undefineds.co/ai-connection/dist/client-config/base-adapter.js +7 -2
  117. package/node_modules/@undefineds.co/ai-connection/dist/client-config/codex.js +3 -3
  118. package/node_modules/@undefineds.co/ai-connection/dist/client-config/index.cjs +15 -9
  119. package/node_modules/@undefineds.co/ai-connection/dist/client-config/json-env-adapter.js +4 -4
  120. package/node_modules/@undefineds.co/ai-connection/dist/client-config/pi.js +3 -3
  121. package/node_modules/@undefineds.co/ai-connection/dist/client-config/types.d.ts +1 -1
  122. package/node_modules/@undefineds.co/ai-connection/dist/controller.d.ts +2 -1
  123. package/node_modules/@undefineds.co/ai-connection/dist/controller.js +1 -0
  124. package/node_modules/@undefineds.co/ai-connection/dist/service-access.js +0 -1
  125. package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +22 -1
  126. package/package.json +3 -3
  127. package/static/app/assets/main.js +7 -7
  128. package/static/dashboard/assets/NetworkPage-CXjiUMR1.js +2 -0
  129. package/static/dashboard/assets/{PaneListHeader-57nvMwH6.js → PaneListHeader-BSipfl0W.js} +1 -1
  130. package/static/dashboard/assets/PodPage-Bd3Xhmp-.js +2 -0
  131. package/static/dashboard/assets/ServicesPage-CI3jWZGe.js +1 -0
  132. package/static/dashboard/assets/{card-B9Zjf_2p.js → card-z5BV5hTo.js} +1 -1
  133. package/static/dashboard/assets/{dashboard-8C6o666W.js → dashboard-CSrqAv2L.js} +2 -2
  134. package/static/dashboard/assets/{database-DPh9wDY9.js → database-Ct5ZPe6L.js} +1 -1
  135. package/static/dashboard/assets/{external-link-VbMQvVMz.js → external-link-B7wD1hkm.js} +1 -1
  136. package/static/dashboard/assets/index-tOBaUnM1.js +44 -0
  137. package/static/dashboard/assets/{refresh-cw-BxVxNxNr.js → refresh-cw-CFDZPaE8.js} +1 -1
  138. package/static/dashboard/assets/{services-status-context-DKmJ7ISr.js → services-status-context-DN1Icg4A.js} +1 -1
  139. package/static/dashboard/dashboard.html +1 -1
  140. package/static/settings/assets/ModelsPage-03NPWzoX.js +1 -0
  141. package/static/settings/assets/{PaneListHeader-Bgaze006.js → PaneListHeader-DMD8OJef.js} +1 -1
  142. package/static/settings/assets/PodPage-DT4EMYhL.js +2 -0
  143. package/static/settings/assets/ServicesPage-CJ0ub6IH.js +1 -0
  144. package/static/settings/assets/SettingsPage-BkR7ZK18.js +41 -0
  145. package/static/settings/assets/{card-B_bXSIn-.js → card-Cjsia0_V.js} +1 -1
  146. package/static/settings/assets/{services-status-context-DiX-AbrP.js → services-status-context-CkuKmH5h.js} +1 -1
  147. package/static/settings/assets/{settings-B30oMfZq.js → settings-Cyyv6-SD.js} +2 -2
  148. package/static/settings/assets/{workspace-layout-Dv1Yn9Ci.js → workspace-layout-B47luv6r.js} +1 -1
  149. package/static/settings/settings.html +1 -1
  150. package/dist/api/ai-gateway/auth/ClientCredentialsInternalPodAccessTokenProvider.d.ts +0 -25
  151. package/dist/api/ai-gateway/auth/ClientCredentialsInternalPodAccessTokenProvider.js +0 -91
  152. package/dist/api/ai-gateway/auth/ClientCredentialsInternalPodAccessTokenProvider.js.map +0 -1
  153. package/dist/api/ai-gateway/auth/GatewayApiKey.d.ts +0 -28
  154. package/dist/api/ai-gateway/auth/GatewayApiKey.js +0 -162
  155. package/dist/api/ai-gateway/auth/GatewayApiKey.js.map +0 -1
  156. package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.d.ts +0 -56
  157. package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js +0 -143
  158. package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js.map +0 -1
  159. package/dist/api/ai-gateway/auth/GatewayKeyLocatorCodec.d.ts +0 -26
  160. package/dist/api/ai-gateway/auth/GatewayKeyLocatorCodec.js +0 -97
  161. package/dist/api/ai-gateway/auth/GatewayKeyLocatorCodec.js.map +0 -1
  162. package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.d.ts +0 -54
  163. package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js +0 -152
  164. package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js.map +0 -1
  165. package/static/dashboard/assets/NetworkPage-Brt79fuQ.js +0 -2
  166. package/static/dashboard/assets/PodPage-CM6do1vB.js +0 -2
  167. package/static/dashboard/assets/ServicesPage-BUNxGJRz.js +0 -1
  168. package/static/dashboard/assets/index-RfiFckzb.js +0 -51
  169. package/static/settings/assets/ModelsPage-D_IH7AH3.js +0 -1
  170. package/static/settings/assets/PodPage-Cy1VNObw.js +0 -2
  171. package/static/settings/assets/ServicesPage-BsFaxVWC.js +0 -1
  172. 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/GatewayApiKey';
4
- import type { InternalPodAccessTokenProvider } from '../auth/PodGatewayAccessKeyRepository';
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 { CredentialVault, ProviderSecret } from '../credentials/CredentialVault';
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 = await this.vault.open({ webId: input.webId }, input.credential.credentialIri, input.provider, input.credential.encryptedSecret);
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' | 'gatewayAccessKeys' | 'quotaSnapshots';
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,