summaryrefslogtreecommitdiff
path: root/u/server/response.ts
diff options
context:
space:
mode:
authorElizabeth Alexander Hunt <me@liz.coffee>2025-05-12 09:40:12 -0700
committerElizabeth <me@liz.coffee>2025-05-26 14:15:42 -0700
commitd51c9d74857aca3c2f172609297266968bc7f809 (patch)
tree64327f9cc4219729aa11af32d7d4c70cddfc2292 /u/server/response.ts
parent30729a0cf707d9022bae0a7baaba77379dc31fd5 (diff)
downloadci-d51c9d74857aca3c2f172609297266968bc7f809.tar.gz
ci-d51c9d74857aca3c2f172609297266968bc7f809.zip
The big refactor TM
Diffstat (limited to 'u/server/response.ts')
-rw-r--r--u/server/response.ts84
1 files changed, 84 insertions, 0 deletions
diff --git a/u/server/response.ts b/u/server/response.ts
new file mode 100644
index 0000000..c21819a
--- /dev/null
+++ b/u/server/response.ts
@@ -0,0 +1,84 @@
+import {
+ type IEither,
+ isEither,
+ type ITraceable,
+ Metric,
+ type PenguenoRequest,
+ type ServerTrace,
+} from "@emprespresso/pengueno";
+
+export type ResponseBody = object | string;
+export type TResponseInit = ResponseInit & {
+ status: number;
+ headers?: Record<string, string>;
+};
+
+const getResponse = (
+ req: PenguenoRequest,
+ opts: TResponseInit,
+): TResponseInit => {
+ return {
+ ...opts,
+ headers: {
+ ...(req.baseResponseHeaders()),
+ ...(opts?.headers),
+ "Content-Type": (opts?.headers?.["Content-Type"] ?? "text/plain") +
+ "; charset=utf-8",
+ },
+ };
+};
+
+const ResponseCodeMetrics = [1, 2, 3, 4, 5].map((x) =>
+ Metric.fromName(`response.${x}xx`)
+);
+export const getResponseMetric = (status: number) => {
+ const index = (Math.floor(status / 100)) + 1;
+ return ResponseCodeMetrics[index] ?? ResponseCodeMetrics[5 - 1];
+};
+
+export class PenguenoResponse extends Response {
+ constructor(
+ req: ITraceable<PenguenoRequest, ServerTrace>,
+ msg: BodyInit,
+ opts: TResponseInit,
+ ) {
+ const responseOpts = getResponse(req.get(), opts);
+ const resMetric = getResponseMetric(opts.status);
+ req.trace.trace(resMetric.count.withValue(1.0));
+ responseOpts.headers;
+ super(msg, responseOpts);
+ }
+}
+
+export class JsonResponse extends PenguenoResponse {
+ constructor(
+ req: ITraceable<PenguenoRequest, ServerTrace>,
+ e: BodyInit | IEither<ResponseBody, ResponseBody>,
+ opts: TResponseInit,
+ ) {
+ const optsWithJsonContentType = {
+ ...opts,
+ headers: {
+ ...opts?.headers,
+ "Content-Type": "application/json",
+ },
+ };
+ if (isEither<ResponseBody, ResponseBody>(e)) {
+ super(
+ req,
+ JSON.stringify(
+ e.fold((err, ok) => err ? ({ error: err! }) : ({ ok: ok! })),
+ ),
+ optsWithJsonContentType,
+ );
+ return;
+ }
+ super(
+ req,
+ JSON.stringify(
+ (Math.floor(opts.status / 100) < 4) ? { ok: e } : { error: e },
+ ),
+ optsWithJsonContentType,
+ );
+ }
+}