{"version":3,"sources":["../src/image-server.ts"],"sourcesContent":["import type {\n  FarmImageFormat,\n  FarmImageLocalPattern,\n  FarmImageRemotePattern,\n  ResolvedFarmImageConfig,\n} from \"./image-config\";\nimport { matchesFarmIfNoneMatch } from \"./server-http\";\n\nexport interface FarmImageTransformInput {\n  source: Uint8Array;\n  sourceUrl: URL;\n  sourceType: string;\n  width: number;\n  quality: number;\n  accept: string;\n  formats: readonly FarmImageFormat[];\n  signal: AbortSignal;\n  /**\n   * Byte ceiling for any source the transformer fetches itself. Supplied by the\n   * image handler; transformers that re-fetch the origin (Cloudflare) must\n   * enforce it, since they bypass the handler's bounded read.\n   */\n  maximumResponseBody?: number;\n}\n\nexport interface FarmImageTransformResult {\n  body: Uint8Array;\n  contentType: string;\n}\n\nexport type FarmImageTransformer = (\n  input: FarmImageTransformInput,\n) => Promise<FarmImageTransformResult>;\n\nexport interface CreateFarmImageHandlerOptions {\n  fetch?: typeof globalThis.fetch;\n  /** Node-only fetcher that validates the DNS result used for remote connections. @internal */\n  fetchRemote?: typeof globalThis.fetch;\n  transform: FarmImageTransformer;\n  validateRemoteUrl?: (url: URL) => void | Promise<void>;\n  onError?: (error: unknown, request: Request) => void;\n  cacheEntries?: number;\n}\n\nexport type FarmImageHandler = (request: Request) => Promise<Response | null>;\n\ntype OptimizedImage = FarmImageTransformResult & {\n  etag: string;\n  cacheControl: string;\n  expiresAt: number;\n};\n\ntype FarmImageRequestErrorCode =\n  | \"BODY_TOO_LARGE\"\n  | \"DISALLOWED_SOURCE\"\n  | \"INVALID_METHOD\"\n  | \"INVALID_PARAMETER\"\n  | \"PRIVATE_SOURCE\"\n  | \"TOO_MANY_REDIRECTS\"\n  | \"UNSUPPORTED_IMAGE\";\n\nexport class FarmImageRequestError extends Error {\n  readonly code: FarmImageRequestErrorCode;\n  readonly status: number;\n\n  constructor(code: FarmImageRequestErrorCode, status: number, message: string) {\n    super(message);\n    this.name = \"FarmImageRequestError\";\n    this.code = code;\n    this.status = status;\n  }\n}\n\nexport function createFarmImageHandler(\n  config: ResolvedFarmImageConfig,\n  options: CreateFarmImageHandlerOptions,\n): FarmImageHandler {\n  const fetcher = options.fetch ?? globalThis.fetch;\n  const cache = new FarmImageMemoryCache(options.cacheEntries ?? 100);\n  // Identical concurrent misses share one fetch + transform. Without this a\n  // burst for an uncached image (a new page going live, a CDN cold start)\n  // fetches the origin and runs the codec once per request.\n  const inflight = new Map<string, InflightOptimization>();\n  const allowedWidths = new Set([...config.deviceSizes, ...config.imageSizes]);\n  const allowedQualities = new Set(config.qualities);\n\n  return async function handleFarmImage(request): Promise<Response | null> {\n    const requestUrl = new URL(request.url);\n    if (requestUrl.pathname !== config.path) return null;\n\n    try {\n      if (config.provider === \"none\") {\n        throw new FarmImageRequestError(\n          \"DISALLOWED_SOURCE\",\n          404,\n          \"The Farm image optimizer is disabled\",\n        );\n      }\n      if (request.method !== \"GET\" && request.method !== \"HEAD\") {\n        throw new FarmImageRequestError(\n          \"INVALID_METHOD\",\n          405,\n          \"The Farm image optimizer only accepts GET and HEAD\",\n        );\n      }\n\n      const sourceUrl = await resolveImageSourceUrl(requestUrl, config, options.validateRemoteUrl);\n      const width = parseAllowedInteger(requestUrl.searchParams.get(\"w\"), allowedWidths, \"width\");\n      const quality = parseAllowedInteger(\n        requestUrl.searchParams.get(\"q\"),\n        allowedQualities,\n        \"quality\",\n      );\n      const accept = request.headers.get(\"accept\") ?? \"\";\n      // Key on the format the Accept header negotiates to, not the header text.\n      // Both transformers derive their output from `selectOutputFormat(accept,\n      // formats)` alone, so every header that negotiates to the same format\n      // produces byte-identical output. Keying on the raw header let a caller\n      // vary it freely (`image/webp,*/*;q=0.8`, reordered lists, extra params)\n      // and force an uncached fetch and transform each time.\n      const negotiatedFormat = selectOutputFormat(accept, config.formats) ?? \"\";\n      const cacheKey = `${sourceUrl.href}\\n${width}\\n${quality}\\n${negotiatedFormat}`;\n      let optimized = cache.get(cacheKey);\n\n      if (!optimized) {\n        optimized = await runCoalesced(inflight, cacheKey, request.signal, async (signal) => {\n          const fetchedSource = await fetchImageSource(\n            sourceUrl,\n            requestUrl.origin,\n            config,\n            fetcher,\n            options.fetchRemote,\n            options.validateRemoteUrl,\n            signal,\n          );\n          const source = await readResponseWithLimit(\n            fetchedSource.response,\n            config.maximumResponseBody,\n          );\n          const sourceType = detectImageContentType(source);\n          validateSourceType(sourceType, config);\n          throwIfAborted(signal);\n\n          const result = await options.transform({\n            source,\n            sourceUrl: fetchedSource.url,\n            sourceType,\n            width,\n            quality,\n            accept,\n            formats: config.formats,\n            signal,\n            maximumResponseBody: config.maximumResponseBody,\n          });\n          throwIfAborted(signal);\n          validateTransformedResult(result, config);\n\n          const entry = {\n            ...result,\n            etag: createImageEtag(result.body),\n            cacheControl: `public, max-age=${config.minimumCacheTTL}, stale-while-revalidate=${Math.max(\n              config.minimumCacheTTL,\n              60,\n            )}`,\n            expiresAt: Date.now() + config.minimumCacheTTL * 1_000,\n          };\n          cache.set(cacheKey, entry);\n          return entry;\n        });\n      }\n\n      return createOptimizedImageResponse(request, optimized, config);\n    } catch (error) {\n      if (!(error instanceof FarmImageRequestError) && !isAbortError(error)) {\n        try {\n          options.onError?.(error, request);\n        } catch {\n          // Error reporting must not replace the optimizer's sanitized response.\n        }\n      }\n      return createFarmImageErrorResponse(error);\n    }\n  };\n}\n\n/** Mirrors the `images.maximumResponseBody` default (\"10mb\"). */\nconst DEFAULT_IMAGE_TRANSFORM_BODY_LIMIT = 10 * 1024 * 1024;\n\nexport function createCloudflareImageTransformer(\n  fetcher: typeof globalThis.fetch = globalThis.fetch,\n): FarmImageTransformer {\n  return async ({ sourceUrl, width, quality, accept, formats, signal, maximumResponseBody }) => {\n    const format = selectOutputFormat(accept, formats);\n    // Cloudflare resizing works by letting the edge fetch the origin, so this\n    // request cannot reuse the bytes the handler already read. It still must not\n    // be a weaker fetch than the validated one: `redirect: \"manual\"` keeps it\n    // from silently following a hop the handler never validated, and the body is\n    // read under the same ceiling as the handler's own read.\n    const response = await fetcher(sourceUrl, {\n      signal,\n      redirect: \"manual\",\n      headers: { accept: \"image/*\" },\n      cf: {\n        image: {\n          fit: \"scale-down\",\n          width,\n          quality,\n          ...(format ? { format: format === \"image/avif\" ? \"avif\" : \"webp\" } : {}),\n        },\n      },\n    } as RequestInit);\n\n    if (response.status >= 300 && response.status < 400) {\n      void cancelResponseBody(response);\n      throw new FarmImageRequestError(\n        \"UNSUPPORTED_IMAGE\",\n        502,\n        \"Source image redirected after validation\",\n      );\n    }\n\n    if (!response.ok) {\n      throw new FarmImageRequestError(\n        \"UNSUPPORTED_IMAGE\",\n        response.status === 404 ? 404 : 502,\n        \"Cloudflare could not transform the source image\",\n      );\n    }\n\n    const body = await readResponseWithLimit(\n      response,\n      maximumResponseBody ?? DEFAULT_IMAGE_TRANSFORM_BODY_LIMIT,\n    );\n    return {\n      body,\n      contentType:\n        normalizeImageContentType(response.headers.get(\"content-type\")) ||\n        detectImageContentType(body),\n    };\n  };\n}\n\nexport function selectOutputFormat(\n  accept: string,\n  formats: readonly FarmImageFormat[],\n): FarmImageFormat | undefined {\n  const qualityByFormat = new Map<string, number>();\n\n  for (const range of accept.split(\",\")) {\n    const [rawType, ...parameters] = range.split(\";\");\n    const type = rawType.trim().toLowerCase();\n    if (!type) continue;\n\n    let quality = 1;\n    for (const parameter of parameters) {\n      const [rawName, rawValue] = parameter.split(\"=\", 2);\n      if (rawName.trim().toLowerCase() !== \"q\") continue;\n      const parsed = Number(rawValue?.trim());\n      quality = Number.isFinite(parsed) && parsed >= 0 && parsed <= 1 ? parsed : 0;\n      break;\n    }\n\n    qualityByFormat.set(type, Math.max(qualityByFormat.get(type) ?? 0, quality));\n  }\n\n  let selected: FarmImageFormat | undefined;\n  let selectedQuality = 0;\n  for (const format of formats) {\n    const quality = qualityByFormat.get(format) ?? 0;\n    if (quality > selectedQuality) {\n      selected = format;\n      selectedQuality = quality;\n    }\n  }\n  return selected;\n}\n\n/**\n * Expand an IPv6 address into its eight 16-bit hextets, or null when the value\n * is not a parseable IPv6 address.\n *\n * Textual comparison is not enough for this boundary: the same address has many\n * spellings, and `new URL()` rewrites some of them. `::ffff:127.0.0.1` becomes\n * `::ffff:7f00:1`, and `::1` may arrive fully expanded, so every form has to be\n * reduced to numbers before any range check.\n */\nfunction parseIpv6Hextets(value: string): number[] | null {\n  // Drop any zone index (fe80::1%eth0); it does not affect the address.\n  let text = value.split(\"%\", 1)[0] ?? \"\";\n  if (!text.includes(\":\")) return null;\n\n  // A trailing dotted quad (::ffff:127.0.0.1) contributes the low two hextets.\n  let tail: number[] = [];\n  const lastColon = text.lastIndexOf(\":\");\n  const candidate = text.slice(lastColon + 1);\n  if (candidate.includes(\".\")) {\n    const octets = parseIpv4Octets(candidate);\n    if (!octets) return null;\n    tail = [(octets[0]! << 8) | octets[1]!, (octets[2]! << 8) | octets[3]!];\n    text = text.slice(0, lastColon);\n    // \"::1.2.3.4\" leaves \"::\" here, and \"1.2.3.4\" alone leaves \"\" — not IPv6.\n    if (text === \"\") return null;\n  }\n\n  const compressionParts = text.split(\"::\");\n  if (compressionParts.length > 2) return null;\n\n  const parseGroup = (group: string): number[] | null => {\n    if (group === \"\") return [];\n    const hextets: number[] = [];\n    for (const part of group.split(\":\")) {\n      if (!/^[0-9a-f]{1,4}$/.test(part)) return null;\n      hextets.push(Number.parseInt(part, 16));\n    }\n    return hextets;\n  };\n\n  const head = parseGroup(compressionParts[0] ?? \"\");\n  const rest = parseGroup(compressionParts[1] ?? \"\");\n  if (!head || !rest) return null;\n\n  const explicit = [...head, ...rest, ...tail];\n  if (compressionParts.length === 1) {\n    return explicit.length === 8 ? explicit : null;\n  }\n\n  // \"::\" stands for at least one zero hextet.\n  if (explicit.length >= 8) return null;\n  const zeros = Array.from({ length: 8 - explicit.length }, () => 0);\n  return [...head, ...zeros, ...rest, ...tail];\n}\n\nfunction parseIpv4Octets(value: string): number[] | null {\n  const parts = value.split(\".\");\n  if (parts.length !== 4 || parts.some((part) => !/^\\d{1,3}$/.test(part))) return null;\n  const octets = parts.map(Number);\n  return octets.some((part) => part > 255) ? null : octets;\n}\n\nfunction isPrivateIpv4(octets: readonly number[]): boolean {\n  const [a, b] = octets as [number, number];\n  return (\n    a === 0 ||\n    a === 10 ||\n    a === 127 ||\n    (a === 100 && b >= 64 && b <= 127) ||\n    (a === 169 && b === 254) ||\n    (a === 172 && b >= 16 && b <= 31) ||\n    (a === 192 && (b === 0 || b === 168)) ||\n    (a === 198 && (b === 18 || b === 19)) ||\n    a >= 224\n  );\n}\n\nexport function isPrivateImageAddress(address: string): boolean {\n  const value = address\n    .trim()\n    .toLowerCase()\n    .replace(/^\\[|\\]$/g, \"\");\n\n  const hextets = parseIpv6Hextets(value);\n  if (hextets) {\n    const [h0, h1, h2, h3, h4, h5, h6, h7] = hextets as [\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n      number,\n    ];\n    const zeroPrefix = h0 === 0 && h1 === 0 && h2 === 0 && h3 === 0;\n\n    // An address that embeds IPv4 is only as safe as that IPv4 address:\n    // IPv4-mapped (::ffff:0:0/96), IPv4-translated (::ffff:0:0:0/96), and the\n    // deprecated IPv4-compatible (::/96) forms all reach the v4 host.\n    const embedsIpv4 =\n      zeroPrefix &&\n      ((h4 === 0 && h5 === 0xffff) || (h4 === 0xffff && h5 === 0) || (h4 === 0 && h5 === 0));\n    if (embedsIpv4 && (h6 !== 0 || h7 !== 0)) {\n      return isPrivateIpv4([h6 >> 8, h6 & 0xff, h7 >> 8, h7 & 0xff]);\n    }\n\n    // Unspecified (::) and loopback (::1) in any spelling.\n    if (zeroPrefix && h4 === 0 && h5 === 0 && h6 === 0 && (h7 === 0 || h7 === 1)) return true;\n    // Unique-local fc00::/7, link-local fe80::/10, multicast ff00::/8.\n    if ((h0 & 0xfe00) === 0xfc00) return true;\n    if ((h0 & 0xffc0) === 0xfe80) return true;\n    if ((h0 & 0xff00) === 0xff00) return true;\n    return false;\n  }\n\n  const octets = parseIpv4Octets(value);\n  return octets ? isPrivateIpv4(octets) : false;\n}\n\nfunction parseAllowedInteger(\n  raw: string | null,\n  allowed: ReadonlySet<number>,\n  name: string,\n): number {\n  if (!raw || !/^\\d+$/.test(raw)) {\n    throw new FarmImageRequestError(\n      \"INVALID_PARAMETER\",\n      400,\n      `Image ${name} must be an allowed integer`,\n    );\n  }\n  const value = Number(raw);\n  if (!allowed.has(value)) {\n    throw new FarmImageRequestError(\"INVALID_PARAMETER\", 400, `Image ${name} is not configured`);\n  }\n  return value;\n}\n\nasync function resolveImageSourceUrl(\n  requestUrl: URL,\n  config: ResolvedFarmImageConfig,\n  validateRemoteUrl: CreateFarmImageHandlerOptions[\"validateRemoteUrl\"],\n): Promise<URL> {\n  const raw = requestUrl.searchParams.get(\"url\");\n  if (!raw || raw.length > 4096 || raw.startsWith(\"//\")) {\n    throw new FarmImageRequestError(\"INVALID_PARAMETER\", 400, \"Invalid image source URL\");\n  }\n\n  let sourceUrl: URL;\n  try {\n    sourceUrl = raw.startsWith(\"/\") ? new URL(raw, requestUrl.origin) : new URL(raw);\n  } catch {\n    throw new FarmImageRequestError(\"INVALID_PARAMETER\", 400, \"Invalid image source URL\");\n  }\n\n  await validateImageSourceUrl(sourceUrl, requestUrl.origin, config, validateRemoteUrl);\n  return sourceUrl;\n}\n\nasync function validateImageSourceUrl(\n  sourceUrl: URL,\n  requestOrigin: string,\n  config: ResolvedFarmImageConfig,\n  validateRemoteUrl: CreateFarmImageHandlerOptions[\"validateRemoteUrl\"],\n): Promise<void> {\n  if (sourceUrl.protocol !== \"http:\" && sourceUrl.protocol !== \"https:\") {\n    throw new FarmImageRequestError(\"DISALLOWED_SOURCE\", 400, \"Unsupported image protocol\");\n  }\n  if (sourceUrl.username || sourceUrl.password || sourceUrl.hash) {\n    throw new FarmImageRequestError(\"DISALLOWED_SOURCE\", 400, \"Unsafe image source URL\");\n  }\n\n  if (sourceUrl.origin === requestOrigin) {\n    if (\n      sourceUrl.pathname === config.path ||\n      !matchesLocalPatterns(sourceUrl, config.localPatterns)\n    ) {\n      throw new FarmImageRequestError(\n        \"DISALLOWED_SOURCE\",\n        400,\n        \"Local image source is not allowed\",\n      );\n    }\n    return;\n  }\n\n  if (!matchesRemoteSource(sourceUrl, config)) {\n    throw new FarmImageRequestError(\"DISALLOWED_SOURCE\", 400, \"Remote image source is not allowed\");\n  }\n  if (!config.dangerouslyAllowLocalIP && isPrivateImageAddress(sourceUrl.hostname)) {\n    throw new FarmImageRequestError(\"PRIVATE_SOURCE\", 400, \"Private image source is not allowed\");\n  }\n  if (!config.dangerouslyAllowLocalIP) {\n    await validateRemoteUrl?.(sourceUrl);\n  }\n}\n\nasync function fetchImageSource(\n  initialUrl: URL,\n  requestOrigin: string,\n  config: ResolvedFarmImageConfig,\n  fetcher: typeof globalThis.fetch,\n  fetchRemote: typeof globalThis.fetch | undefined,\n  validateRemoteUrl: CreateFarmImageHandlerOptions[\"validateRemoteUrl\"],\n  signal: AbortSignal,\n): Promise<{ response: Response; url: URL }> {\n  let currentUrl = initialUrl;\n\n  for (let redirectCount = 0; ; redirectCount += 1) {\n    throwIfAborted(signal);\n    const sourceFetcher = currentUrl.origin === requestOrigin ? fetcher : (fetchRemote ?? fetcher);\n    const response = await sourceFetcher(currentUrl, {\n      method: \"GET\",\n      redirect: \"manual\",\n      signal,\n      headers: {\n        accept: \"image/avif,image/webp,image/*,*/*;q=0.8\",\n        \"user-agent\": \"Farm.js Image Optimizer\",\n      },\n    });\n\n    if (![301, 302, 303, 307, 308].includes(response.status)) {\n      if (!response.ok) {\n        await cancelResponseBody(response);\n        throw new FarmImageRequestError(\n          \"UNSUPPORTED_IMAGE\",\n          response.status === 404 ? 404 : 502,\n          \"Could not fetch source image\",\n        );\n      }\n      return { response, url: currentUrl };\n    }\n\n    if (redirectCount >= config.maximumRedirects) {\n      await cancelResponseBody(response);\n      throw new FarmImageRequestError(\n        \"TOO_MANY_REDIRECTS\",\n        400,\n        \"Source image exceeded the redirect limit\",\n      );\n    }\n    const location = response.headers.get(\"location\");\n    if (!location) {\n      await cancelResponseBody(response);\n      throw new FarmImageRequestError(\"UNSUPPORTED_IMAGE\", 502, \"Invalid image redirect\");\n    }\n    await cancelResponseBody(response);\n    currentUrl = new URL(location, currentUrl);\n    await validateImageSourceUrl(currentUrl, requestOrigin, config, validateRemoteUrl);\n  }\n}\n\ntype InflightOptimization = {\n  promise: Promise<OptimizedImage>;\n  controller: AbortController;\n  waiters: number;\n};\n\n/**\n * Share one in-flight optimization between identical concurrent requests.\n *\n * The shared work runs under its own AbortController rather than any single\n * request's signal, so one caller going away cannot cancel the image everyone\n * else is waiting for. The controller is aborted only when the last waiter\n * leaves, so an abandoned burst still stops promptly.\n */\nasync function runCoalesced(\n  inflight: Map<string, InflightOptimization>,\n  key: string,\n  requestSignal: AbortSignal,\n  run: (signal: AbortSignal) => Promise<OptimizedImage>,\n): Promise<OptimizedImage> {\n  let entry = inflight.get(key);\n  if (!entry) {\n    const controller = new AbortController();\n    const created: InflightOptimization = {\n      controller,\n      waiters: 0,\n      promise: undefined as unknown as Promise<OptimizedImage>,\n    };\n    created.promise = run(controller.signal).finally(() => {\n      if (inflight.get(key) === created) inflight.delete(key);\n    });\n    // Every waiter can detach before the shared work settles: an already\n    // aborted request returns early without ever attaching to this promise,\n    // and the last waiter leaving aborts the controller. Keep one no-op\n    // handler so that rejection is never reported as unhandled. Waiters still\n    // observe it, because this does not replace the promise they await.\n    created.promise.catch(() => {});\n    inflight.set(key, created);\n    entry = created;\n  }\n\n  const pending = entry;\n  pending.waiters += 1;\n  try {\n    return await raceRequestAbort(pending.promise, requestSignal);\n  } finally {\n    pending.waiters -= 1;\n    if (pending.waiters === 0 && inflight.get(key) === pending) {\n      inflight.delete(key);\n      pending.controller.abort();\n    }\n  }\n}\n\nfunction raceRequestAbort(\n  promise: Promise<OptimizedImage>,\n  signal: AbortSignal,\n): Promise<OptimizedImage> {\n  if (!signal) return promise;\n  if (signal.aborted) return Promise.reject(signal.reason ?? new Error(\"Aborted\"));\n\n  return new Promise<OptimizedImage>((resolve, reject) => {\n    const onAbort = () => reject(signal.reason ?? new Error(\"Aborted\"));\n    signal.addEventListener(\"abort\", onAbort, { once: true });\n    promise.then(resolve, reject).finally(() => signal.removeEventListener(\"abort\", onAbort));\n  });\n}\n\nasync function readResponseWithLimit(response: Response, limit: number): Promise<Uint8Array> {\n  const contentLength = response.headers.get(\"content-length\");\n  if (contentLength && Number(contentLength) > limit) {\n    // Cleanup (including an unread tee branch) must not delay the size rejection.\n    void cancelResponseBody(response);\n    throw new FarmImageRequestError(\"BODY_TOO_LARGE\", 413, \"Source image is too large\");\n  }\n\n  if (!response.body) return new Uint8Array();\n  const reader = response.body.getReader();\n  const chunks: Uint8Array[] = [];\n  let byteLength = 0;\n\n  try {\n    while (true) {\n      const { done, value } = await reader.read();\n      if (done) break;\n      byteLength += value.byteLength;\n      if (byteLength > limit) {\n        const error = new FarmImageRequestError(\"BODY_TOO_LARGE\", 413, \"Source image is too large\");\n        void reader.cancel(error).catch(() => {});\n        throw error;\n      }\n      chunks.push(value);\n    }\n  } finally {\n    reader.releaseLock();\n  }\n\n  const result = new Uint8Array(byteLength);\n  let offset = 0;\n  for (const chunk of chunks) {\n    result.set(chunk, offset);\n    offset += chunk.byteLength;\n  }\n  return result;\n}\n\nasync function cancelResponseBody(response: Response): Promise<void> {\n  try {\n    await response.body?.cancel();\n  } catch {\n    // Cleanup must not replace the request error or redirect result.\n  }\n}\n\nfunction detectImageContentType(bytes: Uint8Array): string {\n  if (\n    bytes.length >= 8 &&\n    bytes[0] === 0x89 &&\n    bytes[1] === 0x50 &&\n    bytes[2] === 0x4e &&\n    bytes[3] === 0x47\n  ) {\n    return \"image/png\";\n  }\n  if (bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {\n    return \"image/jpeg\";\n  }\n  if (bytes.length >= 6) {\n    const signature = new TextDecoder().decode(bytes.slice(0, 6));\n    if (signature === \"GIF87a\" || signature === \"GIF89a\") return \"image/gif\";\n  }\n  if (bytes.length >= 12) {\n    const riff = new TextDecoder().decode(bytes.slice(0, 4));\n    const webp = new TextDecoder().decode(bytes.slice(8, 12));\n    if (riff === \"RIFF\" && webp === \"WEBP\") return \"image/webp\";\n    const box = new TextDecoder().decode(bytes.slice(4, 12));\n    if (box.startsWith(\"ftypavif\") || box.startsWith(\"ftypavis\")) return \"image/avif\";\n  }\n\n  const prefix = new TextDecoder().decode(bytes.slice(0, 512)).trimStart().toLowerCase();\n  if (prefix.startsWith(\"<svg\") || (prefix.startsWith(\"<?xml\") && prefix.includes(\"<svg\"))) {\n    return \"image/svg+xml\";\n  }\n  return \"\";\n}\n\nfunction validateSourceType(type: string, config: ResolvedFarmImageConfig): void {\n  if (!type || (type === \"image/svg+xml\" && !config.dangerouslyAllowSVG)) {\n    throw new FarmImageRequestError(\"UNSUPPORTED_IMAGE\", 415, \"Unsupported source image\");\n  }\n}\n\nfunction validateTransformedResult(\n  result: FarmImageTransformResult,\n  config: ResolvedFarmImageConfig,\n): void {\n  if (!(result.body instanceof Uint8Array) || result.body.byteLength === 0) {\n    throw new Error(\"The image transformer returned an empty response\");\n  }\n  if (result.body.byteLength > config.maximumResponseBody) {\n    throw new FarmImageRequestError(\"BODY_TOO_LARGE\", 413, \"Optimized image is too large\");\n  }\n  const contentType = normalizeImageContentType(result.contentType);\n  if (!contentType || (contentType === \"image/svg+xml\" && !config.dangerouslyAllowSVG)) {\n    throw new Error(\"The image transformer returned an unsupported content type\");\n  }\n  result.contentType = contentType;\n}\n\nfunction normalizeImageContentType(value: string | null): string {\n  const type = value?.split(\";\", 1)[0].trim().toLowerCase() ?? \"\";\n  return type.startsWith(\"image/\") ? type : \"\";\n}\n\nfunction matchesRemoteSource(url: URL, config: ResolvedFarmImageConfig): boolean {\n  if (config.domains.includes(url.hostname.toLowerCase())) return true;\n  return config.remotePatterns.some((pattern) => matchesRemotePattern(url, pattern));\n}\n\nfunction matchesRemotePattern(url: URL, pattern: FarmImageRemotePattern): boolean {\n  return (\n    (!pattern.protocol || url.protocol === `${pattern.protocol}:`) &&\n    matchesHostname(url.hostname, pattern.hostname) &&\n    (pattern.port === undefined || url.port === pattern.port) &&\n    matchesGlob(url.pathname, pattern.pathname ?? \"/**\") &&\n    (pattern.search === undefined || url.search === pattern.search)\n  );\n}\n\nfunction matchesLocalPatterns(url: URL, patterns: readonly FarmImageLocalPattern[]): boolean {\n  return patterns.some(\n    (pattern) =>\n      matchesGlob(url.pathname, pattern.pathname) &&\n      (pattern.search === undefined || url.search === pattern.search),\n  );\n}\n\nfunction matchesHostname(hostname: string, pattern: string): boolean {\n  const normalizedHostname = hostname.toLowerCase();\n  const normalizedPattern = pattern.toLowerCase();\n  if (normalizedPattern.startsWith(\"**.\")) {\n    const suffix = normalizedPattern.slice(3);\n    return normalizedHostname === suffix || normalizedHostname.endsWith(`.${suffix}`);\n  }\n  if (normalizedPattern.startsWith(\"*.\")) {\n    const suffix = normalizedPattern.slice(2);\n    const prefix = normalizedHostname.slice(0, -(suffix.length + 1));\n    return normalizedHostname.endsWith(`.${suffix}`) && !!prefix && !prefix.includes(\".\");\n  }\n  return normalizedHostname === normalizedPattern;\n}\n\nfunction matchesGlob(value: string, pattern: string): boolean {\n  const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n  const source = escaped.replace(/\\*\\*/g, \"\\0\").replace(/\\*/g, \"[^/]*\").replace(/\\0/g, \".*\");\n  return new RegExp(`^${source}$`).test(value);\n}\n\nfunction createOptimizedImageResponse(\n  request: Request,\n  image: OptimizedImage,\n  config: ResolvedFarmImageConfig,\n): Response {\n  const headers = new Headers({\n    \"cache-control\": image.cacheControl,\n    \"content-type\": image.contentType,\n    \"content-length\": String(image.body.byteLength),\n    \"content-disposition\": \"inline\",\n    etag: image.etag,\n    vary: \"Accept\",\n    \"x-content-type-options\": \"nosniff\",\n  });\n  if (image.contentType === \"image/svg+xml\" && config.dangerouslyAllowSVG) {\n    headers.set(\"content-security-policy\", \"default-src 'none'; sandbox\");\n  }\n  if (matchesFarmIfNoneMatch(request.headers.get(\"if-none-match\"), image.etag)) {\n    headers.delete(\"content-length\");\n    return new Response(null, { status: 304, headers });\n  }\n  const body =\n    request.method === \"HEAD\"\n      ? null\n      : image.body.buffer.slice(\n          image.body.byteOffset,\n          image.body.byteOffset + image.body.byteLength,\n        );\n  return new Response(body as ArrayBuffer | null, { status: 200, headers });\n}\n\nfunction createFarmImageErrorResponse(error: unknown): Response {\n  const status =\n    error instanceof FarmImageRequestError ? error.status : isAbortError(error) ? 499 : 500;\n  const headers = new Headers({\n    \"cache-control\": \"no-store\",\n    \"content-type\": \"text/plain; charset=utf-8\",\n    \"x-content-type-options\": \"nosniff\",\n  });\n  if (status === 405) headers.set(\"allow\", \"GET, HEAD\");\n\n  const message =\n    status === 400\n      ? \"Invalid image request\"\n      : status === 404\n        ? \"Image not found\"\n        : status === 405\n          ? \"Method not allowed\"\n          : status === 413\n            ? \"Image is too large\"\n            : status === 415\n              ? \"Unsupported image\"\n              : status === 499\n                ? \"Image request cancelled\"\n                : \"Image optimization failed\";\n  return new Response(message, { status, headers });\n}\n\nfunction createImageEtag(bytes: Uint8Array): string {\n  let hash = 0x811c9dc5;\n  for (const byte of bytes) {\n    hash ^= byte;\n    hash = Math.imul(hash, 0x01000193);\n  }\n  return `W/\"farm-${bytes.byteLength.toString(16)}-${(hash >>> 0).toString(16)}\"`;\n}\n\nfunction throwIfAborted(signal: AbortSignal): void {\n  if (signal.aborted) {\n    throw signal.reason instanceof Error\n      ? signal.reason\n      : new DOMException(\"The image request was aborted\", \"AbortError\");\n  }\n}\n\nfunction isAbortError(error: unknown): boolean {\n  return error instanceof Error && error.name === \"AbortError\";\n}\n\nclass FarmImageMemoryCache {\n  private readonly entries = new Map<string, OptimizedImage>();\n\n  constructor(private readonly capacity: number) {}\n\n  get(key: string): OptimizedImage | undefined {\n    const value = this.entries.get(key);\n    if (!value) return undefined;\n    if (value.expiresAt <= Date.now()) {\n      this.entries.delete(key);\n      return undefined;\n    }\n    this.entries.delete(key);\n    this.entries.set(key, value);\n    return value;\n  }\n\n  set(key: string, value: OptimizedImage): void {\n    if (this.capacity <= 0) return;\n    this.entries.delete(key);\n    this.entries.set(key, value);\n    while (this.entries.size > this.capacity) {\n      const oldestKey = this.entries.keys().next().value as string | undefined;\n      if (oldestKey === undefined) break;\n      this.entries.delete(oldestKey);\n    }\n  }\n}\n"],"mappings":"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","names":[]}