{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Attributes } from '@opentelemetry/api';\nimport {\n  IgnoreMatcher,\n  ExpressInstrumentationConfig,\n  LayerPathSegment,\n} from './types';\nimport { ExpressLayerType } from './enums/ExpressLayerType';\nimport { AttributeNames } from './enums/AttributeNames';\nimport {\n  ExpressLayer,\n  PatchedRequest,\n  _LAYERS_STORE_PROPERTY,\n} from './internal-types';\n\n/**\n * Store layers path in the request to be able to construct route later\n * @param request The request where\n * @param [value] the value to push into the array\n */\nexport const storeLayerPath = (\n  request: PatchedRequest,\n  value?: string\n): { isLayerPathStored: boolean } => {\n  if (Array.isArray(request[_LAYERS_STORE_PROPERTY]) === false) {\n    Object.defineProperty(request, _LAYERS_STORE_PROPERTY, {\n      enumerable: false,\n      value: [],\n    });\n  }\n  if (value === undefined) return { isLayerPathStored: false };\n\n  (request[_LAYERS_STORE_PROPERTY] as string[]).push(value);\n\n  return { isLayerPathStored: true };\n};\n\n/**\n * Recursively search the router path from layer stack\n * @param path The path to reconstruct\n * @param layer The layer to reconstruct from\n * @returns The reconstructed path\n */\nexport const getRouterPath = (path: string, layer: ExpressLayer): string => {\n  const stackLayer = layer.handle?.stack?.[0];\n\n  if (stackLayer?.route?.path) {\n    return `${path}${stackLayer.route.path}`;\n  }\n\n  if (stackLayer?.handle?.stack) {\n    return getRouterPath(path, stackLayer);\n  }\n\n  return path;\n};\n\n/**\n * Parse express layer context to retrieve a name and attributes.\n * @param route The route of the layer\n * @param layer Express layer\n * @param [layerPath] if present, the path on which the layer has been mounted\n */\nexport const getLayerMetadata = (\n  route: string,\n  layer: ExpressLayer,\n  layerPath?: string\n): {\n  attributes: Attributes;\n  name: string;\n} => {\n  if (layer.name === 'router') {\n    const maybeRouterPath = getRouterPath('', layer);\n    const extractedRouterPath = maybeRouterPath\n      ? maybeRouterPath\n      : layerPath || route || '/';\n\n    return {\n      attributes: {\n        [AttributeNames.EXPRESS_NAME]: extractedRouterPath,\n        [AttributeNames.EXPRESS_TYPE]: ExpressLayerType.ROUTER,\n      },\n      name: `router - ${extractedRouterPath}`,\n    };\n  } else if (layer.name === 'bound dispatch' || layer.name === 'handle') {\n    return {\n      attributes: {\n        [AttributeNames.EXPRESS_NAME]:\n          (route || layerPath) ?? 'request handler',\n        [AttributeNames.EXPRESS_TYPE]: ExpressLayerType.REQUEST_HANDLER,\n      },\n      name: `request handler${layer.path ? ` - ${route || layerPath}` : ''}`,\n    };\n  } else {\n    return {\n      attributes: {\n        [AttributeNames.EXPRESS_NAME]: layer.name,\n        [AttributeNames.EXPRESS_TYPE]: ExpressLayerType.MIDDLEWARE,\n      },\n      name: `middleware - ${layer.name}`,\n    };\n  }\n};\n\n/**\n * Check whether the given obj match pattern\n * @param constant e.g URL of request\n * @param obj obj to inspect\n * @param pattern Match pattern\n */\nconst satisfiesPattern = (\n  constant: string,\n  pattern: IgnoreMatcher\n): boolean => {\n  if (typeof pattern === 'string') {\n    return pattern === constant;\n  } else if (pattern instanceof RegExp) {\n    return pattern.test(constant);\n  } else if (typeof pattern === 'function') {\n    return pattern(constant);\n  } else {\n    throw new TypeError('Pattern is in unsupported datatype');\n  }\n};\n\n/**\n * Check whether the given request is ignored by configuration\n * It will not re-throw exceptions from `list` provided by the client\n * @param constant e.g URL of request\n * @param [list] List of ignore patterns\n * @param [onException] callback for doing something when an exception has\n *     occurred\n */\nexport const isLayerIgnored = (\n  name: string,\n  type: ExpressLayerType,\n  config?: ExpressInstrumentationConfig\n): boolean => {\n  if (\n    Array.isArray(config?.ignoreLayersType) &&\n    config?.ignoreLayersType?.includes(type)\n  ) {\n    return true;\n  }\n  if (Array.isArray(config?.ignoreLayers) === false) return false;\n  try {\n    for (const pattern of config!.ignoreLayers!) {\n      if (satisfiesPattern(name, pattern)) {\n        return true;\n      }\n    }\n  } catch (e) {\n    /* catch block*/\n  }\n\n  return false;\n};\n\n/**\n * Converts a user-provided error value into an error and error message pair\n *\n * @param error - User-provided error value\n * @returns Both an Error or string representation of the value and an error message\n */\nexport const asErrorAndMessage = (\n  error: unknown\n): [error: string | Error, message: string] =>\n  error instanceof Error\n    ? [error, error.message]\n    : [String(error), String(error)];\n\n/**\n * Extracts the layer path from the route arguments\n *\n * @param args - Arguments of the route\n * @returns The layer path\n */\nexport const getLayerPath = (\n  args: [LayerPathSegment | LayerPathSegment[], ...unknown[]]\n): string | undefined => {\n  const firstArg = args[0];\n\n  if (Array.isArray(firstArg)) {\n    return firstArg.map(arg => extractLayerPathSegment(arg) || '').join(',');\n  }\n\n  return extractLayerPathSegment(firstArg);\n};\n\nconst extractLayerPathSegment = (arg: LayerPathSegment) => {\n  if (typeof arg === 'string') {\n    return arg;\n  }\n\n  if (arg instanceof RegExp || typeof arg === 'number') {\n    return arg.toString();\n  }\n\n  return;\n};\n\nexport function getConstructedRoute(req: {\n  originalUrl: PatchedRequest['originalUrl'];\n  [_LAYERS_STORE_PROPERTY]?: string[];\n}) {\n  const layersStore: string[] = Array.isArray(req[_LAYERS_STORE_PROPERTY])\n    ? (req[_LAYERS_STORE_PROPERTY] as string[])\n    : [];\n\n  const meaningfulPaths = layersStore.filter(\n    path => path !== '/' && path !== '/*'\n  );\n\n  if (meaningfulPaths.length === 1 && meaningfulPaths[0] === '*') {\n    return '*';\n  }\n\n  // Join parts and remove duplicate slashes\n  return meaningfulPaths.join('').replace(/\\/{2,}/g, '/');\n}\n\n/**\n * Extracts the actual matched route from Express request for OpenTelemetry instrumentation.\n * Returns the route that should be used as the http.route attribute.\n *\n * @param req - The Express request object with layers store\n * @param layersStoreProperty - The property name where layer paths are stored\n * @returns The matched route string or undefined if no valid route is found\n */\nexport function getActualMatchedRoute(req: {\n  originalUrl: PatchedRequest['originalUrl'];\n  [_LAYERS_STORE_PROPERTY]?: string[];\n}): string | undefined {\n  const layersStore: string[] = Array.isArray(req[_LAYERS_STORE_PROPERTY])\n    ? (req[_LAYERS_STORE_PROPERTY] as string[])\n    : [];\n\n  // If no layers are stored, no route can be determined\n  if (layersStore.length === 0) {\n    return undefined;\n  }\n\n  // Handle root path case - if all paths are root, only return root if originalUrl is also root\n  // The layer store also includes root paths in case a non-existing url was requested\n  if (layersStore.every(path => path === '/')) {\n    return req.originalUrl === '/' ? '/' : undefined;\n  }\n\n  const constructedRoute = getConstructedRoute(req);\n  if (constructedRoute === '*') {\n    return constructedRoute;\n  }\n\n  // For RegExp routes or route arrays, return the constructed route\n  // This handles the case where the route is defined using RegExp or an array\n  if (\n    constructedRoute.includes('/') &&\n    (constructedRoute.includes(',') ||\n      constructedRoute.includes('\\\\') ||\n      constructedRoute.includes('*') ||\n      constructedRoute.includes('['))\n  ) {\n    return constructedRoute;\n  }\n\n  // Ensure route starts with '/' if it doesn't already\n  const normalizedRoute = constructedRoute.startsWith('/')\n    ? constructedRoute\n    : `/${constructedRoute}`;\n\n  // Validate that this appears to be a matched route\n  // A route is considered matched if:\n  // 1. We have a constructed route\n  // 2. The original URL matches or starts with our route pattern\n  const isValidRoute =\n    normalizedRoute.length > 0 &&\n    (req.originalUrl === normalizedRoute ||\n      req.originalUrl.startsWith(normalizedRoute) ||\n      isRoutePattern(normalizedRoute));\n\n  return isValidRoute ? normalizedRoute : undefined;\n}\n\n/**\n * Checks if a route contains parameter patterns (e.g., :id, :userId)\n * which are valid even if they don't exactly match the original URL\n */\nfunction isRoutePattern(route: string): boolean {\n  return route.includes(':') || route.includes('*');\n}\n"]}