librechat-data-provider 0.7.4 → 0.7.7

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 (49) hide show
  1. package/check_updates.sh +1 -0
  2. package/dist/index.es.js +1 -1
  3. package/dist/index.es.js.map +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/react-query/index.es.js +1 -1
  7. package/dist/react-query/index.es.js.map +1 -1
  8. package/dist/react-query/package.json +1 -1
  9. package/package.json +6 -6
  10. package/react-query/package.json +1 -1
  11. package/server-rollup.config.js +3 -3
  12. package/specs/actions.spec.ts +700 -36
  13. package/specs/azure.spec.ts +8 -5
  14. package/specs/filetypes.spec.ts +1 -7
  15. package/specs/mcp.spec.ts +52 -0
  16. package/specs/openapiSpecs.ts +127 -0
  17. package/specs/utils.spec.ts +129 -0
  18. package/src/actions.ts +311 -101
  19. package/src/api-endpoints.ts +70 -13
  20. package/src/artifacts.ts +3104 -0
  21. package/src/azure.ts +40 -33
  22. package/src/bedrock.ts +227 -0
  23. package/src/config.ts +344 -78
  24. package/src/createPayload.ts +3 -1
  25. package/src/data-service.ts +353 -90
  26. package/src/file-config.ts +13 -2
  27. package/src/generate.ts +31 -2
  28. package/src/index.ts +12 -4
  29. package/src/keys.ts +17 -0
  30. package/src/mcp.ts +87 -0
  31. package/src/models.ts +1 -1
  32. package/src/parsers.ts +118 -60
  33. package/src/react-query/react-query-service.ts +54 -115
  34. package/src/request.ts +31 -7
  35. package/src/roles.ts +91 -2
  36. package/src/schemas.ts +513 -340
  37. package/src/types/agents.ts +276 -0
  38. package/src/types/assistants.ts +181 -27
  39. package/src/types/files.ts +6 -0
  40. package/src/types/mutations.ts +170 -7
  41. package/src/types/queries.ts +43 -21
  42. package/src/types/runs.ts +23 -0
  43. package/src/types.ts +132 -67
  44. package/src/utils.ts +44 -0
  45. package/src/zod.spec.ts +526 -0
  46. package/src/zod.ts +86 -0
  47. package/tsconfig.json +1 -2
  48. package/specs/parsers.spec.ts +0 -48
  49. package/src/sse.js +0 -242
package/src/actions.ts CHANGED
@@ -1,8 +1,15 @@
1
- import axios from 'axios';
1
+ import { z } from 'zod';
2
+ import _axios from 'axios';
2
3
  import { URL } from 'url';
3
4
  import crypto from 'crypto';
4
5
  import { load } from 'js-yaml';
5
- import type { FunctionTool, Schema, Reference, ActionMetadata } from './types/assistants';
6
+ import type {
7
+ FunctionTool,
8
+ Schema,
9
+ Reference,
10
+ ActionMetadata,
11
+ ActionMetadataRuntime,
12
+ } from './types/assistants';
6
13
  import type { OpenAPIV3 } from 'openapi-types';
7
14
  import { Tools, AuthTypeEnum, AuthorizationTypeEnum } from './types/assistants';
8
15
 
@@ -10,8 +17,14 @@ export type ParametersSchema = {
10
17
  type: string;
11
18
  properties: Record<string, Reference | Schema>;
12
19
  required: string[];
20
+ additionalProperties?: boolean;
13
21
  };
14
22
 
23
+ export type OpenAPISchema = OpenAPIV3.SchemaObject &
24
+ ParametersSchema & {
25
+ items?: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject;
26
+ };
27
+
15
28
  export type ApiKeyCredentials = {
16
29
  api_key: string;
17
30
  custom_auth_header?: string;
@@ -27,6 +40,16 @@ export type OAuthCredentials = {
27
40
 
28
41
  export type Credentials = ApiKeyCredentials | OAuthCredentials;
29
42
 
43
+ type MediaTypeObject =
44
+ | undefined
45
+ | {
46
+ [media: string]: OpenAPIV3.MediaTypeObject | undefined;
47
+ };
48
+
49
+ type RequestBodyObject = Omit<OpenAPIV3.RequestBodyObject, 'content'> & {
50
+ content: MediaTypeObject;
51
+ };
52
+
30
53
  export function sha1(input: string) {
31
54
  return crypto.createHash('sha1').update(input).digest('hex');
32
55
  }
@@ -38,65 +61,129 @@ export function createURL(domain: string, path: string) {
38
61
  return new URL(fullURL).toString();
39
62
  }
40
63
 
64
+ const schemaTypeHandlers: Record<string, (schema: OpenAPISchema) => z.ZodTypeAny> = {
65
+ string: (schema) => {
66
+ if (schema.enum) {
67
+ return z.enum(schema.enum as [string, ...string[]]);
68
+ }
69
+
70
+ let stringSchema = z.string();
71
+ if (schema.minLength !== undefined) {
72
+ stringSchema = stringSchema.min(schema.minLength);
73
+ }
74
+ if (schema.maxLength !== undefined) {
75
+ stringSchema = stringSchema.max(schema.maxLength);
76
+ }
77
+ return stringSchema;
78
+ },
79
+ number: (schema) => {
80
+ let numberSchema = z.number();
81
+ if (schema.minimum !== undefined) {
82
+ numberSchema = numberSchema.min(schema.minimum);
83
+ }
84
+ if (schema.maximum !== undefined) {
85
+ numberSchema = numberSchema.max(schema.maximum);
86
+ }
87
+ return numberSchema;
88
+ },
89
+ integer: (schema) => (schemaTypeHandlers.number(schema) as z.ZodNumber).int(),
90
+ boolean: () => z.boolean(),
91
+ array: (schema) => {
92
+ if (schema.items) {
93
+ const zodSchema = openAPISchemaToZod(schema.items as OpenAPISchema);
94
+ if (zodSchema) {
95
+ return z.array(zodSchema);
96
+ }
97
+
98
+ return z.array(z.unknown());
99
+ }
100
+ return z.array(z.unknown());
101
+ },
102
+ object: (schema) => {
103
+ const shape: { [key: string]: z.ZodTypeAny } = {};
104
+ if (schema.properties) {
105
+ Object.entries(schema.properties).forEach(([key, value]) => {
106
+ const zodSchema = openAPISchemaToZod(value as OpenAPISchema);
107
+ shape[key] = zodSchema || z.unknown();
108
+ if (schema.required && schema.required.includes(key)) {
109
+ shape[key] = shape[key].describe(value.description || '');
110
+ } else {
111
+ shape[key] = shape[key].optional().describe(value.description || '');
112
+ }
113
+ });
114
+ }
115
+ return z.object(shape);
116
+ },
117
+ };
118
+
119
+ function openAPISchemaToZod(schema: OpenAPISchema): z.ZodTypeAny | undefined {
120
+ if (schema.type === 'object' && Object.keys(schema.properties || {}).length === 0) {
121
+ return undefined;
122
+ }
123
+
124
+ const handler = schemaTypeHandlers[schema.type as string] || (() => z.unknown());
125
+ return handler(schema);
126
+ }
127
+
128
+ /**
129
+ * Class representing a function signature.
130
+ */
41
131
  export class FunctionSignature {
42
132
  name: string;
43
133
  description: string;
44
134
  parameters: ParametersSchema;
135
+ strict: boolean;
45
136
 
46
- constructor(name: string, description: string, parameters: ParametersSchema) {
137
+ constructor(name: string, description: string, parameters: ParametersSchema, strict?: boolean) {
47
138
  this.name = name;
48
139
  this.description = description;
49
- if (parameters.properties?.['requestBody']) {
50
- this.parameters = parameters.properties?.['requestBody'] as ParametersSchema;
51
- } else {
52
- this.parameters = parameters;
53
- }
140
+ this.parameters = parameters;
141
+ this.strict = strict ?? false;
54
142
  }
55
143
 
56
144
  toObjectTool(): FunctionTool {
145
+ const parameters = {
146
+ ...this.parameters,
147
+ additionalProperties: this.strict ? false : undefined,
148
+ };
149
+
57
150
  return {
58
151
  type: Tools.function,
59
152
  function: {
60
153
  name: this.name,
61
154
  description: this.description,
62
- parameters: this.parameters,
155
+ parameters,
156
+ ...(this.strict ? { strict: this.strict } : {}),
63
157
  },
64
158
  };
65
159
  }
66
160
  }
67
161
 
68
- export class ActionRequest {
69
- domain: string;
70
- path: string;
71
- method: string;
72
- operation: string;
73
- operationHash?: string;
74
- isConsequential: boolean;
75
- contentType: string;
76
- params?: object;
77
-
162
+ class RequestConfig {
78
163
  constructor(
79
- domain: string,
80
- path: string,
81
- method: string,
82
- operation: string,
83
- isConsequential: boolean,
84
- contentType: string,
85
- ) {
86
- this.domain = domain;
87
- this.path = path;
88
- this.method = method;
89
- this.operation = operation;
90
- this.isConsequential = isConsequential;
91
- this.contentType = contentType;
92
- }
164
+ readonly domain: string,
165
+ readonly basePath: string,
166
+ readonly method: string,
167
+ readonly operation: string,
168
+ readonly isConsequential: boolean,
169
+ readonly contentType: string,
170
+ ) {}
171
+ }
93
172
 
173
+ class RequestExecutor {
174
+ path: string;
175
+ params?: object;
176
+ private operationHash?: string;
94
177
  private authHeaders: Record<string, string> = {};
95
178
  private authToken?: string;
96
179
 
180
+ constructor(private config: RequestConfig) {
181
+ this.path = config.basePath;
182
+ }
183
+
97
184
  setParams(params: object) {
98
185
  this.operationHash = sha1(JSON.stringify(params));
99
- this.params = params;
186
+ this.params = Object.assign({}, params);
100
187
 
101
188
  for (const [key, value] of Object.entries(params)) {
102
189
  const paramPattern = `{${key}}`;
@@ -105,11 +192,12 @@ export class ActionRequest {
105
192
  delete (this.params as Record<string, unknown>)[key];
106
193
  }
107
194
  }
195
+ return this;
108
196
  }
109
197
 
110
- async setAuth(metadata: ActionMetadata) {
198
+ async setAuth(metadata: ActionMetadataRuntime) {
111
199
  if (!metadata.auth) {
112
- return;
200
+ return this;
113
201
  }
114
202
 
115
203
  const {
@@ -130,17 +218,25 @@ export class ActionRequest {
130
218
  /* OAuth */
131
219
  oauth_client_id,
132
220
  oauth_client_secret,
221
+ oauth_token_expires_at,
222
+ oauth_access_token = '',
133
223
  } = metadata;
134
224
 
135
- const isApiKey = api_key && type === AuthTypeEnum.ServiceHttp;
136
- const isOAuth =
225
+ const isApiKey = api_key != null && api_key.length > 0 && type === AuthTypeEnum.ServiceHttp;
226
+ const isOAuth = !!(
227
+ oauth_client_id != null &&
137
228
  oauth_client_id &&
229
+ oauth_client_secret != null &&
138
230
  oauth_client_secret &&
139
231
  type === AuthTypeEnum.OAuth &&
232
+ authorization_url != null &&
140
233
  authorization_url &&
234
+ client_url != null &&
141
235
  client_url &&
236
+ scope != null &&
142
237
  scope &&
143
- token_exchange_method;
238
+ token_exchange_method
239
+ );
144
240
 
145
241
  if (isApiKey && authorization_type === AuthorizationTypeEnum.Basic) {
146
242
  const basicToken = Buffer.from(api_key).toString('base64');
@@ -150,39 +246,42 @@ export class ActionRequest {
150
246
  } else if (
151
247
  isApiKey &&
152
248
  authorization_type === AuthorizationTypeEnum.Custom &&
249
+ custom_auth_header != null &&
153
250
  custom_auth_header
154
251
  ) {
155
252
  this.authHeaders[custom_auth_header] = api_key;
156
253
  } else if (isOAuth) {
157
- // TODO: WIP - OAuth support
158
- if (!this.authToken) {
159
- const tokenResponse = await axios.post(
160
- client_url,
161
- {
162
- client_id: oauth_client_id,
163
- client_secret: oauth_client_secret,
164
- scope: scope,
165
- grant_type: 'client_credentials',
166
- },
167
- {
168
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
169
- },
170
- );
171
- this.authToken = tokenResponse.data.access_token;
254
+ // TODO: maybe doing it in a different way later on. but we want that the user needs to folllow the oauth flow.
255
+ // If we do not have a valid token, bail or ask user to sign in
256
+ const now = new Date();
257
+
258
+ // 1. Check if token is set
259
+ if (!oauth_access_token) {
260
+ throw new Error('No access token found. Please log in first.');
172
261
  }
262
+
263
+ // 2. Check if token is expired
264
+ if (oauth_token_expires_at && now >= new Date(oauth_token_expires_at)) {
265
+ // Optionally check refresh_token logic, or just prompt user to re-login
266
+ throw new Error('Access token is expired. Please re-login.');
267
+ }
268
+
269
+ // If valid, use it
270
+ this.authToken = oauth_access_token;
173
271
  this.authHeaders['Authorization'] = `Bearer ${this.authToken}`;
174
272
  }
273
+ return this;
175
274
  }
176
275
 
177
276
  async execute() {
178
- const url = createURL(this.domain, this.path);
277
+ const url = createURL(this.config.domain, this.path);
179
278
  const headers = {
180
279
  ...this.authHeaders,
181
- 'Content-Type': this.contentType,
280
+ 'Content-Type': this.config.contentType,
182
281
  };
183
282
 
184
- const method = this.method.toLowerCase();
185
-
283
+ const method = this.config.method.toLowerCase();
284
+ const axios = _axios.create();
186
285
  if (method === 'get') {
187
286
  return axios.get(url, { headers, params: this.params });
188
287
  } else if (method === 'post') {
@@ -194,39 +293,114 @@ export class ActionRequest {
194
293
  } else if (method === 'patch') {
195
294
  return axios.patch(url, this.params, { headers });
196
295
  } else {
197
- throw new Error(`Unsupported HTTP method: ${this.method}`);
296
+ throw new Error(`Unsupported HTTP method: ${method}`);
198
297
  }
199
298
  }
299
+
300
+ getConfig() {
301
+ return this.config;
302
+ }
303
+ }
304
+
305
+ export class ActionRequest {
306
+ private config: RequestConfig;
307
+
308
+ constructor(
309
+ domain: string,
310
+ path: string,
311
+ method: string,
312
+ operation: string,
313
+ isConsequential: boolean,
314
+ contentType: string,
315
+ ) {
316
+ this.config = new RequestConfig(domain, path, method, operation, isConsequential, contentType);
317
+ }
318
+
319
+ // Add getters to maintain backward compatibility
320
+ get domain() {
321
+ return this.config.domain;
322
+ }
323
+ get path() {
324
+ return this.config.basePath;
325
+ }
326
+ get method() {
327
+ return this.config.method;
328
+ }
329
+ get operation() {
330
+ return this.config.operation;
331
+ }
332
+ get isConsequential() {
333
+ return this.config.isConsequential;
334
+ }
335
+ get contentType() {
336
+ return this.config.contentType;
337
+ }
338
+
339
+ createExecutor() {
340
+ return new RequestExecutor(this.config);
341
+ }
342
+
343
+ // Maintain backward compatibility by delegating to a new executor
344
+ setParams(params: object) {
345
+ const executor = this.createExecutor();
346
+ executor.setParams(params);
347
+ return executor;
348
+ }
349
+
350
+ async setAuth(metadata: ActionMetadata) {
351
+ const executor = this.createExecutor();
352
+ return executor.setAuth(metadata);
353
+ }
354
+
355
+ async execute() {
356
+ const executor = this.createExecutor();
357
+ return executor.execute();
358
+ }
200
359
  }
201
360
 
202
- export function resolveRef(
203
- schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | OpenAPIV3.RequestBodyObject,
204
- components?: OpenAPIV3.ComponentsObject,
205
- ): OpenAPIV3.SchemaObject {
206
- if ('$ref' in schema && components) {
207
- const refPath = schema.$ref.replace(/^#\/components\/schemas\//, '');
208
- const resolvedSchema = components.schemas?.[refPath];
209
- if (!resolvedSchema) {
210
- throw new Error(`Reference ${schema.$ref} not found`);
361
+ export function resolveRef<
362
+ T extends
363
+ | OpenAPIV3.ReferenceObject
364
+ | OpenAPIV3.SchemaObject
365
+ | OpenAPIV3.ParameterObject
366
+ | OpenAPIV3.RequestBodyObject,
367
+ >(obj: T, components?: OpenAPIV3.ComponentsObject): Exclude<T, OpenAPIV3.ReferenceObject> {
368
+ if ('$ref' in obj && components) {
369
+ const refPath = obj.$ref.replace(/^#\/components\//, '').split('/');
370
+
371
+ let resolved: unknown = components as Record<string, unknown>;
372
+ for (const segment of refPath) {
373
+ if (typeof resolved === 'object' && resolved !== null && segment in resolved) {
374
+ resolved = (resolved as Record<string, unknown>)[segment];
375
+ } else {
376
+ throw new Error(`Could not resolve reference: ${obj.$ref}`);
377
+ }
211
378
  }
212
- return resolveRef(resolvedSchema, components);
379
+
380
+ return resolveRef(resolved as typeof obj, components) as Exclude<T, OpenAPIV3.ReferenceObject>;
213
381
  }
214
- return schema as OpenAPIV3.SchemaObject;
382
+
383
+ return obj as Exclude<T, OpenAPIV3.ReferenceObject>;
215
384
  }
216
385
 
217
386
  function sanitizeOperationId(input: string) {
218
387
  return input.replace(/[^a-zA-Z0-9_-]/g, '');
219
388
  }
220
389
 
221
- /** Function to convert OpenAPI spec to function signatures and request builders */
222
- export function openapiToFunction(openapiSpec: OpenAPIV3.Document): {
390
+ /**
391
+ * Converts an OpenAPI spec to function signatures and request builders.
392
+ */
393
+ export function openapiToFunction(
394
+ openapiSpec: OpenAPIV3.Document,
395
+ generateZodSchemas = false,
396
+ ): {
223
397
  functionSignatures: FunctionSignature[];
224
398
  requestBuilders: Record<string, ActionRequest>;
399
+ zodSchemas?: Record<string, z.ZodTypeAny>;
225
400
  } {
226
401
  const functionSignatures: FunctionSignature[] = [];
227
402
  const requestBuilders: Record<string, ActionRequest> = {};
228
-
229
- // Base URL from OpenAPI spec servers
403
+ const zodSchemas: Record<string, z.ZodTypeAny> = {};
230
404
  const baseUrl = openapiSpec.servers?.[0]?.url ?? '';
231
405
 
232
406
  // Iterate over each path and method in the OpenAPI spec
@@ -234,45 +408,70 @@ export function openapiToFunction(openapiSpec: OpenAPIV3.Document): {
234
408
  for (const [method, operation] of Object.entries(methods as OpenAPIV3.PathsObject)) {
235
409
  const operationObj = operation as OpenAPIV3.OperationObject & {
236
410
  'x-openai-isConsequential'?: boolean;
411
+ } & {
412
+ 'x-strict'?: boolean;
237
413
  };
238
414
 
239
415
  // Operation ID is used as the function name
240
416
  const defaultOperationId = `${method}_${path}`;
241
417
  const operationId = operationObj.operationId || sanitizeOperationId(defaultOperationId);
242
418
  const description = operationObj.summary || operationObj.description || '';
419
+ const isStrict = operationObj['x-strict'] ?? false;
420
+
421
+ const parametersSchema: OpenAPISchema = {
422
+ type: 'object',
423
+ properties: {},
424
+ required: [],
425
+ };
426
+
427
+ if (operationObj.parameters) {
428
+ for (const param of operationObj.parameters ?? []) {
429
+ const resolvedParam = resolveRef(
430
+ param,
431
+ openapiSpec.components,
432
+ ) as OpenAPIV3.ParameterObject;
243
433
 
244
- const parametersSchema: ParametersSchema = { type: 'object', properties: {}, required: [] };
434
+ const paramName = resolvedParam.name;
435
+ if (!paramName || !resolvedParam.schema) {
436
+ continue;
437
+ }
438
+
439
+ const paramSchema = resolveRef(
440
+ resolvedParam.schema,
441
+ openapiSpec.components,
442
+ ) as OpenAPIV3.SchemaObject;
443
+
444
+ parametersSchema.properties[paramName] = paramSchema;
445
+ if (resolvedParam.required) {
446
+ parametersSchema.required.push(paramName);
447
+ }
448
+ }
449
+ }
245
450
 
246
451
  if (operationObj.requestBody) {
247
- const requestBody = operationObj.requestBody as OpenAPIV3.RequestBodyObject;
452
+ const requestBody = operationObj.requestBody as RequestBodyObject;
248
453
  const content = requestBody.content;
249
- const contentType = Object.keys(content)[0];
250
- const schema = content[contentType]?.schema;
454
+ const contentType = Object.keys(content ?? {})[0];
455
+ const schema = content?.[contentType]?.schema;
251
456
  const resolvedSchema = resolveRef(
252
457
  schema as OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject,
253
458
  openapiSpec.components,
254
459
  );
255
- parametersSchema.properties['requestBody'] = resolvedSchema;
256
- }
257
-
258
- if (operationObj.parameters) {
259
- for (const param of operationObj.parameters) {
260
- const paramObj = param as OpenAPIV3.ParameterObject;
261
- const resolvedSchema = resolveRef(
262
- { ...paramObj.schema } as OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject,
263
- openapiSpec.components,
264
- );
265
- parametersSchema.properties[paramObj.name] = resolvedSchema;
266
- if (paramObj.required) {
267
- parametersSchema.required.push(paramObj.name);
268
- }
269
- if (paramObj.description && !('$$ref' in parametersSchema.properties[paramObj.name])) {
270
- parametersSchema.properties[paramObj.name].description = paramObj.description;
271
- }
460
+ parametersSchema.properties = {
461
+ ...parametersSchema.properties,
462
+ ...resolvedSchema.properties,
463
+ };
464
+ if (resolvedSchema.required) {
465
+ parametersSchema.required.push(...resolvedSchema.required);
272
466
  }
273
467
  }
274
468
 
275
- const functionSignature = new FunctionSignature(operationId, description, parametersSchema);
469
+ const functionSignature = new FunctionSignature(
470
+ operationId,
471
+ description,
472
+ parametersSchema,
473
+ isStrict,
474
+ );
276
475
  functionSignatures.push(functionSignature);
277
476
 
278
477
  const actionRequest = new ActionRequest(
@@ -280,15 +479,22 @@ export function openapiToFunction(openapiSpec: OpenAPIV3.Document): {
280
479
  path,
281
480
  method,
282
481
  operationId,
283
- !!operationObj['x-openai-isConsequential'], // Custom extension for consequential actions
284
- operationObj.requestBody ? 'application/json' : 'application/x-www-form-urlencoded',
482
+ !!(operationObj['x-openai-isConsequential'] ?? false),
483
+ operationObj.requestBody ? 'application/json' : '',
285
484
  );
286
485
 
287
486
  requestBuilders[operationId] = actionRequest;
487
+
488
+ if (generateZodSchemas && Object.keys(parametersSchema.properties).length > 0) {
489
+ const schema = openAPISchemaToZod(parametersSchema);
490
+ if (schema) {
491
+ zodSchemas[operationId] = schema;
492
+ }
493
+ }
288
494
  }
289
495
  }
290
496
 
291
- return { functionSignatures, requestBuilders };
497
+ return { functionSignatures, requestBuilders, zodSchemas };
292
498
  }
293
499
 
294
500
  export type ValidationResult = {
@@ -297,6 +503,9 @@ export type ValidationResult = {
297
503
  spec?: OpenAPIV3.Document;
298
504
  };
299
505
 
506
+ /**
507
+ * Validates and parses an OpenAPI spec.
508
+ */
300
509
  export function validateAndParseOpenAPISpec(specString: string): ValidationResult {
301
510
  try {
302
511
  let parsedSpec;
@@ -331,10 +540,10 @@ export function validateAndParseOpenAPISpec(specString: string): ValidationResul
331
540
  for (const [path, methods] of Object.entries(paths)) {
332
541
  for (const [httpMethod, operation] of Object.entries(methods as OpenAPIV3.PathItemObject)) {
333
542
  // Ensure operation is a valid operation object
334
- const { responses } = operation as OpenAPIV3.OperationObject;
543
+ const { responses } = operation as OpenAPIV3.OperationObject | { responses: undefined };
335
544
  if (typeof operation === 'object' && responses) {
336
545
  for (const [statusCode, response] of Object.entries(responses)) {
337
- const content = (response as OpenAPIV3.ResponseObject).content;
546
+ const content = (response as OpenAPIV3.ResponseObject).content as MediaTypeObject;
338
547
  if (content && content['application/json'] && content['application/json'].schema) {
339
548
  const schema = content['application/json'].schema;
340
549
  if ('$ref' in schema && typeof schema.$ref === 'string') {
@@ -357,6 +566,7 @@ export function validateAndParseOpenAPISpec(specString: string): ValidationResul
357
566
  spec: parsedSpec,
358
567
  };
359
568
  } catch (error) {
569
+ console.error(error);
360
570
  return { status: false, message: 'Error parsing OpenAPI spec.' };
361
571
  }
362
572
  }