mcp-from-openapi 2.1.0 → 2.1.2
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.
- package/CHANGELOG.md +13 -0
- package/README.md +1 -1
- package/esm/index.mjs +1561 -0
- package/esm/package.json +65 -0
- package/index.js +1612 -0
- package/package.json +18 -10
- package/src/errors.js +0 -67
- package/src/errors.js.map +0 -1
- package/src/generator.js +0 -381
- package/src/generator.js.map +0 -1
- package/src/index.js +0 -30
- package/src/index.js.map +0 -1
- package/src/parameter-resolver.js +0 -294
- package/src/parameter-resolver.js.map +0 -1
- package/src/response-builder.js +0 -149
- package/src/response-builder.js.map +0 -1
- package/src/schema-builder.js +0 -291
- package/src/schema-builder.js.map +0 -1
- package/src/security-resolver.js +0 -324
- package/src/security-resolver.js.map +0 -1
- package/src/types.js +0 -99
- package/src/types.js.map +0 -1
- package/src/validator.js +0 -213
- package/src/validator.js.map +0 -1
- /package/{src/errors.d.ts → errors.d.ts} +0 -0
- /package/{src/generator.d.ts → generator.d.ts} +0 -0
- /package/{src/index.d.ts → index.d.ts} +0 -0
- /package/{src/parameter-resolver.d.ts → parameter-resolver.d.ts} +0 -0
- /package/{src/response-builder.d.ts → response-builder.d.ts} +0 -0
- /package/{src/schema-builder.d.ts → schema-builder.d.ts} +0 -0
- /package/{src/security-resolver.d.ts → security-resolver.d.ts} +0 -0
- /package/{src/types.d.ts → types.d.ts} +0 -0
- /package/{src/validator.d.ts → validator.d.ts} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"security-resolver.js","sourceRoot":"","sources":["../../src/security-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ParameterMapper, SecurityParameterInfo } from './types';\n\n/**\n * Context for resolving security parameters\n * Frameworks should implement this interface based on their auth system\n */\nexport interface SecurityContext {\n /**\n * JWT/Bearer token\n */\n jwt?: string;\n\n /**\n * Basic auth credentials (base64 encoded \"username:password\")\n */\n basic?: string;\n\n /**\n * Digest auth credentials\n * Object with username, password, realm, nonce, etc.\n */\n digest?: DigestAuthCredentials;\n\n /**\n * API key (single key for backward compatibility)\n */\n apiKey?: string;\n\n /**\n * Multiple API keys by name\n * Use this when API requires different keys for different purposes\n * @example { 'X-API-Key': 'key1', 'X-Client-Id': 'client123' }\n */\n apiKeys?: Record<string, string>;\n\n /**\n * OAuth2 access token\n */\n oauth2Token?: string;\n\n /**\n * Client certificate for mutual TLS (mTLS)\n */\n clientCertificate?: ClientCertificate;\n\n /**\n * Private key for signature-based auth (HMAC, AWS Signature V4, etc.)\n */\n privateKey?: string;\n\n /**\n * Public key (if needed for verification)\n */\n publicKey?: string;\n\n /**\n * HMAC secret for HMAC-based authentication\n */\n hmacSecret?: string;\n\n /**\n * AWS credentials for AWS Signature V4\n */\n awsCredentials?: AWSCredentials;\n\n /**\n * Custom headers for proprietary authentication\n * @example { 'X-Custom-Auth': 'custom-value' }\n */\n customHeaders?: Record<string, string>;\n\n /**\n * Session cookies\n */\n cookies?: Record<string, string>;\n\n /**\n * Custom resolver for framework-specific auth\n * @param security - Security parameter info from mapper\n * @returns The auth value to use, or undefined if not available\n */\n customResolver?: (security: SecurityParameterInfo) => string | Promise<string | undefined>;\n\n /**\n * Signature generator for signature-based auth\n * @param data - Data to sign (typically the request)\n * @param security - Security parameter info\n * @returns The signature or signed value\n */\n signatureGenerator?: (data: SignatureData, security: SecurityParameterInfo) => string | Promise<string>;\n}\n\n/**\n * Digest authentication credentials\n */\nexport interface DigestAuthCredentials {\n username: string;\n password: string;\n realm?: string;\n nonce?: string;\n uri?: string;\n qop?: string;\n nc?: string;\n cnonce?: string;\n response?: string;\n opaque?: string;\n}\n\n/**\n * Client certificate for mTLS\n */\nexport interface ClientCertificate {\n /**\n * Certificate in PEM format\n */\n cert: string;\n\n /**\n * Private key in PEM format\n */\n key: string;\n\n /**\n * Passphrase for encrypted key\n */\n passphrase?: string;\n\n /**\n * CA certificates\n */\n ca?: string | string[];\n}\n\n/**\n * AWS credentials for Signature V4\n */\nexport interface AWSCredentials {\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken?: string;\n region?: string;\n service?: string;\n}\n\n/**\n * Data to be signed for signature-based auth\n */\nexport interface SignatureData {\n method: string;\n url: string;\n headers: Record<string, string>;\n body?: string;\n timestamp?: number;\n}\n\n/**\n * Resolved security parameters ready to be added to HTTP request\n */\nexport interface ResolvedSecurity {\n /**\n * Headers to add to the request\n */\n headers: Record<string, string>;\n\n /**\n * Query parameters to add to the request\n */\n query: Record<string, string>;\n\n /**\n * Cookie values to add to the request\n */\n cookies: Record<string, string>;\n\n /**\n * Client certificate for mTLS (if applicable)\n */\n clientCertificate?: ClientCertificate;\n\n /**\n * Whether signature-based auth is required\n * If true, you need to call signRequest() before sending\n */\n requiresSignature?: boolean;\n\n /**\n * Signature metadata (if signature-based auth is used)\n */\n signatureInfo?: {\n scheme: string;\n algorithm?: string;\n };\n}\n\n/**\n * Security resolver that maps OpenAPI security requirements to actual auth values\n *\n * This helper handles security parameters from any OpenAPI spec, regardless of\n * custom naming (BearerAuth, JWT, Authorization, etc.). It uses the mapper's\n * security metadata to determine the auth type and format.\n *\n * @example\n * ```typescript\n * // In FrontMCP\n * const resolver = new SecurityResolver();\n * const resolved = resolver.resolve(tool.mapper, {\n * jwt: context.authInfo.jwt,\n * apiKey: process.env.API_KEY\n * });\n *\n * // Use resolved.headers in HTTP request\n * fetch(url, { headers: { ...resolved.headers, ...otherHeaders } });\n * ```\n *\n * @example\n * ```typescript\n * // Custom resolver for framework-specific auth\n * const resolved = resolver.resolve(tool.mapper, {\n * customResolver: (security) => {\n * if (security.type === 'http' && security.httpScheme === 'bearer') {\n * return myFramework.getAuthToken();\n * }\n * return undefined;\n * }\n * });\n * ```\n */\nexport class SecurityResolver {\n /**\n * Resolve security parameters from mapper entries\n *\n * @param mappers - Parameter mappers from the tool definition\n * @param context - Security context with auth values or custom resolver\n * @returns Resolved headers, query params, and cookies with auth applied\n */\n async resolve(mappers: ParameterMapper[], context: SecurityContext): Promise<ResolvedSecurity> {\n const resolved: ResolvedSecurity = {\n headers: {},\n query: {},\n cookies: {},\n };\n\n // Add client certificate if available (for mTLS)\n if (context.clientCertificate) {\n resolved.clientCertificate = context.clientCertificate;\n }\n\n // Check if signature-based auth is needed\n let requiresSignature = false;\n let signatureScheme: string | undefined;\n\n for (const mapper of mappers) {\n // Skip non-security parameters\n if (!mapper.security) {\n continue;\n }\n\n // Check for signature-based auth\n if (this.isSignatureBasedAuth(mapper.security)) {\n requiresSignature = true;\n signatureScheme = mapper.security.scheme;\n // Signature will be added later by signRequest()\n continue;\n }\n\n // Try to resolve the auth value\n const authValue = await this.resolveAuthValue(mapper.security, context);\n if (!authValue) {\n // Auth value not available - skip this security requirement\n // Framework may want to throw an error or log a warning\n continue;\n }\n\n // Apply to the correct location\n const headerName = mapper.key;\n\n if (mapper.type === 'header') {\n resolved.headers[headerName] = authValue;\n } else if (mapper.type === 'query') {\n resolved.query[headerName] = authValue;\n } else if (mapper.type === 'cookie') {\n resolved.cookies[headerName] = authValue;\n }\n }\n\n // Add context cookies if available\n if (context.cookies) {\n resolved.cookies = { ...resolved.cookies, ...context.cookies };\n }\n\n // Add signature metadata if needed\n if (requiresSignature) {\n resolved.requiresSignature = true;\n resolved.signatureInfo = {\n scheme: signatureScheme || 'unknown',\n };\n }\n\n return resolved;\n }\n\n /**\n * Check if security scheme requires request signing\n */\n private isSignatureBasedAuth(security: SecurityParameterInfo): boolean {\n // Check for schemes that typically require signing\n const signatureSchemes = ['aws4', 'hmac', 'signature', 'hawk', 'custom-signature'];\n return signatureSchemes.some(scheme =>\n security.scheme.toLowerCase().includes(scheme)\n );\n }\n\n /**\n * Resolve the actual auth value based on security type\n */\n private async resolveAuthValue(\n security: SecurityParameterInfo,\n context: SecurityContext\n ): Promise<string | undefined> {\n // Try custom resolver first\n if (context.customResolver) {\n const customValue = await context.customResolver(security);\n if (customValue !== undefined) {\n return customValue;\n }\n }\n\n // Handle standard security types\n if (security.type === 'http') {\n return this.resolveHttpAuth(security, context);\n } else if (security.type === 'apiKey') {\n return this.resolveApiKey(security, context);\n } else if (security.type === 'oauth2' || security.type === 'openIdConnect') {\n return this.resolveOAuth2(security, context);\n }\n\n return undefined;\n }\n\n /**\n * Resolve HTTP authentication (bearer, basic, digest, etc.)\n */\n private resolveHttpAuth(\n security: SecurityParameterInfo,\n context: SecurityContext\n ): string | undefined {\n const scheme = security.httpScheme?.toLowerCase() || 'bearer';\n\n switch (scheme) {\n case 'bearer':\n return this.resolveBearerAuth(context);\n\n case 'basic':\n return this.resolveBasicAuth(context);\n\n case 'digest':\n return this.resolveDigestAuth(context);\n\n case 'hoba':\n case 'mutual':\n case 'negotiate':\n case 'vapid':\n case 'scram':\n // These schemes typically require custom implementation\n // Try custom headers or signature generator\n return this.resolveCustomHttpScheme(scheme, security, context);\n\n default:\n // Unknown scheme - try custom resolver\n return undefined;\n }\n }\n\n /**\n * Resolve Bearer token authentication\n */\n private resolveBearerAuth(context: SecurityContext): string | undefined {\n const token = context.jwt;\n if (!token) return undefined;\n return `Bearer ${token}`;\n }\n\n /**\n * Resolve Basic authentication\n */\n private resolveBasicAuth(context: SecurityContext): string | undefined {\n const credentials = context.basic;\n if (!credentials) return undefined;\n return `Basic ${credentials}`;\n }\n\n /**\n * Resolve Digest authentication\n */\n private resolveDigestAuth(context: SecurityContext): string | undefined {\n const digest = context.digest;\n if (!digest) return undefined;\n\n // Build digest auth header\n const parts: string[] = [\n `username=\"${digest.username}\"`,\n digest.realm ? `realm=\"${digest.realm}\"` : '',\n digest.nonce ? `nonce=\"${digest.nonce}\"` : '',\n digest.uri ? `uri=\"${digest.uri}\"` : '',\n digest.response ? `response=\"${digest.response}\"` : '',\n digest.opaque ? `opaque=\"${digest.opaque}\"` : '',\n digest.qop ? `qop=${digest.qop}` : '',\n digest.nc ? `nc=${digest.nc}` : '',\n digest.cnonce ? `cnonce=\"${digest.cnonce}\"` : '',\n ].filter(Boolean);\n\n return `Digest ${parts.join(', ')}`;\n }\n\n /**\n * Resolve custom HTTP authentication schemes\n */\n private resolveCustomHttpScheme(\n scheme: string,\n security: SecurityParameterInfo,\n context: SecurityContext\n ): string | undefined {\n // Try custom headers first\n const headerKey = security.apiKeyName || `X-${scheme.toUpperCase()}`;\n if (context.customHeaders?.[headerKey]) {\n return context.customHeaders[headerKey];\n }\n\n // Unknown scheme\n return undefined;\n }\n\n /**\n * Resolve API key authentication\n */\n private resolveApiKey(\n security: SecurityParameterInfo,\n context: SecurityContext\n ): string | undefined {\n // Try named API keys first (for multiple keys)\n if (context.apiKeys && security.apiKeyName) {\n const key = context.apiKeys[security.apiKeyName];\n if (key) return key;\n }\n\n // Try custom headers (for proprietary auth headers like X-Custom-Auth)\n if (context.customHeaders && security.apiKeyName) {\n const header = context.customHeaders[security.apiKeyName];\n if (header) return header;\n }\n\n // Fall back to single apiKey (backward compatibility)\n return context.apiKey;\n }\n\n /**\n * Resolve OAuth2/OpenID Connect authentication\n */\n private resolveOAuth2(\n security: SecurityParameterInfo,\n context: SecurityContext\n ): string | undefined {\n const token = context.oauth2Token;\n if (!token) return undefined;\n\n // OAuth2 tokens are typically formatted as \"Bearer {token}\"\n return `Bearer ${token}`;\n }\n\n /**\n * Check if any security requirements are missing from context\n *\n * @param mappers - Parameter mappers from the tool definition\n * @param context - Security context with auth values\n * @returns Array of missing security scheme names\n */\n async checkMissingSecurity(\n mappers: ParameterMapper[],\n context: SecurityContext\n ): Promise<string[]> {\n const missing: string[] = [];\n\n for (const mapper of mappers) {\n if (!mapper.security) continue;\n\n const authValue = await this.resolveAuthValue(mapper.security, context);\n if (!authValue) {\n missing.push(mapper.security.scheme);\n }\n }\n\n return missing;\n }\n\n /**\n * Sign a request for signature-based authentication\n *\n * Use this when resolved.requiresSignature is true.\n * This method will call the signatureGenerator from context to sign the request.\n *\n * @param mappers - Parameter mappers from the tool definition\n * @param signatureData - Request data to sign\n * @param context - Security context with signature generator\n * @returns Headers with signature added\n *\n * @example\n * ```typescript\n * const resolved = resolver.resolve(tool.mapper, context);\n * if (resolved.requiresSignature) {\n * const signedHeaders = await resolver.signRequest(\n * tool.mapper,\n * { method: 'GET', url: 'https://api.example.com/data', headers: resolved.headers },\n * context\n * );\n * // Use signedHeaders in request\n * }\n * ```\n */\n async signRequest(\n mappers: ParameterMapper[],\n signatureData: SignatureData,\n context: SecurityContext\n ): Promise<Record<string, string>> {\n const headers: Record<string, string> = { ...signatureData.headers };\n\n if (!context.signatureGenerator) {\n throw new Error('Signature-based auth required but no signatureGenerator provided');\n }\n\n for (const mapper of mappers) {\n if (!mapper.security || !this.isSignatureBasedAuth(mapper.security)) {\n continue;\n }\n\n // Call signature generator\n const signature = await context.signatureGenerator(signatureData, mapper.security);\n\n // Add signature to appropriate location\n if (mapper.type === 'header') {\n headers[mapper.key] = signature;\n }\n // Note: Query/cookie signatures would be handled differently\n }\n\n return headers;\n }\n}\n\n/**\n * Create a basic security context from common auth sources\n *\n * @example\n * ```typescript\n * const context = createSecurityContext({\n * jwt: process.env.JWT_TOKEN,\n * apiKey: process.env.API_KEY\n * });\n * ```\n */\nexport function createSecurityContext(\n auth: Partial<SecurityContext>\n): SecurityContext {\n return {\n ...auth,\n jwt: auth.jwt,\n basic: auth.basic,\n apiKey: auth.apiKey,\n oauth2Token: auth.oauth2Token,\n customResolver: auth.customResolver,\n };\n}\n"]}
|
package/src/types.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isReferenceObject = isReferenceObject;
|
|
4
|
-
exports.toJsonSchema = toJsonSchema;
|
|
5
|
-
/**
|
|
6
|
-
* Helper to check if an object is a ReferenceObject
|
|
7
|
-
*/
|
|
8
|
-
function isReferenceObject(obj) {
|
|
9
|
-
return obj && typeof obj === 'object' && '$ref' in obj;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Convert OpenAPI schema to JsonSchema
|
|
13
|
-
* Note: OpenAPI 3.0 uses a subset of JSON Schema Draft 4
|
|
14
|
-
* OpenAPI 3.1 uses JSON Schema Draft 2020-12
|
|
15
|
-
*/
|
|
16
|
-
function toJsonSchema(schema) {
|
|
17
|
-
if (isReferenceObject(schema)) {
|
|
18
|
-
return { $ref: schema.$ref };
|
|
19
|
-
}
|
|
20
|
-
// Handle OpenAPI 3.0 boolean exclusiveMaximum/exclusiveMinimum
|
|
21
|
-
// by converting them to JSON Schema Draft 7 numeric format
|
|
22
|
-
const { exclusiveMaximum, exclusiveMinimum, maximum, minimum, ...rest } = schema;
|
|
23
|
-
const result = { ...rest };
|
|
24
|
-
// Handle exclusiveMaximum conversion
|
|
25
|
-
if (typeof exclusiveMaximum === 'boolean') {
|
|
26
|
-
if (exclusiveMaximum && maximum !== undefined) {
|
|
27
|
-
// true + maximum present -> convert to numeric exclusiveMaximum
|
|
28
|
-
result['exclusiveMaximum'] = maximum;
|
|
29
|
-
}
|
|
30
|
-
else if (maximum !== undefined) {
|
|
31
|
-
// false or true without maximum -> keep maximum only
|
|
32
|
-
result['maximum'] = maximum;
|
|
33
|
-
}
|
|
34
|
-
// Boolean exclusiveMaximum is never added (invalid in JSON Schema 7)
|
|
35
|
-
}
|
|
36
|
-
else if (exclusiveMaximum !== undefined) {
|
|
37
|
-
// Already numeric (OpenAPI 3.1) - keep as is
|
|
38
|
-
result['exclusiveMaximum'] = exclusiveMaximum;
|
|
39
|
-
if (maximum !== undefined) {
|
|
40
|
-
result['maximum'] = maximum;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
else if (maximum !== undefined) {
|
|
44
|
-
// No exclusiveMaximum, just maximum
|
|
45
|
-
result['maximum'] = maximum;
|
|
46
|
-
}
|
|
47
|
-
// Handle exclusiveMinimum conversion
|
|
48
|
-
if (typeof exclusiveMinimum === 'boolean') {
|
|
49
|
-
if (exclusiveMinimum && minimum !== undefined) {
|
|
50
|
-
// true + minimum present -> convert to numeric exclusiveMinimum
|
|
51
|
-
result['exclusiveMinimum'] = minimum;
|
|
52
|
-
}
|
|
53
|
-
else if (minimum !== undefined) {
|
|
54
|
-
// false or true without minimum -> keep minimum only
|
|
55
|
-
result['minimum'] = minimum;
|
|
56
|
-
}
|
|
57
|
-
// Boolean exclusiveMinimum is never added (invalid in JSON Schema 7)
|
|
58
|
-
}
|
|
59
|
-
else if (exclusiveMinimum !== undefined) {
|
|
60
|
-
// Already numeric (OpenAPI 3.1) - keep as is
|
|
61
|
-
result['exclusiveMinimum'] = exclusiveMinimum;
|
|
62
|
-
if (minimum !== undefined) {
|
|
63
|
-
result['minimum'] = minimum;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
else if (minimum !== undefined) {
|
|
67
|
-
// No exclusiveMinimum, just minimum
|
|
68
|
-
result['minimum'] = minimum;
|
|
69
|
-
}
|
|
70
|
-
// Recursively convert nested schemas to ensure all nested schemas are valid JsonSchema
|
|
71
|
-
if (result['properties'] && typeof result['properties'] === 'object') {
|
|
72
|
-
const props = {};
|
|
73
|
-
for (const [key, value] of Object.entries(result['properties'])) {
|
|
74
|
-
props[key] = toJsonSchema(value);
|
|
75
|
-
}
|
|
76
|
-
result['properties'] = props;
|
|
77
|
-
}
|
|
78
|
-
if (result['items']) {
|
|
79
|
-
if (Array.isArray(result['items'])) {
|
|
80
|
-
result['items'] = result['items'].map(toJsonSchema);
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
result['items'] = toJsonSchema(result['items']);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (result['additionalProperties'] && typeof result['additionalProperties'] === 'object') {
|
|
87
|
-
result['additionalProperties'] = toJsonSchema(result['additionalProperties']);
|
|
88
|
-
}
|
|
89
|
-
for (const key of ['allOf', 'anyOf', 'oneOf']) {
|
|
90
|
-
if (result[key] && Array.isArray(result[key])) {
|
|
91
|
-
result[key] = result[key].map(toJsonSchema);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
if (result['not']) {
|
|
95
|
-
result['not'] = toJsonSchema(result['not']);
|
|
96
|
-
}
|
|
97
|
-
return result;
|
|
98
|
-
}
|
|
99
|
-
//# sourceMappingURL=types.js.map
|
package/src/types.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { JSONSchema } from 'zod/v4/core';\n\n/** JSON Schema type from Zod v4 */\ntype JsonSchema = JSONSchema.JSONSchema;\nimport type { OpenAPIV3, OpenAPIV3_1 } from 'openapi-types';\n\n/**\n * OpenAPI specification version 3.0.x or 3.1.x\n */\nexport type OpenAPIVersion = '3.0.0' | '3.0.1' | '3.0.2' | '3.0.3' | '3.1.0';\n\n/**\n * Unified OpenAPI Document type (supports both 3.0 and 3.1)\n */\nexport type OpenAPIDocument = OpenAPIV3.Document | OpenAPIV3_1.Document;\n\n/**\n * HTTP methods supported by OpenAPI\n */\nexport type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options' | 'trace';\n\n/**\n * Parameter location types\n */\nexport type ParameterLocation = 'path' | 'query' | 'header' | 'cookie' | 'body';\n\n/**\n * Authentication types supported\n */\nexport type AuthType = 'apiKey' | 'http' | 'oauth2' | 'openIdConnect' | 'mutualTLS';\n\n// Re-export OpenAPI types for convenience\nexport type OperationObject = OpenAPIV3.OperationObject | OpenAPIV3_1.OperationObject;\nexport type ParameterObject = OpenAPIV3.ParameterObject | OpenAPIV3_1.ParameterObject;\nexport type RequestBodyObject = OpenAPIV3.RequestBodyObject | OpenAPIV3_1.RequestBodyObject;\nexport type ResponseObject = OpenAPIV3.ResponseObject | OpenAPIV3_1.ResponseObject;\nexport type ResponsesObject = OpenAPIV3.ResponsesObject | OpenAPIV3_1.ResponsesObject;\nexport type MediaTypeObject = OpenAPIV3.MediaTypeObject | OpenAPIV3_1.MediaTypeObject;\nexport type HeaderObject = OpenAPIV3.HeaderObject | OpenAPIV3_1.HeaderObject;\nexport type ExampleObject = OpenAPIV3.ExampleObject | OpenAPIV3_1.ExampleObject;\nexport type PathItemObject = OpenAPIV3.PathItemObject | OpenAPIV3_1.PathItemObject;\nexport type PathsObject = OpenAPIV3.PathsObject | OpenAPIV3_1.PathsObject;\nexport type ServerObject = OpenAPIV3.ServerObject | OpenAPIV3_1.ServerObject;\nexport type SecuritySchemeObject = OpenAPIV3.SecuritySchemeObject | OpenAPIV3_1.SecuritySchemeObject;\nexport type ReferenceObject = OpenAPIV3.ReferenceObject | OpenAPIV3_1.ReferenceObject;\nexport type TagObject = OpenAPIV3.TagObject | OpenAPIV3_1.TagObject;\nexport type ExternalDocumentationObject =\n | OpenAPIV3.ExternalDocumentationObject\n | OpenAPIV3_1.ExternalDocumentationObject;\nexport type ServerVariableObject = OpenAPIV3.ServerVariableObject | OpenAPIV3_1.ServerVariableObject;\nexport type EncodingObject = OpenAPIV3.EncodingObject | OpenAPIV3_1.EncodingObject;\nexport type SecurityRequirementObject = OpenAPIV3.SecurityRequirementObject | OpenAPIV3_1.SecurityRequirementObject;\nexport type SchemaObject = OpenAPIV3.SchemaObject | OpenAPIV3_1.SchemaObject;\n\n/**\n * Helper to check if an object is a ReferenceObject\n */\nexport function isReferenceObject(obj: any): obj is ReferenceObject {\n return obj && typeof obj === 'object' && '$ref' in obj;\n}\n\n/**\n * Convert OpenAPI schema to JsonSchema\n * Note: OpenAPI 3.0 uses a subset of JSON Schema Draft 4\n * OpenAPI 3.1 uses JSON Schema Draft 2020-12\n */\nexport function toJsonSchema(schema: SchemaObject | ReferenceObject): JsonSchema {\n if (isReferenceObject(schema)) {\n return { $ref: schema.$ref } as JsonSchema;\n }\n\n // Handle OpenAPI 3.0 boolean exclusiveMaximum/exclusiveMinimum\n // by converting them to JSON Schema Draft 7 numeric format\n const { exclusiveMaximum, exclusiveMinimum, maximum, minimum, ...rest } = schema;\n\n const result: Record<string, unknown> = { ...rest };\n\n // Handle exclusiveMaximum conversion\n if (typeof exclusiveMaximum === 'boolean') {\n if (exclusiveMaximum && maximum !== undefined) {\n // true + maximum present -> convert to numeric exclusiveMaximum\n result['exclusiveMaximum'] = maximum;\n } else if (maximum !== undefined) {\n // false or true without maximum -> keep maximum only\n result['maximum'] = maximum;\n }\n // Boolean exclusiveMaximum is never added (invalid in JSON Schema 7)\n } else if (exclusiveMaximum !== undefined) {\n // Already numeric (OpenAPI 3.1) - keep as is\n result['exclusiveMaximum'] = exclusiveMaximum;\n if (maximum !== undefined) {\n result['maximum'] = maximum;\n }\n } else if (maximum !== undefined) {\n // No exclusiveMaximum, just maximum\n result['maximum'] = maximum;\n }\n\n // Handle exclusiveMinimum conversion\n if (typeof exclusiveMinimum === 'boolean') {\n if (exclusiveMinimum && minimum !== undefined) {\n // true + minimum present -> convert to numeric exclusiveMinimum\n result['exclusiveMinimum'] = minimum;\n } else if (minimum !== undefined) {\n // false or true without minimum -> keep minimum only\n result['minimum'] = minimum;\n }\n // Boolean exclusiveMinimum is never added (invalid in JSON Schema 7)\n } else if (exclusiveMinimum !== undefined) {\n // Already numeric (OpenAPI 3.1) - keep as is\n result['exclusiveMinimum'] = exclusiveMinimum;\n if (minimum !== undefined) {\n result['minimum'] = minimum;\n }\n } else if (minimum !== undefined) {\n // No exclusiveMinimum, just minimum\n result['minimum'] = minimum;\n }\n\n // Recursively convert nested schemas to ensure all nested schemas are valid JsonSchema\n if (result['properties'] && typeof result['properties'] === 'object') {\n const props: Record<string, JsonSchema> = {};\n for (const [key, value] of Object.entries(result['properties'] as Record<string, SchemaObject | ReferenceObject>)) {\n props[key] = toJsonSchema(value);\n }\n result['properties'] = props;\n }\n\n if (result['items']) {\n if (Array.isArray(result['items'])) {\n result['items'] = (result['items'] as (SchemaObject | ReferenceObject)[]).map(toJsonSchema);\n } else {\n result['items'] = toJsonSchema(result['items'] as SchemaObject | ReferenceObject);\n }\n }\n\n if (result['additionalProperties'] && typeof result['additionalProperties'] === 'object') {\n result['additionalProperties'] = toJsonSchema(result['additionalProperties'] as SchemaObject | ReferenceObject);\n }\n\n for (const key of ['allOf', 'anyOf', 'oneOf'] as const) {\n if (result[key] && Array.isArray(result[key])) {\n result[key] = (result[key] as (SchemaObject | ReferenceObject)[]).map(toJsonSchema);\n }\n }\n\n if (result['not']) {\n result['not'] = toJsonSchema(result['not'] as SchemaObject | ReferenceObject);\n }\n\n return result as JsonSchema;\n}\n\n/**\n * Main MCP Tool definition generated from OpenAPI\n */\nexport interface McpOpenAPITool {\n /**\n * Unique tool name (from operationId or generated)\n */\n name: string;\n\n /**\n * Tool description (from operation summary/description)\n */\n description: string;\n\n /**\n * Combined input schema including all parameters\n * (path, query, header, cookie, body)\n */\n inputSchema: JsonSchema;\n\n /**\n * Output schema based on response definitions\n * Can be a union of multiple status codes\n */\n outputSchema?: JsonSchema;\n\n /**\n * Mapping from input schema properties to actual request parameters\n */\n mapper: ParameterMapper[];\n\n /**\n * Additional metadata about the tool\n */\n metadata: ToolMetadata;\n}\n\n/**\n * Maps input schema properties to their actual request locations\n */\nexport interface ParameterMapper {\n /**\n * Property name in the input schema\n */\n inputKey: string;\n\n /**\n * Where this parameter should be placed in the request\n */\n type: ParameterLocation;\n\n /**\n * Original parameter name (before conflict resolution)\n */\n key: string;\n\n /**\n * Whether this parameter is required\n */\n required?: boolean;\n\n /**\n * Parameter style (for path/query parameters)\n */\n style?: string;\n\n /**\n * Whether to explode arrays/objects\n */\n explode?: boolean;\n\n /**\n * Custom serialization info\n */\n serialization?: SerializationInfo;\n\n /**\n * Security scheme information (if this is an auth parameter)\n * This allows frameworks to resolve auth from context, env vars, etc.\n */\n security?: SecurityParameterInfo;\n}\n\n/**\n * Serialization information for complex parameters\n */\nexport interface SerializationInfo {\n /**\n * Content type for body parameters\n */\n contentType?: string;\n\n /**\n * Encoding rules\n */\n encoding?: Record<string, EncodingObject>;\n}\n\n/**\n * Security parameter information for framework-agnostic auth resolution\n */\nexport interface SecurityParameterInfo {\n /**\n * Security scheme name from OpenAPI (e.g., \"BearerAuth\")\n */\n scheme: string;\n\n /**\n * Security type (apiKey, http, oauth2, openIdConnect)\n */\n type: AuthType;\n\n /**\n * HTTP authentication scheme (for type: \"http\")\n * e.g., \"bearer\", \"basic\"\n */\n httpScheme?: string;\n\n /**\n * Bearer token format (e.g., \"JWT\")\n */\n bearerFormat?: string;\n\n /**\n * Required OAuth2 scopes\n */\n scopes?: string[];\n\n /**\n * API key parameter name (for type: \"apiKey\")\n */\n apiKeyName?: string;\n\n /**\n * API key location (for type: \"apiKey\")\n */\n apiKeyIn?: 'query' | 'header' | 'cookie';\n\n /**\n * Description of the security scheme\n */\n description?: string;\n}\n\n/**\n * Additional metadata about the generated tool\n */\nexport interface ToolMetadata {\n /**\n * Original OpenAPI path\n */\n path: string;\n\n /**\n * HTTP method\n */\n method: HTTPMethod;\n\n /**\n * Operation ID from OpenAPI\n */\n operationId?: string;\n\n /**\n * Operation summary from OpenAPI (short description)\n */\n operationSummary?: string;\n\n /**\n * Operation description from OpenAPI (detailed description)\n */\n operationDescription?: string;\n\n /**\n * Tags from OpenAPI\n */\n tags?: string[];\n\n /**\n * Whether operation is deprecated\n */\n deprecated?: boolean;\n\n /**\n * Security requirements\n */\n security?: SecurityRequirement[];\n\n /**\n * Server information\n */\n servers?: ServerInfo[];\n\n /**\n * Response status codes included in output schema\n */\n responseStatusCodes?: number[];\n\n /**\n * External documentation\n */\n externalDocs?: ExternalDocumentationObject;\n\n /**\n * FrontMCP extension data from x-frontmcp in the OpenAPI operation.\n * Contains annotations, cache config, codecall config, tags, etc.\n */\n frontmcp?: FrontMcpExtensionData;\n}\n\n/**\n * FrontMCP extension data extracted from x-frontmcp in OpenAPI operations.\n * This provides declarative configuration for tools directly in the OpenAPI spec.\n */\nexport interface FrontMcpExtensionData {\n /**\n * Tool annotations for AI behavior hints.\n */\n annotations?: {\n title?: string;\n readOnlyHint?: boolean;\n destructiveHint?: boolean;\n idempotentHint?: boolean;\n openWorldHint?: boolean;\n };\n\n /**\n * Cache configuration for response caching.\n */\n cache?: {\n ttl?: number;\n slideWindow?: boolean;\n };\n\n /**\n * CodeCall-specific configuration.\n */\n codecall?: {\n enabledInCodeCall?: boolean;\n visibleInListTools?: boolean;\n };\n\n /**\n * Tags/labels for categorization.\n */\n tags?: string[];\n\n /**\n * If true, hide tool from discovery.\n */\n hideFromDiscovery?: boolean;\n\n /**\n * Usage examples.\n */\n examples?: Array<{\n description: string;\n input: Record<string, unknown>;\n output?: unknown;\n }>;\n}\n\n/**\n * Security requirement definition\n */\nexport interface SecurityRequirement {\n /**\n * Security scheme name\n */\n scheme: string;\n\n /**\n * Security type\n */\n type: AuthType;\n\n /**\n * Scopes required (for OAuth2/OpenID Connect)\n */\n scopes?: string[];\n\n /**\n * Parameter name (for API key)\n */\n name?: string;\n\n /**\n * Parameter location (for API key)\n */\n in?: 'query' | 'header' | 'cookie';\n\n /**\n * HTTP authentication scheme (for type: \"http\")\n * e.g., \"bearer\", \"basic\"\n */\n httpScheme?: string;\n\n /**\n * Bearer token format (e.g., \"JWT\")\n */\n bearerFormat?: string;\n\n /**\n * Description of the security scheme\n */\n description?: string;\n}\n\n/**\n * Server information\n */\nexport interface ServerInfo {\n /**\n * Server URL\n */\n url: string;\n\n /**\n * Server description\n */\n description?: string;\n\n /**\n * Server variables\n */\n variables?: Record<string, ServerVariableObject>;\n}\n\n/**\n * Options for loading OpenAPI specifications\n */\nexport interface LoadOptions {\n /**\n * Whether to dereference $refs in schemas\n * @default true\n */\n dereference?: boolean;\n\n /**\n * Base URL for API requests\n * Overrides servers in OpenAPI spec\n */\n baseUrl?: string;\n\n /**\n * Custom HTTP headers for loading from URL\n */\n headers?: Record<string, string>;\n\n /**\n * Request timeout in milliseconds\n * @default 30000\n */\n timeout?: number;\n\n /**\n * Whether to validate the OpenAPI document\n * @default true\n */\n validate?: boolean;\n\n /**\n * Whether to follow HTTP redirects\n * @default true\n */\n followRedirects?: boolean;\n}\n\n/**\n * Operation object with additional context for filtering\n */\nexport type OperationWithContext = OperationObject & {\n path: string;\n method: string;\n};\n\n/**\n * Options for generating tools\n */\nexport interface GenerateOptions {\n /**\n * Include only these operation IDs\n */\n includeOperations?: string[];\n\n /**\n * Exclude these operation IDs\n */\n excludeOperations?: string[];\n\n /**\n * Custom filter function\n */\n filterFn?: (operation: OperationWithContext) => boolean;\n\n /**\n * Naming strategy for resolving conflicts\n */\n namingStrategy?: NamingStrategy;\n\n /**\n * Preferred response status codes (in order of preference)\n * @default [200, 201, 204, 202, 203, 206]\n */\n preferredStatusCodes?: number[];\n\n /**\n * Whether to include deprecated operations\n * @default false\n */\n includeDeprecated?: boolean;\n\n /**\n * Whether to include all response codes in output schema\n * If false, only preferred status code is used\n * @default true\n */\n includeAllResponses?: boolean;\n\n /**\n * Maximum depth for dereferencing schemas\n * @default 10\n */\n maxSchemaDepth?: number;\n\n /**\n * Whether to include examples in schemas\n * @default false\n */\n includeExamples?: boolean;\n\n /**\n * Whether to include security requirements as input parameters\n * If false, security is only in mapper (frameworks resolve from context/env/etc.)\n * If true, security is added to inputSchema as explicit parameters\n * @default false\n */\n includeSecurityInInput?: boolean;\n}\n\n/**\n * Naming strategy for resolving parameter conflicts\n */\nexport interface NamingStrategy {\n /**\n * Resolver function for parameter name conflicts\n * @param paramName - Original parameter name\n * @param location - Parameter location\n * @param index - Index of conflicting parameter (0-based)\n * @returns New parameter name\n */\n conflictResolver: (paramName: string, location: ParameterLocation, index: number) => string;\n\n /**\n * Function to generate tool names\n * @param path - OpenAPI path\n * @param method - HTTP method\n * @param operationId - Operation ID if available\n * @returns Tool name\n */\n toolNameGenerator?: (path: string, method: HTTPMethod, operationId?: string) => string;\n}\n\n/**\n * Validation result\n */\nexport interface ValidationResult {\n /**\n * Whether the document is valid\n */\n valid: boolean;\n\n /**\n * Validation errors\n */\n errors?: ValidationErrorDetail[];\n\n /**\n * Validation warnings\n */\n warnings?: ValidationWarning[];\n}\n\n/**\n * Validation error detail\n */\nexport interface ValidationErrorDetail {\n /**\n * Error message\n */\n message: string;\n\n /**\n * Error path (JSON pointer)\n */\n path?: string;\n\n /**\n * Error code\n */\n code?: string;\n}\n\n/**\n * Validation warning\n */\nexport interface ValidationWarning {\n /**\n * Warning message\n */\n message: string;\n\n /**\n * Warning path (JSON pointer)\n */\n path?: string;\n\n /**\n * Warning code\n */\n code?: string;\n}\n"]}
|
package/src/validator.js
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Validator = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* Validates OpenAPI documents
|
|
6
|
-
*/
|
|
7
|
-
class Validator {
|
|
8
|
-
/**
|
|
9
|
-
* Validate an OpenAPI document
|
|
10
|
-
*/
|
|
11
|
-
async validate(document) {
|
|
12
|
-
const errors = [];
|
|
13
|
-
const warnings = [];
|
|
14
|
-
// Check OpenAPI version
|
|
15
|
-
if (!document.openapi) {
|
|
16
|
-
errors.push({
|
|
17
|
-
message: 'Missing required field: openapi',
|
|
18
|
-
path: '/openapi',
|
|
19
|
-
code: 'MISSING_OPENAPI_VERSION',
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
else if (!this.isValidOpenAPIVersion(document.openapi)) {
|
|
23
|
-
errors.push({
|
|
24
|
-
message: `Unsupported OpenAPI version: ${document.openapi}. Expected 3.0.x or 3.1.x`,
|
|
25
|
-
path: '/openapi',
|
|
26
|
-
code: 'INVALID_OPENAPI_VERSION',
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
// Check info
|
|
30
|
-
if (!document.info) {
|
|
31
|
-
errors.push({
|
|
32
|
-
message: 'Missing required field: info',
|
|
33
|
-
path: '/info',
|
|
34
|
-
code: 'MISSING_INFO',
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
if (!document.info.title) {
|
|
39
|
-
errors.push({
|
|
40
|
-
message: 'Missing required field: info.title',
|
|
41
|
-
path: '/info/title',
|
|
42
|
-
code: 'MISSING_TITLE',
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
if (!document.info.version) {
|
|
46
|
-
errors.push({
|
|
47
|
-
message: 'Missing required field: info.version',
|
|
48
|
-
path: '/info/version',
|
|
49
|
-
code: 'MISSING_VERSION',
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
// Check paths
|
|
54
|
-
if (!document.paths || Object.keys(document.paths).length === 0) {
|
|
55
|
-
warnings.push({
|
|
56
|
-
message: 'No paths defined in OpenAPI document',
|
|
57
|
-
path: '/paths',
|
|
58
|
-
code: 'NO_PATHS',
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
this.validatePaths(document.paths, errors, warnings);
|
|
63
|
-
}
|
|
64
|
-
// Check servers
|
|
65
|
-
if (!document.servers || document.servers.length === 0) {
|
|
66
|
-
warnings.push({
|
|
67
|
-
message: 'No servers defined. You may need to provide a baseUrl option.',
|
|
68
|
-
path: '/servers',
|
|
69
|
-
code: 'NO_SERVERS',
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
// Check security schemes
|
|
73
|
-
if (document.security && !document.components?.securitySchemes) {
|
|
74
|
-
warnings.push({
|
|
75
|
-
message: 'Security requirements defined but no security schemes found',
|
|
76
|
-
path: '/security',
|
|
77
|
-
code: 'NO_SECURITY_SCHEMES',
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
return {
|
|
81
|
-
valid: errors.length === 0,
|
|
82
|
-
errors: errors.length > 0 ? errors : undefined,
|
|
83
|
-
warnings: warnings.length > 0 ? warnings : undefined,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Check if OpenAPI version is valid
|
|
88
|
-
*/
|
|
89
|
-
isValidOpenAPIVersion(version) {
|
|
90
|
-
return /^3\.[01]\.\d+$/.test(version);
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Validate paths
|
|
94
|
-
*/
|
|
95
|
-
validatePaths(paths, errors, warnings) {
|
|
96
|
-
for (const [path, pathItem] of Object.entries(paths)) {
|
|
97
|
-
if (!pathItem)
|
|
98
|
-
continue;
|
|
99
|
-
// Check path format
|
|
100
|
-
if (!path.startsWith('/')) {
|
|
101
|
-
errors.push({
|
|
102
|
-
message: `Path must start with '/': ${path}`,
|
|
103
|
-
path: `/paths/${path}`,
|
|
104
|
-
code: 'INVALID_PATH_FORMAT',
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
// Validate operations
|
|
108
|
-
const methods = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'];
|
|
109
|
-
let hasOperations = false;
|
|
110
|
-
for (const method of methods) {
|
|
111
|
-
const operation = pathItem[method];
|
|
112
|
-
if (operation) {
|
|
113
|
-
hasOperations = true;
|
|
114
|
-
this.validateOperation(operation, path, method, errors, warnings);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
if (!hasOperations && !pathItem.$ref) {
|
|
118
|
-
warnings.push({
|
|
119
|
-
message: `Path has no operations: ${path}`,
|
|
120
|
-
path: `/paths/${path}`,
|
|
121
|
-
code: 'NO_OPERATIONS',
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Validate an operation
|
|
128
|
-
*/
|
|
129
|
-
validateOperation(operation, path, method, errors, warnings) {
|
|
130
|
-
const basePath = `/paths/${path}/${method}`;
|
|
131
|
-
// Check for operationId
|
|
132
|
-
if (!operation.operationId) {
|
|
133
|
-
warnings.push({
|
|
134
|
-
message: `Operation missing operationId: ${method.toUpperCase()} ${path}`,
|
|
135
|
-
path: `${basePath}/operationId`,
|
|
136
|
-
code: 'NO_OPERATION_ID',
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
// Check for responses
|
|
140
|
-
if (!operation.responses || Object.keys(operation.responses).length === 0) {
|
|
141
|
-
errors.push({
|
|
142
|
-
message: `Operation missing responses: ${method.toUpperCase()} ${path}`,
|
|
143
|
-
path: `${basePath}/responses`,
|
|
144
|
-
code: 'NO_RESPONSES',
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
// Validate parameters
|
|
148
|
-
if (operation.parameters) {
|
|
149
|
-
this.validateParameters(operation.parameters, path, method, errors, warnings);
|
|
150
|
-
}
|
|
151
|
-
// Check for path parameters in path string
|
|
152
|
-
const pathParams = path.match(/\{([^}]+)\}/g)?.map((p) => p.slice(1, -1)) ?? [];
|
|
153
|
-
const definedPathParams = new Set(operation.parameters
|
|
154
|
-
?.filter((p) => p.in === 'path')
|
|
155
|
-
.map((p) => p.name) ?? []);
|
|
156
|
-
for (const param of pathParams) {
|
|
157
|
-
if (!definedPathParams.has(param)) {
|
|
158
|
-
errors.push({
|
|
159
|
-
message: `Path parameter '${param}' not defined in parameters: ${method.toUpperCase()} ${path}`,
|
|
160
|
-
path: `${basePath}/parameters`,
|
|
161
|
-
code: 'MISSING_PATH_PARAMETER',
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Validate parameters
|
|
168
|
-
*/
|
|
169
|
-
validateParameters(parameters, path, method, errors, warnings) {
|
|
170
|
-
const basePath = `/paths/${path}/${method}/parameters`;
|
|
171
|
-
for (let i = 0; i < parameters.length; i++) {
|
|
172
|
-
const param = parameters[i];
|
|
173
|
-
const paramPath = `${basePath}/${i}`;
|
|
174
|
-
if (!param.name) {
|
|
175
|
-
errors.push({
|
|
176
|
-
message: 'Parameter missing name',
|
|
177
|
-
path: `${paramPath}/name`,
|
|
178
|
-
code: 'MISSING_PARAMETER_NAME',
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
if (!param.in) {
|
|
182
|
-
errors.push({
|
|
183
|
-
message: 'Parameter missing "in" field',
|
|
184
|
-
path: `${paramPath}/in`,
|
|
185
|
-
code: 'MISSING_PARAMETER_IN',
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
else if (!['path', 'query', 'header', 'cookie'].includes(param.in)) {
|
|
189
|
-
errors.push({
|
|
190
|
-
message: `Invalid parameter location: ${param.in}`,
|
|
191
|
-
path: `${paramPath}/in`,
|
|
192
|
-
code: 'INVALID_PARAMETER_IN',
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
if (param.in === 'path' && !param.required) {
|
|
196
|
-
errors.push({
|
|
197
|
-
message: `Path parameter '${param.name}' must be required`,
|
|
198
|
-
path: `${paramPath}/required`,
|
|
199
|
-
code: 'PATH_PARAMETER_NOT_REQUIRED',
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
if (!param.schema && !param.content) {
|
|
203
|
-
errors.push({
|
|
204
|
-
message: `Parameter '${param.name}' missing schema or content`,
|
|
205
|
-
path: `${paramPath}`,
|
|
206
|
-
code: 'MISSING_PARAMETER_SCHEMA',
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
exports.Validator = Validator;
|
|
213
|
-
//# sourceMappingURL=validator.js.map
|
package/src/validator.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/validator.ts"],"names":[],"mappings":"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","sourcesContent":["import type { OpenAPIDocument, ValidationResult, ValidationErrorDetail, ValidationWarning } from './types';\n\n/**\n * Validates OpenAPI documents\n */\nexport class Validator {\n /**\n * Validate an OpenAPI document\n */\n async validate(document: OpenAPIDocument): Promise<ValidationResult> {\n const errors: ValidationErrorDetail[] = [];\n const warnings: ValidationWarning[] = [];\n\n // Check OpenAPI version\n if (!document.openapi) {\n errors.push({\n message: 'Missing required field: openapi',\n path: '/openapi',\n code: 'MISSING_OPENAPI_VERSION',\n });\n } else if (!this.isValidOpenAPIVersion(document.openapi)) {\n errors.push({\n message: `Unsupported OpenAPI version: ${document.openapi}. Expected 3.0.x or 3.1.x`,\n path: '/openapi',\n code: 'INVALID_OPENAPI_VERSION',\n });\n }\n\n // Check info\n if (!document.info) {\n errors.push({\n message: 'Missing required field: info',\n path: '/info',\n code: 'MISSING_INFO',\n });\n } else {\n if (!document.info.title) {\n errors.push({\n message: 'Missing required field: info.title',\n path: '/info/title',\n code: 'MISSING_TITLE',\n });\n }\n if (!document.info.version) {\n errors.push({\n message: 'Missing required field: info.version',\n path: '/info/version',\n code: 'MISSING_VERSION',\n });\n }\n }\n\n // Check paths\n if (!document.paths || Object.keys(document.paths).length === 0) {\n warnings.push({\n message: 'No paths defined in OpenAPI document',\n path: '/paths',\n code: 'NO_PATHS',\n });\n } else {\n this.validatePaths(document.paths, errors, warnings);\n }\n\n // Check servers\n if (!document.servers || document.servers.length === 0) {\n warnings.push({\n message: 'No servers defined. You may need to provide a baseUrl option.',\n path: '/servers',\n code: 'NO_SERVERS',\n });\n }\n\n // Check security schemes\n if (document.security && !document.components?.securitySchemes) {\n warnings.push({\n message: 'Security requirements defined but no security schemes found',\n path: '/security',\n code: 'NO_SECURITY_SCHEMES',\n });\n }\n\n return {\n valid: errors.length === 0,\n errors: errors.length > 0 ? errors : undefined,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n }\n\n /**\n * Check if OpenAPI version is valid\n */\n private isValidOpenAPIVersion(version: string): boolean {\n return /^3\\.[01]\\.\\d+$/.test(version);\n }\n\n /**\n * Validate paths\n */\n private validatePaths(\n paths: Record<string, any>,\n errors: ValidationErrorDetail[],\n warnings: ValidationWarning[]\n ): void {\n for (const [path, pathItem] of Object.entries(paths)) {\n if (!pathItem) continue;\n\n // Check path format\n if (!path.startsWith('/')) {\n errors.push({\n message: `Path must start with '/': ${path}`,\n path: `/paths/${path}`,\n code: 'INVALID_PATH_FORMAT',\n });\n }\n\n // Validate operations\n const methods = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'];\n let hasOperations = false;\n\n for (const method of methods) {\n const operation = pathItem[method];\n if (operation) {\n hasOperations = true;\n this.validateOperation(operation, path, method, errors, warnings);\n }\n }\n\n if (!hasOperations && !pathItem.$ref) {\n warnings.push({\n message: `Path has no operations: ${path}`,\n path: `/paths/${path}`,\n code: 'NO_OPERATIONS',\n });\n }\n }\n }\n\n /**\n * Validate an operation\n */\n private validateOperation(\n operation: any,\n path: string,\n method: string,\n errors: ValidationErrorDetail[],\n warnings: ValidationWarning[]\n ): void {\n const basePath = `/paths/${path}/${method}`;\n\n // Check for operationId\n if (!operation.operationId) {\n warnings.push({\n message: `Operation missing operationId: ${method.toUpperCase()} ${path}`,\n path: `${basePath}/operationId`,\n code: 'NO_OPERATION_ID',\n });\n }\n\n // Check for responses\n if (!operation.responses || Object.keys(operation.responses).length === 0) {\n errors.push({\n message: `Operation missing responses: ${method.toUpperCase()} ${path}`,\n path: `${basePath}/responses`,\n code: 'NO_RESPONSES',\n });\n }\n\n // Validate parameters\n if (operation.parameters) {\n this.validateParameters(operation.parameters, path, method, errors, warnings);\n }\n\n // Check for path parameters in path string\n const pathParams = path.match(/\\{([^}]+)\\}/g)?.map((p) => p.slice(1, -1)) ?? [];\n const definedPathParams = new Set(\n operation.parameters\n ?.filter((p: any) => p.in === 'path')\n .map((p: any) => p.name) ?? []\n );\n\n for (const param of pathParams) {\n if (!definedPathParams.has(param)) {\n errors.push({\n message: `Path parameter '${param}' not defined in parameters: ${method.toUpperCase()} ${path}`,\n path: `${basePath}/parameters`,\n code: 'MISSING_PATH_PARAMETER',\n });\n }\n }\n }\n\n /**\n * Validate parameters\n */\n private validateParameters(\n parameters: any[],\n path: string,\n method: string,\n errors: ValidationErrorDetail[],\n warnings: ValidationWarning[]\n ): void {\n const basePath = `/paths/${path}/${method}/parameters`;\n\n for (let i = 0; i < parameters.length; i++) {\n const param = parameters[i];\n const paramPath = `${basePath}/${i}`;\n\n if (!param.name) {\n errors.push({\n message: 'Parameter missing name',\n path: `${paramPath}/name`,\n code: 'MISSING_PARAMETER_NAME',\n });\n }\n\n if (!param.in) {\n errors.push({\n message: 'Parameter missing \"in\" field',\n path: `${paramPath}/in`,\n code: 'MISSING_PARAMETER_IN',\n });\n } else if (!['path', 'query', 'header', 'cookie'].includes(param.in)) {\n errors.push({\n message: `Invalid parameter location: ${param.in}`,\n path: `${paramPath}/in`,\n code: 'INVALID_PARAMETER_IN',\n });\n }\n\n if (param.in === 'path' && !param.required) {\n errors.push({\n message: `Path parameter '${param.name}' must be required`,\n path: `${paramPath}/required`,\n code: 'PATH_PARAMETER_NOT_REQUIRED',\n });\n }\n\n if (!param.schema && !param.content) {\n errors.push({\n message: `Parameter '${param.name}' missing schema or content`,\n path: `${paramPath}`,\n code: 'MISSING_PARAMETER_SCHEMA',\n });\n }\n }\n }\n}\n"]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|