UNPKG

@ublitzjs/openapi

Version:

![ublitzjs](https://github.com/ublitzjs/core/blob/main/logo.png)

104 lines (102 loc) 3.63 kB
import { OpenApiBuilder } from "openapi3-ts/oas31"; import { DeclarativeResponse, registerAbort, seeOtherMethods, } from "@ublitzjs/core"; import { basicSendFile, sendFile } from "@ublitzjs/static"; import { staticServe, analyzeFolder } from "@ublitzjs/static/serving"; import { exit } from "node:process"; import { createWriteStream, write } from "node:fs"; import path from "node:path"; import { stat } from "node:fs/promises"; var serverExtension = (opts) => ({ openApiBuilder: new OpenApiBuilder(opts), async serveOpenApi(prefix, opts = {}) { var specController; if (opts.path) { var length; if (opts.build) length = await this.buildOpenApi(opts.path, false); else length = (await stat(opts.path)).size; specController = async (res) => { registerAbort(res); await sendFile({ res, path: opts.path, contentType: "application/json", maxSize: length, }); }; } else { const spec = this.openApiBuilder.getSpecAsJson(); delete this.openApiBuilder; specController = new DeclarativeResponse() .writeHeaders({ "Content-Type": "application/json" }) .end(spec); } var HERE = opts.uiPath || "node_modules/@ublitzjs/openapi/ui"; var paths = await analyzeFolder(HERE, { deleteMimesList: opts?.clearMimes, }); const methods = staticServe({ paths, fullRoute: prefix, dirPath: HERE, }); this.get(prefix + "/*", methods.get) .head(prefix + "/*", methods.head) .any(prefix + "/*", methods.any) .get(prefix + "/openapi.json", specController) .get( prefix + "/swagger-initializer.js", new DeclarativeResponse() .writeHeader("Content-Type", "text/javascript") .end( `window.onload = async function(){window.ui=SwaggerUIBundle({url:"${prefix}/openapi.json",dom_id:"#swagger-ui",deepLinking:true,presets:[SwaggerUIBundle.presets.apis,SwaggerUIStandalonePreset],plugins:[SwaggerUIBundle.plugins.DownloadUrl],layout:"StandaloneLayout"})}` ) ); }, async buildOpenApi(filePath, exitFromNodejs) { var spec = this.openApiBuilder.getSpecAsJson(); delete this.openApiBuilder; var writeStream = createWriteStream(filePath); var offset = 0; var chunk = 64 * 1024 * 1024; while (spec[offset]) { var ok = writeStream.write(spec.slice(offset, (offset += chunk))); if (!ok) await new Promise((resolve) => writeStream.once("drain", resolve)); } return new Promise((resolve) => { writeStream.end(() => { if (exitFromNodejs) exit(0); resolve(spec.length); }); }); }, }); var toOpenapiPath = (v) => v.replace(/:([a-zA-Z0-9_]+)/g, "{$1}"); function RouterPlugin(methods) { var route = this.paths[this._currentPath]; var openApiPath = route?.openapi || {}; delete route?.openapi; for (const method of methods) { if (method === "connect" || method === "ws") continue; openApiPath[method === "del" ? "delete" : method] = route[method].openapi; delete route[method].openapi; } this.server.openApiBuilder.addPath( toOpenapiPath(this.prefixedPath), openApiPath ); } function routePlugin(route, server) { if (route.method === "connect" || route.method === "ws") throw new Error("these methods can't be documented with openapi"); var methodOpenapi = route.openapi || {}; delete route.openapi; server.openApiBuilder.addPath(toOpenapiPath(route.path), { [route.method]: methodOpenapi, }); } export { serverExtension, RouterPlugin, routePlugin };