UNPKG

apitally

Version:

Simple API monitoring & analytics for REST APIs built with Express, Fastify, NestJS, AdonisJS, Hono, H3, Elysia, Hapi, and Koa.

192 lines 6.25 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); import { AsyncLocalStorage } from "node:async_hooks"; import { ApitallyClient } from "../common/client.js"; import { consumerFromStringOrObject } from "../common/consumerRegistry.js"; import { getPackageVersion } from "../common/packageVersions.js"; import { convertBody, convertHeaders } from "../common/requestLogger.js"; import { patchConsole, patchWinston } from "../loggers/index.js"; function useApitally(app, config) { const client = new ApitallyClient(config); const middleware = getMiddleware(client); app.use(middleware); const setStartupData = /* @__PURE__ */ __name((attempt = 1) => { const appInfo = getAppInfo(app, config.appVersion); if (appInfo.paths.length > 0 || attempt >= 10) { client.setStartupData(appInfo); client.startSync(); } else { setTimeout(() => setStartupData(attempt + 1), 500); } }, "setStartupData"); setTimeout(() => setStartupData(), 500); } __name(useApitally, "useApitally"); function getMiddleware(client) { const logsContext = new AsyncLocalStorage(); if (client.requestLogger.config.captureLogs) { patchConsole(logsContext); patchWinston(logsContext); } return async (ctx, next) => { if (!client.isEnabled() || ctx.request.method.toUpperCase() === "OPTIONS") { await next(); return; } await logsContext.run([], async () => { var _a; let path; let statusCode; let serverError; const startTime = performance.now(); try { await next(); } catch (error) { path = getPath(ctx); statusCode = error.statusCode || error.status || 500; if (path && statusCode === 500 && error instanceof Error) { serverError = error; client.serverErrorCounter.addServerError({ consumer: (_a = getConsumer(ctx)) == null ? void 0 : _a.identifier, method: ctx.request.method, path, type: error.name, msg: error.message, traceback: error.stack || "" }); } throw error; } finally { const responseTime = performance.now() - startTime; const consumer = getConsumer(ctx); client.consumerRegistry.addOrUpdateConsumer(consumer); if (!path) { path = getPath(ctx); } if (path) { try { client.requestCounter.addRequest({ consumer: consumer == null ? void 0 : consumer.identifier, method: ctx.request.method, path, statusCode: statusCode || ctx.response.status, responseTime, requestSize: ctx.request.length, responseSize: ctx.response.length }); } catch (error) { client.logger.error("Error while logging request in Apitally middleware.", { context: ctx, error }); } } if (client.requestLogger.enabled) { const logs = logsContext.getStore(); client.requestLogger.logRequest({ timestamp: Date.now() / 1e3, method: ctx.request.method, path, url: ctx.request.href, headers: convertHeaders(ctx.request.headers), size: ctx.request.length, consumer: consumer == null ? void 0 : consumer.identifier, body: convertBody(ctx.request.body, ctx.request.get("content-type")) }, { statusCode: statusCode || ctx.response.status, responseTime: responseTime / 1e3, headers: convertHeaders(ctx.response.headers), size: ctx.response.length, body: convertBody(ctx.response.body, ctx.response.get("content-type")) }, serverError, logs); } } }); }; } __name(getMiddleware, "getMiddleware"); function getPath(ctx) { return ctx._matchedRoute || ctx.routePath; } __name(getPath, "getPath"); function setConsumer(ctx, consumer) { ctx.state.apitallyConsumer = consumer || void 0; } __name(setConsumer, "setConsumer"); function getConsumer(ctx) { if (ctx.state.apitallyConsumer) { return consumerFromStringOrObject(ctx.state.apitallyConsumer); } else if (ctx.state.consumerIdentifier) { process.emitWarning("The consumerIdentifier property on the ctx.state object is deprecated. Use apitallyConsumer instead.", "DeprecationWarning"); return consumerFromStringOrObject(ctx.state.consumerIdentifier); } return null; } __name(getConsumer, "getConsumer"); function getAppInfo(app, appVersion) { const versions = [ [ "nodejs", process.version.replace(/^v/, "") ] ]; const koaVersion = getPackageVersion("koa"); const apitallyVersion = getPackageVersion("../.."); if (koaVersion) { versions.push([ "koa", koaVersion ]); } if (apitallyVersion) { versions.push([ "apitally", apitallyVersion ]); } if (appVersion) { versions.push([ "app", appVersion ]); } return { paths: listEndpoints(app), versions: Object.fromEntries(versions), client: "js:koa" }; } __name(getAppInfo, "getAppInfo"); function isKoaRouterMiddleware(middleware) { return typeof middleware === "function" && middleware.router && Array.isArray(middleware.router.stack); } __name(isKoaRouterMiddleware, "isKoaRouterMiddleware"); function listEndpoints(app) { const endpoints = []; app.middleware.forEach((middleware) => { if (isKoaRouterMiddleware(middleware)) { middleware.router.stack.forEach((layer) => { if (layer.methods && layer.methods.length > 0) { layer.methods.forEach((method) => { if (![ "HEAD", "OPTIONS" ].includes(method.toUpperCase())) { endpoints.push({ method: method.toUpperCase(), path: layer.path }); } }); } }); } }); return endpoints; } __name(listEndpoints, "listEndpoints"); export { setConsumer, useApitally }; //# sourceMappingURL=middleware.js.map