summaryrefslogtreecommitdiff
path: root/src/hero.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'src/hero.mjs')
-rw-r--r--src/hero.mjs208
1 files changed, 104 insertions, 104 deletions
diff --git a/src/hero.mjs b/src/hero.mjs
index 2355bbf..9c6df64 100644
--- a/src/hero.mjs
+++ b/src/hero.mjs
@@ -9,6 +9,110 @@ import util from "node:util";
import * as u from "./utils.mjs";
+export const loggerDefaults = {
+ pid: process.pid,
+ ppid: process.ppid,
+ tool: "hero",
+};
+
+export let loggerGlobals = {};
+
+export const configLogger = o => loggerGlobals = o;
+
+export const logit = (writerFn, level, o) =>
+ writerFn(JSON.stringify({
+ ...loggerDefaults,
+ ...loggerGlobals,
+ level,
+ ...o,
+ }));
+
+export const makeLogger = (writerFn = console.error) => ({
+ debug: (...args) => process.env.DEBUG ?
+ logit(writerFn, "DEBUG", ...args) :
+ null,
+ info: u.partial(logit, writerFn, "INFO"),
+ warn: u.partial(logit, writerFn, "WARN"),
+ error: u.partial(logit, writerFn, "ERROR"),
+});
+
+export const log = makeLogger();
+
+export const interceptorsFn = ({
+ uuidFn = crypto.randomUUID,
+ logger = log,
+} = {}) => ({
+ requestId: (req, next) => next({ ...req, id: uuidFn() }),
+ logged: async (req, next) => {
+ const { id, url, method } = req;
+ logger.info({
+ id,
+ url,
+ method,
+ type: "in-request",
+ });
+ const response = await next(req);
+ const { status } = response;
+ logger.info({
+ id,
+ status,
+ type: "in-response",
+ });
+ return response;
+ },
+ contentType: async (req, next) => {
+ const response = await next(req);
+ const [mimeType, body] = typeof response.body === "string" ?
+ ["text/html", response.body] :
+ ["application/json", JSON.stringify(response.body) || ""];
+ return {
+ ...response,
+ body,
+ headers: {
+ "Content-Type": mimeType,
+ "Content-Length": Buffer.byteLength(body),
+ ...(response.headers || {})
+ },
+ };
+ },
+ serverError: async (req, next) => {
+ try {
+ const response = await next(req);
+ assert.ok("status" in response, `Missing "status"`);
+ return response;
+ } catch (error) {
+ logger.error({
+ id: req.id,
+ type: "server-error-interceptor",
+ message: error.message,
+ });
+ return {
+ status: 500,
+ body: "Internal Server Error\n",
+ };
+ }
+ },
+});
+
+export const interceptors = interceptorsFn();
+
+export const defaultInterceptors = [
+ interceptors.serverError,
+ interceptors.contentType,
+ interceptors.requestId,
+ interceptors.logged,
+];
+
+export const chainInterceptors = arr =>
+ req => arr.length === 0 ?
+ req :
+ arr[0](req, chainInterceptors(arr.slice(1)));
+
+export const wrapHandler = (fn, arr) =>
+ arr.length === 0 ?
+ fn :
+ chainInterceptors(arr.concat([ (req, _next) => fn(req) ]));
+
export const normalizeSegments = segments =>
segments.length === 1 && segments[0] === "" ?
segments :
@@ -155,110 +259,6 @@ export const makeRequestListener = table => async (req, res) => {
res.end(response.body);
};
-export const loggerDefaults = {
- pid: process.pid,
- ppid: process.ppid,
- tool: "hero",
-};
-
-export let loggerGlobals = {};
-
-export const configLogger = o => loggerGlobals = o;
-
-export const logit = (writerFn, level, o) =>
- writerFn(JSON.stringify({
- ...loggerDefaults,
- ...loggerGlobals,
- level,
- ...o,
- }));
-
-export const makeLogger = (writerFn = console.error) => ({
- debug: (...args) => process.env.DEBUG ?
- logit(writerFn, "DEBUG", ...args) :
- null,
- info: u.partial(logit, writerFn, "INFO"),
- warn: u.partial(logit, writerFn, "WARN"),
- error: u.partial(logit, writerFn, "ERROR"),
-});
-
-export const log = makeLogger();
-
-export const interceptorsFn = ({
- uuidFn = crypto.randomUUID,
- logger = log,
-} = {}) => ({
- requestId: (req, next) => next({ ...req, id: uuidFn() }),
- logged: async (req, next) => {
- const { id, url, method } = req;
- logger.info({
- id,
- url,
- method,
- type: "in-request",
- });
- const response = await next(req);
- const { status } = response;
- logger.info({
- id,
- status,
- type: "in-response",
- });
- return response;
- },
- contentType: async (req, next) => {
- const response = await next(req);
- const [mimeType, body] = typeof response.body === "string" ?
- ["text/html", response.body] :
- ["application/json", JSON.stringify(response.body) || ""];
- return {
- ...response,
- body,
- headers: {
- "Content-Type": mimeType,
- "Content-Length": Buffer.byteLength(body),
- ...(response.headers || {})
- },
- };
- },
- serverError: async (req, next) => {
- try {
- const response = await next(req);
- assert.ok("status" in response, `Missing "status"`);
- return response;
- } catch (error) {
- logger.error({
- id: req.id,
- type: "server-error-interceptor",
- message: error.message,
- });
- return {
- status: 500,
- body: "Internal Server Error\n",
- };
- }
- },
-});
-
-export const interceptors = interceptorsFn();
-
-export const defaultInterceptors = [
- interceptors.serverError,
- interceptors.contentType,
- interceptors.requestId,
- interceptors.logged,
-];
-
-export const chainInterceptors = arr =>
- req => arr.length === 0 ?
- req :
- arr[0](req, chainInterceptors(arr.slice(1)));
-
-export const wrapHandler = (fn, arr) =>
- arr.length === 0 ?
- fn :
- chainInterceptors(arr.concat([ (req, _next) => fn(req) ]));
-
export const actionsFn = ({
logger = log,
} = {}) => ({