apitally 0.25.5 → 0.25.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/express/middleware.cjs +14 -2
- package/dist/express/middleware.cjs.map +1 -1
- package/dist/express/middleware.js +15 -3
- package/dist/express/middleware.js.map +1 -1
- package/dist/express/utils.cjs +40 -25
- package/dist/express/utils.cjs.map +1 -1
- package/dist/express/utils.d.cts +3 -1
- package/dist/express/utils.d.ts +3 -1
- package/dist/express/utils.js +37 -24
- package/dist/express/utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -191,14 +191,26 @@ function getRoutePath(req) {
|
|
|
191
191
|
if (!req.route) {
|
|
192
192
|
return;
|
|
193
193
|
}
|
|
194
|
+
let routePath = req.route.path;
|
|
195
|
+
if (Array.isArray(routePath)) {
|
|
196
|
+
routePath = routePath.find((p) => typeof p === "string") ?? routePath[0];
|
|
197
|
+
}
|
|
198
|
+
if (typeof routePath === "string") {
|
|
199
|
+
routePath = (0, import_utils.stripExpressPathParamRegex)(routePath);
|
|
200
|
+
} else if (routePath instanceof RegExp) {
|
|
201
|
+
routePath = (0, import_utils.formatRegExpRoutePath)(routePath);
|
|
202
|
+
}
|
|
203
|
+
if (typeof routePath !== "string") {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
194
206
|
if (req.baseUrl) {
|
|
195
207
|
const routerInfo = (0, import_utils.getRouterInfo)(req.app);
|
|
196
208
|
if (routerInfo.stack) {
|
|
197
209
|
const routerPath = getRouterPath(routerInfo.stack, req.baseUrl);
|
|
198
|
-
return
|
|
210
|
+
return routePath === "/" ? routerPath : routerPath + routePath;
|
|
199
211
|
}
|
|
200
212
|
}
|
|
201
|
-
return
|
|
213
|
+
return routePath;
|
|
202
214
|
}
|
|
203
215
|
__name(getRoutePath, "getRoutePath");
|
|
204
216
|
function getRouterPath(stack, baseUrl) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/express/middleware.ts"],"sourcesContent":["import type { Express, NextFunction, Request, Response, Router } from \"express\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertBody, convertHeaders } from \"../common/requestLogger.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n StartupData,\n ValidationError,\n} from \"../common/types.js\";\nimport {\n patchConsole,\n patchNestLogger,\n patchPinoLogger,\n patchWinston,\n} from \"../loggers/index.js\";\nimport {\n getEndpoints,\n getRouterInfo,\n parseExpressPath,\n parseExpressPathRegExp,\n} from \"./utils.js\";\n\ndeclare module \"express\" {\n interface Request {\n apitallyConsumer?: ApitallyConsumer | string | null;\n consumerIdentifier?: ApitallyConsumer | string | null; // For backwards compatibility\n }\n}\n\nexport function useApitally(\n app: Express | Router,\n config: ApitallyConfig & { basePath?: string },\n) {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(app, client);\n app.use(middleware);\n\n const setStartupData = (attempt: number = 1) => {\n const appInfo = getAppInfo(app, config.basePath, config.appVersion);\n if (appInfo.paths.length > 0 || attempt >= 10) {\n client.setStartupData(appInfo);\n client.startSync();\n } else {\n setTimeout(() => setStartupData(attempt + 1), 500);\n }\n };\n setTimeout(() => setStartupData(), 500);\n}\n\nfunction getMiddleware(app: Express | Router, client: ApitallyClient) {\n let errorHandlerConfigured = false;\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n patchNestLogger(logsContext);\n }\n\n return async (req: Request, res: Response, next: NextFunction) => {\n if (!client.isEnabled() || req.method.toUpperCase() === \"OPTIONS\") {\n next();\n return;\n }\n\n if (!errorHandlerConfigured) {\n // Add error handling middleware to the bottom of the stack when handling the first request\n app.use((err: Error, req: Request, res: Response, next: NextFunction) => {\n res.locals.serverError = err;\n next(err);\n });\n errorHandlerConfigured = true;\n }\n\n if (client.requestLogger.config.captureLogs && \"log\" in req) {\n await patchPinoLogger((req as any).log, logsContext);\n }\n\n logsContext.run([], () => {\n try {\n const startTime = performance.now();\n\n const originalSend = res.send;\n res.send = (body) => {\n const contentType = res.get(\"content-type\");\n if (client.requestLogger.isSupportedContentType(contentType)) {\n res.locals.body = body;\n }\n return originalSend.call(res, body);\n };\n\n const spanHandle = client.spanCollector.startSpan();\n spanHandle.runInContext(() => {\n res.once(\"finish\", () => {\n try {\n const responseTime = performance.now() - startTime;\n const path = getRoutePath(req);\n\n spanHandle.setName(`${req.method} ${path}`);\n const spans = spanHandle.end();\n const traceId = spanHandle.traceId;\n\n const consumer = getConsumer(req);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n const requestSize = parseContentLength(req.get(\"content-length\"));\n const responseSize = parseContentLength(\n res.get(\"content-length\"),\n );\n\n if (path) {\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: req.method,\n path,\n statusCode: res.statusCode,\n responseTime: responseTime,\n requestSize,\n responseSize,\n });\n\n if (\n (res.statusCode === 400 || res.statusCode === 422) &&\n res.locals.body\n ) {\n let jsonBody: any;\n try {\n jsonBody = JSON.parse(res.locals.body);\n } catch {\n // Ignore\n }\n if (jsonBody) {\n const validationErrors: ValidationError[] = [];\n if (validationErrors.length === 0) {\n validationErrors.push(\n ...extractExpressValidatorErrors(jsonBody),\n );\n }\n if (validationErrors.length === 0) {\n validationErrors.push(\n ...extractCelebrateErrors(jsonBody),\n );\n }\n if (validationErrors.length === 0) {\n validationErrors.push(\n ...extractNestValidationErrors(jsonBody),\n );\n }\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: req.method,\n path,\n ...error,\n });\n });\n }\n }\n\n if (res.statusCode === 500 && res.locals.serverError) {\n const serverError = res.locals.serverError as Error;\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: req.method,\n path,\n type: serverError.name,\n msg: serverError.message,\n traceback: serverError.stack || \"\",\n });\n }\n }\n\n if (client.requestLogger.enabled) {\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: Date.now() / 1000,\n method: req.method,\n path,\n url: `${req.protocol}://${req.host}${req.originalUrl}`,\n headers: convertHeaders(req.headers),\n size: requestSize,\n consumer: consumer?.identifier,\n body: convertBody(req.body, req.get(\"content-type\")),\n },\n {\n statusCode: res.statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(res.getHeaders()),\n size: responseSize,\n body: convertBody(res.locals.body, res.get(\"content-type\")),\n },\n res.locals.serverError,\n logs,\n spans,\n traceId,\n );\n }\n } catch (error) {\n client.logger.error(\n \"Error while logging request in Apitally middleware\",\n { request: req, response: res, error },\n );\n }\n });\n\n res.once(\"close\", () => {\n spanHandle.end();\n });\n\n next();\n });\n } catch (error) {\n client.logger.error(\"Error in Apitally middleware\", {\n request: req,\n response: res,\n error,\n });\n }\n });\n };\n}\n\nfunction getRoutePath(req: Request) {\n if (!req.route) {\n return;\n }\n if (req.baseUrl) {\n const routerInfo = getRouterInfo(req.app);\n if (routerInfo.stack) {\n const routerPath = getRouterPath(routerInfo.stack, req.baseUrl);\n return req.route.path === \"/\" ? routerPath : routerPath + req.route.path;\n }\n }\n return req.route.path;\n}\n\nfunction getRouterPath(stack: any[], baseUrl: string) {\n const routerPaths: string[] = [];\n while (stack && stack.length > 0) {\n const routerLayer = stack.find(\n (layer) =>\n layer.name === \"router\" &&\n layer.path &&\n (baseUrl.startsWith(layer.path) || layer.regexp?.test(baseUrl)),\n );\n if (routerLayer) {\n if (\n routerLayer.regexp &&\n routerLayer.keys &&\n routerLayer.keys.length > 0\n ) {\n const parsedPath = parseExpressPathRegExp(\n routerLayer.regexp,\n routerLayer.keys,\n );\n routerPaths.push(\"/\" + parsedPath);\n } else if (\n routerLayer.params &&\n Object.keys(routerLayer.params).length > 0\n ) {\n const parsedPath = parseExpressPath(\n routerLayer.path,\n routerLayer.params,\n );\n routerPaths.push(parsedPath);\n } else {\n routerPaths.push(routerLayer.path);\n }\n stack = routerLayer.handle?.stack;\n baseUrl = baseUrl.slice(routerLayer.path.length);\n } else {\n break;\n }\n }\n return routerPaths.filter((path) => path !== \"/\").join(\"\");\n}\n\nexport function setConsumer(\n req: Request,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n req.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(req: Request) {\n if (req.apitallyConsumer) {\n return consumerFromStringOrObject(req.apitallyConsumer);\n } else if (req.consumerIdentifier) {\n // For backwards compatibility\n process.emitWarning(\n \"The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.\",\n \"DeprecationWarning\",\n );\n return consumerFromStringOrObject(req.consumerIdentifier);\n }\n return null;\n}\n\nfunction extractExpressValidatorErrors(responseBody: any) {\n try {\n const errors: ValidationError[] = [];\n if (\n responseBody &&\n responseBody.errors &&\n Array.isArray(responseBody.errors)\n ) {\n responseBody.errors.forEach((error: any) => {\n if (error.location && error.path && error.msg && error.type) {\n errors.push({\n loc: `${error.location}.${error.path}`,\n msg: error.msg,\n type: error.type,\n });\n }\n });\n }\n return errors;\n } catch (error) {\n return [];\n }\n}\n\nfunction extractCelebrateErrors(responseBody: any) {\n try {\n const errors: ValidationError[] = [];\n if (responseBody && responseBody.validation) {\n Object.values(responseBody.validation).forEach((error: any) => {\n if (\n error.source &&\n error.keys &&\n Array.isArray(error.keys) &&\n error.message\n ) {\n error.keys.forEach((key: string) => {\n errors.push({\n loc: `${error.source}.${key}`,\n msg: subsetJoiMessage(error.message, key),\n type: \"\",\n });\n });\n }\n });\n }\n return errors;\n } catch (error) {\n return [];\n }\n}\n\nfunction extractNestValidationErrors(responseBody: any) {\n try {\n const errors: ValidationError[] = [];\n if (responseBody && Array.isArray(responseBody.message)) {\n responseBody.message.forEach((message: any) => {\n errors.push({\n loc: \"\",\n msg: message,\n type: \"\",\n });\n });\n }\n return errors;\n } catch (error) {\n return [];\n }\n}\n\nfunction subsetJoiMessage(message: string, key: string) {\n const messageWithKey = message\n .split(\". \")\n .find((message) => message.includes(`\"${key}\"`));\n return messageWithKey ? messageWithKey : message;\n}\n\nfunction getAppInfo(\n app: Express | Router,\n basePath?: string,\n appVersion?: string,\n): StartupData {\n const versions: Array<[string, string]> = [\n [\"nodejs\", process.version.replace(/^v/, \"\")],\n ];\n const expressVersion = getPackageVersion(\"express\");\n const nestjsVersion = getPackageVersion(\"@nestjs/core\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (expressVersion) {\n versions.push([\"express\", expressVersion]);\n }\n if (nestjsVersion) {\n versions.push([\"nestjs\", nestjsVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: getEndpoints(app, basePath || \"\"),\n versions: Object.fromEntries(versions),\n client: \"js:express\",\n };\n}\n"],"mappings":"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","names":["useApitally","app","config","client","ApitallyClient","middleware","getMiddleware","use","setStartupData","attempt","appInfo","getAppInfo","basePath","appVersion","paths","length","startSync","setTimeout","errorHandlerConfigured","logsContext","AsyncLocalStorage","requestLogger","captureLogs","patchConsole","patchWinston","patchNestLogger","req","res","next","isEnabled","method","toUpperCase","err","locals","serverError","patchPinoLogger","log","run","startTime","performance","now","originalSend","send","body","contentType","get","isSupportedContentType","call","spanHandle","spanCollector","startSpan","runInContext","once","responseTime","path","getRoutePath","setName","spans","end","traceId","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestSize","parseContentLength","responseSize","requestCounter","addRequest","identifier","statusCode","jsonBody","JSON","parse","validationErrors","push","extractExpressValidatorErrors","extractCelebrateErrors","extractNestValidationErrors","forEach","error","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","enabled","logs","getStore","logRequest","timestamp","Date","url","protocol","host","originalUrl","headers","convertHeaders","size","convertBody","getHeaders","logger","request","response","route","baseUrl","routerInfo","getRouterInfo","routerPath","getRouterPath","routerPaths","routerLayer","find","layer","_a","startsWith","regexp","test","keys","parsedPath","parseExpressPathRegExp","params","Object","parseExpressPath","handle","slice","filter","join","setConsumer","apitallyConsumer","undefined","consumerFromStringOrObject","consumerIdentifier","process","emitWarning","responseBody","errors","Array","isArray","location","loc","validation","values","source","key","subsetJoiMessage","messageWithKey","split","includes","versions","version","replace","expressVersion","getPackageVersion","nestjsVersion","apitallyVersion","getEndpoints","fromEntries"]}
|
|
1
|
+
{"version":3,"sources":["../../src/express/middleware.ts"],"sourcesContent":["import type { Express, NextFunction, Request, Response, Router } from \"express\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertBody, convertHeaders } from \"../common/requestLogger.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n StartupData,\n ValidationError,\n} from \"../common/types.js\";\nimport {\n patchConsole,\n patchNestLogger,\n patchPinoLogger,\n patchWinston,\n} from \"../loggers/index.js\";\nimport {\n formatRegExpRoutePath,\n getEndpoints,\n getRouterInfo,\n parseExpressPath,\n parseExpressPathRegExp,\n stripExpressPathParamRegex,\n} from \"./utils.js\";\n\ndeclare module \"express\" {\n interface Request {\n apitallyConsumer?: ApitallyConsumer | string | null;\n consumerIdentifier?: ApitallyConsumer | string | null; // For backwards compatibility\n }\n}\n\nexport function useApitally(\n app: Express | Router,\n config: ApitallyConfig & { basePath?: string },\n) {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(app, client);\n app.use(middleware);\n\n const setStartupData = (attempt: number = 1) => {\n const appInfo = getAppInfo(app, config.basePath, config.appVersion);\n if (appInfo.paths.length > 0 || attempt >= 10) {\n client.setStartupData(appInfo);\n client.startSync();\n } else {\n setTimeout(() => setStartupData(attempt + 1), 500);\n }\n };\n setTimeout(() => setStartupData(), 500);\n}\n\nfunction getMiddleware(app: Express | Router, client: ApitallyClient) {\n let errorHandlerConfigured = false;\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n patchNestLogger(logsContext);\n }\n\n return async (req: Request, res: Response, next: NextFunction) => {\n if (!client.isEnabled() || req.method.toUpperCase() === \"OPTIONS\") {\n next();\n return;\n }\n\n if (!errorHandlerConfigured) {\n // Add error handling middleware to the bottom of the stack when handling the first request\n app.use((err: Error, req: Request, res: Response, next: NextFunction) => {\n res.locals.serverError = err;\n next(err);\n });\n errorHandlerConfigured = true;\n }\n\n if (client.requestLogger.config.captureLogs && \"log\" in req) {\n await patchPinoLogger((req as any).log, logsContext);\n }\n\n logsContext.run([], () => {\n try {\n const startTime = performance.now();\n\n const originalSend = res.send;\n res.send = (body) => {\n const contentType = res.get(\"content-type\");\n if (client.requestLogger.isSupportedContentType(contentType)) {\n res.locals.body = body;\n }\n return originalSend.call(res, body);\n };\n\n const spanHandle = client.spanCollector.startSpan();\n spanHandle.runInContext(() => {\n res.once(\"finish\", () => {\n try {\n const responseTime = performance.now() - startTime;\n const path = getRoutePath(req);\n\n spanHandle.setName(`${req.method} ${path}`);\n const spans = spanHandle.end();\n const traceId = spanHandle.traceId;\n\n const consumer = getConsumer(req);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n const requestSize = parseContentLength(req.get(\"content-length\"));\n const responseSize = parseContentLength(\n res.get(\"content-length\"),\n );\n\n if (path) {\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: req.method,\n path,\n statusCode: res.statusCode,\n responseTime: responseTime,\n requestSize,\n responseSize,\n });\n\n if (\n (res.statusCode === 400 || res.statusCode === 422) &&\n res.locals.body\n ) {\n let jsonBody: any;\n try {\n jsonBody = JSON.parse(res.locals.body);\n } catch {\n // Ignore\n }\n if (jsonBody) {\n const validationErrors: ValidationError[] = [];\n if (validationErrors.length === 0) {\n validationErrors.push(\n ...extractExpressValidatorErrors(jsonBody),\n );\n }\n if (validationErrors.length === 0) {\n validationErrors.push(\n ...extractCelebrateErrors(jsonBody),\n );\n }\n if (validationErrors.length === 0) {\n validationErrors.push(\n ...extractNestValidationErrors(jsonBody),\n );\n }\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: req.method,\n path,\n ...error,\n });\n });\n }\n }\n\n if (res.statusCode === 500 && res.locals.serverError) {\n const serverError = res.locals.serverError as Error;\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: req.method,\n path,\n type: serverError.name,\n msg: serverError.message,\n traceback: serverError.stack || \"\",\n });\n }\n }\n\n if (client.requestLogger.enabled) {\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: Date.now() / 1000,\n method: req.method,\n path,\n url: `${req.protocol}://${req.host}${req.originalUrl}`,\n headers: convertHeaders(req.headers),\n size: requestSize,\n consumer: consumer?.identifier,\n body: convertBody(req.body, req.get(\"content-type\")),\n },\n {\n statusCode: res.statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(res.getHeaders()),\n size: responseSize,\n body: convertBody(res.locals.body, res.get(\"content-type\")),\n },\n res.locals.serverError,\n logs,\n spans,\n traceId,\n );\n }\n } catch (error) {\n client.logger.error(\n \"Error while logging request in Apitally middleware\",\n { request: req, response: res, error },\n );\n }\n });\n\n res.once(\"close\", () => {\n spanHandle.end();\n });\n\n next();\n });\n } catch (error) {\n client.logger.error(\"Error in Apitally middleware\", {\n request: req,\n response: res,\n error,\n });\n }\n });\n };\n}\n\nfunction getRoutePath(req: Request) {\n if (!req.route) {\n return;\n }\n // req.route.path can be a string, a RegExp, or an array of either\n let routePath: unknown = req.route.path;\n if (Array.isArray(routePath)) {\n routePath = routePath.find((p) => typeof p === \"string\") ?? routePath[0];\n }\n if (typeof routePath === \"string\") {\n routePath = stripExpressPathParamRegex(routePath);\n } else if (routePath instanceof RegExp) {\n routePath = formatRegExpRoutePath(routePath);\n }\n if (typeof routePath !== \"string\") {\n return;\n }\n if (req.baseUrl) {\n const routerInfo = getRouterInfo(req.app);\n if (routerInfo.stack) {\n const routerPath = getRouterPath(routerInfo.stack, req.baseUrl);\n return routePath === \"/\" ? routerPath : routerPath + routePath;\n }\n }\n return routePath;\n}\n\nfunction getRouterPath(stack: any[], baseUrl: string) {\n const routerPaths: string[] = [];\n while (stack && stack.length > 0) {\n const routerLayer = stack.find(\n (layer) =>\n layer.name === \"router\" &&\n layer.path &&\n (baseUrl.startsWith(layer.path) || layer.regexp?.test(baseUrl)),\n );\n if (routerLayer) {\n if (\n routerLayer.regexp &&\n routerLayer.keys &&\n routerLayer.keys.length > 0\n ) {\n const parsedPath = parseExpressPathRegExp(\n routerLayer.regexp,\n routerLayer.keys,\n );\n routerPaths.push(\"/\" + parsedPath);\n } else if (\n routerLayer.params &&\n Object.keys(routerLayer.params).length > 0\n ) {\n const parsedPath = parseExpressPath(\n routerLayer.path,\n routerLayer.params,\n );\n routerPaths.push(parsedPath);\n } else {\n routerPaths.push(routerLayer.path);\n }\n stack = routerLayer.handle?.stack;\n baseUrl = baseUrl.slice(routerLayer.path.length);\n } else {\n break;\n }\n }\n return routerPaths.filter((path) => path !== \"/\").join(\"\");\n}\n\nexport function setConsumer(\n req: Request,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n req.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(req: Request) {\n if (req.apitallyConsumer) {\n return consumerFromStringOrObject(req.apitallyConsumer);\n } else if (req.consumerIdentifier) {\n // For backwards compatibility\n process.emitWarning(\n \"The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.\",\n \"DeprecationWarning\",\n );\n return consumerFromStringOrObject(req.consumerIdentifier);\n }\n return null;\n}\n\nfunction extractExpressValidatorErrors(responseBody: any) {\n try {\n const errors: ValidationError[] = [];\n if (\n responseBody &&\n responseBody.errors &&\n Array.isArray(responseBody.errors)\n ) {\n responseBody.errors.forEach((error: any) => {\n if (error.location && error.path && error.msg && error.type) {\n errors.push({\n loc: `${error.location}.${error.path}`,\n msg: error.msg,\n type: error.type,\n });\n }\n });\n }\n return errors;\n } catch (error) {\n return [];\n }\n}\n\nfunction extractCelebrateErrors(responseBody: any) {\n try {\n const errors: ValidationError[] = [];\n if (responseBody && responseBody.validation) {\n Object.values(responseBody.validation).forEach((error: any) => {\n if (\n error.source &&\n error.keys &&\n Array.isArray(error.keys) &&\n error.message\n ) {\n error.keys.forEach((key: string) => {\n errors.push({\n loc: `${error.source}.${key}`,\n msg: subsetJoiMessage(error.message, key),\n type: \"\",\n });\n });\n }\n });\n }\n return errors;\n } catch (error) {\n return [];\n }\n}\n\nfunction extractNestValidationErrors(responseBody: any) {\n try {\n const errors: ValidationError[] = [];\n if (responseBody && Array.isArray(responseBody.message)) {\n responseBody.message.forEach((message: any) => {\n errors.push({\n loc: \"\",\n msg: message,\n type: \"\",\n });\n });\n }\n return errors;\n } catch (error) {\n return [];\n }\n}\n\nfunction subsetJoiMessage(message: string, key: string) {\n const messageWithKey = message\n .split(\". \")\n .find((message) => message.includes(`\"${key}\"`));\n return messageWithKey ? messageWithKey : message;\n}\n\nfunction getAppInfo(\n app: Express | Router,\n basePath?: string,\n appVersion?: string,\n): StartupData {\n const versions: Array<[string, string]> = [\n [\"nodejs\", process.version.replace(/^v/, \"\")],\n ];\n const expressVersion = getPackageVersion(\"express\");\n const nestjsVersion = getPackageVersion(\"@nestjs/core\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (expressVersion) {\n versions.push([\"express\", expressVersion]);\n }\n if (nestjsVersion) {\n versions.push([\"nestjs\", nestjsVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: getEndpoints(app, basePath || \"\"),\n versions: Object.fromEntries(versions),\n client: \"js:express\",\n };\n}\n"],"mappings":"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","names":["useApitally","app","config","client","ApitallyClient","middleware","getMiddleware","use","setStartupData","attempt","appInfo","getAppInfo","basePath","appVersion","paths","length","startSync","setTimeout","errorHandlerConfigured","logsContext","AsyncLocalStorage","requestLogger","captureLogs","patchConsole","patchWinston","patchNestLogger","req","res","next","isEnabled","method","toUpperCase","err","locals","serverError","patchPinoLogger","log","run","startTime","performance","now","originalSend","send","body","contentType","get","isSupportedContentType","call","spanHandle","spanCollector","startSpan","runInContext","once","responseTime","path","getRoutePath","setName","spans","end","traceId","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestSize","parseContentLength","responseSize","requestCounter","addRequest","identifier","statusCode","jsonBody","JSON","parse","validationErrors","push","extractExpressValidatorErrors","extractCelebrateErrors","extractNestValidationErrors","forEach","error","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","enabled","logs","getStore","logRequest","timestamp","Date","url","protocol","host","originalUrl","headers","convertHeaders","size","convertBody","getHeaders","logger","request","response","route","routePath","Array","isArray","find","p","stripExpressPathParamRegex","RegExp","formatRegExpRoutePath","baseUrl","routerInfo","getRouterInfo","routerPath","getRouterPath","routerPaths","routerLayer","layer","_a","startsWith","regexp","test","keys","parsedPath","parseExpressPathRegExp","params","Object","parseExpressPath","handle","slice","filter","join","setConsumer","apitallyConsumer","undefined","consumerFromStringOrObject","consumerIdentifier","process","emitWarning","responseBody","errors","location","loc","validation","values","source","key","subsetJoiMessage","messageWithKey","split","includes","versions","version","replace","expressVersion","getPackageVersion","nestjsVersion","apitallyVersion","getEndpoints","fromEntries"]}
|
|
@@ -8,7 +8,7 @@ import { parseContentLength } from "../common/headers.js";
|
|
|
8
8
|
import { getPackageVersion } from "../common/packageVersions.js";
|
|
9
9
|
import { convertBody, convertHeaders } from "../common/requestLogger.js";
|
|
10
10
|
import { patchConsole, patchNestLogger, patchPinoLogger, patchWinston } from "../loggers/index.js";
|
|
11
|
-
import { getEndpoints, getRouterInfo, parseExpressPath, parseExpressPathRegExp } from "./utils.js";
|
|
11
|
+
import { formatRegExpRoutePath, getEndpoints, getRouterInfo, parseExpressPath, parseExpressPathRegExp, stripExpressPathParamRegex } from "./utils.js";
|
|
12
12
|
function useApitally(app, config) {
|
|
13
13
|
const client = new ApitallyClient(config);
|
|
14
14
|
const middleware = getMiddleware(app, client);
|
|
@@ -168,14 +168,26 @@ function getRoutePath(req) {
|
|
|
168
168
|
if (!req.route) {
|
|
169
169
|
return;
|
|
170
170
|
}
|
|
171
|
+
let routePath = req.route.path;
|
|
172
|
+
if (Array.isArray(routePath)) {
|
|
173
|
+
routePath = routePath.find((p) => typeof p === "string") ?? routePath[0];
|
|
174
|
+
}
|
|
175
|
+
if (typeof routePath === "string") {
|
|
176
|
+
routePath = stripExpressPathParamRegex(routePath);
|
|
177
|
+
} else if (routePath instanceof RegExp) {
|
|
178
|
+
routePath = formatRegExpRoutePath(routePath);
|
|
179
|
+
}
|
|
180
|
+
if (typeof routePath !== "string") {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
171
183
|
if (req.baseUrl) {
|
|
172
184
|
const routerInfo = getRouterInfo(req.app);
|
|
173
185
|
if (routerInfo.stack) {
|
|
174
186
|
const routerPath = getRouterPath(routerInfo.stack, req.baseUrl);
|
|
175
|
-
return
|
|
187
|
+
return routePath === "/" ? routerPath : routerPath + routePath;
|
|
176
188
|
}
|
|
177
189
|
}
|
|
178
|
-
return
|
|
190
|
+
return routePath;
|
|
179
191
|
}
|
|
180
192
|
__name(getRoutePath, "getRoutePath");
|
|
181
193
|
function getRouterPath(stack, baseUrl) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/express/middleware.ts"],"sourcesContent":["import type { Express, NextFunction, Request, Response, Router } from \"express\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertBody, convertHeaders } from \"../common/requestLogger.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n StartupData,\n ValidationError,\n} from \"../common/types.js\";\nimport {\n patchConsole,\n patchNestLogger,\n patchPinoLogger,\n patchWinston,\n} from \"../loggers/index.js\";\nimport {\n getEndpoints,\n getRouterInfo,\n parseExpressPath,\n parseExpressPathRegExp,\n} from \"./utils.js\";\n\ndeclare module \"express\" {\n interface Request {\n apitallyConsumer?: ApitallyConsumer | string | null;\n consumerIdentifier?: ApitallyConsumer | string | null; // For backwards compatibility\n }\n}\n\nexport function useApitally(\n app: Express | Router,\n config: ApitallyConfig & { basePath?: string },\n) {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(app, client);\n app.use(middleware);\n\n const setStartupData = (attempt: number = 1) => {\n const appInfo = getAppInfo(app, config.basePath, config.appVersion);\n if (appInfo.paths.length > 0 || attempt >= 10) {\n client.setStartupData(appInfo);\n client.startSync();\n } else {\n setTimeout(() => setStartupData(attempt + 1), 500);\n }\n };\n setTimeout(() => setStartupData(), 500);\n}\n\nfunction getMiddleware(app: Express | Router, client: ApitallyClient) {\n let errorHandlerConfigured = false;\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n patchNestLogger(logsContext);\n }\n\n return async (req: Request, res: Response, next: NextFunction) => {\n if (!client.isEnabled() || req.method.toUpperCase() === \"OPTIONS\") {\n next();\n return;\n }\n\n if (!errorHandlerConfigured) {\n // Add error handling middleware to the bottom of the stack when handling the first request\n app.use((err: Error, req: Request, res: Response, next: NextFunction) => {\n res.locals.serverError = err;\n next(err);\n });\n errorHandlerConfigured = true;\n }\n\n if (client.requestLogger.config.captureLogs && \"log\" in req) {\n await patchPinoLogger((req as any).log, logsContext);\n }\n\n logsContext.run([], () => {\n try {\n const startTime = performance.now();\n\n const originalSend = res.send;\n res.send = (body) => {\n const contentType = res.get(\"content-type\");\n if (client.requestLogger.isSupportedContentType(contentType)) {\n res.locals.body = body;\n }\n return originalSend.call(res, body);\n };\n\n const spanHandle = client.spanCollector.startSpan();\n spanHandle.runInContext(() => {\n res.once(\"finish\", () => {\n try {\n const responseTime = performance.now() - startTime;\n const path = getRoutePath(req);\n\n spanHandle.setName(`${req.method} ${path}`);\n const spans = spanHandle.end();\n const traceId = spanHandle.traceId;\n\n const consumer = getConsumer(req);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n const requestSize = parseContentLength(req.get(\"content-length\"));\n const responseSize = parseContentLength(\n res.get(\"content-length\"),\n );\n\n if (path) {\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: req.method,\n path,\n statusCode: res.statusCode,\n responseTime: responseTime,\n requestSize,\n responseSize,\n });\n\n if (\n (res.statusCode === 400 || res.statusCode === 422) &&\n res.locals.body\n ) {\n let jsonBody: any;\n try {\n jsonBody = JSON.parse(res.locals.body);\n } catch {\n // Ignore\n }\n if (jsonBody) {\n const validationErrors: ValidationError[] = [];\n if (validationErrors.length === 0) {\n validationErrors.push(\n ...extractExpressValidatorErrors(jsonBody),\n );\n }\n if (validationErrors.length === 0) {\n validationErrors.push(\n ...extractCelebrateErrors(jsonBody),\n );\n }\n if (validationErrors.length === 0) {\n validationErrors.push(\n ...extractNestValidationErrors(jsonBody),\n );\n }\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: req.method,\n path,\n ...error,\n });\n });\n }\n }\n\n if (res.statusCode === 500 && res.locals.serverError) {\n const serverError = res.locals.serverError as Error;\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: req.method,\n path,\n type: serverError.name,\n msg: serverError.message,\n traceback: serverError.stack || \"\",\n });\n }\n }\n\n if (client.requestLogger.enabled) {\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: Date.now() / 1000,\n method: req.method,\n path,\n url: `${req.protocol}://${req.host}${req.originalUrl}`,\n headers: convertHeaders(req.headers),\n size: requestSize,\n consumer: consumer?.identifier,\n body: convertBody(req.body, req.get(\"content-type\")),\n },\n {\n statusCode: res.statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(res.getHeaders()),\n size: responseSize,\n body: convertBody(res.locals.body, res.get(\"content-type\")),\n },\n res.locals.serverError,\n logs,\n spans,\n traceId,\n );\n }\n } catch (error) {\n client.logger.error(\n \"Error while logging request in Apitally middleware\",\n { request: req, response: res, error },\n );\n }\n });\n\n res.once(\"close\", () => {\n spanHandle.end();\n });\n\n next();\n });\n } catch (error) {\n client.logger.error(\"Error in Apitally middleware\", {\n request: req,\n response: res,\n error,\n });\n }\n });\n };\n}\n\nfunction getRoutePath(req: Request) {\n if (!req.route) {\n return;\n }\n if (req.baseUrl) {\n const routerInfo = getRouterInfo(req.app);\n if (routerInfo.stack) {\n const routerPath = getRouterPath(routerInfo.stack, req.baseUrl);\n return req.route.path === \"/\" ? routerPath : routerPath + req.route.path;\n }\n }\n return req.route.path;\n}\n\nfunction getRouterPath(stack: any[], baseUrl: string) {\n const routerPaths: string[] = [];\n while (stack && stack.length > 0) {\n const routerLayer = stack.find(\n (layer) =>\n layer.name === \"router\" &&\n layer.path &&\n (baseUrl.startsWith(layer.path) || layer.regexp?.test(baseUrl)),\n );\n if (routerLayer) {\n if (\n routerLayer.regexp &&\n routerLayer.keys &&\n routerLayer.keys.length > 0\n ) {\n const parsedPath = parseExpressPathRegExp(\n routerLayer.regexp,\n routerLayer.keys,\n );\n routerPaths.push(\"/\" + parsedPath);\n } else if (\n routerLayer.params &&\n Object.keys(routerLayer.params).length > 0\n ) {\n const parsedPath = parseExpressPath(\n routerLayer.path,\n routerLayer.params,\n );\n routerPaths.push(parsedPath);\n } else {\n routerPaths.push(routerLayer.path);\n }\n stack = routerLayer.handle?.stack;\n baseUrl = baseUrl.slice(routerLayer.path.length);\n } else {\n break;\n }\n }\n return routerPaths.filter((path) => path !== \"/\").join(\"\");\n}\n\nexport function setConsumer(\n req: Request,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n req.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(req: Request) {\n if (req.apitallyConsumer) {\n return consumerFromStringOrObject(req.apitallyConsumer);\n } else if (req.consumerIdentifier) {\n // For backwards compatibility\n process.emitWarning(\n \"The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.\",\n \"DeprecationWarning\",\n );\n return consumerFromStringOrObject(req.consumerIdentifier);\n }\n return null;\n}\n\nfunction extractExpressValidatorErrors(responseBody: any) {\n try {\n const errors: ValidationError[] = [];\n if (\n responseBody &&\n responseBody.errors &&\n Array.isArray(responseBody.errors)\n ) {\n responseBody.errors.forEach((error: any) => {\n if (error.location && error.path && error.msg && error.type) {\n errors.push({\n loc: `${error.location}.${error.path}`,\n msg: error.msg,\n type: error.type,\n });\n }\n });\n }\n return errors;\n } catch (error) {\n return [];\n }\n}\n\nfunction extractCelebrateErrors(responseBody: any) {\n try {\n const errors: ValidationError[] = [];\n if (responseBody && responseBody.validation) {\n Object.values(responseBody.validation).forEach((error: any) => {\n if (\n error.source &&\n error.keys &&\n Array.isArray(error.keys) &&\n error.message\n ) {\n error.keys.forEach((key: string) => {\n errors.push({\n loc: `${error.source}.${key}`,\n msg: subsetJoiMessage(error.message, key),\n type: \"\",\n });\n });\n }\n });\n }\n return errors;\n } catch (error) {\n return [];\n }\n}\n\nfunction extractNestValidationErrors(responseBody: any) {\n try {\n const errors: ValidationError[] = [];\n if (responseBody && Array.isArray(responseBody.message)) {\n responseBody.message.forEach((message: any) => {\n errors.push({\n loc: \"\",\n msg: message,\n type: \"\",\n });\n });\n }\n return errors;\n } catch (error) {\n return [];\n }\n}\n\nfunction subsetJoiMessage(message: string, key: string) {\n const messageWithKey = message\n .split(\". \")\n .find((message) => message.includes(`\"${key}\"`));\n return messageWithKey ? messageWithKey : message;\n}\n\nfunction getAppInfo(\n app: Express | Router,\n basePath?: string,\n appVersion?: string,\n): StartupData {\n const versions: Array<[string, string]> = [\n [\"nodejs\", process.version.replace(/^v/, \"\")],\n ];\n const expressVersion = getPackageVersion(\"express\");\n const nestjsVersion = getPackageVersion(\"@nestjs/core\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (expressVersion) {\n versions.push([\"express\", expressVersion]);\n }\n if (nestjsVersion) {\n versions.push([\"nestjs\", nestjsVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: getEndpoints(app, basePath || \"\"),\n versions: Object.fromEntries(versions),\n client: \"js:express\",\n };\n}\n"],"mappings":";;AACA,SAASA,yBAAyB;AAClC,SAASC,mBAAmB;AAE5B,SAASC,sBAAsB;AAC/B,SAASC,kCAAkC;AAC3C,SAASC,0BAA0B;AACnC,SAASC,yBAAyB;AAElC,SAASC,aAAaC,sBAAsB;AAO5C,SACEC,cACAC,iBACAC,iBACAC,oBACK;AACP,SACEC,cACAC,eACAC,kBACAC,8BACK;AASA,SAASC,YACdC,KACAC,QAA8C;AAE9C,QAAMC,SAAS,IAAIjB,eAAegB,MAAAA;AAClC,QAAME,aAAaC,cAAcJ,KAAKE,MAAAA;AACtCF,MAAIK,IAAIF,UAAAA;AAER,QAAMG,iBAAiB,wBAACC,UAAkB,MAAC;AACzC,UAAMC,UAAUC,WAAWT,KAAKC,OAAOS,UAAUT,OAAOU,UAAU;AAClE,QAAIH,QAAQI,MAAMC,SAAS,KAAKN,WAAW,IAAI;AAC7CL,aAAOI,eAAeE,OAAAA;AACtBN,aAAOY,UAAS;IAClB,OAAO;AACLC,iBAAW,MAAMT,eAAeC,UAAU,CAAA,GAAI,GAAA;IAChD;EACF,GARuB;AASvBQ,aAAW,MAAMT,eAAAA,GAAkB,GAAA;AACrC;AAlBgBP;AAoBhB,SAASK,cAAcJ,KAAuBE,QAAsB;AAClE,MAAIc,yBAAyB;AAC7B,QAAMC,cAAc,IAAIlC,kBAAAA;AAExB,MAAImB,OAAOgB,cAAcjB,OAAOkB,aAAa;AAC3C5B,iBAAa0B,WAAAA;AACbvB,iBAAauB,WAAAA;AACbzB,oBAAgByB,WAAAA;EAClB;AAEA,SAAO,OAAOG,KAAcC,KAAeC,SAAAA;AACzC,QAAI,CAACpB,OAAOqB,UAAS,KAAMH,IAAII,OAAOC,YAAW,MAAO,WAAW;AACjEH,WAAAA;AACA;IACF;AAEA,QAAI,CAACN,wBAAwB;AAE3BhB,UAAIK,IAAI,CAACqB,KAAYN,MAAcC,MAAeC,UAAAA;AAChDD,QAAAA,KAAIM,OAAOC,cAAcF;AACzBJ,QAAAA,MAAKI,GAAAA;MACP,CAAA;AACAV,+BAAyB;IAC3B;AAEA,QAAId,OAAOgB,cAAcjB,OAAOkB,eAAe,SAASC,KAAK;AAC3D,YAAM3B,gBAAiB2B,IAAYS,KAAKZ,WAAAA;IAC1C;AAEAA,gBAAYa,IAAI,CAAA,GAAI,MAAA;AAClB,UAAI;AACF,cAAMC,YAAY/C,YAAYgD,IAAG;AAEjC,cAAMC,eAAeZ,IAAIa;AACzBb,YAAIa,OAAO,CAACC,SAAAA;AACV,gBAAMC,cAAcf,IAAIgB,IAAI,cAAA;AAC5B,cAAInC,OAAOgB,cAAcoB,uBAAuBF,WAAAA,GAAc;AAC5Df,gBAAIM,OAAOQ,OAAOA;UACpB;AACA,iBAAOF,aAAaM,KAAKlB,KAAKc,IAAAA;QAChC;AAEA,cAAMK,aAAatC,OAAOuC,cAAcC,UAAS;AACjDF,mBAAWG,aAAa,MAAA;AACtBtB,cAAIuB,KAAK,UAAU,MAAA;AACjB,gBAAI;AACF,oBAAMC,eAAe7D,YAAYgD,IAAG,IAAKD;AACzC,oBAAMe,OAAOC,aAAa3B,GAAAA;AAE1BoB,yBAAWQ,QAAQ,GAAG5B,IAAII,MAAM,IAAIsB,IAAAA,EAAM;AAC1C,oBAAMG,QAAQT,WAAWU,IAAG;AAC5B,oBAAMC,UAAUX,WAAWW;AAE3B,oBAAMC,WAAWC,YAAYjC,GAAAA;AAC7BlB,qBAAOoD,iBAAiBC,oBAAoBH,QAAAA;AAE5C,oBAAMI,cAAcrE,mBAAmBiC,IAAIiB,IAAI,gBAAA,CAAA;AAC/C,oBAAMoB,eAAetE,mBACnBkC,IAAIgB,IAAI,gBAAA,CAAA;AAGV,kBAAIS,MAAM;AACR5C,uBAAOwD,eAAeC,WAAW;kBAC/BP,UAAUA,qCAAUQ;kBACpBpC,QAAQJ,IAAII;kBACZsB;kBACAe,YAAYxC,IAAIwC;kBAChBhB;kBACAW;kBACAC;gBACF,CAAA;AAEA,qBACGpC,IAAIwC,eAAe,OAAOxC,IAAIwC,eAAe,QAC9CxC,IAAIM,OAAOQ,MACX;AACA,sBAAI2B;AACJ,sBAAI;AACFA,+BAAWC,KAAKC,MAAM3C,IAAIM,OAAOQ,IAAI;kBACvC,QAAQ;kBAER;AACA,sBAAI2B,UAAU;AACZ,0BAAMG,mBAAsC,CAAA;AAC5C,wBAAIA,iBAAiBpD,WAAW,GAAG;AACjCoD,uCAAiBC,KAAI,GAChBC,8BAA8BL,QAAAA,CAAAA;oBAErC;AACA,wBAAIG,iBAAiBpD,WAAW,GAAG;AACjCoD,uCAAiBC,KAAI,GAChBE,uBAAuBN,QAAAA,CAAAA;oBAE9B;AACA,wBAAIG,iBAAiBpD,WAAW,GAAG;AACjCoD,uCAAiBC,KAAI,GAChBG,4BAA4BP,QAAAA,CAAAA;oBAEnC;AACAG,qCAAiBK,QAAQ,CAACC,UAAAA;AACxBrE,6BAAOsE,uBAAuBC,mBAAmB;wBAC/CrB,UAAUA,qCAAUQ;wBACpBpC,QAAQJ,IAAII;wBACZsB;wBACA,GAAGyB;sBACL,CAAA;oBACF,CAAA;kBACF;gBACF;AAEA,oBAAIlD,IAAIwC,eAAe,OAAOxC,IAAIM,OAAOC,aAAa;AACpD,wBAAMA,cAAcP,IAAIM,OAAOC;AAC/B1B,yBAAOwE,mBAAmBC,eAAe;oBACvCvB,UAAUA,qCAAUQ;oBACpBpC,QAAQJ,IAAII;oBACZsB;oBACA8B,MAAMhD,YAAYiD;oBAClBC,KAAKlD,YAAYmD;oBACjBC,WAAWpD,YAAYqD,SAAS;kBAClC,CAAA;gBACF;cACF;AAEA,kBAAI/E,OAAOgB,cAAcgE,SAAS;AAChC,sBAAMC,OAAOlE,YAAYmE,SAAQ;AACjClF,uBAAOgB,cAAcmE,WACnB;kBACEC,WAAWC,KAAKvD,IAAG,IAAK;kBACxBR,QAAQJ,IAAII;kBACZsB;kBACA0C,KAAK,GAAGpE,IAAIqE,QAAQ,MAAMrE,IAAIsE,IAAI,GAAGtE,IAAIuE,WAAW;kBACpDC,SAAStG,eAAe8B,IAAIwE,OAAO;kBACnCC,MAAMrC;kBACNJ,UAAUA,qCAAUQ;kBACpBzB,MAAM9C,YAAY+B,IAAIe,MAAMf,IAAIiB,IAAI,cAAA,CAAA;gBACtC,GACA;kBACEwB,YAAYxC,IAAIwC;kBAChBhB,cAAcA,eAAe;kBAC7B+C,SAAStG,eAAe+B,IAAIyE,WAAU,CAAA;kBACtCD,MAAMpC;kBACNtB,MAAM9C,YAAYgC,IAAIM,OAAOQ,MAAMd,IAAIgB,IAAI,cAAA,CAAA;gBAC7C,GACAhB,IAAIM,OAAOC,aACXuD,MACAlC,OACAE,OAAAA;cAEJ;YACF,SAASoB,OAAO;AACdrE,qBAAO6F,OAAOxB,MACZ,sDACA;gBAAEyB,SAAS5E;gBAAK6E,UAAU5E;gBAAKkD;cAAM,CAAA;YAEzC;UACF,CAAA;AAEAlD,cAAIuB,KAAK,SAAS,MAAA;AAChBJ,uBAAWU,IAAG;UAChB,CAAA;AAEA5B,eAAAA;QACF,CAAA;MACF,SAASiD,OAAO;AACdrE,eAAO6F,OAAOxB,MAAM,gCAAgC;UAClDyB,SAAS5E;UACT6E,UAAU5E;UACVkD;QACF,CAAA;MACF;IACF,CAAA;EACF;AACF;AA5KSnE;AA8KT,SAAS2C,aAAa3B,KAAY;AAChC,MAAI,CAACA,IAAI8E,OAAO;AACd;EACF;AACA,MAAI9E,IAAI+E,SAAS;AACf,UAAMC,aAAaxG,cAAcwB,IAAIpB,GAAG;AACxC,QAAIoG,WAAWnB,OAAO;AACpB,YAAMoB,aAAaC,cAAcF,WAAWnB,OAAO7D,IAAI+E,OAAO;AAC9D,aAAO/E,IAAI8E,MAAMpD,SAAS,MAAMuD,aAAaA,aAAajF,IAAI8E,MAAMpD;IACtE;EACF;AACA,SAAO1B,IAAI8E,MAAMpD;AACnB;AAZSC;AAcT,SAASuD,cAAcrB,OAAckB,SAAe;AAnPpD;AAoPE,QAAMI,cAAwB,CAAA;AAC9B,SAAOtB,SAASA,MAAMpE,SAAS,GAAG;AAChC,UAAM2F,cAAcvB,MAAMwB,KACxB,CAACC,UAAAA;AAvPP,UAAAC;AAwPQD,mBAAM7B,SAAS,YACf6B,MAAM5D,SACLqD,QAAQS,WAAWF,MAAM5D,IAAI,OAAK4D,MAAAA,MAAMG,WAANH,gBAAAA,IAAcI,KAAKX;KAAO;AAEjE,QAAIK,aAAa;AACf,UACEA,YAAYK,UACZL,YAAYO,QACZP,YAAYO,KAAKlG,SAAS,GAC1B;AACA,cAAMmG,aAAalH,uBACjB0G,YAAYK,QACZL,YAAYO,IAAI;AAElBR,oBAAYrC,KAAK,MAAM8C,UAAAA;MACzB,WACER,YAAYS,UACZC,OAAOH,KAAKP,YAAYS,MAAM,EAAEpG,SAAS,GACzC;AACA,cAAMmG,aAAanH,iBACjB2G,YAAY1D,MACZ0D,YAAYS,MAAM;AAEpBV,oBAAYrC,KAAK8C,UAAAA;MACnB,OAAO;AACLT,oBAAYrC,KAAKsC,YAAY1D,IAAI;MACnC;AACAmC,eAAQuB,iBAAYW,WAAZX,mBAAoBvB;AAC5BkB,gBAAUA,QAAQiB,MAAMZ,YAAY1D,KAAKjC,MAAM;IACjD,OAAO;AACL;IACF;EACF;AACA,SAAO0F,YAAYc,OAAO,CAACvE,SAASA,SAAS,GAAA,EAAKwE,KAAK,EAAA;AACzD;AAvCShB;AAyCF,SAASiB,YACdnG,KACAgC,UAAsD;AAEtDhC,MAAIoG,mBAAmBpE,YAAYqE;AACrC;AALgBF;AAOhB,SAASlE,YAAYjC,KAAY;AAC/B,MAAIA,IAAIoG,kBAAkB;AACxB,WAAOtI,2BAA2BkC,IAAIoG,gBAAgB;EACxD,WAAWpG,IAAIsG,oBAAoB;AAEjCC,YAAQC,YACN,sGACA,oBAAA;AAEF,WAAO1I,2BAA2BkC,IAAIsG,kBAAkB;EAC1D;AACA,SAAO;AACT;AAZSrE;AAcT,SAASc,8BAA8B0D,cAAiB;AACtD,MAAI;AACF,UAAMC,SAA4B,CAAA;AAClC,QACED,gBACAA,aAAaC,UACbC,MAAMC,QAAQH,aAAaC,MAAM,GACjC;AACAD,mBAAaC,OAAOxD,QAAQ,CAACC,UAAAA;AAC3B,YAAIA,MAAM0D,YAAY1D,MAAMzB,QAAQyB,MAAMO,OAAOP,MAAMK,MAAM;AAC3DkD,iBAAO5D,KAAK;YACVgE,KAAK,GAAG3D,MAAM0D,QAAQ,IAAI1D,MAAMzB,IAAI;YACpCgC,KAAKP,MAAMO;YACXF,MAAML,MAAMK;UACd,CAAA;QACF;MACF,CAAA;IACF;AACA,WAAOkD;EACT,SAASvD,OAAO;AACd,WAAO,CAAA;EACT;AACF;AAtBSJ;AAwBT,SAASC,uBAAuByD,cAAiB;AAC/C,MAAI;AACF,UAAMC,SAA4B,CAAA;AAClC,QAAID,gBAAgBA,aAAaM,YAAY;AAC3CjB,aAAOkB,OAAOP,aAAaM,UAAU,EAAE7D,QAAQ,CAACC,UAAAA;AAC9C,YACEA,MAAM8D,UACN9D,MAAMwC,QACNgB,MAAMC,QAAQzD,MAAMwC,IAAI,KACxBxC,MAAMQ,SACN;AACAR,gBAAMwC,KAAKzC,QAAQ,CAACgE,QAAAA;AAClBR,mBAAO5D,KAAK;cACVgE,KAAK,GAAG3D,MAAM8D,MAAM,IAAIC,GAAAA;cACxBxD,KAAKyD,iBAAiBhE,MAAMQ,SAASuD,GAAAA;cACrC1D,MAAM;YACR,CAAA;UACF,CAAA;QACF;MACF,CAAA;IACF;AACA,WAAOkD;EACT,SAASvD,OAAO;AACd,WAAO,CAAA;EACT;AACF;AAzBSH;AA2BT,SAASC,4BAA4BwD,cAAiB;AACpD,MAAI;AACF,UAAMC,SAA4B,CAAA;AAClC,QAAID,gBAAgBE,MAAMC,QAAQH,aAAa9C,OAAO,GAAG;AACvD8C,mBAAa9C,QAAQT,QAAQ,CAACS,YAAAA;AAC5B+C,eAAO5D,KAAK;UACVgE,KAAK;UACLpD,KAAKC;UACLH,MAAM;QACR,CAAA;MACF,CAAA;IACF;AACA,WAAOkD;EACT,SAASvD,OAAO;AACd,WAAO,CAAA;EACT;AACF;AAhBSF;AAkBT,SAASkE,iBAAiBxD,SAAiBuD,KAAW;AACpD,QAAME,iBAAiBzD,QACpB0D,MAAM,IAAA,EACNhC,KAAK,CAAC1B,aAAYA,SAAQ2D,SAAS,IAAIJ,GAAAA,GAAM,CAAA;AAChD,SAAOE,iBAAiBA,iBAAiBzD;AAC3C;AALSwD;AAOT,SAAS9H,WACPT,KACAU,UACAC,YAAmB;AAEnB,QAAMgI,WAAoC;IACxC;MAAC;MAAUhB,QAAQiB,QAAQC,QAAQ,MAAM,EAAA;;;AAE3C,QAAMC,iBAAiB1J,kBAAkB,SAAA;AACzC,QAAM2J,gBAAgB3J,kBAAkB,cAAA;AACxC,QAAM4J,kBAAkB5J,kBAAkB,OAAA;AAC1C,MAAI0J,gBAAgB;AAClBH,aAASzE,KAAK;MAAC;MAAW4E;KAAe;EAC3C;AACA,MAAIC,eAAe;AACjBJ,aAASzE,KAAK;MAAC;MAAU6E;KAAc;EACzC;AACA,MAAIC,iBAAiB;AACnBL,aAASzE,KAAK;MAAC;MAAY8E;KAAgB;EAC7C;AACA,MAAIrI,YAAY;AACdgI,aAASzE,KAAK;MAAC;MAAOvD;KAAW;EACnC;AACA,SAAO;IACLC,OAAOjB,aAAaK,KAAKU,YAAY,EAAA;IACrCiI,UAAUzB,OAAO+B,YAAYN,QAAAA;IAC7BzI,QAAQ;EACV;AACF;AA5BSO;","names":["AsyncLocalStorage","performance","ApitallyClient","consumerFromStringOrObject","parseContentLength","getPackageVersion","convertBody","convertHeaders","patchConsole","patchNestLogger","patchPinoLogger","patchWinston","getEndpoints","getRouterInfo","parseExpressPath","parseExpressPathRegExp","useApitally","app","config","client","middleware","getMiddleware","use","setStartupData","attempt","appInfo","getAppInfo","basePath","appVersion","paths","length","startSync","setTimeout","errorHandlerConfigured","logsContext","requestLogger","captureLogs","req","res","next","isEnabled","method","toUpperCase","err","locals","serverError","log","run","startTime","now","originalSend","send","body","contentType","get","isSupportedContentType","call","spanHandle","spanCollector","startSpan","runInContext","once","responseTime","path","getRoutePath","setName","spans","end","traceId","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestSize","responseSize","requestCounter","addRequest","identifier","statusCode","jsonBody","JSON","parse","validationErrors","push","extractExpressValidatorErrors","extractCelebrateErrors","extractNestValidationErrors","forEach","error","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","enabled","logs","getStore","logRequest","timestamp","Date","url","protocol","host","originalUrl","headers","size","getHeaders","logger","request","response","route","baseUrl","routerInfo","routerPath","getRouterPath","routerPaths","routerLayer","find","layer","_a","startsWith","regexp","test","keys","parsedPath","params","Object","handle","slice","filter","join","setConsumer","apitallyConsumer","undefined","consumerIdentifier","process","emitWarning","responseBody","errors","Array","isArray","location","loc","validation","values","source","key","subsetJoiMessage","messageWithKey","split","includes","versions","version","replace","expressVersion","nestjsVersion","apitallyVersion","fromEntries"]}
|
|
1
|
+
{"version":3,"sources":["../../src/express/middleware.ts"],"sourcesContent":["import type { Express, NextFunction, Request, Response, Router } from \"express\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { performance } from \"node:perf_hooks\";\n\nimport { ApitallyClient } from \"../common/client.js\";\nimport { consumerFromStringOrObject } from \"../common/consumerRegistry.js\";\nimport { parseContentLength } from \"../common/headers.js\";\nimport { getPackageVersion } from \"../common/packageVersions.js\";\nimport type { LogRecord } from \"../common/requestLogger.js\";\nimport { convertBody, convertHeaders } from \"../common/requestLogger.js\";\nimport {\n ApitallyConfig,\n ApitallyConsumer,\n StartupData,\n ValidationError,\n} from \"../common/types.js\";\nimport {\n patchConsole,\n patchNestLogger,\n patchPinoLogger,\n patchWinston,\n} from \"../loggers/index.js\";\nimport {\n formatRegExpRoutePath,\n getEndpoints,\n getRouterInfo,\n parseExpressPath,\n parseExpressPathRegExp,\n stripExpressPathParamRegex,\n} from \"./utils.js\";\n\ndeclare module \"express\" {\n interface Request {\n apitallyConsumer?: ApitallyConsumer | string | null;\n consumerIdentifier?: ApitallyConsumer | string | null; // For backwards compatibility\n }\n}\n\nexport function useApitally(\n app: Express | Router,\n config: ApitallyConfig & { basePath?: string },\n) {\n const client = new ApitallyClient(config);\n const middleware = getMiddleware(app, client);\n app.use(middleware);\n\n const setStartupData = (attempt: number = 1) => {\n const appInfo = getAppInfo(app, config.basePath, config.appVersion);\n if (appInfo.paths.length > 0 || attempt >= 10) {\n client.setStartupData(appInfo);\n client.startSync();\n } else {\n setTimeout(() => setStartupData(attempt + 1), 500);\n }\n };\n setTimeout(() => setStartupData(), 500);\n}\n\nfunction getMiddleware(app: Express | Router, client: ApitallyClient) {\n let errorHandlerConfigured = false;\n const logsContext = new AsyncLocalStorage<LogRecord[]>();\n\n if (client.requestLogger.config.captureLogs) {\n patchConsole(logsContext);\n patchWinston(logsContext);\n patchNestLogger(logsContext);\n }\n\n return async (req: Request, res: Response, next: NextFunction) => {\n if (!client.isEnabled() || req.method.toUpperCase() === \"OPTIONS\") {\n next();\n return;\n }\n\n if (!errorHandlerConfigured) {\n // Add error handling middleware to the bottom of the stack when handling the first request\n app.use((err: Error, req: Request, res: Response, next: NextFunction) => {\n res.locals.serverError = err;\n next(err);\n });\n errorHandlerConfigured = true;\n }\n\n if (client.requestLogger.config.captureLogs && \"log\" in req) {\n await patchPinoLogger((req as any).log, logsContext);\n }\n\n logsContext.run([], () => {\n try {\n const startTime = performance.now();\n\n const originalSend = res.send;\n res.send = (body) => {\n const contentType = res.get(\"content-type\");\n if (client.requestLogger.isSupportedContentType(contentType)) {\n res.locals.body = body;\n }\n return originalSend.call(res, body);\n };\n\n const spanHandle = client.spanCollector.startSpan();\n spanHandle.runInContext(() => {\n res.once(\"finish\", () => {\n try {\n const responseTime = performance.now() - startTime;\n const path = getRoutePath(req);\n\n spanHandle.setName(`${req.method} ${path}`);\n const spans = spanHandle.end();\n const traceId = spanHandle.traceId;\n\n const consumer = getConsumer(req);\n client.consumerRegistry.addOrUpdateConsumer(consumer);\n\n const requestSize = parseContentLength(req.get(\"content-length\"));\n const responseSize = parseContentLength(\n res.get(\"content-length\"),\n );\n\n if (path) {\n client.requestCounter.addRequest({\n consumer: consumer?.identifier,\n method: req.method,\n path,\n statusCode: res.statusCode,\n responseTime: responseTime,\n requestSize,\n responseSize,\n });\n\n if (\n (res.statusCode === 400 || res.statusCode === 422) &&\n res.locals.body\n ) {\n let jsonBody: any;\n try {\n jsonBody = JSON.parse(res.locals.body);\n } catch {\n // Ignore\n }\n if (jsonBody) {\n const validationErrors: ValidationError[] = [];\n if (validationErrors.length === 0) {\n validationErrors.push(\n ...extractExpressValidatorErrors(jsonBody),\n );\n }\n if (validationErrors.length === 0) {\n validationErrors.push(\n ...extractCelebrateErrors(jsonBody),\n );\n }\n if (validationErrors.length === 0) {\n validationErrors.push(\n ...extractNestValidationErrors(jsonBody),\n );\n }\n validationErrors.forEach((error) => {\n client.validationErrorCounter.addValidationError({\n consumer: consumer?.identifier,\n method: req.method,\n path,\n ...error,\n });\n });\n }\n }\n\n if (res.statusCode === 500 && res.locals.serverError) {\n const serverError = res.locals.serverError as Error;\n client.serverErrorCounter.addServerError({\n consumer: consumer?.identifier,\n method: req.method,\n path,\n type: serverError.name,\n msg: serverError.message,\n traceback: serverError.stack || \"\",\n });\n }\n }\n\n if (client.requestLogger.enabled) {\n const logs = logsContext.getStore();\n client.requestLogger.logRequest(\n {\n timestamp: Date.now() / 1000,\n method: req.method,\n path,\n url: `${req.protocol}://${req.host}${req.originalUrl}`,\n headers: convertHeaders(req.headers),\n size: requestSize,\n consumer: consumer?.identifier,\n body: convertBody(req.body, req.get(\"content-type\")),\n },\n {\n statusCode: res.statusCode,\n responseTime: responseTime / 1000,\n headers: convertHeaders(res.getHeaders()),\n size: responseSize,\n body: convertBody(res.locals.body, res.get(\"content-type\")),\n },\n res.locals.serverError,\n logs,\n spans,\n traceId,\n );\n }\n } catch (error) {\n client.logger.error(\n \"Error while logging request in Apitally middleware\",\n { request: req, response: res, error },\n );\n }\n });\n\n res.once(\"close\", () => {\n spanHandle.end();\n });\n\n next();\n });\n } catch (error) {\n client.logger.error(\"Error in Apitally middleware\", {\n request: req,\n response: res,\n error,\n });\n }\n });\n };\n}\n\nfunction getRoutePath(req: Request) {\n if (!req.route) {\n return;\n }\n // req.route.path can be a string, a RegExp, or an array of either\n let routePath: unknown = req.route.path;\n if (Array.isArray(routePath)) {\n routePath = routePath.find((p) => typeof p === \"string\") ?? routePath[0];\n }\n if (typeof routePath === \"string\") {\n routePath = stripExpressPathParamRegex(routePath);\n } else if (routePath instanceof RegExp) {\n routePath = formatRegExpRoutePath(routePath);\n }\n if (typeof routePath !== \"string\") {\n return;\n }\n if (req.baseUrl) {\n const routerInfo = getRouterInfo(req.app);\n if (routerInfo.stack) {\n const routerPath = getRouterPath(routerInfo.stack, req.baseUrl);\n return routePath === \"/\" ? routerPath : routerPath + routePath;\n }\n }\n return routePath;\n}\n\nfunction getRouterPath(stack: any[], baseUrl: string) {\n const routerPaths: string[] = [];\n while (stack && stack.length > 0) {\n const routerLayer = stack.find(\n (layer) =>\n layer.name === \"router\" &&\n layer.path &&\n (baseUrl.startsWith(layer.path) || layer.regexp?.test(baseUrl)),\n );\n if (routerLayer) {\n if (\n routerLayer.regexp &&\n routerLayer.keys &&\n routerLayer.keys.length > 0\n ) {\n const parsedPath = parseExpressPathRegExp(\n routerLayer.regexp,\n routerLayer.keys,\n );\n routerPaths.push(\"/\" + parsedPath);\n } else if (\n routerLayer.params &&\n Object.keys(routerLayer.params).length > 0\n ) {\n const parsedPath = parseExpressPath(\n routerLayer.path,\n routerLayer.params,\n );\n routerPaths.push(parsedPath);\n } else {\n routerPaths.push(routerLayer.path);\n }\n stack = routerLayer.handle?.stack;\n baseUrl = baseUrl.slice(routerLayer.path.length);\n } else {\n break;\n }\n }\n return routerPaths.filter((path) => path !== \"/\").join(\"\");\n}\n\nexport function setConsumer(\n req: Request,\n consumer: ApitallyConsumer | string | null | undefined,\n) {\n req.apitallyConsumer = consumer || undefined;\n}\n\nfunction getConsumer(req: Request) {\n if (req.apitallyConsumer) {\n return consumerFromStringOrObject(req.apitallyConsumer);\n } else if (req.consumerIdentifier) {\n // For backwards compatibility\n process.emitWarning(\n \"The consumerIdentifier property on the request object is deprecated. Use apitallyConsumer instead.\",\n \"DeprecationWarning\",\n );\n return consumerFromStringOrObject(req.consumerIdentifier);\n }\n return null;\n}\n\nfunction extractExpressValidatorErrors(responseBody: any) {\n try {\n const errors: ValidationError[] = [];\n if (\n responseBody &&\n responseBody.errors &&\n Array.isArray(responseBody.errors)\n ) {\n responseBody.errors.forEach((error: any) => {\n if (error.location && error.path && error.msg && error.type) {\n errors.push({\n loc: `${error.location}.${error.path}`,\n msg: error.msg,\n type: error.type,\n });\n }\n });\n }\n return errors;\n } catch (error) {\n return [];\n }\n}\n\nfunction extractCelebrateErrors(responseBody: any) {\n try {\n const errors: ValidationError[] = [];\n if (responseBody && responseBody.validation) {\n Object.values(responseBody.validation).forEach((error: any) => {\n if (\n error.source &&\n error.keys &&\n Array.isArray(error.keys) &&\n error.message\n ) {\n error.keys.forEach((key: string) => {\n errors.push({\n loc: `${error.source}.${key}`,\n msg: subsetJoiMessage(error.message, key),\n type: \"\",\n });\n });\n }\n });\n }\n return errors;\n } catch (error) {\n return [];\n }\n}\n\nfunction extractNestValidationErrors(responseBody: any) {\n try {\n const errors: ValidationError[] = [];\n if (responseBody && Array.isArray(responseBody.message)) {\n responseBody.message.forEach((message: any) => {\n errors.push({\n loc: \"\",\n msg: message,\n type: \"\",\n });\n });\n }\n return errors;\n } catch (error) {\n return [];\n }\n}\n\nfunction subsetJoiMessage(message: string, key: string) {\n const messageWithKey = message\n .split(\". \")\n .find((message) => message.includes(`\"${key}\"`));\n return messageWithKey ? messageWithKey : message;\n}\n\nfunction getAppInfo(\n app: Express | Router,\n basePath?: string,\n appVersion?: string,\n): StartupData {\n const versions: Array<[string, string]> = [\n [\"nodejs\", process.version.replace(/^v/, \"\")],\n ];\n const expressVersion = getPackageVersion(\"express\");\n const nestjsVersion = getPackageVersion(\"@nestjs/core\");\n const apitallyVersion = getPackageVersion(\"../..\");\n if (expressVersion) {\n versions.push([\"express\", expressVersion]);\n }\n if (nestjsVersion) {\n versions.push([\"nestjs\", nestjsVersion]);\n }\n if (apitallyVersion) {\n versions.push([\"apitally\", apitallyVersion]);\n }\n if (appVersion) {\n versions.push([\"app\", appVersion]);\n }\n return {\n paths: getEndpoints(app, basePath || \"\"),\n versions: Object.fromEntries(versions),\n client: \"js:express\",\n };\n}\n"],"mappings":"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","names":["AsyncLocalStorage","performance","ApitallyClient","consumerFromStringOrObject","parseContentLength","getPackageVersion","convertBody","convertHeaders","patchConsole","patchNestLogger","patchPinoLogger","patchWinston","formatRegExpRoutePath","getEndpoints","getRouterInfo","parseExpressPath","parseExpressPathRegExp","stripExpressPathParamRegex","useApitally","app","config","client","middleware","getMiddleware","use","setStartupData","attempt","appInfo","getAppInfo","basePath","appVersion","paths","length","startSync","setTimeout","errorHandlerConfigured","logsContext","requestLogger","captureLogs","req","res","next","isEnabled","method","toUpperCase","err","locals","serverError","log","run","startTime","now","originalSend","send","body","contentType","get","isSupportedContentType","call","spanHandle","spanCollector","startSpan","runInContext","once","responseTime","path","getRoutePath","setName","spans","end","traceId","consumer","getConsumer","consumerRegistry","addOrUpdateConsumer","requestSize","responseSize","requestCounter","addRequest","identifier","statusCode","jsonBody","JSON","parse","validationErrors","push","extractExpressValidatorErrors","extractCelebrateErrors","extractNestValidationErrors","forEach","error","validationErrorCounter","addValidationError","serverErrorCounter","addServerError","type","name","msg","message","traceback","stack","enabled","logs","getStore","logRequest","timestamp","Date","url","protocol","host","originalUrl","headers","size","getHeaders","logger","request","response","route","routePath","Array","isArray","find","p","RegExp","baseUrl","routerInfo","routerPath","getRouterPath","routerPaths","routerLayer","layer","_a","startsWith","regexp","test","keys","parsedPath","params","Object","handle","slice","filter","join","setConsumer","apitallyConsumer","undefined","consumerIdentifier","process","emitWarning","responseBody","errors","location","loc","validation","values","source","key","subsetJoiMessage","messageWithKey","split","includes","versions","version","replace","expressVersion","nestjsVersion","apitallyVersion","fromEntries"]}
|
package/dist/express/utils.cjs
CHANGED
|
@@ -19,22 +19,30 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
19
19
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
20
|
var utils_exports = {};
|
|
21
21
|
__export(utils_exports, {
|
|
22
|
+
formatRegExpRoutePath: () => formatRegExpRoutePath,
|
|
22
23
|
getEndpoints: () => getEndpoints,
|
|
23
24
|
getRouterInfo: () => getRouterInfo,
|
|
24
25
|
parseExpressPath: () => parseExpressPath,
|
|
25
|
-
parseExpressPathRegExp: () => parseExpressPathRegExp
|
|
26
|
+
parseExpressPathRegExp: () => parseExpressPathRegExp,
|
|
27
|
+
stripExpressPathParamRegex: () => stripExpressPathParamRegex
|
|
26
28
|
});
|
|
27
29
|
module.exports = __toCommonJS(utils_exports);
|
|
28
30
|
const regExpToParseExpressPathRegExp = /^\/\^\\?\/?(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\\?\/?\([^)]+\)\)))\\\/.*/;
|
|
29
31
|
const regExpToReplaceExpressPathRegExpParams = /\(\?:\\?\/?\([^)]+\)\)/;
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
const
|
|
32
|
+
const regExpExpressParamRegExp = /\(\?:\\?\\?\/?\([^)]+\)\)/g;
|
|
33
|
+
const regExpExpressPathParamRegExp = /(:[^)]+)\([^)]+\)/g;
|
|
34
|
+
const rootPathRegExpValue = "/^\\/?(?=\\/|$)/i";
|
|
35
|
+
const stackItemValidNames = [
|
|
34
36
|
"router",
|
|
35
37
|
"bound dispatch",
|
|
36
38
|
"mounted_app"
|
|
37
39
|
];
|
|
40
|
+
const stripExpressPathParamRegex = /* @__PURE__ */ __name(function(path) {
|
|
41
|
+
return path.replace(regExpExpressPathParamRegExp, "$1");
|
|
42
|
+
}, "stripExpressPathParamRegex");
|
|
43
|
+
const formatRegExpRoutePath = /* @__PURE__ */ __name(function(re) {
|
|
44
|
+
return `RegExp(${re})`;
|
|
45
|
+
}, "formatRegExpRoutePath");
|
|
38
46
|
const getRouterInfo = /* @__PURE__ */ __name(function(app) {
|
|
39
47
|
var _a, _b;
|
|
40
48
|
if (app.stack) {
|
|
@@ -70,23 +78,29 @@ const getRouteMiddlewares = /* @__PURE__ */ __name(function(route) {
|
|
|
70
78
|
});
|
|
71
79
|
}, "getRouteMiddlewares");
|
|
72
80
|
const hasParams = /* @__PURE__ */ __name(function(expressPathRegExp) {
|
|
73
|
-
return
|
|
81
|
+
return regExpExpressParamRegExp.test(expressPathRegExp);
|
|
74
82
|
}, "hasParams");
|
|
75
83
|
const parseExpressRoute = /* @__PURE__ */ __name(function(route, basePath) {
|
|
76
|
-
const paths = [
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
return
|
|
84
|
+
const paths = Array.isArray(route.path) ? route.path : [
|
|
85
|
+
route.path
|
|
86
|
+
];
|
|
87
|
+
const endpoints = paths.flatMap((path) => {
|
|
88
|
+
let pathStr;
|
|
89
|
+
if (typeof path === "string") {
|
|
90
|
+
pathStr = stripExpressPathParamRegex(path);
|
|
91
|
+
} else if (path instanceof RegExp) {
|
|
92
|
+
pathStr = formatRegExpRoutePath(path);
|
|
93
|
+
} else {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
const completePath = basePath && pathStr === "/" ? basePath : `${basePath}${pathStr}`;
|
|
97
|
+
return [
|
|
98
|
+
{
|
|
99
|
+
path: completePath,
|
|
100
|
+
methods: getRouteMethods(route),
|
|
101
|
+
middlewares: getRouteMiddlewares(route)
|
|
102
|
+
}
|
|
103
|
+
];
|
|
90
104
|
});
|
|
91
105
|
return endpoints;
|
|
92
106
|
}, "parseExpressRoute");
|
|
@@ -155,16 +169,15 @@ const parseStack = /* @__PURE__ */ __name(function(stack, basePath, endpoints, v
|
|
|
155
169
|
if (stackItem.route) {
|
|
156
170
|
const newEndpoints = parseExpressRoute(stackItem.route, basePath);
|
|
157
171
|
endpoints = addEndpoints(endpoints, newEndpoints);
|
|
158
|
-
} else if (
|
|
172
|
+
} else if (stackItemValidNames.includes(stackItem.name)) {
|
|
159
173
|
let newBasePath = basePath;
|
|
160
174
|
if (version === "v4") {
|
|
161
175
|
const isExpressPathRegExp = regExpToParseExpressPathRegExp.test(stackItem.regexp);
|
|
162
176
|
if (isExpressPathRegExp) {
|
|
163
177
|
const parsedPath = parseExpressPathRegExp(stackItem.regexp, stackItem.keys);
|
|
164
178
|
newBasePath += `/${parsedPath}`;
|
|
165
|
-
} else if (!stackItem.path && stackItem.regexp && stackItem.regexp.toString() !==
|
|
166
|
-
|
|
167
|
-
newBasePath += `/${regExpPath}`;
|
|
179
|
+
} else if (!stackItem.path && stackItem.regexp && stackItem.regexp.toString() !== rootPathRegExpValue) {
|
|
180
|
+
newBasePath += `/${formatRegExpRoutePath(stackItem.regexp)}`;
|
|
168
181
|
}
|
|
169
182
|
} else if (version === "v5") {
|
|
170
183
|
if (!stackItem.path) {
|
|
@@ -194,9 +207,11 @@ const getEndpoints = /* @__PURE__ */ __name(function(app, basePath) {
|
|
|
194
207
|
}, "getEndpoints");
|
|
195
208
|
// Annotate the CommonJS export names for ESM import in node:
|
|
196
209
|
0 && (module.exports = {
|
|
210
|
+
formatRegExpRoutePath,
|
|
197
211
|
getEndpoints,
|
|
198
212
|
getRouterInfo,
|
|
199
213
|
parseExpressPath,
|
|
200
|
-
parseExpressPathRegExp
|
|
214
|
+
parseExpressPathRegExp,
|
|
215
|
+
stripExpressPathParamRegex
|
|
201
216
|
});
|
|
202
217
|
//# sourceMappingURL=utils.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/express/utils.js"],"sourcesContent":["// Adapted from https://github.com/AlbertoFdzM/express-list-endpoints/blob/305535d43008b46f34e18b01947762e039af6d2d/src/index.js\n// and also incorporated https://github.com/AlbertoFdzM/express-list-endpoints/pull/96\n// and https://github.com/labithiotis/express-list-routes/blob/5432c83a67c2788c56a1cdfc067ec809961c0c05/index.js\n\n/**\n * @typedef {Object} Route\n * @property {Object} methods\n * @property {string | string[]} path\n * @property {any[]} stack\n *\n * @typedef {Object} Endpoint\n * @property {string} path Path name\n * @property {string[]} methods Methods handled\n * @property {string[]} middlewares Mounted middlewares\n */\n\nconst regExpToParseExpressPathRegExp =\n /^\\/\\^\\\\?\\/?(?:(:?[\\w\\\\.-]*(?:\\\\\\/:?[\\w\\\\.-]*)*)|(\\(\\?:\\\\?\\/?\\([^)]+\\)\\)))\\\\\\/.*/;\nconst regExpToReplaceExpressPathRegExpParams = /\\(\\?:\\\\?\\/?\\([^)]+\\)\\)/;\nconst regexpExpressParamRegexp = /\\(\\?:\\\\?\\\\?\\/?\\([^)]+\\)\\)/g;\nconst regexpExpressPathParamRegexp = /(:[^)]+)\\([^)]+\\)/g;\n\nconst EXPRESS_ROOT_PATH_REGEXP_VALUE = \"/^\\\\/?(?=\\\\/|$)/i\";\nconst STACK_ITEM_VALID_NAMES = [\"router\", \"bound dispatch\", \"mounted_app\"];\n\n/**\n * Detects Express version and returns router information\n * @param {import('express').Express | import('express').Router | any} app\n * @returns {{stack: any[] | null, version: 'v4' | 'v5'}}\n */\nexport const getRouterInfo = function (app) {\n if (app.stack) {\n // Express 4 router\n return { stack: app.stack, version: \"v4\" };\n } else if (app._router?.stack) {\n // Express 4\n return { stack: app._router.stack, version: \"v4\" };\n } else if (app.router?.stack) {\n // Express 5\n return { stack: app.router.stack, version: \"v5\" };\n }\n return { stack: null, version: \"v4\" };\n};\n\n/**\n * Returns all the verbs detected for the passed route\n * @param {Route} route\n */\nconst getRouteMethods = function (route) {\n let methods = Object.keys(route.methods);\n\n methods = methods.filter((method) => method !== \"_all\");\n methods = methods.map((method) => method.toUpperCase());\n\n return methods;\n};\n\n/**\n * Returns the names (or anonymous) of all the middlewares attached to the\n * passed route\n * @param {Route} route\n * @returns {string[]}\n */\nconst getRouteMiddlewares = function (route) {\n return route.stack.map((item) => {\n return item.handle.name || \"anonymous\";\n });\n};\n\n/**\n * Returns true if found regexp related with express params\n * @param {string} expressPathRegExp\n * @returns {boolean}\n */\nconst hasParams = function (expressPathRegExp) {\n return regexpExpressParamRegexp.test(expressPathRegExp);\n};\n\n/**\n * @param {Route} route Express route object to be parsed\n * @param {string} basePath The basePath the route is on\n * @return {Endpoint[]} Endpoints info\n */\nconst parseExpressRoute = function (route, basePath) {\n const paths = [];\n\n if (Array.isArray(route.path)) {\n paths.push(...route.path);\n } else {\n paths.push(route.path);\n }\n\n /** @type {Endpoint[]} */\n const endpoints = paths.map((path) => {\n const completePath =\n basePath && path === \"/\" ? basePath : `${basePath}${path}`;\n\n /** @type {Endpoint} */\n const endpoint = {\n path: completePath.replace(regexpExpressPathParamRegexp, \"$1\"),\n methods: getRouteMethods(route),\n middlewares: getRouteMiddlewares(route),\n };\n\n return endpoint;\n });\n\n return endpoints;\n};\n\n/**\n * @param {RegExp} expressPathRegExp\n * @param {any[]} keys\n * @returns {string}\n */\nexport const parseExpressPathRegExp = function (expressPathRegExp, keys) {\n let parsedRegExp = expressPathRegExp.toString();\n let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n let paramIndex = 0;\n\n while (hasParams(parsedRegExp)) {\n const paramName = keys[paramIndex].name;\n const paramId = `:${paramName}`;\n\n parsedRegExp = parsedRegExp.replace(\n regExpToReplaceExpressPathRegExpParams,\n (str) => {\n // Express >= 4.20.0 uses a different RegExp for parameters: it\n // captures the slash as part of the parameter. We need to check\n // for this case and add the slash to the value that will replace\n // the parameter in the path.\n if (str.startsWith(\"(?:\\\\/\")) {\n return `\\\\/${paramId}`;\n }\n\n return paramId;\n },\n );\n\n paramIndex++;\n }\n\n if (parsedRegExp !== expressPathRegExp.toString()) {\n expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n }\n\n return expressPathRegExpExec[1].replace(/\\\\\\//g, \"/\");\n};\n\n/**\n * @param {string} expressPath\n * @param {Object.<string, string>} params\n * @returns {string}\n */\nexport const parseExpressPath = function (expressPath, params) {\n let result = expressPath;\n for (const [paramName, paramValue] of Object.entries(params)) {\n result = result.replace(paramValue, `:${paramName}`);\n }\n return result;\n};\n\n/**\n * @param {import('express').Express | import('express').Router | any} app\n * @param {string} [basePath]\n * @param {Endpoint[]} [endpoints]\n * @returns {Endpoint[]}\n */\nconst parseEndpoints = function (app, basePath, endpoints) {\n const routerInfo = getRouterInfo(app);\n const stack = routerInfo.stack;\n const version = routerInfo.version;\n\n endpoints = endpoints || [];\n basePath = basePath || \"\";\n\n if (!stack) {\n if (endpoints.length) {\n endpoints = addEndpoints(endpoints, [\n {\n path: basePath,\n methods: [],\n middlewares: [],\n },\n ]);\n }\n } else {\n endpoints = parseStack(stack, basePath, endpoints, version);\n }\n\n return endpoints;\n};\n\n/**\n * Ensures the path of the new endpoints isn't yet in the array.\n * If the path is already in the array merges the endpoints with the existing\n * one, if not, it adds them to the array.\n *\n * @param {Endpoint[]} currentEndpoints Array of current endpoints\n * @param {Endpoint[]} endpointsToAdd New endpoints to be added to the array\n * @returns {Endpoint[]} Updated endpoints array\n */\nconst addEndpoints = function (currentEndpoints, endpointsToAdd) {\n endpointsToAdd.forEach((newEndpoint) => {\n const existingEndpoint = currentEndpoints.find(\n (endpoint) => endpoint.path === newEndpoint.path,\n );\n\n if (existingEndpoint !== undefined) {\n const newMethods = newEndpoint.methods.filter(\n (method) => !existingEndpoint.methods.includes(method),\n );\n\n existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);\n } else {\n currentEndpoints.push(newEndpoint);\n }\n });\n\n return currentEndpoints;\n};\n\n/**\n * @param {any[]} stack\n * @param {string} basePath\n * @param {Endpoint[]} endpoints\n * @param {'v4' | 'v5'} [version]\n * @returns {Endpoint[]}\n */\nconst parseStack = function (stack, basePath, endpoints, version) {\n stack.forEach((stackItem) => {\n if (stackItem.route) {\n const newEndpoints = parseExpressRoute(stackItem.route, basePath);\n\n endpoints = addEndpoints(endpoints, newEndpoints);\n } else if (STACK_ITEM_VALID_NAMES.includes(stackItem.name)) {\n let newBasePath = basePath;\n\n if (version === \"v4\") {\n const isExpressPathRegExp = regExpToParseExpressPathRegExp.test(\n stackItem.regexp,\n );\n if (isExpressPathRegExp) {\n const parsedPath = parseExpressPathRegExp(\n stackItem.regexp,\n stackItem.keys,\n );\n newBasePath += `/${parsedPath}`;\n } else if (\n !stackItem.path &&\n stackItem.regexp &&\n stackItem.regexp.toString() !== EXPRESS_ROOT_PATH_REGEXP_VALUE\n ) {\n const regExpPath = `RegExp(${stackItem.regexp})`;\n newBasePath += `/${regExpPath}`;\n }\n } else if (version === \"v5\") {\n if (!stackItem.path) {\n return;\n } else if (stackItem.path !== \"/\") {\n newBasePath += stackItem.path.startsWith(\"/\")\n ? stackItem.path\n : `/${stackItem.path}`;\n }\n }\n\n endpoints = parseEndpoints(stackItem.handle, newBasePath, endpoints);\n }\n });\n\n return endpoints;\n};\n\nexport const getEndpoints = function (app, basePath) {\n const endpoints = parseEndpoints(app);\n const standardHttpMethods = [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"];\n return endpoints.flatMap((route) =>\n route.methods\n .filter((method) => standardHttpMethods.includes(method.toUpperCase()))\n .map((method) => ({\n method,\n path: (basePath + route.path).replace(/\\/\\//g, \"/\"),\n })),\n );\n};\n"],"mappings":"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","names":["regExpToParseExpressPathRegExp","regExpToReplaceExpressPathRegExpParams","regexpExpressParamRegexp","regexpExpressPathParamRegexp","EXPRESS_ROOT_PATH_REGEXP_VALUE","STACK_ITEM_VALID_NAMES","getRouterInfo","app","stack","version","_router","router","getRouteMethods","route","methods","Object","keys","filter","method","map","toUpperCase","getRouteMiddlewares","item","handle","name","hasParams","expressPathRegExp","test","parseExpressRoute","basePath","paths","Array","isArray","path","push","endpoints","completePath","endpoint","replace","middlewares","parseExpressPathRegExp","parsedRegExp","toString","expressPathRegExpExec","exec","paramIndex","paramName","paramId","str","startsWith","parseExpressPath","expressPath","params","result","paramValue","entries","parseEndpoints","routerInfo","length","addEndpoints","parseStack","currentEndpoints","endpointsToAdd","forEach","newEndpoint","existingEndpoint","find","undefined","newMethods","includes","concat","stackItem","newEndpoints","newBasePath","isExpressPathRegExp","regexp","parsedPath","regExpPath","getEndpoints","standardHttpMethods","flatMap"]}
|
|
1
|
+
{"version":3,"sources":["../../src/express/utils.js"],"sourcesContent":["// Adapted from https://github.com/AlbertoFdzM/express-list-endpoints/blob/305535d43008b46f34e18b01947762e039af6d2d/src/index.js\n// and also incorporated https://github.com/AlbertoFdzM/express-list-endpoints/pull/96\n// and https://github.com/labithiotis/express-list-routes/blob/5432c83a67c2788c56a1cdfc067ec809961c0c05/index.js\n\n/**\n * @typedef {Object} Route\n * @property {Object} methods\n * @property {string | string[]} path\n * @property {any[]} stack\n *\n * @typedef {Object} Endpoint\n * @property {string} path Path name\n * @property {string[]} methods Methods handled\n * @property {string[]} middlewares Mounted middlewares\n */\n\nconst regExpToParseExpressPathRegExp =\n /^\\/\\^\\\\?\\/?(?:(:?[\\w\\\\.-]*(?:\\\\\\/:?[\\w\\\\.-]*)*)|(\\(\\?:\\\\?\\/?\\([^)]+\\)\\)))\\\\\\/.*/;\nconst regExpToReplaceExpressPathRegExpParams = /\\(\\?:\\\\?\\/?\\([^)]+\\)\\)/;\nconst regExpExpressParamRegExp = /\\(\\?:\\\\?\\\\?\\/?\\([^)]+\\)\\)/g;\nconst regExpExpressPathParamRegExp = /(:[^)]+)\\([^)]+\\)/g;\nconst rootPathRegExpValue = \"/^\\\\/?(?=\\\\/|$)/i\";\nconst stackItemValidNames = [\"router\", \"bound dispatch\", \"mounted_app\"];\n\n/**\n * Strips inline RegExp validators from Express path params, e.g.\n * \"/users/:id(\\\\d+)\" → \"/users/:id\".\n * @param {string} path\n * @returns {string}\n */\nexport const stripExpressPathParamRegex = function (path) {\n return path.replace(regExpExpressPathParamRegExp, \"$1\");\n};\n\n/**\n * Formats a RegExp route as a stable string identifier, e.g.\n * /^\\/foo$/ → \"RegExp(/^\\\\/foo$/)\".\n * @param {RegExp} re\n * @returns {string}\n */\nexport const formatRegExpRoutePath = function (re) {\n return `RegExp(${re})`;\n};\n\n/**\n * Detects Express version and returns router information\n * @param {import('express').Express | import('express').Router | any} app\n * @returns {{stack: any[] | null, version: 'v4' | 'v5'}}\n */\nexport const getRouterInfo = function (app) {\n if (app.stack) {\n // Express 4 router\n return { stack: app.stack, version: \"v4\" };\n } else if (app._router?.stack) {\n // Express 4\n return { stack: app._router.stack, version: \"v4\" };\n } else if (app.router?.stack) {\n // Express 5\n return { stack: app.router.stack, version: \"v5\" };\n }\n return { stack: null, version: \"v4\" };\n};\n\n/**\n * Returns all the verbs detected for the passed route\n * @param {Route} route\n */\nconst getRouteMethods = function (route) {\n let methods = Object.keys(route.methods);\n\n methods = methods.filter((method) => method !== \"_all\");\n methods = methods.map((method) => method.toUpperCase());\n\n return methods;\n};\n\n/**\n * Returns the names (or anonymous) of all the middlewares attached to the\n * passed route\n * @param {Route} route\n * @returns {string[]}\n */\nconst getRouteMiddlewares = function (route) {\n return route.stack.map((item) => {\n return item.handle.name || \"anonymous\";\n });\n};\n\n/**\n * Returns true if found regexp related with express params\n * @param {string} expressPathRegExp\n * @returns {boolean}\n */\nconst hasParams = function (expressPathRegExp) {\n return regExpExpressParamRegExp.test(expressPathRegExp);\n};\n\n/**\n * @param {Route} route Express route object to be parsed\n * @param {string} basePath The basePath the route is on\n * @return {Endpoint[]} Endpoints info\n */\nconst parseExpressRoute = function (route, basePath) {\n // route.path can be a string, a RegExp, or an array of either\n const paths = Array.isArray(route.path) ? route.path : [route.path];\n\n /** @type {Endpoint[]} */\n const endpoints = paths.flatMap((path) => {\n let pathStr;\n if (typeof path === \"string\") {\n pathStr = stripExpressPathParamRegex(path);\n } else if (path instanceof RegExp) {\n pathStr = formatRegExpRoutePath(path);\n } else {\n return [];\n }\n const completePath =\n basePath && pathStr === \"/\" ? basePath : `${basePath}${pathStr}`;\n return [\n {\n path: completePath,\n methods: getRouteMethods(route),\n middlewares: getRouteMiddlewares(route),\n },\n ];\n });\n\n return endpoints;\n};\n\n/**\n * @param {RegExp} expressPathRegExp\n * @param {any[]} keys\n * @returns {string}\n */\nexport const parseExpressPathRegExp = function (expressPathRegExp, keys) {\n let parsedRegExp = expressPathRegExp.toString();\n let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n let paramIndex = 0;\n\n while (hasParams(parsedRegExp)) {\n const paramName = keys[paramIndex].name;\n const paramId = `:${paramName}`;\n\n parsedRegExp = parsedRegExp.replace(\n regExpToReplaceExpressPathRegExpParams,\n (str) => {\n // Express >= 4.20.0 uses a different RegExp for parameters: it\n // captures the slash as part of the parameter. We need to check\n // for this case and add the slash to the value that will replace\n // the parameter in the path.\n if (str.startsWith(\"(?:\\\\/\")) {\n return `\\\\/${paramId}`;\n }\n\n return paramId;\n },\n );\n\n paramIndex++;\n }\n\n if (parsedRegExp !== expressPathRegExp.toString()) {\n expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n }\n\n return expressPathRegExpExec[1].replace(/\\\\\\//g, \"/\");\n};\n\n/**\n * @param {string} expressPath\n * @param {Object.<string, string>} params\n * @returns {string}\n */\nexport const parseExpressPath = function (expressPath, params) {\n let result = expressPath;\n for (const [paramName, paramValue] of Object.entries(params)) {\n result = result.replace(paramValue, `:${paramName}`);\n }\n return result;\n};\n\n/**\n * @param {import('express').Express | import('express').Router | any} app\n * @param {string} [basePath]\n * @param {Endpoint[]} [endpoints]\n * @returns {Endpoint[]}\n */\nconst parseEndpoints = function (app, basePath, endpoints) {\n const routerInfo = getRouterInfo(app);\n const stack = routerInfo.stack;\n const version = routerInfo.version;\n\n endpoints = endpoints || [];\n basePath = basePath || \"\";\n\n if (!stack) {\n if (endpoints.length) {\n endpoints = addEndpoints(endpoints, [\n {\n path: basePath,\n methods: [],\n middlewares: [],\n },\n ]);\n }\n } else {\n endpoints = parseStack(stack, basePath, endpoints, version);\n }\n\n return endpoints;\n};\n\n/**\n * Ensures the path of the new endpoints isn't yet in the array.\n * If the path is already in the array merges the endpoints with the existing\n * one, if not, it adds them to the array.\n *\n * @param {Endpoint[]} currentEndpoints Array of current endpoints\n * @param {Endpoint[]} endpointsToAdd New endpoints to be added to the array\n * @returns {Endpoint[]} Updated endpoints array\n */\nconst addEndpoints = function (currentEndpoints, endpointsToAdd) {\n endpointsToAdd.forEach((newEndpoint) => {\n const existingEndpoint = currentEndpoints.find(\n (endpoint) => endpoint.path === newEndpoint.path,\n );\n\n if (existingEndpoint !== undefined) {\n const newMethods = newEndpoint.methods.filter(\n (method) => !existingEndpoint.methods.includes(method),\n );\n\n existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);\n } else {\n currentEndpoints.push(newEndpoint);\n }\n });\n\n return currentEndpoints;\n};\n\n/**\n * @param {any[]} stack\n * @param {string} basePath\n * @param {Endpoint[]} endpoints\n * @param {'v4' | 'v5'} [version]\n * @returns {Endpoint[]}\n */\nconst parseStack = function (stack, basePath, endpoints, version) {\n stack.forEach((stackItem) => {\n if (stackItem.route) {\n const newEndpoints = parseExpressRoute(stackItem.route, basePath);\n\n endpoints = addEndpoints(endpoints, newEndpoints);\n } else if (stackItemValidNames.includes(stackItem.name)) {\n let newBasePath = basePath;\n\n if (version === \"v4\") {\n const isExpressPathRegExp = regExpToParseExpressPathRegExp.test(\n stackItem.regexp,\n );\n if (isExpressPathRegExp) {\n const parsedPath = parseExpressPathRegExp(\n stackItem.regexp,\n stackItem.keys,\n );\n newBasePath += `/${parsedPath}`;\n } else if (\n !stackItem.path &&\n stackItem.regexp &&\n stackItem.regexp.toString() !== rootPathRegExpValue\n ) {\n newBasePath += `/${formatRegExpRoutePath(stackItem.regexp)}`;\n }\n } else if (version === \"v5\") {\n if (!stackItem.path) {\n return;\n } else if (stackItem.path !== \"/\") {\n newBasePath += stackItem.path.startsWith(\"/\")\n ? stackItem.path\n : `/${stackItem.path}`;\n }\n }\n\n endpoints = parseEndpoints(stackItem.handle, newBasePath, endpoints);\n }\n });\n\n return endpoints;\n};\n\nexport const getEndpoints = function (app, basePath) {\n const endpoints = parseEndpoints(app);\n const standardHttpMethods = [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"];\n return endpoints.flatMap((route) =>\n route.methods\n .filter((method) => standardHttpMethods.includes(method.toUpperCase()))\n .map((method) => ({\n method,\n path: (basePath + route.path).replace(/\\/\\//g, \"/\"),\n })),\n );\n};\n"],"mappings":"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","names":["regExpToParseExpressPathRegExp","regExpToReplaceExpressPathRegExpParams","regExpExpressParamRegExp","regExpExpressPathParamRegExp","rootPathRegExpValue","stackItemValidNames","stripExpressPathParamRegex","path","replace","formatRegExpRoutePath","re","getRouterInfo","app","stack","version","_router","router","getRouteMethods","route","methods","Object","keys","filter","method","map","toUpperCase","getRouteMiddlewares","item","handle","name","hasParams","expressPathRegExp","test","parseExpressRoute","basePath","paths","Array","isArray","endpoints","flatMap","pathStr","RegExp","completePath","middlewares","parseExpressPathRegExp","parsedRegExp","toString","expressPathRegExpExec","exec","paramIndex","paramName","paramId","str","startsWith","parseExpressPath","expressPath","params","result","paramValue","entries","parseEndpoints","routerInfo","length","addEndpoints","parseStack","currentEndpoints","endpointsToAdd","forEach","newEndpoint","existingEndpoint","find","endpoint","undefined","newMethods","includes","concat","push","stackItem","newEndpoints","newBasePath","isExpressPathRegExp","regexp","parsedPath","getEndpoints","standardHttpMethods"]}
|
package/dist/express/utils.d.cts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as express from 'express';
|
|
2
2
|
|
|
3
|
+
declare function stripExpressPathParamRegex(path: string): string;
|
|
4
|
+
declare function formatRegExpRoutePath(re: RegExp): string;
|
|
3
5
|
declare function getRouterInfo(app: express.Express | express.Router | any): {
|
|
4
6
|
stack: any[] | null;
|
|
5
7
|
version: "v4" | "v5";
|
|
@@ -32,4 +34,4 @@ type Endpoint = {
|
|
|
32
34
|
middlewares: string[];
|
|
33
35
|
};
|
|
34
36
|
|
|
35
|
-
export { type Endpoint, type Route, getEndpoints, getRouterInfo, parseExpressPath, parseExpressPathRegExp };
|
|
37
|
+
export { type Endpoint, type Route, formatRegExpRoutePath, getEndpoints, getRouterInfo, parseExpressPath, parseExpressPathRegExp, stripExpressPathParamRegex };
|
package/dist/express/utils.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as express from 'express';
|
|
2
2
|
|
|
3
|
+
declare function stripExpressPathParamRegex(path: string): string;
|
|
4
|
+
declare function formatRegExpRoutePath(re: RegExp): string;
|
|
3
5
|
declare function getRouterInfo(app: express.Express | express.Router | any): {
|
|
4
6
|
stack: any[] | null;
|
|
5
7
|
version: "v4" | "v5";
|
|
@@ -32,4 +34,4 @@ type Endpoint = {
|
|
|
32
34
|
middlewares: string[];
|
|
33
35
|
};
|
|
34
36
|
|
|
35
|
-
export { type Endpoint, type Route, getEndpoints, getRouterInfo, parseExpressPath, parseExpressPathRegExp };
|
|
37
|
+
export { type Endpoint, type Route, formatRegExpRoutePath, getEndpoints, getRouterInfo, parseExpressPath, parseExpressPathRegExp, stripExpressPathParamRegex };
|
package/dist/express/utils.js
CHANGED
|
@@ -2,14 +2,20 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
const regExpToParseExpressPathRegExp = /^\/\^\\?\/?(?:(:?[\w\\.-]*(?:\\\/:?[\w\\.-]*)*)|(\(\?:\\?\/?\([^)]+\)\)))\\\/.*/;
|
|
4
4
|
const regExpToReplaceExpressPathRegExpParams = /\(\?:\\?\/?\([^)]+\)\)/;
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
5
|
+
const regExpExpressParamRegExp = /\(\?:\\?\\?\/?\([^)]+\)\)/g;
|
|
6
|
+
const regExpExpressPathParamRegExp = /(:[^)]+)\([^)]+\)/g;
|
|
7
|
+
const rootPathRegExpValue = "/^\\/?(?=\\/|$)/i";
|
|
8
|
+
const stackItemValidNames = [
|
|
9
9
|
"router",
|
|
10
10
|
"bound dispatch",
|
|
11
11
|
"mounted_app"
|
|
12
12
|
];
|
|
13
|
+
const stripExpressPathParamRegex = /* @__PURE__ */ __name(function(path) {
|
|
14
|
+
return path.replace(regExpExpressPathParamRegExp, "$1");
|
|
15
|
+
}, "stripExpressPathParamRegex");
|
|
16
|
+
const formatRegExpRoutePath = /* @__PURE__ */ __name(function(re) {
|
|
17
|
+
return `RegExp(${re})`;
|
|
18
|
+
}, "formatRegExpRoutePath");
|
|
13
19
|
const getRouterInfo = /* @__PURE__ */ __name(function(app) {
|
|
14
20
|
var _a, _b;
|
|
15
21
|
if (app.stack) {
|
|
@@ -45,23 +51,29 @@ const getRouteMiddlewares = /* @__PURE__ */ __name(function(route) {
|
|
|
45
51
|
});
|
|
46
52
|
}, "getRouteMiddlewares");
|
|
47
53
|
const hasParams = /* @__PURE__ */ __name(function(expressPathRegExp) {
|
|
48
|
-
return
|
|
54
|
+
return regExpExpressParamRegExp.test(expressPathRegExp);
|
|
49
55
|
}, "hasParams");
|
|
50
56
|
const parseExpressRoute = /* @__PURE__ */ __name(function(route, basePath) {
|
|
51
|
-
const paths = [
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
return
|
|
57
|
+
const paths = Array.isArray(route.path) ? route.path : [
|
|
58
|
+
route.path
|
|
59
|
+
];
|
|
60
|
+
const endpoints = paths.flatMap((path) => {
|
|
61
|
+
let pathStr;
|
|
62
|
+
if (typeof path === "string") {
|
|
63
|
+
pathStr = stripExpressPathParamRegex(path);
|
|
64
|
+
} else if (path instanceof RegExp) {
|
|
65
|
+
pathStr = formatRegExpRoutePath(path);
|
|
66
|
+
} else {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
const completePath = basePath && pathStr === "/" ? basePath : `${basePath}${pathStr}`;
|
|
70
|
+
return [
|
|
71
|
+
{
|
|
72
|
+
path: completePath,
|
|
73
|
+
methods: getRouteMethods(route),
|
|
74
|
+
middlewares: getRouteMiddlewares(route)
|
|
75
|
+
}
|
|
76
|
+
];
|
|
65
77
|
});
|
|
66
78
|
return endpoints;
|
|
67
79
|
}, "parseExpressRoute");
|
|
@@ -130,16 +142,15 @@ const parseStack = /* @__PURE__ */ __name(function(stack, basePath, endpoints, v
|
|
|
130
142
|
if (stackItem.route) {
|
|
131
143
|
const newEndpoints = parseExpressRoute(stackItem.route, basePath);
|
|
132
144
|
endpoints = addEndpoints(endpoints, newEndpoints);
|
|
133
|
-
} else if (
|
|
145
|
+
} else if (stackItemValidNames.includes(stackItem.name)) {
|
|
134
146
|
let newBasePath = basePath;
|
|
135
147
|
if (version === "v4") {
|
|
136
148
|
const isExpressPathRegExp = regExpToParseExpressPathRegExp.test(stackItem.regexp);
|
|
137
149
|
if (isExpressPathRegExp) {
|
|
138
150
|
const parsedPath = parseExpressPathRegExp(stackItem.regexp, stackItem.keys);
|
|
139
151
|
newBasePath += `/${parsedPath}`;
|
|
140
|
-
} else if (!stackItem.path && stackItem.regexp && stackItem.regexp.toString() !==
|
|
141
|
-
|
|
142
|
-
newBasePath += `/${regExpPath}`;
|
|
152
|
+
} else if (!stackItem.path && stackItem.regexp && stackItem.regexp.toString() !== rootPathRegExpValue) {
|
|
153
|
+
newBasePath += `/${formatRegExpRoutePath(stackItem.regexp)}`;
|
|
143
154
|
}
|
|
144
155
|
} else if (version === "v5") {
|
|
145
156
|
if (!stackItem.path) {
|
|
@@ -168,9 +179,11 @@ const getEndpoints = /* @__PURE__ */ __name(function(app, basePath) {
|
|
|
168
179
|
})));
|
|
169
180
|
}, "getEndpoints");
|
|
170
181
|
export {
|
|
182
|
+
formatRegExpRoutePath,
|
|
171
183
|
getEndpoints,
|
|
172
184
|
getRouterInfo,
|
|
173
185
|
parseExpressPath,
|
|
174
|
-
parseExpressPathRegExp
|
|
186
|
+
parseExpressPathRegExp,
|
|
187
|
+
stripExpressPathParamRegex
|
|
175
188
|
};
|
|
176
189
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/express/utils.js"],"sourcesContent":["// Adapted from https://github.com/AlbertoFdzM/express-list-endpoints/blob/305535d43008b46f34e18b01947762e039af6d2d/src/index.js\n// and also incorporated https://github.com/AlbertoFdzM/express-list-endpoints/pull/96\n// and https://github.com/labithiotis/express-list-routes/blob/5432c83a67c2788c56a1cdfc067ec809961c0c05/index.js\n\n/**\n * @typedef {Object} Route\n * @property {Object} methods\n * @property {string | string[]} path\n * @property {any[]} stack\n *\n * @typedef {Object} Endpoint\n * @property {string} path Path name\n * @property {string[]} methods Methods handled\n * @property {string[]} middlewares Mounted middlewares\n */\n\nconst regExpToParseExpressPathRegExp =\n /^\\/\\^\\\\?\\/?(?:(:?[\\w\\\\.-]*(?:\\\\\\/:?[\\w\\\\.-]*)*)|(\\(\\?:\\\\?\\/?\\([^)]+\\)\\)))\\\\\\/.*/;\nconst regExpToReplaceExpressPathRegExpParams = /\\(\\?:\\\\?\\/?\\([^)]+\\)\\)/;\nconst regexpExpressParamRegexp = /\\(\\?:\\\\?\\\\?\\/?\\([^)]+\\)\\)/g;\nconst regexpExpressPathParamRegexp = /(:[^)]+)\\([^)]+\\)/g;\n\nconst EXPRESS_ROOT_PATH_REGEXP_VALUE = \"/^\\\\/?(?=\\\\/|$)/i\";\nconst STACK_ITEM_VALID_NAMES = [\"router\", \"bound dispatch\", \"mounted_app\"];\n\n/**\n * Detects Express version and returns router information\n * @param {import('express').Express | import('express').Router | any} app\n * @returns {{stack: any[] | null, version: 'v4' | 'v5'}}\n */\nexport const getRouterInfo = function (app) {\n if (app.stack) {\n // Express 4 router\n return { stack: app.stack, version: \"v4\" };\n } else if (app._router?.stack) {\n // Express 4\n return { stack: app._router.stack, version: \"v4\" };\n } else if (app.router?.stack) {\n // Express 5\n return { stack: app.router.stack, version: \"v5\" };\n }\n return { stack: null, version: \"v4\" };\n};\n\n/**\n * Returns all the verbs detected for the passed route\n * @param {Route} route\n */\nconst getRouteMethods = function (route) {\n let methods = Object.keys(route.methods);\n\n methods = methods.filter((method) => method !== \"_all\");\n methods = methods.map((method) => method.toUpperCase());\n\n return methods;\n};\n\n/**\n * Returns the names (or anonymous) of all the middlewares attached to the\n * passed route\n * @param {Route} route\n * @returns {string[]}\n */\nconst getRouteMiddlewares = function (route) {\n return route.stack.map((item) => {\n return item.handle.name || \"anonymous\";\n });\n};\n\n/**\n * Returns true if found regexp related with express params\n * @param {string} expressPathRegExp\n * @returns {boolean}\n */\nconst hasParams = function (expressPathRegExp) {\n return regexpExpressParamRegexp.test(expressPathRegExp);\n};\n\n/**\n * @param {Route} route Express route object to be parsed\n * @param {string} basePath The basePath the route is on\n * @return {Endpoint[]} Endpoints info\n */\nconst parseExpressRoute = function (route, basePath) {\n const paths = [];\n\n if (Array.isArray(route.path)) {\n paths.push(...route.path);\n } else {\n paths.push(route.path);\n }\n\n /** @type {Endpoint[]} */\n const endpoints = paths.map((path) => {\n const completePath =\n basePath && path === \"/\" ? basePath : `${basePath}${path}`;\n\n /** @type {Endpoint} */\n const endpoint = {\n path: completePath.replace(regexpExpressPathParamRegexp, \"$1\"),\n methods: getRouteMethods(route),\n middlewares: getRouteMiddlewares(route),\n };\n\n return endpoint;\n });\n\n return endpoints;\n};\n\n/**\n * @param {RegExp} expressPathRegExp\n * @param {any[]} keys\n * @returns {string}\n */\nexport const parseExpressPathRegExp = function (expressPathRegExp, keys) {\n let parsedRegExp = expressPathRegExp.toString();\n let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n let paramIndex = 0;\n\n while (hasParams(parsedRegExp)) {\n const paramName = keys[paramIndex].name;\n const paramId = `:${paramName}`;\n\n parsedRegExp = parsedRegExp.replace(\n regExpToReplaceExpressPathRegExpParams,\n (str) => {\n // Express >= 4.20.0 uses a different RegExp for parameters: it\n // captures the slash as part of the parameter. We need to check\n // for this case and add the slash to the value that will replace\n // the parameter in the path.\n if (str.startsWith(\"(?:\\\\/\")) {\n return `\\\\/${paramId}`;\n }\n\n return paramId;\n },\n );\n\n paramIndex++;\n }\n\n if (parsedRegExp !== expressPathRegExp.toString()) {\n expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n }\n\n return expressPathRegExpExec[1].replace(/\\\\\\//g, \"/\");\n};\n\n/**\n * @param {string} expressPath\n * @param {Object.<string, string>} params\n * @returns {string}\n */\nexport const parseExpressPath = function (expressPath, params) {\n let result = expressPath;\n for (const [paramName, paramValue] of Object.entries(params)) {\n result = result.replace(paramValue, `:${paramName}`);\n }\n return result;\n};\n\n/**\n * @param {import('express').Express | import('express').Router | any} app\n * @param {string} [basePath]\n * @param {Endpoint[]} [endpoints]\n * @returns {Endpoint[]}\n */\nconst parseEndpoints = function (app, basePath, endpoints) {\n const routerInfo = getRouterInfo(app);\n const stack = routerInfo.stack;\n const version = routerInfo.version;\n\n endpoints = endpoints || [];\n basePath = basePath || \"\";\n\n if (!stack) {\n if (endpoints.length) {\n endpoints = addEndpoints(endpoints, [\n {\n path: basePath,\n methods: [],\n middlewares: [],\n },\n ]);\n }\n } else {\n endpoints = parseStack(stack, basePath, endpoints, version);\n }\n\n return endpoints;\n};\n\n/**\n * Ensures the path of the new endpoints isn't yet in the array.\n * If the path is already in the array merges the endpoints with the existing\n * one, if not, it adds them to the array.\n *\n * @param {Endpoint[]} currentEndpoints Array of current endpoints\n * @param {Endpoint[]} endpointsToAdd New endpoints to be added to the array\n * @returns {Endpoint[]} Updated endpoints array\n */\nconst addEndpoints = function (currentEndpoints, endpointsToAdd) {\n endpointsToAdd.forEach((newEndpoint) => {\n const existingEndpoint = currentEndpoints.find(\n (endpoint) => endpoint.path === newEndpoint.path,\n );\n\n if (existingEndpoint !== undefined) {\n const newMethods = newEndpoint.methods.filter(\n (method) => !existingEndpoint.methods.includes(method),\n );\n\n existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);\n } else {\n currentEndpoints.push(newEndpoint);\n }\n });\n\n return currentEndpoints;\n};\n\n/**\n * @param {any[]} stack\n * @param {string} basePath\n * @param {Endpoint[]} endpoints\n * @param {'v4' | 'v5'} [version]\n * @returns {Endpoint[]}\n */\nconst parseStack = function (stack, basePath, endpoints, version) {\n stack.forEach((stackItem) => {\n if (stackItem.route) {\n const newEndpoints = parseExpressRoute(stackItem.route, basePath);\n\n endpoints = addEndpoints(endpoints, newEndpoints);\n } else if (STACK_ITEM_VALID_NAMES.includes(stackItem.name)) {\n let newBasePath = basePath;\n\n if (version === \"v4\") {\n const isExpressPathRegExp = regExpToParseExpressPathRegExp.test(\n stackItem.regexp,\n );\n if (isExpressPathRegExp) {\n const parsedPath = parseExpressPathRegExp(\n stackItem.regexp,\n stackItem.keys,\n );\n newBasePath += `/${parsedPath}`;\n } else if (\n !stackItem.path &&\n stackItem.regexp &&\n stackItem.regexp.toString() !== EXPRESS_ROOT_PATH_REGEXP_VALUE\n ) {\n const regExpPath = `RegExp(${stackItem.regexp})`;\n newBasePath += `/${regExpPath}`;\n }\n } else if (version === \"v5\") {\n if (!stackItem.path) {\n return;\n } else if (stackItem.path !== \"/\") {\n newBasePath += stackItem.path.startsWith(\"/\")\n ? stackItem.path\n : `/${stackItem.path}`;\n }\n }\n\n endpoints = parseEndpoints(stackItem.handle, newBasePath, endpoints);\n }\n });\n\n return endpoints;\n};\n\nexport const getEndpoints = function (app, basePath) {\n const endpoints = parseEndpoints(app);\n const standardHttpMethods = [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"];\n return endpoints.flatMap((route) =>\n route.methods\n .filter((method) => standardHttpMethods.includes(method.toUpperCase()))\n .map((method) => ({\n method,\n path: (basePath + route.path).replace(/\\/\\//g, \"/\"),\n })),\n );\n};\n"],"mappings":"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","names":["regExpToParseExpressPathRegExp","regExpToReplaceExpressPathRegExpParams","regexpExpressParamRegexp","regexpExpressPathParamRegexp","EXPRESS_ROOT_PATH_REGEXP_VALUE","STACK_ITEM_VALID_NAMES","getRouterInfo","app","stack","version","_router","router","getRouteMethods","route","methods","Object","keys","filter","method","map","toUpperCase","getRouteMiddlewares","item","handle","name","hasParams","expressPathRegExp","test","parseExpressRoute","basePath","paths","Array","isArray","path","push","endpoints","completePath","endpoint","replace","middlewares","parseExpressPathRegExp","parsedRegExp","toString","expressPathRegExpExec","exec","paramIndex","paramName","paramId","str","startsWith","parseExpressPath","expressPath","params","result","paramValue","entries","parseEndpoints","routerInfo","length","addEndpoints","parseStack","currentEndpoints","endpointsToAdd","forEach","newEndpoint","existingEndpoint","find","undefined","newMethods","includes","concat","stackItem","newEndpoints","newBasePath","isExpressPathRegExp","regexp","parsedPath","regExpPath","getEndpoints","standardHttpMethods","flatMap"]}
|
|
1
|
+
{"version":3,"sources":["../../src/express/utils.js"],"sourcesContent":["// Adapted from https://github.com/AlbertoFdzM/express-list-endpoints/blob/305535d43008b46f34e18b01947762e039af6d2d/src/index.js\n// and also incorporated https://github.com/AlbertoFdzM/express-list-endpoints/pull/96\n// and https://github.com/labithiotis/express-list-routes/blob/5432c83a67c2788c56a1cdfc067ec809961c0c05/index.js\n\n/**\n * @typedef {Object} Route\n * @property {Object} methods\n * @property {string | string[]} path\n * @property {any[]} stack\n *\n * @typedef {Object} Endpoint\n * @property {string} path Path name\n * @property {string[]} methods Methods handled\n * @property {string[]} middlewares Mounted middlewares\n */\n\nconst regExpToParseExpressPathRegExp =\n /^\\/\\^\\\\?\\/?(?:(:?[\\w\\\\.-]*(?:\\\\\\/:?[\\w\\\\.-]*)*)|(\\(\\?:\\\\?\\/?\\([^)]+\\)\\)))\\\\\\/.*/;\nconst regExpToReplaceExpressPathRegExpParams = /\\(\\?:\\\\?\\/?\\([^)]+\\)\\)/;\nconst regExpExpressParamRegExp = /\\(\\?:\\\\?\\\\?\\/?\\([^)]+\\)\\)/g;\nconst regExpExpressPathParamRegExp = /(:[^)]+)\\([^)]+\\)/g;\nconst rootPathRegExpValue = \"/^\\\\/?(?=\\\\/|$)/i\";\nconst stackItemValidNames = [\"router\", \"bound dispatch\", \"mounted_app\"];\n\n/**\n * Strips inline RegExp validators from Express path params, e.g.\n * \"/users/:id(\\\\d+)\" → \"/users/:id\".\n * @param {string} path\n * @returns {string}\n */\nexport const stripExpressPathParamRegex = function (path) {\n return path.replace(regExpExpressPathParamRegExp, \"$1\");\n};\n\n/**\n * Formats a RegExp route as a stable string identifier, e.g.\n * /^\\/foo$/ → \"RegExp(/^\\\\/foo$/)\".\n * @param {RegExp} re\n * @returns {string}\n */\nexport const formatRegExpRoutePath = function (re) {\n return `RegExp(${re})`;\n};\n\n/**\n * Detects Express version and returns router information\n * @param {import('express').Express | import('express').Router | any} app\n * @returns {{stack: any[] | null, version: 'v4' | 'v5'}}\n */\nexport const getRouterInfo = function (app) {\n if (app.stack) {\n // Express 4 router\n return { stack: app.stack, version: \"v4\" };\n } else if (app._router?.stack) {\n // Express 4\n return { stack: app._router.stack, version: \"v4\" };\n } else if (app.router?.stack) {\n // Express 5\n return { stack: app.router.stack, version: \"v5\" };\n }\n return { stack: null, version: \"v4\" };\n};\n\n/**\n * Returns all the verbs detected for the passed route\n * @param {Route} route\n */\nconst getRouteMethods = function (route) {\n let methods = Object.keys(route.methods);\n\n methods = methods.filter((method) => method !== \"_all\");\n methods = methods.map((method) => method.toUpperCase());\n\n return methods;\n};\n\n/**\n * Returns the names (or anonymous) of all the middlewares attached to the\n * passed route\n * @param {Route} route\n * @returns {string[]}\n */\nconst getRouteMiddlewares = function (route) {\n return route.stack.map((item) => {\n return item.handle.name || \"anonymous\";\n });\n};\n\n/**\n * Returns true if found regexp related with express params\n * @param {string} expressPathRegExp\n * @returns {boolean}\n */\nconst hasParams = function (expressPathRegExp) {\n return regExpExpressParamRegExp.test(expressPathRegExp);\n};\n\n/**\n * @param {Route} route Express route object to be parsed\n * @param {string} basePath The basePath the route is on\n * @return {Endpoint[]} Endpoints info\n */\nconst parseExpressRoute = function (route, basePath) {\n // route.path can be a string, a RegExp, or an array of either\n const paths = Array.isArray(route.path) ? route.path : [route.path];\n\n /** @type {Endpoint[]} */\n const endpoints = paths.flatMap((path) => {\n let pathStr;\n if (typeof path === \"string\") {\n pathStr = stripExpressPathParamRegex(path);\n } else if (path instanceof RegExp) {\n pathStr = formatRegExpRoutePath(path);\n } else {\n return [];\n }\n const completePath =\n basePath && pathStr === \"/\" ? basePath : `${basePath}${pathStr}`;\n return [\n {\n path: completePath,\n methods: getRouteMethods(route),\n middlewares: getRouteMiddlewares(route),\n },\n ];\n });\n\n return endpoints;\n};\n\n/**\n * @param {RegExp} expressPathRegExp\n * @param {any[]} keys\n * @returns {string}\n */\nexport const parseExpressPathRegExp = function (expressPathRegExp, keys) {\n let parsedRegExp = expressPathRegExp.toString();\n let expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n let paramIndex = 0;\n\n while (hasParams(parsedRegExp)) {\n const paramName = keys[paramIndex].name;\n const paramId = `:${paramName}`;\n\n parsedRegExp = parsedRegExp.replace(\n regExpToReplaceExpressPathRegExpParams,\n (str) => {\n // Express >= 4.20.0 uses a different RegExp for parameters: it\n // captures the slash as part of the parameter. We need to check\n // for this case and add the slash to the value that will replace\n // the parameter in the path.\n if (str.startsWith(\"(?:\\\\/\")) {\n return `\\\\/${paramId}`;\n }\n\n return paramId;\n },\n );\n\n paramIndex++;\n }\n\n if (parsedRegExp !== expressPathRegExp.toString()) {\n expressPathRegExpExec = regExpToParseExpressPathRegExp.exec(parsedRegExp);\n }\n\n return expressPathRegExpExec[1].replace(/\\\\\\//g, \"/\");\n};\n\n/**\n * @param {string} expressPath\n * @param {Object.<string, string>} params\n * @returns {string}\n */\nexport const parseExpressPath = function (expressPath, params) {\n let result = expressPath;\n for (const [paramName, paramValue] of Object.entries(params)) {\n result = result.replace(paramValue, `:${paramName}`);\n }\n return result;\n};\n\n/**\n * @param {import('express').Express | import('express').Router | any} app\n * @param {string} [basePath]\n * @param {Endpoint[]} [endpoints]\n * @returns {Endpoint[]}\n */\nconst parseEndpoints = function (app, basePath, endpoints) {\n const routerInfo = getRouterInfo(app);\n const stack = routerInfo.stack;\n const version = routerInfo.version;\n\n endpoints = endpoints || [];\n basePath = basePath || \"\";\n\n if (!stack) {\n if (endpoints.length) {\n endpoints = addEndpoints(endpoints, [\n {\n path: basePath,\n methods: [],\n middlewares: [],\n },\n ]);\n }\n } else {\n endpoints = parseStack(stack, basePath, endpoints, version);\n }\n\n return endpoints;\n};\n\n/**\n * Ensures the path of the new endpoints isn't yet in the array.\n * If the path is already in the array merges the endpoints with the existing\n * one, if not, it adds them to the array.\n *\n * @param {Endpoint[]} currentEndpoints Array of current endpoints\n * @param {Endpoint[]} endpointsToAdd New endpoints to be added to the array\n * @returns {Endpoint[]} Updated endpoints array\n */\nconst addEndpoints = function (currentEndpoints, endpointsToAdd) {\n endpointsToAdd.forEach((newEndpoint) => {\n const existingEndpoint = currentEndpoints.find(\n (endpoint) => endpoint.path === newEndpoint.path,\n );\n\n if (existingEndpoint !== undefined) {\n const newMethods = newEndpoint.methods.filter(\n (method) => !existingEndpoint.methods.includes(method),\n );\n\n existingEndpoint.methods = existingEndpoint.methods.concat(newMethods);\n } else {\n currentEndpoints.push(newEndpoint);\n }\n });\n\n return currentEndpoints;\n};\n\n/**\n * @param {any[]} stack\n * @param {string} basePath\n * @param {Endpoint[]} endpoints\n * @param {'v4' | 'v5'} [version]\n * @returns {Endpoint[]}\n */\nconst parseStack = function (stack, basePath, endpoints, version) {\n stack.forEach((stackItem) => {\n if (stackItem.route) {\n const newEndpoints = parseExpressRoute(stackItem.route, basePath);\n\n endpoints = addEndpoints(endpoints, newEndpoints);\n } else if (stackItemValidNames.includes(stackItem.name)) {\n let newBasePath = basePath;\n\n if (version === \"v4\") {\n const isExpressPathRegExp = regExpToParseExpressPathRegExp.test(\n stackItem.regexp,\n );\n if (isExpressPathRegExp) {\n const parsedPath = parseExpressPathRegExp(\n stackItem.regexp,\n stackItem.keys,\n );\n newBasePath += `/${parsedPath}`;\n } else if (\n !stackItem.path &&\n stackItem.regexp &&\n stackItem.regexp.toString() !== rootPathRegExpValue\n ) {\n newBasePath += `/${formatRegExpRoutePath(stackItem.regexp)}`;\n }\n } else if (version === \"v5\") {\n if (!stackItem.path) {\n return;\n } else if (stackItem.path !== \"/\") {\n newBasePath += stackItem.path.startsWith(\"/\")\n ? stackItem.path\n : `/${stackItem.path}`;\n }\n }\n\n endpoints = parseEndpoints(stackItem.handle, newBasePath, endpoints);\n }\n });\n\n return endpoints;\n};\n\nexport const getEndpoints = function (app, basePath) {\n const endpoints = parseEndpoints(app);\n const standardHttpMethods = [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"];\n return endpoints.flatMap((route) =>\n route.methods\n .filter((method) => standardHttpMethods.includes(method.toUpperCase()))\n .map((method) => ({\n method,\n path: (basePath + route.path).replace(/\\/\\//g, \"/\"),\n })),\n );\n};\n"],"mappings":"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","names":["regExpToParseExpressPathRegExp","regExpToReplaceExpressPathRegExpParams","regExpExpressParamRegExp","regExpExpressPathParamRegExp","rootPathRegExpValue","stackItemValidNames","stripExpressPathParamRegex","path","replace","formatRegExpRoutePath","re","getRouterInfo","app","stack","version","_router","router","getRouteMethods","route","methods","Object","keys","filter","method","map","toUpperCase","getRouteMiddlewares","item","handle","name","hasParams","expressPathRegExp","test","parseExpressRoute","basePath","paths","Array","isArray","endpoints","flatMap","pathStr","RegExp","completePath","middlewares","parseExpressPathRegExp","parsedRegExp","toString","expressPathRegExpExec","exec","paramIndex","paramName","paramId","str","startsWith","parseExpressPath","expressPath","params","result","paramValue","entries","parseEndpoints","routerInfo","length","addEndpoints","parseStack","currentEndpoints","endpointsToAdd","forEach","newEndpoint","existingEndpoint","find","endpoint","undefined","newMethods","includes","concat","push","stackItem","newEndpoints","newBasePath","isExpressPathRegExp","regexp","parsedPath","getEndpoints","standardHttpMethods"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apitally",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.6",
|
|
4
4
|
"description": "Simple API monitoring & analytics for REST APIs built with Express, Fastify, NestJS, AdonisJS, Hono, H3, Elysia, Hapi, and Koa.",
|
|
5
5
|
"author": "Apitally <hello@apitally.io>",
|
|
6
6
|
"license": "MIT",
|