import { BaseResponse, Body, HttpStatusCodes, ITraceable, Metric, Optional, PenguenoRequest, ResponseOpts, ServerTrace, } from '@emprespresso/pengueno'; const getHeaders = (req: PenguenoRequest, extraHeaders: Record) => { const optHeaders = { ...req.getResponseHeaders(), ...extraHeaders, }; optHeaders['Content-Type'] = (optHeaders['Content-Type'] ?? 'text/plain') + '; charset=utf-8'; return optHeaders; }; const ResponseCodeMetrics = [0, 1, 2, 3, 4, 5].map((x) => Metric.fromName(`response.${x}xx`).asResult()); export const getResponseMetrics = (status: number, elapsedMs?: number) => { const index = Math.floor(status / 100); return ResponseCodeMetrics.flatMap((metric, i) => Optional.from(i) .filter((i) => i === index) .map(() => [metric.count.withValue(1.0)]) .flatMap((metricValues) => Optional.from(elapsedMs) .map((ms) => metricValues.concat(metric.time.withValue(ms))) .orSome(() => metricValues), ) .orSome(() => [metric.count.withValue(0.0)]) .get(), ); }; export class PenguenoResponse implements BaseResponse { public readonly statusText: string; public readonly status: number; public readonly headers: Record; constructor( req: ITraceable, private readonly _body: Body, opts: ResponseOpts, ) { this.headers = getHeaders(req.get(), opts?.headers ?? {}); this.status = opts.status; this.statusText = opts.statusText ?? HttpStatusCodes[this.status]!; req.trace.trace(getResponseMetrics(opts.status, req.get().elapsedTimeMs())); } public body() { return this._body; } }