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

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 (225) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/.turbo/turbo-build.log +4 -0
  3. package/.turbo/turbo-test.log +2979 -0
  4. package/COMPLIANCE_IMPROVEMENT_REPORT.md +483 -0
  5. package/Composer 3.md +615 -0
  6. package/GPT-5.md +1169 -0
  7. package/OPUS-plan.md +352 -0
  8. package/PHASE_3_AND_4.1_SUMMARY.md +585 -0
  9. package/PHASE_3_SUMMARY.md +317 -0
  10. package/PHASE_4.1.3_SUMMARY.md +428 -0
  11. package/PHASE_4.1_COMPLETE.md +525 -0
  12. package/PHASE_4_USER_DID_IDENTITY_LINKING_PLAN.md +1240 -0
  13. package/SCHEMA_COMPLIANCE_REPORT.md +275 -0
  14. package/TEST_PLAN.md +571 -0
  15. package/coverage/coverage-final.json +57 -0
  16. package/dist/__tests__/utils/mock-providers.d.ts +1 -2
  17. package/dist/__tests__/utils/mock-providers.d.ts.map +1 -1
  18. package/dist/__tests__/utils/mock-providers.js.map +1 -1
  19. package/dist/cache/oauth-config-cache.d.ts +69 -0
  20. package/dist/cache/oauth-config-cache.d.ts.map +1 -0
  21. package/dist/cache/oauth-config-cache.js +76 -0
  22. package/dist/cache/oauth-config-cache.js.map +1 -0
  23. package/dist/identity/idp-token-resolver.d.ts +53 -0
  24. package/dist/identity/idp-token-resolver.d.ts.map +1 -0
  25. package/dist/identity/idp-token-resolver.js +108 -0
  26. package/dist/identity/idp-token-resolver.js.map +1 -0
  27. package/dist/identity/idp-token-storage.interface.d.ts +42 -0
  28. package/dist/identity/idp-token-storage.interface.d.ts.map +1 -0
  29. package/dist/identity/idp-token-storage.interface.js +12 -0
  30. package/dist/identity/idp-token-storage.interface.js.map +1 -0
  31. package/dist/identity/user-did-manager.d.ts +39 -1
  32. package/dist/identity/user-did-manager.d.ts.map +1 -1
  33. package/dist/identity/user-did-manager.js +69 -3
  34. package/dist/identity/user-did-manager.js.map +1 -1
  35. package/dist/index.d.ts +22 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +39 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/runtime/audit-logger.d.ts +37 -0
  40. package/dist/runtime/audit-logger.d.ts.map +1 -0
  41. package/dist/runtime/audit-logger.js +9 -0
  42. package/dist/runtime/audit-logger.js.map +1 -0
  43. package/dist/runtime/base.d.ts +58 -2
  44. package/dist/runtime/base.d.ts.map +1 -1
  45. package/dist/runtime/base.js +266 -11
  46. package/dist/runtime/base.js.map +1 -1
  47. package/dist/services/access-control.service.d.ts.map +1 -1
  48. package/dist/services/access-control.service.js +200 -35
  49. package/dist/services/access-control.service.js.map +1 -1
  50. package/dist/services/authorization/authorization-registry.d.ts +29 -0
  51. package/dist/services/authorization/authorization-registry.d.ts.map +1 -0
  52. package/dist/services/authorization/authorization-registry.js +57 -0
  53. package/dist/services/authorization/authorization-registry.js.map +1 -0
  54. package/dist/services/authorization/types.d.ts +53 -0
  55. package/dist/services/authorization/types.d.ts.map +1 -0
  56. package/dist/services/authorization/types.js +10 -0
  57. package/dist/services/authorization/types.js.map +1 -0
  58. package/dist/services/batch-delegation.service.d.ts +53 -0
  59. package/dist/services/batch-delegation.service.d.ts.map +1 -0
  60. package/dist/services/batch-delegation.service.js +95 -0
  61. package/dist/services/batch-delegation.service.js.map +1 -0
  62. package/dist/services/oauth-config.service.d.ts +53 -0
  63. package/dist/services/oauth-config.service.d.ts.map +1 -0
  64. package/dist/services/oauth-config.service.js +119 -0
  65. package/dist/services/oauth-config.service.js.map +1 -0
  66. package/dist/services/oauth-provider-registry.d.ts +88 -0
  67. package/dist/services/oauth-provider-registry.d.ts.map +1 -0
  68. package/dist/services/oauth-provider-registry.js +128 -0
  69. package/dist/services/oauth-provider-registry.js.map +1 -0
  70. package/dist/services/oauth-service.d.ts +77 -0
  71. package/dist/services/oauth-service.d.ts.map +1 -0
  72. package/dist/services/oauth-service.js +348 -0
  73. package/dist/services/oauth-service.js.map +1 -0
  74. package/dist/services/oauth-token-retrieval.service.d.ts +49 -0
  75. package/dist/services/oauth-token-retrieval.service.d.ts.map +1 -0
  76. package/dist/services/oauth-token-retrieval.service.js +150 -0
  77. package/dist/services/oauth-token-retrieval.service.js.map +1 -0
  78. package/dist/services/provider-resolver.d.ts +48 -0
  79. package/dist/services/provider-resolver.d.ts.map +1 -0
  80. package/dist/services/provider-resolver.js +121 -0
  81. package/dist/services/provider-resolver.js.map +1 -0
  82. package/dist/services/provider-validator.d.ts +55 -0
  83. package/dist/services/provider-validator.d.ts.map +1 -0
  84. package/dist/services/provider-validator.js +135 -0
  85. package/dist/services/provider-validator.js.map +1 -0
  86. package/dist/services/tool-context-builder.d.ts +57 -0
  87. package/dist/services/tool-context-builder.d.ts.map +1 -0
  88. package/dist/services/tool-context-builder.js +125 -0
  89. package/dist/services/tool-context-builder.js.map +1 -0
  90. package/dist/services/tool-protection.service.d.ts +87 -10
  91. package/dist/services/tool-protection.service.d.ts.map +1 -1
  92. package/dist/services/tool-protection.service.js +282 -112
  93. package/dist/services/tool-protection.service.js.map +1 -1
  94. package/dist/types/oauth-required-error.d.ts +40 -0
  95. package/dist/types/oauth-required-error.d.ts.map +1 -0
  96. package/dist/types/oauth-required-error.js +40 -0
  97. package/dist/types/oauth-required-error.js.map +1 -0
  98. package/dist/utils/did-helpers.d.ts +33 -0
  99. package/dist/utils/did-helpers.d.ts.map +1 -1
  100. package/dist/utils/did-helpers.js +40 -0
  101. package/dist/utils/did-helpers.js.map +1 -1
  102. package/dist/utils/index.d.ts +1 -0
  103. package/dist/utils/index.d.ts.map +1 -1
  104. package/dist/utils/index.js +1 -0
  105. package/dist/utils/index.js.map +1 -1
  106. package/docs/API_REFERENCE.md +1362 -0
  107. package/docs/COMPLIANCE_MATRIX.md +691 -0
  108. package/docs/STATUSLIST2021_GUIDE.md +696 -0
  109. package/docs/W3C_VC_DELEGATION_GUIDE.md +710 -0
  110. package/package.json +24 -50
  111. package/scripts/audit-compliance.ts +724 -0
  112. package/src/__tests__/cache/tool-protection-cache.test.ts +640 -0
  113. package/src/__tests__/config/provider-runtime-config.test.ts +309 -0
  114. package/src/__tests__/delegation-e2e.test.ts +690 -0
  115. package/src/__tests__/identity/user-did-manager.test.ts +213 -0
  116. package/src/__tests__/index.test.ts +56 -0
  117. package/src/__tests__/integration/full-flow.test.ts +776 -0
  118. package/src/__tests__/integration.test.ts +281 -0
  119. package/src/__tests__/providers/base.test.ts +173 -0
  120. package/src/__tests__/providers/memory.test.ts +319 -0
  121. package/src/__tests__/regression/phase2-regression.test.ts +429 -0
  122. package/src/__tests__/runtime/audit-logger.test.ts +154 -0
  123. package/src/__tests__/runtime/base-extensions.test.ts +593 -0
  124. package/src/__tests__/runtime/base.test.ts +869 -0
  125. package/src/__tests__/runtime/delegation-flow.test.ts +164 -0
  126. package/src/__tests__/runtime/proof-client-did.test.ts +375 -0
  127. package/src/__tests__/runtime/route-interception.test.ts +686 -0
  128. package/src/__tests__/runtime/tool-protection-enforcement.test.ts +908 -0
  129. package/src/__tests__/services/agentshield-integration.test.ts +784 -0
  130. package/src/__tests__/services/provider-resolver-edge-cases.test.ts +591 -0
  131. package/src/__tests__/services/tool-protection-oauth-provider.test.ts +480 -0
  132. package/src/__tests__/services/tool-protection.service.test.ts +1366 -0
  133. package/src/__tests__/utils/mock-providers.ts +340 -0
  134. package/src/cache/oauth-config-cache.d.ts +69 -0
  135. package/src/cache/oauth-config-cache.d.ts.map +1 -0
  136. package/src/cache/oauth-config-cache.js.map +1 -0
  137. package/src/cache/oauth-config-cache.ts +123 -0
  138. package/src/cache/tool-protection-cache.ts +171 -0
  139. package/src/compliance/EXAMPLE.md +412 -0
  140. package/src/compliance/__tests__/schema-verifier.test.ts +797 -0
  141. package/src/compliance/index.ts +8 -0
  142. package/src/compliance/schema-registry.ts +460 -0
  143. package/src/compliance/schema-verifier.ts +708 -0
  144. package/src/config/__tests__/remote-config.spec.ts +268 -0
  145. package/src/config/remote-config.ts +174 -0
  146. package/src/config.ts +309 -0
  147. package/src/delegation/__tests__/audience-validator.test.ts +112 -0
  148. package/src/delegation/__tests__/bitstring.test.ts +346 -0
  149. package/src/delegation/__tests__/cascading-revocation.test.ts +628 -0
  150. package/src/delegation/__tests__/delegation-graph.test.ts +584 -0
  151. package/src/delegation/__tests__/utils.test.ts +152 -0
  152. package/src/delegation/__tests__/vc-issuer.test.ts +442 -0
  153. package/src/delegation/__tests__/vc-verifier.test.ts +922 -0
  154. package/src/delegation/audience-validator.ts +52 -0
  155. package/src/delegation/bitstring.ts +278 -0
  156. package/src/delegation/cascading-revocation.ts +370 -0
  157. package/src/delegation/delegation-graph.ts +299 -0
  158. package/src/delegation/index.ts +14 -0
  159. package/src/delegation/statuslist-manager.ts +353 -0
  160. package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +366 -0
  161. package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +228 -0
  162. package/src/delegation/storage/index.ts +9 -0
  163. package/src/delegation/storage/memory-graph-storage.ts +178 -0
  164. package/src/delegation/storage/memory-statuslist-storage.ts +77 -0
  165. package/src/delegation/utils.ts +42 -0
  166. package/src/delegation/vc-issuer.ts +232 -0
  167. package/src/delegation/vc-verifier.ts +568 -0
  168. package/src/identity/idp-token-resolver.ts +147 -0
  169. package/src/identity/idp-token-storage.interface.ts +59 -0
  170. package/src/identity/user-did-manager.ts +370 -0
  171. package/src/index.ts +260 -0
  172. package/src/providers/base.d.ts +91 -0
  173. package/src/providers/base.d.ts.map +1 -0
  174. package/src/providers/base.js.map +1 -0
  175. package/src/providers/base.ts +96 -0
  176. package/src/providers/memory.ts +142 -0
  177. package/src/runtime/audit-logger.ts +39 -0
  178. package/src/runtime/base.ts +1329 -0
  179. package/src/services/__tests__/access-control.integration.test.ts +443 -0
  180. package/src/services/__tests__/access-control.proof-response-validation.test.ts +578 -0
  181. package/src/services/__tests__/access-control.service.test.ts +970 -0
  182. package/src/services/__tests__/batch-delegation.service.test.ts +351 -0
  183. package/src/services/__tests__/crypto.service.test.ts +531 -0
  184. package/src/services/__tests__/oauth-provider-registry.test.ts +142 -0
  185. package/src/services/__tests__/proof-verifier.integration.test.ts +485 -0
  186. package/src/services/__tests__/proof-verifier.test.ts +489 -0
  187. package/src/services/__tests__/provider-resolution.integration.test.ts +202 -0
  188. package/src/services/__tests__/provider-resolver.test.ts +213 -0
  189. package/src/services/__tests__/storage.service.test.ts +358 -0
  190. package/src/services/access-control.service.ts +990 -0
  191. package/src/services/authorization/authorization-registry.ts +66 -0
  192. package/src/services/authorization/types.ts +71 -0
  193. package/src/services/batch-delegation.service.ts +137 -0
  194. package/src/services/crypto.service.ts +302 -0
  195. package/src/services/errors.ts +76 -0
  196. package/src/services/index.ts +9 -0
  197. package/src/services/oauth-config.service.d.ts +53 -0
  198. package/src/services/oauth-config.service.d.ts.map +1 -0
  199. package/src/services/oauth-config.service.js.map +1 -0
  200. package/src/services/oauth-config.service.ts +169 -0
  201. package/src/services/oauth-provider-registry.d.ts +57 -0
  202. package/src/services/oauth-provider-registry.d.ts.map +1 -0
  203. package/src/services/oauth-provider-registry.js.map +1 -0
  204. package/src/services/oauth-provider-registry.ts +141 -0
  205. package/src/services/oauth-service.ts +510 -0
  206. package/src/services/oauth-token-retrieval.service.ts +245 -0
  207. package/src/services/proof-verifier.ts +478 -0
  208. package/src/services/provider-resolver.d.ts +48 -0
  209. package/src/services/provider-resolver.d.ts.map +1 -0
  210. package/src/services/provider-resolver.js.map +1 -0
  211. package/src/services/provider-resolver.ts +146 -0
  212. package/src/services/provider-validator.ts +170 -0
  213. package/src/services/storage.service.ts +566 -0
  214. package/src/services/tool-context-builder.ts +172 -0
  215. package/src/services/tool-protection.service.ts +958 -0
  216. package/src/types/oauth-required-error.ts +63 -0
  217. package/src/types/tool-protection.ts +155 -0
  218. package/src/utils/__tests__/did-helpers.test.ts +101 -0
  219. package/src/utils/base64.ts +148 -0
  220. package/src/utils/cors.ts +83 -0
  221. package/src/utils/did-helpers.ts +150 -0
  222. package/src/utils/index.ts +8 -0
  223. package/src/utils/storage-keys.ts +278 -0
  224. package/tsconfig.json +21 -0
  225. package/vitest.config.ts +56 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Provider Resolver
3
+ *
4
+ * Resolves OAuth provider for tools using priority-based resolution strategy.
5
+ * Supports Phase 2+ tool-specific providers with backward compatibility for Phase 1.
6
+ *
7
+ * @package @kya-os/mcp-i-core
8
+ */
9
+ import type { ToolProtection } from "@kya-os/contracts/tool-protection";
10
+ import type { OAuthProviderRegistry } from "./oauth-provider-registry.js";
11
+ import type { OAuthConfigService } from "./oauth-config.service.js";
12
+ /**
13
+ * Resolves OAuth provider for tools with priority-based fallback strategy
14
+ *
15
+ * Priority order:
16
+ * 1. Tool-specific oauthProvider field (Phase 2+ preferred)
17
+ * 2. Scope prefix inference (fallback)
18
+ * 3. First configured provider (Phase 1 compatibility fallback)
19
+ * 4. Error if no provider can be resolved
20
+ */
21
+ export declare class ProviderResolver {
22
+ private registry;
23
+ private configService;
24
+ constructor(registry: OAuthProviderRegistry, configService: OAuthConfigService);
25
+ /**
26
+ * Resolve OAuth provider for a tool
27
+ *
28
+ * @param toolProtection - Tool protection configuration
29
+ * @param projectId - Project ID for fetching provider config
30
+ * @returns Provider name (never null - throws if cannot resolve)
31
+ * @throws Error if provider cannot be resolved
32
+ */
33
+ resolveProvider(toolProtection: ToolProtection, projectId: string): Promise<string>;
34
+ /**
35
+ * Infer provider from scope prefixes
36
+ *
37
+ * Used as Priority 2 fallback when oauthProvider is not specified.
38
+ * Examples:
39
+ * - github:repo:read → github
40
+ * - gmail:read → google
41
+ * - microsoft:calendar:read → microsoft
42
+ *
43
+ * @param scopes - Required scopes for the tool
44
+ * @returns Provider name if uniquely inferred, null otherwise
45
+ */
46
+ private inferProviderFromScopes;
47
+ }
48
+ //# sourceMappingURL=provider-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-resolver.d.ts","sourceRoot":"","sources":["provider-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE;;;;;;;;GAQG;AACH,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,aAAa;gBADb,QAAQ,EAAE,qBAAqB,EAC/B,aAAa,EAAE,kBAAkB;IAG3C;;;;;;;OAOG;IACG,eAAe,CACnB,cAAc,EAAE,cAAc,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC;IA6ClB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,uBAAuB;CAoChC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-resolver.js","sourceRoot":"","sources":["provider-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Provider Resolver
3
+ *
4
+ * Resolves OAuth provider for tools using priority-based resolution strategy.
5
+ * Supports Phase 2+ tool-specific providers with backward compatibility for Phase 1.
6
+ *
7
+ * @package @kya-os/mcp-i-core
8
+ */
9
+
10
+ import type { ToolProtection } from "@kya-os/contracts/tool-protection";
11
+ import type { OAuthProviderRegistry } from "./oauth-provider-registry.js";
12
+ import type { OAuthConfigService } from "./oauth-config.service.js";
13
+
14
+ /**
15
+ * Resolves OAuth provider for tools with priority-based fallback strategy
16
+ *
17
+ * Priority order:
18
+ * 1. Tool-specific oauthProvider field (Phase 2+ preferred)
19
+ * 2. Scope prefix inference (fallback)
20
+ * 3. Project-configured provider from AgentShield dashboard
21
+ * 4. Error if no provider can be resolved
22
+ */
23
+ export class ProviderResolver {
24
+ constructor(
25
+ private registry: OAuthProviderRegistry,
26
+ private configService: OAuthConfigService
27
+ ) {}
28
+
29
+ /**
30
+ * Resolve OAuth provider for a tool
31
+ *
32
+ * @param toolProtection - Tool protection configuration
33
+ * @param projectId - Project ID for fetching provider config
34
+ * @returns Provider name (never null - throws if cannot resolve)
35
+ * @throws Error if provider cannot be resolved
36
+ */
37
+ async resolveProvider(
38
+ toolProtection: ToolProtection,
39
+ projectId: string
40
+ ): Promise<string> {
41
+ // Priority 1: Tool-specific provider (Phase 2+ preferred)
42
+ if (toolProtection.oauthProvider) {
43
+ // Ensure registry is loaded before checking
44
+ if (this.registry.getProviderNames().length === 0) {
45
+ await this.registry.loadFromAgentShield(projectId);
46
+ }
47
+ if (!this.registry.hasProvider(toolProtection.oauthProvider)) {
48
+ throw new Error(
49
+ `Provider "${toolProtection.oauthProvider}" not configured for project "${projectId}". ` +
50
+ `Add provider in project settings.`
51
+ );
52
+ }
53
+ return toolProtection.oauthProvider;
54
+ }
55
+
56
+ // Priority 2: Scope prefix inference (fallback)
57
+ const inferredProvider = this.inferProviderFromScopes(
58
+ toolProtection.requiredScopes || []
59
+ );
60
+ if (inferredProvider) {
61
+ // Ensure registry is loaded before checking
62
+ if (this.registry.getProviderNames().length === 0) {
63
+ await this.registry.loadFromAgentShield(projectId);
64
+ }
65
+ if (this.registry.hasProvider(inferredProvider)) {
66
+ console.log(
67
+ `[ProviderResolver] Inferred provider "${inferredProvider}" from scopes`
68
+ );
69
+ return inferredProvider;
70
+ }
71
+ }
72
+
73
+ // Priority 3: Use explicitly configured provider from AgentShield dashboard
74
+ // This is the provider the user has actually configured, not just any available provider
75
+ await this.registry.loadFromAgentShield(projectId);
76
+ const configuredProvider = this.registry.getConfiguredProvider();
77
+
78
+ if (configuredProvider && this.registry.hasProvider(configuredProvider)) {
79
+ console.warn(
80
+ `[ProviderResolver] Tool does not specify oauthProvider. ` +
81
+ `Using project-configured provider "${configuredProvider}" as fallback. ` +
82
+ `Consider explicitly setting oauthProvider in tool protection config.`
83
+ );
84
+ return configuredProvider;
85
+ }
86
+
87
+ // Priority 4: Error if no provider is configured
88
+ // NOTE: We intentionally do NOT fall back to "first available provider" anymore
89
+ // because AgentShield returns ALL providers (even unconfigured ones).
90
+ // Only use providers explicitly configured by the user.
91
+ throw new Error(
92
+ `Tool requires OAuth but no provider is configured for project "${projectId}". ` +
93
+ `Configure an OAuth provider in AgentShield dashboard.`
94
+ );
95
+ }
96
+
97
+ /**
98
+ * Infer provider from scope prefixes
99
+ *
100
+ * Used as Priority 2 fallback when oauthProvider is not specified.
101
+ * Examples:
102
+ * - github:repo:read → github
103
+ * - gmail:read → google
104
+ * - microsoft:calendar:read → microsoft
105
+ *
106
+ * @param scopes - Required scopes for the tool
107
+ * @returns Provider name if uniquely inferred, null otherwise
108
+ */
109
+ private inferProviderFromScopes(scopes: string[]): string | null {
110
+ if (!scopes || scopes.length === 0) {
111
+ return null;
112
+ }
113
+
114
+ // Extract first part of scope (before first colon)
115
+ const scopePrefixes = scopes.map((scope) => {
116
+ const parts = scope.split(":");
117
+ return parts[0].toLowerCase();
118
+ });
119
+
120
+ // Provider mapping
121
+ const providerMap: Record<string, string> = {
122
+ github: "github",
123
+ google: "google",
124
+ gmail: "google", // gmail:read → google
125
+ calendar: "google", // calendar:read → google (if ambiguous, use project default)
126
+ microsoft: "microsoft",
127
+ outlook: "microsoft",
128
+ slack: "slack",
129
+ auth0: "auth0",
130
+ okta: "okta",
131
+ };
132
+
133
+ // Find unique provider
134
+ const providers = new Set(
135
+ scopePrefixes.map((prefix) => providerMap[prefix]).filter(Boolean)
136
+ );
137
+
138
+ if (providers.size === 1) {
139
+ return Array.from(providers)[0];
140
+ }
141
+
142
+ // Ambiguous or no prefix → return null (use project-level provider)
143
+ return null;
144
+ }
145
+ }
146
+
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Provider Validator
3
+ *
4
+ * Validates OAuth provider configurations for custom IDP support.
5
+ * Ensures provider configurations are valid before registration.
6
+ *
7
+ * @package @kya-os/mcp-i-core
8
+ */
9
+
10
+ import type { OAuthProvider } from "@kya-os/contracts/config";
11
+
12
+ /**
13
+ * Reserved OAuth parameters that cannot be overridden by custom parameters
14
+ */
15
+ const RESERVED_PARAMETERS = [
16
+ "response_type",
17
+ "client_id",
18
+ "redirect_uri",
19
+ "scope",
20
+ "state",
21
+ "code_challenge",
22
+ "code_challenge_method",
23
+ ] as const;
24
+
25
+ /**
26
+ * Validation error for provider configuration issues
27
+ */
28
+ export class ProviderValidationError extends Error {
29
+ constructor(message: string, public readonly field?: string) {
30
+ super(message);
31
+ this.name = "ProviderValidationError";
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Service for validating OAuth provider configurations
37
+ */
38
+ export class ProviderValidator {
39
+ /**
40
+ * Validate provider configuration
41
+ *
42
+ * @param provider - Provider configuration to validate
43
+ * @param name - Provider name (for error messages)
44
+ * @throws ProviderValidationError if validation fails
45
+ */
46
+ validate(provider: OAuthProvider, name: string): void {
47
+ // Validate required fields
48
+ if (!provider.clientId || provider.clientId.trim().length === 0) {
49
+ throw new ProviderValidationError(
50
+ `Provider "${name}" must have a clientId`,
51
+ "clientId"
52
+ );
53
+ }
54
+
55
+ if (!provider.authorizationUrl || provider.authorizationUrl.trim().length === 0) {
56
+ throw new ProviderValidationError(
57
+ `Provider "${name}" must have an authorizationUrl`,
58
+ "authorizationUrl"
59
+ );
60
+ }
61
+
62
+ if (!provider.tokenUrl || provider.tokenUrl.trim().length === 0) {
63
+ throw new ProviderValidationError(
64
+ `Provider "${name}" must have a tokenUrl`,
65
+ "tokenUrl"
66
+ );
67
+ }
68
+
69
+ // Validate URL formats
70
+ this.validateUrl(provider.authorizationUrl, name, "authorizationUrl");
71
+ this.validateUrl(provider.tokenUrl, name, "tokenUrl");
72
+
73
+ if (provider.userInfoUrl) {
74
+ this.validateUrl(provider.userInfoUrl, name, "userInfoUrl");
75
+ }
76
+
77
+ // Validate proxy mode requirements
78
+ if (provider.proxyMode && !provider.requiresClientSecret) {
79
+ throw new ProviderValidationError(
80
+ `Provider "${name}" with proxyMode=true must have requiresClientSecret=true`,
81
+ "proxyMode"
82
+ );
83
+ }
84
+
85
+ // Validate custom parameters don't conflict with reserved parameters
86
+ if (provider.customParams) {
87
+ this.validateCustomParams(provider.customParams, name);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Validate URL format
93
+ *
94
+ * @param url - URL to validate
95
+ * @param providerName - Provider name (for error messages)
96
+ * @param fieldName - Field name (for error messages)
97
+ * @throws ProviderValidationError if URL is invalid
98
+ */
99
+ private validateUrl(url: string, providerName: string, fieldName: string): void {
100
+ try {
101
+ const parsedUrl = new URL(url);
102
+ if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
103
+ throw new ProviderValidationError(
104
+ `Provider "${providerName}" ${fieldName} must use HTTP or HTTPS protocol`,
105
+ fieldName
106
+ );
107
+ }
108
+ } catch (error) {
109
+ if (error instanceof ProviderValidationError) {
110
+ throw error;
111
+ }
112
+ throw new ProviderValidationError(
113
+ `Provider "${providerName}" ${fieldName} is not a valid URL: ${error instanceof Error ? error.message : String(error)}`,
114
+ fieldName
115
+ );
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Validate custom parameters don't override reserved OAuth parameters
121
+ *
122
+ * @param customParams - Custom parameters to validate
123
+ * @param providerName - Provider name (for error messages)
124
+ * @throws ProviderValidationError if reserved parameter is overridden
125
+ */
126
+ private validateCustomParams(
127
+ customParams: Record<string, string>,
128
+ providerName: string
129
+ ): void {
130
+ for (const [key, value] of Object.entries(customParams)) {
131
+ const normalizedKey = key.toLowerCase();
132
+ if (RESERVED_PARAMETERS.includes(normalizedKey as any)) {
133
+ throw new ProviderValidationError(
134
+ `Provider "${providerName}" custom parameter "${key}" conflicts with reserved OAuth parameter. Reserved parameters: ${RESERVED_PARAMETERS.join(", ")}`,
135
+ `customParams.${key}`
136
+ );
137
+ }
138
+ if (!value || value.trim().length === 0) {
139
+ throw new ProviderValidationError(
140
+ `Provider "${providerName}" custom parameter "${key}" has empty value`,
141
+ `customParams.${key}`
142
+ );
143
+ }
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Test provider endpoint reachability (optional)
149
+ *
150
+ * @param provider - Provider configuration
151
+ * @param fetchProvider - Fetch implementation
152
+ * @returns True if endpoint is reachable, false otherwise
153
+ */
154
+ async testProvider(
155
+ provider: OAuthProvider,
156
+ fetchProvider: typeof fetch
157
+ ): Promise<boolean> {
158
+ try {
159
+ // Test authorization URL (HEAD request to avoid triggering OAuth flow)
160
+ const authResponse = await fetchProvider(provider.authorizationUrl, {
161
+ method: "HEAD",
162
+ signal: AbortSignal.timeout(5000), // 5 second timeout
163
+ });
164
+ return authResponse.ok || authResponse.status === 405; // 405 Method Not Allowed is OK
165
+ } catch (error) {
166
+ return false;
167
+ }
168
+ }
169
+ }
170
+