{"version":3,"sources":["../src/nextjs.ts","../src/utils.ts"],"sourcesContent":["import type { SnapWyrConfig, LogEntry } from '@snapwyr/core';\nimport { generateRequestId } from '@snapwyr/core';\nimport { logRequest } from './utils.js';\n\ninterface NextRequest {\n  method: string;\n  url: string;\n  nextUrl: { pathname: string; search: string };\n  headers: Headers;\n  clone(): NextRequest;\n  text(): Promise<string>;\n}\n\ninterface NextResponseInit {\n  status?: number;\n  headers?: Record<string, string> | [string, string][];\n}\n\ndeclare class NextResponseClass {\n  status: number;\n  headers: Headers;\n  static next(init?: NextResponseInit): NextResponseClass;\n}\n\ntype ProxyFunction = (\n  request: NextRequest\n) => NextResponseClass | Promise<NextResponseClass>;\n\n/**\n * @example\n * ```ts\n * export const proxy = snapwyr({ logBody: true });\n * ```\n */\nexport function snapwyr(config: SnapWyrConfig = {}): ProxyFunction {\n  return async function proxy(request) {\n    // eslint-disable-next-line @typescript-eslint/no-require-imports\n    const { NextResponse } = require('next/server') as {\n      NextResponse: typeof NextResponseClass;\n    };\n\n    if (config.enabled === false) return NextResponse.next();\n\n    const id = generateRequestId();\n    const startTime = Date.now();\n    const method = request.method;\n    const url = request.nextUrl.pathname + request.nextUrl.search;\n\n    // Check ignore patterns\n    if (config.ignorePatterns) {\n      const shouldIgnore = config.ignorePatterns.some((pattern) => {\n        if (typeof pattern === 'string') {\n          return url.includes(pattern);\n        }\n        return pattern.test(url);\n      });\n      if (shouldIgnore) return NextResponse.next();\n    }\n\n    if (config.methods && config.methods.length > 0) {\n      if (!config.methods.includes(method.toUpperCase())) {\n        return NextResponse.next();\n      }\n    }\n\n    let requestBody: string | undefined;\n    if (config.logBody) {\n      try {\n        const body = await request\n          .clone()\n          .text()\n          .catch(() => null);\n        if (body) requestBody = body.slice(0, config.bodySizeLimit || 500);\n      } catch {}\n    }\n\n    const response = NextResponse.next();\n    if (config.requestId) response.headers.set('X-Request-ID', id);\n\n    const duration = Date.now() - startTime;\n    const status = response.status;\n\n    // Check status codes filter\n    if (\n      config.statusCodes &&\n      config.statusCodes.length > 0 &&\n      !config.statusCodes.includes(status)\n    ) {\n      return response;\n    }\n\n    if (config.errorsOnly && status < 400) {\n      return response;\n    }\n\n    logRequest({\n      id,\n      method,\n      status,\n      duration,\n      url,\n      startTime,\n      config,\n      requestBody: config.logBody ? requestBody : undefined,\n    });\n\n    return response;\n  };\n}\n\nexport type { SnapWyrConfig, LogEntry };\n","import type { SnapWyrConfig, LogEntry } from '@snapwyr/core';\nimport {\n  snapwyr as coreEmitter,\n  getByteSize,\n  formatBytes,\n  redactSensitiveData,\n} from '@snapwyr/core';\n\nexport interface LogParams {\n  id: string;\n  method: string;\n  status: number;\n  duration: number;\n  url: string;\n  startTime: number;\n  config: SnapWyrConfig;\n  requestBody?: string;\n  responseBody?: string;\n  error?: string;\n}\n\nexport function logRequest(params: LogParams): void {\n  const { id, method, status, duration, url, startTime, config, error } =\n    params;\n  let { requestBody, responseBody } = params;\n\n  if (config.silent) return;\n\n  const showTimestamp = config.showTimestamp !== false;\n  const format = config.format || 'pretty';\n  const slowThreshold = config.slowThreshold ?? 1000;\n  const isSlow = duration >= slowThreshold;\n\n  const requestSize = requestBody ? getByteSize(requestBody) : 0;\n  const responseSize = responseBody ? getByteSize(responseBody) : 0;\n  const totalSize = requestSize + responseSize;\n\n  if (config.redact && config.redact.length > 0) {\n    if (requestBody)\n      requestBody = redactSensitiveData(requestBody, config.redact);\n    if (responseBody)\n      responseBody = redactSensitiveData(responseBody, config.redact);\n  }\n\n  const logEntry: LogEntry = {\n    id,\n    timestamp: new Date(startTime).toISOString(),\n    method: method.toUpperCase(),\n    url,\n    status,\n    duration,\n    slow: isSlow,\n  };\n\n  if (config.prefix) logEntry.prefix = config.prefix;\n  if (error) logEntry.error = error;\n  if (requestBody) logEntry.requestBody = requestBody;\n  if (responseBody) logEntry.responseBody = responseBody;\n  if (config.sizeTracking) {\n    logEntry.requestSize = requestSize;\n    logEntry.responseSize = responseSize;\n    logEntry.totalSize = totalSize;\n  }\n\n  try {\n    coreEmitter.emit('request', {\n      id,\n      method: method.toUpperCase(),\n      url,\n      status,\n      duration,\n      timestamp: startTime,\n      requestBody,\n      responseBody,\n      error,\n      requestSize: config.sizeTracking ? requestSize : undefined,\n      responseSize: config.sizeTracking ? responseSize : undefined,\n      direction: 'incoming',\n    });\n  } catch {}\n\n  if (config.transport) {\n    config.transport(logEntry);\n  }\n\n  if (format === 'json') {\n    console.log(JSON.stringify(logEntry));\n    return;\n  }\n\n  const useEmoji = config.emoji === true;\n  let statusEmoji = '';\n  if (useEmoji) {\n    if (error || status >= 500) statusEmoji = '✗ ';\n    else if (status >= 400) statusEmoji = '⚠ ';\n    else if (status >= 300) statusEmoji = '↪ ';\n    else statusEmoji = '✓ ';\n  }\n\n  const statusColor =\n    status >= 500\n      ? '\\x1b[31m'\n      : status >= 400\n        ? '\\x1b[33m'\n        : status >= 300\n          ? '\\x1b[36m'\n          : '\\x1b[32m';\n  const durationColor = isSlow\n    ? '\\x1b[31m'\n    : duration < 100\n      ? '\\x1b[32m'\n      : '\\x1b[33m';\n  const methodColors: Record<string, string> = {\n    GET: '\\x1b[34m',\n    POST: '\\x1b[32m',\n    PUT: '\\x1b[33m',\n    PATCH: '\\x1b[35m',\n    DELETE: '\\x1b[31m',\n  };\n  const methodColor = methodColors[method] || '';\n  const reset = '\\x1b[0m';\n  const dim = '\\x1b[2m';\n  const bold = '\\x1b[1m';\n  const timestamp = showTimestamp\n    ? new Date(startTime).toISOString().slice(11, 23) + ' '\n    : '';\n  const slowIndicator = isSlow ? ` ${bold}[SLOW]${reset}` : '';\n  const requestIdDisplay = config.requestId ? `${dim}[${id}]${reset} ` : '';\n  const sizeDisplay = config.sizeTracking\n    ? `${dim}${formatBytes(totalSize)}${reset} `\n    : '';\n\n  const parts = [\n    config.prefix ? `${dim}${config.prefix} ${reset}` : '',\n    requestIdDisplay,\n    `${dim}${timestamp}${reset}`,\n    `${methodColor}${method.padEnd(6)}${reset}`,\n    `${statusColor}${statusEmoji}${status}${reset}`,\n    `${durationColor}${duration}ms${reset}${slowIndicator}`,\n    sizeDisplay,\n    `${dim}${url}${reset}`,\n  ].filter(Boolean);\n\n  if (error) parts.push(`\\n  ${dim}Error: ${error}${reset}`);\n  if (requestBody) parts.push(`\\n  ${dim}Request: ${requestBody}${reset}`);\n  if (responseBody) parts.push(`\\n  ${dim}Response: ${responseBody}${reset}`);\n\n  console.log(parts.join(' '));\n}\n"],"mappings":"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","names":[]}