@hedystia/swagger 2.3.3 → 2.3.5

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/dist/swagger.cjs CHANGED
@@ -41,34 +41,59 @@ var Swagger = class {
41
41
  if (tags) operationObject.tags = tags;
42
42
  this.spec.paths[normalizedPath][methodLower] = operationObject;
43
43
  }
44
+ extractJsonSchema(schema) {
45
+ if (!schema) return {};
46
+ const js = schema.jsonSchema || schema;
47
+ if (js.type || js.properties || js.$ref || js.items) {
48
+ const standardProps = [
49
+ "type",
50
+ "properties",
51
+ "required",
52
+ "items",
53
+ "enum",
54
+ "nullable",
55
+ "format",
56
+ "description",
57
+ "title",
58
+ "default",
59
+ "minimum",
60
+ "maximum",
61
+ "minLength",
62
+ "maxLength",
63
+ "pattern",
64
+ "anyOf",
65
+ "oneOf",
66
+ "allOf",
67
+ "not",
68
+ "$ref",
69
+ "additionalProperties"
70
+ ];
71
+ const filtered = {};
72
+ for (const prop of standardProps) if (js[prop] !== void 0) filtered[prop] = js[prop];
73
+ return filtered;
74
+ }
75
+ return {};
76
+ }
44
77
  buildParameters(schema) {
45
78
  const parameters = [];
46
- if (schema.params) try {
47
- const jsonSchema = schema.params;
48
- if (jsonSchema.properties) Object.entries(jsonSchema.properties).forEach(([name, propSchema]) => {
49
- parameters.push({
50
- name,
51
- in: "path",
52
- required: jsonSchema.required?.includes(name) ?? true,
53
- schema: propSchema
54
- });
79
+ const paramsSchema = this.extractJsonSchema(schema.params);
80
+ if (paramsSchema.properties) Object.entries(paramsSchema.properties).forEach(([name, propSchema]) => {
81
+ parameters.push({
82
+ name,
83
+ in: "path",
84
+ required: paramsSchema.required?.includes(name) ?? true,
85
+ schema: propSchema
55
86
  });
56
- } catch (e) {
57
- console.error("Failed to convert params schema:", e);
58
- }
59
- if (schema.query) try {
60
- const jsonSchema = schema.query;
61
- if (jsonSchema.properties) Object.entries(jsonSchema.properties).forEach(([name, propSchema]) => {
62
- parameters.push({
63
- name,
64
- in: "query",
65
- required: jsonSchema.required?.includes(name) ?? false,
66
- schema: propSchema
67
- });
87
+ });
88
+ const querySchema = this.extractJsonSchema(schema.query);
89
+ if (querySchema.properties) Object.entries(querySchema.properties).forEach(([name, propSchema]) => {
90
+ parameters.push({
91
+ name,
92
+ in: "query",
93
+ required: querySchema.required?.includes(name) ?? false,
94
+ schema: propSchema
68
95
  });
69
- } catch (e) {
70
- console.error("Failed to convert query schema:", e);
71
- }
96
+ });
72
97
  return parameters.length > 0 ? parameters : void 0;
73
98
  }
74
99
  buildRequestBody(schema) {
@@ -76,7 +101,7 @@ var Swagger = class {
76
101
  try {
77
102
  return {
78
103
  required: true,
79
- content: { "application/json": { schema: schema.body } }
104
+ content: { "application/json": { schema: this.extractJsonSchema(schema.body) } }
80
105
  };
81
106
  } catch (e) {
82
107
  console.error("Failed to convert body schema:", e);
@@ -86,7 +111,7 @@ var Swagger = class {
86
111
  buildResponses(schema) {
87
112
  const responses = { "200": { description: "Successful response" } };
88
113
  if (schema.response) try {
89
- const jsonSchema = schema.response;
114
+ const jsonSchema = this.extractJsonSchema(schema.response);
90
115
  responses["200"].content = { "application/json": { schema: jsonSchema } };
91
116
  } catch (e) {
92
117
  console.error("Failed to convert response schema:", e);
@@ -107,12 +132,6 @@ var Swagger = class {
107
132
  }
108
133
  generateHTML() {
109
134
  const hostname = new URL(this.host).hostname;
110
- const extractJsonSchema = (schema) => {
111
- if (!schema) return {};
112
- if (schema.jsonSchema) return schema.jsonSchema;
113
- if (schema.type || schema.properties || schema.$ref) return schema;
114
- return {};
115
- };
116
135
  const groupedPaths = {};
117
136
  const defaultGroup = "API";
118
137
  Object.entries(this.spec.paths || {}).forEach(([path, pathItem]) => {
@@ -223,7 +242,7 @@ var Swagger = class {
223
242
  let requestBodySection = "";
224
243
  if (operation.requestBody) {
225
244
  const schema = operation.requestBody.content?.["application/json"]?.schema;
226
- const cleanSchema = extractJsonSchema(schema);
245
+ const cleanSchema = this.extractJsonSchema(schema);
227
246
  if (cleanSchema.properties) requestBodySection = `
228
247
  <div>
229
248
  <h4 class="text-lg font-semibold text-white mb-3">Body Parameters</h4>
@@ -246,7 +265,7 @@ var Swagger = class {
246
265
  if (operation.requestBody) {
247
266
  curlCommand += ` \\\n -H 'Content-Type: application/json'`;
248
267
  const schema = operation.requestBody.content?.["application/json"]?.schema;
249
- const cleanSchema = extractJsonSchema(schema);
268
+ const cleanSchema = this.extractJsonSchema(schema);
250
269
  if (cleanSchema.properties) {
251
270
  const exampleData = {};
252
271
  Object.entries(cleanSchema.properties).forEach(([propName, propSchema]) => {
@@ -276,7 +295,7 @@ var Swagger = class {
276
295
  const response200 = operation.responses?.["200"];
277
296
  if (response200?.content?.["application/json"]?.schema) {
278
297
  const schema = response200.content["application/json"].schema;
279
- const cleanSchema = extractJsonSchema(schema);
298
+ const cleanSchema = this.extractJsonSchema(schema);
280
299
  responseSection = `
281
300
  <div>
282
301
  <h4 class="text-lg font-semibold text-white mb-4">Response Schema</h4>
@@ -1 +1 @@
1
- {"version":3,"file":"swagger.cjs","names":["SwaggerParser"],"sources":["../src/swagger.ts"],"sourcesContent":["import SwaggerParser from \"@apidevtools/swagger-parser\";\nimport type { OpenAPI } from \"openapi-types\";\n\nexport interface SwaggerOptions {\n title?: string;\n description?: string;\n version?: string;\n basePath?: string;\n schemes?: string[];\n consumes?: string[];\n produces?: string[];\n tags?: { name: string; description?: string }[];\n securityDefinitions?: Record<string, any>;\n externalDocs?: { description: string; url: string };\n host?: string;\n}\n\nexport class Swagger {\n private spec: OpenAPI.Document = {\n openapi: \"3.0.0\",\n info: {\n title: \"API Documentation\",\n version: \"1.0.0\",\n },\n paths: {},\n components: {\n schemas: {},\n },\n } as OpenAPI.Document;\n host: string;\n\n constructor(options: SwaggerOptions = {}) {\n this.spec.info.title = options.title || \"API Documentation\";\n this.spec.info.description = options.description;\n this.spec.info.version = options.version || \"1.0.0\";\n this.host = options.host || \"https://example.com\";\n\n if (options.tags) {\n this.spec.tags = options.tags;\n }\n\n if (options.externalDocs) {\n this.spec.externalDocs = options.externalDocs;\n }\n\n if (options.securityDefinitions) {\n (this.spec as any).components = (this.spec as any).components || {};\n (this.spec as any).components.securitySchemes = options.securityDefinitions;\n }\n }\n\n addRoute(\n method: string,\n path: string,\n schema: any,\n summary?: string,\n description?: string,\n tags?: string[],\n ) {\n if (!schema) {\n return;\n }\n\n const normalizedPath = path.replace(/:([^/]+)/g, \"{$1}\");\n if (!this.spec.paths) {\n this.spec.paths = {};\n }\n if (!this.spec.paths[normalizedPath]) {\n this.spec.paths[normalizedPath] = {};\n }\n\n const methodLower = method.toLowerCase();\n const operationObject: any = {\n summary: summary || `${method} ${path}`,\n parameters: this.buildParameters(schema),\n requestBody: this.buildRequestBody(schema),\n responses: this.buildResponses(schema),\n };\n\n if (description) {\n operationObject.description = description;\n }\n\n if (tags) {\n operationObject.tags = tags;\n }\n\n (this.spec.paths as any)[normalizedPath][methodLower] = operationObject;\n }\n\n private buildParameters(schema: any) {\n const parameters: any[] = [];\n\n if (schema.params) {\n try {\n const jsonSchema = schema.params;\n if (jsonSchema.properties) {\n Object.entries(jsonSchema.properties).forEach(([name, propSchema]: [string, any]) => {\n parameters.push({\n name,\n in: \"path\",\n required: jsonSchema.required?.includes(name) ?? true,\n schema: propSchema,\n });\n });\n }\n } catch (e) {\n console.error(\"Failed to convert params schema:\", e);\n }\n }\n\n if (schema.query) {\n try {\n const jsonSchema = schema.query;\n if (jsonSchema.properties) {\n Object.entries(jsonSchema.properties).forEach(([name, propSchema]: [string, any]) => {\n parameters.push({\n name,\n in: \"query\",\n required: jsonSchema.required?.includes(name) ?? false,\n schema: propSchema,\n });\n });\n }\n } catch (e) {\n console.error(\"Failed to convert query schema:\", e);\n }\n }\n\n return parameters.length > 0 ? parameters : undefined;\n }\n\n private buildRequestBody(schema: any) {\n if (!schema.body) {\n return undefined;\n }\n\n try {\n const jsonSchema = schema.body;\n return {\n required: true,\n content: {\n \"application/json\": {\n schema: jsonSchema,\n },\n },\n };\n } catch (e) {\n console.error(\"Failed to convert body schema:\", e);\n return undefined;\n }\n }\n\n private buildResponses(schema: any) {\n const responses: Record<string, any> = {\n \"200\": {\n description: \"Successful response\",\n },\n };\n\n if (schema.response) {\n try {\n const jsonSchema = schema.response;\n responses[\"200\"].content = {\n \"application/json\": {\n schema: jsonSchema,\n },\n };\n } catch (e) {\n console.error(\"Failed to convert response schema:\", e);\n }\n }\n\n return responses;\n }\n\n async validate() {\n try {\n await SwaggerParser.validate(this.spec as any);\n return true;\n } catch (error) {\n console.error(\"Swagger validation error:\", error);\n return false;\n }\n }\n\n getSpec() {\n return this.spec;\n }\n\n generateHTML(): string {\n const hostname = new URL(this.host).hostname;\n\n const extractJsonSchema = (schema: any): any => {\n // biome-ignore lint/style/useBlockStatements: off\n if (!schema) return {};\n\n if (schema.jsonSchema) {\n return schema.jsonSchema;\n }\n\n if (schema.type || schema.properties || schema.$ref) {\n return schema;\n }\n\n return {};\n };\n\n const groupedPaths: Record<\n string,\n Array<{\n path: string;\n method: string;\n operation: any;\n }>\n > = {};\n\n const defaultGroup = \"API\";\n\n Object.entries(this.spec.paths || {}).forEach(([path, pathItem]: [string, any]) => {\n Object.entries(pathItem).forEach(([method, operation]: [string, any]) => {\n const tags = operation.tags || [defaultGroup];\n const primaryTag = tags[0];\n\n if (!groupedPaths[primaryTag]) {\n groupedPaths[primaryTag] = [];\n }\n\n groupedPaths[primaryTag].push({\n path,\n method: method.toUpperCase(),\n operation,\n });\n });\n });\n\n const sidebarSections = Object.entries(groupedPaths)\n .map(([tag, endpoints]) => {\n const endpointCount = endpoints.length;\n const endpointLinks = endpoints\n .map(({ path, method }) => {\n const operationId = `${method.toLowerCase()}-${path.replace(/[^a-zA-Z0-9]/g, \"-\")}`;\n return `<li><a href=\"#${operationId}\" class=\"block px-3 py-1.5 rounded-lg hover:bg-dark-700/50 transition-colors text-sm text-gray-400 hover:text-white\">${method} ${path}</a></li>`;\n })\n .join(\"\\n \");\n\n return `\n <div>\n <button class=\"sidebar-group-toggle w-full flex items-center justify-between px-3 py-2 hover:bg-dark-700/30 rounded-lg transition-colors group\" data-target=\"${tag.toLowerCase()}-group\">\n <div class=\"flex items-center space-x-2\">\n <h3 class=\"text-sm font-medium text-gray-300 group-hover:text-white\">${tag}</h3>\n <span class=\"text-xs text-gray-500 bg-dark-600 px-2 py-0.5 rounded-full\">${endpointCount}</span>\n <svg class=\"w-4 h-4 text-gray-400 transform transition-transform duration-200 group-hover:text-gray-300\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\"></path>\n </svg>\n </div>\n </button>\n <div id=\"${tag.toLowerCase()}-group\" class=\"sidebar-group-content max-h-0 overflow-hidden transition-all duration-300\">\n <ul class=\"ml-6 mt-1 space-y-1\">\n ${endpointLinks}\n </ul>\n </div>\n </div>\n\n <div class=\"border-t border-dark-600 my-3\"></div>`;\n })\n .join(\"\");\n\n const contentSections = Object.entries(groupedPaths)\n .map(([tag, endpoints]) => {\n const tagDescription =\n this.spec.tags?.find((t) => t.name === tag)?.description ||\n `Manage ${tag.toLowerCase()} operations`;\n\n const endpointCards = endpoints\n .map(({ path, method, operation }) => {\n const operationId = `${method.toLowerCase()}-${path.replace(/[^a-zA-Z0-9]/g, \"-\")}`;\n const methodColor =\n {\n GET: \"bg-green-600\",\n POST: \"bg-blue-600\",\n PUT: \"bg-yellow-600\",\n DELETE: \"bg-red-600\",\n PATCH: \"bg-purple-600\",\n WS: \"bg-indigo-600\",\n SUB: \"bg-pink-600\",\n }[method] || \"bg-gray-600\";\n\n return `\n <a href=\"#${operationId}\" class=\"block p-4 rounded-lg border border-dark-600 hover:border-blue-500 hover:bg-dark-700/30 transition-all group\">\n <div class=\"flex items-center justify-between mb-2\">\n <div class=\"flex items-center space-x-3\">\n <span class=\"${methodColor} text-white px-3 py-1 rounded-lg text-sm font-medium\">${method}</span>\n <code class=\"text-blue-400 font-mono\">${path}</code>\n </div>\n <svg class=\"w-5 h-5 text-gray-400 group-hover:text-blue-400 transition-colors\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\"></path>\n </svg>\n </div>\n <p class=\"text-gray-300 text-sm\">${operation.summary || operation.description || `${method} ${path} operation`}</p>\n </a>`;\n })\n .join(\"\\n\");\n\n const detailedEndpoints = endpoints\n .map(({ path, method, operation }) => {\n const operationId = `${method.toLowerCase()}-${path.replace(/[^a-zA-Z0-9]/g, \"-\")}`;\n const methodColor =\n {\n GET: \"bg-green-600\",\n POST: \"bg-blue-600\",\n PUT: \"bg-yellow-600\",\n DELETE: \"bg-red-600\",\n PATCH: \"bg-purple-600\",\n WS: \"bg-indigo-600\",\n SUB: \"bg-pink-600\",\n }[method] || \"bg-gray-600\";\n\n let parametersSection = \"\";\n if (operation.parameters && operation.parameters.length > 0) {\n const pathParams = operation.parameters.filter((p: any) => p.in === \"path\");\n const queryParams = operation.parameters.filter((p: any) => p.in === \"query\");\n\n if (pathParams.length > 0) {\n parametersSection += `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Path Parameters</h4>\n <div class=\"space-y-3\">\n ${pathParams\n .map(\n (param: any) => `\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">${param.name}</code>\n <span class=\"text-xs ${param.required ? \"text-red-400\" : \"text-gray-400\"}\">${param.required ? \"required\" : \"optional\"}</span>\n </div>\n <p class=\"text-sm text-gray-300\">${param.description || `${param.name} parameter`}</p>\n </div>`,\n )\n .join(\"\")}\n </div>\n </div>`;\n }\n\n if (queryParams.length > 0) {\n parametersSection += `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Query Parameters</h4>\n <div class=\"space-y-3\">\n ${queryParams\n .map(\n (param: any) => `\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">${param.name}</code>\n <span class=\"text-xs ${param.required ? \"text-red-400\" : \"text-gray-400\"}\">${param.required ? \"required\" : \"optional\"}</span>\n </div>\n <p class=\"text-sm text-gray-300\">${param.description || `${param.name} parameter`}</p>\n </div>`,\n )\n .join(\"\")}\n </div>\n </div>`;\n }\n }\n\n let requestBodySection = \"\";\n if (operation.requestBody) {\n const schema = operation.requestBody.content?.[\"application/json\"]?.schema;\n const cleanSchema = extractJsonSchema(schema);\n\n if (cleanSchema.properties) {\n requestBodySection = `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Body Parameters</h4>\n <div class=\"space-y-3\">\n ${Object.entries(cleanSchema.properties)\n .map(\n ([propName, propSchema]: [string, any]) => `\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">${propName}</code>\n <span class=\"text-xs ${cleanSchema.required?.includes(propName) ? \"text-red-400\" : \"text-gray-400\"}\">${cleanSchema.required?.includes(propName) ? \"required\" : \"optional\"}</span>\n </div>\n <p class=\"text-sm text-gray-300\">${propSchema.description || `${propName} field`}</p>\n </div>`,\n )\n .join(\"\")}\n </div>\n </div>`;\n }\n }\n\n const baseUrl = `https://${hostname}`;\n let requestExample = \"\";\n\n if (method !== \"WS\" && method !== \"SUB\") {\n let curlCommand = `curl -X ${method} '${baseUrl}${path}'`;\n\n if (operation.requestBody) {\n curlCommand += ` \\\\\\n -H 'Content-Type: application/json'`;\n const schema = operation.requestBody.content?.[\"application/json\"]?.schema;\n const cleanSchema = extractJsonSchema(schema);\n\n if (cleanSchema.properties) {\n const exampleData: Record<string, any> = {};\n Object.entries(cleanSchema.properties).forEach(\n ([propName, propSchema]: [string, any]) => {\n if (propSchema.type === \"string\") {\n exampleData[propName] =\n propSchema.format === \"email\"\n ? \"user@example.com\"\n : `example ${propName}`;\n } else if (propSchema.type === \"number\") {\n exampleData[propName] = 123;\n } else if (propSchema.type === \"boolean\") {\n exampleData[propName] = true;\n } else {\n exampleData[propName] = `example ${propName}`;\n }\n },\n );\n curlCommand += ` \\\\\\n -d '${JSON.stringify(exampleData, null, 2).replace(/\\n/g, \"\\\\n \")}'`;\n }\n }\n\n curlCommand += ` \\\\\\n -H 'Authorization: Bearer your-token'`;\n\n requestExample = `\n <div>\n <div class=\"flex items-center justify-between mb-4\">\n <h4 class=\"text-lg font-semibold text-white\">Request Example</h4>\n <button class=\"copy-btn bg-dark-700 hover:bg-dark-600 px-3 py-1 rounded-lg text-sm transition-colors\" data-copy=\"${curlCommand.replace(/'/g, \"\\\\'\")}\">\n Copy\n </button>\n </div>\n <div class=\"code-block rounded-xl p-4 border border-dark-600\">\n <pre class=\"text-sm text-gray-300 overflow-x-auto\"><code>${curlCommand}</code></pre>\n </div>\n </div>`;\n }\n\n let responseSection = \"\";\n const response200 = operation.responses?.[\"200\"];\n if (response200?.content?.[\"application/json\"]?.schema) {\n const schema = response200.content[\"application/json\"].schema;\n const cleanSchema = extractJsonSchema(schema);\n\n responseSection = `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-4\">Response Schema</h4>\n <div class=\"code-block rounded-xl p-4 border border-dark-600\">\n <pre class=\"text-sm text-gray-300 overflow-x-auto\"><code>${JSON.stringify(cleanSchema, null, 2)}</code></pre>\n </div>\n </div>`;\n }\n\n return `\n <section id=\"${operationId}\" class=\"fade-in\">\n <div class=\"grid lg:grid-cols-3 gap-8\">\n <div class=\"lg:col-span-1 space-y-6\">\n <div>\n <div class=\"flex items-center space-x-3 mb-4\">\n <span class=\"${methodColor} text-white px-3 py-1 rounded-lg text-sm font-medium\">${method}</span>\n <code class=\"text-blue-400 font-mono\">${path}</code>\n </div>\n <p class=\"text-gray-300\">${operation.description || operation.summary || `${method} ${path} operation`}</p>\n </div>\n\n ${parametersSection}\n ${requestBodySection}\n\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Headers</h4>\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">Authorization</code>\n <span class=\"text-xs text-red-400\">required</span>\n </div>\n <p class=\"text-sm text-gray-300\">Bearer token for authentication</p>\n </div>\n </div>\n\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Responses</h4>\n <div class=\"space-y-2\">\n ${Object.entries(operation.responses || {})\n .map(([code, response]: [string, any]) => {\n const statusColor = code.startsWith(\"2\")\n ? \"bg-green-600\"\n : code.startsWith(\"4\")\n ? \"bg-red-600\"\n : \"bg-yellow-600\";\n return `\n <div class=\"flex items-center space-x-3\">\n <span class=\"${statusColor} text-white px-2 py-1 rounded text-xs\">${code}</span>\n <span class=\"text-gray-300 text-sm\">${response.description || \"Response\"}</span>\n </div>`;\n })\n .join(\"\")}\n </div>\n </div>\n </div>\n\n <div class=\"lg:col-span-2 space-y-6\">\n ${requestExample}\n ${responseSection}\n </div>\n </div>\n </section>`;\n })\n .join(\"\\n\");\n\n return `\n <section id=\"${tag.toLowerCase()}-tag\" class=\"fade-in\">\n <div class=\"grid lg:grid-cols-3 gap-8 mb-12\">\n <div class=\"lg:col-span-1\">\n <div class=\"sticky top-24\">\n <h2 class=\"text-3xl font-bold text-white mb-4\">${tag}</h2>\n <p class=\"text-gray-300 text-lg leading-relaxed\">\n ${tagDescription}\n </p>\n <div class=\"mt-6 flex items-center space-x-2\">\n <span class=\"bg-blue-600 text-white px-3 py-1 rounded-full text-sm font-medium\">${endpoints.length} endpoints</span>\n <span class=\"bg-gray-600 text-white px-3 py-1 rounded-full text-sm font-medium\">Authentication required</span>\n </div>\n </div>\n </div>\n\n <div class=\"lg:col-span-2\">\n <div class=\"bg-dark-800/30 backdrop-blur-sm rounded-xl p-6 border border-dark-700\">\n <h3 class=\"text-xl font-semibold text-white mb-6\">Available Endpoints</h3>\n <div class=\"space-y-4\">\n ${endpointCards}\n </div>\n </div>\n </div>\n </div>\n </section>\n\n <hr class=\"border-dark-600\">\n\n <div class=\"space-y-16\">\n ${detailedEndpoints}\n </div>`;\n })\n .join(\"\\n\\n\");\n\n return `<!DOCTYPE html>\n<html lang=\"es\" class=\"dark\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${this.spec.info.title}</title>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <script>\n tailwind.config = {\n darkMode: 'class',\n theme: {\n extend: {\n colors: {\n dark: {\n 50: '#f8fafc',\n 100: '#f1f5f9',\n 200: '#e2e8f0',\n 300: '#cbd5e1',\n 400: '#94a3b8',\n 500: '#64748b',\n 600: '#475569',\n 700: '#334155',\n 800: '#1e293b',\n 900: '#0f172a',\n }\n }\n }\n }\n }\n </script>\n <style>\n .sidebar-transition {\n transition: transform 0.3s ease-in-out, width 0.3s ease-in-out;\n }\n .fade-in {\n animation: fadeIn 0.3s ease-in-out;\n }\n @keyframes fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .code-block {\n background: linear-gradient(135deg, #1e293b 0%, #334155 100%);\n }\n </style>\n</head>\n<body class=\"bg-dark-900 text-gray-100 font-sans\">\n\n <nav class=\"fixed top-0 left-0 right-0 z-50 bg-dark-900/80 backdrop-blur-md border-b border-dark-700\">\n <div class=\"flex items-center justify-between px-4 py-3\">\n <div class=\"flex items-center space-x-4\">\n <button id=\"sidebarToggle\" class=\"p-2 rounded-lg hover:bg-dark-700 transition-colors\">\n <svg class=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 6h16M4 12h16M4 18h16\"></path>\n </svg>\n </button>\n <h1 class=\"text-xl font-bold text-blue-400\">${this.spec.info.title}</h1>\n </div>\n\n <div class=\"flex items-center space-x-4\">\n <!-- <select id=\"languageSelect\" class=\"bg-dark-800 border border-dark-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all\">\n <option value=\"shell\">Shell</option>\n <option value=\"nodejs\">Node.js</option>\n </select> -->\n\n <button id=\"themeToggle\" class=\"p-2 rounded-lg hover:bg-dark-700 transition-colors\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z\"></path>\n </svg>\n </button>\n </div>\n </div>\n </nav>\n\n <div class=\"flex pt-16\">\n\n <aside id=\"sidebar\" class=\"fixed top-16 bottom-0 left-0 z-40 w-64 bg-dark-800/50 backdrop-blur-sm border-r border-dark-700 sidebar-transition transform translate-x-0\">\n <div class=\"p-4 h-full overflow-y-auto pt-6\">\n <div class=\"space-y-1\">\n ${sidebarSections}\n </div>\n </div>\n </aside>\n\n <div id=\"sidebarOverlay\" class=\"fixed top-16 bottom-0 left-0 right-0 bg-black/50 z-30 lg:hidden hidden\"></div>\n\n <main id=\"mainContent\" class=\"flex-1 ml-64 transition-all duration-300\">\n <div class=\"max-w-7xl mx-auto px-4 py-8\">\n\n <div class=\"mb-12 fade-in\">\n <h1 class=\"text-4xl font-bold text-white mb-4\">${this.spec.info.title}</h1>\n <p class=\"text-xl text-gray-300 mb-4\">${this.spec.info.description || \"Complete reference for our REST API\"}</p>\n <span class=\"inline-block bg-blue-600 text-white px-3 py-1 rounded-full text-sm font-medium\">v${this.spec.info.version}</span>\n </div>\n\n <div class=\"grid gap-8 mb-12 fade-in\">\n <div class=\"bg-dark-800/30 backdrop-blur-sm rounded-xl p-6 border border-dark-700\">\n <h3 class=\"text-xl font-semibold text-white mb-4\">Server</h3>\n <div class=\"space-y-3\">\n <a href=\"${this.host}\" target=\"_blank\" class=\"flex items-center space-x-3 hover:bg-dark-700/30 p-2 rounded-lg transition-colors group\">\n <div class=\"w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center\">\n <svg class=\"w-4 h-4 text-white\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14\"></path>\n </svg>\n </div>\n <span class=\"text-gray-300 group-hover:text-white transition-colors\">${this.host}</span>\n </a>\n </div>\n </div>\n </div>\n\n <div class=\"space-y-20\">\n ${contentSections}\n </div>\n </div>\n </main>\n </div>\n\n <script>\n const sidebarToggle = document.getElementById('sidebarToggle');\n const sidebar = document.getElementById('sidebar');\n const sidebarOverlay = document.getElementById('sidebarOverlay');\n const mainContent = document.getElementById('mainContent');\n const themeToggle = document.getElementById('themeToggle');\n const html = document.documentElement;\n\n themeToggle.addEventListener('click', () => {\n if (html.classList.contains('dark')) {\n html.classList.remove('dark');\n html.classList.add('light');\n document.body.className = 'bg-gray-50 text-gray-900 font-sans';\n\n const navbar = document.querySelector('nav');\n navbar.className = 'fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-gray-200';\n\n const sidebar = document.getElementById('sidebar');\n sidebar.className = sidebar.className.replace('bg-dark-800/50 backdrop-blur-sm border-r border-dark-700', 'bg-white/50 backdrop-blur-sm border-r border-gray-200');\n\n document.querySelectorAll('h1, h2, h3, h4').forEach(heading => {\n heading.classList.remove('text-white', 'text-gray-100');\n heading.classList.add('text-gray-900');\n });\n\n document.querySelectorAll('.text-gray-300').forEach(el => {\n el.classList.remove('text-gray-300');\n el.classList.add('text-gray-700');\n });\n\n document.querySelectorAll('.text-gray-400').forEach(el => {\n el.classList.remove('text-gray-400');\n el.classList.add('text-gray-600');\n });\n\n document.querySelectorAll('.border-dark-600').forEach(el => {\n el.classList.remove('border-dark-600');\n el.classList.add('border-gray-300');\n });\n\n document.querySelectorAll('.bg-dark-700\\\\/30').forEach(el => {\n el.classList.remove('bg-dark-700/30');\n el.classList.add('bg-gray-100/30');\n });\n\n document.querySelectorAll('.bg-dark-800\\\\/20').forEach(el => {\n el.classList.remove('bg-dark-800/20');\n el.classList.add('bg-gray-50/20');\n });\n\n document.querySelectorAll('.bg-dark-600').forEach(el => {\n el.classList.remove('bg-dark-600');\n el.classList.add('bg-gray-400');\n });\n\n document.querySelectorAll('.text-gray-500').forEach(el => {\n el.classList.remove('text-gray-500');\n el.classList.add('text-gray-600');\n });\n\n document.querySelectorAll('aside a').forEach(link => {\n link.classList.add('text-gray-700', 'hover:text-gray-900', 'hover:bg-gray-100');\n });\n\n document.querySelectorAll('pre code').forEach(code => {\n code.classList.remove('text-gray-300');\n code.classList.add('text-gray-800');\n });\n\n document.querySelectorAll('.bg-dark-800\\\\/30').forEach(el => {\n el.classList.remove('bg-dark-800/30', 'border-dark-700');\n el.classList.add('bg-white/30', 'border-gray-200');\n });\n\n document.querySelectorAll('.code-block').forEach(el => {\n el.style.background = 'linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%)';\n el.classList.remove('border-dark-600');\n el.classList.add('border-gray-300');\n });\n\n document.querySelectorAll('.border-dark-600').forEach(el => {\n el.classList.remove('border-dark-600');\n el.classList.add('border-gray-300');\n });\n\n } else {\n html.classList.remove('light');\n html.classList.add('dark');\n document.body.className = 'bg-dark-900 text-gray-100 font-sans';\n\n const navbar = document.querySelector('nav');\n navbar.className = 'fixed top-0 left-0 right-0 z-50 bg-dark-900/80 backdrop-blur-md border-b border-dark-700';\n\n const sidebar = document.getElementById('sidebar');\n sidebar.className = sidebar.className.replace('bg-white/50 backdrop-blur-sm border-r border-gray-200', 'bg-dark-800/50 backdrop-blur-sm border-r border-dark-700');\n\n document.querySelectorAll('h1, h2, h3, h4').forEach(heading => {\n heading.classList.remove('text-gray-900');\n heading.classList.add('text-white');\n });\n\n document.querySelectorAll('.text-gray-700').forEach(el => {\n el.classList.remove('text-gray-700');\n el.classList.add('text-gray-300');\n });\n\n document.querySelectorAll('.text-gray-600').forEach(el => {\n el.classList.remove('text-gray-600');\n el.classList.add('text-gray-400');\n });\n\n document.querySelectorAll('.border-gray-300').forEach(el => {\n el.classList.remove('border-gray-300');\n el.classList.add('border-dark-600');\n });\n\n document.querySelectorAll('.bg-gray-100\\\\/30').forEach(el => {\n el.classList.remove('bg-gray-100/30');\n el.classList.add('bg-dark-700/30');\n });\n\n document.querySelectorAll('.bg-gray-50\\\\/20').forEach(el => {\n el.classList.remove('bg-gray-50/20');\n el.classList.add('bg-dark-800/20');\n });\n\n document.querySelectorAll('.bg-gray-400').forEach(el => {\n el.classList.remove('bg-gray-400');\n el.classList.add('bg-dark-600');\n });\n\n document.querySelectorAll('.text-gray-600').forEach(el => {\n el.classList.remove('text-gray-600');\n el.classList.add('text-gray-500');\n });\n\n document.querySelectorAll('aside a').forEach(link => {\n link.classList.remove('text-gray-700', 'hover:text-gray-900', 'hover:bg-gray-100');\n });\n\n document.querySelectorAll('pre code').forEach(code => {\n code.classList.remove('text-gray-800');\n code.classList.add('text-gray-300');\n });\n\n document.querySelectorAll('.bg-white\\\\/30').forEach(el => {\n el.classList.remove('bg-white/30', 'border-gray-200');\n el.classList.add('bg-dark-800/30', 'border-dark-700');\n });\n\n document.querySelectorAll('.code-block').forEach(el => {\n el.style.background = 'linear-gradient(135deg, #1e293b 0%, #334155 100%)';\n el.classList.remove('border-gray-300');\n el.classList.add('border-dark-600');\n });\n\n document.querySelectorAll('.border-gray-300').forEach(el => {\n el.classList.remove('border-gray-300');\n el.classList.add('border-dark-600');\n });\n }\n });\n\n function toggleSidebar() {\n const isHidden = sidebar.classList.contains('-translate-x-full');\n\n if (isHidden) {\n sidebar.classList.remove('-translate-x-full');\n mainContent.classList.remove('ml-0');\n mainContent.classList.add('ml-64');\n } else {\n sidebar.classList.add('-translate-x-full');\n mainContent.classList.remove('ml-64');\n mainContent.classList.add('ml-0');\n }\n\n if (window.innerWidth < 1024) {\n sidebarOverlay.classList.toggle('hidden');\n }\n }\n\n sidebarToggle.addEventListener('click', toggleSidebar);\n sidebarOverlay.addEventListener('click', toggleSidebar);\n\n document.querySelectorAll('.copy-btn').forEach(btn => {\n btn.addEventListener('click', async () => {\n const textToCopy = btn.getAttribute('data-copy');\n try {\n await navigator.clipboard.writeText(textToCopy);\n btn.textContent = 'Copied!';\n setTimeout(() => {\n btn.textContent = 'Copy';\n }, 2000);\n } catch (err) {\n console.error('Failed to copy text: ', err);\n }\n });\n });\n\n document.querySelectorAll('a[href^=\"#\"]').forEach(anchor => {\n anchor.addEventListener('click', function (e) {\n e.preventDefault();\n const target = document.querySelector(this.getAttribute('href'));\n if (target) {\n target.scrollIntoView({\n behavior: 'smooth',\n block: 'start'\n });\n\n if (window.innerWidth < 1024) {\n toggleSidebar();\n }\n }\n });\n });\n\n document.querySelectorAll('.sidebar-group-toggle').forEach(button => {\n button.addEventListener('click', () => {\n const targetId = button.getAttribute('data-target');\n const targetGroup = document.getElementById(targetId);\n const arrow = button.querySelector('svg');\n\n if (targetGroup.style.maxHeight && targetGroup.style.maxHeight !== '0px') {\n targetGroup.style.maxHeight = '0px';\n arrow.style.transform = 'rotate(0deg)';\n } else {\n targetGroup.style.maxHeight = targetGroup.scrollHeight + 'px';\n arrow.style.transform = 'rotate(180deg)';\n }\n });\n });\n\n document.querySelectorAll('.sidebar-group-content').forEach(group => {\n group.style.maxHeight = group.scrollHeight + 'px';\n });\n document.querySelectorAll('.sidebar-group-toggle svg').forEach(arrow => {\n arrow.style.transform = 'rotate(180deg)';\n });\n\n function handleResize() {\n if (window.innerWidth < 1024) {\n sidebar.classList.add('-translate-x-full');\n mainContent.classList.remove('ml-64');\n mainContent.classList.add('ml-0');\n } else {\n if (!sidebar.hasAttribute('data-manually-hidden')) {\n sidebar.classList.remove('-translate-x-full');\n mainContent.classList.remove('ml-0');\n mainContent.classList.add('ml-64');\n }\n sidebarOverlay.classList.add('hidden');\n }\n }\n\n window.addEventListener('resize', handleResize);\n handleResize();\n </script>\n</body>\n</html>`;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"swagger.cjs","names":["SwaggerParser"],"sources":["../src/swagger.ts"],"sourcesContent":["import SwaggerParser from \"@apidevtools/swagger-parser\";\nimport type { OpenAPI } from \"openapi-types\";\n\nexport interface SwaggerOptions {\n title?: string;\n description?: string;\n version?: string;\n basePath?: string;\n schemes?: string[];\n consumes?: string[];\n produces?: string[];\n tags?: { name: string; description?: string }[];\n securityDefinitions?: Record<string, any>;\n externalDocs?: { description: string; url: string };\n host?: string;\n}\n\nexport class Swagger {\n private spec: OpenAPI.Document = {\n openapi: \"3.0.0\",\n info: {\n title: \"API Documentation\",\n version: \"1.0.0\",\n },\n paths: {},\n components: {\n schemas: {},\n },\n } as OpenAPI.Document;\n host: string;\n\n constructor(options: SwaggerOptions = {}) {\n this.spec.info.title = options.title || \"API Documentation\";\n this.spec.info.description = options.description;\n this.spec.info.version = options.version || \"1.0.0\";\n this.host = options.host || \"https://example.com\";\n\n if (options.tags) {\n this.spec.tags = options.tags;\n }\n\n if (options.externalDocs) {\n this.spec.externalDocs = options.externalDocs;\n }\n\n if (options.securityDefinitions) {\n (this.spec as any).components = (this.spec as any).components || {};\n (this.spec as any).components.securitySchemes = options.securityDefinitions;\n }\n }\n\n addRoute(\n method: string,\n path: string,\n schema: any,\n summary?: string,\n description?: string,\n tags?: string[],\n ) {\n if (!schema) {\n return;\n }\n\n const normalizedPath = path.replace(/:([^/]+)/g, \"{$1}\");\n if (!this.spec.paths) {\n this.spec.paths = {};\n }\n if (!this.spec.paths[normalizedPath]) {\n this.spec.paths[normalizedPath] = {};\n }\n\n const methodLower = method.toLowerCase();\n const operationObject: any = {\n summary: summary || `${method} ${path}`,\n parameters: this.buildParameters(schema),\n requestBody: this.buildRequestBody(schema),\n responses: this.buildResponses(schema),\n };\n\n if (description) {\n operationObject.description = description;\n }\n\n if (tags) {\n operationObject.tags = tags;\n }\n\n (this.spec.paths as any)[normalizedPath][methodLower] = operationObject;\n }\n\n private extractJsonSchema(schema: any): any {\n if (!schema) {\n return {};\n }\n\n const js = schema.jsonSchema || schema;\n\n if (js.type || js.properties || js.$ref || js.items) {\n const standardProps = [\n \"type\",\n \"properties\",\n \"required\",\n \"items\",\n \"enum\",\n \"nullable\",\n \"format\",\n \"description\",\n \"title\",\n \"default\",\n \"minimum\",\n \"maximum\",\n \"minLength\",\n \"maxLength\",\n \"pattern\",\n \"anyOf\",\n \"oneOf\",\n \"allOf\",\n \"not\",\n \"$ref\",\n \"additionalProperties\",\n ];\n\n const filtered: any = {};\n for (const prop of standardProps) {\n if (js[prop] !== undefined) {\n filtered[prop] = js[prop];\n }\n }\n return filtered;\n }\n\n return {};\n }\n\n private buildParameters(schema: any) {\n const parameters: any[] = [];\n\n const paramsSchema = this.extractJsonSchema(schema.params);\n if (paramsSchema.properties) {\n Object.entries(paramsSchema.properties).forEach(([name, propSchema]: [string, any]) => {\n parameters.push({\n name,\n in: \"path\",\n required: paramsSchema.required?.includes(name) ?? true,\n schema: propSchema,\n });\n });\n }\n\n const querySchema = this.extractJsonSchema(schema.query);\n if (querySchema.properties) {\n Object.entries(querySchema.properties).forEach(([name, propSchema]: [string, any]) => {\n parameters.push({\n name,\n in: \"query\",\n required: querySchema.required?.includes(name) ?? false,\n schema: propSchema,\n });\n });\n }\n\n return parameters.length > 0 ? parameters : undefined;\n }\n\n private buildRequestBody(schema: any) {\n if (!schema.body) {\n return undefined;\n }\n\n try {\n const jsonSchema = this.extractJsonSchema(schema.body);\n return {\n required: true,\n content: {\n \"application/json\": {\n schema: jsonSchema,\n },\n },\n };\n } catch (e) {\n console.error(\"Failed to convert body schema:\", e);\n return undefined;\n }\n }\n\n private buildResponses(schema: any) {\n const responses: Record<string, any> = {\n \"200\": {\n description: \"Successful response\",\n },\n };\n\n if (schema.response) {\n try {\n const jsonSchema = this.extractJsonSchema(schema.response);\n responses[\"200\"].content = {\n \"application/json\": {\n schema: jsonSchema,\n },\n };\n } catch (e) {\n console.error(\"Failed to convert response schema:\", e);\n }\n }\n\n return responses;\n }\n\n async validate() {\n try {\n await SwaggerParser.validate(this.spec as any);\n return true;\n } catch (error) {\n console.error(\"Swagger validation error:\", error);\n return false;\n }\n }\n\n getSpec() {\n return this.spec;\n }\n\n generateHTML(): string {\n const hostname = new URL(this.host).hostname;\n\n const groupedPaths: Record<\n string,\n Array<{\n path: string;\n method: string;\n operation: any;\n }>\n > = {};\n\n const defaultGroup = \"API\";\n\n Object.entries(this.spec.paths || {}).forEach(([path, pathItem]: [string, any]) => {\n Object.entries(pathItem).forEach(([method, operation]: [string, any]) => {\n const tags = operation.tags || [defaultGroup];\n const primaryTag = tags[0];\n\n if (!groupedPaths[primaryTag]) {\n groupedPaths[primaryTag] = [];\n }\n\n groupedPaths[primaryTag].push({\n path,\n method: method.toUpperCase(),\n operation,\n });\n });\n });\n\n const sidebarSections = Object.entries(groupedPaths)\n .map(([tag, endpoints]) => {\n const endpointCount = endpoints.length;\n const endpointLinks = endpoints\n .map(({ path, method }) => {\n const operationId = `${method.toLowerCase()}-${path.replace(/[^a-zA-Z0-9]/g, \"-\")}`;\n return `<li><a href=\"#${operationId}\" class=\"block px-3 py-1.5 rounded-lg hover:bg-dark-700/50 transition-colors text-sm text-gray-400 hover:text-white\">${method} ${path}</a></li>`;\n })\n .join(\"\\n \");\n\n return `\n <div>\n <button class=\"sidebar-group-toggle w-full flex items-center justify-between px-3 py-2 hover:bg-dark-700/30 rounded-lg transition-colors group\" data-target=\"${tag.toLowerCase()}-group\">\n <div class=\"flex items-center space-x-2\">\n <h3 class=\"text-sm font-medium text-gray-300 group-hover:text-white\">${tag}</h3>\n <span class=\"text-xs text-gray-500 bg-dark-600 px-2 py-0.5 rounded-full\">${endpointCount}</span>\n <svg class=\"w-4 h-4 text-gray-400 transform transition-transform duration-200 group-hover:text-gray-300\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\"></path>\n </svg>\n </div>\n </button>\n <div id=\"${tag.toLowerCase()}-group\" class=\"sidebar-group-content max-h-0 overflow-hidden transition-all duration-300\">\n <ul class=\"ml-6 mt-1 space-y-1\">\n ${endpointLinks}\n </ul>\n </div>\n </div>\n\n <div class=\"border-t border-dark-600 my-3\"></div>`;\n })\n .join(\"\");\n\n const contentSections = Object.entries(groupedPaths)\n .map(([tag, endpoints]) => {\n const tagDescription =\n this.spec.tags?.find((t) => t.name === tag)?.description ||\n `Manage ${tag.toLowerCase()} operations`;\n\n const endpointCards = endpoints\n .map(({ path, method, operation }) => {\n const operationId = `${method.toLowerCase()}-${path.replace(/[^a-zA-Z0-9]/g, \"-\")}`;\n const methodColor =\n {\n GET: \"bg-green-600\",\n POST: \"bg-blue-600\",\n PUT: \"bg-yellow-600\",\n DELETE: \"bg-red-600\",\n PATCH: \"bg-purple-600\",\n WS: \"bg-indigo-600\",\n SUB: \"bg-pink-600\",\n }[method] || \"bg-gray-600\";\n\n return `\n <a href=\"#${operationId}\" class=\"block p-4 rounded-lg border border-dark-600 hover:border-blue-500 hover:bg-dark-700/30 transition-all group\">\n <div class=\"flex items-center justify-between mb-2\">\n <div class=\"flex items-center space-x-3\">\n <span class=\"${methodColor} text-white px-3 py-1 rounded-lg text-sm font-medium\">${method}</span>\n <code class=\"text-blue-400 font-mono\">${path}</code>\n </div>\n <svg class=\"w-5 h-5 text-gray-400 group-hover:text-blue-400 transition-colors\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\"></path>\n </svg>\n </div>\n <p class=\"text-gray-300 text-sm\">${operation.summary || operation.description || `${method} ${path} operation`}</p>\n </a>`;\n })\n .join(\"\\n\");\n\n const detailedEndpoints = endpoints\n .map(({ path, method, operation }) => {\n const operationId = `${method.toLowerCase()}-${path.replace(/[^a-zA-Z0-9]/g, \"-\")}`;\n const methodColor =\n {\n GET: \"bg-green-600\",\n POST: \"bg-blue-600\",\n PUT: \"bg-yellow-600\",\n DELETE: \"bg-red-600\",\n PATCH: \"bg-purple-600\",\n WS: \"bg-indigo-600\",\n SUB: \"bg-pink-600\",\n }[method] || \"bg-gray-600\";\n\n let parametersSection = \"\";\n if (operation.parameters && operation.parameters.length > 0) {\n const pathParams = operation.parameters.filter((p: any) => p.in === \"path\");\n const queryParams = operation.parameters.filter((p: any) => p.in === \"query\");\n\n if (pathParams.length > 0) {\n parametersSection += `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Path Parameters</h4>\n <div class=\"space-y-3\">\n ${pathParams\n .map(\n (param: any) => `\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">${param.name}</code>\n <span class=\"text-xs ${param.required ? \"text-red-400\" : \"text-gray-400\"}\">${param.required ? \"required\" : \"optional\"}</span>\n </div>\n <p class=\"text-sm text-gray-300\">${param.description || `${param.name} parameter`}</p>\n </div>`,\n )\n .join(\"\")}\n </div>\n </div>`;\n }\n\n if (queryParams.length > 0) {\n parametersSection += `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Query Parameters</h4>\n <div class=\"space-y-3\">\n ${queryParams\n .map(\n (param: any) => `\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">${param.name}</code>\n <span class=\"text-xs ${param.required ? \"text-red-400\" : \"text-gray-400\"}\">${param.required ? \"required\" : \"optional\"}</span>\n </div>\n <p class=\"text-sm text-gray-300\">${param.description || `${param.name} parameter`}</p>\n </div>`,\n )\n .join(\"\")}\n </div>\n </div>`;\n }\n }\n\n let requestBodySection = \"\";\n if (operation.requestBody) {\n const schema = operation.requestBody.content?.[\"application/json\"]?.schema;\n const cleanSchema = this.extractJsonSchema(schema);\n\n if (cleanSchema.properties) {\n requestBodySection = `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Body Parameters</h4>\n <div class=\"space-y-3\">\n ${Object.entries(cleanSchema.properties)\n .map(\n ([propName, propSchema]: [string, any]) => `\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">${propName}</code>\n <span class=\"text-xs ${cleanSchema.required?.includes(propName) ? \"text-red-400\" : \"text-gray-400\"}\">${cleanSchema.required?.includes(propName) ? \"required\" : \"optional\"}</span>\n </div>\n <p class=\"text-sm text-gray-300\">${propSchema.description || `${propName} field`}</p>\n </div>`,\n )\n .join(\"\")}\n </div>\n </div>`;\n }\n }\n\n const baseUrl = `https://${hostname}`;\n let requestExample = \"\";\n\n if (method !== \"WS\" && method !== \"SUB\") {\n let curlCommand = `curl -X ${method} '${baseUrl}${path}'`;\n\n if (operation.requestBody) {\n curlCommand += ` \\\\\\n -H 'Content-Type: application/json'`;\n const schema = operation.requestBody.content?.[\"application/json\"]?.schema;\n const cleanSchema = this.extractJsonSchema(schema);\n\n if (cleanSchema.properties) {\n const exampleData: Record<string, any> = {};\n Object.entries(cleanSchema.properties).forEach(\n ([propName, propSchema]: [string, any]) => {\n if (propSchema.type === \"string\") {\n exampleData[propName] =\n propSchema.format === \"email\"\n ? \"user@example.com\"\n : `example ${propName}`;\n } else if (propSchema.type === \"number\") {\n exampleData[propName] = 123;\n } else if (propSchema.type === \"boolean\") {\n exampleData[propName] = true;\n } else {\n exampleData[propName] = `example ${propName}`;\n }\n },\n );\n curlCommand += ` \\\\\\n -d '${JSON.stringify(exampleData, null, 2).replace(/\\n/g, \"\\\\n \")}'`;\n }\n }\n\n curlCommand += ` \\\\\\n -H 'Authorization: Bearer your-token'`;\n\n requestExample = `\n <div>\n <div class=\"flex items-center justify-between mb-4\">\n <h4 class=\"text-lg font-semibold text-white\">Request Example</h4>\n <button class=\"copy-btn bg-dark-700 hover:bg-dark-600 px-3 py-1 rounded-lg text-sm transition-colors\" data-copy=\"${curlCommand.replace(/'/g, \"\\\\'\")}\">\n Copy\n </button>\n </div>\n <div class=\"code-block rounded-xl p-4 border border-dark-600\">\n <pre class=\"text-sm text-gray-300 overflow-x-auto\"><code>${curlCommand}</code></pre>\n </div>\n </div>`;\n }\n\n let responseSection = \"\";\n const response200 = operation.responses?.[\"200\"];\n if (response200?.content?.[\"application/json\"]?.schema) {\n const schema = response200.content[\"application/json\"].schema;\n const cleanSchema = this.extractJsonSchema(schema);\n\n responseSection = `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-4\">Response Schema</h4>\n <div class=\"code-block rounded-xl p-4 border border-dark-600\">\n <pre class=\"text-sm text-gray-300 overflow-x-auto\"><code>${JSON.stringify(cleanSchema, null, 2)}</code></pre>\n </div>\n </div>`;\n }\n\n return `\n <section id=\"${operationId}\" class=\"fade-in\">\n <div class=\"grid lg:grid-cols-3 gap-8\">\n <div class=\"lg:col-span-1 space-y-6\">\n <div>\n <div class=\"flex items-center space-x-3 mb-4\">\n <span class=\"${methodColor} text-white px-3 py-1 rounded-lg text-sm font-medium\">${method}</span>\n <code class=\"text-blue-400 font-mono\">${path}</code>\n </div>\n <p class=\"text-gray-300\">${operation.description || operation.summary || `${method} ${path} operation`}</p>\n </div>\n\n ${parametersSection}\n ${requestBodySection}\n\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Headers</h4>\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">Authorization</code>\n <span class=\"text-xs text-red-400\">required</span>\n </div>\n <p class=\"text-sm text-gray-300\">Bearer token for authentication</p>\n </div>\n </div>\n\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Responses</h4>\n <div class=\"space-y-2\">\n ${Object.entries(operation.responses || {})\n .map(([code, response]: [string, any]) => {\n const statusColor = code.startsWith(\"2\")\n ? \"bg-green-600\"\n : code.startsWith(\"4\")\n ? \"bg-red-600\"\n : \"bg-yellow-600\";\n return `\n <div class=\"flex items-center space-x-3\">\n <span class=\"${statusColor} text-white px-2 py-1 rounded text-xs\">${code}</span>\n <span class=\"text-gray-300 text-sm\">${response.description || \"Response\"}</span>\n </div>`;\n })\n .join(\"\")}\n </div>\n </div>\n </div>\n\n <div class=\"lg:col-span-2 space-y-6\">\n ${requestExample}\n ${responseSection}\n </div>\n </div>\n </section>`;\n })\n .join(\"\\n\");\n\n return `\n <section id=\"${tag.toLowerCase()}-tag\" class=\"fade-in\">\n <div class=\"grid lg:grid-cols-3 gap-8 mb-12\">\n <div class=\"lg:col-span-1\">\n <div class=\"sticky top-24\">\n <h2 class=\"text-3xl font-bold text-white mb-4\">${tag}</h2>\n <p class=\"text-gray-300 text-lg leading-relaxed\">\n ${tagDescription}\n </p>\n <div class=\"mt-6 flex items-center space-x-2\">\n <span class=\"bg-blue-600 text-white px-3 py-1 rounded-full text-sm font-medium\">${endpoints.length} endpoints</span>\n <span class=\"bg-gray-600 text-white px-3 py-1 rounded-full text-sm font-medium\">Authentication required</span>\n </div>\n </div>\n </div>\n\n <div class=\"lg:col-span-2\">\n <div class=\"bg-dark-800/30 backdrop-blur-sm rounded-xl p-6 border border-dark-700\">\n <h3 class=\"text-xl font-semibold text-white mb-6\">Available Endpoints</h3>\n <div class=\"space-y-4\">\n ${endpointCards}\n </div>\n </div>\n </div>\n </div>\n </section>\n\n <hr class=\"border-dark-600\">\n\n <div class=\"space-y-16\">\n ${detailedEndpoints}\n </div>`;\n })\n .join(\"\\n\\n\");\n\n return `<!DOCTYPE html>\n<html lang=\"es\" class=\"dark\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${this.spec.info.title}</title>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <script>\n tailwind.config = {\n darkMode: 'class',\n theme: {\n extend: {\n colors: {\n dark: {\n 50: '#f8fafc',\n 100: '#f1f5f9',\n 200: '#e2e8f0',\n 300: '#cbd5e1',\n 400: '#94a3b8',\n 500: '#64748b',\n 600: '#475569',\n 700: '#334155',\n 800: '#1e293b',\n 900: '#0f172a',\n }\n }\n }\n }\n }\n </script>\n <style>\n .sidebar-transition {\n transition: transform 0.3s ease-in-out, width 0.3s ease-in-out;\n }\n .fade-in {\n animation: fadeIn 0.3s ease-in-out;\n }\n @keyframes fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .code-block {\n background: linear-gradient(135deg, #1e293b 0%, #334155 100%);\n }\n </style>\n</head>\n<body class=\"bg-dark-900 text-gray-100 font-sans\">\n\n <nav class=\"fixed top-0 left-0 right-0 z-50 bg-dark-900/80 backdrop-blur-md border-b border-dark-700\">\n <div class=\"flex items-center justify-between px-4 py-3\">\n <div class=\"flex items-center space-x-4\">\n <button id=\"sidebarToggle\" class=\"p-2 rounded-lg hover:bg-dark-700 transition-colors\">\n <svg class=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 6h16M4 12h16M4 18h16\"></path>\n </svg>\n </button>\n <h1 class=\"text-xl font-bold text-blue-400\">${this.spec.info.title}</h1>\n </div>\n\n <div class=\"flex items-center space-x-4\">\n <!-- <select id=\"languageSelect\" class=\"bg-dark-800 border border-dark-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all\">\n <option value=\"shell\">Shell</option>\n <option value=\"nodejs\">Node.js</option>\n </select> -->\n\n <button id=\"themeToggle\" class=\"p-2 rounded-lg hover:bg-dark-700 transition-colors\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z\"></path>\n </svg>\n </button>\n </div>\n </div>\n </nav>\n\n <div class=\"flex pt-16\">\n\n <aside id=\"sidebar\" class=\"fixed top-16 bottom-0 left-0 z-40 w-64 bg-dark-800/50 backdrop-blur-sm border-r border-dark-700 sidebar-transition transform translate-x-0\">\n <div class=\"p-4 h-full overflow-y-auto pt-6\">\n <div class=\"space-y-1\">\n ${sidebarSections}\n </div>\n </div>\n </aside>\n\n <div id=\"sidebarOverlay\" class=\"fixed top-16 bottom-0 left-0 right-0 bg-black/50 z-30 lg:hidden hidden\"></div>\n\n <main id=\"mainContent\" class=\"flex-1 ml-64 transition-all duration-300\">\n <div class=\"max-w-7xl mx-auto px-4 py-8\">\n\n <div class=\"mb-12 fade-in\">\n <h1 class=\"text-4xl font-bold text-white mb-4\">${this.spec.info.title}</h1>\n <p class=\"text-xl text-gray-300 mb-4\">${this.spec.info.description || \"Complete reference for our REST API\"}</p>\n <span class=\"inline-block bg-blue-600 text-white px-3 py-1 rounded-full text-sm font-medium\">v${this.spec.info.version}</span>\n </div>\n\n <div class=\"grid gap-8 mb-12 fade-in\">\n <div class=\"bg-dark-800/30 backdrop-blur-sm rounded-xl p-6 border border-dark-700\">\n <h3 class=\"text-xl font-semibold text-white mb-4\">Server</h3>\n <div class=\"space-y-3\">\n <a href=\"${this.host}\" target=\"_blank\" class=\"flex items-center space-x-3 hover:bg-dark-700/30 p-2 rounded-lg transition-colors group\">\n <div class=\"w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center\">\n <svg class=\"w-4 h-4 text-white\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14\"></path>\n </svg>\n </div>\n <span class=\"text-gray-300 group-hover:text-white transition-colors\">${this.host}</span>\n </a>\n </div>\n </div>\n </div>\n\n <div class=\"space-y-20\">\n ${contentSections}\n </div>\n </div>\n </main>\n </div>\n\n <script>\n const sidebarToggle = document.getElementById('sidebarToggle');\n const sidebar = document.getElementById('sidebar');\n const sidebarOverlay = document.getElementById('sidebarOverlay');\n const mainContent = document.getElementById('mainContent');\n const themeToggle = document.getElementById('themeToggle');\n const html = document.documentElement;\n\n themeToggle.addEventListener('click', () => {\n if (html.classList.contains('dark')) {\n html.classList.remove('dark');\n html.classList.add('light');\n document.body.className = 'bg-gray-50 text-gray-900 font-sans';\n\n const navbar = document.querySelector('nav');\n navbar.className = 'fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-gray-200';\n\n const sidebar = document.getElementById('sidebar');\n sidebar.className = sidebar.className.replace('bg-dark-800/50 backdrop-blur-sm border-r border-dark-700', 'bg-white/50 backdrop-blur-sm border-r border-gray-200');\n\n document.querySelectorAll('h1, h2, h3, h4').forEach(heading => {\n heading.classList.remove('text-white', 'text-gray-100');\n heading.classList.add('text-gray-900');\n });\n\n document.querySelectorAll('.text-gray-300').forEach(el => {\n el.classList.remove('text-gray-300');\n el.classList.add('text-gray-700');\n });\n\n document.querySelectorAll('.text-gray-400').forEach(el => {\n el.classList.remove('text-gray-400');\n el.classList.add('text-gray-600');\n });\n\n document.querySelectorAll('.border-dark-600').forEach(el => {\n el.classList.remove('border-dark-600');\n el.classList.add('border-gray-300');\n });\n\n document.querySelectorAll('.bg-dark-700\\\\/30').forEach(el => {\n el.classList.remove('bg-dark-700/30');\n el.classList.add('bg-gray-100/30');\n });\n\n document.querySelectorAll('.bg-dark-800\\\\/20').forEach(el => {\n el.classList.remove('bg-dark-800/20');\n el.classList.add('bg-gray-50/20');\n });\n\n document.querySelectorAll('.bg-dark-600').forEach(el => {\n el.classList.remove('bg-dark-600');\n el.classList.add('bg-gray-400');\n });\n\n document.querySelectorAll('.text-gray-500').forEach(el => {\n el.classList.remove('text-gray-500');\n el.classList.add('text-gray-600');\n });\n\n document.querySelectorAll('aside a').forEach(link => {\n link.classList.add('text-gray-700', 'hover:text-gray-900', 'hover:bg-gray-100');\n });\n\n document.querySelectorAll('pre code').forEach(code => {\n code.classList.remove('text-gray-300');\n code.classList.add('text-gray-800');\n });\n\n document.querySelectorAll('.bg-dark-800\\\\/30').forEach(el => {\n el.classList.remove('bg-dark-800/30', 'border-dark-700');\n el.classList.add('bg-white/30', 'border-gray-200');\n });\n\n document.querySelectorAll('.code-block').forEach(el => {\n el.style.background = 'linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%)';\n el.classList.remove('border-dark-600');\n el.classList.add('border-gray-300');\n });\n\n document.querySelectorAll('.border-dark-600').forEach(el => {\n el.classList.remove('border-dark-600');\n el.classList.add('border-gray-300');\n });\n\n } else {\n html.classList.remove('light');\n html.classList.add('dark');\n document.body.className = 'bg-dark-900 text-gray-100 font-sans';\n\n const navbar = document.querySelector('nav');\n navbar.className = 'fixed top-0 left-0 right-0 z-50 bg-dark-900/80 backdrop-blur-md border-b border-dark-700';\n\n const sidebar = document.getElementById('sidebar');\n sidebar.className = sidebar.className.replace('bg-white/50 backdrop-blur-sm border-r border-gray-200', 'bg-dark-800/50 backdrop-blur-sm border-r border-dark-700');\n\n document.querySelectorAll('h1, h2, h3, h4').forEach(heading => {\n heading.classList.remove('text-gray-900');\n heading.classList.add('text-white');\n });\n\n document.querySelectorAll('.text-gray-700').forEach(el => {\n el.classList.remove('text-gray-700');\n el.classList.add('text-gray-300');\n });\n\n document.querySelectorAll('.text-gray-600').forEach(el => {\n el.classList.remove('text-gray-600');\n el.classList.add('text-gray-400');\n });\n\n document.querySelectorAll('.border-gray-300').forEach(el => {\n el.classList.remove('border-gray-300');\n el.classList.add('border-dark-600');\n });\n\n document.querySelectorAll('.bg-gray-100\\\\/30').forEach(el => {\n el.classList.remove('bg-gray-100/30');\n el.classList.add('bg-dark-700/30');\n });\n\n document.querySelectorAll('.bg-gray-50\\\\/20').forEach(el => {\n el.classList.remove('bg-gray-50/20');\n el.classList.add('bg-dark-800/20');\n });\n\n document.querySelectorAll('.bg-gray-400').forEach(el => {\n el.classList.remove('bg-gray-400');\n el.classList.add('bg-dark-600');\n });\n\n document.querySelectorAll('.text-gray-600').forEach(el => {\n el.classList.remove('text-gray-600');\n el.classList.add('text-gray-500');\n });\n\n document.querySelectorAll('aside a').forEach(link => {\n link.classList.remove('text-gray-700', 'hover:text-gray-900', 'hover:bg-gray-100');\n });\n\n document.querySelectorAll('pre code').forEach(code => {\n code.classList.remove('text-gray-800');\n code.classList.add('text-gray-300');\n });\n\n document.querySelectorAll('.bg-white\\\\/30').forEach(el => {\n el.classList.remove('bg-white/30', 'border-gray-200');\n el.classList.add('bg-dark-800/30', 'border-dark-700');\n });\n\n document.querySelectorAll('.code-block').forEach(el => {\n el.style.background = 'linear-gradient(135deg, #1e293b 0%, #334155 100%)';\n el.classList.remove('border-gray-300');\n el.classList.add('border-dark-600');\n });\n\n document.querySelectorAll('.border-gray-300').forEach(el => {\n el.classList.remove('border-gray-300');\n el.classList.add('border-dark-600');\n });\n }\n });\n\n function toggleSidebar() {\n const isHidden = sidebar.classList.contains('-translate-x-full');\n\n if (isHidden) {\n sidebar.classList.remove('-translate-x-full');\n mainContent.classList.remove('ml-0');\n mainContent.classList.add('ml-64');\n } else {\n sidebar.classList.add('-translate-x-full');\n mainContent.classList.remove('ml-64');\n mainContent.classList.add('ml-0');\n }\n\n if (window.innerWidth < 1024) {\n sidebarOverlay.classList.toggle('hidden');\n }\n }\n\n sidebarToggle.addEventListener('click', toggleSidebar);\n sidebarOverlay.addEventListener('click', toggleSidebar);\n\n document.querySelectorAll('.copy-btn').forEach(btn => {\n btn.addEventListener('click', async () => {\n const textToCopy = btn.getAttribute('data-copy');\n try {\n await navigator.clipboard.writeText(textToCopy);\n btn.textContent = 'Copied!';\n setTimeout(() => {\n btn.textContent = 'Copy';\n }, 2000);\n } catch (err) {\n console.error('Failed to copy text: ', err);\n }\n });\n });\n\n document.querySelectorAll('a[href^=\"#\"]').forEach(anchor => {\n anchor.addEventListener('click', function (e) {\n e.preventDefault();\n const target = document.querySelector(this.getAttribute('href'));\n if (target) {\n target.scrollIntoView({\n behavior: 'smooth',\n block: 'start'\n });\n\n if (window.innerWidth < 1024) {\n toggleSidebar();\n }\n }\n });\n });\n\n document.querySelectorAll('.sidebar-group-toggle').forEach(button => {\n button.addEventListener('click', () => {\n const targetId = button.getAttribute('data-target');\n const targetGroup = document.getElementById(targetId);\n const arrow = button.querySelector('svg');\n\n if (targetGroup.style.maxHeight && targetGroup.style.maxHeight !== '0px') {\n targetGroup.style.maxHeight = '0px';\n arrow.style.transform = 'rotate(0deg)';\n } else {\n targetGroup.style.maxHeight = targetGroup.scrollHeight + 'px';\n arrow.style.transform = 'rotate(180deg)';\n }\n });\n });\n\n document.querySelectorAll('.sidebar-group-content').forEach(group => {\n group.style.maxHeight = group.scrollHeight + 'px';\n });\n document.querySelectorAll('.sidebar-group-toggle svg').forEach(arrow => {\n arrow.style.transform = 'rotate(180deg)';\n });\n\n function handleResize() {\n if (window.innerWidth < 1024) {\n sidebar.classList.add('-translate-x-full');\n mainContent.classList.remove('ml-64');\n mainContent.classList.add('ml-0');\n } else {\n if (!sidebar.hasAttribute('data-manually-hidden')) {\n sidebar.classList.remove('-translate-x-full');\n mainContent.classList.remove('ml-0');\n mainContent.classList.add('ml-64');\n }\n sidebarOverlay.classList.add('hidden');\n }\n }\n\n window.addEventListener('resize', handleResize);\n handleResize();\n </script>\n</body>\n</html>`;\n }\n}\n"],"mappings":"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"}
@@ -25,6 +25,7 @@ declare class Swagger {
25
25
  host: string;
26
26
  constructor(options?: SwaggerOptions);
27
27
  addRoute(method: string, path: string, schema: any, summary?: string, description?: string, tags?: string[]): void;
28
+ private extractJsonSchema;
28
29
  private buildParameters;
29
30
  private buildRequestBody;
30
31
  private buildResponses;
@@ -25,6 +25,7 @@ declare class Swagger {
25
25
  host: string;
26
26
  constructor(options?: SwaggerOptions);
27
27
  addRoute(method: string, path: string, schema: any, summary?: string, description?: string, tags?: string[]): void;
28
+ private extractJsonSchema;
28
29
  private buildParameters;
29
30
  private buildRequestBody;
30
31
  private buildResponses;
package/dist/swagger.mjs CHANGED
@@ -39,34 +39,59 @@ var Swagger = class {
39
39
  if (tags) operationObject.tags = tags;
40
40
  this.spec.paths[normalizedPath][methodLower] = operationObject;
41
41
  }
42
+ extractJsonSchema(schema) {
43
+ if (!schema) return {};
44
+ const js = schema.jsonSchema || schema;
45
+ if (js.type || js.properties || js.$ref || js.items) {
46
+ const standardProps = [
47
+ "type",
48
+ "properties",
49
+ "required",
50
+ "items",
51
+ "enum",
52
+ "nullable",
53
+ "format",
54
+ "description",
55
+ "title",
56
+ "default",
57
+ "minimum",
58
+ "maximum",
59
+ "minLength",
60
+ "maxLength",
61
+ "pattern",
62
+ "anyOf",
63
+ "oneOf",
64
+ "allOf",
65
+ "not",
66
+ "$ref",
67
+ "additionalProperties"
68
+ ];
69
+ const filtered = {};
70
+ for (const prop of standardProps) if (js[prop] !== void 0) filtered[prop] = js[prop];
71
+ return filtered;
72
+ }
73
+ return {};
74
+ }
42
75
  buildParameters(schema) {
43
76
  const parameters = [];
44
- if (schema.params) try {
45
- const jsonSchema = schema.params;
46
- if (jsonSchema.properties) Object.entries(jsonSchema.properties).forEach(([name, propSchema]) => {
47
- parameters.push({
48
- name,
49
- in: "path",
50
- required: jsonSchema.required?.includes(name) ?? true,
51
- schema: propSchema
52
- });
77
+ const paramsSchema = this.extractJsonSchema(schema.params);
78
+ if (paramsSchema.properties) Object.entries(paramsSchema.properties).forEach(([name, propSchema]) => {
79
+ parameters.push({
80
+ name,
81
+ in: "path",
82
+ required: paramsSchema.required?.includes(name) ?? true,
83
+ schema: propSchema
53
84
  });
54
- } catch (e) {
55
- console.error("Failed to convert params schema:", e);
56
- }
57
- if (schema.query) try {
58
- const jsonSchema = schema.query;
59
- if (jsonSchema.properties) Object.entries(jsonSchema.properties).forEach(([name, propSchema]) => {
60
- parameters.push({
61
- name,
62
- in: "query",
63
- required: jsonSchema.required?.includes(name) ?? false,
64
- schema: propSchema
65
- });
85
+ });
86
+ const querySchema = this.extractJsonSchema(schema.query);
87
+ if (querySchema.properties) Object.entries(querySchema.properties).forEach(([name, propSchema]) => {
88
+ parameters.push({
89
+ name,
90
+ in: "query",
91
+ required: querySchema.required?.includes(name) ?? false,
92
+ schema: propSchema
66
93
  });
67
- } catch (e) {
68
- console.error("Failed to convert query schema:", e);
69
- }
94
+ });
70
95
  return parameters.length > 0 ? parameters : void 0;
71
96
  }
72
97
  buildRequestBody(schema) {
@@ -74,7 +99,7 @@ var Swagger = class {
74
99
  try {
75
100
  return {
76
101
  required: true,
77
- content: { "application/json": { schema: schema.body } }
102
+ content: { "application/json": { schema: this.extractJsonSchema(schema.body) } }
78
103
  };
79
104
  } catch (e) {
80
105
  console.error("Failed to convert body schema:", e);
@@ -84,7 +109,7 @@ var Swagger = class {
84
109
  buildResponses(schema) {
85
110
  const responses = { "200": { description: "Successful response" } };
86
111
  if (schema.response) try {
87
- const jsonSchema = schema.response;
112
+ const jsonSchema = this.extractJsonSchema(schema.response);
88
113
  responses["200"].content = { "application/json": { schema: jsonSchema } };
89
114
  } catch (e) {
90
115
  console.error("Failed to convert response schema:", e);
@@ -105,12 +130,6 @@ var Swagger = class {
105
130
  }
106
131
  generateHTML() {
107
132
  const hostname = new URL(this.host).hostname;
108
- const extractJsonSchema = (schema) => {
109
- if (!schema) return {};
110
- if (schema.jsonSchema) return schema.jsonSchema;
111
- if (schema.type || schema.properties || schema.$ref) return schema;
112
- return {};
113
- };
114
133
  const groupedPaths = {};
115
134
  const defaultGroup = "API";
116
135
  Object.entries(this.spec.paths || {}).forEach(([path, pathItem]) => {
@@ -221,7 +240,7 @@ var Swagger = class {
221
240
  let requestBodySection = "";
222
241
  if (operation.requestBody) {
223
242
  const schema = operation.requestBody.content?.["application/json"]?.schema;
224
- const cleanSchema = extractJsonSchema(schema);
243
+ const cleanSchema = this.extractJsonSchema(schema);
225
244
  if (cleanSchema.properties) requestBodySection = `
226
245
  <div>
227
246
  <h4 class="text-lg font-semibold text-white mb-3">Body Parameters</h4>
@@ -244,7 +263,7 @@ var Swagger = class {
244
263
  if (operation.requestBody) {
245
264
  curlCommand += ` \\\n -H 'Content-Type: application/json'`;
246
265
  const schema = operation.requestBody.content?.["application/json"]?.schema;
247
- const cleanSchema = extractJsonSchema(schema);
266
+ const cleanSchema = this.extractJsonSchema(schema);
248
267
  if (cleanSchema.properties) {
249
268
  const exampleData = {};
250
269
  Object.entries(cleanSchema.properties).forEach(([propName, propSchema]) => {
@@ -274,7 +293,7 @@ var Swagger = class {
274
293
  const response200 = operation.responses?.["200"];
275
294
  if (response200?.content?.["application/json"]?.schema) {
276
295
  const schema = response200.content["application/json"].schema;
277
- const cleanSchema = extractJsonSchema(schema);
296
+ const cleanSchema = this.extractJsonSchema(schema);
278
297
  responseSection = `
279
298
  <div>
280
299
  <h4 class="text-lg font-semibold text-white mb-4">Response Schema</h4>
@@ -1 +1 @@
1
- {"version":3,"file":"swagger.mjs","names":[],"sources":["../src/swagger.ts"],"sourcesContent":["import SwaggerParser from \"@apidevtools/swagger-parser\";\nimport type { OpenAPI } from \"openapi-types\";\n\nexport interface SwaggerOptions {\n title?: string;\n description?: string;\n version?: string;\n basePath?: string;\n schemes?: string[];\n consumes?: string[];\n produces?: string[];\n tags?: { name: string; description?: string }[];\n securityDefinitions?: Record<string, any>;\n externalDocs?: { description: string; url: string };\n host?: string;\n}\n\nexport class Swagger {\n private spec: OpenAPI.Document = {\n openapi: \"3.0.0\",\n info: {\n title: \"API Documentation\",\n version: \"1.0.0\",\n },\n paths: {},\n components: {\n schemas: {},\n },\n } as OpenAPI.Document;\n host: string;\n\n constructor(options: SwaggerOptions = {}) {\n this.spec.info.title = options.title || \"API Documentation\";\n this.spec.info.description = options.description;\n this.spec.info.version = options.version || \"1.0.0\";\n this.host = options.host || \"https://example.com\";\n\n if (options.tags) {\n this.spec.tags = options.tags;\n }\n\n if (options.externalDocs) {\n this.spec.externalDocs = options.externalDocs;\n }\n\n if (options.securityDefinitions) {\n (this.spec as any).components = (this.spec as any).components || {};\n (this.spec as any).components.securitySchemes = options.securityDefinitions;\n }\n }\n\n addRoute(\n method: string,\n path: string,\n schema: any,\n summary?: string,\n description?: string,\n tags?: string[],\n ) {\n if (!schema) {\n return;\n }\n\n const normalizedPath = path.replace(/:([^/]+)/g, \"{$1}\");\n if (!this.spec.paths) {\n this.spec.paths = {};\n }\n if (!this.spec.paths[normalizedPath]) {\n this.spec.paths[normalizedPath] = {};\n }\n\n const methodLower = method.toLowerCase();\n const operationObject: any = {\n summary: summary || `${method} ${path}`,\n parameters: this.buildParameters(schema),\n requestBody: this.buildRequestBody(schema),\n responses: this.buildResponses(schema),\n };\n\n if (description) {\n operationObject.description = description;\n }\n\n if (tags) {\n operationObject.tags = tags;\n }\n\n (this.spec.paths as any)[normalizedPath][methodLower] = operationObject;\n }\n\n private buildParameters(schema: any) {\n const parameters: any[] = [];\n\n if (schema.params) {\n try {\n const jsonSchema = schema.params;\n if (jsonSchema.properties) {\n Object.entries(jsonSchema.properties).forEach(([name, propSchema]: [string, any]) => {\n parameters.push({\n name,\n in: \"path\",\n required: jsonSchema.required?.includes(name) ?? true,\n schema: propSchema,\n });\n });\n }\n } catch (e) {\n console.error(\"Failed to convert params schema:\", e);\n }\n }\n\n if (schema.query) {\n try {\n const jsonSchema = schema.query;\n if (jsonSchema.properties) {\n Object.entries(jsonSchema.properties).forEach(([name, propSchema]: [string, any]) => {\n parameters.push({\n name,\n in: \"query\",\n required: jsonSchema.required?.includes(name) ?? false,\n schema: propSchema,\n });\n });\n }\n } catch (e) {\n console.error(\"Failed to convert query schema:\", e);\n }\n }\n\n return parameters.length > 0 ? parameters : undefined;\n }\n\n private buildRequestBody(schema: any) {\n if (!schema.body) {\n return undefined;\n }\n\n try {\n const jsonSchema = schema.body;\n return {\n required: true,\n content: {\n \"application/json\": {\n schema: jsonSchema,\n },\n },\n };\n } catch (e) {\n console.error(\"Failed to convert body schema:\", e);\n return undefined;\n }\n }\n\n private buildResponses(schema: any) {\n const responses: Record<string, any> = {\n \"200\": {\n description: \"Successful response\",\n },\n };\n\n if (schema.response) {\n try {\n const jsonSchema = schema.response;\n responses[\"200\"].content = {\n \"application/json\": {\n schema: jsonSchema,\n },\n };\n } catch (e) {\n console.error(\"Failed to convert response schema:\", e);\n }\n }\n\n return responses;\n }\n\n async validate() {\n try {\n await SwaggerParser.validate(this.spec as any);\n return true;\n } catch (error) {\n console.error(\"Swagger validation error:\", error);\n return false;\n }\n }\n\n getSpec() {\n return this.spec;\n }\n\n generateHTML(): string {\n const hostname = new URL(this.host).hostname;\n\n const extractJsonSchema = (schema: any): any => {\n // biome-ignore lint/style/useBlockStatements: off\n if (!schema) return {};\n\n if (schema.jsonSchema) {\n return schema.jsonSchema;\n }\n\n if (schema.type || schema.properties || schema.$ref) {\n return schema;\n }\n\n return {};\n };\n\n const groupedPaths: Record<\n string,\n Array<{\n path: string;\n method: string;\n operation: any;\n }>\n > = {};\n\n const defaultGroup = \"API\";\n\n Object.entries(this.spec.paths || {}).forEach(([path, pathItem]: [string, any]) => {\n Object.entries(pathItem).forEach(([method, operation]: [string, any]) => {\n const tags = operation.tags || [defaultGroup];\n const primaryTag = tags[0];\n\n if (!groupedPaths[primaryTag]) {\n groupedPaths[primaryTag] = [];\n }\n\n groupedPaths[primaryTag].push({\n path,\n method: method.toUpperCase(),\n operation,\n });\n });\n });\n\n const sidebarSections = Object.entries(groupedPaths)\n .map(([tag, endpoints]) => {\n const endpointCount = endpoints.length;\n const endpointLinks = endpoints\n .map(({ path, method }) => {\n const operationId = `${method.toLowerCase()}-${path.replace(/[^a-zA-Z0-9]/g, \"-\")}`;\n return `<li><a href=\"#${operationId}\" class=\"block px-3 py-1.5 rounded-lg hover:bg-dark-700/50 transition-colors text-sm text-gray-400 hover:text-white\">${method} ${path}</a></li>`;\n })\n .join(\"\\n \");\n\n return `\n <div>\n <button class=\"sidebar-group-toggle w-full flex items-center justify-between px-3 py-2 hover:bg-dark-700/30 rounded-lg transition-colors group\" data-target=\"${tag.toLowerCase()}-group\">\n <div class=\"flex items-center space-x-2\">\n <h3 class=\"text-sm font-medium text-gray-300 group-hover:text-white\">${tag}</h3>\n <span class=\"text-xs text-gray-500 bg-dark-600 px-2 py-0.5 rounded-full\">${endpointCount}</span>\n <svg class=\"w-4 h-4 text-gray-400 transform transition-transform duration-200 group-hover:text-gray-300\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\"></path>\n </svg>\n </div>\n </button>\n <div id=\"${tag.toLowerCase()}-group\" class=\"sidebar-group-content max-h-0 overflow-hidden transition-all duration-300\">\n <ul class=\"ml-6 mt-1 space-y-1\">\n ${endpointLinks}\n </ul>\n </div>\n </div>\n\n <div class=\"border-t border-dark-600 my-3\"></div>`;\n })\n .join(\"\");\n\n const contentSections = Object.entries(groupedPaths)\n .map(([tag, endpoints]) => {\n const tagDescription =\n this.spec.tags?.find((t) => t.name === tag)?.description ||\n `Manage ${tag.toLowerCase()} operations`;\n\n const endpointCards = endpoints\n .map(({ path, method, operation }) => {\n const operationId = `${method.toLowerCase()}-${path.replace(/[^a-zA-Z0-9]/g, \"-\")}`;\n const methodColor =\n {\n GET: \"bg-green-600\",\n POST: \"bg-blue-600\",\n PUT: \"bg-yellow-600\",\n DELETE: \"bg-red-600\",\n PATCH: \"bg-purple-600\",\n WS: \"bg-indigo-600\",\n SUB: \"bg-pink-600\",\n }[method] || \"bg-gray-600\";\n\n return `\n <a href=\"#${operationId}\" class=\"block p-4 rounded-lg border border-dark-600 hover:border-blue-500 hover:bg-dark-700/30 transition-all group\">\n <div class=\"flex items-center justify-between mb-2\">\n <div class=\"flex items-center space-x-3\">\n <span class=\"${methodColor} text-white px-3 py-1 rounded-lg text-sm font-medium\">${method}</span>\n <code class=\"text-blue-400 font-mono\">${path}</code>\n </div>\n <svg class=\"w-5 h-5 text-gray-400 group-hover:text-blue-400 transition-colors\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\"></path>\n </svg>\n </div>\n <p class=\"text-gray-300 text-sm\">${operation.summary || operation.description || `${method} ${path} operation`}</p>\n </a>`;\n })\n .join(\"\\n\");\n\n const detailedEndpoints = endpoints\n .map(({ path, method, operation }) => {\n const operationId = `${method.toLowerCase()}-${path.replace(/[^a-zA-Z0-9]/g, \"-\")}`;\n const methodColor =\n {\n GET: \"bg-green-600\",\n POST: \"bg-blue-600\",\n PUT: \"bg-yellow-600\",\n DELETE: \"bg-red-600\",\n PATCH: \"bg-purple-600\",\n WS: \"bg-indigo-600\",\n SUB: \"bg-pink-600\",\n }[method] || \"bg-gray-600\";\n\n let parametersSection = \"\";\n if (operation.parameters && operation.parameters.length > 0) {\n const pathParams = operation.parameters.filter((p: any) => p.in === \"path\");\n const queryParams = operation.parameters.filter((p: any) => p.in === \"query\");\n\n if (pathParams.length > 0) {\n parametersSection += `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Path Parameters</h4>\n <div class=\"space-y-3\">\n ${pathParams\n .map(\n (param: any) => `\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">${param.name}</code>\n <span class=\"text-xs ${param.required ? \"text-red-400\" : \"text-gray-400\"}\">${param.required ? \"required\" : \"optional\"}</span>\n </div>\n <p class=\"text-sm text-gray-300\">${param.description || `${param.name} parameter`}</p>\n </div>`,\n )\n .join(\"\")}\n </div>\n </div>`;\n }\n\n if (queryParams.length > 0) {\n parametersSection += `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Query Parameters</h4>\n <div class=\"space-y-3\">\n ${queryParams\n .map(\n (param: any) => `\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">${param.name}</code>\n <span class=\"text-xs ${param.required ? \"text-red-400\" : \"text-gray-400\"}\">${param.required ? \"required\" : \"optional\"}</span>\n </div>\n <p class=\"text-sm text-gray-300\">${param.description || `${param.name} parameter`}</p>\n </div>`,\n )\n .join(\"\")}\n </div>\n </div>`;\n }\n }\n\n let requestBodySection = \"\";\n if (operation.requestBody) {\n const schema = operation.requestBody.content?.[\"application/json\"]?.schema;\n const cleanSchema = extractJsonSchema(schema);\n\n if (cleanSchema.properties) {\n requestBodySection = `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Body Parameters</h4>\n <div class=\"space-y-3\">\n ${Object.entries(cleanSchema.properties)\n .map(\n ([propName, propSchema]: [string, any]) => `\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">${propName}</code>\n <span class=\"text-xs ${cleanSchema.required?.includes(propName) ? \"text-red-400\" : \"text-gray-400\"}\">${cleanSchema.required?.includes(propName) ? \"required\" : \"optional\"}</span>\n </div>\n <p class=\"text-sm text-gray-300\">${propSchema.description || `${propName} field`}</p>\n </div>`,\n )\n .join(\"\")}\n </div>\n </div>`;\n }\n }\n\n const baseUrl = `https://${hostname}`;\n let requestExample = \"\";\n\n if (method !== \"WS\" && method !== \"SUB\") {\n let curlCommand = `curl -X ${method} '${baseUrl}${path}'`;\n\n if (operation.requestBody) {\n curlCommand += ` \\\\\\n -H 'Content-Type: application/json'`;\n const schema = operation.requestBody.content?.[\"application/json\"]?.schema;\n const cleanSchema = extractJsonSchema(schema);\n\n if (cleanSchema.properties) {\n const exampleData: Record<string, any> = {};\n Object.entries(cleanSchema.properties).forEach(\n ([propName, propSchema]: [string, any]) => {\n if (propSchema.type === \"string\") {\n exampleData[propName] =\n propSchema.format === \"email\"\n ? \"user@example.com\"\n : `example ${propName}`;\n } else if (propSchema.type === \"number\") {\n exampleData[propName] = 123;\n } else if (propSchema.type === \"boolean\") {\n exampleData[propName] = true;\n } else {\n exampleData[propName] = `example ${propName}`;\n }\n },\n );\n curlCommand += ` \\\\\\n -d '${JSON.stringify(exampleData, null, 2).replace(/\\n/g, \"\\\\n \")}'`;\n }\n }\n\n curlCommand += ` \\\\\\n -H 'Authorization: Bearer your-token'`;\n\n requestExample = `\n <div>\n <div class=\"flex items-center justify-between mb-4\">\n <h4 class=\"text-lg font-semibold text-white\">Request Example</h4>\n <button class=\"copy-btn bg-dark-700 hover:bg-dark-600 px-3 py-1 rounded-lg text-sm transition-colors\" data-copy=\"${curlCommand.replace(/'/g, \"\\\\'\")}\">\n Copy\n </button>\n </div>\n <div class=\"code-block rounded-xl p-4 border border-dark-600\">\n <pre class=\"text-sm text-gray-300 overflow-x-auto\"><code>${curlCommand}</code></pre>\n </div>\n </div>`;\n }\n\n let responseSection = \"\";\n const response200 = operation.responses?.[\"200\"];\n if (response200?.content?.[\"application/json\"]?.schema) {\n const schema = response200.content[\"application/json\"].schema;\n const cleanSchema = extractJsonSchema(schema);\n\n responseSection = `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-4\">Response Schema</h4>\n <div class=\"code-block rounded-xl p-4 border border-dark-600\">\n <pre class=\"text-sm text-gray-300 overflow-x-auto\"><code>${JSON.stringify(cleanSchema, null, 2)}</code></pre>\n </div>\n </div>`;\n }\n\n return `\n <section id=\"${operationId}\" class=\"fade-in\">\n <div class=\"grid lg:grid-cols-3 gap-8\">\n <div class=\"lg:col-span-1 space-y-6\">\n <div>\n <div class=\"flex items-center space-x-3 mb-4\">\n <span class=\"${methodColor} text-white px-3 py-1 rounded-lg text-sm font-medium\">${method}</span>\n <code class=\"text-blue-400 font-mono\">${path}</code>\n </div>\n <p class=\"text-gray-300\">${operation.description || operation.summary || `${method} ${path} operation`}</p>\n </div>\n\n ${parametersSection}\n ${requestBodySection}\n\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Headers</h4>\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">Authorization</code>\n <span class=\"text-xs text-red-400\">required</span>\n </div>\n <p class=\"text-sm text-gray-300\">Bearer token for authentication</p>\n </div>\n </div>\n\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Responses</h4>\n <div class=\"space-y-2\">\n ${Object.entries(operation.responses || {})\n .map(([code, response]: [string, any]) => {\n const statusColor = code.startsWith(\"2\")\n ? \"bg-green-600\"\n : code.startsWith(\"4\")\n ? \"bg-red-600\"\n : \"bg-yellow-600\";\n return `\n <div class=\"flex items-center space-x-3\">\n <span class=\"${statusColor} text-white px-2 py-1 rounded text-xs\">${code}</span>\n <span class=\"text-gray-300 text-sm\">${response.description || \"Response\"}</span>\n </div>`;\n })\n .join(\"\")}\n </div>\n </div>\n </div>\n\n <div class=\"lg:col-span-2 space-y-6\">\n ${requestExample}\n ${responseSection}\n </div>\n </div>\n </section>`;\n })\n .join(\"\\n\");\n\n return `\n <section id=\"${tag.toLowerCase()}-tag\" class=\"fade-in\">\n <div class=\"grid lg:grid-cols-3 gap-8 mb-12\">\n <div class=\"lg:col-span-1\">\n <div class=\"sticky top-24\">\n <h2 class=\"text-3xl font-bold text-white mb-4\">${tag}</h2>\n <p class=\"text-gray-300 text-lg leading-relaxed\">\n ${tagDescription}\n </p>\n <div class=\"mt-6 flex items-center space-x-2\">\n <span class=\"bg-blue-600 text-white px-3 py-1 rounded-full text-sm font-medium\">${endpoints.length} endpoints</span>\n <span class=\"bg-gray-600 text-white px-3 py-1 rounded-full text-sm font-medium\">Authentication required</span>\n </div>\n </div>\n </div>\n\n <div class=\"lg:col-span-2\">\n <div class=\"bg-dark-800/30 backdrop-blur-sm rounded-xl p-6 border border-dark-700\">\n <h3 class=\"text-xl font-semibold text-white mb-6\">Available Endpoints</h3>\n <div class=\"space-y-4\">\n ${endpointCards}\n </div>\n </div>\n </div>\n </div>\n </section>\n\n <hr class=\"border-dark-600\">\n\n <div class=\"space-y-16\">\n ${detailedEndpoints}\n </div>`;\n })\n .join(\"\\n\\n\");\n\n return `<!DOCTYPE html>\n<html lang=\"es\" class=\"dark\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${this.spec.info.title}</title>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <script>\n tailwind.config = {\n darkMode: 'class',\n theme: {\n extend: {\n colors: {\n dark: {\n 50: '#f8fafc',\n 100: '#f1f5f9',\n 200: '#e2e8f0',\n 300: '#cbd5e1',\n 400: '#94a3b8',\n 500: '#64748b',\n 600: '#475569',\n 700: '#334155',\n 800: '#1e293b',\n 900: '#0f172a',\n }\n }\n }\n }\n }\n </script>\n <style>\n .sidebar-transition {\n transition: transform 0.3s ease-in-out, width 0.3s ease-in-out;\n }\n .fade-in {\n animation: fadeIn 0.3s ease-in-out;\n }\n @keyframes fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .code-block {\n background: linear-gradient(135deg, #1e293b 0%, #334155 100%);\n }\n </style>\n</head>\n<body class=\"bg-dark-900 text-gray-100 font-sans\">\n\n <nav class=\"fixed top-0 left-0 right-0 z-50 bg-dark-900/80 backdrop-blur-md border-b border-dark-700\">\n <div class=\"flex items-center justify-between px-4 py-3\">\n <div class=\"flex items-center space-x-4\">\n <button id=\"sidebarToggle\" class=\"p-2 rounded-lg hover:bg-dark-700 transition-colors\">\n <svg class=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 6h16M4 12h16M4 18h16\"></path>\n </svg>\n </button>\n <h1 class=\"text-xl font-bold text-blue-400\">${this.spec.info.title}</h1>\n </div>\n\n <div class=\"flex items-center space-x-4\">\n <!-- <select id=\"languageSelect\" class=\"bg-dark-800 border border-dark-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all\">\n <option value=\"shell\">Shell</option>\n <option value=\"nodejs\">Node.js</option>\n </select> -->\n\n <button id=\"themeToggle\" class=\"p-2 rounded-lg hover:bg-dark-700 transition-colors\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z\"></path>\n </svg>\n </button>\n </div>\n </div>\n </nav>\n\n <div class=\"flex pt-16\">\n\n <aside id=\"sidebar\" class=\"fixed top-16 bottom-0 left-0 z-40 w-64 bg-dark-800/50 backdrop-blur-sm border-r border-dark-700 sidebar-transition transform translate-x-0\">\n <div class=\"p-4 h-full overflow-y-auto pt-6\">\n <div class=\"space-y-1\">\n ${sidebarSections}\n </div>\n </div>\n </aside>\n\n <div id=\"sidebarOverlay\" class=\"fixed top-16 bottom-0 left-0 right-0 bg-black/50 z-30 lg:hidden hidden\"></div>\n\n <main id=\"mainContent\" class=\"flex-1 ml-64 transition-all duration-300\">\n <div class=\"max-w-7xl mx-auto px-4 py-8\">\n\n <div class=\"mb-12 fade-in\">\n <h1 class=\"text-4xl font-bold text-white mb-4\">${this.spec.info.title}</h1>\n <p class=\"text-xl text-gray-300 mb-4\">${this.spec.info.description || \"Complete reference for our REST API\"}</p>\n <span class=\"inline-block bg-blue-600 text-white px-3 py-1 rounded-full text-sm font-medium\">v${this.spec.info.version}</span>\n </div>\n\n <div class=\"grid gap-8 mb-12 fade-in\">\n <div class=\"bg-dark-800/30 backdrop-blur-sm rounded-xl p-6 border border-dark-700\">\n <h3 class=\"text-xl font-semibold text-white mb-4\">Server</h3>\n <div class=\"space-y-3\">\n <a href=\"${this.host}\" target=\"_blank\" class=\"flex items-center space-x-3 hover:bg-dark-700/30 p-2 rounded-lg transition-colors group\">\n <div class=\"w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center\">\n <svg class=\"w-4 h-4 text-white\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14\"></path>\n </svg>\n </div>\n <span class=\"text-gray-300 group-hover:text-white transition-colors\">${this.host}</span>\n </a>\n </div>\n </div>\n </div>\n\n <div class=\"space-y-20\">\n ${contentSections}\n </div>\n </div>\n </main>\n </div>\n\n <script>\n const sidebarToggle = document.getElementById('sidebarToggle');\n const sidebar = document.getElementById('sidebar');\n const sidebarOverlay = document.getElementById('sidebarOverlay');\n const mainContent = document.getElementById('mainContent');\n const themeToggle = document.getElementById('themeToggle');\n const html = document.documentElement;\n\n themeToggle.addEventListener('click', () => {\n if (html.classList.contains('dark')) {\n html.classList.remove('dark');\n html.classList.add('light');\n document.body.className = 'bg-gray-50 text-gray-900 font-sans';\n\n const navbar = document.querySelector('nav');\n navbar.className = 'fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-gray-200';\n\n const sidebar = document.getElementById('sidebar');\n sidebar.className = sidebar.className.replace('bg-dark-800/50 backdrop-blur-sm border-r border-dark-700', 'bg-white/50 backdrop-blur-sm border-r border-gray-200');\n\n document.querySelectorAll('h1, h2, h3, h4').forEach(heading => {\n heading.classList.remove('text-white', 'text-gray-100');\n heading.classList.add('text-gray-900');\n });\n\n document.querySelectorAll('.text-gray-300').forEach(el => {\n el.classList.remove('text-gray-300');\n el.classList.add('text-gray-700');\n });\n\n document.querySelectorAll('.text-gray-400').forEach(el => {\n el.classList.remove('text-gray-400');\n el.classList.add('text-gray-600');\n });\n\n document.querySelectorAll('.border-dark-600').forEach(el => {\n el.classList.remove('border-dark-600');\n el.classList.add('border-gray-300');\n });\n\n document.querySelectorAll('.bg-dark-700\\\\/30').forEach(el => {\n el.classList.remove('bg-dark-700/30');\n el.classList.add('bg-gray-100/30');\n });\n\n document.querySelectorAll('.bg-dark-800\\\\/20').forEach(el => {\n el.classList.remove('bg-dark-800/20');\n el.classList.add('bg-gray-50/20');\n });\n\n document.querySelectorAll('.bg-dark-600').forEach(el => {\n el.classList.remove('bg-dark-600');\n el.classList.add('bg-gray-400');\n });\n\n document.querySelectorAll('.text-gray-500').forEach(el => {\n el.classList.remove('text-gray-500');\n el.classList.add('text-gray-600');\n });\n\n document.querySelectorAll('aside a').forEach(link => {\n link.classList.add('text-gray-700', 'hover:text-gray-900', 'hover:bg-gray-100');\n });\n\n document.querySelectorAll('pre code').forEach(code => {\n code.classList.remove('text-gray-300');\n code.classList.add('text-gray-800');\n });\n\n document.querySelectorAll('.bg-dark-800\\\\/30').forEach(el => {\n el.classList.remove('bg-dark-800/30', 'border-dark-700');\n el.classList.add('bg-white/30', 'border-gray-200');\n });\n\n document.querySelectorAll('.code-block').forEach(el => {\n el.style.background = 'linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%)';\n el.classList.remove('border-dark-600');\n el.classList.add('border-gray-300');\n });\n\n document.querySelectorAll('.border-dark-600').forEach(el => {\n el.classList.remove('border-dark-600');\n el.classList.add('border-gray-300');\n });\n\n } else {\n html.classList.remove('light');\n html.classList.add('dark');\n document.body.className = 'bg-dark-900 text-gray-100 font-sans';\n\n const navbar = document.querySelector('nav');\n navbar.className = 'fixed top-0 left-0 right-0 z-50 bg-dark-900/80 backdrop-blur-md border-b border-dark-700';\n\n const sidebar = document.getElementById('sidebar');\n sidebar.className = sidebar.className.replace('bg-white/50 backdrop-blur-sm border-r border-gray-200', 'bg-dark-800/50 backdrop-blur-sm border-r border-dark-700');\n\n document.querySelectorAll('h1, h2, h3, h4').forEach(heading => {\n heading.classList.remove('text-gray-900');\n heading.classList.add('text-white');\n });\n\n document.querySelectorAll('.text-gray-700').forEach(el => {\n el.classList.remove('text-gray-700');\n el.classList.add('text-gray-300');\n });\n\n document.querySelectorAll('.text-gray-600').forEach(el => {\n el.classList.remove('text-gray-600');\n el.classList.add('text-gray-400');\n });\n\n document.querySelectorAll('.border-gray-300').forEach(el => {\n el.classList.remove('border-gray-300');\n el.classList.add('border-dark-600');\n });\n\n document.querySelectorAll('.bg-gray-100\\\\/30').forEach(el => {\n el.classList.remove('bg-gray-100/30');\n el.classList.add('bg-dark-700/30');\n });\n\n document.querySelectorAll('.bg-gray-50\\\\/20').forEach(el => {\n el.classList.remove('bg-gray-50/20');\n el.classList.add('bg-dark-800/20');\n });\n\n document.querySelectorAll('.bg-gray-400').forEach(el => {\n el.classList.remove('bg-gray-400');\n el.classList.add('bg-dark-600');\n });\n\n document.querySelectorAll('.text-gray-600').forEach(el => {\n el.classList.remove('text-gray-600');\n el.classList.add('text-gray-500');\n });\n\n document.querySelectorAll('aside a').forEach(link => {\n link.classList.remove('text-gray-700', 'hover:text-gray-900', 'hover:bg-gray-100');\n });\n\n document.querySelectorAll('pre code').forEach(code => {\n code.classList.remove('text-gray-800');\n code.classList.add('text-gray-300');\n });\n\n document.querySelectorAll('.bg-white\\\\/30').forEach(el => {\n el.classList.remove('bg-white/30', 'border-gray-200');\n el.classList.add('bg-dark-800/30', 'border-dark-700');\n });\n\n document.querySelectorAll('.code-block').forEach(el => {\n el.style.background = 'linear-gradient(135deg, #1e293b 0%, #334155 100%)';\n el.classList.remove('border-gray-300');\n el.classList.add('border-dark-600');\n });\n\n document.querySelectorAll('.border-gray-300').forEach(el => {\n el.classList.remove('border-gray-300');\n el.classList.add('border-dark-600');\n });\n }\n });\n\n function toggleSidebar() {\n const isHidden = sidebar.classList.contains('-translate-x-full');\n\n if (isHidden) {\n sidebar.classList.remove('-translate-x-full');\n mainContent.classList.remove('ml-0');\n mainContent.classList.add('ml-64');\n } else {\n sidebar.classList.add('-translate-x-full');\n mainContent.classList.remove('ml-64');\n mainContent.classList.add('ml-0');\n }\n\n if (window.innerWidth < 1024) {\n sidebarOverlay.classList.toggle('hidden');\n }\n }\n\n sidebarToggle.addEventListener('click', toggleSidebar);\n sidebarOverlay.addEventListener('click', toggleSidebar);\n\n document.querySelectorAll('.copy-btn').forEach(btn => {\n btn.addEventListener('click', async () => {\n const textToCopy = btn.getAttribute('data-copy');\n try {\n await navigator.clipboard.writeText(textToCopy);\n btn.textContent = 'Copied!';\n setTimeout(() => {\n btn.textContent = 'Copy';\n }, 2000);\n } catch (err) {\n console.error('Failed to copy text: ', err);\n }\n });\n });\n\n document.querySelectorAll('a[href^=\"#\"]').forEach(anchor => {\n anchor.addEventListener('click', function (e) {\n e.preventDefault();\n const target = document.querySelector(this.getAttribute('href'));\n if (target) {\n target.scrollIntoView({\n behavior: 'smooth',\n block: 'start'\n });\n\n if (window.innerWidth < 1024) {\n toggleSidebar();\n }\n }\n });\n });\n\n document.querySelectorAll('.sidebar-group-toggle').forEach(button => {\n button.addEventListener('click', () => {\n const targetId = button.getAttribute('data-target');\n const targetGroup = document.getElementById(targetId);\n const arrow = button.querySelector('svg');\n\n if (targetGroup.style.maxHeight && targetGroup.style.maxHeight !== '0px') {\n targetGroup.style.maxHeight = '0px';\n arrow.style.transform = 'rotate(0deg)';\n } else {\n targetGroup.style.maxHeight = targetGroup.scrollHeight + 'px';\n arrow.style.transform = 'rotate(180deg)';\n }\n });\n });\n\n document.querySelectorAll('.sidebar-group-content').forEach(group => {\n group.style.maxHeight = group.scrollHeight + 'px';\n });\n document.querySelectorAll('.sidebar-group-toggle svg').forEach(arrow => {\n arrow.style.transform = 'rotate(180deg)';\n });\n\n function handleResize() {\n if (window.innerWidth < 1024) {\n sidebar.classList.add('-translate-x-full');\n mainContent.classList.remove('ml-64');\n mainContent.classList.add('ml-0');\n } else {\n if (!sidebar.hasAttribute('data-manually-hidden')) {\n sidebar.classList.remove('-translate-x-full');\n mainContent.classList.remove('ml-0');\n mainContent.classList.add('ml-64');\n }\n sidebarOverlay.classList.add('hidden');\n }\n }\n\n window.addEventListener('resize', handleResize);\n handleResize();\n </script>\n</body>\n</html>`;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"swagger.mjs","names":[],"sources":["../src/swagger.ts"],"sourcesContent":["import SwaggerParser from \"@apidevtools/swagger-parser\";\nimport type { OpenAPI } from \"openapi-types\";\n\nexport interface SwaggerOptions {\n title?: string;\n description?: string;\n version?: string;\n basePath?: string;\n schemes?: string[];\n consumes?: string[];\n produces?: string[];\n tags?: { name: string; description?: string }[];\n securityDefinitions?: Record<string, any>;\n externalDocs?: { description: string; url: string };\n host?: string;\n}\n\nexport class Swagger {\n private spec: OpenAPI.Document = {\n openapi: \"3.0.0\",\n info: {\n title: \"API Documentation\",\n version: \"1.0.0\",\n },\n paths: {},\n components: {\n schemas: {},\n },\n } as OpenAPI.Document;\n host: string;\n\n constructor(options: SwaggerOptions = {}) {\n this.spec.info.title = options.title || \"API Documentation\";\n this.spec.info.description = options.description;\n this.spec.info.version = options.version || \"1.0.0\";\n this.host = options.host || \"https://example.com\";\n\n if (options.tags) {\n this.spec.tags = options.tags;\n }\n\n if (options.externalDocs) {\n this.spec.externalDocs = options.externalDocs;\n }\n\n if (options.securityDefinitions) {\n (this.spec as any).components = (this.spec as any).components || {};\n (this.spec as any).components.securitySchemes = options.securityDefinitions;\n }\n }\n\n addRoute(\n method: string,\n path: string,\n schema: any,\n summary?: string,\n description?: string,\n tags?: string[],\n ) {\n if (!schema) {\n return;\n }\n\n const normalizedPath = path.replace(/:([^/]+)/g, \"{$1}\");\n if (!this.spec.paths) {\n this.spec.paths = {};\n }\n if (!this.spec.paths[normalizedPath]) {\n this.spec.paths[normalizedPath] = {};\n }\n\n const methodLower = method.toLowerCase();\n const operationObject: any = {\n summary: summary || `${method} ${path}`,\n parameters: this.buildParameters(schema),\n requestBody: this.buildRequestBody(schema),\n responses: this.buildResponses(schema),\n };\n\n if (description) {\n operationObject.description = description;\n }\n\n if (tags) {\n operationObject.tags = tags;\n }\n\n (this.spec.paths as any)[normalizedPath][methodLower] = operationObject;\n }\n\n private extractJsonSchema(schema: any): any {\n if (!schema) {\n return {};\n }\n\n const js = schema.jsonSchema || schema;\n\n if (js.type || js.properties || js.$ref || js.items) {\n const standardProps = [\n \"type\",\n \"properties\",\n \"required\",\n \"items\",\n \"enum\",\n \"nullable\",\n \"format\",\n \"description\",\n \"title\",\n \"default\",\n \"minimum\",\n \"maximum\",\n \"minLength\",\n \"maxLength\",\n \"pattern\",\n \"anyOf\",\n \"oneOf\",\n \"allOf\",\n \"not\",\n \"$ref\",\n \"additionalProperties\",\n ];\n\n const filtered: any = {};\n for (const prop of standardProps) {\n if (js[prop] !== undefined) {\n filtered[prop] = js[prop];\n }\n }\n return filtered;\n }\n\n return {};\n }\n\n private buildParameters(schema: any) {\n const parameters: any[] = [];\n\n const paramsSchema = this.extractJsonSchema(schema.params);\n if (paramsSchema.properties) {\n Object.entries(paramsSchema.properties).forEach(([name, propSchema]: [string, any]) => {\n parameters.push({\n name,\n in: \"path\",\n required: paramsSchema.required?.includes(name) ?? true,\n schema: propSchema,\n });\n });\n }\n\n const querySchema = this.extractJsonSchema(schema.query);\n if (querySchema.properties) {\n Object.entries(querySchema.properties).forEach(([name, propSchema]: [string, any]) => {\n parameters.push({\n name,\n in: \"query\",\n required: querySchema.required?.includes(name) ?? false,\n schema: propSchema,\n });\n });\n }\n\n return parameters.length > 0 ? parameters : undefined;\n }\n\n private buildRequestBody(schema: any) {\n if (!schema.body) {\n return undefined;\n }\n\n try {\n const jsonSchema = this.extractJsonSchema(schema.body);\n return {\n required: true,\n content: {\n \"application/json\": {\n schema: jsonSchema,\n },\n },\n };\n } catch (e) {\n console.error(\"Failed to convert body schema:\", e);\n return undefined;\n }\n }\n\n private buildResponses(schema: any) {\n const responses: Record<string, any> = {\n \"200\": {\n description: \"Successful response\",\n },\n };\n\n if (schema.response) {\n try {\n const jsonSchema = this.extractJsonSchema(schema.response);\n responses[\"200\"].content = {\n \"application/json\": {\n schema: jsonSchema,\n },\n };\n } catch (e) {\n console.error(\"Failed to convert response schema:\", e);\n }\n }\n\n return responses;\n }\n\n async validate() {\n try {\n await SwaggerParser.validate(this.spec as any);\n return true;\n } catch (error) {\n console.error(\"Swagger validation error:\", error);\n return false;\n }\n }\n\n getSpec() {\n return this.spec;\n }\n\n generateHTML(): string {\n const hostname = new URL(this.host).hostname;\n\n const groupedPaths: Record<\n string,\n Array<{\n path: string;\n method: string;\n operation: any;\n }>\n > = {};\n\n const defaultGroup = \"API\";\n\n Object.entries(this.spec.paths || {}).forEach(([path, pathItem]: [string, any]) => {\n Object.entries(pathItem).forEach(([method, operation]: [string, any]) => {\n const tags = operation.tags || [defaultGroup];\n const primaryTag = tags[0];\n\n if (!groupedPaths[primaryTag]) {\n groupedPaths[primaryTag] = [];\n }\n\n groupedPaths[primaryTag].push({\n path,\n method: method.toUpperCase(),\n operation,\n });\n });\n });\n\n const sidebarSections = Object.entries(groupedPaths)\n .map(([tag, endpoints]) => {\n const endpointCount = endpoints.length;\n const endpointLinks = endpoints\n .map(({ path, method }) => {\n const operationId = `${method.toLowerCase()}-${path.replace(/[^a-zA-Z0-9]/g, \"-\")}`;\n return `<li><a href=\"#${operationId}\" class=\"block px-3 py-1.5 rounded-lg hover:bg-dark-700/50 transition-colors text-sm text-gray-400 hover:text-white\">${method} ${path}</a></li>`;\n })\n .join(\"\\n \");\n\n return `\n <div>\n <button class=\"sidebar-group-toggle w-full flex items-center justify-between px-3 py-2 hover:bg-dark-700/30 rounded-lg transition-colors group\" data-target=\"${tag.toLowerCase()}-group\">\n <div class=\"flex items-center space-x-2\">\n <h3 class=\"text-sm font-medium text-gray-300 group-hover:text-white\">${tag}</h3>\n <span class=\"text-xs text-gray-500 bg-dark-600 px-2 py-0.5 rounded-full\">${endpointCount}</span>\n <svg class=\"w-4 h-4 text-gray-400 transform transition-transform duration-200 group-hover:text-gray-300\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\"></path>\n </svg>\n </div>\n </button>\n <div id=\"${tag.toLowerCase()}-group\" class=\"sidebar-group-content max-h-0 overflow-hidden transition-all duration-300\">\n <ul class=\"ml-6 mt-1 space-y-1\">\n ${endpointLinks}\n </ul>\n </div>\n </div>\n\n <div class=\"border-t border-dark-600 my-3\"></div>`;\n })\n .join(\"\");\n\n const contentSections = Object.entries(groupedPaths)\n .map(([tag, endpoints]) => {\n const tagDescription =\n this.spec.tags?.find((t) => t.name === tag)?.description ||\n `Manage ${tag.toLowerCase()} operations`;\n\n const endpointCards = endpoints\n .map(({ path, method, operation }) => {\n const operationId = `${method.toLowerCase()}-${path.replace(/[^a-zA-Z0-9]/g, \"-\")}`;\n const methodColor =\n {\n GET: \"bg-green-600\",\n POST: \"bg-blue-600\",\n PUT: \"bg-yellow-600\",\n DELETE: \"bg-red-600\",\n PATCH: \"bg-purple-600\",\n WS: \"bg-indigo-600\",\n SUB: \"bg-pink-600\",\n }[method] || \"bg-gray-600\";\n\n return `\n <a href=\"#${operationId}\" class=\"block p-4 rounded-lg border border-dark-600 hover:border-blue-500 hover:bg-dark-700/30 transition-all group\">\n <div class=\"flex items-center justify-between mb-2\">\n <div class=\"flex items-center space-x-3\">\n <span class=\"${methodColor} text-white px-3 py-1 rounded-lg text-sm font-medium\">${method}</span>\n <code class=\"text-blue-400 font-mono\">${path}</code>\n </div>\n <svg class=\"w-5 h-5 text-gray-400 group-hover:text-blue-400 transition-colors\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\"></path>\n </svg>\n </div>\n <p class=\"text-gray-300 text-sm\">${operation.summary || operation.description || `${method} ${path} operation`}</p>\n </a>`;\n })\n .join(\"\\n\");\n\n const detailedEndpoints = endpoints\n .map(({ path, method, operation }) => {\n const operationId = `${method.toLowerCase()}-${path.replace(/[^a-zA-Z0-9]/g, \"-\")}`;\n const methodColor =\n {\n GET: \"bg-green-600\",\n POST: \"bg-blue-600\",\n PUT: \"bg-yellow-600\",\n DELETE: \"bg-red-600\",\n PATCH: \"bg-purple-600\",\n WS: \"bg-indigo-600\",\n SUB: \"bg-pink-600\",\n }[method] || \"bg-gray-600\";\n\n let parametersSection = \"\";\n if (operation.parameters && operation.parameters.length > 0) {\n const pathParams = operation.parameters.filter((p: any) => p.in === \"path\");\n const queryParams = operation.parameters.filter((p: any) => p.in === \"query\");\n\n if (pathParams.length > 0) {\n parametersSection += `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Path Parameters</h4>\n <div class=\"space-y-3\">\n ${pathParams\n .map(\n (param: any) => `\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">${param.name}</code>\n <span class=\"text-xs ${param.required ? \"text-red-400\" : \"text-gray-400\"}\">${param.required ? \"required\" : \"optional\"}</span>\n </div>\n <p class=\"text-sm text-gray-300\">${param.description || `${param.name} parameter`}</p>\n </div>`,\n )\n .join(\"\")}\n </div>\n </div>`;\n }\n\n if (queryParams.length > 0) {\n parametersSection += `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Query Parameters</h4>\n <div class=\"space-y-3\">\n ${queryParams\n .map(\n (param: any) => `\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">${param.name}</code>\n <span class=\"text-xs ${param.required ? \"text-red-400\" : \"text-gray-400\"}\">${param.required ? \"required\" : \"optional\"}</span>\n </div>\n <p class=\"text-sm text-gray-300\">${param.description || `${param.name} parameter`}</p>\n </div>`,\n )\n .join(\"\")}\n </div>\n </div>`;\n }\n }\n\n let requestBodySection = \"\";\n if (operation.requestBody) {\n const schema = operation.requestBody.content?.[\"application/json\"]?.schema;\n const cleanSchema = this.extractJsonSchema(schema);\n\n if (cleanSchema.properties) {\n requestBodySection = `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Body Parameters</h4>\n <div class=\"space-y-3\">\n ${Object.entries(cleanSchema.properties)\n .map(\n ([propName, propSchema]: [string, any]) => `\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">${propName}</code>\n <span class=\"text-xs ${cleanSchema.required?.includes(propName) ? \"text-red-400\" : \"text-gray-400\"}\">${cleanSchema.required?.includes(propName) ? \"required\" : \"optional\"}</span>\n </div>\n <p class=\"text-sm text-gray-300\">${propSchema.description || `${propName} field`}</p>\n </div>`,\n )\n .join(\"\")}\n </div>\n </div>`;\n }\n }\n\n const baseUrl = `https://${hostname}`;\n let requestExample = \"\";\n\n if (method !== \"WS\" && method !== \"SUB\") {\n let curlCommand = `curl -X ${method} '${baseUrl}${path}'`;\n\n if (operation.requestBody) {\n curlCommand += ` \\\\\\n -H 'Content-Type: application/json'`;\n const schema = operation.requestBody.content?.[\"application/json\"]?.schema;\n const cleanSchema = this.extractJsonSchema(schema);\n\n if (cleanSchema.properties) {\n const exampleData: Record<string, any> = {};\n Object.entries(cleanSchema.properties).forEach(\n ([propName, propSchema]: [string, any]) => {\n if (propSchema.type === \"string\") {\n exampleData[propName] =\n propSchema.format === \"email\"\n ? \"user@example.com\"\n : `example ${propName}`;\n } else if (propSchema.type === \"number\") {\n exampleData[propName] = 123;\n } else if (propSchema.type === \"boolean\") {\n exampleData[propName] = true;\n } else {\n exampleData[propName] = `example ${propName}`;\n }\n },\n );\n curlCommand += ` \\\\\\n -d '${JSON.stringify(exampleData, null, 2).replace(/\\n/g, \"\\\\n \")}'`;\n }\n }\n\n curlCommand += ` \\\\\\n -H 'Authorization: Bearer your-token'`;\n\n requestExample = `\n <div>\n <div class=\"flex items-center justify-between mb-4\">\n <h4 class=\"text-lg font-semibold text-white\">Request Example</h4>\n <button class=\"copy-btn bg-dark-700 hover:bg-dark-600 px-3 py-1 rounded-lg text-sm transition-colors\" data-copy=\"${curlCommand.replace(/'/g, \"\\\\'\")}\">\n Copy\n </button>\n </div>\n <div class=\"code-block rounded-xl p-4 border border-dark-600\">\n <pre class=\"text-sm text-gray-300 overflow-x-auto\"><code>${curlCommand}</code></pre>\n </div>\n </div>`;\n }\n\n let responseSection = \"\";\n const response200 = operation.responses?.[\"200\"];\n if (response200?.content?.[\"application/json\"]?.schema) {\n const schema = response200.content[\"application/json\"].schema;\n const cleanSchema = this.extractJsonSchema(schema);\n\n responseSection = `\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-4\">Response Schema</h4>\n <div class=\"code-block rounded-xl p-4 border border-dark-600\">\n <pre class=\"text-sm text-gray-300 overflow-x-auto\"><code>${JSON.stringify(cleanSchema, null, 2)}</code></pre>\n </div>\n </div>`;\n }\n\n return `\n <section id=\"${operationId}\" class=\"fade-in\">\n <div class=\"grid lg:grid-cols-3 gap-8\">\n <div class=\"lg:col-span-1 space-y-6\">\n <div>\n <div class=\"flex items-center space-x-3 mb-4\">\n <span class=\"${methodColor} text-white px-3 py-1 rounded-lg text-sm font-medium\">${method}</span>\n <code class=\"text-blue-400 font-mono\">${path}</code>\n </div>\n <p class=\"text-gray-300\">${operation.description || operation.summary || `${method} ${path} operation`}</p>\n </div>\n\n ${parametersSection}\n ${requestBodySection}\n\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Headers</h4>\n <div class=\"border border-dark-600 rounded-lg p-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <code class=\"text-blue-400\">Authorization</code>\n <span class=\"text-xs text-red-400\">required</span>\n </div>\n <p class=\"text-sm text-gray-300\">Bearer token for authentication</p>\n </div>\n </div>\n\n <div>\n <h4 class=\"text-lg font-semibold text-white mb-3\">Responses</h4>\n <div class=\"space-y-2\">\n ${Object.entries(operation.responses || {})\n .map(([code, response]: [string, any]) => {\n const statusColor = code.startsWith(\"2\")\n ? \"bg-green-600\"\n : code.startsWith(\"4\")\n ? \"bg-red-600\"\n : \"bg-yellow-600\";\n return `\n <div class=\"flex items-center space-x-3\">\n <span class=\"${statusColor} text-white px-2 py-1 rounded text-xs\">${code}</span>\n <span class=\"text-gray-300 text-sm\">${response.description || \"Response\"}</span>\n </div>`;\n })\n .join(\"\")}\n </div>\n </div>\n </div>\n\n <div class=\"lg:col-span-2 space-y-6\">\n ${requestExample}\n ${responseSection}\n </div>\n </div>\n </section>`;\n })\n .join(\"\\n\");\n\n return `\n <section id=\"${tag.toLowerCase()}-tag\" class=\"fade-in\">\n <div class=\"grid lg:grid-cols-3 gap-8 mb-12\">\n <div class=\"lg:col-span-1\">\n <div class=\"sticky top-24\">\n <h2 class=\"text-3xl font-bold text-white mb-4\">${tag}</h2>\n <p class=\"text-gray-300 text-lg leading-relaxed\">\n ${tagDescription}\n </p>\n <div class=\"mt-6 flex items-center space-x-2\">\n <span class=\"bg-blue-600 text-white px-3 py-1 rounded-full text-sm font-medium\">${endpoints.length} endpoints</span>\n <span class=\"bg-gray-600 text-white px-3 py-1 rounded-full text-sm font-medium\">Authentication required</span>\n </div>\n </div>\n </div>\n\n <div class=\"lg:col-span-2\">\n <div class=\"bg-dark-800/30 backdrop-blur-sm rounded-xl p-6 border border-dark-700\">\n <h3 class=\"text-xl font-semibold text-white mb-6\">Available Endpoints</h3>\n <div class=\"space-y-4\">\n ${endpointCards}\n </div>\n </div>\n </div>\n </div>\n </section>\n\n <hr class=\"border-dark-600\">\n\n <div class=\"space-y-16\">\n ${detailedEndpoints}\n </div>`;\n })\n .join(\"\\n\\n\");\n\n return `<!DOCTYPE html>\n<html lang=\"es\" class=\"dark\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${this.spec.info.title}</title>\n <script src=\"https://cdn.tailwindcss.com\"></script>\n <script>\n tailwind.config = {\n darkMode: 'class',\n theme: {\n extend: {\n colors: {\n dark: {\n 50: '#f8fafc',\n 100: '#f1f5f9',\n 200: '#e2e8f0',\n 300: '#cbd5e1',\n 400: '#94a3b8',\n 500: '#64748b',\n 600: '#475569',\n 700: '#334155',\n 800: '#1e293b',\n 900: '#0f172a',\n }\n }\n }\n }\n }\n </script>\n <style>\n .sidebar-transition {\n transition: transform 0.3s ease-in-out, width 0.3s ease-in-out;\n }\n .fade-in {\n animation: fadeIn 0.3s ease-in-out;\n }\n @keyframes fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n }\n .code-block {\n background: linear-gradient(135deg, #1e293b 0%, #334155 100%);\n }\n </style>\n</head>\n<body class=\"bg-dark-900 text-gray-100 font-sans\">\n\n <nav class=\"fixed top-0 left-0 right-0 z-50 bg-dark-900/80 backdrop-blur-md border-b border-dark-700\">\n <div class=\"flex items-center justify-between px-4 py-3\">\n <div class=\"flex items-center space-x-4\">\n <button id=\"sidebarToggle\" class=\"p-2 rounded-lg hover:bg-dark-700 transition-colors\">\n <svg class=\"w-6 h-6\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 6h16M4 12h16M4 18h16\"></path>\n </svg>\n </button>\n <h1 class=\"text-xl font-bold text-blue-400\">${this.spec.info.title}</h1>\n </div>\n\n <div class=\"flex items-center space-x-4\">\n <!-- <select id=\"languageSelect\" class=\"bg-dark-800 border border-dark-600 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all\">\n <option value=\"shell\">Shell</option>\n <option value=\"nodejs\">Node.js</option>\n </select> -->\n\n <button id=\"themeToggle\" class=\"p-2 rounded-lg hover:bg-dark-700 transition-colors\">\n <svg class=\"w-5 h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z\"></path>\n </svg>\n </button>\n </div>\n </div>\n </nav>\n\n <div class=\"flex pt-16\">\n\n <aside id=\"sidebar\" class=\"fixed top-16 bottom-0 left-0 z-40 w-64 bg-dark-800/50 backdrop-blur-sm border-r border-dark-700 sidebar-transition transform translate-x-0\">\n <div class=\"p-4 h-full overflow-y-auto pt-6\">\n <div class=\"space-y-1\">\n ${sidebarSections}\n </div>\n </div>\n </aside>\n\n <div id=\"sidebarOverlay\" class=\"fixed top-16 bottom-0 left-0 right-0 bg-black/50 z-30 lg:hidden hidden\"></div>\n\n <main id=\"mainContent\" class=\"flex-1 ml-64 transition-all duration-300\">\n <div class=\"max-w-7xl mx-auto px-4 py-8\">\n\n <div class=\"mb-12 fade-in\">\n <h1 class=\"text-4xl font-bold text-white mb-4\">${this.spec.info.title}</h1>\n <p class=\"text-xl text-gray-300 mb-4\">${this.spec.info.description || \"Complete reference for our REST API\"}</p>\n <span class=\"inline-block bg-blue-600 text-white px-3 py-1 rounded-full text-sm font-medium\">v${this.spec.info.version}</span>\n </div>\n\n <div class=\"grid gap-8 mb-12 fade-in\">\n <div class=\"bg-dark-800/30 backdrop-blur-sm rounded-xl p-6 border border-dark-700\">\n <h3 class=\"text-xl font-semibold text-white mb-4\">Server</h3>\n <div class=\"space-y-3\">\n <a href=\"${this.host}\" target=\"_blank\" class=\"flex items-center space-x-3 hover:bg-dark-700/30 p-2 rounded-lg transition-colors group\">\n <div class=\"w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center\">\n <svg class=\"w-4 h-4 text-white\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14\"></path>\n </svg>\n </div>\n <span class=\"text-gray-300 group-hover:text-white transition-colors\">${this.host}</span>\n </a>\n </div>\n </div>\n </div>\n\n <div class=\"space-y-20\">\n ${contentSections}\n </div>\n </div>\n </main>\n </div>\n\n <script>\n const sidebarToggle = document.getElementById('sidebarToggle');\n const sidebar = document.getElementById('sidebar');\n const sidebarOverlay = document.getElementById('sidebarOverlay');\n const mainContent = document.getElementById('mainContent');\n const themeToggle = document.getElementById('themeToggle');\n const html = document.documentElement;\n\n themeToggle.addEventListener('click', () => {\n if (html.classList.contains('dark')) {\n html.classList.remove('dark');\n html.classList.add('light');\n document.body.className = 'bg-gray-50 text-gray-900 font-sans';\n\n const navbar = document.querySelector('nav');\n navbar.className = 'fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-md border-b border-gray-200';\n\n const sidebar = document.getElementById('sidebar');\n sidebar.className = sidebar.className.replace('bg-dark-800/50 backdrop-blur-sm border-r border-dark-700', 'bg-white/50 backdrop-blur-sm border-r border-gray-200');\n\n document.querySelectorAll('h1, h2, h3, h4').forEach(heading => {\n heading.classList.remove('text-white', 'text-gray-100');\n heading.classList.add('text-gray-900');\n });\n\n document.querySelectorAll('.text-gray-300').forEach(el => {\n el.classList.remove('text-gray-300');\n el.classList.add('text-gray-700');\n });\n\n document.querySelectorAll('.text-gray-400').forEach(el => {\n el.classList.remove('text-gray-400');\n el.classList.add('text-gray-600');\n });\n\n document.querySelectorAll('.border-dark-600').forEach(el => {\n el.classList.remove('border-dark-600');\n el.classList.add('border-gray-300');\n });\n\n document.querySelectorAll('.bg-dark-700\\\\/30').forEach(el => {\n el.classList.remove('bg-dark-700/30');\n el.classList.add('bg-gray-100/30');\n });\n\n document.querySelectorAll('.bg-dark-800\\\\/20').forEach(el => {\n el.classList.remove('bg-dark-800/20');\n el.classList.add('bg-gray-50/20');\n });\n\n document.querySelectorAll('.bg-dark-600').forEach(el => {\n el.classList.remove('bg-dark-600');\n el.classList.add('bg-gray-400');\n });\n\n document.querySelectorAll('.text-gray-500').forEach(el => {\n el.classList.remove('text-gray-500');\n el.classList.add('text-gray-600');\n });\n\n document.querySelectorAll('aside a').forEach(link => {\n link.classList.add('text-gray-700', 'hover:text-gray-900', 'hover:bg-gray-100');\n });\n\n document.querySelectorAll('pre code').forEach(code => {\n code.classList.remove('text-gray-300');\n code.classList.add('text-gray-800');\n });\n\n document.querySelectorAll('.bg-dark-800\\\\/30').forEach(el => {\n el.classList.remove('bg-dark-800/30', 'border-dark-700');\n el.classList.add('bg-white/30', 'border-gray-200');\n });\n\n document.querySelectorAll('.code-block').forEach(el => {\n el.style.background = 'linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%)';\n el.classList.remove('border-dark-600');\n el.classList.add('border-gray-300');\n });\n\n document.querySelectorAll('.border-dark-600').forEach(el => {\n el.classList.remove('border-dark-600');\n el.classList.add('border-gray-300');\n });\n\n } else {\n html.classList.remove('light');\n html.classList.add('dark');\n document.body.className = 'bg-dark-900 text-gray-100 font-sans';\n\n const navbar = document.querySelector('nav');\n navbar.className = 'fixed top-0 left-0 right-0 z-50 bg-dark-900/80 backdrop-blur-md border-b border-dark-700';\n\n const sidebar = document.getElementById('sidebar');\n sidebar.className = sidebar.className.replace('bg-white/50 backdrop-blur-sm border-r border-gray-200', 'bg-dark-800/50 backdrop-blur-sm border-r border-dark-700');\n\n document.querySelectorAll('h1, h2, h3, h4').forEach(heading => {\n heading.classList.remove('text-gray-900');\n heading.classList.add('text-white');\n });\n\n document.querySelectorAll('.text-gray-700').forEach(el => {\n el.classList.remove('text-gray-700');\n el.classList.add('text-gray-300');\n });\n\n document.querySelectorAll('.text-gray-600').forEach(el => {\n el.classList.remove('text-gray-600');\n el.classList.add('text-gray-400');\n });\n\n document.querySelectorAll('.border-gray-300').forEach(el => {\n el.classList.remove('border-gray-300');\n el.classList.add('border-dark-600');\n });\n\n document.querySelectorAll('.bg-gray-100\\\\/30').forEach(el => {\n el.classList.remove('bg-gray-100/30');\n el.classList.add('bg-dark-700/30');\n });\n\n document.querySelectorAll('.bg-gray-50\\\\/20').forEach(el => {\n el.classList.remove('bg-gray-50/20');\n el.classList.add('bg-dark-800/20');\n });\n\n document.querySelectorAll('.bg-gray-400').forEach(el => {\n el.classList.remove('bg-gray-400');\n el.classList.add('bg-dark-600');\n });\n\n document.querySelectorAll('.text-gray-600').forEach(el => {\n el.classList.remove('text-gray-600');\n el.classList.add('text-gray-500');\n });\n\n document.querySelectorAll('aside a').forEach(link => {\n link.classList.remove('text-gray-700', 'hover:text-gray-900', 'hover:bg-gray-100');\n });\n\n document.querySelectorAll('pre code').forEach(code => {\n code.classList.remove('text-gray-800');\n code.classList.add('text-gray-300');\n });\n\n document.querySelectorAll('.bg-white\\\\/30').forEach(el => {\n el.classList.remove('bg-white/30', 'border-gray-200');\n el.classList.add('bg-dark-800/30', 'border-dark-700');\n });\n\n document.querySelectorAll('.code-block').forEach(el => {\n el.style.background = 'linear-gradient(135deg, #1e293b 0%, #334155 100%)';\n el.classList.remove('border-gray-300');\n el.classList.add('border-dark-600');\n });\n\n document.querySelectorAll('.border-gray-300').forEach(el => {\n el.classList.remove('border-gray-300');\n el.classList.add('border-dark-600');\n });\n }\n });\n\n function toggleSidebar() {\n const isHidden = sidebar.classList.contains('-translate-x-full');\n\n if (isHidden) {\n sidebar.classList.remove('-translate-x-full');\n mainContent.classList.remove('ml-0');\n mainContent.classList.add('ml-64');\n } else {\n sidebar.classList.add('-translate-x-full');\n mainContent.classList.remove('ml-64');\n mainContent.classList.add('ml-0');\n }\n\n if (window.innerWidth < 1024) {\n sidebarOverlay.classList.toggle('hidden');\n }\n }\n\n sidebarToggle.addEventListener('click', toggleSidebar);\n sidebarOverlay.addEventListener('click', toggleSidebar);\n\n document.querySelectorAll('.copy-btn').forEach(btn => {\n btn.addEventListener('click', async () => {\n const textToCopy = btn.getAttribute('data-copy');\n try {\n await navigator.clipboard.writeText(textToCopy);\n btn.textContent = 'Copied!';\n setTimeout(() => {\n btn.textContent = 'Copy';\n }, 2000);\n } catch (err) {\n console.error('Failed to copy text: ', err);\n }\n });\n });\n\n document.querySelectorAll('a[href^=\"#\"]').forEach(anchor => {\n anchor.addEventListener('click', function (e) {\n e.preventDefault();\n const target = document.querySelector(this.getAttribute('href'));\n if (target) {\n target.scrollIntoView({\n behavior: 'smooth',\n block: 'start'\n });\n\n if (window.innerWidth < 1024) {\n toggleSidebar();\n }\n }\n });\n });\n\n document.querySelectorAll('.sidebar-group-toggle').forEach(button => {\n button.addEventListener('click', () => {\n const targetId = button.getAttribute('data-target');\n const targetGroup = document.getElementById(targetId);\n const arrow = button.querySelector('svg');\n\n if (targetGroup.style.maxHeight && targetGroup.style.maxHeight !== '0px') {\n targetGroup.style.maxHeight = '0px';\n arrow.style.transform = 'rotate(0deg)';\n } else {\n targetGroup.style.maxHeight = targetGroup.scrollHeight + 'px';\n arrow.style.transform = 'rotate(180deg)';\n }\n });\n });\n\n document.querySelectorAll('.sidebar-group-content').forEach(group => {\n group.style.maxHeight = group.scrollHeight + 'px';\n });\n document.querySelectorAll('.sidebar-group-toggle svg').forEach(arrow => {\n arrow.style.transform = 'rotate(180deg)';\n });\n\n function handleResize() {\n if (window.innerWidth < 1024) {\n sidebar.classList.add('-translate-x-full');\n mainContent.classList.remove('ml-64');\n mainContent.classList.add('ml-0');\n } else {\n if (!sidebar.hasAttribute('data-manually-hidden')) {\n sidebar.classList.remove('-translate-x-full');\n mainContent.classList.remove('ml-0');\n mainContent.classList.add('ml-64');\n }\n sidebarOverlay.classList.add('hidden');\n }\n }\n\n window.addEventListener('resize', handleResize);\n handleResize();\n </script>\n</body>\n</html>`;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hedystia/swagger",
3
- "version": "2.3.3",
3
+ "version": "2.3.5",
4
4
  "description": "Next-gen TypeScript framework for building type-safe APIs at lightspeed",
5
5
  "homepage": "https://docs.hedystia.com/plugins/swagger",
6
6
  "devDependencies": {
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "dependencies": {
11
11
  "@apidevtools/swagger-parser": "^10.1.1",
12
- "hedystia": "2.3.3",
12
+ "hedystia": "2.3.5",
13
13
  "openapi-types": "^12.1.3"
14
14
  },
15
15
  "peerDependencies": {