{"version":3,"sources":["../src/error.ts","../src/parser.ts","../src/helpers.ts","../src/constants.ts","../src/fetch.ts","../src/client.ts","../src/expired-shapes-cache.ts","../src/snapshot-tracker.ts","../src/shape.ts"],"sourcesContent":["export class FetchError extends Error {\n  status: number\n  text?: string\n  json?: object\n  headers: Record<string, string>\n\n  constructor(\n    status: number,\n    text: string | undefined,\n    json: object | undefined,\n    headers: Record<string, string>,\n    public url: string,\n    message?: string\n  ) {\n    super(\n      message ||\n        `HTTP Error ${status} at ${url}: ${text ?? JSON.stringify(json)}`\n    )\n    this.name = `FetchError`\n    this.status = status\n    this.text = text\n    this.json = json\n    this.headers = headers\n  }\n\n  static async fromResponse(\n    response: Response,\n    url: string\n  ): Promise<FetchError> {\n    const status = response.status\n    const headers = Object.fromEntries([...response.headers.entries()])\n    let text: string | undefined = undefined\n    let json: object | undefined = undefined\n\n    const contentType = response.headers.get(`content-type`)\n    if (!response.bodyUsed) {\n      if (contentType && contentType.includes(`application/json`)) {\n        json = (await response.json()) as object\n      } else {\n        text = await response.text()\n      }\n    }\n\n    return new FetchError(status, text, json, headers, url)\n  }\n}\n\nexport class FetchBackoffAbortError extends Error {\n  constructor() {\n    super(`Fetch with backoff aborted`)\n    this.name = `FetchBackoffAbortError`\n  }\n}\n\nexport class InvalidShapeOptionsError extends Error {\n  constructor(message: string) {\n    super(message)\n    this.name = `InvalidShapeOptionsError`\n  }\n}\n\nexport class MissingShapeUrlError extends Error {\n  constructor() {\n    super(`Invalid shape options: missing required url parameter`)\n    this.name = `MissingShapeUrlError`\n  }\n}\n\nexport class InvalidSignalError extends Error {\n  constructor() {\n    super(`Invalid signal option. It must be an instance of AbortSignal.`)\n    this.name = `InvalidSignalError`\n  }\n}\n\nexport class MissingShapeHandleError extends Error {\n  constructor() {\n    super(\n      `shapeHandle is required if this isn't an initial fetch (i.e. offset > -1)`\n    )\n    this.name = `MissingShapeHandleError`\n  }\n}\n\nexport class ReservedParamError extends Error {\n  constructor(reservedParams: string[]) {\n    super(\n      `Cannot use reserved Electric parameter names in custom params: ${reservedParams.join(`, `)}`\n    )\n    this.name = `ReservedParamError`\n  }\n}\n\nexport class ParserNullValueError extends Error {\n  constructor(columnName: string) {\n    super(`Column \"${columnName ?? `unknown`}\" does not allow NULL values`)\n    this.name = `ParserNullValueError`\n  }\n}\n\nexport class ShapeStreamAlreadyRunningError extends Error {\n  constructor() {\n    super(`ShapeStream is already running`)\n    this.name = `ShapeStreamAlreadyRunningError`\n  }\n}\n\nexport class MissingHeadersError extends Error {\n  constructor(url: string, missingHeaders: Array<string>) {\n    let msg = `The response for the shape request to ${url} didn't include the following required headers:\\n`\n    missingHeaders.forEach((h) => {\n      msg += `- ${h}\\n`\n    })\n    msg += `\\nThis is often due to a proxy not setting CORS correctly so that all Electric headers can be read by the client.`\n    msg += `\\nFor more information visit the troubleshooting guide: /docs/guides/troubleshooting/missing-headers`\n    super(msg)\n  }\n}\n","import { ColumnInfo, GetExtensions, Row, Schema, Value } from './types'\nimport { ParserNullValueError } from './error'\n\ntype Token = string\ntype NullableToken = Token | null\nexport type ParseFunction<Extensions = never> = (\n  value: Token,\n  additionalInfo?: Omit<ColumnInfo, `type` | `dims`>\n) => Value<Extensions>\ntype NullableParseFunction<Extensions = never> = (\n  value: NullableToken,\n  additionalInfo?: Omit<ColumnInfo, `type` | `dims`>\n) => Value<Extensions>\n/**\n * @typeParam Extensions - Additional types that can be parsed by this parser beyond the standard SQL types.\n *                         Defaults to no additional types.\n */\nexport type Parser<Extensions = never> = {\n  [key: string]: ParseFunction<Extensions>\n}\n\nexport type TransformFunction<Extensions = never> = (\n  message: Row<Extensions>\n) => Row<Extensions>\n\nconst parseNumber = (value: string) => Number(value)\nconst parseBool = (value: string) => value === `true` || value === `t`\nconst parseBigInt = (value: string) => BigInt(value)\nconst parseJson = (value: string) => JSON.parse(value)\nconst identityParser: ParseFunction = (v: string) => v\n\nexport const defaultParser: Parser = {\n  int2: parseNumber,\n  int4: parseNumber,\n  int8: parseBigInt,\n  bool: parseBool,\n  float4: parseNumber,\n  float8: parseNumber,\n  json: parseJson,\n  jsonb: parseJson,\n}\n\n// Taken from: https://github.com/electric-sql/pglite/blob/main/packages/pglite/src/types.ts#L233-L279\nexport function pgArrayParser<Extensions>(\n  value: Token,\n  parser?: NullableParseFunction<Extensions>\n): Value<Extensions> {\n  let i = 0\n  let char = null\n  let str = ``\n  let quoted = false\n  let last = 0\n  let p: string | undefined = undefined\n\n  function extractValue(x: Token, start: number, end: number) {\n    let val: Token | null = x.slice(start, end)\n    val = val === `NULL` ? null : val\n    return parser ? parser(val) : val\n  }\n\n  function loop(x: string): Array<Value<Extensions>> {\n    const xs = []\n    for (; i < x.length; i++) {\n      char = x[i]\n      if (quoted) {\n        if (char === `\\\\`) {\n          str += x[++i]\n        } else if (char === `\"`) {\n          xs.push(parser ? parser(str) : str)\n          str = ``\n          quoted = x[i + 1] === `\"`\n          last = i + 2\n        } else {\n          str += char\n        }\n      } else if (char === `\"`) {\n        quoted = true\n      } else if (char === `{`) {\n        last = ++i\n        xs.push(loop(x))\n      } else if (char === `}`) {\n        quoted = false\n        last < i && xs.push(extractValue(x, last, i))\n        last = i + 1\n        break\n      } else if (char === `,` && p !== `}` && p !== `\"`) {\n        xs.push(extractValue(x, last, i))\n        last = i + 1\n      }\n      p = char\n    }\n    last < i && xs.push(xs.push(extractValue(x, last, i + 1)))\n    return xs\n  }\n\n  return loop(value)[0]\n}\n\nexport class MessageParser<T extends Row<unknown>> {\n  private parser: Parser<GetExtensions<T>>\n  private transformer?: TransformFunction<GetExtensions<T>>\n  constructor(\n    parser?: Parser<GetExtensions<T>>,\n    transformer?: TransformFunction<GetExtensions<T>>\n  ) {\n    // Merge the provided parser with the default parser\n    // to use the provided parser whenever defined\n    // and otherwise fall back to the default parser\n    this.parser = { ...defaultParser, ...parser }\n    this.transformer = transformer\n  }\n\n  parse<Result>(messages: string, schema: Schema): Result {\n    return JSON.parse(messages, (key, value) => {\n      // typeof value === `object` && value !== null\n      // is needed because there could be a column named `value`\n      // and the value associated to that column will be a string or null.\n      // But `typeof null === 'object'` so we need to make an explicit check.\n      // We also parse the `old_value`, which appears on updates when `replica=full`.\n      if (\n        (key === `value` || key === `old_value`) &&\n        typeof value === `object` &&\n        value !== null\n      ) {\n        // Parse the row values\n        const row = value as Record<string, Value<GetExtensions<T>>>\n        Object.keys(row).forEach((key) => {\n          row[key] = this.parseRow(key, row[key] as NullableToken, schema)\n        })\n\n        if (this.transformer) value = this.transformer(value)\n      }\n      return value\n    }) as Result\n  }\n\n  // Parses the message values using the provided parser based on the schema information\n  private parseRow(\n    key: string,\n    value: NullableToken,\n    schema: Schema\n  ): Value<GetExtensions<T>> {\n    const columnInfo = schema[key]\n    if (!columnInfo) {\n      // We don't have information about the value\n      // so we just return it\n      return value\n    }\n\n    // Copy the object but don't include `dimensions` and `type`\n    const { type: typ, dims: dimensions, ...additionalInfo } = columnInfo\n\n    // Pick the right parser for the type\n    // and support parsing null values if needed\n    // if no parser is provided for the given type, just return the value as is\n    const typeParser = this.parser[typ] ?? identityParser\n    const parser = makeNullableParser(typeParser, columnInfo, key)\n\n    if (dimensions && dimensions > 0) {\n      // It's an array\n      const nullablePgArrayParser = makeNullableParser(\n        (value, _) => pgArrayParser(value, parser),\n        columnInfo,\n        key\n      )\n      return nullablePgArrayParser(value)\n    }\n\n    return parser(value, additionalInfo)\n  }\n}\n\nfunction makeNullableParser<Extensions>(\n  parser: ParseFunction<Extensions>,\n  columnInfo: ColumnInfo,\n  columnName?: string\n): NullableParseFunction<Extensions> {\n  const isNullable = !(columnInfo.not_null ?? false)\n  // The sync service contains `null` value for a column whose value is NULL\n  // but if the column value is an array that contains a NULL value\n  // then it will be included in the array string as `NULL`, e.g.: `\"{1,NULL,3}\"`\n  return (value: NullableToken) => {\n    if (value === null) {\n      if (!isNullable) {\n        throw new ParserNullValueError(columnName ?? `unknown`)\n      }\n      return null\n    }\n    return parser(value, columnInfo)\n  }\n}\n","import {\n  ChangeMessage,\n  ControlMessage,\n  Message,\n  NormalizedPgSnapshot,\n  Offset,\n  PostgresSnapshot,\n  Row,\n} from './types'\n\n/**\n * Type guard for checking {@link Message} is {@link ChangeMessage}.\n *\n * See [TS docs](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards)\n * for information on how to use type guards.\n *\n * @param message - the message to check\n * @returns true if the message is a {@link ChangeMessage}\n *\n * @example\n * ```ts\n * if (isChangeMessage(message)) {\n *   const msgChng: ChangeMessage = message // Ok\n *   const msgCtrl: ControlMessage = message // Err, type mismatch\n * }\n * ```\n */\nexport function isChangeMessage<T extends Row<unknown> = Row>(\n  message: Message<T>\n): message is ChangeMessage<T> {\n  return `key` in message\n}\n\n/**\n * Type guard for checking {@link Message} is {@link ControlMessage}.\n *\n * See [TS docs](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards)\n * for information on how to use type guards.\n *\n * @param message - the message to check\n * @returns true if the message is a {@link ControlMessage}\n *\n *  * @example\n * ```ts\n * if (isControlMessage(message)) {\n *   const msgChng: ChangeMessage = message // Err, type mismatch\n *   const msgCtrl: ControlMessage = message // Ok\n * }\n * ```\n */\nexport function isControlMessage<T extends Row<unknown> = Row>(\n  message: Message<T>\n): message is ControlMessage {\n  return !isChangeMessage(message)\n}\n\nexport function isUpToDateMessage<T extends Row<unknown> = Row>(\n  message: Message<T>\n): message is ControlMessage & { up_to_date: true } {\n  return isControlMessage(message) && message.headers.control === `up-to-date`\n}\n\n/**\n * Parses the LSN from the up-to-date message and turns it into an offset.\n * The LSN is only present in the up-to-date control message when in SSE mode.\n * If we are not in SSE mode this function will return undefined.\n */\nexport function getOffset(message: ControlMessage): Offset | undefined {\n  const lsn = message.headers.global_last_seen_lsn\n  if (!lsn) {\n    return\n  }\n  return `${lsn}_0` as Offset\n}\n\n/**\n * Checks if a transaction is visible in a snapshot.\n *\n * @param txid - the transaction id to check\n * @param snapshot - the information about the snapshot\n * @returns true if the transaction is visible in the snapshot\n */\nexport function isVisibleInSnapshot(\n  txid: number | bigint | `${bigint}`,\n  snapshot: PostgresSnapshot | NormalizedPgSnapshot\n): boolean {\n  const xid = BigInt(txid)\n  const xmin = BigInt(snapshot.xmin)\n  const xmax = BigInt(snapshot.xmax)\n  const xip = snapshot.xip_list.map(BigInt)\n\n  // If the transaction id is less than the minimum transaction id, it is visible in the snapshot.\n  // If the transaction id is less than the maximum transaction id and not in the list of active\n  //   transactions at the time of the snapshot, it has been committed before the snapshot was taken\n  //   and is therefore visible in the snapshot.\n  // Otherwise, it is not visible in the snapshot.\n\n  return xid < xmin || (xid < xmax && !xip.includes(xid))\n}\n","export const LIVE_CACHE_BUSTER_HEADER = `electric-cursor`\nexport const SHAPE_HANDLE_HEADER = `electric-handle`\nexport const CHUNK_LAST_OFFSET_HEADER = `electric-offset`\nexport const SHAPE_SCHEMA_HEADER = `electric-schema`\nexport const CHUNK_UP_TO_DATE_HEADER = `electric-up-to-date`\nexport const COLUMNS_QUERY_PARAM = `columns`\nexport const LIVE_CACHE_BUSTER_QUERY_PARAM = `cursor`\nexport const EXPIRED_HANDLE_QUERY_PARAM = `expired_handle`\nexport const SHAPE_HANDLE_QUERY_PARAM = `handle`\nexport const LIVE_QUERY_PARAM = `live`\nexport const OFFSET_QUERY_PARAM = `offset`\nexport const TABLE_QUERY_PARAM = `table`\nexport const WHERE_QUERY_PARAM = `where`\nexport const REPLICA_PARAM = `replica`\nexport const WHERE_PARAMS_PARAM = `params`\n/**\n * @deprecated Use {@link LIVE_SSE_QUERY_PARAM} instead.\n */\nexport const EXPERIMENTAL_LIVE_SSE_QUERY_PARAM = `experimental_live_sse`\nexport const LIVE_SSE_QUERY_PARAM = `live_sse`\nexport const FORCE_DISCONNECT_AND_REFRESH = `force-disconnect-and-refresh`\nexport const PAUSE_STREAM = `pause-stream`\nexport const LOG_MODE_QUERY_PARAM = `log`\nexport const SUBSET_PARAM_WHERE = `subset__where`\nexport const SUBSET_PARAM_LIMIT = `subset__limit`\nexport const SUBSET_PARAM_OFFSET = `subset__offset`\nexport const SUBSET_PARAM_ORDER_BY = `subset__order_by`\nexport const SUBSET_PARAM_WHERE_PARAMS = `subset__params`\n\n// Query parameters that should be passed through when proxying Electric requests\nexport const ELECTRIC_PROTOCOL_QUERY_PARAMS: Array<string> = [\n  LIVE_QUERY_PARAM,\n  LIVE_SSE_QUERY_PARAM,\n  SHAPE_HANDLE_QUERY_PARAM,\n  OFFSET_QUERY_PARAM,\n  LIVE_CACHE_BUSTER_QUERY_PARAM,\n  EXPIRED_HANDLE_QUERY_PARAM,\n  LOG_MODE_QUERY_PARAM,\n  SUBSET_PARAM_WHERE,\n  SUBSET_PARAM_LIMIT,\n  SUBSET_PARAM_OFFSET,\n  SUBSET_PARAM_ORDER_BY,\n  SUBSET_PARAM_WHERE_PARAMS,\n]\n","import {\n  CHUNK_LAST_OFFSET_HEADER,\n  CHUNK_UP_TO_DATE_HEADER,\n  LIVE_QUERY_PARAM,\n  OFFSET_QUERY_PARAM,\n  SHAPE_HANDLE_HEADER,\n  SHAPE_HANDLE_QUERY_PARAM,\n  SUBSET_PARAM_LIMIT,\n  SUBSET_PARAM_OFFSET,\n  SUBSET_PARAM_ORDER_BY,\n  SUBSET_PARAM_WHERE,\n  SUBSET_PARAM_WHERE_PARAMS,\n} from './constants'\nimport {\n  FetchError,\n  FetchBackoffAbortError,\n  MissingHeadersError,\n} from './error'\n\n// Some specific 4xx and 5xx HTTP status codes that we definitely\n// want to retry\nconst HTTP_RETRY_STATUS_CODES = [429]\n\nexport interface BackoffOptions {\n  /**\n   * Initial delay before retrying in milliseconds\n   */\n  initialDelay: number\n  /**\n   * Maximum retry delay in milliseconds\n   * After reaching this, delay stays constant (e.g., retry every 60s)\n   */\n  maxDelay: number\n  multiplier: number\n  onFailedAttempt?: () => void\n  debug?: boolean\n  /**\n   * Maximum number of retry attempts before giving up.\n   * Set to Infinity (default) for indefinite retries - needed for offline scenarios\n   * where clients may go offline and come back later.\n   */\n  maxRetries?: number\n}\n\nexport const BackoffDefaults = {\n  initialDelay: 100,\n  maxDelay: 60_000, // Cap at 60s - reasonable for long-lived connections\n  multiplier: 1.3,\n  maxRetries: Infinity, // Retry forever - clients may go offline and come back\n}\n\n/**\n * Parse Retry-After header value and return delay in milliseconds\n * Supports both delta-seconds format and HTTP-date format\n * Returns 0 if header is not present or invalid\n */\nexport function parseRetryAfterHeader(retryAfter: string | undefined): number {\n  if (!retryAfter) return 0\n\n  // Try parsing as seconds (delta-seconds format)\n  const retryAfterSec = Number(retryAfter)\n  if (Number.isFinite(retryAfterSec) && retryAfterSec > 0) {\n    return retryAfterSec * 1000\n  }\n\n  // Try parsing as HTTP-date\n  const retryDate = Date.parse(retryAfter)\n  if (!isNaN(retryDate)) {\n    // Handle clock skew: clamp to non-negative, cap at reasonable max\n    const deltaMs = retryDate - Date.now()\n    return Math.max(0, Math.min(deltaMs, 3600_000)) // Cap at 1 hour\n  }\n\n  return 0\n}\n\nexport function createFetchWithBackoff(\n  fetchClient: typeof fetch,\n  backoffOptions: BackoffOptions = BackoffDefaults\n): typeof fetch {\n  const {\n    initialDelay,\n    maxDelay,\n    multiplier,\n    debug = false,\n    onFailedAttempt,\n    maxRetries = Infinity,\n  } = backoffOptions\n  return async (...args: Parameters<typeof fetch>): Promise<Response> => {\n    const url = args[0]\n    const options = args[1]\n\n    let delay = initialDelay\n    let attempt = 0\n\n    while (true) {\n      try {\n        const result = await fetchClient(...args)\n        if (result.ok) {\n          return result\n        }\n\n        const err = await FetchError.fromResponse(result, url.toString())\n\n        throw err\n      } catch (e) {\n        onFailedAttempt?.()\n        if (options?.signal?.aborted) {\n          throw new FetchBackoffAbortError()\n        } else if (\n          e instanceof FetchError &&\n          !HTTP_RETRY_STATUS_CODES.includes(e.status) &&\n          e.status >= 400 &&\n          e.status < 500\n        ) {\n          // Any client errors cannot be backed off on, leave it to the caller to handle.\n          throw e\n        } else {\n          // Check max retries\n          attempt++\n          if (attempt > maxRetries) {\n            if (debug) {\n              console.log(\n                `Max retries reached (${attempt}/${maxRetries}), giving up`\n              )\n            }\n            throw e\n          }\n\n          // Calculate wait time honoring server-driven backoff as a floor\n          // Precedence: max(serverMinimum, min(clientMaxDelay, backoffWithJitter))\n\n          // 1. Parse server-provided Retry-After (if present)\n          const serverMinimumMs =\n            e instanceof FetchError && e.headers\n              ? parseRetryAfterHeader(e.headers[`retry-after`])\n              : 0\n\n          // 2. Calculate client backoff with full jitter strategy\n          // Full jitter: random_between(0, min(cap, exponential_backoff))\n          // See: https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/\n          const jitter = Math.random() * delay // random value between 0 and current delay\n          const clientBackoffMs = Math.min(jitter, maxDelay) // cap at maxDelay\n\n          // 3. Server minimum is the floor, client cap is the ceiling\n          const waitMs = Math.max(serverMinimumMs, clientBackoffMs)\n\n          if (debug) {\n            const source = serverMinimumMs > 0 ? `server+client` : `client`\n            console.log(\n              `Retry attempt #${attempt} after ${waitMs}ms (${source}, serverMin=${serverMinimumMs}ms, clientBackoff=${clientBackoffMs}ms)`\n            )\n          }\n\n          // Wait for the calculated duration\n          await new Promise((resolve) => setTimeout(resolve, waitMs))\n\n          // Increase the delay for the next attempt (capped at maxDelay)\n          delay = Math.min(delay * multiplier, maxDelay)\n        }\n      }\n    }\n  }\n}\n\nconst NO_BODY_STATUS_CODES = [201, 204, 205]\n\n// Ensure body can actually be read in its entirety\nexport function createFetchWithConsumedMessages(fetchClient: typeof fetch) {\n  return async (...args: Parameters<typeof fetch>): Promise<Response> => {\n    const url = args[0]\n    const res = await fetchClient(...args)\n    try {\n      if (res.status < 200 || NO_BODY_STATUS_CODES.includes(res.status)) {\n        return res\n      }\n\n      const text = await res.text()\n      return new Response(text, res)\n    } catch (err) {\n      if (args[1]?.signal?.aborted) {\n        throw new FetchBackoffAbortError()\n      }\n\n      throw new FetchError(\n        res.status,\n        undefined,\n        undefined,\n        Object.fromEntries([...res.headers.entries()]),\n        url.toString(),\n        err instanceof Error\n          ? err.message\n          : typeof err === `string`\n            ? err\n            : `failed to read body`\n      )\n    }\n  }\n}\n\ninterface ChunkPrefetchOptions {\n  maxChunksToPrefetch: number\n}\n\nconst ChunkPrefetchDefaults = {\n  maxChunksToPrefetch: 2,\n}\n\n/**\n * Creates a fetch client that prefetches subsequent log chunks for\n * consumption by the shape stream without waiting for the chunk bodies\n * themselves to be loaded.\n *\n * @param fetchClient the client to wrap\n * @param prefetchOptions options to configure prefetching\n * @returns wrapped client with prefetch capabilities\n */\nexport function createFetchWithChunkBuffer(\n  fetchClient: typeof fetch,\n  prefetchOptions: ChunkPrefetchOptions = ChunkPrefetchDefaults\n): typeof fetch {\n  const { maxChunksToPrefetch } = prefetchOptions\n\n  let prefetchQueue: PrefetchQueue\n\n  const prefetchClient = async (...args: Parameters<typeof fetchClient>) => {\n    const url = args[0].toString()\n\n    // try to consume from the prefetch queue first, and if request is\n    // not present abort the prefetch queue as it must no longer be valid\n    const prefetchedRequest = prefetchQueue?.consume(...args)\n    if (prefetchedRequest) {\n      return prefetchedRequest\n    }\n\n    prefetchQueue?.abort()\n\n    // perform request and fire off prefetch queue if request is eligible\n    const response = await fetchClient(...args)\n    const nextUrl = getNextChunkUrl(url, response)\n    if (nextUrl) {\n      prefetchQueue = new PrefetchQueue({\n        fetchClient,\n        maxPrefetchedRequests: maxChunksToPrefetch,\n        url: nextUrl,\n        requestInit: args[1],\n      })\n    }\n\n    return response\n  }\n\n  return prefetchClient\n}\n\nexport const requiredElectricResponseHeaders = [\n  `electric-offset`,\n  `electric-handle`,\n]\n\nexport const requiredLiveResponseHeaders = [`electric-cursor`]\n\nexport const requiredNonLiveResponseHeaders = [`electric-schema`]\n\nexport function createFetchWithResponseHeadersCheck(\n  fetchClient: typeof fetch\n): typeof fetch {\n  return async (...args: Parameters<typeof fetchClient>) => {\n    const response = await fetchClient(...args)\n\n    if (response.ok) {\n      // Check that the necessary Electric headers are present on the response\n      const headers = response.headers\n      const missingHeaders: Array<string> = []\n\n      const addMissingHeaders = (requiredHeaders: Array<string>) =>\n        missingHeaders.push(...requiredHeaders.filter((h) => !headers.has(h)))\n\n      const input = args[0]\n      const urlString = input.toString()\n      const url = new URL(urlString)\n\n      // Snapshot responses (subset params) return a JSON object and do not include Electric chunk headers\n      const isSnapshotRequest = [\n        SUBSET_PARAM_WHERE,\n        SUBSET_PARAM_WHERE_PARAMS,\n        SUBSET_PARAM_LIMIT,\n        SUBSET_PARAM_OFFSET,\n        SUBSET_PARAM_ORDER_BY,\n      ].some((p) => url.searchParams.has(p))\n      if (isSnapshotRequest) {\n        return response\n      }\n\n      addMissingHeaders(requiredElectricResponseHeaders)\n      if (url.searchParams.get(LIVE_QUERY_PARAM) === `true`) {\n        addMissingHeaders(requiredLiveResponseHeaders)\n      }\n\n      if (\n        !url.searchParams.has(LIVE_QUERY_PARAM) ||\n        url.searchParams.get(LIVE_QUERY_PARAM) === `false`\n      ) {\n        addMissingHeaders(requiredNonLiveResponseHeaders)\n      }\n\n      if (missingHeaders.length > 0) {\n        throw new MissingHeadersError(urlString, missingHeaders)\n      }\n    }\n\n    return response\n  }\n}\n\nclass PrefetchQueue {\n  readonly #fetchClient: typeof fetch\n  readonly #maxPrefetchedRequests: number\n  readonly #prefetchQueue = new Map<\n    string,\n    [Promise<Response>, AbortController]\n  >()\n  #queueHeadUrl: string | void\n  #queueTailUrl: string | void\n\n  constructor(options: {\n    url: Parameters<typeof fetch>[0]\n    requestInit: Parameters<typeof fetch>[1]\n    maxPrefetchedRequests: number\n    fetchClient?: typeof fetch\n  }) {\n    this.#fetchClient =\n      options.fetchClient ??\n      ((...args: Parameters<typeof fetch>) => fetch(...args))\n    this.#maxPrefetchedRequests = options.maxPrefetchedRequests\n    this.#queueHeadUrl = options.url.toString()\n    this.#queueTailUrl = this.#queueHeadUrl\n    this.#prefetch(options.url, options.requestInit)\n  }\n\n  abort(): void {\n    this.#prefetchQueue.forEach(([_, aborter]) => aborter.abort())\n  }\n\n  consume(...args: Parameters<typeof fetch>): Promise<Response> | void {\n    const url = args[0].toString()\n\n    const request = this.#prefetchQueue.get(url)?.[0]\n    // only consume if request is in queue and is the queue \"head\"\n    // if request is in the queue but not the head, the queue is being\n    // consumed out of order and should be restarted\n    if (!request || url !== this.#queueHeadUrl) return\n    this.#prefetchQueue.delete(url)\n\n    // fire off new prefetch since request has been consumed\n    request\n      .then((response) => {\n        const nextUrl = getNextChunkUrl(url, response)\n        this.#queueHeadUrl = nextUrl\n        if (\n          this.#queueTailUrl &&\n          !this.#prefetchQueue.has(this.#queueTailUrl)\n        ) {\n          this.#prefetch(this.#queueTailUrl, args[1])\n        }\n      })\n      .catch(() => {})\n\n    return request\n  }\n\n  #prefetch(...args: Parameters<typeof fetch>): void {\n    const url = args[0].toString()\n\n    // only prefetch when queue is not full\n    if (this.#prefetchQueue.size >= this.#maxPrefetchedRequests) return\n\n    // initialize aborter per request, to avoid aborting consumed requests that\n    // are still streaming their bodies to the consumer\n    const aborter = new AbortController()\n\n    try {\n      const { signal, cleanup } = chainAborter(aborter, args[1]?.signal)\n      const request = this.#fetchClient(url, { ...(args[1] ?? {}), signal })\n      this.#prefetchQueue.set(url, [request, aborter])\n      request\n        .then((response) => {\n          // only keep prefetching if response chain is uninterrupted\n          if (!response.ok || aborter.signal.aborted) return\n\n          const nextUrl = getNextChunkUrl(url, response)\n\n          // only prefetch when there is a next URL\n          if (!nextUrl || nextUrl === url) {\n            this.#queueTailUrl = undefined\n            return\n          }\n\n          this.#queueTailUrl = nextUrl\n          return this.#prefetch(nextUrl, args[1])\n        })\n        .catch(() => {})\n        .finally(cleanup)\n    } catch (_) {\n      // ignore prefetch errors\n    }\n  }\n}\n\n/**\n * Generate the next chunk's URL if the url and response are valid\n */\nfunction getNextChunkUrl(url: string, res: Response): string | void {\n  const shapeHandle = res.headers.get(SHAPE_HANDLE_HEADER)\n  const lastOffset = res.headers.get(CHUNK_LAST_OFFSET_HEADER)\n  const isUpToDate = res.headers.has(CHUNK_UP_TO_DATE_HEADER)\n\n  // only prefetch if shape handle and offset for next chunk are available, and\n  // response is not already up-to-date\n  if (!shapeHandle || !lastOffset || isUpToDate) return\n\n  const nextUrl = new URL(url)\n\n  // don't prefetch live requests, rushing them will only\n  // potentially miss more recent data\n  if (nextUrl.searchParams.has(LIVE_QUERY_PARAM)) return\n\n  nextUrl.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, shapeHandle)\n  nextUrl.searchParams.set(OFFSET_QUERY_PARAM, lastOffset)\n  nextUrl.searchParams.sort()\n  return nextUrl.toString()\n}\n\n/**\n * Chains an abort controller on an optional source signal's\n * aborted state - if the source signal is aborted, the provided abort\n * controller will also abort\n */\nfunction chainAborter(\n  aborter: AbortController,\n  sourceSignal?: AbortSignal | null\n): {\n  signal: AbortSignal\n  cleanup: () => void\n} {\n  let cleanup = noop\n  if (!sourceSignal) {\n    // no-op, nothing to chain to\n  } else if (sourceSignal.aborted) {\n    // source signal is already aborted, abort immediately\n    aborter.abort()\n  } else {\n    // chain to source signal abort event, and add callback to unlink\n    // the aborter to avoid memory leaks\n    const abortParent = () => aborter.abort()\n    sourceSignal.addEventListener(`abort`, abortParent, {\n      once: true,\n      signal: aborter.signal,\n    })\n    cleanup = () => sourceSignal.removeEventListener(`abort`, abortParent)\n  }\n\n  return {\n    signal: aborter.signal,\n    cleanup,\n  }\n}\n\nfunction noop() {}\n","import {\n  Message,\n  Offset,\n  Schema,\n  Row,\n  MaybePromise,\n  GetExtensions,\n  ChangeMessage,\n  SnapshotMetadata,\n} from './types'\nimport { MessageParser, Parser, TransformFunction } from './parser'\nimport { getOffset, isUpToDateMessage, isChangeMessage } from './helpers'\nimport {\n  FetchError,\n  FetchBackoffAbortError,\n  MissingShapeUrlError,\n  InvalidSignalError,\n  MissingShapeHandleError,\n  ReservedParamError,\n} from './error'\nimport {\n  BackoffDefaults,\n  BackoffOptions,\n  createFetchWithBackoff,\n  createFetchWithChunkBuffer,\n  createFetchWithConsumedMessages,\n  createFetchWithResponseHeadersCheck,\n} from './fetch'\nimport {\n  CHUNK_LAST_OFFSET_HEADER,\n  LIVE_CACHE_BUSTER_HEADER,\n  LIVE_CACHE_BUSTER_QUERY_PARAM,\n  EXPIRED_HANDLE_QUERY_PARAM,\n  COLUMNS_QUERY_PARAM,\n  LIVE_QUERY_PARAM,\n  OFFSET_QUERY_PARAM,\n  SHAPE_HANDLE_HEADER,\n  SHAPE_HANDLE_QUERY_PARAM,\n  SHAPE_SCHEMA_HEADER,\n  WHERE_QUERY_PARAM,\n  WHERE_PARAMS_PARAM,\n  TABLE_QUERY_PARAM,\n  REPLICA_PARAM,\n  FORCE_DISCONNECT_AND_REFRESH,\n  PAUSE_STREAM,\n  EXPERIMENTAL_LIVE_SSE_QUERY_PARAM,\n  LIVE_SSE_QUERY_PARAM,\n  ELECTRIC_PROTOCOL_QUERY_PARAMS,\n  LOG_MODE_QUERY_PARAM,\n  SUBSET_PARAM_WHERE,\n  SUBSET_PARAM_WHERE_PARAMS,\n  SUBSET_PARAM_LIMIT,\n  SUBSET_PARAM_OFFSET,\n  SUBSET_PARAM_ORDER_BY,\n} from './constants'\nimport {\n  EventSourceMessage,\n  fetchEventSource,\n} from '@microsoft/fetch-event-source'\nimport { expiredShapesCache } from './expired-shapes-cache'\nimport { SnapshotTracker } from './snapshot-tracker'\n\nconst RESERVED_PARAMS: Set<ReservedParamKeys> = new Set([\n  LIVE_CACHE_BUSTER_QUERY_PARAM,\n  SHAPE_HANDLE_QUERY_PARAM,\n  LIVE_QUERY_PARAM,\n  OFFSET_QUERY_PARAM,\n])\n\ntype Replica = `full` | `default`\nexport type LogMode = `changes_only` | `full`\n\n/**\n * PostgreSQL-specific shape parameters that can be provided externally\n */\nexport interface PostgresParams<T extends Row<unknown> = Row> {\n  /** The root table for the shape. Not required if you set the table in your proxy. */\n  table?: string\n\n  /**\n   * The columns to include in the shape.\n   * Must include primary keys, and can only include valid columns.\n   * Defaults to all columns of the type `T`. If provided, must include primary keys, and can only include valid columns.\n\n   */\n  columns?: (keyof T)[]\n\n  /** The where clauses for the shape */\n  where?: string\n\n  /**\n   * Positional where clause paramater values. These will be passed to the server\n   * and will substitute `$i` parameters in the where clause.\n   *\n   * It can be an array (note that positional arguments start at 1, the array will be mapped\n   * accordingly), or an object with keys matching the used positional parameters in the where clause.\n   *\n   * If where clause is `id = $1 or id = $2`, params must have keys `\"1\"` and `\"2\"`, or be an array with length 2.\n   */\n  params?: Record<`${number}`, string> | string[]\n\n  /**\n   * If `replica` is `default` (the default) then Electric will only send the\n   * changed columns in an update.\n   *\n   * If it's `full` Electric will send the entire row with both changed and\n   * unchanged values. `old_value` will also be present on update messages,\n   * containing the previous value for changed columns.\n   *\n   * Setting `replica` to `full` will result in higher bandwidth\n   * usage and so is not generally recommended.\n   */\n  replica?: Replica\n}\ntype SerializableParamValue = string | string[] | Record<string, string>\ntype ParamValue =\n  | SerializableParamValue\n  | (() => SerializableParamValue | Promise<SerializableParamValue>)\n\n/**\n * External params type - what users provide.\n * Excludes reserved parameters to prevent dynamic variations that could cause stream shape changes.\n */\nexport type ExternalParamsRecord<T extends Row<unknown> = Row> = {\n  [K in string]: ParamValue | undefined\n} & Partial<PostgresParams<T>> & { [K in ReservedParamKeys]?: never }\n\nexport type SubsetParams = {\n  where?: string\n  params?: Record<string, string>\n  limit?: number\n  offset?: number\n  orderBy?: string\n}\n\ntype ReservedParamKeys =\n  | typeof LIVE_CACHE_BUSTER_QUERY_PARAM\n  | typeof SHAPE_HANDLE_QUERY_PARAM\n  | typeof LIVE_QUERY_PARAM\n  | typeof OFFSET_QUERY_PARAM\n  | `subset__${string}`\n\n/**\n * External headers type - what users provide.\n * Allows string or function values for any header.\n */\nexport type ExternalHeadersRecord = {\n  [key: string]: string | (() => string | Promise<string>)\n}\n\n/**\n * Internal params type - used within the library.\n * All values are converted to strings.\n */\ntype InternalParamsRecord = {\n  [K in string as K extends ReservedParamKeys ? never : K]:\n    | string\n    | Record<string, string>\n}\n\n/**\n * Helper function to resolve a function or value to its final value\n */\nexport async function resolveValue<T>(\n  value: T | (() => T | Promise<T>)\n): Promise<T> {\n  if (typeof value === `function`) {\n    return (value as () => T | Promise<T>)()\n  }\n  return value\n}\n\n/**\n * Helper function to convert external params to internal format\n */\nasync function toInternalParams(\n  params: ExternalParamsRecord<Row>\n): Promise<InternalParamsRecord> {\n  const entries = Object.entries(params)\n  const resolvedEntries = await Promise.all(\n    entries.map(async ([key, value]) => {\n      if (value === undefined) return [key, undefined]\n      const resolvedValue = await resolveValue(value)\n      return [\n        key,\n        Array.isArray(resolvedValue) ? resolvedValue.join(`,`) : resolvedValue,\n      ]\n    })\n  )\n\n  return Object.fromEntries(\n    resolvedEntries.filter(([_, value]) => value !== undefined)\n  )\n}\n\n/**\n * Helper function to resolve headers\n */\nasync function resolveHeaders(\n  headers?: ExternalHeadersRecord\n): Promise<Record<string, string>> {\n  if (!headers) return {}\n\n  const entries = Object.entries(headers)\n  const resolvedEntries = await Promise.all(\n    entries.map(async ([key, value]) => [key, await resolveValue(value)])\n  )\n\n  return Object.fromEntries(resolvedEntries)\n}\n\ntype RetryOpts = {\n  params?: ExternalParamsRecord\n  headers?: ExternalHeadersRecord\n}\n\ntype ShapeStreamErrorHandler = (\n  error: Error\n) => void | RetryOpts | Promise<void | RetryOpts>\n\n/**\n * Options for constructing a ShapeStream.\n */\nexport interface ShapeStreamOptions<T = never> {\n  /**\n   * The full URL to where the Shape is served. This can either be the Electric server\n   * directly or a proxy. E.g. for a local Electric instance, you might set `http://localhost:3000/v1/shape`\n   */\n  url: string\n\n  /**\n   * The \"offset\" on the shape log. This is typically not set as the ShapeStream\n   * will handle this automatically. A common scenario where you might pass an offset\n   * is if you're maintaining a local cache of the log. If you've gone offline\n   * and are re-starting a ShapeStream to catch-up to the latest state of the Shape,\n   * you'd pass in the last offset and shapeHandle you'd seen from the Electric server\n   * so it knows at what point in the shape to catch you up from.\n   */\n  offset?: Offset\n\n  /**\n   * Similar to `offset`, this isn't typically used unless you're maintaining\n   * a cache of the shape log.\n   */\n  handle?: string\n\n  /**\n   * HTTP headers to attach to requests made by the client.\n   * Values can be strings or functions (sync or async) that return strings.\n   * Function values are resolved in parallel when needed, making this useful\n   * for authentication tokens or other dynamic headers.\n   */\n  headers?: ExternalHeadersRecord\n\n  /**\n   * Additional request parameters to attach to the URL.\n   * Values can be strings, string arrays, or functions (sync or async) that return these types.\n   * Function values are resolved in parallel when needed, making this useful\n   * for user-specific parameters or dynamic filters.\n   *\n   * These will be merged with Electric's standard parameters.\n   * Note: You cannot use Electric's reserved parameter names\n   * (offset, handle, live, cursor).\n   *\n   * PostgreSQL-specific options like table, where, columns, and replica\n   * should be specified here.\n   */\n  params?: ExternalParamsRecord\n\n  /**\n   * Automatically fetch updates to the Shape. If you just want to sync the current\n   * shape and stop, pass false.\n   */\n  subscribe?: boolean\n\n  /**\n   * @deprecated No longer experimental, use {@link liveSse} instead.\n   */\n  experimentalLiveSse?: boolean\n\n  /**\n   * Use Server-Sent Events (SSE) for live updates.\n   */\n  liveSse?: boolean\n\n  /**\n   * Initial data loading mode\n   */\n  log?: LogMode\n\n  signal?: AbortSignal\n  fetchClient?: typeof fetch\n  backoffOptions?: BackoffOptions\n  parser?: Parser<T>\n  transformer?: TransformFunction<T>\n\n  /**\n   * A function for handling shapestream errors.\n   *\n   * **Automatic retries**: The client automatically retries 5xx server errors, network\n   * errors, and 429 rate limits with exponential backoff. The `onError` callback is\n   * only invoked after these automatic retries are exhausted, or for non-retryable\n   * errors like 4xx client errors.\n   *\n   * When not provided, non-retryable errors will be thrown and syncing will stop.\n   *\n   * **Return value behavior**:\n   * - Return an **object** (RetryOpts or empty `{}`) to retry syncing:\n   *   - `{}` - Retry with the same params and headers\n   *   - `{ params }` - Retry with modified params\n   *   - `{ headers }` - Retry with modified headers (e.g., refreshed auth token)\n   *   - `{ params, headers }` - Retry with both modified\n   * - Return **void** or **undefined** to stop the stream permanently\n   *\n   * **Important**: If you want syncing to continue after an error (e.g., to retry\n   * on network failures), you MUST return at least an empty object `{}`. Simply\n   * logging the error and returning nothing will stop syncing.\n   *\n   * Supports async functions that return `Promise<void | RetryOpts>`.\n   *\n   * @example\n   * ```typescript\n   * // Retry on network errors, stop on others\n   * onError: (error) => {\n   *   console.error('Stream error:', error)\n   *   if (error instanceof FetchError && error.status >= 500) {\n   *     return {} // Retry with same params\n   *   }\n   *   // Return void to stop on other errors\n   * }\n   * ```\n   *\n   * @example\n   * ```typescript\n   * // Refresh auth token on 401\n   * onError: async (error) => {\n   *   if (error instanceof FetchError && error.status === 401) {\n   *     const newToken = await refreshAuthToken()\n   *     return { headers: { Authorization: `Bearer ${newToken}` } }\n   *   }\n   *   return {} // Retry other errors\n   * }\n   * ```\n   */\n  onError?: ShapeStreamErrorHandler\n}\n\nexport interface ShapeStreamInterface<T extends Row<unknown> = Row> {\n  subscribe(\n    callback: (\n      messages: Message<T>[]\n    ) => MaybePromise<void> | { columns?: (keyof T)[] },\n    onError?: (error: FetchError | Error) => void\n  ): () => void\n  unsubscribeAll(): void\n\n  isLoading(): boolean\n  lastSyncedAt(): number | undefined\n  lastSynced(): number\n  isConnected(): boolean\n  hasStarted(): boolean\n\n  isUpToDate: boolean\n  lastOffset: Offset\n  shapeHandle?: string\n  error?: unknown\n  mode: LogMode\n\n  forceDisconnectAndRefresh(): Promise<void>\n\n  requestSnapshot(params: {\n    where?: string\n    params?: Record<string, string>\n    limit: number\n    offset?: number\n    orderBy: string\n  }): Promise<{\n    metadata: SnapshotMetadata\n    data: Array<Message<T>>\n  }>\n}\n\n/**\n * Creates a canonical shape key from a URL excluding only Electric protocol parameters\n */\nfunction canonicalShapeKey(url: URL): string {\n  const cleanUrl = new URL(url.origin + url.pathname)\n\n  // Copy all params except Electric protocol ones that vary between requests\n  for (const [key, value] of url.searchParams) {\n    if (!ELECTRIC_PROTOCOL_QUERY_PARAMS.includes(key)) {\n      cleanUrl.searchParams.set(key, value)\n    }\n  }\n\n  cleanUrl.searchParams.sort()\n  return cleanUrl.toString()\n}\n\n/**\n * Reads updates to a shape from Electric using HTTP requests and long polling or\n * Server-Sent Events (SSE).\n * Notifies subscribers when new messages come in. Doesn't maintain any history of the\n * log but does keep track of the offset position and is the best way\n * to consume the HTTP `GET /v1/shape` api.\n *\n * @constructor\n * @param {ShapeStreamOptions} options - configure the shape stream\n * @example\n * Register a callback function to subscribe to the messages.\n * ```\n * const stream = new ShapeStream(options)\n * stream.subscribe(messages => {\n *   // messages is 1 or more row updates\n * })\n * ```\n *\n * To use Server-Sent Events (SSE) for real-time updates:\n * ```\n * const stream = new ShapeStream({\n *   url: `http://localhost:3000/v1/shape`,\n *   liveSse: true\n * })\n * ```\n *\n * To abort the stream, abort the `signal`\n * passed in via the `ShapeStreamOptions`.\n * ```\n * const aborter = new AbortController()\n * const issueStream = new ShapeStream({\n *   url: `${BASE_URL}/${table}`\n *   subscribe: true,\n *   signal: aborter.signal,\n * })\n * // Later...\n * aborter.abort()\n * ```\n */\n\nexport class ShapeStream<T extends Row<unknown> = Row>\n  implements ShapeStreamInterface<T>\n{\n  static readonly Replica = {\n    FULL: `full` as Replica,\n    DEFAULT: `default` as Replica,\n  }\n\n  readonly options: ShapeStreamOptions<GetExtensions<T>>\n  #error: unknown = null\n\n  readonly #fetchClient: typeof fetch\n  readonly #sseFetchClient: typeof fetch\n  readonly #messageParser: MessageParser<T>\n\n  readonly #subscribers = new Map<\n    number,\n    [\n      (messages: Message<T>[]) => MaybePromise<void>,\n      ((error: Error) => void) | undefined,\n    ]\n  >()\n\n  #started = false\n  #state = `active` as `active` | `pause-requested` | `paused`\n  #lastOffset: Offset\n  #liveCacheBuster: string // Seconds since our Electric Epoch 😎\n  #lastSyncedAt?: number // unix time\n  #isUpToDate: boolean = false\n  #isMidStream: boolean = true\n  #connected: boolean = false\n  #shapeHandle?: string\n  #mode: LogMode\n  #schema?: Schema\n  #onError?: ShapeStreamErrorHandler\n  #requestAbortController?: AbortController\n  #isRefreshing = false\n  #tickPromise?: Promise<void>\n  #tickPromiseResolver?: () => void\n  #tickPromiseRejecter?: (reason?: unknown) => void\n  #messageChain = Promise.resolve<void[]>([]) // promise chain for incoming messages\n  #snapshotTracker = new SnapshotTracker()\n  #activeSnapshotRequests = 0 // counter for concurrent snapshot requests\n  #midStreamPromise?: Promise<void>\n  #midStreamPromiseResolver?: () => void\n  #lastSseConnectionStartTime?: number\n  #minSseConnectionDuration = 1000 // Minimum expected SSE connection duration (1 second)\n  #consecutiveShortSseConnections = 0\n  #maxShortSseConnections = 3 // Fall back to long polling after this many short connections\n  #sseFallbackToLongPolling = false\n  #sseBackoffBaseDelay = 100 // Base delay for exponential backoff (ms)\n  #sseBackoffMaxDelay = 5000 // Maximum delay cap (ms)\n\n  constructor(options: ShapeStreamOptions<GetExtensions<T>>) {\n    this.options = { subscribe: true, ...options }\n    validateOptions(this.options)\n    this.#lastOffset = this.options.offset ?? `-1`\n    this.#liveCacheBuster = ``\n    this.#shapeHandle = this.options.handle\n    this.#messageParser = new MessageParser<T>(\n      options.parser,\n      options.transformer\n    )\n    this.#onError = this.options.onError\n    this.#mode = this.options.log ?? `full`\n\n    const baseFetchClient =\n      options.fetchClient ??\n      ((...args: Parameters<typeof fetch>) => fetch(...args))\n\n    const backOffOpts = {\n      ...(options.backoffOptions ?? BackoffDefaults),\n      onFailedAttempt: () => {\n        this.#connected = false\n        options.backoffOptions?.onFailedAttempt?.()\n      },\n    }\n    const fetchWithBackoffClient = createFetchWithBackoff(\n      baseFetchClient,\n      backOffOpts\n    )\n\n    this.#sseFetchClient = createFetchWithResponseHeadersCheck(\n      createFetchWithChunkBuffer(fetchWithBackoffClient)\n    )\n\n    this.#fetchClient = createFetchWithConsumedMessages(this.#sseFetchClient)\n\n    this.#subscribeToVisibilityChanges()\n  }\n\n  get shapeHandle() {\n    return this.#shapeHandle\n  }\n\n  get error() {\n    return this.#error\n  }\n\n  get isUpToDate() {\n    return this.#isUpToDate\n  }\n\n  get lastOffset() {\n    return this.#lastOffset\n  }\n\n  get mode() {\n    return this.#mode\n  }\n\n  async #start(): Promise<void> {\n    this.#started = true\n\n    try {\n      await this.#requestShape()\n    } catch (err) {\n      this.#error = err\n\n      // Check if onError handler wants to retry\n      if (this.#onError) {\n        const retryOpts = await this.#onError(err as Error)\n        // Guard against null (typeof null === \"object\" in JavaScript)\n        if (retryOpts && typeof retryOpts === `object`) {\n          // Update params/headers but don't reset offset\n          // We want to continue from where we left off, not refetch everything\n          if (retryOpts.params) {\n            // Merge new params with existing params to preserve other parameters\n            this.options.params = {\n              ...(this.options.params ?? {}),\n              ...retryOpts.params,\n            }\n          }\n\n          if (retryOpts.headers) {\n            // Merge new headers with existing headers to preserve other headers\n            this.options.headers = {\n              ...(this.options.headers ?? {}),\n              ...retryOpts.headers,\n            }\n          }\n\n          // Clear the error since we're retrying\n          this.#error = null\n\n          // Restart from current offset\n          this.#started = false\n          await this.#start()\n          return\n        }\n        // onError returned void, meaning it doesn't want to retry\n        // This is an unrecoverable error, notify subscribers\n        if (err instanceof Error) {\n          this.#sendErrorToSubscribers(err)\n        }\n        this.#connected = false\n        this.#tickPromiseRejecter?.()\n        return\n      }\n\n      // No onError handler provided, this is an unrecoverable error\n      // Notify subscribers and throw\n      if (err instanceof Error) {\n        this.#sendErrorToSubscribers(err)\n      }\n      this.#connected = false\n      this.#tickPromiseRejecter?.()\n      throw err\n    }\n\n    // Normal completion, clean up\n    this.#connected = false\n    this.#tickPromiseRejecter?.()\n  }\n\n  async #requestShape(): Promise<void> {\n    if (this.#state === `pause-requested`) {\n      this.#state = `paused`\n\n      return\n    }\n\n    if (\n      !this.options.subscribe &&\n      (this.options.signal?.aborted || this.#isUpToDate)\n    ) {\n      return\n    }\n\n    const resumingFromPause = this.#state === `paused`\n    this.#state = `active`\n\n    const { url, signal } = this.options\n    const { fetchUrl, requestHeaders } = await this.#constructUrl(\n      url,\n      resumingFromPause\n    )\n    const abortListener = await this.#createAbortListener(signal)\n    const requestAbortController = this.#requestAbortController! // we know that it is not undefined because it is set by `this.#createAbortListener`\n\n    try {\n      await this.#fetchShape({\n        fetchUrl,\n        requestAbortController,\n        headers: requestHeaders,\n        resumingFromPause,\n      })\n    } catch (e) {\n      // Handle abort error triggered by refresh\n      if (\n        (e instanceof FetchError || e instanceof FetchBackoffAbortError) &&\n        requestAbortController.signal.aborted &&\n        requestAbortController.signal.reason === FORCE_DISCONNECT_AND_REFRESH\n      ) {\n        // Start a new request\n        return this.#requestShape()\n      }\n\n      if (e instanceof FetchBackoffAbortError) {\n        if (\n          requestAbortController.signal.aborted &&\n          requestAbortController.signal.reason === PAUSE_STREAM\n        ) {\n          this.#state = `paused`\n        }\n        return // interrupted\n      }\n      if (!(e instanceof FetchError)) throw e // should never happen\n\n      if (e.status == 409) {\n        // Upon receiving a 409, we should start from scratch\n        // with the newly provided shape handle, or a fallback\n        // pseudo-handle based on the current one to act as a\n        // consistent cache buster\n\n        // Store the current shape URL as expired to avoid future 409s\n        if (this.#shapeHandle) {\n          const shapeKey = canonicalShapeKey(fetchUrl)\n          expiredShapesCache.markExpired(shapeKey, this.#shapeHandle)\n        }\n\n        const newShapeHandle =\n          e.headers[SHAPE_HANDLE_HEADER] || `${this.#shapeHandle!}-next`\n        this.#reset(newShapeHandle)\n\n        // must refetch control message might be in a list or not depending\n        // on whether it came from an SSE request or long poll - handle both\n        // cases for safety here but worth revisiting 409 handling\n        await this.#publish(\n          (Array.isArray(e.json) ? e.json : [e.json]) as Message<T>[]\n        )\n        return this.#requestShape()\n      } else {\n        // errors that have reached this point are not actionable without\n        // additional user input, such as 400s or failures to read the\n        // body of a response, so we exit the loop and let #start handle it\n        // Note: We don't notify subscribers here because onError might recover\n        throw e\n      }\n    } finally {\n      if (abortListener && signal) {\n        signal.removeEventListener(`abort`, abortListener)\n      }\n      this.#requestAbortController = undefined\n    }\n\n    this.#tickPromiseResolver?.()\n    return this.#requestShape()\n  }\n\n  async #constructUrl(\n    url: string,\n    resumingFromPause: boolean,\n    subsetParams?: SubsetParams\n  ) {\n    // Resolve headers and params in parallel\n    const [requestHeaders, params] = await Promise.all([\n      resolveHeaders(this.options.headers),\n      this.options.params\n        ? toInternalParams(convertWhereParamsToObj(this.options.params))\n        : undefined,\n    ])\n\n    // Validate params after resolution\n    if (params) validateParams(params)\n\n    const fetchUrl = new URL(url)\n\n    // Add PostgreSQL-specific parameters\n    if (params) {\n      if (params.table) setQueryParam(fetchUrl, TABLE_QUERY_PARAM, params.table)\n      if (params.where) setQueryParam(fetchUrl, WHERE_QUERY_PARAM, params.where)\n      if (params.columns)\n        setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns)\n      if (params.replica) setQueryParam(fetchUrl, REPLICA_PARAM, params.replica)\n      if (params.params)\n        setQueryParam(fetchUrl, WHERE_PARAMS_PARAM, params.params)\n\n      // Add any remaining custom parameters\n      const customParams = { ...params }\n      delete customParams.table\n      delete customParams.where\n      delete customParams.columns\n      delete customParams.replica\n      delete customParams.params\n\n      for (const [key, value] of Object.entries(customParams)) {\n        setQueryParam(fetchUrl, key, value)\n      }\n    }\n\n    if (subsetParams) {\n      if (subsetParams.where)\n        setQueryParam(fetchUrl, SUBSET_PARAM_WHERE, subsetParams.where)\n      if (subsetParams.params)\n        setQueryParam(fetchUrl, SUBSET_PARAM_WHERE_PARAMS, subsetParams.params)\n      if (subsetParams.limit)\n        setQueryParam(fetchUrl, SUBSET_PARAM_LIMIT, subsetParams.limit)\n      if (subsetParams.offset)\n        setQueryParam(fetchUrl, SUBSET_PARAM_OFFSET, subsetParams.offset)\n      if (subsetParams.orderBy)\n        setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, subsetParams.orderBy)\n    }\n\n    // Add Electric's internal parameters\n    fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, this.#lastOffset)\n    fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, this.#mode)\n\n    if (this.#isUpToDate) {\n      // If we are resuming from a paused state, we don't want to perform a live request\n      // because it could be a long poll that holds for 20sec\n      // and during all that time `isConnected` will be false\n      if (!this.#isRefreshing && !resumingFromPause) {\n        fetchUrl.searchParams.set(LIVE_QUERY_PARAM, `true`)\n      }\n      fetchUrl.searchParams.set(\n        LIVE_CACHE_BUSTER_QUERY_PARAM,\n        this.#liveCacheBuster\n      )\n    }\n\n    if (this.#shapeHandle) {\n      // This should probably be a header for better cache breaking?\n      fetchUrl.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, this.#shapeHandle!)\n    }\n\n    // Add cache buster for shapes known to be expired to prevent 409s\n    const shapeKey = canonicalShapeKey(fetchUrl)\n    const expiredHandle = expiredShapesCache.getExpiredHandle(shapeKey)\n    if (expiredHandle) {\n      fetchUrl.searchParams.set(EXPIRED_HANDLE_QUERY_PARAM, expiredHandle)\n    }\n\n    // sort query params in-place for stable URLs and improved cache hits\n    fetchUrl.searchParams.sort()\n\n    return {\n      fetchUrl,\n      requestHeaders,\n    }\n  }\n\n  async #createAbortListener(signal?: AbortSignal) {\n    // Create a new AbortController for this request\n    this.#requestAbortController = new AbortController()\n\n    // If user provided a signal, listen to it and pass on the reason for the abort\n    if (signal) {\n      const abortListener = () => {\n        this.#requestAbortController?.abort(signal.reason)\n      }\n\n      signal.addEventListener(`abort`, abortListener, { once: true })\n\n      if (signal.aborted) {\n        // If the signal is already aborted, abort the request immediately\n        this.#requestAbortController?.abort(signal.reason)\n      }\n\n      return abortListener\n    }\n  }\n\n  async #onInitialResponse(response: Response) {\n    const { headers, status } = response\n    const shapeHandle = headers.get(SHAPE_HANDLE_HEADER)\n    if (shapeHandle) {\n      this.#shapeHandle = shapeHandle\n    }\n\n    const lastOffset = headers.get(CHUNK_LAST_OFFSET_HEADER)\n    if (lastOffset) {\n      this.#lastOffset = lastOffset as Offset\n    }\n\n    const liveCacheBuster = headers.get(LIVE_CACHE_BUSTER_HEADER)\n    if (liveCacheBuster) {\n      this.#liveCacheBuster = liveCacheBuster\n    }\n\n    const getSchema = (): Schema => {\n      const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER)\n      return schemaHeader ? JSON.parse(schemaHeader) : {}\n    }\n    this.#schema = this.#schema ?? getSchema()\n\n    // NOTE: 204s are deprecated, the Electric server should not\n    // send these in latest versions but this is here for backwards\n    // compatibility\n    if (status === 204) {\n      // There's no content so we are live and up to date\n      this.#lastSyncedAt = Date.now()\n    }\n  }\n\n  async #onMessages(batch: Array<Message<T>>, isSseMessage = false) {\n    // Update isUpToDate\n    if (batch.length > 0) {\n      // Set isMidStream to true when we receive any data\n      this.#isMidStream = true\n\n      const lastMessage = batch[batch.length - 1]\n      if (isUpToDateMessage(lastMessage)) {\n        if (isSseMessage) {\n          // Only use the offset from the up-to-date message if this was an SSE message.\n          // If we would use this offset from a regular fetch, then it will be wrong\n          // and we will get an \"offset is out of bounds for this shape\" error\n          const offset = getOffset(lastMessage)\n          if (offset) {\n            this.#lastOffset = offset\n          }\n        }\n        this.#lastSyncedAt = Date.now()\n        this.#isUpToDate = true\n        // Set isMidStream to false when we see an up-to-date message\n        this.#isMidStream = false\n        // Resolve the promise waiting for mid-stream to end\n        this.#midStreamPromiseResolver?.()\n      }\n\n      // Filter messages using snapshot tracker\n      const messagesToProcess = batch.filter((message) => {\n        if (isChangeMessage(message)) {\n          return !this.#snapshotTracker.shouldRejectMessage(message)\n        }\n        return true // Always process control messages\n      })\n\n      await this.#publish(messagesToProcess)\n    }\n  }\n\n  /**\n   * Fetches the shape from the server using either long polling or SSE.\n   * Upon receiving a successfull response, the #onInitialResponse method is called.\n   * Afterwards, the #onMessages method is called for all the incoming updates.\n   * @param opts - The options for the request.\n   * @returns A promise that resolves when the request is complete (i.e. the long poll receives a response or the SSE connection is closed).\n   */\n  async #fetchShape(opts: {\n    fetchUrl: URL\n    requestAbortController: AbortController\n    headers: Record<string, string>\n    resumingFromPause?: boolean\n  }): Promise<void> {\n    const useSse = this.options.liveSse ?? this.options.experimentalLiveSse\n    if (\n      this.#isUpToDate &&\n      useSse &&\n      !this.#isRefreshing &&\n      !opts.resumingFromPause &&\n      !this.#sseFallbackToLongPolling\n    ) {\n      opts.fetchUrl.searchParams.set(EXPERIMENTAL_LIVE_SSE_QUERY_PARAM, `true`)\n      opts.fetchUrl.searchParams.set(LIVE_SSE_QUERY_PARAM, `true`)\n      return this.#requestShapeSSE(opts)\n    }\n\n    return this.#requestShapeLongPoll(opts)\n  }\n\n  async #requestShapeLongPoll(opts: {\n    fetchUrl: URL\n    requestAbortController: AbortController\n    headers: Record<string, string>\n  }): Promise<void> {\n    const { fetchUrl, requestAbortController, headers } = opts\n    const response = await this.#fetchClient(fetchUrl.toString(), {\n      signal: requestAbortController.signal,\n      headers,\n    })\n\n    this.#connected = true\n    await this.#onInitialResponse(response)\n\n    const schema = this.#schema! // we know that it is not undefined because it is set by `this.#onInitialResponse`\n    const res = await response.text()\n    const messages = res || `[]`\n    const batch = this.#messageParser.parse<Array<Message<T>>>(messages, schema)\n\n    await this.#onMessages(batch)\n  }\n\n  async #requestShapeSSE(opts: {\n    fetchUrl: URL\n    requestAbortController: AbortController\n    headers: Record<string, string>\n  }): Promise<void> {\n    const { fetchUrl, requestAbortController, headers } = opts\n    const fetch = this.#sseFetchClient\n\n    // Track when the SSE connection starts\n    this.#lastSseConnectionStartTime = Date.now()\n\n    try {\n      let buffer: Array<Message<T>> = []\n      await fetchEventSource(fetchUrl.toString(), {\n        headers,\n        fetch,\n        onopen: async (response: Response) => {\n          this.#connected = true\n          await this.#onInitialResponse(response)\n        },\n        onmessage: (event: EventSourceMessage) => {\n          if (event.data) {\n            // event.data is a single JSON object\n            const schema = this.#schema! // we know that it is not undefined because it is set in onopen when we call this.#onInitialResponse\n            const message = this.#messageParser.parse<Message<T>>(\n              event.data,\n              schema\n            )\n            buffer.push(message)\n\n            if (isUpToDateMessage(message)) {\n              // Flush the buffer on up-to-date message.\n              // Ensures that we only process complete batches of operations.\n              this.#onMessages(buffer, true)\n              buffer = []\n            }\n          }\n        },\n        onerror: (error: Error) => {\n          // rethrow to close the SSE connection\n          throw error\n        },\n        signal: requestAbortController.signal,\n      })\n    } catch (error) {\n      if (requestAbortController.signal.aborted) {\n        // During an SSE request, the fetch might have succeeded\n        // and we are parsing the incoming stream.\n        // If the abort happens while we're parsing the stream,\n        // then it won't be caught by our `createFetchWithBackoff` wrapper\n        // and instead we will get a raw AbortError here\n        // which we need to turn into a `FetchBackoffAbortError`\n        // such that #start handles it correctly.`\n        throw new FetchBackoffAbortError()\n      }\n      throw error\n    } finally {\n      // Check if the SSE connection closed too quickly\n      // This can happen when responses are cached or when the proxy/server\n      // is misconfigured for SSE and closes the connection immediately\n      const connectionDuration = Date.now() - this.#lastSseConnectionStartTime!\n      const wasAborted = requestAbortController.signal.aborted\n\n      if (connectionDuration < this.#minSseConnectionDuration && !wasAborted) {\n        // Connection was too short - likely a cached response or misconfiguration\n        this.#consecutiveShortSseConnections++\n\n        if (\n          this.#consecutiveShortSseConnections >= this.#maxShortSseConnections\n        ) {\n          // Too many short connections - fall back to long polling\n          this.#sseFallbackToLongPolling = true\n          console.warn(\n            `[Electric] SSE connections are closing immediately (possibly due to proxy buffering or misconfiguration). ` +\n              `Falling back to long polling. ` +\n              `Your proxy must support streaming SSE responses (not buffer the complete response). ` +\n              `Configuration: Nginx add 'X-Accel-Buffering: no', Caddy add 'flush_interval -1' to reverse_proxy. ` +\n              `Note: Do NOT disable caching entirely - Electric uses cache headers to enable request collapsing for efficiency.`\n          )\n        } else {\n          // Add exponential backoff with full jitter to prevent tight infinite loop\n          // Formula: random(0, min(cap, base * 2^attempt))\n          const maxDelay = Math.min(\n            this.#sseBackoffMaxDelay,\n            this.#sseBackoffBaseDelay *\n              Math.pow(2, this.#consecutiveShortSseConnections)\n          )\n          const delayMs = Math.floor(Math.random() * maxDelay)\n          await new Promise((resolve) => setTimeout(resolve, delayMs))\n        }\n      } else if (connectionDuration >= this.#minSseConnectionDuration) {\n        // Connection was healthy - reset counter\n        this.#consecutiveShortSseConnections = 0\n      }\n    }\n  }\n\n  #pause() {\n    if (this.#started && this.#state === `active`) {\n      this.#state = `pause-requested`\n      this.#requestAbortController?.abort(PAUSE_STREAM)\n    }\n  }\n\n  #resume() {\n    if (this.#started && this.#state === `paused`) {\n      this.#start()\n    }\n  }\n\n  subscribe(\n    callback: (messages: Message<T>[]) => MaybePromise<void>,\n    onError: (error: Error) => void = () => {}\n  ) {\n    const subscriptionId = Math.random()\n\n    this.#subscribers.set(subscriptionId, [callback, onError])\n    if (!this.#started) this.#start()\n\n    return () => {\n      this.#subscribers.delete(subscriptionId)\n    }\n  }\n\n  unsubscribeAll(): void {\n    this.#subscribers.clear()\n  }\n\n  /** Unix time at which we last synced. Undefined when `isLoading` is true. */\n  lastSyncedAt(): number | undefined {\n    return this.#lastSyncedAt\n  }\n\n  /** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */\n  lastSynced(): number {\n    if (this.#lastSyncedAt === undefined) return Infinity\n    return Date.now() - this.#lastSyncedAt\n  }\n\n  /** Indicates if we are connected to the Electric sync service. */\n  isConnected(): boolean {\n    return this.#connected\n  }\n\n  /** True during initial fetch. False afterwise.  */\n  isLoading(): boolean {\n    return !this.#isUpToDate\n  }\n\n  hasStarted(): boolean {\n    return this.#started\n  }\n\n  isPaused(): boolean {\n    return this.#state === `paused`\n  }\n\n  /** Await the next tick of the request loop */\n  async #nextTick() {\n    if (this.#tickPromise) {\n      return this.#tickPromise\n    }\n    this.#tickPromise = new Promise((resolve, reject) => {\n      this.#tickPromiseResolver = resolve\n      this.#tickPromiseRejecter = reject\n    })\n    this.#tickPromise.finally(() => {\n      this.#tickPromise = undefined\n      this.#tickPromiseResolver = undefined\n      this.#tickPromiseRejecter = undefined\n    })\n    return this.#tickPromise\n  }\n\n  /** Await until we're not in the middle of a stream (i.e., until we see an up-to-date message) */\n  async #waitForStreamEnd() {\n    if (!this.#isMidStream) {\n      return\n    }\n    if (this.#midStreamPromise) {\n      return this.#midStreamPromise\n    }\n    this.#midStreamPromise = new Promise((resolve) => {\n      this.#midStreamPromiseResolver = resolve\n    })\n    this.#midStreamPromise.finally(() => {\n      this.#midStreamPromise = undefined\n      this.#midStreamPromiseResolver = undefined\n    })\n    return this.#midStreamPromise\n  }\n\n  /**\n   * Refreshes the shape stream.\n   * This preemptively aborts any ongoing long poll and reconnects without\n   * long polling, ensuring that the stream receives an up to date message with the\n   * latest LSN from Postgres at that point in time.\n   */\n  async forceDisconnectAndRefresh(): Promise<void> {\n    this.#isRefreshing = true\n    if (this.#isUpToDate && !this.#requestAbortController?.signal.aborted) {\n      // If we are \"up to date\", any current request will be a \"live\" request\n      // and needs to be aborted\n      this.#requestAbortController?.abort(FORCE_DISCONNECT_AND_REFRESH)\n    }\n    await this.#nextTick()\n    this.#isRefreshing = false\n  }\n\n  async #publish(messages: Message<T>[]): Promise<void[]> {\n    // We process messages asynchronously\n    // but SSE's `onmessage` handler is synchronous.\n    // We use a promise chain to ensure that the handlers\n    // execute sequentially in the order the messages were received.\n    this.#messageChain = this.#messageChain.then(() =>\n      Promise.all(\n        Array.from(this.#subscribers.values()).map(async ([callback, __]) => {\n          try {\n            await callback(messages)\n          } catch (err) {\n            queueMicrotask(() => {\n              throw err\n            })\n          }\n        })\n      )\n    )\n\n    return this.#messageChain\n  }\n\n  #sendErrorToSubscribers(error: Error) {\n    this.#subscribers.forEach(([_, errorFn]) => {\n      errorFn?.(error)\n    })\n  }\n\n  #subscribeToVisibilityChanges() {\n    if (\n      typeof document === `object` &&\n      typeof document.hidden === `boolean` &&\n      typeof document.addEventListener === `function`\n    ) {\n      const visibilityHandler = () => {\n        if (document.hidden) {\n          this.#pause()\n        } else {\n          this.#resume()\n        }\n      }\n\n      document.addEventListener(`visibilitychange`, visibilityHandler)\n    }\n  }\n\n  /**\n   * Resets the state of the stream, optionally with a provided\n   * shape handle\n   */\n  #reset(handle?: string) {\n    this.#lastOffset = `-1`\n    this.#liveCacheBuster = ``\n    this.#shapeHandle = handle\n    this.#isUpToDate = false\n    this.#isMidStream = true\n    this.#connected = false\n    this.#schema = undefined\n    this.#activeSnapshotRequests = 0\n    // Reset SSE fallback state to try SSE again after reset\n    this.#consecutiveShortSseConnections = 0\n    this.#sseFallbackToLongPolling = false\n  }\n\n  /**\n   * Request a snapshot for subset of data.\n   *\n   * Only available when mode is `changes_only`.\n   * Returns the insertion point & the data, but more importantly injects the data\n   * into the subscribed data stream. Returned value is unlikely to be useful for the caller,\n   * unless the caller has complicated additional logic.\n   *\n   * Data will be injected in a way that's also tracking further incoming changes, and it'll\n   * skip the ones that are already in the snapshot.\n   *\n   * @param opts - The options for the snapshot request.\n   * @returns The metadata and the data for the snapshot.\n   */\n  async requestSnapshot(opts: SubsetParams): Promise<{\n    metadata: SnapshotMetadata\n    data: Array<ChangeMessage<T>>\n  }> {\n    if (this.#mode === `full`) {\n      throw new Error(\n        `Snapshot requests are not supported in ${this.#mode} mode, as the consumer is guaranteed to observe all data`\n      )\n    }\n    // We shouldn't be getting a snapshot on a shape that's not started\n    if (!this.#started) await this.#start()\n\n    // Wait until we're not mid-stream before pausing\n    // This ensures we don't pause in the middle of a transaction\n    await this.#waitForStreamEnd()\n\n    // Pause the stream if this is the first snapshot request\n    this.#activeSnapshotRequests++\n\n    try {\n      if (this.#activeSnapshotRequests === 1) {\n        // Currently this cannot throw, but in case it can later it's in this try block to not have a stuck counter\n        this.#pause()\n      }\n\n      const { fetchUrl, requestHeaders } = await this.#constructUrl(\n        this.options.url,\n        true,\n        opts\n      )\n\n      const { metadata, data } = await this.#fetchSnapshot(\n        fetchUrl,\n        requestHeaders\n      )\n\n      const dataWithEndBoundary = (data as Array<Message<T>>).concat([\n        { headers: { control: `snapshot-end`, ...metadata } },\n      ])\n\n      this.#snapshotTracker.addSnapshot(\n        metadata,\n        new Set(data.map((message) => message.key))\n      )\n      this.#onMessages(dataWithEndBoundary, false)\n\n      return {\n        metadata,\n        data,\n      }\n    } finally {\n      // Resume the stream if this was the last snapshot request\n      this.#activeSnapshotRequests--\n      if (this.#activeSnapshotRequests === 0) {\n        this.#resume()\n      }\n    }\n  }\n\n  async #fetchSnapshot(url: URL, headers: Record<string, string>) {\n    const response = await this.#fetchClient(url.toString(), { headers })\n\n    if (!response.ok) {\n      throw new FetchError(\n        response.status,\n        undefined,\n        undefined,\n        Object.fromEntries([...response.headers.entries()]),\n        url.toString()\n      )\n    }\n\n    const { metadata, data } = await response.json()\n    const batch = this.#messageParser.parse<Array<ChangeMessage<T>>>(\n      JSON.stringify(data),\n      this.#schema!\n    )\n\n    return {\n      metadata,\n      data: batch,\n    }\n  }\n}\n\n/**\n * Validates that no reserved parameter names are used in the provided params object\n * @throws {ReservedParamError} if any reserved parameter names are found\n */\nfunction validateParams(params: Record<string, unknown> | undefined): void {\n  if (!params) return\n\n  const reservedParams = Object.keys(params).filter((key) =>\n    RESERVED_PARAMS.has(key as ReservedParamKeys)\n  )\n  if (reservedParams.length > 0) {\n    throw new ReservedParamError(reservedParams)\n  }\n}\n\nfunction validateOptions<T>(options: Partial<ShapeStreamOptions<T>>): void {\n  if (!options.url) {\n    throw new MissingShapeUrlError()\n  }\n  if (options.signal && !(options.signal instanceof AbortSignal)) {\n    throw new InvalidSignalError()\n  }\n\n  if (\n    options.offset !== undefined &&\n    options.offset !== `-1` &&\n    options.offset !== `now` &&\n    !options.handle\n  ) {\n    throw new MissingShapeHandleError()\n  }\n\n  validateParams(options.params)\n\n  return\n}\n\n// `unknown` being in the value is a bit of defensive programming if user doesn't use TS\nfunction setQueryParam(\n  url: URL,\n  key: string,\n  value: Record<string, string> | string | unknown\n): void {\n  if (value === undefined || value == null) {\n    return\n  } else if (typeof value === `string`) {\n    url.searchParams.set(key, value)\n  } else if (typeof value === `object`) {\n    for (const [k, v] of Object.entries(value)) {\n      url.searchParams.set(`${key}[${k}]`, v)\n    }\n  } else {\n    url.searchParams.set(key, value.toString())\n  }\n}\n\nfunction convertWhereParamsToObj(\n  allPgParams: ExternalParamsRecord<Row>\n): ExternalParamsRecord<Row> {\n  if (Array.isArray(allPgParams.params)) {\n    return {\n      ...allPgParams,\n      params: Object.fromEntries(allPgParams.params.map((v, i) => [i + 1, v])),\n    }\n  }\n  return allPgParams\n}\n","interface ExpiredShapeCacheEntry {\n  expiredHandle: string\n  lastUsed: number\n}\n\n/**\n * LRU cache for tracking expired shapes with automatic cleanup\n */\nexport class ExpiredShapesCache {\n  private data: Record<string, ExpiredShapeCacheEntry> = {}\n  private max: number = 250\n  private readonly storageKey = `electric_expired_shapes`\n\n  getExpiredHandle(shapeUrl: string): string | null {\n    const entry = this.data[shapeUrl]\n    if (entry) {\n      // Update last used time when accessed\n      entry.lastUsed = Date.now()\n      this.save()\n      return entry.expiredHandle\n    }\n    return null\n  }\n\n  markExpired(shapeUrl: string, handle: string): void {\n    this.data[shapeUrl] = { expiredHandle: handle, lastUsed: Date.now() }\n\n    const keys = Object.keys(this.data)\n    if (keys.length > this.max) {\n      const oldest = keys.reduce((min, k) =>\n        this.data[k].lastUsed < this.data[min].lastUsed ? k : min\n      )\n      delete this.data[oldest]\n    }\n\n    this.save()\n  }\n\n  private save(): void {\n    if (typeof localStorage === `undefined`) return\n    try {\n      localStorage.setItem(this.storageKey, JSON.stringify(this.data))\n    } catch {\n      // Ignore localStorage errors\n    }\n  }\n\n  private load(): void {\n    if (typeof localStorage === `undefined`) return\n    try {\n      const stored = localStorage.getItem(this.storageKey)\n      if (stored) {\n        this.data = JSON.parse(stored)\n      }\n    } catch {\n      // Ignore localStorage errors, start fresh\n      this.data = {}\n    }\n  }\n\n  constructor() {\n    this.load()\n  }\n\n  clear(): void {\n    this.data = {}\n    this.save()\n  }\n}\n\n// Module-level singleton instance\nexport const expiredShapesCache = new ExpiredShapesCache()\n","import { isVisibleInSnapshot } from './helpers'\nimport { Row, SnapshotMetadata } from './types'\nimport { ChangeMessage } from './types'\n\n/**\n * Tracks active snapshots and filters out duplicate change messages that are already included in snapshots.\n *\n * When requesting a snapshot in changes_only mode, we need to track which transactions were included in the\n * snapshot to avoid processing duplicate changes that arrive via the live stream. This class maintains that\n * tracking state and provides methods to:\n *\n * - Add new snapshots for tracking via addSnapshot()\n * - Remove completed snapshots via removeSnapshot()\n * - Check if incoming changes should be filtered via shouldRejectMessage()\n */\nexport class SnapshotTracker {\n  private activeSnapshots: Map<\n    number,\n    { xmin: bigint; xmax: bigint; xip_list: bigint[]; keys: Set<string> }\n  > = new Map()\n  private xmaxSnapshots: Map<bigint, Set<number>> = new Map()\n  private snapshotsByDatabaseLsn: Map<bigint, Set<number>> = new Map()\n\n  /**\n   * Add a new snapshot for tracking\n   */\n  addSnapshot(metadata: SnapshotMetadata, keys: Set<string>): void {\n    this.activeSnapshots.set(metadata.snapshot_mark, {\n      xmin: BigInt(metadata.xmin),\n      xmax: BigInt(metadata.xmax),\n      xip_list: metadata.xip_list.map(BigInt),\n      keys,\n    })\n    const xmaxSet =\n      this.xmaxSnapshots\n        .get(BigInt(metadata.xmax))\n        ?.add(metadata.snapshot_mark) ?? new Set([metadata.snapshot_mark])\n    this.xmaxSnapshots.set(BigInt(metadata.xmax), xmaxSet)\n    const databaseLsnSet =\n      this.snapshotsByDatabaseLsn\n        .get(BigInt(metadata.database_lsn))\n        ?.add(metadata.snapshot_mark) ?? new Set([metadata.snapshot_mark])\n    this.snapshotsByDatabaseLsn.set(\n      BigInt(metadata.database_lsn),\n      databaseLsnSet\n    )\n  }\n\n  /**\n   * Remove a snapshot from tracking\n   */\n  removeSnapshot(snapshotMark: number): void {\n    this.activeSnapshots.delete(snapshotMark)\n  }\n\n  /**\n   * Check if a change message should be filtered because its already in an active snapshot\n   * Returns true if the message should be filtered out (not processed)\n   */\n  shouldRejectMessage(message: ChangeMessage<Row<unknown>>): boolean {\n    const txids = message.headers.txids || []\n    if (txids.length === 0) return false\n\n    const xid = Math.max(...txids) // Use the maximum transaction ID\n\n    for (const [xmax, snapshots] of this.xmaxSnapshots.entries()) {\n      if (xid >= xmax) {\n        for (const snapshot of snapshots) {\n          this.removeSnapshot(snapshot)\n        }\n      }\n    }\n\n    return [...this.activeSnapshots.values()].some(\n      (x) => x.keys.has(message.key) && isVisibleInSnapshot(xid, x)\n    )\n  }\n\n  lastSeenUpdate(newDatabaseLsn: bigint): void {\n    for (const [dbLsn, snapshots] of this.snapshotsByDatabaseLsn.entries()) {\n      if (dbLsn <= newDatabaseLsn) {\n        for (const snapshot of snapshots) {\n          this.removeSnapshot(snapshot)\n        }\n      }\n    }\n  }\n}\n","import { Message, Offset, Row } from './types'\nimport { isChangeMessage, isControlMessage } from './helpers'\nimport { FetchError } from './error'\nimport { LogMode, ShapeStreamInterface } from './client'\n\nexport type ShapeData<T extends Row<unknown> = Row> = Map<string, T>\nexport type ShapeChangedCallback<T extends Row<unknown> = Row> = (data: {\n  value: ShapeData<T>\n  rows: T[]\n}) => void\n\ntype ShapeStatus = `syncing` | `up-to-date`\n\n/**\n * A Shape is an object that subscribes to a shape log,\n * keeps a materialised shape `.rows` in memory and\n * notifies subscribers when the value has changed.\n *\n * It can be used without a framework and as a primitive\n * to simplify developing framework hooks.\n *\n * @constructor\n * @param {ShapeStream<T extends Row>} - the underlying shape stream\n * @example\n * ```\n * const shapeStream = new ShapeStream<{ foo: number }>({\n *   url: `http://localhost:3000/v1/shape`,\n *   params: {\n *     table: `foo`\n *   }\n * })\n * const shape = new Shape(shapeStream)\n * ```\n *\n * `rows` returns a promise that resolves the Shape data once the Shape has been\n * fully loaded (and when resuming from being offline):\n *\n *     const rows = await shape.rows\n *\n * `currentRows` returns the current data synchronously:\n *\n *     const rows = shape.currentRows\n *\n *  Subscribe to updates. Called whenever the shape updates in Postgres.\n *\n *     shape.subscribe(({ rows }) => {\n *       console.log(rows)\n *     })\n */\nexport class Shape<T extends Row<unknown> = Row> {\n  readonly stream: ShapeStreamInterface<T>\n\n  readonly #data: ShapeData<T> = new Map()\n  readonly #subscribers = new Map<number, ShapeChangedCallback<T>>()\n  readonly #insertedKeys = new Set<string>()\n  readonly #requestedSubSnapshots = new Set<string>()\n  #reexecuteSnapshotsPending = false\n  #status: ShapeStatus = `syncing`\n  #error: FetchError | false = false\n\n  constructor(stream: ShapeStreamInterface<T>) {\n    this.stream = stream\n    this.stream.subscribe(\n      this.#process.bind(this),\n      this.#handleError.bind(this)\n    )\n  }\n\n  get isUpToDate(): boolean {\n    return this.#status === `up-to-date`\n  }\n\n  get lastOffset(): Offset {\n    return this.stream.lastOffset\n  }\n\n  get handle(): string | undefined {\n    return this.stream.shapeHandle\n  }\n\n  get rows(): Promise<T[]> {\n    return this.value.then((v) => Array.from(v.values()))\n  }\n\n  get currentRows(): T[] {\n    return Array.from(this.currentValue.values())\n  }\n\n  get value(): Promise<ShapeData<T>> {\n    return new Promise((resolve, reject) => {\n      if (this.stream.isUpToDate) {\n        resolve(this.currentValue)\n      } else {\n        const unsubscribe = this.subscribe(({ value }) => {\n          unsubscribe()\n          if (this.#error) reject(this.#error)\n          resolve(value)\n        })\n      }\n    })\n  }\n\n  get currentValue() {\n    return this.#data\n  }\n\n  get error() {\n    return this.#error\n  }\n\n  /** Unix time at which we last synced. Undefined when `isLoading` is true. */\n  lastSyncedAt(): number | undefined {\n    return this.stream.lastSyncedAt()\n  }\n\n  /** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */\n  lastSynced() {\n    return this.stream.lastSynced()\n  }\n\n  /** True during initial fetch. False afterwise.  */\n  isLoading() {\n    return this.stream.isLoading()\n  }\n\n  /** Indicates if we are connected to the Electric sync service. */\n  isConnected(): boolean {\n    return this.stream.isConnected()\n  }\n\n  /** Current log mode of the underlying stream */\n  get mode(): LogMode {\n    return this.stream.mode\n  }\n\n  /**\n   * Request a snapshot for subset of data. Only available when mode is changes_only.\n   * Returns void; data will be emitted via the stream and processed by this Shape.\n   */\n  async requestSnapshot(\n    params: Parameters<ShapeStreamInterface<T>[`requestSnapshot`]>[0]\n  ): Promise<void> {\n    // Track this snapshot request for future re-execution on shape rotation\n    const key = JSON.stringify(params)\n    this.#requestedSubSnapshots.add(key)\n    // Ensure the stream is up-to-date so schema is available for parsing\n    await this.#awaitUpToDate()\n    await this.stream.requestSnapshot(params)\n  }\n\n  subscribe(callback: ShapeChangedCallback<T>): () => void {\n    const subscriptionId = Math.random()\n\n    this.#subscribers.set(subscriptionId, callback)\n\n    return () => {\n      this.#subscribers.delete(subscriptionId)\n    }\n  }\n\n  unsubscribeAll(): void {\n    this.#subscribers.clear()\n  }\n\n  get numSubscribers() {\n    return this.#subscribers.size\n  }\n\n  #process(messages: Message<T>[]): void {\n    let shouldNotify = false\n\n    messages.forEach((message) => {\n      if (isChangeMessage(message)) {\n        shouldNotify = this.#updateShapeStatus(`syncing`)\n        if (this.mode === `full`) {\n          switch (message.headers.operation) {\n            case `insert`:\n              this.#data.set(message.key, message.value)\n              break\n            case `update`:\n              this.#data.set(message.key, {\n                ...this.#data.get(message.key)!,\n                ...message.value,\n              })\n              break\n            case `delete`:\n              this.#data.delete(message.key)\n              break\n          }\n        } else {\n          // changes_only: only apply updates/deletes for keys for which we observed an insert\n          switch (message.headers.operation) {\n            case `insert`:\n              this.#insertedKeys.add(message.key)\n              this.#data.set(message.key, message.value)\n              break\n            case `update`:\n              if (this.#insertedKeys.has(message.key)) {\n                this.#data.set(message.key, {\n                  ...this.#data.get(message.key)!,\n                  ...message.value,\n                })\n              }\n              break\n            case `delete`:\n              if (this.#insertedKeys.has(message.key)) {\n                this.#data.delete(message.key)\n                this.#insertedKeys.delete(message.key)\n              }\n              break\n          }\n        }\n      }\n\n      if (isControlMessage(message)) {\n        switch (message.headers.control) {\n          case `up-to-date`:\n            shouldNotify = this.#updateShapeStatus(`up-to-date`)\n            if (this.#reexecuteSnapshotsPending) {\n              this.#reexecuteSnapshotsPending = false\n              void this.#reexecuteSnapshots()\n            }\n            break\n          case `must-refetch`:\n            this.#data.clear()\n            this.#insertedKeys.clear()\n            this.#error = false\n            shouldNotify = this.#updateShapeStatus(`syncing`)\n            // Flag to re-execute sub-snapshots once the new shape is up-to-date\n            this.#reexecuteSnapshotsPending = true\n            break\n        }\n      }\n    })\n\n    if (shouldNotify) this.#notify()\n  }\n\n  async #reexecuteSnapshots(): Promise<void> {\n    // Wait until stream is up-to-date again (ensures schema is available)\n    await this.#awaitUpToDate()\n\n    // Re-execute all snapshots concurrently\n    await Promise.all(\n      Array.from(this.#requestedSubSnapshots).map(async (jsonParams) => {\n        try {\n          const snapshot = JSON.parse(jsonParams)\n          await this.stream.requestSnapshot(snapshot)\n        } catch (_) {\n          // Ignore and continue; errors will be surfaced via stream onError\n        }\n      })\n    )\n  }\n\n  async #awaitUpToDate(): Promise<void> {\n    if (this.stream.isUpToDate) return\n    await new Promise<void>((resolve) => {\n      const check = () => {\n        if (this.stream.isUpToDate) {\n          clearInterval(interval)\n          unsub()\n          resolve()\n        }\n      }\n      const interval = setInterval(check, 10)\n      const unsub = this.stream.subscribe(\n        () => check(),\n        () => check()\n      )\n      check()\n    })\n  }\n\n  #updateShapeStatus(status: ShapeStatus): boolean {\n    const stateChanged = this.#status !== status\n    this.#status = status\n    return stateChanged && status === `up-to-date`\n  }\n\n  #handleError(e: Error): void {\n    if (e instanceof FetchError) {\n      this.#error = e\n      this.#notify()\n    }\n  }\n\n  #notify(): void {\n    this.#subscribers.forEach((callback) => {\n      callback({ value: this.currentValue, rows: this.currentRows })\n    })\n  }\n}\n"],"mappings":"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","names":["key","value","_fetchClient","_a","_b","fetch","_subscribers","_error"]}