@kya-os/mcp-i-core 1.2.3-canary.7 → 1.3.0

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 (231) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/.turbo/turbo-build.log +4 -0
  3. package/.turbo/turbo-test$colon$coverage.log +4514 -0
  4. package/.turbo/turbo-test.log +2973 -0
  5. package/COMPLIANCE_IMPROVEMENT_REPORT.md +483 -0
  6. package/Composer 3.md +615 -0
  7. package/GPT-5.md +1169 -0
  8. package/OPUS-plan.md +352 -0
  9. package/PHASE_3_AND_4.1_SUMMARY.md +585 -0
  10. package/PHASE_3_SUMMARY.md +317 -0
  11. package/PHASE_4.1.3_SUMMARY.md +428 -0
  12. package/PHASE_4.1_COMPLETE.md +525 -0
  13. package/PHASE_4_USER_DID_IDENTITY_LINKING_PLAN.md +1240 -0
  14. package/SCHEMA_COMPLIANCE_REPORT.md +275 -0
  15. package/TEST_PLAN.md +571 -0
  16. package/coverage/coverage-final.json +57 -0
  17. package/dist/__tests__/utils/mock-providers.d.ts +1 -2
  18. package/dist/__tests__/utils/mock-providers.d.ts.map +1 -1
  19. package/dist/__tests__/utils/mock-providers.js.map +1 -1
  20. package/dist/cache/oauth-config-cache.d.ts +69 -0
  21. package/dist/cache/oauth-config-cache.d.ts.map +1 -0
  22. package/dist/cache/oauth-config-cache.js +76 -0
  23. package/dist/cache/oauth-config-cache.js.map +1 -0
  24. package/dist/identity/idp-token-resolver.d.ts +53 -0
  25. package/dist/identity/idp-token-resolver.d.ts.map +1 -0
  26. package/dist/identity/idp-token-resolver.js +108 -0
  27. package/dist/identity/idp-token-resolver.js.map +1 -0
  28. package/dist/identity/idp-token-storage.interface.d.ts +42 -0
  29. package/dist/identity/idp-token-storage.interface.d.ts.map +1 -0
  30. package/dist/identity/idp-token-storage.interface.js +12 -0
  31. package/dist/identity/idp-token-storage.interface.js.map +1 -0
  32. package/dist/identity/user-did-manager.d.ts +39 -1
  33. package/dist/identity/user-did-manager.d.ts.map +1 -1
  34. package/dist/identity/user-did-manager.js +69 -3
  35. package/dist/identity/user-did-manager.js.map +1 -1
  36. package/dist/index.d.ts +22 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +39 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/runtime/audit-logger.d.ts +37 -0
  41. package/dist/runtime/audit-logger.d.ts.map +1 -0
  42. package/dist/runtime/audit-logger.js +9 -0
  43. package/dist/runtime/audit-logger.js.map +1 -0
  44. package/dist/runtime/base.d.ts +58 -2
  45. package/dist/runtime/base.d.ts.map +1 -1
  46. package/dist/runtime/base.js +266 -11
  47. package/dist/runtime/base.js.map +1 -1
  48. package/dist/services/access-control.service.d.ts.map +1 -1
  49. package/dist/services/access-control.service.js +200 -35
  50. package/dist/services/access-control.service.js.map +1 -1
  51. package/dist/services/authorization/authorization-registry.d.ts +29 -0
  52. package/dist/services/authorization/authorization-registry.d.ts.map +1 -0
  53. package/dist/services/authorization/authorization-registry.js +57 -0
  54. package/dist/services/authorization/authorization-registry.js.map +1 -0
  55. package/dist/services/authorization/types.d.ts +53 -0
  56. package/dist/services/authorization/types.d.ts.map +1 -0
  57. package/dist/services/authorization/types.js +10 -0
  58. package/dist/services/authorization/types.js.map +1 -0
  59. package/dist/services/batch-delegation.service.d.ts +53 -0
  60. package/dist/services/batch-delegation.service.d.ts.map +1 -0
  61. package/dist/services/batch-delegation.service.js +95 -0
  62. package/dist/services/batch-delegation.service.js.map +1 -0
  63. package/dist/services/oauth-config.service.d.ts +53 -0
  64. package/dist/services/oauth-config.service.d.ts.map +1 -0
  65. package/dist/services/oauth-config.service.js +117 -0
  66. package/dist/services/oauth-config.service.js.map +1 -0
  67. package/dist/services/oauth-provider-registry.d.ts +77 -0
  68. package/dist/services/oauth-provider-registry.d.ts.map +1 -0
  69. package/dist/services/oauth-provider-registry.js +112 -0
  70. package/dist/services/oauth-provider-registry.js.map +1 -0
  71. package/dist/services/oauth-service.d.ts +77 -0
  72. package/dist/services/oauth-service.d.ts.map +1 -0
  73. package/dist/services/oauth-service.js +348 -0
  74. package/dist/services/oauth-service.js.map +1 -0
  75. package/dist/services/oauth-token-retrieval.service.d.ts +49 -0
  76. package/dist/services/oauth-token-retrieval.service.d.ts.map +1 -0
  77. package/dist/services/oauth-token-retrieval.service.js +150 -0
  78. package/dist/services/oauth-token-retrieval.service.js.map +1 -0
  79. package/dist/services/provider-resolver.d.ts +48 -0
  80. package/dist/services/provider-resolver.d.ts.map +1 -0
  81. package/dist/services/provider-resolver.js +120 -0
  82. package/dist/services/provider-resolver.js.map +1 -0
  83. package/dist/services/provider-validator.d.ts +55 -0
  84. package/dist/services/provider-validator.d.ts.map +1 -0
  85. package/dist/services/provider-validator.js +135 -0
  86. package/dist/services/provider-validator.js.map +1 -0
  87. package/dist/services/tool-context-builder.d.ts +57 -0
  88. package/dist/services/tool-context-builder.d.ts.map +1 -0
  89. package/dist/services/tool-context-builder.js +125 -0
  90. package/dist/services/tool-context-builder.js.map +1 -0
  91. package/dist/services/tool-protection.service.d.ts +87 -10
  92. package/dist/services/tool-protection.service.d.ts.map +1 -1
  93. package/dist/services/tool-protection.service.js +282 -112
  94. package/dist/services/tool-protection.service.js.map +1 -1
  95. package/dist/types/oauth-required-error.d.ts +40 -0
  96. package/dist/types/oauth-required-error.d.ts.map +1 -0
  97. package/dist/types/oauth-required-error.js +40 -0
  98. package/dist/types/oauth-required-error.js.map +1 -0
  99. package/dist/utils/did-helpers.d.ts +33 -0
  100. package/dist/utils/did-helpers.d.ts.map +1 -1
  101. package/dist/utils/did-helpers.js +40 -0
  102. package/dist/utils/did-helpers.js.map +1 -1
  103. package/dist/utils/index.d.ts +1 -0
  104. package/dist/utils/index.d.ts.map +1 -1
  105. package/dist/utils/index.js +1 -0
  106. package/dist/utils/index.js.map +1 -1
  107. package/docs/API_REFERENCE.md +1362 -0
  108. package/docs/COMPLIANCE_MATRIX.md +691 -0
  109. package/docs/STATUSLIST2021_GUIDE.md +696 -0
  110. package/docs/W3C_VC_DELEGATION_GUIDE.md +710 -0
  111. package/package.json +24 -50
  112. package/scripts/audit-compliance.ts +724 -0
  113. package/src/__tests__/cache/tool-protection-cache.test.ts +640 -0
  114. package/src/__tests__/config/provider-runtime-config.test.ts +309 -0
  115. package/src/__tests__/delegation-e2e.test.ts +690 -0
  116. package/src/__tests__/identity/user-did-manager.test.ts +213 -0
  117. package/src/__tests__/index.test.ts +56 -0
  118. package/src/__tests__/integration/full-flow.test.ts +776 -0
  119. package/src/__tests__/integration.test.ts +281 -0
  120. package/src/__tests__/providers/base.test.ts +173 -0
  121. package/src/__tests__/providers/memory.test.ts +319 -0
  122. package/src/__tests__/regression/phase2-regression.test.ts +427 -0
  123. package/src/__tests__/runtime/audit-logger.test.ts +154 -0
  124. package/src/__tests__/runtime/base-extensions.test.ts +593 -0
  125. package/src/__tests__/runtime/base.test.ts +869 -0
  126. package/src/__tests__/runtime/delegation-flow.test.ts +164 -0
  127. package/src/__tests__/runtime/proof-client-did.test.ts +375 -0
  128. package/src/__tests__/runtime/route-interception.test.ts +686 -0
  129. package/src/__tests__/runtime/tool-protection-enforcement.test.ts +908 -0
  130. package/src/__tests__/services/agentshield-integration.test.ts +784 -0
  131. package/src/__tests__/services/provider-resolver-edge-cases.test.ts +487 -0
  132. package/src/__tests__/services/tool-protection-oauth-provider.test.ts +480 -0
  133. package/src/__tests__/services/tool-protection.service.test.ts +1366 -0
  134. package/src/__tests__/utils/mock-providers.ts +340 -0
  135. package/src/cache/oauth-config-cache.d.ts +69 -0
  136. package/src/cache/oauth-config-cache.d.ts.map +1 -0
  137. package/src/cache/oauth-config-cache.js +71 -0
  138. package/src/cache/oauth-config-cache.js.map +1 -0
  139. package/src/cache/oauth-config-cache.ts +123 -0
  140. package/src/cache/tool-protection-cache.ts +171 -0
  141. package/src/compliance/EXAMPLE.md +412 -0
  142. package/src/compliance/__tests__/schema-verifier.test.ts +797 -0
  143. package/src/compliance/index.ts +8 -0
  144. package/src/compliance/schema-registry.ts +460 -0
  145. package/src/compliance/schema-verifier.ts +708 -0
  146. package/src/config/__tests__/remote-config.spec.ts +268 -0
  147. package/src/config/remote-config.ts +174 -0
  148. package/src/config.ts +309 -0
  149. package/src/delegation/__tests__/audience-validator.test.ts +112 -0
  150. package/src/delegation/__tests__/bitstring.test.ts +346 -0
  151. package/src/delegation/__tests__/cascading-revocation.test.ts +628 -0
  152. package/src/delegation/__tests__/delegation-graph.test.ts +584 -0
  153. package/src/delegation/__tests__/utils.test.ts +152 -0
  154. package/src/delegation/__tests__/vc-issuer.test.ts +442 -0
  155. package/src/delegation/__tests__/vc-verifier.test.ts +922 -0
  156. package/src/delegation/audience-validator.ts +52 -0
  157. package/src/delegation/bitstring.ts +278 -0
  158. package/src/delegation/cascading-revocation.ts +370 -0
  159. package/src/delegation/delegation-graph.ts +299 -0
  160. package/src/delegation/index.ts +14 -0
  161. package/src/delegation/statuslist-manager.ts +353 -0
  162. package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +366 -0
  163. package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +228 -0
  164. package/src/delegation/storage/index.ts +9 -0
  165. package/src/delegation/storage/memory-graph-storage.ts +178 -0
  166. package/src/delegation/storage/memory-statuslist-storage.ts +77 -0
  167. package/src/delegation/utils.ts +42 -0
  168. package/src/delegation/vc-issuer.ts +232 -0
  169. package/src/delegation/vc-verifier.ts +568 -0
  170. package/src/identity/idp-token-resolver.ts +147 -0
  171. package/src/identity/idp-token-storage.interface.ts +59 -0
  172. package/src/identity/user-did-manager.ts +370 -0
  173. package/src/index.ts +260 -0
  174. package/src/providers/base.d.ts +91 -0
  175. package/src/providers/base.d.ts.map +1 -0
  176. package/src/providers/base.js +38 -0
  177. package/src/providers/base.js.map +1 -0
  178. package/src/providers/base.ts +96 -0
  179. package/src/providers/memory.ts +142 -0
  180. package/src/runtime/audit-logger.ts +39 -0
  181. package/src/runtime/base.ts +1329 -0
  182. package/src/services/__tests__/access-control.integration.test.ts +443 -0
  183. package/src/services/__tests__/access-control.proof-response-validation.test.ts +578 -0
  184. package/src/services/__tests__/access-control.service.test.ts +970 -0
  185. package/src/services/__tests__/batch-delegation.service.test.ts +351 -0
  186. package/src/services/__tests__/crypto.service.test.ts +531 -0
  187. package/src/services/__tests__/oauth-provider-registry.test.ts +142 -0
  188. package/src/services/__tests__/proof-verifier.integration.test.ts +485 -0
  189. package/src/services/__tests__/proof-verifier.test.ts +489 -0
  190. package/src/services/__tests__/provider-resolution.integration.test.ts +198 -0
  191. package/src/services/__tests__/provider-resolver.test.ts +217 -0
  192. package/src/services/__tests__/storage.service.test.ts +358 -0
  193. package/src/services/access-control.service.ts +990 -0
  194. package/src/services/authorization/authorization-registry.ts +66 -0
  195. package/src/services/authorization/types.ts +71 -0
  196. package/src/services/batch-delegation.service.ts +137 -0
  197. package/src/services/crypto.service.ts +302 -0
  198. package/src/services/errors.ts +76 -0
  199. package/src/services/index.ts +9 -0
  200. package/src/services/oauth-config.service.d.ts +53 -0
  201. package/src/services/oauth-config.service.d.ts.map +1 -0
  202. package/src/services/oauth-config.service.js +113 -0
  203. package/src/services/oauth-config.service.js.map +1 -0
  204. package/src/services/oauth-config.service.ts +166 -0
  205. package/src/services/oauth-provider-registry.d.ts +57 -0
  206. package/src/services/oauth-provider-registry.d.ts.map +1 -0
  207. package/src/services/oauth-provider-registry.js +73 -0
  208. package/src/services/oauth-provider-registry.js.map +1 -0
  209. package/src/services/oauth-provider-registry.ts +123 -0
  210. package/src/services/oauth-service.ts +510 -0
  211. package/src/services/oauth-token-retrieval.service.ts +245 -0
  212. package/src/services/proof-verifier.ts +478 -0
  213. package/src/services/provider-resolver.d.ts +48 -0
  214. package/src/services/provider-resolver.d.ts.map +1 -0
  215. package/src/services/provider-resolver.js +106 -0
  216. package/src/services/provider-resolver.js.map +1 -0
  217. package/src/services/provider-resolver.ts +144 -0
  218. package/src/services/provider-validator.ts +170 -0
  219. package/src/services/storage.service.ts +566 -0
  220. package/src/services/tool-context-builder.ts +172 -0
  221. package/src/services/tool-protection.service.ts +958 -0
  222. package/src/types/oauth-required-error.ts +63 -0
  223. package/src/types/tool-protection.ts +155 -0
  224. package/src/utils/__tests__/did-helpers.test.ts +101 -0
  225. package/src/utils/base64.ts +148 -0
  226. package/src/utils/cors.ts +83 -0
  227. package/src/utils/did-helpers.ts +150 -0
  228. package/src/utils/index.ts +8 -0
  229. package/src/utils/storage-keys.ts +278 -0
  230. package/tsconfig.json +21 -0
  231. package/vitest.config.ts +56 -0
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Tests for Remote Configuration Fetching
3
+ *
4
+ * Validates that remote config fetching works correctly with caching
5
+ * and fallback behavior.
6
+ */
7
+
8
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
9
+ import {
10
+ fetchRemoteConfig,
11
+ type RemoteConfigOptions,
12
+ type RemoteConfigCache
13
+ } from '../remote-config.js';
14
+ import type { MCPIConfig } from '@kya-os/contracts/config';
15
+
16
+ describe('fetchRemoteConfig', () => {
17
+ let mockFetch: ReturnType<typeof vi.fn>;
18
+ let mockCache: RemoteConfigCache;
19
+
20
+ beforeEach(() => {
21
+ mockFetch = vi.fn();
22
+ mockCache = {
23
+ get: vi.fn(),
24
+ set: vi.fn()
25
+ };
26
+ });
27
+
28
+ describe('Cache hit scenario', () => {
29
+ it('should return cached config if available and not expired', async () => {
30
+ const cachedConfig: MCPIConfig = {
31
+ environment: 'production',
32
+ identity: { enabled: true, environment: 'production' }
33
+ };
34
+
35
+ vi.mocked(mockCache.get).mockResolvedValue(
36
+ JSON.stringify({
37
+ config: cachedConfig,
38
+ expiresAt: Date.now() + 60000 // 1 minute in future
39
+ })
40
+ );
41
+
42
+ const options: RemoteConfigOptions = {
43
+ apiUrl: 'https://kya.vouched.id',
44
+ apiKey: 'test-key',
45
+ projectId: 'test-project',
46
+ fetchProvider: mockFetch
47
+ };
48
+
49
+ const result = await fetchRemoteConfig(options, mockCache);
50
+
51
+ expect(result).toEqual(cachedConfig);
52
+ expect(mockCache.get).toHaveBeenCalledWith('config:project:test-project');
53
+ expect(mockFetch).not.toHaveBeenCalled();
54
+ });
55
+
56
+ it('should fetch fresh config if cache expired', async () => {
57
+ const cachedConfig: MCPIConfig = {
58
+ environment: 'production'
59
+ };
60
+
61
+ vi.mocked(mockCache.get).mockResolvedValue(
62
+ JSON.stringify({
63
+ config: cachedConfig,
64
+ expiresAt: Date.now() - 1000 // Expired
65
+ })
66
+ );
67
+
68
+ const freshConfig: MCPIConfig = {
69
+ environment: 'production',
70
+ identity: { enabled: true, environment: 'production' }
71
+ };
72
+
73
+ mockFetch.mockResolvedValue({
74
+ ok: true,
75
+ json: async () => ({ success: true, data: freshConfig })
76
+ } as Response);
77
+
78
+ const options: RemoteConfigOptions = {
79
+ apiUrl: 'https://kya.vouched.id',
80
+ apiKey: 'test-key',
81
+ projectId: 'test-project',
82
+ fetchProvider: mockFetch
83
+ };
84
+
85
+ const result = await fetchRemoteConfig(options, mockCache);
86
+
87
+ expect(result).toEqual(freshConfig);
88
+ expect(mockFetch).toHaveBeenCalled();
89
+ });
90
+ });
91
+
92
+ describe('Cache miss scenario', () => {
93
+ it('should fetch from API when cache is empty', async () => {
94
+ vi.mocked(mockCache.get).mockResolvedValue(null);
95
+
96
+ const config: MCPIConfig = {
97
+ environment: 'production',
98
+ identity: { enabled: true, environment: 'production' }
99
+ };
100
+
101
+ mockFetch.mockResolvedValue({
102
+ ok: true,
103
+ json: async () => ({ success: true, data: config })
104
+ } as Response);
105
+
106
+ const options: RemoteConfigOptions = {
107
+ apiUrl: 'https://kya.vouched.id',
108
+ apiKey: 'test-key',
109
+ projectId: 'test-project',
110
+ fetchProvider: mockFetch
111
+ };
112
+
113
+ const result = await fetchRemoteConfig(options, mockCache);
114
+
115
+ expect(result).toEqual(config);
116
+ expect(mockCache.set).toHaveBeenCalled();
117
+ });
118
+
119
+ it('should use agentDid when projectId not available', async () => {
120
+ vi.mocked(mockCache.get).mockResolvedValue(null);
121
+
122
+ const config: MCPIConfig = {
123
+ environment: 'production'
124
+ };
125
+
126
+ mockFetch.mockResolvedValue({
127
+ ok: true,
128
+ json: async () => ({ success: true, data: config })
129
+ } as Response);
130
+
131
+ const options: RemoteConfigOptions = {
132
+ apiUrl: 'https://kya.vouched.id',
133
+ apiKey: 'test-key',
134
+ agentDid: 'did:key:test',
135
+ fetchProvider: mockFetch
136
+ };
137
+
138
+ const result = await fetchRemoteConfig(options, mockCache);
139
+
140
+ expect(result).toEqual(config);
141
+ expect(mockCache.get).toHaveBeenCalledWith('config:agent:did:key:test');
142
+ });
143
+ });
144
+
145
+ describe('Error handling', () => {
146
+ it('should return null if API request fails', async () => {
147
+ vi.mocked(mockCache.get).mockResolvedValue(null);
148
+
149
+ mockFetch.mockResolvedValue({
150
+ ok: false,
151
+ status: 404,
152
+ statusText: 'Not Found'
153
+ } as Response);
154
+
155
+ const options: RemoteConfigOptions = {
156
+ apiUrl: 'https://kya.vouched.id',
157
+ apiKey: 'test-key',
158
+ projectId: 'test-project',
159
+ fetchProvider: mockFetch
160
+ };
161
+
162
+ const result = await fetchRemoteConfig(options, mockCache);
163
+
164
+ expect(result).toBeNull();
165
+ });
166
+
167
+ it('should return null if API throws error', async () => {
168
+ vi.mocked(mockCache.get).mockResolvedValue(null);
169
+
170
+ mockFetch.mockRejectedValue(new Error('Network error'));
171
+
172
+ const options: RemoteConfigOptions = {
173
+ apiUrl: 'https://kya.vouched.id',
174
+ apiKey: 'test-key',
175
+ projectId: 'test-project',
176
+ fetchProvider: mockFetch
177
+ };
178
+
179
+ const result = await fetchRemoteConfig(options, mockCache);
180
+
181
+ expect(result).toBeNull();
182
+ });
183
+
184
+ it('should return null if neither projectId nor agentDid provided', async () => {
185
+ const options: RemoteConfigOptions = {
186
+ apiUrl: 'https://kya.vouched.id',
187
+ apiKey: 'test-key',
188
+ fetchProvider: mockFetch
189
+ };
190
+
191
+ const result = await fetchRemoteConfig(options, mockCache);
192
+
193
+ expect(result).toBeNull();
194
+ expect(mockFetch).not.toHaveBeenCalled();
195
+ });
196
+
197
+ it('should handle cache read errors gracefully', async () => {
198
+ vi.mocked(mockCache.get).mockRejectedValue(new Error('Cache error'));
199
+
200
+ const config: MCPIConfig = {
201
+ environment: 'production'
202
+ };
203
+
204
+ mockFetch.mockResolvedValue({
205
+ ok: true,
206
+ json: async () => ({ success: true, data: config })
207
+ } as Response);
208
+
209
+ const options: RemoteConfigOptions = {
210
+ apiUrl: 'https://kya.vouched.id',
211
+ apiKey: 'test-key',
212
+ projectId: 'test-project',
213
+ fetchProvider: mockFetch
214
+ };
215
+
216
+ const result = await fetchRemoteConfig(options, mockCache);
217
+
218
+ expect(result).toEqual(config);
219
+ });
220
+ });
221
+
222
+ describe('Response format handling', () => {
223
+ it('should handle different API response formats', async () => {
224
+ vi.mocked(mockCache.get).mockResolvedValue(null);
225
+
226
+ const config: MCPIConfig = {
227
+ environment: 'production'
228
+ };
229
+
230
+ // Format 1: { config: {...} }
231
+ mockFetch.mockResolvedValueOnce({
232
+ ok: true,
233
+ json: async () => ({ config })
234
+ } as Response);
235
+
236
+ const options: RemoteConfigOptions = {
237
+ apiUrl: 'https://kya.vouched.id',
238
+ apiKey: 'test-key',
239
+ projectId: 'test-project',
240
+ fetchProvider: mockFetch
241
+ };
242
+
243
+ const result1 = await fetchRemoteConfig(options, mockCache);
244
+ expect(result1).toEqual(config);
245
+
246
+ // Format 2: { data: { config: {...} } }
247
+ mockCache.get.mockResolvedValue(null);
248
+ mockFetch.mockResolvedValueOnce({
249
+ ok: true,
250
+ json: async () => ({ data: { config } })
251
+ } as Response);
252
+
253
+ const result2 = await fetchRemoteConfig(options, mockCache);
254
+ expect(result2).toEqual(config);
255
+
256
+ // Format 3: { success: true, data: {...} }
257
+ mockCache.get.mockResolvedValue(null);
258
+ mockFetch.mockResolvedValueOnce({
259
+ ok: true,
260
+ json: async () => ({ success: true, data: config })
261
+ } as Response);
262
+
263
+ const result3 = await fetchRemoteConfig(options, mockCache);
264
+ expect(result3).toEqual(config);
265
+ });
266
+ });
267
+ });
268
+
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Remote Configuration Fetching
3
+ *
4
+ * Service for fetching configuration from remote APIs (AgentShield dashboard)
5
+ * with caching support for performance optimization.
6
+ *
7
+ * @module @kya-os/mcp-i-core/config/remote-config
8
+ */
9
+
10
+ import type { MCPIConfig } from '@kya-os/contracts/config';
11
+ import { AGENTSHIELD_ENDPOINTS } from '@kya-os/contracts/agentshield-api';
12
+
13
+ /**
14
+ * Options for fetching remote configuration
15
+ */
16
+ export interface RemoteConfigOptions {
17
+ /**
18
+ * API base URL
19
+ * @example 'https://kya.vouched.id'
20
+ */
21
+ apiUrl: string;
22
+
23
+ /**
24
+ * API key for authentication
25
+ */
26
+ apiKey: string;
27
+
28
+ /**
29
+ * Project ID (optional, preferred over agentDid)
30
+ * Used for project-scoped configuration
31
+ */
32
+ projectId?: string;
33
+
34
+ /**
35
+ * Agent DID (optional, used when projectId not available)
36
+ * Used for agent-scoped configuration
37
+ */
38
+ agentDid?: string;
39
+
40
+ /**
41
+ * Cache TTL in milliseconds
42
+ * @default 300000 (5 minutes)
43
+ */
44
+ cacheTtl?: number;
45
+
46
+ /**
47
+ * Fetch provider function
48
+ * Platform-agnostic fetch implementation
49
+ */
50
+ fetchProvider: (url: string, options: RequestInit) => Promise<Response>;
51
+ }
52
+
53
+ /**
54
+ * Cache interface for remote configuration
55
+ * Abstracts platform-specific caching (KV, Redis, Memory, etc.)
56
+ */
57
+ export interface RemoteConfigCache {
58
+ /**
59
+ * Get a cached value
60
+ */
61
+ get(key: string): Promise<string | null>;
62
+
63
+ /**
64
+ * Set a cached value with TTL
65
+ */
66
+ set(key: string, value: string, ttl: number): Promise<void>;
67
+ }
68
+
69
+ /**
70
+ * Fetch configuration from remote API (AgentShield dashboard)
71
+ *
72
+ * Attempts to fetch configuration from the AgentShield API with caching support.
73
+ * Falls back gracefully if remote fetch fails.
74
+ *
75
+ * @param options - Remote config options
76
+ * @param cache - Optional cache implementation
77
+ * @returns Configuration object or null if fetch fails
78
+ */
79
+ export async function fetchRemoteConfig(
80
+ options: RemoteConfigOptions,
81
+ cache?: RemoteConfigCache
82
+ ): Promise<MCPIConfig | null> {
83
+ const { apiUrl, apiKey, projectId, agentDid, cacheTtl = 300000, fetchProvider } = options;
84
+
85
+ // Generate cache key
86
+ const cacheKey = projectId
87
+ ? `config:project:${projectId}`
88
+ : agentDid
89
+ ? `config:agent:${agentDid}`
90
+ : null;
91
+
92
+ // Try cache first
93
+ if (cache && cacheKey) {
94
+ try {
95
+ const cached = await cache.get(cacheKey);
96
+ if (cached) {
97
+ try {
98
+ const parsed = JSON.parse(cached) as { config: MCPIConfig; expiresAt: number };
99
+ if (parsed.expiresAt > Date.now()) {
100
+ return parsed.config;
101
+ }
102
+ } catch {
103
+ // Invalid cache entry, continue to fetch
104
+ }
105
+ }
106
+ } catch (error) {
107
+ // Cache read failed, continue to fetch
108
+ console.warn('[RemoteConfig] Cache read failed:', error);
109
+ }
110
+ }
111
+
112
+ // Fetch from API
113
+ try {
114
+ // Build API URL
115
+ let url: string;
116
+ if (projectId) {
117
+ // Use project-scoped endpoint (preferred)
118
+ url = `${apiUrl}${AGENTSHIELD_ENDPOINTS.CONFIG(projectId)}`;
119
+ } else if (agentDid) {
120
+ // Use agent-scoped endpoint
121
+ url = `${apiUrl}/api/v1/bouncer/config?agent_did=${encodeURIComponent(agentDid)}`;
122
+ } else {
123
+ console.warn('[RemoteConfig] Neither projectId nor agentDid provided');
124
+ return null;
125
+ }
126
+
127
+ const response = await fetchProvider(url, {
128
+ headers: {
129
+ 'Authorization': `Bearer ${apiKey}`,
130
+ 'Content-Type': 'application/json'
131
+ }
132
+ });
133
+
134
+ if (!response.ok) {
135
+ console.warn(`[RemoteConfig] API returned ${response.status}: ${response.statusText}`);
136
+ return null;
137
+ }
138
+
139
+ const data = await response.json();
140
+
141
+ // Extract config from API response
142
+ // API response format: { success: boolean, data: { config: MCPIConfig } }
143
+ const responseData = data as { config?: MCPIConfig; data?: { config?: MCPIConfig }; success?: boolean };
144
+ const config = responseData.config || responseData.data?.config || (responseData.success ? responseData.data as MCPIConfig | null : null) as MCPIConfig | null;
145
+
146
+ if (!config) {
147
+ console.warn('[RemoteConfig] No config found in API response');
148
+ return null;
149
+ }
150
+
151
+ // Cache the result
152
+ if (cache && cacheKey) {
153
+ try {
154
+ await cache.set(
155
+ cacheKey,
156
+ JSON.stringify({
157
+ config,
158
+ expiresAt: Date.now() + cacheTtl
159
+ }),
160
+ cacheTtl
161
+ );
162
+ } catch (error) {
163
+ // Cache write failed, but we got the config so continue
164
+ console.warn('[RemoteConfig] Cache write failed:', error);
165
+ }
166
+ }
167
+
168
+ return config as MCPIConfig;
169
+ } catch (error) {
170
+ console.warn('[RemoteConfig] Failed to fetch config:', error);
171
+ return null;
172
+ }
173
+ }
174
+