UNPKG

@nahkies/typescript-koa-runtime

Version:

Runtime package for code generated by @nahkies/openapi-code-generator using the typescript-koa template

186 lines (185 loc) 6.45 kB
import { t as KoaRuntimeError } from "./errors-CrlMSPkU.mjs"; import Cors from "@koa/cors"; import getRawBody from "raw-body"; import Koa from "koa"; import { koaBody } from "koa-body"; //#region ../typescript-common-runtime/dist/esm/request-bodies/octet-stream.mjs async function parseOctetStreamRequestBody(req, opts) { const contentLength = opts.contentLength ?? (req.headers["content-length"] ? parseInt(req.headers["content-length"], 10) : void 0); if (!contentLength) throw new Error("No content length provided"); const body = await getRawBody(req, { length: contentLength, limit: opts.sizeLimit }); if (!body) return; if (!Buffer.isBuffer(body)) throw new Error("body must be a buffer"); return new Blob([new Uint8Array(body)], { type: "application/octet-stream" }); } //#endregion //#region ../typescript-common-runtime/dist/esm/types.mjs const SkipResponse = Symbol.for("skip response processing"); //#endregion //#region ../typescript-common-runtime/dist/esm/query-parser.mjs const separators = { deepObject: ",", form: ",", pipeDelimited: "|", spaceDelimited: " " }; function parseCsvPairsToObject(str, sep) { const split = str.split(sep); const result = {}; for (let i = 0; i < split.length; i += 2) { const key = split[i]; const value = split[i + 1]; if (key) result[key] = value; } return result; } function escapeStringForRegExp(str) { return str.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d"); } /** * Returns an ordered list of keys that match the provided key with array notation. E.g., * For key "foo" return ["foo[0]", "foo[1]", "foo[2]", ...] */ function extractArrayNotationKeys(key, keys) { const regex = new RegExp(`^${escapeStringForRegExp(key)}\\[[0-9]+]$`); return Array.from(keys).filter((it) => regex.test(it)).sort(); } function parseObjectQueryParameter(key, schema, encoding, query) { const type = schema.type; if (encoding.explode) if (encoding.style === "deepObject") { if (type === "object") { const result = {}; for (const [subKey, subSchema] of Object.entries(schema.properties)) if (subSchema.type === "object") result[subKey] = parseObjectQueryParameter(`${key}[${subKey}]`, subSchema, encoding, query); else result[subKey] = query.get(`${key}[${subKey}]`) ?? void 0; return result; } throw new Error(`[expected to be unreachable] parseObjectQueryParameter: unsupported parameter type: ${type} for explode: ${encoding.explode}, style: ${encoding.style}`); } else { if (type === "object") { const result = {}; for (const it of Object.keys(schema.properties)) result[it] = query.get(it) ?? void 0; return result; } throw new Error(`[expected to be unreachable] parseObjectQueryParameter: unsupported parameter type: ${type} for explode: ${encoding.explode}, style: ${encoding.style}`); } else if ([ "form", "spaceDelimited", "pipeDelimited" ].includes(encoding.style)) { const sep = separators[encoding.style]; return parseCsvPairsToObject(query.get(key) ?? "", sep); } else return JSON.parse(query.get(key) ?? "null"); } function parseArrayQueryParameter(key, _schema, encoding, query) { if (encoding.explode) { if (encoding.style === "deepObject") return extractArrayNotationKeys(key, query.keys()).map((it) => query.get(it) ?? void 0); return query.getAll(key); } else return query.get(key)?.split(separators[encoding.style]); } function parsePrimitiveQueryParameter(key, query) { return query.get(key) ?? void 0; } function parseQueryParameter({ name, schema, explode, style }, query) { const encoding = { style: style ?? "form", explode: explode ?? true }; const type = schema.type; switch (type) { case "object": return parseObjectQueryParameter(name, schema, encoding, query); case "array": return parseArrayQueryParameter(name, schema, encoding, query); case "string": case "number": case "boolean": case "null": return parsePrimitiveQueryParameter(name, query); default: throw new Error(`unsupported parameter type: ${type}`); } } function parseQueryParameters(rawQuery, parameters) { const query = new URLSearchParams(rawQuery); const result = {}; for (const parameter of parameters) result[parameter.name] = parseQueryParameter(parameter, query); return result; } //#endregion //#region src/server.ts var KoaRuntimeResponse = class { status; _body; constructor(status) { this.status = status; } body(body) { this._body = body; return this; } unpack() { return { status: this.status, body: this._body }; } }; function handleResponse(ctx, validator) { return async (response) => { if (response === SkipResponse) return; const { status, body } = response instanceof KoaRuntimeResponse ? response.unpack() : response; ctx.body = validator(status, body); ctx.status = status; }; } function handleImplementationError(err) { throw KoaRuntimeError.HandlerError(err); } async function parseOctetStream(ctx, sizeLimit) { const body = await parseOctetStreamRequestBody(ctx.req, { sizeLimit }); ctx.body = body; return body; } /** * Starts a Koa server and listens on `port` or a randomly allocated port if none provided. * Enables CORS and body parsing by default. It's recommended to customize the CORS options * for production usage. * * If you need more control over your Koa server, you should avoid calling this function * and instead mount the router from your generated codes `createRouter` call directly * onto a server you have constructed. */ async function startServer({ middleware = [], cors = void 0, body = void 0, port = 0, router }) { const app = new Koa(); if (cors !== "disabled") app.use(Cors(cors)); if (body !== "disabled") app.use(koaBody(body)); for (const it of middleware) app.use(it); app.use(router.routes()); app.use(router.allowedMethods()); return new Promise((resolve, reject) => { try { const server = app.listen(port); server.once("listening", () => { try { const address = server.address(); if (!address || typeof address !== "object") throw new Error("failed to bind port"); resolve({ app, server, address }); } catch (err) { reject(err); } }); server.once("error", (err) => { reject(err); }); } catch (err) { reject(err); } }); } //#endregion export { KoaRuntimeResponse, SkipResponse, handleImplementationError, handleResponse, parseOctetStream, parseQueryParameters, startServer }; //# sourceMappingURL=server.mjs.map