{"version":3,"sources":["../../src/query/client.ts","../../src/client/metadata-reconciler.ts","../../src/i18n/client-runtime.ts","../../src/i18n/bridge.ts","../../src/client/spa-router.ts","../../src/client/history-sync.ts","../../src/server/request-bridge.ts","../../src/query/sync.ts","../../src/query/params.ts","../../src/query/parsers.ts"],"sourcesContent":["/**\n * Farm.js Client-Side Query State Management\n *\n * Type-safe URL search parameter state management - Like useState, but stored in the URL query string.\n * Client-only hooks for managing query parameters in the browser.\n * Inspired by nuqs implementation patterns.\n */\n\nimport { useState, useEffect, useCallback, useRef } from \"react\";\nimport {\n  notifyHistoryChange,\n  subscribeHistoryChange,\n  writeFarmURLSearchHistory,\n} from \"../client/history-sync\";\nimport { _resolveCurrentRequest } from \"../server/request-bridge\";\nimport { emitter, type KeyUpdate } from \"./sync\";\nexport { parseRouteParams, loadRouteParams, type RouteParamsInput } from \"./params\";\n\nimport { asString as asStringClient, asInteger as asIntegerClient, type Parser } from \"./parsers\";\n\nexport {\n  asString,\n  asInteger,\n  asFloat,\n  asBoolean,\n  asArrayOf,\n  asJson,\n  asIsoDate,\n  asIsoDateTime,\n  createParser,\n  type ArrayParserOptions,\n  type Parser,\n  type inferParserType,\n} from \"./parsers\";\n\nexport type UrlUpdateType = \"push\" | \"replace\";\nexport type HistoryMethod = \"pushState\" | \"replaceState\";\n\nexport interface Options {\n  history?: HistoryMethod;\n  shallow?: boolean;\n  scroll?: boolean;\n  throttleMs?: number;\n}\n\nconst getCurrentSearchParams = (): URLSearchParams => {\n  if (typeof window !== \"undefined\") {\n    discardDepartedURLUpdates();\n    let params = new URLSearchParams(window.location.search);\n    // Draft values belong to the existing throttle queue, not to a parser's\n    // identity. Inline parsers and newly mounted consumers see the same draft.\n    for (const pending of throttleTimers.values()) {\n      if (pending.href === window.location.href) params = applyChange(params, pending.updates);\n    }\n    return params;\n  }\n\n  // Server rendering used to see an empty query string here, so a hook read one\n  // value on the server and another in the browser. React reports that as a\n  // hydration mismatch and discards the server rendered markup for the branch.\n  const request = _resolveCurrentRequest();\n  if (!request) return new URLSearchParams();\n  try {\n    return new URL(request.url).searchParams;\n  } catch {\n    return new URLSearchParams();\n  }\n};\n\nconst readSearchParam = (searchParams: URLSearchParams, key: string): string => {\n  const values = searchParams.getAll(key);\n  return values.length > 1 ? values.join(\",\") : (values[0] ?? \"\");\n};\n\nconst throttleTimers = new Map<\n  string,\n  {\n    timer: ReturnType<typeof setTimeout>;\n    updates: Record<string, string | null>;\n    href: string;\n  }\n>();\n\nfunction discardDepartedURLUpdates(): void {\n  for (const [key, pending] of throttleTimers) {\n    if (pending.href === window.location.href) continue;\n    clearTimeout(pending.timer);\n    throttleTimers.delete(key);\n  }\n}\n\nfunction getUpdateKey(updates: Record<string, unknown>): string {\n  return JSON.stringify(Object.keys(updates).sort());\n}\n\nfunction supersedeQueuedKeys(updates: Record<string, string | null>): void {\n  const keys = Object.keys(updates);\n  for (const [queueKey, pending] of throttleTimers) {\n    for (const key of keys) delete pending.updates[key];\n    if (Object.keys(pending.updates).length > 0) continue;\n    clearTimeout(pending.timer);\n    throttleTimers.delete(queueKey);\n  }\n}\n\nconst compareStructuredValues = (\n  current: unknown,\n  next: unknown,\n  seen = new WeakMap<object, object>(),\n): boolean | undefined => {\n  if (Object.is(current, next)) return true;\n  if (current === null || next === null || typeof current !== typeof next) return false;\n  if (typeof current !== \"object\" || typeof next !== \"object\") return false;\n  if (current instanceof Date || next instanceof Date) {\n    return current instanceof Date && next instanceof Date && current.getTime() === next.getTime();\n  }\n  if (Array.isArray(current) || Array.isArray(next)) {\n    if (!Array.isArray(current) || !Array.isArray(next) || current.length !== next.length) {\n      return false;\n    }\n    const knownNext = seen.get(current);\n    if (knownNext) return knownNext === next;\n    seen.set(current, next);\n    for (let index = 0; index < current.length; index++) {\n      const equal = compareStructuredValues(current[index], next[index], seen);\n      if (equal !== true) return equal;\n    }\n    return true;\n  }\n\n  const currentPrototype = Object.getPrototypeOf(current);\n  const nextPrototype = Object.getPrototypeOf(next);\n  if (currentPrototype !== nextPrototype) return false;\n  if (currentPrototype !== Object.prototype && currentPrototype !== null) return undefined;\n\n  const knownNext = seen.get(current);\n  if (knownNext) return knownNext === next;\n  seen.set(current, next);\n\n  const currentKeys = Object.keys(current);\n  const nextKeys = Object.keys(next);\n  if (\n    currentKeys.length !== nextKeys.length ||\n    currentKeys.some((key) => !Object.prototype.hasOwnProperty.call(next, key))\n  ) {\n    return false;\n  }\n  for (const key of currentKeys) {\n    const equal = compareStructuredValues(\n      (current as Record<string, unknown>)[key],\n      (next as Record<string, unknown>)[key],\n      seen,\n    );\n    if (equal !== true) return equal;\n  }\n  return true;\n};\n\nconst areParsedValuesEqual = <T>(parser: Parser<T>, current: T | null, next: T | null) => {\n  if (Object.is(current, next)) return true;\n  const structuredResult = compareStructuredValues(current, next);\n  if (structuredResult === false) return false;\n  if (current === null || next === null) return false;\n\n  try {\n    return parser.serialize(current) === parser.serialize(next);\n  } catch {\n    return structuredResult === true;\n  }\n};\n\nconst applyChange = (\n  searchParams: URLSearchParams,\n  updates: Record<string, string | null>,\n  keepExisting = true,\n): URLSearchParams => {\n  const newParams = keepExisting ? new URLSearchParams(searchParams) : new URLSearchParams();\n\n  Object.entries(updates).forEach(([key, value]) => {\n    if (value === null || value === undefined || value === \"\") {\n      newParams.delete(key);\n    } else {\n      newParams.set(key, value);\n    }\n  });\n\n  return newParams;\n};\n\nconst commitURLUpdate = (\n  updates: Record<string, string | null>,\n  options: Options,\n  emitUpdate: boolean,\n) => {\n  const { history = \"pushState\", shallow = true, scroll = false } = options;\n  const url = new URL(window.location.href);\n  const newSearchParams = applyChange(url.searchParams, updates);\n  const newSearch = newSearchParams.toString();\n  const newUrl = url.pathname + (newSearch ? `?${newSearch}` : \"\") + url.hash;\n  const currentUrl = url.pathname + url.search + url.hash;\n\n  if (newUrl === currentUrl) return;\n\n  const historyAction = history === \"replaceState\" ? \"replace\" : \"push\";\n  if (!writeFarmURLSearchHistory(historyAction, newUrl)) {\n    const historyState = window.history.state;\n    const nextHistoryState =\n      historyState && typeof historyState === \"object\" && \"path\" in historyState\n        ? { ...historyState, path: newUrl }\n        : historyState;\n    window.history[history](nextHistoryState, \"\", newUrl);\n  }\n\n  if (emitUpdate) {\n    // Composing one queued key must not discard drafts for other keys. Only\n    // carry drafts forward across this write, never across unrelated navigation.\n    for (const pending of throttleTimers.values()) {\n      if (pending.href === url.href) pending.href = window.location.href;\n    }\n    emitter.emitUpdate(getCurrentSearchParams());\n  }\n\n  if (shallow) notifyHistoryChange(\"url-search\");\n\n  if (scroll) {\n    window.scrollTo(0, 0);\n  }\n};\n\nconst updateURL = (\n  updates: Record<string, string | null>,\n  options: Options = {},\n  emitUpdate = true,\n): (() => boolean) | undefined => {\n  if (typeof window === \"undefined\") return;\n\n  discardDepartedURLUpdates();\n\n  const { throttleMs } = options;\n  // Latest intent owns each key, including immediate writes and URL no-ops.\n  // Keep unrelated keys in an older batch scheduled with their original owner.\n  supersedeQueuedKeys(updates);\n  if (!throttleMs || throttleMs <= 0) {\n    commitURLUpdate(updates, options, emitUpdate);\n    return;\n  }\n\n  const throttleKey = getUpdateKey(updates);\n\n  const currentUrl = new URL(window.location.href);\n  const nextSearch = applyChange(currentUrl.searchParams, updates).toString();\n  if (nextSearch === currentUrl.searchParams.toString()) return;\n\n  const timeout = setTimeout(() => {\n    const pending = throttleTimers.get(throttleKey);\n    if (pending?.timer !== timeout) return;\n    throttleTimers.delete(throttleKey);\n    if (pending.href !== window.location.href) return;\n    commitURLUpdate(updates, options, emitUpdate);\n  }, throttleMs);\n\n  throttleTimers.set(throttleKey, { timer: timeout, updates, href: currentUrl.href });\n  return () => {\n    if (throttleTimers.get(throttleKey)?.timer !== timeout) return false;\n    clearTimeout(timeout);\n    throttleTimers.delete(throttleKey);\n    return true;\n  };\n};\n\nexport function useQueryState<TParser extends Parser<any>>(\n  key: string,\n  parser: TParser,\n  options?: Options,\n): [\n  NonNullable<ReturnType<TParser[\"parse\"]>> | null,\n  (value: NonNullable<ReturnType<TParser[\"parse\"]>> | null) => void,\n];\nexport function useQueryState<T>(\n  key: string,\n  parser: Parser<T>,\n  options?: Options,\n): [T | null, (value: T | null) => void];\nexport function useQueryState<TParser extends Parser<any>>(\n  key: string,\n  parser: TParser,\n  options?: Options,\n): [\n  NonNullable<ReturnType<TParser[\"parse\"]>> | null,\n  (value: NonNullable<ReturnType<TParser[\"parse\"]>> | null) => void,\n] {\n  type T = NonNullable<ReturnType<TParser[\"parse\"]>>;\n  const [state, setState] = useState<T | null>(() => {\n    const searchParams = getCurrentSearchParams();\n    const parsed = parser.parse(readSearchParam(searchParams, key));\n    return parsed;\n  });\n\n  const stateRef = useRef(state);\n  const stateKeyRef = useRef(key);\n  const cancelPendingUpdateRef = useRef<(() => boolean) | undefined>(undefined);\n  stateRef.current = state;\n\n  const setValue = useCallback(\n    (value: T | null) => {\n      setState(value);\n      stateRef.current = value;\n\n      const serialized = value === null ? null : parser.serialize(value);\n\n      emitter.emitKey(key, { state: value, query: serialized, source: stateRef });\n\n      cancelPendingUpdateRef.current?.();\n      cancelPendingUpdateRef.current = updateURL({ [key]: serialized }, options, true);\n    },\n    [key, parser, options],\n  );\n\n  useEffect(() => {\n    if (typeof window === \"undefined\") return;\n\n    const onPopState = () => {\n      const searchParams = getCurrentSearchParams();\n      const parsed = parser.parse(readSearchParam(searchParams, key));\n      const sourceChanged = stateKeyRef.current !== key;\n      stateKeyRef.current = key;\n      if (sourceChanged || !areParsedValuesEqual(parser, stateRef.current, parsed)) {\n        setState(parsed);\n        stateRef.current = parsed;\n      }\n    };\n\n    const onEmitterUpdate = (searchParams: URLSearchParams) => {\n      const parsed = parser.parse(readSearchParam(searchParams, key));\n      if (!areParsedValuesEqual(parser, stateRef.current, parsed)) {\n        setState(parsed);\n        stateRef.current = parsed;\n      }\n    };\n\n    const onKeyUpdate = (payload: KeyUpdate) => {\n      // Skip only this hook's synchronous echo, never a peer's newer edit.\n      // The ref identity is stable across renders and is not serialized.\n      if (payload.source === stateRef) {\n        return;\n      }\n\n      // Consumers may use different parsers for the same URL key.\n      const parsed = parser.parse(payload.query ?? \"\");\n      if (!areParsedValuesEqual(parser, stateRef.current, parsed)) {\n        setState(parsed);\n        stateRef.current = parsed;\n      }\n    };\n\n    // Page-state writes with an href can change the query string without a\n    // popstate, so listen through the shared history channel (real\n    // back/forward events included). Self-updates no-op via the Object.is\n    // comparison above.\n    onPopState();\n    const unsubscribeHistory = subscribeHistoryChange(onPopState);\n    emitter.on(\"update\", onEmitterUpdate);\n    emitter.onKey(key, onKeyUpdate);\n\n    return () => {\n      unsubscribeHistory();\n      emitter.off(\"update\", onEmitterUpdate);\n      emitter.offKey(key, onKeyUpdate);\n    };\n  }, [key, parser]);\n\n  useEffect(\n    () => () => {\n      const canceledPendingWrite = cancelPendingUpdateRef.current?.() ?? false;\n      cancelPendingUpdateRef.current = undefined;\n      // A throttled write is discarded on unmount, but its value was already\n      // broadcast to peers via emitKey. Peers that adopted the optimistic draft\n      // get no other reconciliation signal (unmount fires no history event), so\n      // tell them to re-read the URL, which no longer carries this draft.\n      if (canceledPendingWrite && typeof window !== \"undefined\") {\n        emitter.emitUpdate(getCurrentSearchParams());\n      }\n    },\n    [key],\n  );\n\n  return [state, setValue];\n}\n\nexport function useQueryStates<T extends Record<string, Parser<any>>>(\n  parsers: T,\n  options: Options = {},\n): [\n  { [K in keyof T]: ReturnType<T[K][\"parse\"]> },\n  (updates: Partial<{ [K in keyof T]: ReturnType<T[K][\"parse\"]> | null }>) => void,\n] {\n  const keys = Object.keys(parsers);\n  const watchKeys = JSON.stringify(keys);\n\n  const [state, setState] = useState<{ [K in keyof T]: ReturnType<T[K][\"parse\"]> }>(() => {\n    const searchParams = getCurrentSearchParams();\n    const result = {} as { [K in keyof T]: ReturnType<T[K][\"parse\"]> };\n\n    Object.entries(parsers).forEach(([key, parser]) => {\n      result[key as keyof T] = parser.parse(readSearchParam(searchParams, key));\n    });\n\n    return result;\n  });\n\n  const stateRef = useRef(state);\n  const pendingUpdatesRef = useRef(new Map<string, () => boolean>());\n  stateRef.current = state;\n\n  const setValues = useCallback(\n    (updates: Partial<{ [K in keyof T]: ReturnType<T[K][\"parse\"]> | null }>) => {\n      const newState = { ...stateRef.current, ...updates };\n      setState(newState);\n      stateRef.current = newState;\n\n      Object.entries(updates).forEach(([key, value]) => {\n        const parser = parsers[key];\n        if (parser) {\n          const serialized = value === null ? null : parser.serialize(value);\n          emitter.emitKey(key, { state: value, query: serialized, source: stateRef });\n        }\n      });\n\n      const urlUpdates: Record<string, string | null> = {};\n      Object.entries(updates).forEach(([key, value]) => {\n        const parser = parsers[key];\n        if (parser) {\n          const serialized = value === null ? null : parser.serialize(value);\n          urlUpdates[key] = serialized;\n        }\n      });\n\n      const updateKey = getUpdateKey(urlUpdates);\n      pendingUpdatesRef.current.get(updateKey)?.();\n      const cancelPendingUpdate = updateURL(urlUpdates, options, true);\n      if (cancelPendingUpdate) {\n        pendingUpdatesRef.current.set(updateKey, cancelPendingUpdate);\n      } else {\n        pendingUpdatesRef.current.delete(updateKey);\n      }\n    },\n    [parsers, options],\n  );\n\n  useEffect(() => {\n    if (typeof window === \"undefined\") return;\n\n    const applyChange = (searchParams: URLSearchParams) => {\n      const result = {} as { [K in keyof T]: ReturnType<T[K][\"parse\"]> };\n      const currentKeys = Object.keys(stateRef.current);\n      let hasChanged =\n        currentKeys.length !== keys.length ||\n        currentKeys.some((key) => !Object.prototype.hasOwnProperty.call(parsers, key));\n\n      Object.entries(parsers).forEach(([key, parser]) => {\n        const parsed = parser.parse(readSearchParam(searchParams, key));\n        const currentValue = stateRef.current[key as keyof T];\n\n        if (!areParsedValuesEqual(parser, currentValue, parsed)) {\n          hasChanged = true;\n        }\n        result[key as keyof T] = parsed;\n      });\n\n      if (hasChanged) {\n        setState(result);\n        stateRef.current = result;\n      }\n    };\n\n    const onPopState = () => {\n      const searchParams = getCurrentSearchParams();\n      applyChange(searchParams);\n    };\n\n    const onEmitterUpdate = (searchParams: URLSearchParams) => {\n      applyChange(searchParams);\n    };\n\n    applyChange(getCurrentSearchParams());\n    const unsubscribeHistory = subscribeHistoryChange(onPopState);\n    emitter.on(\"update\", onEmitterUpdate);\n    const unsubscribeKeys = Object.entries(parsers).map(([key, parser]) => {\n      const onKeyUpdate = (payload: KeyUpdate) => {\n        if (payload.source === stateRef) return;\n        const parsed = parser.parse(payload.query ?? \"\");\n        if (areParsedValuesEqual(parser, stateRef.current[key as keyof T], parsed)) return;\n\n        // Update only this key, preserving local drafts for the other fields.\n        const next = { ...stateRef.current, [key]: parsed };\n        stateRef.current = next;\n        setState(next);\n      };\n      emitter.onKey(key, onKeyUpdate);\n      return () => emitter.offKey(key, onKeyUpdate);\n    });\n\n    return () => {\n      unsubscribeHistory();\n      emitter.off(\"update\", onEmitterUpdate);\n      for (const unsubscribe of unsubscribeKeys) unsubscribe();\n    };\n  }, [watchKeys, parsers]);\n\n  useEffect(\n    () => () => {\n      let canceledPendingWrite = false;\n      for (const cancelPendingUpdate of pendingUpdatesRef.current.values()) {\n        if (cancelPendingUpdate()) canceledPendingWrite = true;\n      }\n      pendingUpdatesRef.current.clear();\n      // Discarded throttled writes were already broadcast to peers via emitKey;\n      // reconcile any peer that adopted a now-cancelled draft (see useQueryState).\n      if (canceledPendingWrite && typeof window !== \"undefined\") {\n        emitter.emitUpdate(getCurrentSearchParams());\n      }\n    },\n    [watchKeys],\n  );\n\n  return [state, setValues];\n}\n\nexport function usePagination(options?: {\n  defaultPage?: number;\n  defaultLimit?: number;\n  pageKey?: string;\n  limitKey?: string;\n}) {\n  const {\n    defaultPage = 1,\n    defaultLimit = 10,\n    pageKey = \"page\",\n    limitKey = \"limit\",\n  } = options || {};\n\n  const [page, setPage] = useQueryState(pageKey, asIntegerClient.withDefault!(defaultPage));\n  const [limit, setLimit] = useQueryState(limitKey, asIntegerClient.withDefault!(defaultLimit));\n\n  const currentPage = page ?? defaultPage;\n  const currentLimit = limit ?? defaultLimit;\n  const offset = ((currentPage as number) - 1) * (currentLimit as number);\n\n  return {\n    page: currentPage,\n    setPage,\n    limit: currentLimit,\n    setLimit,\n    offset,\n    resetPagination: () => {\n      setPage(defaultPage);\n      setLimit(defaultLimit);\n    },\n  };\n}\n\nexport function useSearchFilters<T extends Record<string, any>>(options?: {\n  searchKey?: string;\n  defaultFilters?: T;\n  filterKeys?: (keyof T)[];\n}) {\n  const {\n    searchKey = \"search\",\n    defaultFilters = {} as T,\n    filterKeys = Object.keys(defaultFilters) as (keyof T)[],\n  } = options || {};\n\n  const [search, setSearch] = useQueryState(searchKey, asStringClient);\n\n  const filterParsers = filterKeys.reduce(\n    (acc, key) => {\n      acc[key as string] = asStringClient;\n      return acc;\n    },\n    {} as Record<string, Parser<string>>,\n  );\n\n  const [filters, setFilters] = useQueryStates(filterParsers);\n\n  const clearFilters = () => {\n    setSearch(null);\n    const clearedFilters = filterKeys.reduce(\n      (acc, key) => {\n        acc[key as string] = null;\n        return acc;\n      },\n      {} as Record<string, null>,\n    );\n    setFilters(clearedFilters);\n  };\n\n  return {\n    search,\n    setSearch,\n    filters: filters as T,\n    setFilters,\n    clearFilters,\n  };\n}\n","import { renderMetadataHead, resolveMetadataTitle } from \"../metadata\";\nimport type { Metadata } from \"../types\";\n\nexport type NavigationMetadata = (Metadata & Record<string, any>) | undefined;\n\n/** Marks head elements this reconciler inserted, so they can be replaced. */\nconst MANAGED_ATTRIBUTE = \"data-farm-metadata\";\n\n/**\n * Head tags the metadata system owns outright. These are swept on every\n * navigation whether or not they carry the managed marker, because the tags\n * rendered by the server for the first page have no marker and must not\n * survive into the next page's head.\n */\nconst OWNED_SELECTORS = [\n  'meta[name=\"description\"]',\n  'meta[name=\"keywords\"]',\n  'meta[name=\"author\"]',\n  'meta[name=\"creator\"]',\n  'meta[name=\"publisher\"]',\n  'meta[name=\"robots\"]',\n  'link[rel=\"author\"]',\n  'link[rel=\"canonical\"]',\n  'link[rel=\"alternate\"]',\n  'meta[property^=\"og:\"]',\n  'meta[name^=\"twitter:\"]',\n].join(\", \");\n\n/**\n * Icons and the web-app manifest have document-level defaults that exist\n * outside page metadata (the default favicon, a discovered manifest route), so\n * an absent value means \"keep what the document has\", not \"remove it\". They\n * are only swept when the next page defines its own.\n */\nconst ICON_SELECTORS = [\n  'link[rel=\"icon\"]',\n  'link[rel=\"shortcut icon\"]',\n  'link[rel=\"apple-touch-icon\"]',\n].join(\", \");\nconst MANIFEST_SELECTOR = 'link[rel=\"manifest\"]';\n\nfunction removeAll(selector: string): void {\n  for (const element of Array.from(document.head.querySelectorAll(selector))) {\n    element.remove();\n  }\n}\n\n/**\n * Make the document head for a client-side navigation match what a full-page\n * load of the target route renders: same title resolution and the same managed\n * tag set, produced by the same `renderMetadataHead` the server uses.\n *\n * JSON-LD is deliberately untouched: the agent JSON-LD script is site identity\n * rather than page metadata, and sweeping ld+json scripts could remove ones the\n * application authored itself.\n */\nexport function applyFarmMetadataToDocument(metadata: NavigationMetadata, pathname: string): void {\n  document.title = resolveMetadataTitle(metadata?.title) || \"Farm.js App\";\n\n  const rendered = renderMetadataHead(metadata, { pathname });\n  const template = document.createElement(\"template\");\n  template.innerHTML = rendered.tags;\n\n  removeAll(OWNED_SELECTORS);\n  if (metadata?.icons) removeAll(ICON_SELECTORS);\n  if (metadata?.manifest) removeAll(MANIFEST_SELECTOR);\n\n  for (const element of Array.from(template.content.children)) {\n    element.setAttribute(MANAGED_ATTRIBUTE, \"\");\n    document.head.appendChild(element);\n  }\n}\n","import IntlMessageFormat from \"intl-messageformat\";\nimport { getActiveFarmI18nSnapshot } from \"./bridge\";\nimport { localizeFarmHref, resolveFarmLocalePath } from \"./routing\";\nimport type {\n  FarmI18nClientSnapshot,\n  FarmI18nLocale,\n  FarmI18nMessageArgs,\n  FarmI18nMessageKey,\n  FarmTranslator,\n} from \"./types\";\n\ntype Listener = () => void;\n\nconst listeners = new Set<Listener>();\nconst compiled = new Map<string, IntlMessageFormat>();\nlet currentSnapshot: FarmI18nClientSnapshot | undefined;\n\nexport function getFarmI18nClientState(): FarmI18nClientSnapshot | undefined {\n  return currentSnapshot || getActiveFarmI18nSnapshot();\n}\n\nexport function subscribeFarmI18n(listener: Listener): () => void {\n  listeners.add(listener);\n  return () => listeners.delete(listener);\n}\n\nexport function _hydrateFarmI18n(snapshot: FarmI18nClientSnapshot | undefined): void {\n  if (!snapshot) return;\n  const changed = currentSnapshot?.locale !== snapshot.locale;\n  currentSnapshot = snapshot;\n  if (typeof window !== \"undefined\") window.__FARM_I18N__ = snapshot;\n  if (typeof document !== \"undefined\") {\n    document.documentElement.lang = snapshot.locale;\n    document.documentElement.dir = snapshot.direction;\n  }\n  if (changed) compiled.clear();\n  for (const listener of listeners) listener();\n}\n\n// Only own catalog entries count. `snapshot.messages` is a spread object that\n// inherits Object.prototype, so a bare lookup for a key like \"toString\" or\n// \"constructor\" would resolve to a native method. The server side guards the\n// same way (readOwnMessage), so without this the client diverges: the server\n// renders the literal key while the client feeds a function to IntlMessageFormat\n// and throws during hydration.\nconst readOwnMessage = (messages: Record<string, string>, key: string): string | undefined =>\n  Object.prototype.hasOwnProperty.call(messages, key) ? messages[key] : undefined;\n\nconst translate = (key: string, values?: Record<string, unknown>, rich = false): unknown => {\n  const snapshot = requireSnapshot();\n  const message = readOwnMessage(snapshot.messages, key);\n  if (message === undefined) return key;\n  const cacheKey = `${snapshot.locale}\\u0000${key}\\u0000${message}`;\n  let formatter = compiled.get(cacheKey);\n  if (!formatter) {\n    formatter = new IntlMessageFormat(message, snapshot.locale);\n    compiled.set(cacheKey, formatter);\n  }\n  const result = formatter.format(values as any);\n  if (rich) return Array.isArray(result) && result.length === 1 ? result[0] : result;\n  if (Array.isArray(result) && result.some((part) => typeof part !== \"string\")) {\n    throw new Error(`Farm i18n message \"${key}\" contains rich content. Render it with t.rich().`);\n  }\n  return Array.isArray(result) ? result.join(\"\") : String(result);\n};\n\nexport const t = ((key: string, values?: Record<string, unknown>) =>\n  translate(key, values)) as FarmTranslator;\nt.rich = (key: string, values?: Record<string, unknown>) => translate(key, values, true);\nt.raw = (key: string) => readOwnMessage(requireSnapshot().messages, key) ?? key;\nt.has = (key: string) => Object.prototype.hasOwnProperty.call(requireSnapshot().messages, key);\n\nexport function localizeActiveFarmHref(href: string, locale?: FarmI18nLocale): string {\n  const snapshot = getFarmI18nClientState();\n  if (!snapshot) return href;\n  return localizeFarmHref(href, locale || snapshot.locale, snapshot);\n}\n\nexport function isFarmLocaleChangeHref(href: string): boolean {\n  const snapshot = getFarmI18nClientState();\n  if (!snapshot || typeof window === \"undefined\") return false;\n  if (snapshot.routing === \"none\") return false;\n  const target = new URL(href, window.location.origin);\n  const match = resolveFarmLocalePath(target.pathname, snapshot);\n  const targetLocale = match.locale || snapshot.defaultLocale;\n  return targetLocale !== snapshot.locale;\n}\n\nexport function createFarmClientTranslator(): FarmTranslator {\n  return (<TKey extends FarmI18nMessageKey>(key: TKey, ...args: FarmI18nMessageArgs<TKey>) =>\n    t(key, ...args)) as FarmTranslator;\n}\n\nfunction requireSnapshot(): FarmI18nClientSnapshot {\n  const snapshot = getFarmI18nClientState();\n  if (!snapshot) {\n    throw new Error(\"Farm i18n is not configured or has not been hydrated.\");\n  }\n  return snapshot;\n}\n","import type { FarmI18nClientSnapshot } from \"./types\";\n\ntype SnapshotResolver = () => FarmI18nClientSnapshot | undefined;\n\nconst FARM_I18N_SNAPSHOT_RESOLVER = Symbol.for(\"farm.i18n.snapshotResolver\");\ntype GlobalWithI18nResolver = typeof globalThis & {\n  [FARM_I18N_SNAPSHOT_RESOLVER]?: SnapshotResolver;\n};\n\nexport function _setFarmI18nSnapshotResolver(resolver: SnapshotResolver | undefined): void {\n  (globalThis as GlobalWithI18nResolver)[FARM_I18N_SNAPSHOT_RESOLVER] = resolver;\n}\n\nexport function getActiveFarmI18nSnapshot(): FarmI18nClientSnapshot | undefined {\n  if (typeof window !== \"undefined\" && window.__FARM_I18N__) {\n    return window.__FARM_I18N__;\n  }\n  return (globalThis as GlobalWithI18nResolver)[FARM_I18N_SNAPSHOT_RESOLVER]?.();\n}\n","\"use client\";\n\nimport { readDeferredDataResponse } from \"../deferred\";\nimport { notifyHistoryChange, notifyRouterHistoryChange } from \"./history-sync\";\nimport {\n  createFarmDeploymentMismatchError,\n  createFarmDeploymentRequestHeaders,\n  isFarmDeploymentMismatchResponse,\n} from \"../deployment\";\nimport { getHashTargetElement } from \"./hash-target\";\nimport { isFarmExternalNavigationURL, resolveFarmNavigationURL } from \"./navigation-url\";\nimport { applyFarmMetadataToDocument, type NavigationMetadata } from \"./metadata-reconciler\";\nimport type { FarmClientNavigationSession, FarmClientPluginManager } from \"./plugin\";\nimport { _hydrateFarmI18n, isFarmLocaleChangeHref } from \"../i18n/client-runtime\";\nimport type { FarmI18nClientSnapshot } from \"../i18n/types\";\nimport type { FarmIslandStrategy } from \"../island\";\nimport type { FarmRouteRenderPlan } from \"../navigation/render-plan\";\n\nexport { getHashTargetElement } from \"./hash-target\";\nexport { isFarmExternalNavigationURL } from \"./navigation-url\";\n\n/**\n * Farm.js SPA Router\n *\n * Provides client-side navigation without full page reloads.\n * Features:\n * - Prefetch on viewport intersection\n * - Prefetch on hover\n * - Page caching\n * - History API integration\n * - Scroll restoration\n */\n\ninterface PageData {\n  props: Record<string, any>;\n  modulePath: string;\n  loadingModulePath?: string | null;\n  canonicalPath?: string;\n  isClientComponent?: boolean;\n  shouldHydrate?: boolean;\n  islandStrategy?: FarmIslandStrategy | null;\n  renderPlan?: FarmRouteRenderPlan;\n  fragment?: {\n    html: string;\n    layoutPatterns: string[];\n  };\n  metadata?: NavigationMetadata;\n  layoutModules?: string[];\n  routeSlots?: RouteSlotPageData[];\n  interception?: {\n    from?: string;\n    slots: string[];\n  };\n  i18n?: FarmI18nClientSnapshot;\n}\n\ninterface RouteSlotPageData {\n  name: string;\n  ownerPattern: string;\n  containerId: string;\n  interception: boolean;\n  fallback: boolean;\n  modulePath: string;\n  isClientComponent: boolean;\n  shouldHydrate: boolean;\n  props: Record<string, any>;\n}\n\nexport interface RouterOptions {\n  prefetchTimeout?: number;\n  cacheMaxAge?: number;\n  scrollRestoration?: boolean;\n  shouldUseDocumentNavigation?: (pathname: string) => boolean;\n  deploymentId?: string;\n}\n\ninterface CacheEntry {\n  data: PageData;\n  timestamp: number;\n}\n\nexport interface FarmNavigationBlockerContext {\n  from: string;\n  to: string;\n  action: \"push\" | \"replace\" | \"pop\";\n}\n\nexport type FarmNavigationBlocker = (\n  context: FarmNavigationBlockerContext,\n) => boolean | void | Promise<boolean | void>;\n\nexport type FarmViewTransitionMode = boolean | \"auto\";\n\nexport interface FarmNavigateOptions {\n  replace?: boolean;\n  scroll?: boolean;\n  state?: unknown;\n  viewTransition?: FarmViewTransitionMode;\n  /** Re-fetch the current route even when its URL has not changed. */\n  refresh?: boolean;\n}\n\nexport interface FarmNavigationLocation {\n  href: string;\n  pathname: string;\n  search: string;\n  hash: string;\n}\n\nexport interface FarmNavigationState {\n  state: \"idle\" | \"loading\";\n  pending: boolean;\n  from: string | null;\n  to: FarmNavigationLocation | null;\n  action: FarmNavigationBlockerContext[\"action\"] | null;\n  startedAt: number | null;\n}\n\nexport type FarmNavigationListener = (state: FarmNavigationState) => void;\n\nconst FARM_PAGE_STATE_KEY = \"__farmPageState\";\nconst FARM_INTERCEPT_FROM_KEY = \"__farmInterceptFrom\";\nconst FARM_HISTORY_INDEX_KEY = \"__farmHistoryIndex\";\n\nfunction readHistoryIndex(state: unknown): number | null {\n  if (!state || typeof state !== \"object\") return null;\n  const value = (state as Record<string, unknown>)[FARM_HISTORY_INDEX_KEY];\n  return typeof value === \"number\" && Number.isFinite(value) ? value : null;\n}\nconst IDLE_NAVIGATION_STATE: FarmNavigationState = {\n  state: \"idle\",\n  pending: false,\n  from: null,\n  to: null,\n  action: null,\n  startedAt: null,\n};\n\nfunction getActiveLayoutChainHeader(): string | undefined {\n  if (typeof document === \"undefined\") return undefined;\n  const patterns = Array.from(\n    document.querySelectorAll<HTMLElement>('[data-farm-layout-boundary=\"true\"]'),\n  )\n    .map((element) => element.dataset.farmLayoutPattern)\n    .filter((pattern): pattern is string => Boolean(pattern));\n  return patterns.length > 0 ? JSON.stringify(patterns) : undefined;\n}\n\n// Global router instance\nlet routerInstance: SPARouter | null = null;\n\nexport class SPARouter {\n  private cache: Map<string, CacheEntry> = new Map();\n  private prefetchingUrls: Set<string> = new Set();\n  private observers: Map<Element, IntersectionObserver> = new Map();\n  private prefetchTimers: Map<Element, ReturnType<typeof setTimeout>> = new Map();\n  private blockers: Set<FarmNavigationBlocker> = new Set();\n  private unloadBlockers: Map<FarmNavigationBlocker, () => boolean> = new Map();\n  private navigationListeners: Set<FarmNavigationListener> = new Set();\n  private navigationState: FarmNavigationState = IDLE_NAVIGATION_STATE;\n  private currentHistoryPath: string | null = null;\n  private currentHistoryIndex: number | null = null;\n  private suppressNextPopState = false;\n  private navigationSequence = 0;\n  private activeNavigation?: {\n    id: number;\n    controller: AbortController;\n  };\n  private scrollElements: Map<string, HTMLElement> = new Map();\n  private options: Required<Omit<RouterOptions, \"deploymentId\">> &\n    Pick<RouterOptions, \"deploymentId\">;\n  private onNavigate?: (data: PageData) => Promise<void>;\n  private clientPlugins?: Pick<\n    FarmClientPluginManager,\n    | \"beginNavigation\"\n    | \"markNavigationLoaded\"\n    | \"resolveNavigation\"\n    | \"scheduleNavigationRendered\"\n    | \"failNavigation\"\n  >;\n\n  private readonly onPopState = (event: PopStateEvent) => {\n    void this.handlePopState(event);\n  };\n\n  private readonly onBeforeUnload = (event: BeforeUnloadEvent) => {\n    if (this.shouldBlockUnload()) {\n      event.preventDefault();\n      event.returnValue = \"\";\n    }\n    this.saveScrollPosition(window.location.pathname + window.location.search);\n  };\n\n  constructor(options: RouterOptions = {}) {\n    this.options = {\n      prefetchTimeout: options.prefetchTimeout ?? 100,\n      cacheMaxAge: options.cacheMaxAge ?? 30000, // 30 seconds\n      scrollRestoration: options.scrollRestoration ?? true,\n      shouldUseDocumentNavigation: options.shouldUseDocumentNavigation ?? (() => false),\n      deploymentId: options.deploymentId ?? readBrowserDeploymentId(),\n    };\n\n    if (typeof window !== \"undefined\") {\n      // Listen for popstate (back/forward navigation)\n      window.addEventListener(\"popstate\", this.onPopState);\n\n      // Save scroll position before unload\n      window.addEventListener(\"beforeunload\", this.onBeforeUnload);\n\n      // Track the rendered location and its position in the history stack so\n      // popstate can report a real `from` and revert blocked traversals.\n      this.currentHistoryPath = window.location.pathname + window.location.search;\n      const existingIndex = readHistoryIndex(window.history.state);\n      if (existingIndex == null) {\n        try {\n          window.history.replaceState(\n            {\n              ...((window.history.state as object | null) ?? {}),\n              [FARM_HISTORY_INDEX_KEY]: 0,\n            },\n            \"\",\n            window.location.href,\n          );\n          this.currentHistoryIndex = 0;\n        } catch {\n          this.currentHistoryIndex = null;\n        }\n      } else {\n        this.currentHistoryIndex = existingIndex;\n      }\n    }\n  }\n\n  /** Remove global listeners. Intended for tests and teardown. */\n  destroy(): void {\n    if (typeof window === \"undefined\") return;\n    this.cancelActiveNavigation();\n    for (const observer of this.observers.values()) observer.disconnect();\n    for (const timer of this.prefetchTimers.values()) clearTimeout(timer);\n    this.observers.clear();\n    this.prefetchTimers.clear();\n    window.removeEventListener(\"popstate\", this.onPopState);\n    window.removeEventListener(\"beforeunload\", this.onBeforeUnload);\n  }\n\n  /**\n   * Set the navigation handler that updates React\n   */\n  setNavigationHandler(handler: (data: PageData) => Promise<void>) {\n    this.onNavigate = handler;\n  }\n\n  /**\n   * Connect Farm's browser plugin lifecycle to SPA navigation.\n   */\n  setClientPluginManager(manager: FarmClientPluginManager) {\n    this.clientPlugins = manager;\n  }\n\n  /**\n   * Navigate to a new URL\n   */\n  async navigate(href: string, options: FarmNavigateOptions = {}): Promise<void> {\n    const {\n      replace = false,\n      scroll = true,\n      state,\n      viewTransition = false,\n      refresh = false,\n    } = options;\n\n    // Relative targets resolve against the current document, not the origin.\n    const url = resolveFarmNavigationURL(href, window.location.href);\n    const pathname = url.pathname;\n    const search = url.search;\n    const fullPath = pathname + search;\n\n    if (\n      isFarmExternalNavigationURL(url, window.location.origin) ||\n      isFarmLocaleChangeHref(url.toString()) ||\n      this.options.shouldUseDocumentNavigation(pathname)\n    ) {\n      this.cancelActiveNavigation();\n      if (replace) window.location.replace(url.toString());\n      else window.location.assign(url.toString());\n      return;\n    }\n\n    // Same page navigation - update fragment history without fetching route data.\n    if (!refresh && pathname === window.location.pathname && search === window.location.search) {\n      this.cancelActiveNavigation();\n      if (url.hash === window.location.hash) return;\n\n      this.writePageState(\n        replace ? \"replace\" : \"push\",\n        state === undefined ? readPageState() : state,\n        url.toString(),\n      );\n      if (scroll) {\n        if (url.hash) {\n          getHashTargetElement(url.hash)?.scrollIntoView();\n        } else {\n          window.scrollTo(0, 0);\n        }\n      }\n      return;\n    }\n\n    const from = window.location.pathname + window.location.search;\n    if (\n      await this.shouldBlockNavigation({\n        from,\n        to: fullPath,\n        action: replace ? \"replace\" : \"push\",\n      })\n    ) {\n      return;\n    }\n\n    // Save current scroll position\n    if (this.options.scrollRestoration) {\n      this.saveScrollPosition(window.location.pathname + window.location.search);\n    }\n\n    const navigation = this.startNavigation({\n      from,\n      to: createNavigationLocation(url),\n      action: replace ? \"replace\" : \"push\",\n    });\n\n    let clientNavigation: FarmClientNavigationSession | undefined;\n    try {\n      clientNavigation = await this.clientPlugins?.beginNavigation({\n        from,\n        to: url,\n        action: replace ? \"replace\" : \"push\",\n      });\n      if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n\n      // Fetch page data (from cache or server)\n      const pageData = await this.fetchPageData(\n        fullPath,\n        true,\n        from,\n        refresh,\n        navigation.controller.signal,\n      );\n      if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n      if (clientNavigation) {\n        await this.clientPlugins?.markNavigationLoaded(clientNavigation, pageData);\n      }\n      if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n\n      await this.runViewTransition(viewTransition, () =>\n        this.isCurrentNavigation(navigation, clientNavigation)\n          ? this.commitNavigation({\n              fullPath,\n              pageData,\n              pathname,\n              replace,\n              scroll,\n              state,\n              url,\n            })\n          : Promise.resolve(),\n      );\n      if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n\n      if (clientNavigation) {\n        await this.clientPlugins?.resolveNavigation(clientNavigation);\n        void this.clientPlugins?.scheduleNavigationRendered(clientNavigation);\n      }\n      this.finishNavigation(navigation);\n    } catch (error) {\n      if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n      if (clientNavigation) {\n        await this.clientPlugins?.failNavigation(clientNavigation, error);\n      }\n      this.finishNavigation(navigation);\n      console.error(\"[Farm.js] Navigation error:\", error);\n      // Fall back to full page navigation\n      window.location.href = href;\n    }\n  }\n\n  /**\n   * Re-render the active route from the server while preserving the document,\n   * shared layouts, client runtime, and browser history entry.\n   */\n  refresh(options: Omit<FarmNavigateOptions, \"replace\" | \"refresh\"> = {}): Promise<void> {\n    return this.navigate(window.location.href, {\n      ...options,\n      replace: true,\n      refresh: true,\n      scroll: options.scroll ?? false,\n    });\n  }\n\n  /**\n   * Prefetch a URL\n   */\n  async prefetch(href: string): Promise<void> {\n    if (isFarmLocaleChangeHref(href)) return;\n    const url = resolveFarmNavigationURL(href, window.location.href);\n    if (isFarmExternalNavigationURL(url, window.location.origin)) return;\n    if (this.options.shouldUseDocumentNavigation(url.pathname)) return;\n    const fullPath = url.pathname + url.search;\n    const interceptFrom = window.location.pathname + window.location.search;\n\n    // Skip if already prefetching or cached\n    if (this.prefetchingUrls.has(fullPath)) return;\n    if (this.isCached(fullPath, interceptFrom)) return;\n\n    this.prefetchingUrls.add(fullPath);\n\n    try {\n      await this.fetchPageData(fullPath, false, interceptFrom);\n    } catch (error) {\n      console.warn(\"[Farm.js] Prefetch failed:\", href, error);\n    } finally {\n      this.prefetchingUrls.delete(fullPath);\n    }\n  }\n\n  /**\n   * Observe an element for viewport intersection (prefetch when visible)\n   */\n  observeForPrefetch(element: HTMLAnchorElement): void {\n    if (typeof IntersectionObserver === \"undefined\") return;\n\n    const href = element.getAttribute(\"href\");\n    if (!href || this.isExternalUrl(href)) return;\n    this.unobserveForPrefetch(element);\n\n    const observer = new IntersectionObserver(\n      (entries) => {\n        for (const entry of entries) {\n          if (entry.isIntersecting) {\n            if (this.observers.get(element) !== observer) continue;\n            // Delay prefetch slightly to avoid prefetching during scroll\n            const timer = setTimeout(() => {\n              if (this.prefetchTimers.get(element) !== timer) return;\n              this.prefetchTimers.delete(element);\n              void this.prefetch(href);\n            }, this.options.prefetchTimeout);\n            this.prefetchTimers.set(element, timer);\n\n            // Stop observing after first intersection\n            observer.unobserve(element);\n            this.observers.delete(element);\n          }\n        }\n      },\n      { rootMargin: \"200px\" }, // Start prefetching when 200px from viewport\n    );\n\n    observer.observe(element);\n    this.observers.set(element, observer);\n  }\n\n  /**\n   * Stop observing an element\n   */\n  unobserveForPrefetch(element: HTMLAnchorElement): void {\n    const observer = this.observers.get(element);\n    if (observer) {\n      observer.unobserve(element);\n      this.observers.delete(element);\n    }\n    const timer = this.prefetchTimers.get(element);\n    if (timer !== undefined) {\n      clearTimeout(timer);\n      this.prefetchTimers.delete(element);\n    }\n  }\n\n  addBlocker(blocker: FarmNavigationBlocker, shouldBlockUnload?: () => boolean): () => void {\n    this.blockers.add(blocker);\n    this.unloadBlockers.set(\n      blocker,\n      shouldBlockUnload ?? (() => this.evaluateBlockerForUnload(blocker)),\n    );\n    return () => {\n      this.blockers.delete(blocker);\n      this.unloadBlockers.delete(blocker);\n    };\n  }\n\n  getNavigationState(): FarmNavigationState {\n    return this.navigationState;\n  }\n\n  subscribeNavigation(listener: FarmNavigationListener): () => void {\n    this.navigationListeners.add(listener);\n    listener(this.navigationState);\n    return () => {\n      this.navigationListeners.delete(listener);\n    };\n  }\n\n  registerScrollElement(key: string, element: HTMLElement): () => void {\n    this.scrollElements.set(key, element);\n    this.restoreScrollElement(window.location.pathname + window.location.search, key, element);\n    return () => {\n      if (this.scrollElements.get(key) === element) {\n        this.scrollElements.delete(key);\n      }\n    };\n  }\n\n  pushState(state: unknown, href?: string): void {\n    this.writePageState(\"push\", state, href);\n  }\n\n  replaceState(state: unknown, href?: string): void {\n    this.writePageState(\"replace\", state, href);\n  }\n\n  /** @internal Keep shallow URL-search writes inside the router's history bookkeeping. */\n  writeURLSearch(action: \"push\" | \"replace\", href: string): void {\n    this.writePageState(action, readPageState(), href, false);\n  }\n\n  private async commitNavigation(options: {\n    fullPath: string;\n    pageData: PageData;\n    pathname: string;\n    replace: boolean;\n    scroll: boolean;\n    state: unknown;\n    url: URL;\n  }): Promise<void> {\n    const historyUrl = resolveFarmNavigationURL(\n      options.pageData.canonicalPath || options.fullPath,\n      window.location.href,\n    );\n    historyUrl.hash = options.url.hash;\n    const historyPath = historyUrl.pathname + historyUrl.search + historyUrl.hash;\n    const historyState = createHistoryState(\n      historyPath,\n      options.state,\n      options.replace ? window.history.state : undefined,\n      options.pageData.interception?.from ?? null,\n    ) as Record<string, unknown>;\n    const nextHistoryIndex =\n      this.currentHistoryIndex == null\n        ? null\n        : options.replace\n          ? this.currentHistoryIndex\n          : this.currentHistoryIndex + 1;\n    if (nextHistoryIndex != null) {\n      historyState[FARM_HISTORY_INDEX_KEY] = nextHistoryIndex;\n    }\n    if (options.replace) {\n      window.history.replaceState(historyState, \"\", historyPath);\n    } else {\n      window.history.pushState(historyState, \"\", historyPath);\n    }\n    this.currentHistoryIndex = nextHistoryIndex;\n    const resolvedHistoryUrl = resolveFarmNavigationURL(historyPath, window.location.href);\n    this.currentHistoryPath = resolvedHistoryUrl.pathname + resolvedHistoryUrl.search;\n    notifyRouterHistoryChange();\n\n    this.updateDocumentMetadata(options.pageData.metadata);\n\n    _hydrateFarmI18n(options.pageData.i18n);\n\n    if (this.onNavigate) {\n      await this.onNavigate(options.pageData);\n    }\n\n    if (options.scroll) {\n      if (options.url.hash) {\n        const element = getHashTargetElement(options.url.hash);\n        if (element) {\n          element.scrollIntoView();\n        }\n      } else {\n        window.scrollTo(0, 0);\n      }\n    } else if (this.options.scrollRestoration) {\n      const restorePath = this.currentHistoryPath ?? options.fullPath;\n      this.restoreWindowScroll(restorePath);\n      this.restoreScrollElements(restorePath);\n    }\n  }\n\n  private async runViewTransition(\n    mode: FarmViewTransitionMode,\n    callback: () => Promise<void>,\n  ): Promise<void> {\n    if (!mode || typeof document === \"undefined\") {\n      await callback();\n      return;\n    }\n\n    const startViewTransition = (document as any).startViewTransition;\n    if (typeof startViewTransition !== \"function\") {\n      await callback();\n      return;\n    }\n\n    const transition = startViewTransition.call(document, () => callback());\n    const updateDone = transition?.updateCallbackDone || transition?.ready;\n    if (updateDone && typeof updateDone.then === \"function\") {\n      await updateDone;\n    }\n    transition?.finished?.catch?.(() => undefined);\n  }\n\n  /**\n   * Fetch page data from cache or server\n   */\n  private async fetchPageData(\n    path: string,\n    recover = true,\n    interceptFrom?: string,\n    fresh = false,\n    signal?: AbortSignal,\n  ): Promise<PageData> {\n    const cacheKey = getPageDataCacheKey(path, interceptFrom);\n    // Check cache first\n    const cached = fresh ? undefined : this.cache.get(cacheKey);\n    if (cached && Date.now() - cached.timestamp < this.options.cacheMaxAge) {\n      return cached.data;\n    }\n\n    // Fetch from server. The active layout chain lets the server omit shared\n    // shell HTML from the fragment without inspecting component source.\n    const activeLayoutChain = getActiveLayoutChainHeader();\n    const response = await fetch(`/__farm/page-data?path=${encodeURIComponent(path)}`, {\n      signal,\n      headers: createFarmDeploymentRequestHeaders(this.options.deploymentId, {\n        Accept: \"application/x-farm-deferred+json, application/json\",\n        \"X-Farm-SPA\": \"1\",\n        ...(activeLayoutChain ? { \"X-Farm-Layout-Chain\": activeLayoutChain } : {}),\n        ...(interceptFrom ? { \"X-Farm-Intercept-From\": interceptFrom } : {}),\n      }),\n    });\n\n    if (isFarmDeploymentMismatchResponse(response, this.options.deploymentId)) {\n      const error = createFarmDeploymentMismatchError(\n        response,\n        this.options.deploymentId || \"unknown\",\n      );\n      dispatchDeploymentMismatch(error);\n      if (recover) {\n        window.location.assign(path);\n      }\n      throw error;\n    }\n\n    if (!response.ok) {\n      throw new Error(`Failed to fetch page data: ${response.status}`);\n    }\n\n    const data = await readDeferredDataResponse<PageData>(response);\n\n    // Cache the result. Expiry was previously only consulted on read, so a\n    // long-lived tab that navigates or prefetches many distinct routes grew\n    // this map without bound; sweeping on write bounds it to entries touched\n    // within the cacheMaxAge window.\n    const now = Date.now();\n    for (const [key, entry] of this.cache) {\n      if (now - entry.timestamp >= this.options.cacheMaxAge) this.cache.delete(key);\n    }\n    this.cache.set(cacheKey, {\n      data,\n      timestamp: now,\n    });\n\n    return data;\n  }\n\n  /**\n   * Put the browser URL back on the rendered page after a blocked pop. When\n   * both entries carry a Farm history index the traversal is reversed\n   * exactly; otherwise the current path is pushed again, which restores the\n   * address bar at the cost of one extra history entry.\n   */\n  private revertBlockedPopState(event: PopStateEvent, from: string): void {\n    const eventIndex = readHistoryIndex(event.state);\n    if (eventIndex != null && this.currentHistoryIndex != null) {\n      const delta = eventIndex - this.currentHistoryIndex;\n      if (delta !== 0) {\n        this.suppressNextPopState = true;\n        window.history.go(-delta);\n        return;\n      }\n    }\n\n    try {\n      const restoredState: Record<string, unknown> = {\n        path: from,\n      };\n      if (this.currentHistoryIndex != null && eventIndex != null) {\n        restoredState[FARM_HISTORY_INDEX_KEY] = eventIndex + 1;\n        this.currentHistoryIndex = eventIndex + 1;\n      }\n      window.history.pushState(restoredState, \"\", from);\n    } catch {\n      // Leave the URL as-is if the history API rejects the write; the\n      // rendered page is still the blocked-from page.\n    }\n  }\n\n  /**\n   * Handle browser back/forward navigation\n   */\n  private async handlePopState(event: PopStateEvent): Promise<void> {\n    if (document.documentElement.dataset.farmDocsRuntime === \"true\") return;\n\n    if (this.suppressNextPopState) {\n      // This traversal is our own revert of a blocked pop; the rendered page\n      // never changed.\n      this.suppressNextPopState = false;\n      return;\n    }\n\n    const path = window.location.pathname + window.location.search;\n    // The browser has already moved to the destination entry, so its state\n    // describes `to`; the page still rendered is the tracked current path.\n    const from = this.currentHistoryPath ?? path;\n\n    if (\n      await this.shouldBlockNavigation({\n        from,\n        to: path,\n        action: \"pop\",\n      })\n    ) {\n      this.revertBlockedPopState(event, from);\n      return;\n    }\n\n    this.currentHistoryPath = path;\n    this.currentHistoryIndex = readHistoryIndex(event.state);\n\n    const navigation = this.startNavigation({\n      from,\n      to: createNavigationLocation(new URL(window.location.href)),\n      action: \"pop\",\n    });\n\n    let clientNavigation: FarmClientNavigationSession | undefined;\n    try {\n      clientNavigation = await this.clientPlugins?.beginNavigation({\n        from: null,\n        to: window.location.href,\n        action: \"pop\",\n      });\n      if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n      const interceptFrom =\n        typeof event.state?.[FARM_INTERCEPT_FROM_KEY] === \"string\"\n          ? event.state[FARM_INTERCEPT_FROM_KEY]\n          : undefined;\n      const pageData = await this.fetchPageData(\n        path,\n        true,\n        interceptFrom,\n        false,\n        navigation.controller.signal,\n      );\n      if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n      if (clientNavigation) {\n        await this.clientPlugins?.markNavigationLoaded(clientNavigation, pageData);\n      }\n      if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n\n      this.updateDocumentMetadata(pageData.metadata);\n\n      _hydrateFarmI18n(pageData.i18n);\n\n      // Call the navigation handler to update React\n      if (this.onNavigate) {\n        await this.onNavigate(pageData);\n      }\n\n      // A fragment in the destination URL is an explicit scroll target for the\n      // window and takes precedence over the saved *window* scroll position,\n      // matching forward navigation and native browser back/forward. Element\n      // scroll positions are keyed without the hash (see\n      // getScrollElementStorageKey), so registered scroll containers are\n      // restored regardless of whether a fragment is present, even when the\n      // anchor resolves, so a persistent-layout scroll element is not left at\n      // the prior route's offset on a hash-destination popstate.\n      const destinationPath = window.location.pathname + window.location.search;\n      if (window.location.hash) {\n        const target = getHashTargetElement(window.location.hash);\n        if (target) {\n          target.scrollIntoView();\n        } else if (this.options.scrollRestoration) {\n          this.restoreWindowScroll(destinationPath);\n        }\n      } else if (this.options.scrollRestoration) {\n        this.restoreWindowScroll(destinationPath);\n      }\n      if (this.options.scrollRestoration) {\n        this.restoreScrollElements(destinationPath);\n      }\n\n      if (clientNavigation) {\n        await this.clientPlugins?.resolveNavigation(clientNavigation);\n        void this.clientPlugins?.scheduleNavigationRendered(clientNavigation);\n      }\n      this.finishNavigation(navigation);\n    } catch (error) {\n      if (!this.isCurrentNavigation(navigation, clientNavigation)) return;\n      if (clientNavigation) {\n        await this.clientPlugins?.failNavigation(clientNavigation, error);\n      }\n      this.finishNavigation(navigation);\n      console.error(\"[Farm.js] Popstate navigation error:\", error);\n      // Reload the page as fallback\n      window.location.reload();\n    }\n  }\n\n  /**\n   * Check if URL is cached\n   */\n  private isCached(path: string, interceptFrom?: string): boolean {\n    const cached = this.cache.get(getPageDataCacheKey(path, interceptFrom));\n    return cached !== undefined && Date.now() - cached.timestamp < this.options.cacheMaxAge;\n  }\n\n  /**\n   * Check if URL is external\n   */\n  private isExternalUrl(href: string): boolean {\n    return href.startsWith(\"http://\") || href.startsWith(\"https://\") || href.startsWith(\"//\");\n  }\n\n  private async shouldBlockNavigation(context: FarmNavigationBlockerContext): Promise<boolean> {\n    for (const blocker of this.blockers) {\n      if (await blocker(context)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private evaluateBlockerForUnload(blocker: FarmNavigationBlocker): boolean {\n    const path = window.location.pathname + window.location.search;\n    const result = blocker({ from: path, to: path, action: \"replace\" });\n    if (result && typeof result !== \"boolean\") {\n      void result.catch(() => undefined);\n      return true;\n    }\n    return result === true;\n  }\n\n  private shouldBlockUnload(): boolean {\n    for (const blocker of this.blockers) {\n      try {\n        if (this.unloadBlockers.get(blocker)?.()) return true;\n      } catch {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private updateDocumentMetadata(metadata: PageData[\"metadata\"]): void {\n    // Both call sites run after the history entry is committed, so the current\n    // pathname is the navigated-to page and drives the default canonical.\n    applyFarmMetadataToDocument(metadata, window.location.pathname);\n  }\n\n  private startNavigation(options: {\n    from: string;\n    to: FarmNavigationLocation;\n    action: FarmNavigationBlockerContext[\"action\"];\n  }): { id: number; controller: AbortController } {\n    this.activeNavigation?.controller.abort(\"superseded\");\n    const navigation = {\n      id: ++this.navigationSequence,\n      controller: new AbortController(),\n    };\n    this.activeNavigation = navigation;\n    this.setNavigationState({\n      state: \"loading\",\n      pending: true,\n      from: options.from,\n      to: options.to,\n      action: options.action,\n      startedAt: Date.now(),\n    });\n    return navigation;\n  }\n\n  private isCurrentNavigation(\n    navigation: { id: number; controller: AbortController },\n    clientNavigation?: FarmClientNavigationSession,\n  ): boolean {\n    return (\n      this.activeNavigation?.id === navigation.id &&\n      !navigation.controller.signal.aborted &&\n      !clientNavigation?.signal.aborted\n    );\n  }\n\n  private finishNavigation(navigation: { id: number; controller: AbortController }): void {\n    if (this.activeNavigation?.id !== navigation.id) return;\n    this.activeNavigation = undefined;\n    this.setNavigationState(IDLE_NAVIGATION_STATE);\n  }\n\n  private cancelActiveNavigation(): void {\n    if (!this.activeNavigation) return;\n    this.activeNavigation.controller.abort(\"superseded\");\n    this.activeNavigation = undefined;\n    this.setNavigationState(IDLE_NAVIGATION_STATE);\n  }\n\n  private setNavigationState(state: FarmNavigationState): void {\n    this.navigationState = state;\n    for (const listener of this.navigationListeners) {\n      listener(state);\n    }\n  }\n\n  private writePageState(\n    action: \"push\" | \"replace\",\n    state: unknown,\n    href?: string,\n    notify = true,\n  ): void {\n    if (typeof window === \"undefined\") return;\n\n    const url = href\n      ? resolveFarmNavigationURL(href, window.location.href).toString()\n      : window.location.href;\n    const parsedUrl = new URL(url);\n    const nextPath = parsedUrl.pathname + parsedUrl.search;\n    const historyPath = nextPath + parsedUrl.hash;\n    const nextState = createHistoryState(historyPath, state, window.history.state) as Record<\n      string,\n      unknown\n    >;\n\n    if (action === \"replace\") {\n      window.history.replaceState(nextState, \"\", url);\n    } else {\n      if (this.currentHistoryIndex != null) {\n        nextState[FARM_HISTORY_INDEX_KEY] = this.currentHistoryIndex + 1;\n      }\n      window.history.pushState(nextState, \"\", url);\n      this.currentHistoryIndex =\n        this.currentHistoryIndex == null ? null : this.currentHistoryIndex + 1;\n    }\n    this.currentHistoryPath = nextPath;\n\n    if (notify) notifyHistoryChange(\"page-state\");\n  }\n\n  /**\n   * Save scroll position for a path\n   */\n  private saveScrollPosition(path: string): void {\n    try {\n      sessionStorage.setItem(\n        `farm-scroll-${path}`,\n        JSON.stringify({ x: window.scrollX, y: window.scrollY }),\n      );\n      for (const [key, element] of this.scrollElements) {\n        sessionStorage.setItem(\n          getScrollElementStorageKey(path, key),\n          JSON.stringify({ x: element.scrollLeft, y: element.scrollTop }),\n        );\n      }\n    } catch {\n      // Ignore storage errors\n    }\n  }\n\n  /**\n   * Restore the saved window scroll position for a path.\n   */\n  private restoreWindowScroll(path: string): void {\n    try {\n      const saved = sessionStorage.getItem(`farm-scroll-${path}`);\n      if (saved) {\n        const { x, y } = JSON.parse(saved);\n        setTimeout(() => window.scrollTo(x, y), 0);\n      }\n    } catch {\n      // Ignore storage errors\n    }\n  }\n\n  /**\n   * Restore saved scroll positions for every registered scroll element. Keys\n   * are hash-stripped (see getScrollElementStorageKey), so this runs regardless\n   * of whether the destination URL carries a fragment.\n   */\n  private restoreScrollElements(path: string): void {\n    try {\n      for (const [key, element] of this.scrollElements) {\n        this.restoreScrollElement(path, key, element);\n      }\n    } catch {\n      // Ignore storage errors\n    }\n  }\n\n  private restoreScrollElement(path: string, key: string, element: HTMLElement): void {\n    try {\n      const saved = sessionStorage.getItem(getScrollElementStorageKey(path, key));\n      if (!saved) return;\n      const { x, y } = JSON.parse(saved);\n      setTimeout(() => {\n        element.scrollLeft = x;\n        element.scrollTop = y;\n      }, 0);\n    } catch {\n      // Ignore storage errors\n    }\n  }\n\n  /**\n   * Clear the page cache\n   */\n  clearCache(): void {\n    this.cache.clear();\n  }\n}\n\nfunction readBrowserDeploymentId(): string | undefined {\n  if (typeof window === \"undefined\") return undefined;\n\n  const runtimeId = (window as Window & { __FARM_DEPLOYMENT_ID__?: unknown })\n    .__FARM_DEPLOYMENT_ID__;\n  if (typeof runtimeId === \"string\" && runtimeId) return runtimeId;\n\n  return document.querySelector<HTMLMetaElement>('meta[name=\"farm-deployment-id\"]')?.content;\n}\n\nfunction dispatchDeploymentMismatch(error: Error): void {\n  if (typeof window === \"undefined\" || typeof CustomEvent === \"undefined\") return;\n  window.dispatchEvent(new CustomEvent(\"farm:deployment-mismatch\", { detail: error }));\n}\n\n/**\n * Get or create the global router instance\n */\nexport function getInstalledFarmSPARouter(): SPARouter | undefined {\n  if (typeof window === \"undefined\") return undefined;\n  return (window as Window & { __FARM_SPA_ROUTER__?: SPARouter }).__FARM_SPA_ROUTER__;\n}\n\nexport function getRouter(): SPARouter {\n  if (typeof window === \"undefined\") {\n    // Return a no-op router for SSR\n    return new SPARouter();\n  }\n\n  const installedRouter = getInstalledFarmSPARouter();\n  if (installedRouter) {\n    routerInstance = installedRouter;\n    return installedRouter;\n  }\n\n  if (!routerInstance) {\n    routerInstance = new SPARouter();\n  }\n\n  return routerInstance;\n}\n\n/**\n * Navigate to a URL using the SPA router\n */\nexport function navigateTo(href: string, options?: FarmNavigateOptions): Promise<void> {\n  return getRouter().navigate(href, options);\n}\n\n/**\n * Prefetch a URL\n */\nexport function prefetch(href: string): Promise<void> {\n  return getRouter().prefetch(href);\n}\n\nexport function pushState(state: unknown, href?: string): void {\n  getRouter().pushState(state, href);\n}\n\nexport function replaceState(state: unknown, href?: string): void {\n  getRouter().replaceState(state, href);\n}\n\nexport function readPageState<TState = unknown>(): TState | null {\n  if (typeof window === \"undefined\") return null;\n  const state = window.history.state;\n  if (!state || typeof state !== \"object\") return null;\n  return ((state as Record<string, unknown>)[FARM_PAGE_STATE_KEY] as TState | undefined) ?? null;\n}\n\nfunction createHistoryState(\n  path: string,\n  pageState: unknown,\n  currentState?: unknown,\n  interceptFrom?: string | null,\n) {\n  const base =\n    currentState && typeof currentState === \"object\" ? { ...(currentState as object) } : {};\n  const nextState: Record<string, unknown> = {\n    ...base,\n    path,\n    [FARM_PAGE_STATE_KEY]: pageState,\n  };\n  if (interceptFrom === null) {\n    delete nextState[FARM_INTERCEPT_FROM_KEY];\n  } else if (interceptFrom) {\n    nextState[FARM_INTERCEPT_FROM_KEY] = interceptFrom;\n  }\n  return nextState;\n}\n\nfunction getPageDataCacheKey(path: string, interceptFrom?: string): string {\n  return interceptFrom ? `${path}\\nintercept:${interceptFrom}` : path;\n}\n\nfunction createNavigationLocation(url: URL): FarmNavigationLocation {\n  return {\n    href: url.href,\n    pathname: url.pathname,\n    search: url.search,\n    hash: url.hash,\n  };\n}\n\nfunction getScrollElementStorageKey(path: string, key: string): string {\n  return `farm-scroll-${path}:${key}`;\n}\n","import { getInstalledFarmSPARouter, type SPARouter } from \"./spa-router\";\n\n/** Fired after programmatic history writes that must not start a navigation. */\nexport const FARM_HISTORY_CHANGE_EVENT = \"farm:historychange\";\n\nexport type FarmHistoryChangeKind = \"url-search\" | \"page-state\";\n\nexport interface FarmHistoryChangeDetail {\n  kind: FarmHistoryChangeKind;\n}\n\n/** Write shallow URL history through the installed SPA router when available. */\nexport function writeFarmURLSearchHistory(action: \"push\" | \"replace\", href: string): boolean {\n  const router = getInstalledFarmSPARouter();\n  if (!router) return false;\n  const writeURLSearch = (router as { writeURLSearch?: SPARouter[\"writeURLSearch\"] })\n    .writeURLSearch;\n  if (typeof writeURLSearch !== \"function\") return false;\n  if (window.history.state !== null && typeof window.history.state !== \"object\") return false;\n  writeURLSearch.call(router, action, href);\n  return true;\n}\n\nfunction dispatchHistoryChange(kind: FarmHistoryChangeKind): void {\n  window.dispatchEvent(\n    new CustomEvent<FarmHistoryChangeDetail>(FARM_HISTORY_CHANGE_EVENT, {\n      detail: { kind },\n    }),\n  );\n}\n\n/**\n * Notify history observers after pushState/replaceState.\n *\n * Farm's SPA router treats `popstate` as real back/forward navigation, so a\n * dedicated event is used instead. `url-search` keeps the nuqs-style synthetic\n * `popstate` when no Farm router is installed, so standalone `useQueryState`\n * consumers still resync; `page-state` is Farm-internal and never falls back.\n */\nexport function notifyHistoryChange(kind: FarmHistoryChangeKind): void {\n  if (typeof window === \"undefined\") return;\n\n  setTimeout(() => {\n    if (kind === \"url-search\" && !getInstalledFarmSPARouter()) {\n      window.dispatchEvent(new PopStateEvent(\"popstate\"));\n      return;\n    }\n\n    dispatchHistoryChange(kind);\n  }, 0);\n}\n\n/** Notify observers after a Farm router commit without simulating traversal. */\nexport function notifyRouterHistoryChange(): void {\n  if (typeof window === \"undefined\") return;\n  setTimeout(() => dispatchHistoryChange(\"url-search\"), 0);\n}\n\nexport function subscribeHistoryChange(listener: () => void): () => void {\n  if (typeof window === \"undefined\") return () => {};\n\n  window.addEventListener(\"popstate\", listener);\n  window.addEventListener(FARM_HISTORY_CHANGE_EVENT, listener);\n\n  return () => {\n    window.removeEventListener(\"popstate\", listener);\n    window.removeEventListener(FARM_HISTORY_CHANGE_EVENT, listener);\n  };\n}\n","type CurrentRequestResolver = () => Request | undefined;\n\nconst CURRENT_REQUEST_RESOLVER_KEY = Symbol.for(\"farm.currentRequestResolver\");\n\ntype GlobalWithCurrentRequestResolver = typeof globalThis & {\n  [CURRENT_REQUEST_RESOLVER_KEY]?: CurrentRequestResolver;\n};\n\nfunction getGlobalState(): GlobalWithCurrentRequestResolver {\n  return globalThis as GlobalWithCurrentRequestResolver;\n}\n\nexport function _setCurrentRequestResolver(resolver: CurrentRequestResolver | undefined): void {\n  getGlobalState()[CURRENT_REQUEST_RESOLVER_KEY] = resolver;\n}\n\nexport function _resolveCurrentRequest(): Request | undefined {\n  return getGlobalState()[CURRENT_REQUEST_RESOLVER_KEY]?.();\n}\n","/**\n * Cross-hook synchronization system for query state\n * Inspired by nuqs implementation\n */\n\ntype Listener = (searchParams: URLSearchParams) => void;\nexport type KeyUpdate = { state: any; query: string | null; source?: object };\ntype KeyListener = (payload: KeyUpdate) => void;\n\nclass Emitter {\n  private listeners: Map<string, Set<Listener>> = new Map();\n  private keyListeners: Map<string, Set<KeyListener>> = new Map();\n\n  /**\n   * Emit a global update event (all hooks should sync)\n   */\n  emitUpdate(searchParams: URLSearchParams): void {\n    const listeners = this.listeners.get(\"update\") || new Set();\n    listeners.forEach((listener) => listener(searchParams));\n  }\n\n  /**\n   * Emit a key-specific update (for cross-hook sync)\n   */\n  emitKey(key: string, payload: KeyUpdate): void {\n    const listeners = this.keyListeners.get(key) || new Set();\n    listeners.forEach((listener) => listener(payload));\n  }\n\n  /**\n   * Subscribe to global updates\n   */\n  on(event: \"update\", listener: Listener): void {\n    if (!this.listeners.has(event)) {\n      this.listeners.set(event, new Set());\n    }\n    this.listeners.get(event)!.add(listener);\n  }\n\n  /**\n   * Subscribe to key-specific updates\n   */\n  onKey(key: string, listener: KeyListener): void {\n    if (!this.keyListeners.has(key)) {\n      this.keyListeners.set(key, new Set());\n    }\n    this.keyListeners.get(key)!.add(listener);\n  }\n\n  /**\n   * Unsubscribe from global updates\n   */\n  off(event: \"update\", listener: Listener): void {\n    const listeners = this.listeners.get(event);\n    if (listeners) {\n      listeners.delete(listener);\n    }\n  }\n\n  /**\n   * Unsubscribe from key-specific updates\n   */\n  offKey(key: string, listener: KeyListener): void {\n    const listeners = this.keyListeners.get(key);\n    if (listeners) {\n      listeners.delete(listener);\n    }\n  }\n}\n\nexport const emitter = new Emitter();\n","import type { Parser } from \"./parsers\";\n\nexport type RouteParamsInput =\n  | Record<string, string | undefined>\n  | URLSearchParams\n  | Promise<Record<string, string | undefined> | URLSearchParams>;\n\nfunction normalizeParams(input: Record<string, string | undefined> | URLSearchParams) {\n  if (input instanceof URLSearchParams) {\n    const params: Record<string, string | undefined> = {};\n    input.forEach((value, key) => {\n      params[key] = value;\n    });\n    return params;\n  }\n  return input;\n}\n\nexport async function loadRouteParams<T extends Record<string, Parser<any>>>(\n  input: RouteParamsInput,\n  parsers: T,\n  options: { strict?: boolean } = {},\n): Promise<{ [K in keyof T]: ReturnType<T[K][\"parse\"]> }> {\n  const resolved = await Promise.resolve(input);\n  const params = normalizeParams(resolved);\n  const result = {} as { [K in keyof T]: ReturnType<T[K][\"parse\"]> };\n\n  for (const [key, parser] of Object.entries(parsers)) {\n    const raw = params[key] ?? \"\";\n    const parsed = parser.parse(raw);\n    if (parsed === null && options.strict) {\n      throw new Error(`Failed to parse route param \"${key}\" with value \"${raw}\"`);\n    }\n    result[key as keyof T] = parsed as ReturnType<T[typeof key][\"parse\"]>;\n  }\n\n  return result;\n}\n\nexport function parseRouteParams<T extends Record<string, Parser<any>>>(\n  input: Record<string, string | undefined> | URLSearchParams,\n  parsers: T,\n  options: { strict?: boolean } = {},\n): { [K in keyof T]: ReturnType<T[K][\"parse\"]> } {\n  const params = normalizeParams(input);\n  const result = {} as { [K in keyof T]: ReturnType<T[K][\"parse\"]> };\n\n  for (const [key, parser] of Object.entries(parsers)) {\n    const raw = params[key] ?? \"\";\n    const parsed = parser.parse(raw);\n    if (parsed === null && options.strict) {\n      throw new Error(`Failed to parse route param \"${key}\" with value \"${raw}\"`);\n    }\n    result[key as keyof T] = parsed as ReturnType<T[typeof key][\"parse\"]>;\n  }\n\n  return result;\n}\n","/**\n * Farm.js Query State Parsers\n *\n * Shared parsers that can be used in both client and server contexts\n */\n\nexport interface Parser<T> {\n  parse: (value: string) => T | null;\n  serialize: (value: T) => string;\n  withDefault?: (defaultValue: T) => Parser<T>;\n}\n\nconst INTEGER_PATTERN = /^[+-]?\\d+$/;\nconst FLOAT_PATTERN = /^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:[eE][+-]?\\d+)?$/;\nconst ISO_DATE_PATTERN = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\nconst ISO_DATE_TIME_PATTERN =\n  /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(?:\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$/;\n\nfunction parseInteger(value: string): number | null {\n  if (!INTEGER_PATTERN.test(value)) return null;\n  const parsed = Number(value);\n  return Number.isSafeInteger(parsed) ? parsed : null;\n}\n\nfunction parseFloatValue(value: string): number | null {\n  if (!FLOAT_PATTERN.test(value)) return null;\n  const parsed = Number(value);\n  return Number.isFinite(parsed) ? parsed : null;\n}\n\nfunction isValidCalendarDate(year: number, month: number, day: number): boolean {\n  if (month < 1 || month > 12 || day < 1) return false;\n  const leapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);\n  const daysInMonth = [31, leapYear ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n  return day <= daysInMonth[month - 1];\n}\n\nfunction parseIsoDate(value: string): Date | null {\n  const match = value.match(ISO_DATE_PATTERN);\n  if (!match) return null;\n\n  const year = Number(match[1]);\n  const month = Number(match[2]);\n  const day = Number(match[3]);\n  if (!isValidCalendarDate(year, month, day)) return null;\n\n  const date = new Date(0);\n  date.setUTCHours(0, 0, 0, 0);\n  date.setUTCFullYear(year, month - 1, day);\n  return date;\n}\n\nfunction parseIsoDateTime(value: string): Date | null {\n  const match = value.match(ISO_DATE_TIME_PATTERN);\n  if (!match) return null;\n\n  const year = Number(match[1]);\n  const month = Number(match[2]);\n  const day = Number(match[3]);\n  const hour = Number(match[4]);\n  const minute = Number(match[5]);\n  const second = Number(match[6]);\n  const timezone = match[7];\n  if (!isValidCalendarDate(year, month, day) || hour > 23 || minute > 59 || second > 59) {\n    return null;\n  }\n\n  if (timezone !== \"Z\") {\n    const [offsetHour, offsetMinute] = timezone.slice(1).split(\":\").map(Number);\n    if (offsetHour > 23 || offsetMinute > 59) return null;\n  }\n\n  const date = new Date(value);\n  return Number.isFinite(date.getTime()) ? date : null;\n}\n\n// String parser\nexport const asString: Parser<string> = {\n  parse: (value: string) => (value && value.trim()) || null,\n  serialize: (value: string) => value,\n  withDefault: (defaultValue: string) => ({\n    parse: (value: string) => (value && value.trim()) || defaultValue,\n    serialize: (value: string) => value || defaultValue,\n  }),\n};\n\n// Integer parser\nexport const asInteger: Parser<number> = {\n  parse: parseInteger,\n  serialize: (value: number) => value.toString(),\n  withDefault: (defaultValue: number) => ({\n    parse: (value: string) => parseInteger(value) ?? defaultValue,\n    serialize: (value: number) => value.toString(),\n  }),\n};\n\n// Float parser\nexport const asFloat: Parser<number> = {\n  parse: parseFloatValue,\n  serialize: (value: number) => value.toString(),\n  withDefault: (defaultValue: number) => ({\n    parse: (value: string) => parseFloatValue(value) ?? defaultValue,\n    serialize: (value: number) => value.toString(),\n  }),\n};\n\n// Boolean parser\nexport const asBoolean: Parser<boolean> = {\n  parse: (value: string) => {\n    if (value === \"true\") return true;\n    if (value === \"false\") return false;\n    return null;\n  },\n  serialize: (value: boolean) => value.toString(),\n  withDefault: (defaultValue: boolean) => ({\n    parse: (value: string) => {\n      if (value === \"true\") return true;\n      if (value === \"false\") return false;\n      return defaultValue;\n    },\n    serialize: (value: boolean) => value.toString(),\n  }),\n};\n\n// Array parser\nconst STRUCTURED_ARRAY_PREFIX = \"~farm-array:v1:\";\nexport interface ArrayParserOptions {\n  /** Preserve comma URLs by default; opt in when item delimiters must round-trip. */\n  format?: \"comma\" | \"structured\";\n}\n\nfunction parseArrayItems(value: string, structured: boolean): string[] {\n  if (structured && value.startsWith(STRUCTURED_ARRAY_PREFIX)) {\n    try {\n      const parsed = JSON.parse(value.slice(STRUCTURED_ARRAY_PREFIX.length));\n      if (Array.isArray(parsed) && parsed.every((item) => typeof item === \"string\")) {\n        return parsed;\n      }\n    } catch {\n      // Keep accepting legacy values that happen to begin with the prefix.\n    }\n  }\n\n  return value\n    .split(\",\")\n    .filter(Boolean)\n    .map((item) => item.trim());\n}\n\nfunction serializeArrayItems(values: string[], structured: boolean): string {\n  if (!structured) return values.join(\",\");\n\n  const needsStructuredEncoding = values.some(\n    (value, index) =>\n      value === \"\" ||\n      value.trim() !== value ||\n      value.includes(\",\") ||\n      (index === 0 && value.startsWith(STRUCTURED_ARRAY_PREFIX)),\n  );\n  return needsStructuredEncoding\n    ? `${STRUCTURED_ARRAY_PREFIX}${JSON.stringify(values)}`\n    : values.join(\",\");\n}\n\nexport function asArrayOf<T>(itemParser: Parser<T>, options: ArrayParserOptions = {}): Parser<T[]> {\n  const structured = options.format === \"structured\";\n  const parse = (value: string): T[] | null => {\n    if (!value) return null;\n    return parseArrayItems(value, structured)\n      .map((item) => itemParser.parse(item))\n      .filter((item) => item !== null) as T[];\n  };\n  const serialize = (value: T[]) =>\n    serializeArrayItems(\n      value.map((item) => itemParser.serialize(item)),\n      structured,\n    );\n\n  return {\n    parse,\n    serialize,\n    withDefault: (defaultValue: T[]) => ({\n      parse: (value: string) => parse(value) ?? defaultValue,\n      serialize,\n    }),\n  };\n}\n\n// JSON parser\nexport function asJson<T>(): Parser<T> {\n  return {\n    parse: (value: string) => {\n      try {\n        return JSON.parse(value);\n      } catch {\n        return null;\n      }\n    },\n    serialize: (value: T) => JSON.stringify(value),\n    withDefault: (defaultValue: T) => ({\n      parse: (value: string) => {\n        try {\n          return JSON.parse(value);\n        } catch {\n          return defaultValue;\n        }\n      },\n      serialize: (value: T) => JSON.stringify(value),\n    }),\n  };\n}\n\n// ISO Date parser\nexport const asIsoDate: Parser<Date> = {\n  parse: parseIsoDate,\n  serialize: (value: Date) => value.toISOString().slice(0, 10),\n  withDefault: (defaultValue: Date) => ({\n    parse: (value: string) => parseIsoDate(value) ?? defaultValue,\n    serialize: (value: Date) => value.toISOString().slice(0, 10),\n  }),\n};\n\n// ISO DateTime parser\nexport const asIsoDateTime: Parser<Date> = {\n  parse: parseIsoDateTime,\n  serialize: (value: Date) => value.toISOString(),\n  withDefault: (defaultValue: Date) => ({\n    parse: (value: string) => parseIsoDateTime(value) ?? defaultValue,\n    serialize: (value: Date) => value.toISOString(),\n  }),\n};\n\n// Custom parser creator\nexport function createParser<T>(config: {\n  parse: (value: string) => T | null;\n  serialize: (value: T) => string;\n}): Parser<T> {\n  return {\n    parse: config.parse,\n    serialize: config.serialize,\n    withDefault: (defaultValue: T) => ({\n      parse: (value: string) => config.parse(value) ?? defaultValue,\n      serialize: config.serialize,\n    }),\n  };\n}\n\n// Type inference helper\nexport type inferParserType<T> = T extends Parser<infer U> ? U : never;\n"],"mappings":"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","names":["IntlMessageFormat","knownNext","applyChange"]}