@kya-os/mcp-i-core 1.3.13 → 1.3.15

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 (255) hide show
  1. package/dist/config/remote-config.js +9 -12
  2. package/dist/runtime/base.d.ts +2 -1
  3. package/dist/runtime/base.js +34 -6
  4. package/dist/services/access-control.service.js +5 -0
  5. package/dist/services/tool-protection.service.js +17 -8
  6. package/package.json +2 -2
  7. package/.turbo/turbo-build.log +0 -4
  8. package/.turbo/turbo-test$colon$coverage.log +0 -4586
  9. package/.turbo/turbo-test.log +0 -4631
  10. package/COMPLIANCE_IMPROVEMENT_REPORT.md +0 -483
  11. package/Composer 3.md +0 -615
  12. package/GPT-5.md +0 -1169
  13. package/OPUS-plan.md +0 -352
  14. package/PHASE_3_AND_4.1_SUMMARY.md +0 -585
  15. package/PHASE_3_SUMMARY.md +0 -317
  16. package/PHASE_4.1.3_SUMMARY.md +0 -428
  17. package/PHASE_4.1_COMPLETE.md +0 -525
  18. package/PHASE_4_USER_DID_IDENTITY_LINKING_PLAN.md +0 -1240
  19. package/SCHEMA_COMPLIANCE_REPORT.md +0 -275
  20. package/TEST_PLAN.md +0 -571
  21. package/coverage/coverage-final.json +0 -60
  22. package/dist/cache/oauth-config-cache.d.ts.map +0 -1
  23. package/dist/cache/oauth-config-cache.js.map +0 -1
  24. package/dist/cache/tool-protection-cache.d.ts.map +0 -1
  25. package/dist/cache/tool-protection-cache.js.map +0 -1
  26. package/dist/compliance/index.d.ts.map +0 -1
  27. package/dist/compliance/index.js.map +0 -1
  28. package/dist/compliance/schema-registry.d.ts.map +0 -1
  29. package/dist/compliance/schema-registry.js.map +0 -1
  30. package/dist/compliance/schema-verifier.d.ts.map +0 -1
  31. package/dist/compliance/schema-verifier.js.map +0 -1
  32. package/dist/config/remote-config.d.ts.map +0 -1
  33. package/dist/config/remote-config.js.map +0 -1
  34. package/dist/config.d.ts.map +0 -1
  35. package/dist/config.js.map +0 -1
  36. package/dist/delegation/audience-validator.d.ts.map +0 -1
  37. package/dist/delegation/audience-validator.js.map +0 -1
  38. package/dist/delegation/bitstring.d.ts.map +0 -1
  39. package/dist/delegation/bitstring.js.map +0 -1
  40. package/dist/delegation/cascading-revocation.d.ts.map +0 -1
  41. package/dist/delegation/cascading-revocation.js.map +0 -1
  42. package/dist/delegation/delegation-graph.d.ts.map +0 -1
  43. package/dist/delegation/delegation-graph.js.map +0 -1
  44. package/dist/delegation/did-key-resolver.d.ts.map +0 -1
  45. package/dist/delegation/did-key-resolver.js.map +0 -1
  46. package/dist/delegation/index.d.ts.map +0 -1
  47. package/dist/delegation/index.js.map +0 -1
  48. package/dist/delegation/statuslist-manager.d.ts.map +0 -1
  49. package/dist/delegation/statuslist-manager.js.map +0 -1
  50. package/dist/delegation/storage/index.d.ts.map +0 -1
  51. package/dist/delegation/storage/index.js.map +0 -1
  52. package/dist/delegation/storage/memory-graph-storage.d.ts.map +0 -1
  53. package/dist/delegation/storage/memory-graph-storage.js.map +0 -1
  54. package/dist/delegation/storage/memory-statuslist-storage.d.ts.map +0 -1
  55. package/dist/delegation/storage/memory-statuslist-storage.js.map +0 -1
  56. package/dist/delegation/utils.d.ts.map +0 -1
  57. package/dist/delegation/utils.js.map +0 -1
  58. package/dist/delegation/vc-issuer.d.ts.map +0 -1
  59. package/dist/delegation/vc-issuer.js.map +0 -1
  60. package/dist/delegation/vc-verifier.d.ts.map +0 -1
  61. package/dist/delegation/vc-verifier.js.map +0 -1
  62. package/dist/identity/idp-token-resolver.d.ts.map +0 -1
  63. package/dist/identity/idp-token-resolver.js.map +0 -1
  64. package/dist/identity/idp-token-storage.interface.d.ts.map +0 -1
  65. package/dist/identity/idp-token-storage.interface.js.map +0 -1
  66. package/dist/identity/user-did-manager.d.ts.map +0 -1
  67. package/dist/identity/user-did-manager.js.map +0 -1
  68. package/dist/index.d.ts.map +0 -1
  69. package/dist/index.js.map +0 -1
  70. package/dist/providers/base.d.ts.map +0 -1
  71. package/dist/providers/base.js.map +0 -1
  72. package/dist/providers/memory.d.ts.map +0 -1
  73. package/dist/providers/memory.js.map +0 -1
  74. package/dist/runtime/audit-logger.d.ts.map +0 -1
  75. package/dist/runtime/audit-logger.js.map +0 -1
  76. package/dist/runtime/base.d.ts.map +0 -1
  77. package/dist/runtime/base.js.map +0 -1
  78. package/dist/services/access-control.service.d.ts.map +0 -1
  79. package/dist/services/access-control.service.js.map +0 -1
  80. package/dist/services/authorization/authorization-registry.d.ts.map +0 -1
  81. package/dist/services/authorization/authorization-registry.js.map +0 -1
  82. package/dist/services/authorization/types.d.ts.map +0 -1
  83. package/dist/services/authorization/types.js.map +0 -1
  84. package/dist/services/batch-delegation.service.d.ts.map +0 -1
  85. package/dist/services/batch-delegation.service.js.map +0 -1
  86. package/dist/services/crypto.service.d.ts.map +0 -1
  87. package/dist/services/crypto.service.js.map +0 -1
  88. package/dist/services/errors.d.ts.map +0 -1
  89. package/dist/services/errors.js.map +0 -1
  90. package/dist/services/index.d.ts.map +0 -1
  91. package/dist/services/index.js.map +0 -1
  92. package/dist/services/oauth-config.service.d.ts.map +0 -1
  93. package/dist/services/oauth-config.service.js.map +0 -1
  94. package/dist/services/oauth-provider-registry.d.ts.map +0 -1
  95. package/dist/services/oauth-provider-registry.js.map +0 -1
  96. package/dist/services/oauth-service.d.ts.map +0 -1
  97. package/dist/services/oauth-service.js.map +0 -1
  98. package/dist/services/oauth-token-retrieval.service.d.ts.map +0 -1
  99. package/dist/services/oauth-token-retrieval.service.js.map +0 -1
  100. package/dist/services/proof-verifier.d.ts.map +0 -1
  101. package/dist/services/proof-verifier.js.map +0 -1
  102. package/dist/services/provider-resolver.d.ts.map +0 -1
  103. package/dist/services/provider-resolver.js.map +0 -1
  104. package/dist/services/provider-validator.d.ts.map +0 -1
  105. package/dist/services/provider-validator.js.map +0 -1
  106. package/dist/services/session-registration.service.d.ts.map +0 -1
  107. package/dist/services/session-registration.service.js.map +0 -1
  108. package/dist/services/storage.service.d.ts.map +0 -1
  109. package/dist/services/storage.service.js.map +0 -1
  110. package/dist/services/tool-context-builder.d.ts.map +0 -1
  111. package/dist/services/tool-context-builder.js.map +0 -1
  112. package/dist/services/tool-protection.service.d.ts.map +0 -1
  113. package/dist/services/tool-protection.service.js.map +0 -1
  114. package/dist/types/oauth-required-error.d.ts.map +0 -1
  115. package/dist/types/oauth-required-error.js.map +0 -1
  116. package/dist/types/tool-protection.d.ts.map +0 -1
  117. package/dist/types/tool-protection.js.map +0 -1
  118. package/dist/utils/base58.d.ts.map +0 -1
  119. package/dist/utils/base58.js.map +0 -1
  120. package/dist/utils/base64.d.ts.map +0 -1
  121. package/dist/utils/base64.js.map +0 -1
  122. package/dist/utils/cors.d.ts.map +0 -1
  123. package/dist/utils/cors.js.map +0 -1
  124. package/dist/utils/did-helpers.d.ts.map +0 -1
  125. package/dist/utils/did-helpers.js.map +0 -1
  126. package/dist/utils/index.d.ts.map +0 -1
  127. package/dist/utils/index.js.map +0 -1
  128. package/dist/utils/storage-keys.d.ts.map +0 -1
  129. package/dist/utils/storage-keys.js.map +0 -1
  130. package/docs/API_REFERENCE.md +0 -1362
  131. package/docs/COMPLIANCE_MATRIX.md +0 -691
  132. package/docs/STATUSLIST2021_GUIDE.md +0 -696
  133. package/docs/W3C_VC_DELEGATION_GUIDE.md +0 -710
  134. package/src/__tests__/cache/tool-protection-cache.test.ts +0 -640
  135. package/src/__tests__/config/provider-runtime-config.test.ts +0 -309
  136. package/src/__tests__/delegation-e2e.test.ts +0 -690
  137. package/src/__tests__/identity/user-did-manager.test.ts +0 -232
  138. package/src/__tests__/index.test.ts +0 -56
  139. package/src/__tests__/integration/full-flow.test.ts +0 -789
  140. package/src/__tests__/integration.test.ts +0 -281
  141. package/src/__tests__/providers/base.test.ts +0 -173
  142. package/src/__tests__/providers/memory.test.ts +0 -319
  143. package/src/__tests__/regression/phase2-regression.test.ts +0 -429
  144. package/src/__tests__/runtime/audit-logger.test.ts +0 -154
  145. package/src/__tests__/runtime/base-extensions.test.ts +0 -595
  146. package/src/__tests__/runtime/base.test.ts +0 -869
  147. package/src/__tests__/runtime/delegation-flow.test.ts +0 -164
  148. package/src/__tests__/runtime/proof-client-did.test.ts +0 -376
  149. package/src/__tests__/runtime/route-interception.test.ts +0 -686
  150. package/src/__tests__/runtime/tool-protection-enforcement.test.ts +0 -908
  151. package/src/__tests__/services/agentshield-integration.test.ts +0 -791
  152. package/src/__tests__/services/cache-busting.test.ts +0 -125
  153. package/src/__tests__/services/oauth-service-pkce.test.ts +0 -556
  154. package/src/__tests__/services/provider-resolver-edge-cases.test.ts +0 -591
  155. package/src/__tests__/services/tool-protection-merged-config.test.ts +0 -485
  156. package/src/__tests__/services/tool-protection-oauth-provider.test.ts +0 -480
  157. package/src/__tests__/services/tool-protection.service.test.ts +0 -1373
  158. package/src/__tests__/utils/mock-providers.ts +0 -340
  159. package/src/cache/oauth-config-cache.d.ts +0 -69
  160. package/src/cache/oauth-config-cache.d.ts.map +0 -1
  161. package/src/cache/oauth-config-cache.js.map +0 -1
  162. package/src/cache/oauth-config-cache.ts +0 -123
  163. package/src/cache/tool-protection-cache.ts +0 -171
  164. package/src/compliance/EXAMPLE.md +0 -412
  165. package/src/compliance/__tests__/schema-verifier.test.ts +0 -797
  166. package/src/compliance/index.ts +0 -8
  167. package/src/compliance/schema-registry.ts +0 -460
  168. package/src/compliance/schema-verifier.ts +0 -708
  169. package/src/config/__tests__/merged-config.spec.ts +0 -445
  170. package/src/config/__tests__/remote-config.spec.ts +0 -268
  171. package/src/config/remote-config.ts +0 -264
  172. package/src/config.ts +0 -312
  173. package/src/delegation/__tests__/audience-validator.test.ts +0 -112
  174. package/src/delegation/__tests__/bitstring.test.ts +0 -346
  175. package/src/delegation/__tests__/cascading-revocation.test.ts +0 -628
  176. package/src/delegation/__tests__/delegation-graph.test.ts +0 -584
  177. package/src/delegation/__tests__/did-key-resolver.test.ts +0 -265
  178. package/src/delegation/__tests__/utils.test.ts +0 -152
  179. package/src/delegation/__tests__/vc-issuer.test.ts +0 -442
  180. package/src/delegation/__tests__/vc-verifier.test.ts +0 -922
  181. package/src/delegation/audience-validator.ts +0 -52
  182. package/src/delegation/bitstring.ts +0 -278
  183. package/src/delegation/cascading-revocation.ts +0 -370
  184. package/src/delegation/delegation-graph.ts +0 -299
  185. package/src/delegation/did-key-resolver.ts +0 -179
  186. package/src/delegation/index.ts +0 -14
  187. package/src/delegation/statuslist-manager.ts +0 -353
  188. package/src/delegation/storage/__tests__/memory-graph-storage.test.ts +0 -366
  189. package/src/delegation/storage/__tests__/memory-statuslist-storage.test.ts +0 -228
  190. package/src/delegation/storage/index.ts +0 -9
  191. package/src/delegation/storage/memory-graph-storage.ts +0 -178
  192. package/src/delegation/storage/memory-statuslist-storage.ts +0 -77
  193. package/src/delegation/utils.ts +0 -221
  194. package/src/delegation/vc-issuer.ts +0 -232
  195. package/src/delegation/vc-verifier.ts +0 -568
  196. package/src/identity/idp-token-resolver.ts +0 -181
  197. package/src/identity/idp-token-storage.interface.ts +0 -94
  198. package/src/identity/user-did-manager.ts +0 -526
  199. package/src/index.ts +0 -310
  200. package/src/providers/base.d.ts +0 -91
  201. package/src/providers/base.d.ts.map +0 -1
  202. package/src/providers/base.js.map +0 -1
  203. package/src/providers/base.ts +0 -96
  204. package/src/providers/memory.ts +0 -142
  205. package/src/runtime/audit-logger.ts +0 -39
  206. package/src/runtime/base.ts +0 -1392
  207. package/src/services/__tests__/access-control.integration.test.ts +0 -443
  208. package/src/services/__tests__/access-control.proof-response-validation.test.ts +0 -578
  209. package/src/services/__tests__/access-control.service.test.ts +0 -970
  210. package/src/services/__tests__/batch-delegation.service.test.ts +0 -351
  211. package/src/services/__tests__/crypto.service.test.ts +0 -531
  212. package/src/services/__tests__/oauth-provider-registry.test.ts +0 -142
  213. package/src/services/__tests__/proof-verifier.integration.test.ts +0 -485
  214. package/src/services/__tests__/proof-verifier.test.ts +0 -489
  215. package/src/services/__tests__/provider-resolution.integration.test.ts +0 -202
  216. package/src/services/__tests__/provider-resolver.test.ts +0 -213
  217. package/src/services/__tests__/storage.service.test.ts +0 -358
  218. package/src/services/access-control.service.ts +0 -990
  219. package/src/services/authorization/authorization-registry.ts +0 -66
  220. package/src/services/authorization/types.ts +0 -71
  221. package/src/services/batch-delegation.service.ts +0 -137
  222. package/src/services/crypto.service.ts +0 -302
  223. package/src/services/errors.ts +0 -76
  224. package/src/services/index.ts +0 -18
  225. package/src/services/oauth-config.service.d.ts +0 -53
  226. package/src/services/oauth-config.service.d.ts.map +0 -1
  227. package/src/services/oauth-config.service.js.map +0 -1
  228. package/src/services/oauth-config.service.ts +0 -192
  229. package/src/services/oauth-provider-registry.d.ts +0 -57
  230. package/src/services/oauth-provider-registry.d.ts.map +0 -1
  231. package/src/services/oauth-provider-registry.js.map +0 -1
  232. package/src/services/oauth-provider-registry.ts +0 -141
  233. package/src/services/oauth-service.ts +0 -544
  234. package/src/services/oauth-token-retrieval.service.ts +0 -245
  235. package/src/services/proof-verifier.ts +0 -478
  236. package/src/services/provider-resolver.d.ts +0 -48
  237. package/src/services/provider-resolver.d.ts.map +0 -1
  238. package/src/services/provider-resolver.js.map +0 -1
  239. package/src/services/provider-resolver.ts +0 -146
  240. package/src/services/provider-validator.ts +0 -170
  241. package/src/services/session-registration.service.ts +0 -251
  242. package/src/services/storage.service.ts +0 -566
  243. package/src/services/tool-context-builder.ts +0 -237
  244. package/src/services/tool-protection.service.ts +0 -1070
  245. package/src/types/oauth-required-error.ts +0 -63
  246. package/src/types/tool-protection.ts +0 -155
  247. package/src/utils/__tests__/did-helpers.test.ts +0 -156
  248. package/src/utils/base58.ts +0 -109
  249. package/src/utils/base64.ts +0 -148
  250. package/src/utils/cors.ts +0 -83
  251. package/src/utils/did-helpers.ts +0 -210
  252. package/src/utils/index.ts +0 -8
  253. package/src/utils/storage-keys.ts +0 -278
  254. package/tsconfig.json +0 -21
  255. package/vitest.config.ts +0 -56
@@ -1,708 +0,0 @@
1
- /**
2
- * Schema Compliance Verification Tool
3
- *
4
- * Supports JSON Schema draft-07 features:
5
- * - $ref resolution
6
- * - oneOf, anyOf, allOf
7
- * - Nested required fields
8
- * - Array tuple validation
9
- * - Format, pattern, enum, const
10
- * - Recursive object validation
11
- */
12
-
13
- export interface SchemaMetadata {
14
- id: string;
15
- url: string;
16
- version: string;
17
- type: string;
18
- description?: string;
19
- }
20
-
21
- export interface FieldComplianceResult {
22
- fieldPath: string;
23
- present: boolean;
24
- expectedType: string;
25
- actualType?: string;
26
- typeMatches: boolean;
27
- required: boolean;
28
- status: 'pass' | 'fail' | 'warning';
29
- reason?: string;
30
- }
31
-
32
- export interface SchemaComplianceReport {
33
- schema: SchemaMetadata;
34
- compliant: boolean;
35
- compliancePercentage: number;
36
- fields: FieldComplianceResult[];
37
- issues: string[];
38
- warnings: string[];
39
- timestamp: number;
40
- }
41
-
42
- export interface FullComplianceReport {
43
- totalSchemas: number;
44
- compliantSchemas: number;
45
- overallCompliance: number;
46
- schemaReports: SchemaComplianceReport[];
47
- criticalIssues: string[];
48
- timestamp: number;
49
- }
50
-
51
- /**
52
- * Schema Verifier with JSON Schema draft-07 support
53
- */
54
- export class SchemaVerifier {
55
- private schemasBaseUrl = 'https://schemas.kya-os.ai';
56
- private schemaCache = new Map<string, any>();
57
-
58
- constructor(options?: { schemasBaseUrl?: string }) {
59
- if (options?.schemasBaseUrl) {
60
- this.schemasBaseUrl = options.schemasBaseUrl;
61
- }
62
- }
63
-
64
- /**
65
- * Verify a single schema against implementation
66
- */
67
- async verifySchema(
68
- schema: SchemaMetadata,
69
- implementation: any
70
- ): Promise<SchemaComplianceReport> {
71
- const fields: FieldComplianceResult[] = [];
72
- const issues: string[] = [];
73
- const warnings: string[] = [];
74
-
75
- // Fetch the canonical schema
76
- let canonicalSchema: any;
77
- try {
78
- canonicalSchema = await this.fetchSchema(schema.url);
79
- } catch (error) {
80
- return {
81
- schema,
82
- compliant: false,
83
- compliancePercentage: 0,
84
- fields: [],
85
- issues: [
86
- `Failed to fetch schema: ${error instanceof Error ? error.message : 'Unknown error'}`,
87
- ],
88
- warnings: [],
89
- timestamp: Date.now(),
90
- };
91
- }
92
-
93
- // Resolve $ref if present at root
94
- const resolvedSchema = this.resolveRef(canonicalSchema, canonicalSchema);
95
-
96
- // Validate the implementation against the schema
97
- const validationResult = this.validateAgainstSchema(
98
- implementation,
99
- resolvedSchema,
100
- canonicalSchema,
101
- ''
102
- );
103
-
104
- fields.push(...validationResult.fields);
105
-
106
- // Separate issues and warnings
107
- for (const field of fields) {
108
- if (field.status === 'fail') {
109
- issues.push(`${field.fieldPath}: ${field.reason}`);
110
- } else if (field.status === 'warning') {
111
- warnings.push(`${field.fieldPath}: ${field.reason}`);
112
- }
113
- }
114
-
115
- // Calculate compliance
116
- const requiredFields = fields.filter((f) => f.required);
117
- const passingRequiredFields = requiredFields.filter(
118
- (f) => f.status === 'pass'
119
- ).length;
120
-
121
- const compliancePercentage =
122
- requiredFields.length > 0
123
- ? (passingRequiredFields / requiredFields.length) * 100
124
- : 100; // If no required fields, 100% compliant
125
-
126
- const compliant = issues.length === 0 && compliancePercentage >= 95;
127
-
128
- return {
129
- schema,
130
- compliant,
131
- compliancePercentage,
132
- fields,
133
- issues,
134
- warnings,
135
- timestamp: Date.now(),
136
- };
137
- }
138
-
139
- /**
140
- * Verify all schemas
141
- */
142
- async verifyAll(
143
- schemas: SchemaMetadata[],
144
- implementations: Map<string, any>
145
- ): Promise<FullComplianceReport> {
146
- const schemaReports: SchemaComplianceReport[] = [];
147
- const criticalIssues: string[] = [];
148
-
149
- for (const schema of schemas) {
150
- const implementation = implementations.get(schema.id);
151
- if (!implementation) {
152
- criticalIssues.push(`No implementation found for schema: ${schema.id}`);
153
- continue;
154
- }
155
-
156
- const report = await this.verifySchema(schema, implementation);
157
- schemaReports.push(report);
158
-
159
- if (!report.compliant) {
160
- criticalIssues.push(`${schema.id}: ${report.issues.join(', ')}`);
161
- }
162
- }
163
-
164
- const compliantSchemas = schemaReports.filter((r) => r.compliant).length;
165
- const overallCompliance =
166
- schemas.length > 0 ? (compliantSchemas / schemas.length) * 100 : 0;
167
-
168
- return {
169
- totalSchemas: schemas.length,
170
- compliantSchemas,
171
- overallCompliance,
172
- schemaReports,
173
- criticalIssues,
174
- timestamp: Date.now(),
175
- };
176
- }
177
-
178
- /**
179
- * Validate implementation against schema recursively
180
- */
181
- private validateAgainstSchema(
182
- value: any,
183
- schema: any,
184
- rootSchema: any,
185
- path: string
186
- ): { fields: FieldComplianceResult[] } {
187
- const fields: FieldComplianceResult[] = [];
188
-
189
- // Resolve $ref
190
- schema = this.resolveRef(schema, rootSchema);
191
-
192
- // Handle oneOf, anyOf, allOf
193
- if (schema.oneOf || schema.anyOf || schema.allOf) {
194
- return this.validateUnion(value, schema, rootSchema, path);
195
- }
196
-
197
- // Handle type: object
198
- if (schema.type === 'object' && schema.properties) {
199
- const required = schema.required || [];
200
-
201
- for (const [propName, propSchema] of Object.entries<any>(
202
- schema.properties
203
- )) {
204
- const propPath = path ? `${path}.${propName}` : propName;
205
- const propValue = value?.[propName];
206
- const isRequired = required.includes(propName);
207
-
208
- const fieldResult = this.checkField(
209
- propPath,
210
- propValue,
211
- propSchema,
212
- rootSchema,
213
- isRequired
214
- );
215
-
216
- fields.push(fieldResult);
217
-
218
- // Recurse into nested objects
219
- if (propValue !== undefined && propSchema.type === 'object') {
220
- const nestedResult = this.validateAgainstSchema(
221
- propValue,
222
- propSchema,
223
- rootSchema,
224
- propPath
225
- );
226
- fields.push(...nestedResult.fields);
227
- }
228
- }
229
- }
230
-
231
- // Handle type: array
232
- if (schema.type === 'array' && value && Array.isArray(value)) {
233
- const arrayResult = this.validateArray(value, schema, rootSchema, path);
234
- fields.push(...arrayResult.fields);
235
- }
236
-
237
- return { fields };
238
- }
239
-
240
- /**
241
- * Validate against oneOf, anyOf, allOf
242
- */
243
- private validateUnion(
244
- value: any,
245
- schema: any,
246
- rootSchema: any,
247
- path: string
248
- ): { fields: FieldComplianceResult[] } {
249
- const fields: FieldComplianceResult[] = [];
250
-
251
- // For anyOf/oneOf, try to find a matching schema
252
- if (schema.anyOf || schema.oneOf) {
253
- const options = schema.anyOf || schema.oneOf;
254
- let matched = false;
255
-
256
- for (const option of options) {
257
- const resolvedOption = this.resolveRef(option, rootSchema);
258
-
259
- // Try to validate against this option
260
- try {
261
- if (this.matchesSchema(value, resolvedOption, rootSchema)) {
262
- // Found a match, validate with this schema
263
- const result = this.validateAgainstSchema(
264
- value,
265
- resolvedOption,
266
- rootSchema,
267
- path
268
- );
269
- fields.push(...result.fields);
270
- matched = true;
271
- break;
272
- }
273
- } catch (e) {
274
- // Doesn't match this option, try next
275
- continue;
276
- }
277
- }
278
-
279
- if (!matched && path) {
280
- // Didn't match any option
281
- fields.push({
282
- fieldPath: path,
283
- present: value !== undefined,
284
- expectedType: 'oneOf/anyOf options',
285
- actualType: typeof value,
286
- typeMatches: false,
287
- required: true,
288
- status: 'fail',
289
- reason: 'Value does not match any of the schema options',
290
- });
291
- }
292
- }
293
-
294
- // For allOf, validate against all schemas
295
- if (schema.allOf) {
296
- for (const subSchema of schema.allOf) {
297
- const resolvedSubSchema = this.resolveRef(subSchema, rootSchema);
298
- const result = this.validateAgainstSchema(
299
- value,
300
- resolvedSubSchema,
301
- rootSchema,
302
- path
303
- );
304
- fields.push(...result.fields);
305
- }
306
- }
307
-
308
- return { fields };
309
- }
310
-
311
- /**
312
- * Check if value matches schema (lightweight check)
313
- */
314
- private matchesSchema(value: any, schema: any, rootSchema: any): boolean {
315
- schema = this.resolveRef(schema, rootSchema);
316
-
317
- // Check type
318
- if (schema.type) {
319
- const actualType = Array.isArray(value) ? 'array' : typeof value;
320
- // JSON Schema "integer" matches JavaScript "number" (if it's an integer)
321
- if (schema.type === 'integer' && actualType === 'number') {
322
- if (!Number.isInteger(value)) {
323
- return false;
324
- }
325
- } else if (schema.type !== actualType) {
326
- return false;
327
- }
328
- }
329
-
330
- // Check const
331
- if (schema.const !== undefined && value !== schema.const) {
332
- return false;
333
- }
334
-
335
- // Check enum
336
- if (schema.enum && !schema.enum.includes(value)) {
337
- return false;
338
- }
339
-
340
- // Check pattern (for strings)
341
- if (schema.pattern && typeof value === 'string') {
342
- const regex = new RegExp(schema.pattern);
343
- if (!regex.test(value)) {
344
- return false;
345
- }
346
- }
347
-
348
- // Check required properties (for objects)
349
- if (schema.type === 'object' && schema.required) {
350
- for (const requiredProp of schema.required) {
351
- if (!(requiredProp in value)) {
352
- return false;
353
- }
354
- }
355
- }
356
-
357
- return true;
358
- }
359
-
360
- /**
361
- * Validate array against schema
362
- */
363
- private validateArray(
364
- value: any[],
365
- schema: any,
366
- rootSchema: any,
367
- path: string
368
- ): { fields: FieldComplianceResult[] } {
369
- const fields: FieldComplianceResult[] = [];
370
-
371
- // Check minItems
372
- if (schema.minItems !== undefined && value.length < schema.minItems) {
373
- fields.push({
374
- fieldPath: `${path}.length`,
375
- present: true,
376
- expectedType: `array with minItems: ${schema.minItems}`,
377
- actualType: `array with length: ${value.length}`,
378
- typeMatches: false,
379
- required: true,
380
- status: 'fail',
381
- reason: `Array length ${value.length} is less than minItems ${schema.minItems}`,
382
- });
383
- }
384
-
385
- // Check tuple validation (items as array)
386
- if (Array.isArray(schema.items)) {
387
- for (let i = 0; i < schema.items.length; i++) {
388
- const itemSchema = schema.items[i];
389
- const itemValue = value[i];
390
- const itemPath = `${path}[${i}]`;
391
-
392
- if (itemValue !== undefined) {
393
- const resolvedItemSchema = this.resolveRef(itemSchema, rootSchema);
394
- const itemResult = this.validateAgainstSchema(
395
- itemValue,
396
- resolvedItemSchema,
397
- rootSchema,
398
- itemPath
399
- );
400
- fields.push(...itemResult.fields);
401
- }
402
- }
403
-
404
- // Check additionalItems
405
- if (schema.additionalItems !== undefined && value.length > schema.items.length) {
406
- for (let i = schema.items.length; i < value.length; i++) {
407
- const itemValue = value[i];
408
- const itemPath = `${path}[${i}]`;
409
- const itemResult = this.validateAgainstSchema(
410
- itemValue,
411
- schema.additionalItems,
412
- rootSchema,
413
- itemPath
414
- );
415
- fields.push(...itemResult.fields);
416
- }
417
- }
418
- } else if (schema.items) {
419
- // Single schema for all items
420
- for (let i = 0; i < value.length; i++) {
421
- const itemValue = value[i];
422
- const itemPath = `${path}[${i}]`;
423
- const resolvedItemSchema = this.resolveRef(schema.items, rootSchema);
424
- const itemResult = this.validateAgainstSchema(
425
- itemValue,
426
- resolvedItemSchema,
427
- rootSchema,
428
- itemPath
429
- );
430
- fields.push(...itemResult.fields);
431
- }
432
- }
433
-
434
- // Check contains (at least one item must match)
435
- if (schema.contains) {
436
- const containsSchema = this.resolveRef(schema.contains, rootSchema);
437
- const hasMatch = value.some((item) =>
438
- this.matchesSchema(item, containsSchema, rootSchema)
439
- );
440
-
441
- if (!hasMatch) {
442
- fields.push({
443
- fieldPath: `${path}.contains`,
444
- present: true,
445
- expectedType: 'array containing matching item',
446
- actualType: 'array without matching item',
447
- typeMatches: false,
448
- required: true,
449
- status: 'fail',
450
- reason: 'Array does not contain any item matching the "contains" schema',
451
- });
452
- }
453
- }
454
-
455
- return { fields };
456
- }
457
-
458
- /**
459
- * Check a single field
460
- */
461
- private checkField(
462
- fieldPath: string,
463
- value: any,
464
- schema: any,
465
- rootSchema: any,
466
- required: boolean
467
- ): FieldComplianceResult {
468
- schema = this.resolveRef(schema, rootSchema);
469
-
470
- const present = value !== undefined;
471
- const actualType = this.getActualType(value);
472
-
473
- // Get expected type
474
- let expectedType = 'unknown';
475
- if (schema.type) {
476
- expectedType = schema.type;
477
- } else if (schema.anyOf) {
478
- expectedType = 'anyOf';
479
- } else if (schema.oneOf) {
480
- expectedType = 'oneOf';
481
- } else if (schema.allOf) {
482
- expectedType = 'allOf';
483
- }
484
-
485
- // Check if required field is missing
486
- if (required && !present) {
487
- return {
488
- fieldPath,
489
- present,
490
- expectedType,
491
- actualType,
492
- typeMatches: false,
493
- required,
494
- status: 'fail',
495
- reason: 'Required field missing',
496
- };
497
- }
498
-
499
- // Check if optional field is missing
500
- if (!required && !present) {
501
- return {
502
- fieldPath,
503
- present,
504
- expectedType,
505
- actualType,
506
- typeMatches: true, // Optional field can be missing
507
- required,
508
- status: 'pass',
509
- };
510
- }
511
-
512
- // Value is present, check if it matches schema
513
- const typeMatches = this.matchesSchema(value, schema, rootSchema);
514
-
515
- if (!typeMatches) {
516
- return {
517
- fieldPath,
518
- present,
519
- expectedType,
520
- actualType,
521
- typeMatches: false,
522
- required,
523
- status: 'fail',
524
- reason: `Type/value mismatch`,
525
- };
526
- }
527
-
528
- // All good
529
- return {
530
- fieldPath,
531
- present,
532
- expectedType,
533
- actualType,
534
- typeMatches: true,
535
- required,
536
- status: 'pass',
537
- };
538
- }
539
-
540
- /**
541
- * Get actual JavaScript type
542
- */
543
- private getActualType(value: any): string {
544
- if (value === null) return 'null';
545
- if (Array.isArray(value)) return 'array';
546
- if (typeof value === 'number' && Number.isInteger(value)) return 'integer';
547
- return typeof value;
548
- }
549
-
550
- /**
551
- * Resolve $ref reference
552
- */
553
- private resolveRef(schema: any, rootSchema: any): any {
554
- if (!schema.$ref) {
555
- return schema;
556
- }
557
-
558
- const ref = schema.$ref;
559
-
560
- // Handle #/definitions/Foo
561
- if (ref.startsWith('#/definitions/')) {
562
- const defName = ref.substring('#/definitions/'.length);
563
- if (rootSchema.definitions && rootSchema.definitions[defName]) {
564
- return rootSchema.definitions[defName];
565
- }
566
- }
567
-
568
- // Handle #/$defs/Foo (draft-07+)
569
- if (ref.startsWith('#/$defs/')) {
570
- const defName = ref.substring('#/$defs/'.length);
571
- if (rootSchema.$defs && rootSchema.$defs[defName]) {
572
- return rootSchema.$defs[defName];
573
- }
574
- }
575
-
576
- // Handle # (root)
577
- if (ref === '#') {
578
- return rootSchema;
579
- }
580
-
581
- // If we can't resolve, return original
582
- return schema;
583
- }
584
-
585
- /**
586
- * Fetch a schema from URL
587
- */
588
- private async fetchSchema(url: string): Promise<any> {
589
- // Check cache
590
- if (this.schemaCache.has(url)) {
591
- return this.schemaCache.get(url);
592
- }
593
-
594
- try {
595
- const response = await fetch(url);
596
-
597
- if (!response.ok) {
598
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
599
- }
600
-
601
- const schema = await response.json();
602
- this.schemaCache.set(url, schema);
603
- return schema;
604
- } catch (error) {
605
- if (error instanceof Error) {
606
- throw new Error(`Failed to fetch schema from ${url}: ${error.message}`);
607
- }
608
- throw new Error(`Failed to fetch schema from ${url}: Unknown error`);
609
- }
610
- }
611
-
612
- /**
613
- * Generate a formatted report
614
- */
615
- generateReport(report: SchemaComplianceReport): string {
616
- const lines: string[] = [];
617
-
618
- lines.push(`\n${'='.repeat(80)}`);
619
- lines.push(`SCHEMA COMPLIANCE REPORT: ${report.schema.id}`);
620
- lines.push(`${'='.repeat(80)}\n`);
621
-
622
- lines.push(`Schema: ${report.schema.type} v${report.schema.version}`);
623
- lines.push(`URL: ${report.schema.url}`);
624
- lines.push(
625
- `Status: ${report.compliant ? '✅ COMPLIANT' : '❌ NON-COMPLIANT'}`
626
- );
627
- lines.push(`Compliance: ${report.compliancePercentage.toFixed(1)}%\n`);
628
-
629
- if (report.issues.length > 0) {
630
- lines.push(`\n🚨 ISSUES (${report.issues.length}):`);
631
- report.issues.forEach((issue, i) => {
632
- lines.push(` ${i + 1}. ${issue}`);
633
- });
634
- }
635
-
636
- if (report.warnings.length > 0) {
637
- lines.push(`\n⚠️ WARNINGS (${report.warnings.length}):`);
638
- report.warnings.forEach((warning, i) => {
639
- lines.push(` ${i + 1}. ${warning}`);
640
- });
641
- }
642
-
643
- lines.push(`\n📊 FIELD DETAILS:\n`);
644
- const requiredFields = report.fields.filter((f) => f.required);
645
- const passing = requiredFields.filter((f) => f.status === 'pass').length;
646
- const failing = requiredFields.filter((f) => f.status === 'fail').length;
647
- const warnings = report.fields.filter((f) => f.status === 'warning').length;
648
-
649
- lines.push(` ✅ Pass: ${passing}/${requiredFields.length} required fields`);
650
- lines.push(` ❌ Fail: ${failing}/${requiredFields.length} required fields`);
651
- lines.push(` ⚠️ Warn: ${warnings} optional fields`);
652
- lines.push(` 📝 Total: ${report.fields.length} fields checked\n`);
653
-
654
- lines.push(`${'='.repeat(80)}\n`);
655
-
656
- return lines.join('\n');
657
- }
658
-
659
- /**
660
- * Generate full report
661
- */
662
- generateFullReport(report: FullComplianceReport): string {
663
- const lines: string[] = [];
664
-
665
- lines.push(`\n${'='.repeat(80)}`);
666
- lines.push(`FULL SCHEMA COMPLIANCE REPORT`);
667
- lines.push(`${'='.repeat(80)}\n`);
668
-
669
- lines.push(`Total Schemas: ${report.totalSchemas}`);
670
- lines.push(`Compliant: ${report.compliantSchemas}`);
671
- lines.push(
672
- `Non-Compliant: ${report.totalSchemas - report.compliantSchemas}`
673
- );
674
- lines.push(`Overall Compliance: ${report.overallCompliance.toFixed(1)}%\n`);
675
-
676
- if (report.criticalIssues.length > 0) {
677
- lines.push(`\n🚨 CRITICAL ISSUES (${report.criticalIssues.length}):`);
678
- report.criticalIssues.slice(0, 10).forEach((issue, i) => {
679
- lines.push(` ${i + 1}. ${issue}`);
680
- });
681
- if (report.criticalIssues.length > 10) {
682
- lines.push(
683
- ` ... and ${report.criticalIssues.length - 10} more issues`
684
- );
685
- }
686
- }
687
-
688
- lines.push(`\n📊 SCHEMA BREAKDOWN:\n`);
689
- report.schemaReports.forEach((schemaReport) => {
690
- const icon = schemaReport.compliant ? '✅' : '❌';
691
- const percentage = schemaReport.compliancePercentage.toFixed(1);
692
- lines.push(` ${icon} ${schemaReport.schema.id}: ${percentage}%`);
693
- });
694
-
695
- lines.push(`\n${'='.repeat(80)}\n`);
696
-
697
- return lines.join('\n');
698
- }
699
- }
700
-
701
- /**
702
- * Create a schema verifier
703
- */
704
- export function createSchemaVerifier(options?: {
705
- schemasBaseUrl?: string;
706
- }): SchemaVerifier {
707
- return new SchemaVerifier(options);
708
- }