{"version":3,"sources":["../../src/metadata-image.ts","../../src/response-body.ts","../../src/server-http.ts"],"sourcesContent":["import type { ImageResponseOptions } from \"@vercel/og\";\nimport type { ReactElement } from \"react\";\nimport { omitFarmResponseBody } from \"./response-body\";\nimport { matchesFarmIfNoneMatch } from \"./server-http\";\n\nconst REACT_ELEMENT_TYPE = Symbol.for(\"react.element\");\nconst REACT_TRANSITIONAL_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\");\nconst REACT_FORWARD_REF_TYPE = Symbol.for(\"react.forward_ref\");\nconst REACT_MEMO_TYPE = Symbol.for(\"react.memo\");\nconst REACT_LAZY_TYPE = Symbol.for(\"react.lazy\");\n\ntype MetadataImageSize = {\n  width?: number;\n  height?: number;\n};\n\ntype MetadataImageFont = Omit<NonNullable<ImageResponseOptions[\"fonts\"]>[number], \"data\"> & {\n  data: ArrayBuffer | ArrayBufferView | Promise<ArrayBuffer | ArrayBufferView>;\n};\n\nexport type FarmMetadataImageModule = {\n  size?: MetadataImageSize;\n  contentType?: string;\n  revalidate?: number | false;\n  fonts?: MetadataImageFont[];\n  emoji?: ImageResponseOptions[\"emoji\"];\n  debug?: boolean;\n};\n\nexport type FarmMetadataImageResponseOptions = {\n  method?: string;\n  ifNoneMatch?: string | null;\n};\n\nfunction isResponse(value: unknown): value is Response {\n  return (\n    typeof Response !== \"undefined\" &&\n    (value instanceof Response ||\n      Boolean(\n        value &&\n        typeof value === \"object\" &&\n        typeof (value as Response).arrayBuffer === \"function\" &&\n        (value as Response).headers,\n      ))\n  );\n}\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n  return Boolean(\n    value &&\n    (typeof value === \"object\" || typeof value === \"function\") &&\n    typeof (value as PromiseLike<unknown>).then === \"function\",\n  );\n}\n\nfunction isReactElement(value: unknown): value is ReactElement<Record<string, unknown>> {\n  if (!value || typeof value !== \"object\") return false;\n  const marker = (value as { $$typeof?: symbol }).$$typeof;\n  return marker === REACT_ELEMENT_TYPE || marker === REACT_TRANSITIONAL_ELEMENT_TYPE;\n}\n\nasync function prepareMetadataImageNode(node: unknown): Promise<unknown> {\n  if (isThenable(node)) {\n    return prepareMetadataImageNode(await node);\n  }\n\n  if (Array.isArray(node)) {\n    return Promise.all(node.map((child) => prepareMetadataImageNode(child)));\n  }\n\n  if (!isReactElement(node)) {\n    return node;\n  }\n\n  const element = node;\n  const type = element.type as any;\n  const props = element.props || {};\n\n  if (typeof type === \"function\") {\n    if (type.prototype?.isReactComponent) {\n      throw new Error(\n        \"Metadata image components must be stateless function components; React class components are not supported.\",\n      );\n    }\n    return prepareMetadataImageNode(await type(props));\n  }\n\n  if (type && typeof type === \"object\") {\n    if (type.$$typeof === REACT_MEMO_TYPE) {\n      const { createElement } = await import(\"react\");\n      return prepareMetadataImageNode(createElement(type.type, props));\n    }\n    if (type.$$typeof === REACT_FORWARD_REF_TYPE) {\n      return prepareMetadataImageNode(await type.render(props, null));\n    }\n    if (type.$$typeof === REACT_LAZY_TYPE) {\n      const { createElement } = await import(\"react\");\n      let resolvedType: unknown;\n      try {\n        resolvedType = type._init(type._payload);\n      } catch (suspension) {\n        if (suspension && typeof (suspension as Promise<unknown>).then === \"function\") {\n          await suspension;\n          resolvedType = type._init(type._payload);\n        } else {\n          throw suspension;\n        }\n      }\n      return prepareMetadataImageNode(createElement(resolvedType as any, props));\n    }\n  }\n\n  const preparedChildren = await prepareMetadataImageNode(props.children);\n  const preparedProps: Record<string, unknown> = { ...props };\n\n  if (typeof preparedProps.className === \"string\") {\n    preparedProps.tw = [preparedProps.tw, preparedProps.className].filter(Boolean).join(\" \");\n    delete preparedProps.className;\n  }\n  delete preparedProps.children;\n\n  const { createElement } = await import(\"react\");\n  return createElement(type, {\n    ...preparedProps,\n    key: element.key,\n    children: preparedChildren,\n  });\n}\n\nasync function normalizeFonts(\n  fonts: MetadataImageFont[] | undefined,\n): Promise<ImageResponseOptions[\"fonts\"] | undefined> {\n  if (!fonts?.length) return undefined;\n\n  return Promise.all(\n    fonts.map(async (font) => {\n      const data = await font.data;\n      const arrayBuffer = ArrayBuffer.isView(data) ? toArrayBuffer(data) : data;\n      return { ...font, data: arrayBuffer } as NonNullable<ImageResponseOptions[\"fonts\"]>[number];\n    }),\n  );\n}\n\nfunction resolveCacheControl(revalidate: number | false | undefined): string {\n  if (revalidate === false) {\n    return \"public, max-age=31536000, immutable\";\n  }\n  if (typeof revalidate === \"number\" && Number.isFinite(revalidate) && revalidate > 0) {\n    return `public, s-maxage=${Math.floor(revalidate)}, stale-while-revalidate=300`;\n  }\n  return \"public, max-age=0, must-revalidate\";\n}\n\nfunction toArrayBuffer(value: ArrayBuffer | ArrayBufferView): ArrayBuffer {\n  if (value instanceof ArrayBuffer) return value;\n  const bytes = new Uint8Array(value.byteLength);\n  bytes.set(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));\n  return bytes.buffer;\n}\n\nasync function createEntityTag(body: ArrayBuffer): Promise<string> {\n  const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", body);\n  const hash = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, \"0\"))\n    .join(\"\")\n    .slice(0, 32);\n  return `\"${hash}\"`;\n}\n\nasync function finalizeMetadataImageResponse(\n  body: ArrayBuffer,\n  headers: HeadersInit,\n  options: FarmMetadataImageResponseOptions,\n): Promise<Response> {\n  const responseHeaders = new Headers(headers);\n  const etag = await createEntityTag(body);\n  responseHeaders.set(\"ETag\", etag);\n  responseHeaders.set(\"Content-Length\", String(body.byteLength));\n  responseHeaders.set(\"X-Content-Type-Options\", \"nosniff\");\n\n  if (matchesFarmIfNoneMatch(options.ifNoneMatch, etag)) {\n    return new Response(null, { status: 304, headers: responseHeaders });\n  }\n\n  return new Response(options.method?.toUpperCase() === \"HEAD\" ? null : body, {\n    status: 200,\n    headers: responseHeaders,\n  });\n}\n\n/** @internal */\nexport async function createFarmMetadataImageResponse(\n  value: unknown,\n  imageModule: FarmMetadataImageModule,\n  options: FarmMetadataImageResponseOptions = {},\n): Promise<Response> {\n  const method = (options.method || \"GET\").toUpperCase();\n  if (method !== \"GET\" && method !== \"HEAD\") {\n    return new Response(null, { status: 405, headers: { Allow: \"GET, HEAD\" } });\n  }\n\n  if (isResponse(value)) {\n    return method === \"HEAD\" ? omitFarmResponseBody(value) : value;\n  }\n\n  const cacheControl = resolveCacheControl(imageModule.revalidate);\n  const explicitContentType = imageModule.contentType?.split(\";\", 1)[0]?.trim().toLowerCase();\n\n  if (isReactElement(value) && explicitContentType !== \"image/svg+xml\") {\n    const { ImageResponse } = await import(\"@vercel/og\");\n    const element = (await prepareMetadataImageNode(value)) as ReactElement;\n    const response = new ImageResponse(element, {\n      width: imageModule.size?.width || 1200,\n      height: imageModule.size?.height || 630,\n      fonts: await normalizeFonts(imageModule.fonts),\n      emoji: imageModule.emoji,\n      debug: imageModule.debug,\n      headers: { \"cache-control\": cacheControl },\n    });\n    const headers = new Headers(response.headers);\n    headers.set(\"Cache-Control\", cacheControl);\n    return finalizeMetadataImageResponse(await response.arrayBuffer(), headers, options);\n  }\n\n  let body: ArrayBuffer;\n  if (typeof value === \"string\") {\n    body = toArrayBuffer(new TextEncoder().encode(value));\n  } else if (value instanceof ArrayBuffer || ArrayBuffer.isView(value)) {\n    body = toArrayBuffer(value);\n  } else if (isReactElement(value)) {\n    const { renderToStaticMarkup } = await import(\"react-dom/server\");\n    body = toArrayBuffer(new TextEncoder().encode(renderToStaticMarkup(value)));\n  } else {\n    throw new Error(\"Metadata image must return a Response, string, bytes, or React element\");\n  }\n\n  return finalizeMetadataImageResponse(\n    body,\n    {\n      \"Content-Type\": imageModule.contentType || \"image/svg+xml; charset=utf-8\",\n      \"Cache-Control\": cacheControl,\n    },\n    options,\n  );\n}\n","/** @internal */\nexport function omitFarmResponseBody(response: Response): Response {\n  if (response.body) {\n    void response.body.cancel().catch(() => undefined);\n  }\n\n  return new Response(null, {\n    status: response.status,\n    statusText: response.statusText,\n    headers: response.headers,\n  });\n}\n","import { assertBrowserStableRoutePath } from \"./routing/specificity\";\n\ninterface FarmNodeAbortRequest {\n  aborted?: boolean;\n  once(event: \"aborted\", listener: () => void): unknown;\n  off(event: \"aborted\", listener: () => void): unknown;\n}\n\ninterface FarmNodeAbortResponse {\n  writableEnded: boolean;\n  once(event: \"close\" | \"finish\", listener: () => void): unknown;\n  off(event: \"close\" | \"finish\", listener: () => void): unknown;\n}\n\n/** Share disconnect semantics between development and production Node requests. */\nexport function createFarmNodeRequestAbortSignal(\n  req: FarmNodeAbortRequest,\n  res: FarmNodeAbortResponse,\n): AbortSignal {\n  const controller = new AbortController();\n  let disposed = false;\n  const dispose = () => {\n    if (disposed) return;\n    disposed = true;\n    req.off(\"aborted\", abort);\n    res.off(\"close\", abortOnEarlyClose);\n    res.off(\"finish\", dispose);\n    controller.signal.removeEventListener(\"abort\", dispose);\n  };\n  const abort = () => controller.abort();\n  const abortOnEarlyClose = () => {\n    if (!res.writableEnded) abort();\n    dispose();\n  };\n\n  if (req.aborted) {\n    controller.abort();\n    return controller.signal;\n  }\n\n  req.once(\"aborted\", abort);\n  res.once(\"close\", abortOnEarlyClose);\n  res.once(\"finish\", dispose);\n  controller.signal.addEventListener(\"abort\", dispose, { once: true });\n  return controller.signal;\n}\n\nexport const DEFAULT_FARM_SERVER_BODY_SIZE_LIMIT = 10_000_000;\nexport const DEFAULT_FARM_SERVER_HEADERS_TIMEOUT = 60_000;\nexport const DEFAULT_FARM_SERVER_REQUEST_TIMEOUT = 300_000;\nexport const DEFAULT_FARM_SERVER_KEEP_ALIVE_TIMEOUT = 5_000;\nexport const DEFAULT_FARM_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT = 30_000;\nconst MAX_FARM_SERVER_TIMEOUT = 2_147_483_647;\n\nexport type FarmServerDuration = number | `${number}${\"ms\" | \"s\" | \"m\" | \"h\"}`;\n\nexport interface FarmServerHealthConfig {\n  /** Liveness endpoint. It remains healthy while a production process drains. */\n  livenessPath?: string;\n  /** Readiness endpoint. It returns 503 until startup completes and while draining. */\n  readinessPath?: string;\n}\n\nexport interface ResolvedFarmServerHealthConfig {\n  enabled: boolean;\n  livenessPath: string;\n  readinessPath: string;\n}\n\nexport interface FarmServerConfig {\n  /** Maximum request body size for API routes, integrations, workflows, and uploads. */\n  bodySizeLimit?: number | string;\n  /** Trust proxy-provided client address and request authority headers. Enable only behind a trusted proxy. */\n  trustProxy?: boolean;\n  /** Maximum time for a Node client to send complete request headers. */\n  headersTimeout?: FarmServerDuration;\n  /** Maximum time for a Node client to send the complete request. */\n  requestTimeout?: FarmServerDuration;\n  /** How long an idle Node keep-alive connection remains open after a response. */\n  keepAliveTimeout?: FarmServerDuration;\n  /** Maximum time the Node adapter drains traffic before forcing shutdown. */\n  gracefulShutdownTimeout?: FarmServerDuration;\n  /** Production liveness and readiness endpoints. Set to false to disable them. */\n  health?: false | FarmServerHealthConfig;\n}\n\nexport interface ResolvedFarmServerConfig {\n  bodySizeLimit: number;\n  trustProxy: boolean;\n  headersTimeout: number;\n  requestTimeout: number;\n  keepAliveTimeout: number;\n  gracefulShutdownTimeout: number;\n  health: ResolvedFarmServerHealthConfig;\n}\n\nexport type FarmRequestBodyErrorCode = \"BODY_TOO_LARGE\" | \"INVALID_CONTENT_LENGTH\";\n\n/** Apply the weak entity-tag comparison required by If-None-Match. */\nexport function matchesFarmIfNoneMatch(\n  value: string | readonly string[] | null | undefined,\n  etag: string,\n): boolean {\n  const expected = parseEntityTag(trimOptionalWhitespace(etag));\n  if (!expected) return false;\n\n  const values = Array.isArray(value) ? value : [value];\n  const combined = values\n    .filter((header): header is string => typeof header === \"string\")\n    .join(\",\");\n  const fieldValue = trimOptionalWhitespace(combined);\n  if (!fieldValue) return false;\n  if (fieldValue === \"*\") return true;\n\n  let matched = false;\n  let hasEntityTag = false;\n  for (const candidate of splitEntityTags(fieldValue)) {\n    const token = trimOptionalWhitespace(candidate);\n    if (!token) continue;\n\n    const parsed = parseEntityTag(token);\n    if (!parsed) return false;\n    hasEntityTag = true;\n    if (parsed === expected) matched = true;\n  }\n\n  return hasEntityTag && matched;\n}\n\nfunction trimOptionalWhitespace(value: string): string {\n  return value.replace(/^[\\t ]+|[\\t ]+$/g, \"\");\n}\n\nfunction parseEntityTag(value: string): string | null {\n  const opaqueTag = value.startsWith(\"W/\") ? value.slice(2) : value;\n  if (opaqueTag.length < 2 || opaqueTag[0] !== '\"' || opaqueTag.at(-1) !== '\"') return null;\n\n  for (let index = 1; index < opaqueTag.length - 1; index++) {\n    const code = opaqueTag.charCodeAt(index);\n    if (code === 0x21 || (code >= 0x23 && code <= 0x7e) || code >= 0x80) continue;\n    return null;\n  }\n\n  return opaqueTag;\n}\n\nfunction splitEntityTags(value: string): string[] {\n  const tags: string[] = [];\n  let start = 0;\n  let quoted = false;\n\n  for (let index = 0; index < value.length; index++) {\n    const character = value[index];\n    if (character === '\"') {\n      quoted = !quoted;\n    } else if (character === \",\" && !quoted) {\n      tags.push(value.slice(start, index));\n      start = index + 1;\n    }\n  }\n\n  tags.push(value.slice(start));\n  return tags;\n}\n\nexport class FarmRequestBodyError extends Error {\n  readonly code: FarmRequestBodyErrorCode;\n  readonly status: number;\n\n  constructor(code: FarmRequestBodyErrorCode, status: number, message: string) {\n    super(message);\n    this.name = \"FarmRequestBodyError\";\n    this.code = code;\n    this.status = status;\n  }\n}\n\nexport function resolveFarmServerConfig(\n  config: FarmServerConfig | ResolvedFarmServerConfig | undefined,\n): ResolvedFarmServerConfig {\n  const headersTimeout = parseFarmServerDuration(\n    config?.headersTimeout ?? DEFAULT_FARM_SERVER_HEADERS_TIMEOUT,\n    \"server.headersTimeout\",\n  );\n  const requestTimeout = parseFarmServerDuration(\n    config?.requestTimeout ?? DEFAULT_FARM_SERVER_REQUEST_TIMEOUT,\n    \"server.requestTimeout\",\n  );\n  if (headersTimeout > requestTimeout) {\n    throw new TypeError(\"server.headersTimeout must not exceed server.requestTimeout\");\n  }\n\n  return Object.freeze({\n    bodySizeLimit: parseBodySizeLimit(\n      config?.bodySizeLimit ?? DEFAULT_FARM_SERVER_BODY_SIZE_LIMIT,\n      \"server.bodySizeLimit\",\n    ),\n    trustProxy: config?.trustProxy === true,\n    headersTimeout,\n    requestTimeout,\n    keepAliveTimeout: parseFarmServerDuration(\n      config?.keepAliveTimeout ?? DEFAULT_FARM_SERVER_KEEP_ALIVE_TIMEOUT,\n      \"server.keepAliveTimeout\",\n    ),\n    gracefulShutdownTimeout: parseFarmServerDuration(\n      config?.gracefulShutdownTimeout ?? DEFAULT_FARM_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT,\n      \"server.gracefulShutdownTimeout\",\n    ),\n    health: resolveFarmServerHealthConfig(config?.health),\n  });\n}\n\nexport function parseFarmServerDuration(\n  value: FarmServerDuration,\n  optionName = \"duration\",\n): number {\n  if (typeof value === \"number\") {\n    if (!Number.isSafeInteger(value) || value <= 0) {\n      throw new TypeError(`${optionName} must be a positive safe integer`);\n    }\n    if (value > MAX_FARM_SERVER_TIMEOUT) {\n      throw new TypeError(`${optionName} must not exceed ${MAX_FARM_SERVER_TIMEOUT} milliseconds`);\n    }\n    return value;\n  }\n\n  const match = value\n    .trim()\n    .toLowerCase()\n    .match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h)$/);\n  if (!match) {\n    throw new TypeError(`${optionName} must be milliseconds or a duration such as \"30s\" or \"2m\"`);\n  }\n\n  const amount = Number(match[1]);\n  const unit = match[2];\n  const multiplier = unit === \"ms\" ? 1 : unit === \"s\" ? 1_000 : unit === \"m\" ? 60_000 : 3_600_000;\n  const milliseconds = Math.floor(amount * multiplier);\n  if (!Number.isSafeInteger(milliseconds) || milliseconds <= 0) {\n    throw new TypeError(`${optionName} must resolve to a positive safe integer`);\n  }\n  if (milliseconds > MAX_FARM_SERVER_TIMEOUT) {\n    throw new TypeError(`${optionName} must not exceed ${MAX_FARM_SERVER_TIMEOUT} milliseconds`);\n  }\n  return milliseconds;\n}\n\nfunction resolveFarmServerHealthConfig(\n  config: false | FarmServerHealthConfig | ResolvedFarmServerHealthConfig | undefined,\n): ResolvedFarmServerHealthConfig {\n  if (config === false || (config && \"enabled\" in config && config.enabled === false)) {\n    return Object.freeze({\n      enabled: false,\n      livenessPath: \"/_farm/health/live\",\n      readinessPath: \"/_farm/health/ready\",\n    });\n  }\n\n  const livenessPath = normalizeHealthPath(\n    config?.livenessPath ?? \"/_farm/health/live\",\n    \"server.health.livenessPath\",\n  );\n  const readinessPath = normalizeHealthPath(\n    config?.readinessPath ?? \"/_farm/health/ready\",\n    \"server.health.readinessPath\",\n  );\n  if (livenessPath === readinessPath) {\n    throw new TypeError(\"server.health livenessPath and readinessPath must be different\");\n  }\n\n  return Object.freeze({ enabled: true, livenessPath, readinessPath });\n}\n\nfunction normalizeHealthPath(value: string, optionName: string): string {\n  const path = value.trim();\n  if (!path.startsWith(\"/\") || path.includes(\"?\") || path.includes(\"#\") || path.includes(\"*\")) {\n    throw new TypeError(`${optionName} must be an absolute pathname without a query or wildcard`);\n  }\n  const normalized = path.length > 1 ? path.replace(/\\/+$/, \"\") || \"/\" : path;\n  assertBrowserStableRoutePath(normalized);\n  return normalized;\n}\n\nexport function parseBodySizeLimit(value: number | string, optionName = \"bodySizeLimit\"): number {\n  if (typeof value === \"number\") {\n    if (!Number.isSafeInteger(value) || value <= 0) {\n      throw new TypeError(`${optionName} must be a positive safe integer`);\n    }\n    return value;\n  }\n\n  const match = value\n    .trim()\n    .toLowerCase()\n    .match(/^(\\d+(?:\\.\\d+)?)\\s*(b|kb|mb|gb|kib|mib|gib)?$/);\n  if (!match) {\n    throw new TypeError(`${optionName} must be bytes or a size string such as \"500kb\" or \"10mb\"`);\n  }\n\n  const amount = Number(match[1]);\n  const unit = match[2] ?? \"b\";\n  const multiplier: Record<string, number> = {\n    b: 1,\n    kb: 1_000,\n    mb: 1_000_000,\n    gb: 1_000_000_000,\n    kib: 1_024,\n    mib: 1_048_576,\n    gib: 1_073_741_824,\n  };\n  const bytes = Math.floor(amount * multiplier[unit]);\n\n  if (!Number.isSafeInteger(bytes) || bytes <= 0) {\n    throw new TypeError(`${optionName} must resolve to a positive safe integer`);\n  }\n\n  return bytes;\n}\n\nexport async function bufferFarmRequestBody(request: Request, limit: number): Promise<Request> {\n  if (request.method === \"GET\" || request.method === \"HEAD\" || request.body === null) {\n    return request;\n  }\n\n  const bytes = await readFarmRequestBody(request, limit);\n  const body = new Uint8Array(bytes.byteLength);\n  body.set(bytes);\n  return new Request(request, {\n    // oxlint-disable-next-line unicorn/no-invalid-fetch-options -- GET and HEAD return above.\n    body: body.buffer,\n  });\n}\n\nexport async function readFarmRequestBody(request: Request, limit: number): Promise<Uint8Array> {\n  try {\n    validateContentLength(request.headers.get(\"content-length\"), limit);\n  } catch (error) {\n    // A cloned Request is a tee branch: its cancellation may wait for the\n    // untouched branch. Rejection must not wait for producer-owned cleanup.\n    void request.body?.cancel(error).catch(() => {});\n    throw error;\n  }\n  throwIfAborted(request.signal);\n  if (!request.body) return new Uint8Array();\n\n  const reader = request.body.getReader();\n  const chunks: Uint8Array[] = [];\n  let total = 0;\n  const cancelBodyRead = () => {\n    void reader.cancel(request.signal.reason).catch(() => {});\n  };\n  request.signal.addEventListener(\"abort\", cancelBodyRead, { once: true });\n\n  try {\n    while (true) {\n      throwIfAborted(request.signal);\n      const { done, value } = await reader.read();\n      // Cancellation resolves a pending read as EOF, not necessarily an error.\n      throwIfAborted(request.signal);\n      if (done) break;\n      if (!value) continue;\n\n      total += value.byteLength;\n      if (total > limit) {\n        const error = new FarmRequestBodyError(\"BODY_TOO_LARGE\", 413, \"Request body is too large\");\n        void reader.cancel(error).catch(() => {});\n        throw error;\n      }\n      chunks.push(value);\n    }\n  } catch (error) {\n    if (request.signal.aborted) throwIfAborted(request.signal);\n    throw error;\n  } finally {\n    request.signal.removeEventListener(\"abort\", cancelBodyRead);\n    reader.releaseLock();\n  }\n\n  const body = new Uint8Array(total);\n  let offset = 0;\n  for (const chunk of chunks) {\n    body.set(chunk, offset);\n    offset += chunk.byteLength;\n  }\n  return body;\n}\n\nexport async function readNodeRequestBody(\n  request: {\n    headers: Record<string, string | string[] | undefined>;\n    on(event: \"data\", listener: (chunk: unknown) => void): unknown;\n    on(event: \"end\", listener: () => void): unknown;\n    on(event: \"error\", listener: (error: Error) => void): unknown;\n    removeListener?(event: string, listener: (...args: any[]) => void): unknown;\n    resume?(): unknown;\n  },\n  limit: number,\n): Promise<Buffer> {\n  const rawContentLength = request.headers[\"content-length\"];\n  const contentLength = Array.isArray(rawContentLength) ? rawContentLength[0] : rawContentLength;\n  try {\n    validateContentLength(contentLength, limit);\n  } catch (error) {\n    request.resume?.();\n    throw error;\n  }\n\n  return await new Promise<Buffer>((resolve, reject) => {\n    const chunks: Buffer[] = [];\n    let total = 0;\n    let settled = false;\n\n    const cleanup = () => {\n      request.removeListener?.(\"data\", onData);\n      request.removeListener?.(\"end\", onEnd);\n      request.removeListener?.(\"error\", onError);\n    };\n    const rejectOnce = (error: Error) => {\n      if (settled) return;\n      settled = true;\n      cleanup();\n      request.resume?.();\n      reject(error);\n    };\n    const onData = (chunk: unknown) => {\n      const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk as any);\n      total += bytes.byteLength;\n      if (total > limit) {\n        rejectOnce(new FarmRequestBodyError(\"BODY_TOO_LARGE\", 413, \"Request body is too large\"));\n        return;\n      }\n      chunks.push(bytes);\n    };\n    const onEnd = () => {\n      if (settled) return;\n      settled = true;\n      cleanup();\n      resolve(Buffer.concat(chunks, total));\n    };\n    const onError = (error: Error) => rejectOnce(error);\n\n    request.on(\"data\", onData);\n    request.on(\"end\", onEnd);\n    request.on(\"error\", onError);\n  });\n}\n\nexport function createFarmRequestBodyErrorResponse(error: unknown): Response | null {\n  if (!(error instanceof FarmRequestBodyError)) return null;\n\n  return new Response(error.status === 413 ? \"Payload Too Large\" : \"Bad Request\", {\n    status: error.status,\n    headers: {\n      \"cache-control\": \"no-store\",\n      \"content-type\": \"text/plain; charset=utf-8\",\n      \"x-content-type-options\": \"nosniff\",\n    },\n  });\n}\n\nfunction validateContentLength(value: string | null | undefined, limit: number): void {\n  const contentLength = value?.trim();\n  if (!contentLength) return;\n  if (!/^\\d+$/.test(contentLength)) {\n    throw new FarmRequestBodyError(\"INVALID_CONTENT_LENGTH\", 400, \"Invalid content-length header\");\n  }\n  if (Number(contentLength) > limit) {\n    throw new FarmRequestBodyError(\"BODY_TOO_LARGE\", 413, \"Request body is too large\");\n  }\n}\n\nfunction throwIfAborted(signal: AbortSignal): void {\n  if (!signal.aborted) return;\n  if (signal.reason !== undefined) throw signal.reason;\n  throw new DOMException(\"The operation was aborted\", \"AbortError\");\n}\n"],"mappings":"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","names":["createElement"]}