@kya-os/mcp-i-core 1.3.3 → 1.3.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-config.service.d.ts","sourceRoot":"","sources":["../../src/services/oauth-config.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,0BAA0B,CAAC;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAGvE,MAAM,WAAW,wBAAwB;IACvC,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAEhB,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IAEf,8CAA8C;IAC9C,aAAa,EAAE,aAAa,CAAC;IAE7B,mDAAmD;IACnD,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAEzB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACpD;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAGZ;gBAEU,MAAM,EAAE,wBAAwB;IAW5C;;;;;;;;OAQG;IACG,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAuF7D;;;;OAIG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlD;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;CAIrC"}
1
+ {"version":3,"file":"oauth-config.service.d.ts","sourceRoot":"","sources":["../../src/services/oauth-config.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,0BAA0B,CAAC;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAGvE,MAAM,WAAW,wBAAwB;IACvC,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAEhB,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IAEf,8CAA8C;IAC9C,aAAa,EAAE,aAAa,CAAC;IAE7B,mDAAmD;IACnD,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAEzB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACpD;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAGZ;gBAEU,MAAM,EAAE,wBAAwB;IAW5C;;;;;;;;OAQG;IACG,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IA8G7D;;;;OAIG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlD;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;CAIrC"}
@@ -66,17 +66,39 @@ class OAuthConfigService {
66
66
  if (!result.success || !result.data) {
67
67
  throw new Error("Invalid API response: missing success or data field");
68
68
  }
69
- // Parse providers object
70
- const providers = result.data.providers || {};
71
- if (typeof providers !== "object" || Array.isArray(providers)) {
69
+ // Parse providers object with snake_case → camelCase mapping
70
+ // AgentShield API may return snake_case fields, but OAuthProvider interface uses camelCase
71
+ const rawProviders = result.data.providers || {};
72
+ if (typeof rawProviders !== "object" || Array.isArray(rawProviders)) {
72
73
  throw new Error("Invalid API response: providers must be an object, not an array");
73
74
  }
75
+ // Map each provider's fields from snake_case to camelCase
76
+ const providers = {};
77
+ for (const [name, raw] of Object.entries(rawProviders)) {
78
+ const p = raw;
79
+ providers[name] = {
80
+ clientId: (p.clientId ?? p.client_id ?? ""),
81
+ clientSecret: (p.clientSecret ?? p.client_secret ?? null),
82
+ authorizationUrl: (p.authorizationUrl ?? p.authorization_url ?? ""),
83
+ tokenUrl: (p.tokenUrl ?? p.token_url ?? ""),
84
+ userInfoUrl: (p.userInfoUrl ?? p.user_info_url),
85
+ supportsPKCE: (p.supportsPKCE ?? p.supports_pkce ?? false),
86
+ requiresClientSecret: (p.requiresClientSecret ?? p.requires_client_secret ?? true),
87
+ scopes: (p.scopes ?? []),
88
+ defaultScopes: (p.defaultScopes ?? p.default_scopes),
89
+ proxyMode: (p.proxyMode ?? p.proxy_mode ?? false),
90
+ customParams: (p.customParams ?? p.custom_params),
91
+ tokenEndpointAuthMethod: (p.tokenEndpointAuthMethod ?? p.token_endpoint_auth_method),
92
+ responseType: (p.responseType ?? p.response_type),
93
+ grantType: (p.grantType ?? p.grant_type),
94
+ };
95
+ }
74
96
  // Build OAuthConfig object
75
97
  // Extract configuredProvider from API response - this indicates which provider
76
98
  // the user has actually configured in AgentShield dashboard
77
- const configuredProvider = result.data.configuredProvider || null;
99
+ const configuredProvider = result.data.configuredProvider ?? result.data.configured_provider ?? null;
78
100
  const config = {
79
- providers: providers,
101
+ providers,
80
102
  configuredProvider,
81
103
  };
82
104
  // Cache config
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-config.service.js","sourceRoot":"","sources":["../../src/services/oauth-config.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oauth-config.service.js","sourceRoot":"","sources":["../../src/services/oauth-config.service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kya-os/mcp-i-core",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "description": "Core runtime and types for MCP-I framework",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,125 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { ToolProtectionService } from "../../services/tool-protection.service";
3
+ import { InMemoryToolProtectionCache } from "../../cache/tool-protection-cache";
4
+
5
+ describe("Cache Busting in clearAndRefresh", () => {
6
+ let cache: InMemoryToolProtectionCache;
7
+ let service: ToolProtectionService;
8
+ const agentDid = "did:key:test-agent";
9
+ const projectId = "test-project-123";
10
+
11
+ beforeEach(() => {
12
+ cache = new InMemoryToolProtectionCache();
13
+ service = new ToolProtectionService(
14
+ {
15
+ apiUrl: "https://test.agentshield.com",
16
+ apiKey: "test-api-key",
17
+ projectId,
18
+ cacheTtl: 300000,
19
+ debug: true,
20
+ },
21
+ cache
22
+ );
23
+ });
24
+
25
+ it("clearAndRefresh should call fetchFromApi with bypassCDNCache: true", async () => {
26
+ // Spy on the private fetchFromApi method
27
+ const fetchSpy = vi.spyOn(service as any, "fetchFromApi").mockResolvedValue({
28
+ success: true,
29
+ data: {
30
+ toolProtections: {
31
+ greet: { requiresDelegation: true, requiredScopes: ["greet:execute"] },
32
+ },
33
+ },
34
+ });
35
+
36
+ await service.clearAndRefresh(agentDid);
37
+
38
+ // Verify fetchFromApi was called with bypassCDNCache: true
39
+ expect(fetchSpy).toHaveBeenCalledTimes(1);
40
+ expect(fetchSpy).toHaveBeenCalledWith(agentDid, { bypassCDNCache: true });
41
+ });
42
+
43
+ it("fetchFromApi should add cache-busting query param when bypassCDNCache is true", async () => {
44
+ // Mock global fetch
45
+ const fetchMock = vi.fn().mockResolvedValue({
46
+ ok: true,
47
+ json: () => Promise.resolve({ success: true, data: { toolProtections: {} } }),
48
+ });
49
+ global.fetch = fetchMock;
50
+
51
+ // Call fetchFromApi directly with bypassCDNCache: true
52
+ await (service as any).fetchFromApi(agentDid, { bypassCDNCache: true });
53
+
54
+ // Verify the URL contains cache-busting timestamp
55
+ const calledUrl = fetchMock.mock.calls[0][0] as string;
56
+ expect(calledUrl).toContain("?_t=");
57
+ expect(calledUrl).toMatch(/\?_t=\d+$/); // Ends with ?_t=<timestamp>
58
+ });
59
+
60
+ it("fetchFromApi should add Cache-Control headers when bypassCDNCache is true", async () => {
61
+ // Mock global fetch
62
+ const fetchMock = vi.fn().mockResolvedValue({
63
+ ok: true,
64
+ json: () => Promise.resolve({ success: true, data: { toolProtections: {} } }),
65
+ });
66
+ global.fetch = fetchMock;
67
+
68
+ // Call fetchFromApi directly with bypassCDNCache: true
69
+ await (service as any).fetchFromApi(agentDid, { bypassCDNCache: true });
70
+
71
+ // Verify the headers contain cache-control
72
+ const calledOptions = fetchMock.mock.calls[0][1] as RequestInit;
73
+ const headers = calledOptions.headers as Record<string, string>;
74
+
75
+ expect(headers["Cache-Control"]).toBe("no-cache, no-store, must-revalidate");
76
+ expect(headers["Pragma"]).toBe("no-cache");
77
+ });
78
+
79
+ it("fetchFromApi should NOT add cache-busting when bypassCDNCache is false/undefined", async () => {
80
+ // Mock global fetch
81
+ const fetchMock = vi.fn().mockResolvedValue({
82
+ ok: true,
83
+ json: () => Promise.resolve({ success: true, data: { toolProtections: {} } }),
84
+ });
85
+ global.fetch = fetchMock;
86
+
87
+ // Call fetchFromApi without bypassCDNCache
88
+ await (service as any).fetchFromApi(agentDid);
89
+
90
+ // Verify the URL does NOT contain cache-busting timestamp
91
+ const calledUrl = fetchMock.mock.calls[0][0] as string;
92
+ expect(calledUrl).not.toContain("?_t=");
93
+
94
+ // Verify no cache-control header
95
+ const calledOptions = fetchMock.mock.calls[0][1] as RequestInit;
96
+ const headers = calledOptions.headers as Record<string, string>;
97
+ expect(headers["Cache-Control"]).toBeUndefined();
98
+ });
99
+
100
+ it("cache should be empty after clearAndRefresh deletes it", async () => {
101
+ const cacheKey = `config:tool-protections:${projectId}`;
102
+
103
+ // Pre-populate cache
104
+ await cache.set(cacheKey, { toolProtections: { old: { requiresDelegation: false, requiredScopes: [] } } }, 300000);
105
+
106
+ // Verify cache has data
107
+ const before = await cache.get(cacheKey);
108
+ expect(before).not.toBeNull();
109
+
110
+ // Mock fetchFromApi to avoid network call
111
+ vi.spyOn(service as any, "fetchFromApi").mockResolvedValue({
112
+ success: true,
113
+ data: { toolProtections: {} },
114
+ });
115
+
116
+ // Clear and refresh
117
+ await service.clearAndRefresh(agentDid);
118
+
119
+ // Note: clearAndRefresh deletes then re-populates with fresh data
120
+ // But since our mock returns empty toolProtections, cache should have empty config
121
+ const after = await cache.get(cacheKey);
122
+ expect(after).toBeDefined();
123
+ });
124
+ });
125
+
@@ -108,20 +108,43 @@ export class OAuthConfigService {
108
108
  throw new Error("Invalid API response: missing success or data field");
109
109
  }
110
110
 
111
- // Parse providers object
112
- const providers = result.data.providers || {};
113
- if (typeof providers !== "object" || Array.isArray(providers)) {
111
+ // Parse providers object with snake_case → camelCase mapping
112
+ // AgentShield API may return snake_case fields, but OAuthProvider interface uses camelCase
113
+ const rawProviders = result.data.providers || {};
114
+ if (typeof rawProviders !== "object" || Array.isArray(rawProviders)) {
114
115
  throw new Error(
115
116
  "Invalid API response: providers must be an object, not an array"
116
117
  );
117
118
  }
118
119
 
120
+ // Map each provider's fields from snake_case to camelCase
121
+ const providers: Record<string, OAuthProvider> = {};
122
+ for (const [name, raw] of Object.entries(rawProviders)) {
123
+ const p = raw as Record<string, unknown>;
124
+ providers[name] = {
125
+ clientId: (p.clientId ?? p.client_id ?? "") as string,
126
+ clientSecret: (p.clientSecret ?? p.client_secret ?? null) as string | null,
127
+ authorizationUrl: (p.authorizationUrl ?? p.authorization_url ?? "") as string,
128
+ tokenUrl: (p.tokenUrl ?? p.token_url ?? "") as string,
129
+ userInfoUrl: (p.userInfoUrl ?? p.user_info_url) as string | undefined,
130
+ supportsPKCE: (p.supportsPKCE ?? p.supports_pkce ?? false) as boolean,
131
+ requiresClientSecret: (p.requiresClientSecret ?? p.requires_client_secret ?? true) as boolean,
132
+ scopes: (p.scopes ?? []) as string[],
133
+ defaultScopes: (p.defaultScopes ?? p.default_scopes) as string[] | undefined,
134
+ proxyMode: (p.proxyMode ?? p.proxy_mode ?? false) as boolean,
135
+ customParams: (p.customParams ?? p.custom_params) as Record<string, string> | undefined,
136
+ tokenEndpointAuthMethod: (p.tokenEndpointAuthMethod ?? p.token_endpoint_auth_method) as "client_secret_post" | "client_secret_basic" | undefined,
137
+ responseType: (p.responseType ?? p.response_type) as string | undefined,
138
+ grantType: (p.grantType ?? p.grant_type) as string | undefined,
139
+ };
140
+ }
141
+
119
142
  // Build OAuthConfig object
120
143
  // Extract configuredProvider from API response - this indicates which provider
121
144
  // the user has actually configured in AgentShield dashboard
122
- const configuredProvider = result.data.configuredProvider || null;
145
+ const configuredProvider = result.data.configuredProvider ?? (result.data as any).configured_provider ?? null;
123
146
  const config: OAuthConfig = {
124
- providers: providers as Record<string, OAuthProvider>,
147
+ providers,
125
148
  configuredProvider,
126
149
  };
127
150