{"version":3,"file":"routeHandler.cjs","sources":["../../src/routeHandler.ts"],"sourcesContent":["import { EVENT, Logger, LogLevel } from '@axiomhq/logging';\nimport * as next from 'next/server';\nimport { runWithServerContext, ServerContextFields } from './context';\nimport { getAccessFallbackHTTPStatus, isHTTPAccessFallbackError } from 'src/lib/next-http-errors';\nimport { getRedirectStatus, isRedirectError } from 'src/lib/next-redirect-errors';\nimport { NextRequest, NextResponse } from 'next/server';\nimport { isEdgeRuntime } from 'src/lib/runtime';\n\n/**\n * If we don't use a constant + access via bracket notation, webpack will throw an error when after is not exported\n */\nconst AFTER = 'after' as const;\nconst after = AFTER in next ? next[AFTER] : undefined;\n\nexport type NextHandler<T = Request, A = any, R extends Response = Response> = (\n  req: T extends Request ? T : Request,\n  arg?: A,\n) => Promise<R> | Promise<NextResponse> | NextResponse | R;\n\nexport const transformRouteHandlerSuccessResult = (\n  data: SuccessData,\n): [message: string, report: Record<string | symbol, any>] => {\n  const request = {\n    startTime: data.start,\n    endTime: data.end,\n    path: 'nextUrl' in data.req ? (data.req.nextUrl as URL).pathname : new URL(data.req.url).pathname,\n    method: data.req.method,\n    host: data.req.headers.get('host'),\n    userAgent: data.req.headers.get('user-agent'),\n    scheme: data.req.url.split('://')[0],\n    ip: data.req.headers.get('x-forwarded-for'),\n    region: 'geo' in data.req ? (data.req.geo as { region: string }).region ?? undefined : undefined,\n    statusCode: data.res.status,\n  };\n\n  const report = {\n    [EVENT]: { request, source: isEdgeRuntime ? 'edge' : 'lambda' },\n  };\n\n  return [\n    `${request.method} ${request.path} ${request.statusCode} in ${request.endTime - request.startTime}ms`,\n    report,\n  ];\n};\n\nexport const transformRouteHandlerErrorResult = (\n  data: ErrorData,\n): [message: string, report: Record<string | symbol, any>] => {\n  const statusCode = data.error instanceof Error ? getNextErrorStatusCode(data.error) : 500;\n\n  const request = {\n    startTime: data.start,\n    endTime: data.end,\n    path: 'nextUrl' in data.req ? (data.req.nextUrl as URL).pathname : new URL(data.req.url).pathname,\n    method: data.req.method,\n    host: data.req.headers.get('host'),\n    userAgent: data.req.headers.get('user-agent'),\n    scheme: data.req.url.split('://')[0],\n    ip: data.req.headers.get('x-forwarded-for'),\n    region: 'geo' in data.req ? (data.req.geo as { region: string }).region ?? '' : '',\n    statusCode: statusCode,\n  };\n\n  const report = {\n    [EVENT]: { request, source: isEdgeRuntime ? 'edge' : 'lambda' },\n  };\n\n  return [\n    `${request.method} ${request.path} ${request.statusCode} in ${request.endTime - request.startTime}ms`,\n    report,\n  ];\n};\n\nexport interface BaseData<T = Request> {\n  req: T extends Request ? T : Request;\n  start: number;\n  end: number;\n}\n\nexport interface SuccessData<T = Request, R extends Response = Response> extends BaseData<T> {\n  res: R;\n}\n\nexport interface ErrorData<T = Request> extends BaseData<T> {\n  error: Error | unknown;\n}\n\nexport type AxiomHandlerCallbackParams<T = Request, R extends Response = Response> =\n  | {\n      ok: true;\n      data: SuccessData<T, R>;\n    }\n  | { ok: false; data: ErrorData<T> };\n\nexport type axiomHandlerCallback<T = Request, R extends Response = Response> = (\n  result: AxiomHandlerCallbackParams<T, R>,\n) => void | Promise<void>;\n\nexport const getNextErrorStatusCode = (error: Error & { digest?: string }) => {\n  if (isRedirectError(error)) {\n    return getRedirectStatus(error);\n  } else if (isHTTPAccessFallbackError(error)) {\n    return getAccessFallbackHTTPStatus(error);\n  }\n\n  return 500;\n};\n\nexport const getLogLevelFromStatusCode = (statusCode: number): LogLevel => {\n  if (statusCode >= 300 && statusCode < 400) {\n    return LogLevel.info;\n  } else if (statusCode >= 400 && statusCode < 500) {\n    return LogLevel.warn;\n  }\n  return LogLevel.error;\n};\n\nexport const defaultRouteHandlerOnSuccess = async (logger: Logger, data: SuccessData) => {\n  logger.info(...transformRouteHandlerSuccessResult(data));\n  await logger.flush();\n};\n\nconst defaultRouteHandlerOnError = async (logger: Logger, data: ErrorData) => {\n  if (data.error instanceof Error) {\n    logger.error(data.error.message, data.error);\n  }\n  const [message, report] = transformRouteHandlerErrorResult(data);\n  logger.log(getLogLevelFromStatusCode(report.statusCsode), message, report);\n  await logger.flush();\n};\n\nconst getStore = async <T = Request, C extends any = any>({\n  store,\n  req,\n  ctx,\n}: {\n  store?:\n    | ServerContextFields\n    | ((req: T extends Request ? T : Request, ctx: C) => ServerContextFields | Promise<ServerContextFields>);\n  req: T extends Request ? T : Request;\n  ctx: C;\n}) => {\n  if (!store) {\n    const newStore = new Map();\n    newStore.set('request_id', globalThis.crypto.randomUUID());\n    newStore.set('source', isEdgeRuntime ? 'edge' : 'lambda');\n    return newStore;\n  }\n  if (typeof store === 'function') {\n    return await store(req, ctx);\n  }\n\n  // Always add source to the store\n  if (store instanceof Map) {\n    store.set(EVENT, { source: isEdgeRuntime ? 'edge' : 'lambda' });\n  } else {\n    store[EVENT] = { source: isEdgeRuntime ? 'edge' : 'lambda' };\n  }\n\n  return store;\n};\n\nexport const createAxiomRouteHandler = <TRequestCreateRouteHandler = NextRequest>(\n  logger: Logger,\n  config?: {\n    store?:\n      | ServerContextFields\n      | (<TRequestStore = TRequestCreateRouteHandler, C extends any = any>(\n          req: TRequestStore,\n          ctx: C,\n        ) => ServerContextFields | Promise<ServerContextFields>);\n    onSuccess?: (data: SuccessData) => void;\n    onError?: (data: ErrorData) => void;\n  },\n) => {\n  const { store: argStore, onSuccess, onError } = config ?? {};\n  const withAxiom = <TRequestRouteHandler = TRequestCreateRouteHandler>(handler: NextHandler<TRequestRouteHandler>) => {\n    return async <C extends any = any>(\n      req: TRequestRouteHandler extends Request ? TRequestRouteHandler : Request,\n      ctx: C,\n    ) => {\n      const store = await getStore({ store: argStore, req, ctx });\n\n      return runWithServerContext(async () => {\n        const start = Date.now();\n\n        try {\n          const response = await handler(req, ctx);\n          const end = Date.now();\n          const httpData = { req, res: response, start, end };\n\n          const callbackFn = async () => {\n            if (onSuccess) {\n              onSuccess(httpData);\n            } else {\n              await defaultRouteHandlerOnSuccess(logger, httpData);\n            }\n          };\n          // TODO: this surely can be written better\n          if (typeof after !== 'undefined') {\n            after(callbackFn());\n          } else {\n            await callbackFn();\n          }\n\n          return response;\n        } catch (error) {\n          const end = Date.now();\n          const callbackFn = async () => {\n            if (onError) {\n              onError({ req, error, start, end });\n            } else {\n              defaultRouteHandlerOnError(logger, { req, error, start, end });\n            }\n          };\n          if (typeof after !== 'undefined') {\n            after(callbackFn());\n          } else {\n            await callbackFn();\n          }\n          throw error;\n        }\n      }, store);\n    };\n  };\n\n  return withAxiom;\n};\n"],"names":["next","EVENT","isEdgeRuntime","isRedirectError","getRedirectStatus","isHTTPAccessFallbackError","getAccessFallbackHTTPStatus","LogLevel","runWithServerContext"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAWA,MAAM,QAAQ;AACd,MAAM,QAAQ,SAASA,kBAAOA,gBAAK,KAAK,IAAI;AAOrC,MAAM,qCAAqC,CAChD,SAC4D;AAC5D,QAAM,UAAU;AAAA,IACd,WAAW,KAAK;AAAA,IAChB,SAAS,KAAK;AAAA,IACd,MAAM,aAAa,KAAK,MAAO,KAAK,IAAI,QAAgB,WAAW,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE;AAAA,IACzF,QAAQ,KAAK,IAAI;AAAA,IACjB,MAAM,KAAK,IAAI,QAAQ,IAAI,MAAM;AAAA,IACjC,WAAW,KAAK,IAAI,QAAQ,IAAI,YAAY;AAAA,IAC5C,QAAQ,KAAK,IAAI,IAAI,MAAM,KAAK,EAAE,CAAC;AAAA,IACnC,IAAI,KAAK,IAAI,QAAQ,IAAI,iBAAiB;AAAA,IAC1C,QAAQ,SAAS,KAAK,MAAO,KAAK,IAAI,IAA2B,UAAU,SAAY;AAAA,IACvF,YAAY,KAAK,IAAI;AAAA,EAAA;AAGvB,QAAM,SAAS;AAAA,IACb,CAACC,QAAAA,KAAK,GAAG,EAAE,SAAS,QAAQC,QAAAA,gBAAgB,SAAS,SAAA;AAAA,EAAS;AAGhE,SAAO;AAAA,IACL,GAAG,QAAQ,MAAM,IAAI,QAAQ,IAAI,IAAI,QAAQ,UAAU,OAAO,QAAQ,UAAU,QAAQ,SAAS;AAAA,IACjG;AAAA,EAAA;AAEJ;AAEO,MAAM,mCAAmC,CAC9C,SAC4D;AAC5D,QAAM,aAAa,KAAK,iBAAiB,QAAQ,uBAAuB,KAAK,KAAK,IAAI;AAEtF,QAAM,UAAU;AAAA,IACd,WAAW,KAAK;AAAA,IAChB,SAAS,KAAK;AAAA,IACd,MAAM,aAAa,KAAK,MAAO,KAAK,IAAI,QAAgB,WAAW,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE;AAAA,IACzF,QAAQ,KAAK,IAAI;AAAA,IACjB,MAAM,KAAK,IAAI,QAAQ,IAAI,MAAM;AAAA,IACjC,WAAW,KAAK,IAAI,QAAQ,IAAI,YAAY;AAAA,IAC5C,QAAQ,KAAK,IAAI,IAAI,MAAM,KAAK,EAAE,CAAC;AAAA,IACnC,IAAI,KAAK,IAAI,QAAQ,IAAI,iBAAiB;AAAA,IAC1C,QAAQ,SAAS,KAAK,MAAO,KAAK,IAAI,IAA2B,UAAU,KAAK;AAAA,IAChF;AAAA,EAAA;AAGF,QAAM,SAAS;AAAA,IACb,CAACD,QAAAA,KAAK,GAAG,EAAE,SAAS,QAAQC,QAAAA,gBAAgB,SAAS,SAAA;AAAA,EAAS;AAGhE,SAAO;AAAA,IACL,GAAG,QAAQ,MAAM,IAAI,QAAQ,IAAI,IAAI,QAAQ,UAAU,OAAO,QAAQ,UAAU,QAAQ,SAAS;AAAA,IACjG;AAAA,EAAA;AAEJ;AA2BO,MAAM,yBAAyB,CAAC,UAAuC;AAC5E,MAAIC,mBAAAA,gBAAgB,KAAK,GAAG;AAC1B,WAAOC,mBAAAA,kBAAkB,KAAK;AAAA,EAChC,WAAWC,yCAA0B,KAAK,GAAG;AAC3C,WAAOC,eAAAA,4BAA4B,KAAK;AAAA,EAC1C;AAEA,SAAO;AACT;AAEO,MAAM,4BAA4B,CAAC,eAAiC;AACzE,MAAI,cAAc,OAAO,aAAa,KAAK;AACzC,WAAOC,QAAAA,SAAS;AAAA,EAClB,WAAW,cAAc,OAAO,aAAa,KAAK;AAChD,WAAOA,QAAAA,SAAS;AAAA,EAClB;AACA,SAAOA,QAAAA,SAAS;AAClB;AAEO,MAAM,+BAA+B,OAAO,QAAgB,SAAsB;AACvF,SAAO,KAAK,GAAG,mCAAmC,IAAI,CAAC;AACvD,QAAM,OAAO,MAAA;AACf;AAEA,MAAM,6BAA6B,OAAO,QAAgB,SAAoB;AAC5E,MAAI,KAAK,iBAAiB,OAAO;AAC/B,WAAO,MAAM,KAAK,MAAM,SAAS,KAAK,KAAK;AAAA,EAC7C;AACA,QAAM,CAAC,SAAS,MAAM,IAAI,iCAAiC,IAAI;AAC/D,SAAO,IAAI,0BAA0B,OAAO,WAAW,GAAG,SAAS,MAAM;AACzE,QAAM,OAAO,MAAA;AACf;AAEA,MAAM,WAAW,OAAyC;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AACF,MAMM;AACJ,MAAI,CAAC,OAAO;AACV,UAAM,+BAAe,IAAA;AACrB,aAAS,IAAI,cAAc,WAAW,OAAO,YAAY;AACzD,aAAS,IAAI,UAAUL,QAAAA,gBAAgB,SAAS,QAAQ;AACxD,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,YAAY;AAC/B,WAAO,MAAM,MAAM,KAAK,GAAG;AAAA,EAC7B;AAGA,MAAI,iBAAiB,KAAK;AACxB,UAAM,IAAID,eAAO,EAAE,QAAQC,wBAAgB,SAAS,UAAU;AAAA,EAChE,OAAO;AACL,UAAMD,QAAAA,KAAK,IAAI,EAAE,QAAQC,QAAAA,gBAAgB,SAAS,SAAA;AAAA,EACpD;AAEA,SAAO;AACT;AAEO,MAAM,0BAA0B,CACrC,QACA,WAUG;AACH,QAAM,EAAE,OAAO,UAAU,WAAW,QAAA,IAAY,UAAU,CAAA;AAC1D,QAAM,YAAY,CAAoD,YAA+C;AACnH,WAAO,OACL,KACA,QACG;AACH,YAAM,QAAQ,MAAM,SAAS,EAAE,OAAO,UAAU,KAAK,KAAK;AAE1D,aAAOM,QAAAA,qBAAqB,YAAY;AACtC,cAAM,QAAQ,KAAK,IAAA;AAEnB,YAAI;AACF,gBAAM,WAAW,MAAM,QAAQ,KAAK,GAAG;AACvC,gBAAM,MAAM,KAAK,IAAA;AACjB,gBAAM,WAAW,EAAE,KAAK,KAAK,UAAU,OAAO,IAAA;AAE9C,gBAAM,aAAa,YAAY;AAC7B,gBAAI,WAAW;AACb,wBAAU,QAAQ;AAAA,YACpB,OAAO;AACL,oBAAM,6BAA6B,QAAQ,QAAQ;AAAA,YACrD;AAAA,UACF;AAEA,cAAI,OAAO,UAAU,aAAa;AAChC,kBAAM,YAAY;AAAA,UACpB,OAAO;AACL,kBAAM,WAAA;AAAA,UACR;AAEA,iBAAO;AAAA,QACT,SAAS,OAAO;AACd,gBAAM,MAAM,KAAK,IAAA;AACjB,gBAAM,aAAa,YAAY;AAC7B,gBAAI,SAAS;AACX,sBAAQ,EAAE,KAAK,OAAO,OAAO,KAAK;AAAA,YACpC,OAAO;AACL,yCAA2B,QAAQ,EAAE,KAAK,OAAO,OAAO,KAAK;AAAA,YAC/D;AAAA,UACF;AACA,cAAI,OAAO,UAAU,aAAa;AAChC,kBAAM,YAAY;AAAA,UACpB,OAAO;AACL,kBAAM,WAAA;AAAA,UACR;AACA,gBAAM;AAAA,QACR;AAAA,MACF,GAAG,KAAK;AAAA,IACV;AAAA,EACF;AAEA,SAAO;AACT;;;;;;;"}