{"version":3,"sources":["../src/error.ts","../src/parser.ts","../src/column-mapper.ts","../src/helpers.ts","../src/constants.ts","../src/fetch.ts","../src/expression-compiler.ts","../../../node_modules/.pnpm/@microsoft+fetch-event-source@2.0.1_patch_hash=46f4e76dd960e002a542732bb4323817a24fce1673cb71e2f458fe09776fa188/node_modules/@microsoft/fetch-event-source/src/parse.ts","../../../node_modules/.pnpm/@microsoft+fetch-event-source@2.0.1_patch_hash=46f4e76dd960e002a542732bb4323817a24fce1673cb71e2f458fe09776fa188/node_modules/@microsoft/fetch-event-source/src/fetch.ts","../src/expired-shapes-cache.ts","../src/up-to-date-tracker.ts","../src/snapshot-tracker.ts","../src/shape-stream-state.ts","../src/pause-lock.ts","../src/client.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\nexport class StaleCacheError extends Error {\n  constructor(message: string) {\n    super(message)\n    this.name = `StaleCacheError`\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        return this.transformMessageValue(value, schema)\n      }\n      return value\n    }) as Result\n  }\n\n  /**\n   * Parse an array of ChangeMessages from a snapshot response.\n   * Applies type parsing and transformations to the value and old_value properties.\n   */\n  parseSnapshotData<Result>(\n    messages: Array<unknown>,\n    schema: Schema\n  ): Array<Result> {\n    return messages.map((message) => {\n      const msg = message as Record<string, unknown>\n\n      // Transform the value property if it exists\n      if (msg.value && typeof msg.value === `object` && msg.value !== null) {\n        msg.value = this.transformMessageValue(msg.value, schema)\n      }\n\n      // Transform the old_value property if it exists\n      if (\n        msg.old_value &&\n        typeof msg.old_value === `object` &&\n        msg.old_value !== null\n      ) {\n        msg.old_value = this.transformMessageValue(msg.old_value, schema)\n      }\n\n      return msg as Result\n    })\n  }\n\n  /**\n   * Transform a message value or old_value object by parsing its columns.\n   */\n  private transformMessageValue(\n    value: unknown,\n    schema: Schema\n  ): Row<GetExtensions<T>> {\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    return this.transformer ? this.transformer(row) : row\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 { Schema } from './types'\n\ntype DbColumnName = string\ntype AppColumnName = string\n\n/**\n * Quote a PostgreSQL identifier for safe use in query parameters.\n *\n * Wraps the identifier in double quotes and escapes any internal\n * double quotes by doubling them. This ensures identifiers with\n * special characters (commas, spaces, etc.) are handled correctly.\n *\n * @param identifier - The identifier to quote\n * @returns The quoted identifier\n *\n * @example\n * ```typescript\n * quoteIdentifier('user_id')        // '\"user_id\"'\n * quoteIdentifier('foo,bar')        // '\"foo,bar\"'\n * quoteIdentifier('has\"quote')      // '\"has\"\"quote\"'\n * ```\n *\n * @internal\n */\nexport function quoteIdentifier(identifier: string): string {\n  // Escape internal double quotes by doubling them\n  const escaped = identifier.replace(/\"/g, `\"\"`)\n  return `\"${escaped}\"`\n}\n\n/**\n * A bidirectional column mapper that handles transforming column **names**\n * between database format (e.g., snake_case) and application format (e.g., camelCase).\n *\n * **Important**: ColumnMapper only transforms column names, not column values or types.\n * For type conversions (e.g., string → Date), use the `parser` option.\n * For value transformations (e.g., encryption), use the `transformer` option.\n *\n * @example\n * ```typescript\n * const mapper = snakeCamelMapper()\n * mapper.decode('user_id') // 'userId'\n * mapper.encode('userId') // 'user_id'\n * ```\n */\nexport interface ColumnMapper {\n  /**\n   * Transform a column name from database format to application format.\n   * Applied to column names in query results.\n   */\n  decode: (dbColumnName: DbColumnName) => AppColumnName\n\n  /**\n   * Transform a column name from application format to database format.\n   * Applied to column names in WHERE clauses and other query parameters.\n   */\n  encode: (appColumnName: AppColumnName) => DbColumnName\n}\n\n/**\n * Converts a snake_case string to camelCase.\n *\n * Handles edge cases:\n * - Preserves leading underscores: `_user_id` → `_userId`\n * - Preserves trailing underscores: `user_id_` → `userId_`\n * - Collapses multiple underscores: `user__id` → `userId`\n * - Normalizes to lowercase first: `user_Column` → `userColumn`\n *\n * @example\n * snakeToCamel('user_id') // 'userId'\n * snakeToCamel('project_id') // 'projectId'\n * snakeToCamel('created_at') // 'createdAt'\n * snakeToCamel('_private') // '_private'\n * snakeToCamel('user__id') // 'userId'\n * snakeToCamel('user_id_') // 'userId_'\n */\nexport function snakeToCamel(str: string): string {\n  // Preserve leading underscores\n  const leadingUnderscores = str.match(/^_+/)?.[0] ?? ``\n  const withoutLeading = str.slice(leadingUnderscores.length)\n\n  // Preserve trailing underscores for round-trip safety\n  const trailingUnderscores = withoutLeading.match(/_+$/)?.[0] ?? ``\n  const core = trailingUnderscores\n    ? withoutLeading.slice(\n        0,\n        withoutLeading.length - trailingUnderscores.length\n      )\n    : withoutLeading\n\n  // Convert to lowercase\n  const normalized = core.toLowerCase()\n\n  // Convert snake_case to camelCase (handling multiple underscores)\n  const camelCased = normalized.replace(/_+([a-z])/g, (_, letter) =>\n    letter.toUpperCase()\n  )\n\n  return leadingUnderscores + camelCased + trailingUnderscores\n}\n\n/**\n * Converts a camelCase string to snake_case.\n *\n * Handles consecutive capitals (acronyms) properly:\n * - `userID` → `user_id`\n * - `userHTTPSURL` → `user_https_url`\n *\n * @example\n * camelToSnake('userId') // 'user_id'\n * camelToSnake('projectId') // 'project_id'\n * camelToSnake('createdAt') // 'created_at'\n * camelToSnake('userID') // 'user_id'\n * camelToSnake('parseHTMLString') // 'parse_html_string'\n */\nexport function camelToSnake(str: string): string {\n  return (\n    str\n      // Insert underscore before uppercase letters that follow lowercase letters\n      // e.g., userId -> user_Id\n      .replace(/([a-z])([A-Z])/g, `$1_$2`)\n      // Insert underscore before uppercase letters that are followed by lowercase letters\n      // This handles acronyms: userID -> user_ID, but parseHTMLString -> parse_HTML_String\n      .replace(/([A-Z]+)([A-Z][a-z])/g, `$1_$2`)\n      .toLowerCase()\n  )\n}\n\n/**\n * Creates a column mapper from an explicit mapping of database columns to application columns.\n *\n * @param mapping - Object mapping database column names (keys) to application column names (values)\n * @returns A ColumnMapper that can encode and decode column names bidirectionally\n *\n * @example\n * const mapper = createColumnMapper({\n *   user_id: 'userId',\n *   project_id: 'projectId',\n *   created_at: 'createdAt'\n * })\n *\n * // Use with ShapeStream\n * const stream = new ShapeStream({\n *   url: 'http://localhost:3000/v1/shape',\n *   params: { table: 'todos' },\n *   columnMapper: mapper\n * })\n */\nexport function createColumnMapper(\n  mapping: Record<string, string>\n): ColumnMapper {\n  // Build reverse mapping: app name -> db name\n  const reverseMapping: Record<string, string> = {}\n  for (const [dbName, appName] of Object.entries(mapping)) {\n    reverseMapping[appName] = dbName\n  }\n\n  return {\n    decode: (dbColumnName: string) => {\n      return mapping[dbColumnName] ?? dbColumnName\n    },\n\n    encode: (appColumnName: string) => {\n      return reverseMapping[appColumnName] ?? appColumnName\n    },\n  }\n}\n\n/**\n * Encodes column names in a WHERE clause using the provided encoder function.\n * Uses regex to identify column references and replace them.\n *\n * Handles common SQL patterns:\n * - Simple comparisons: columnName = $1\n * - Function calls: LOWER(columnName)\n * - Qualified names: table.columnName\n * - Operators: columnName IS NULL, columnName IN (...)\n * - Quoted strings: Preserves string literals unchanged\n *\n * Note: This uses regex-based replacement which works for most common cases\n * but may not handle all complex SQL expressions perfectly. For complex queries,\n * test thoroughly or use database column names directly in WHERE clauses.\n *\n * @param whereClause - The WHERE clause string to encode\n * @param encode - Optional encoder function. If undefined, returns whereClause unchanged.\n * @returns The encoded WHERE clause\n *\n * @internal\n */\nexport function encodeWhereClause(\n  whereClause: string | undefined,\n  encode?: (columnName: string) => string\n): string {\n  if (!whereClause || !encode) return whereClause ?? ``\n\n  // SQL keywords that should not be transformed (common ones)\n  const sqlKeywords = new Set([\n    `SELECT`,\n    `FROM`,\n    `WHERE`,\n    `AND`,\n    `OR`,\n    `NOT`,\n    `IN`,\n    `IS`,\n    `NULL`,\n    `NULLS`,\n    `FIRST`,\n    `LAST`,\n    `TRUE`,\n    `FALSE`,\n    `LIKE`,\n    `ILIKE`,\n    `BETWEEN`,\n    `ASC`,\n    `DESC`,\n    `LIMIT`,\n    `OFFSET`,\n    `ORDER`,\n    `BY`,\n    `GROUP`,\n    `HAVING`,\n    `DISTINCT`,\n    `AS`,\n    `ON`,\n    `JOIN`,\n    `LEFT`,\n    `RIGHT`,\n    `INNER`,\n    `OUTER`,\n    `CROSS`,\n    `CASE`,\n    `WHEN`,\n    `THEN`,\n    `ELSE`,\n    `END`,\n    `CAST`,\n    `LOWER`,\n    `UPPER`,\n    `COALESCE`,\n    `NULLIF`,\n  ])\n\n  // Track positions of quoted strings and double-quoted identifiers to skip them\n  const quotedRanges: Array<{ start: number; end: number }> = []\n\n  // Find all single-quoted strings and double-quoted identifiers\n  let pos = 0\n  while (pos < whereClause.length) {\n    const ch = whereClause[pos]\n    if (ch === `'` || ch === `\"`) {\n      const start = pos\n      const quoteChar = ch\n      pos++ // Skip opening quote\n      // Find closing quote, handling escaped quotes ('' or \"\")\n      while (pos < whereClause.length) {\n        if (whereClause[pos] === quoteChar) {\n          if (whereClause[pos + 1] === quoteChar) {\n            pos += 2 // Skip escaped quote\n          } else {\n            pos++ // Skip closing quote\n            break\n          }\n        } else {\n          pos++\n        }\n      }\n      quotedRanges.push({ start, end: pos })\n    } else {\n      pos++\n    }\n  }\n\n  // Helper to check if position is within a quoted string or double-quoted identifier\n  const isInQuotedString = (pos: number): boolean => {\n    return quotedRanges.some((range) => pos >= range.start && pos < range.end)\n  }\n\n  // Pattern explanation:\n  // (?<![a-zA-Z0-9_]) - negative lookbehind: not preceded by identifier char\n  // ([a-zA-Z_][a-zA-Z0-9_]*) - capture: valid SQL identifier\n  // (?![a-zA-Z0-9_]) - negative lookahead: not followed by identifier char\n  //\n  // This avoids matching:\n  // - Parts of longer identifiers\n  // - SQL keywords (handled by checking if result differs from input)\n  const identifierPattern =\n    /(?<![a-zA-Z0-9_])([a-zA-Z_][a-zA-Z0-9_]*)(?![a-zA-Z0-9_])/g\n\n  return whereClause.replace(identifierPattern, (match, _p1, offset) => {\n    // Don't transform if inside quoted string\n    if (isInQuotedString(offset)) {\n      return match\n    }\n\n    // Don't transform SQL keywords\n    if (sqlKeywords.has(match.toUpperCase())) {\n      return match\n    }\n\n    // Don't transform parameter placeholders ($1, $2, etc.)\n    // This regex won't match them anyway, but being explicit\n    if (match.startsWith(`$`)) {\n      return match\n    }\n\n    // Apply encoding\n    const encoded = encode(match)\n    return encoded\n  })\n}\n\n/**\n * Creates a column mapper that automatically converts between snake_case and camelCase.\n * This is the most common use case for column mapping.\n *\n * When a schema is provided, it will only map columns that exist in the schema.\n * Otherwise, it will map any column name it encounters.\n *\n * **⚠️ Limitations and Edge Cases:**\n * - **WHERE clause encoding**: Uses regex-based parsing which may not handle all complex\n *   SQL expressions. Test thoroughly with your queries, especially those with:\n *   - Complex nested expressions\n *   - Custom operators or functions\n *   - Column names that conflict with SQL keywords\n *   - Quoted identifiers (e.g., `\"$price\"`, `\"user-id\"`) - not supported\n *   - Column names with special characters (non-alphanumeric except underscore)\n * - **Acronym ambiguity**: `userID` → `user_id` → `userId` (ID becomes Id after roundtrip)\n *   Use `createColumnMapper()` with explicit mapping if you need exact control\n * - **Type conversion**: This only renames columns, not values. Use `parser` for type conversion\n *\n * **When to use explicit mapping instead:**\n * - You have column names that don't follow snake_case/camelCase patterns\n * - You need exact control over mappings (e.g., `id` → `identifier`)\n * - Your WHERE clauses are complex and automatic encoding fails\n * - You have quoted identifiers or column names with special characters\n *\n * @param schema - Optional database schema to constrain mapping to known columns\n * @returns A ColumnMapper for snake_case ↔ camelCase conversion\n *\n * @example\n * // Basic usage\n * const mapper = snakeCamelMapper()\n *\n * // With schema - only maps columns in schema (recommended)\n * const mapper = snakeCamelMapper(schema)\n *\n * // Use with ShapeStream\n * const stream = new ShapeStream({\n *   url: 'http://localhost:3000/v1/shape',\n *   params: { table: 'todos' },\n *   columnMapper: snakeCamelMapper()\n * })\n *\n * @example\n * // If automatic encoding fails, fall back to manual column names in WHERE clauses:\n * stream.requestSnapshot({\n *   where: \"user_id = $1\", // Use database column names directly if needed\n *   params: { \"1\": \"123\" }\n * })\n */\nexport function snakeCamelMapper(schema?: Schema): ColumnMapper {\n  // If schema provided, build explicit mapping\n  if (schema) {\n    const mapping: Record<string, string> = {}\n    for (const dbColumn of Object.keys(schema)) {\n      mapping[dbColumn] = snakeToCamel(dbColumn)\n    }\n    return createColumnMapper(mapping)\n  }\n\n  // Otherwise, map dynamically\n  return {\n    decode: (dbColumnName: string) => {\n      return snakeToCamel(dbColumnName)\n    },\n\n    encode: (appColumnName: string) => {\n      return camelToSnake(appColumnName)\n    },\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 message != null && `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 message != null && `headers` in message && `control` in message.headers\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  if (message.headers.control != `up-to-date`) return\n  const lsn = message.headers.global_last_seen_lsn\n  return lsn ? (`${lsn}_0` as Offset) : undefined\n}\n\nfunction bigintReplacer(_key: string, value: unknown): unknown {\n  return typeof value === `bigint` ? value.toString() : value\n}\n\n/**\n * BigInt-safe version of JSON.stringify.\n * Converts BigInt values to their string representation (as JSON strings,\n * e.g. `{ id: 42n }` becomes `{\"id\":\"42\"}`) instead of throwing.\n * Assumes input is a JSON-serializable value — passing `undefined` at the\n * top level will return `undefined` (matching `JSON.stringify` behavior).\n */\nexport function bigintSafeStringify(value: unknown): string {\n  return JSON.stringify(value, bigintReplacer)\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 SYSTEM_WAKE = `system-wake`\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`\nexport const SUBSET_PARAM_WHERE_EXPR = `subset__where_expr`\nexport const SUBSET_PARAM_ORDER_BY_EXPR = `subset__order_by_expr`\nexport const CACHE_BUSTER_QUERY_PARAM = `cache-buster` // Random cache buster to bypass stale CDN responses\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  SUBSET_PARAM_WHERE_EXPR,\n  SUBSET_PARAM_ORDER_BY_EXPR,\n  CACHE_BUSTER_QUERY_PARAM,\n]\n","import {\n  CHUNK_LAST_OFFSET_HEADER,\n  CHUNK_UP_TO_DATE_HEADER,\n  EXPIRED_HANDLE_QUERY_PARAM,\n  LIVE_CACHE_BUSTER_HEADER,\n  LIVE_QUERY_PARAM,\n  OFFSET_QUERY_PARAM,\n  SHAPE_SCHEMA_HEADER,\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: 1_000,\n  maxDelay: 32_000,\n  multiplier: 2,\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 | undefined\n\n  const prefetchClient = async (...args: Parameters<typeof fetchClient>) => {\n    const url = args[0].toString()\n    const method = getRequestMethod(args[0], args[1])\n\n    // Prefetch is only valid for GET requests. The prefetch queue matches\n    // requests by URL alone and ignores HTTP method/body, so a POST request\n    // with the same URL would incorrectly consume the prefetched stream\n    // response instead of making its own request.\n    if (method !== `GET`) {\n      prefetchQueue?.abort()\n      prefetchQueue = undefined\n      return fetchClient(...args)\n    }\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    // Clear the prefetch queue after aborting to prevent returning\n    // stale/aborted requests on future calls with the same URL\n    prefetchQueue?.abort()\n    prefetchQueue = undefined\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  CHUNK_LAST_OFFSET_HEADER,\n  SHAPE_HANDLE_HEADER,\n]\n\nexport const requiredLiveResponseHeaders = [LIVE_CACHE_BUSTER_HEADER]\n\nexport const requiredNonLiveResponseHeaders = [SHAPE_SCHEMA_HEADER]\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    this.#prefetchQueue.clear()\n  }\n\n  consume(...args: Parameters<typeof fetch>): Promise<Response> | void {\n    const url = args[0].toString()\n\n    const entry = this.#prefetchQueue.get(url)\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 (!entry || url !== this.#queueHeadUrl) return\n\n    const [request, aborter] = entry\n    // Don't return aborted requests - they will reject with AbortError\n    if (aborter.signal.aborted) {\n      this.#prefetchQueue.delete(url)\n      return\n    }\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  // don't prefetch if the response handle is the expired handle from the request\n  // this can happen when a proxy serves a stale cached response despite the\n  // expired_handle cache buster parameter\n  const expiredHandle = nextUrl.searchParams.get(EXPIRED_HANDLE_QUERY_PARAM)\n  if (expiredHandle && shapeHandle === expiredHandle) {\n    console.warn(\n      `[Electric] Received stale cached response with expired shape handle. ` +\n        `This should not happen and indicates a proxy/CDN caching misconfiguration. ` +\n        `The response contained handle \"${shapeHandle}\" which was previously marked as expired. ` +\n        `Check that your proxy includes all query parameters (especially 'handle' and 'offset') in its cache key. ` +\n        `Skipping prefetch to prevent infinite 409 loop.`\n    )\n    return\n  }\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\nfunction getRequestMethod(\n  input: Parameters<typeof fetch>[0],\n  init?: Parameters<typeof fetch>[1]\n): string {\n  if (init?.method) {\n    return init.method.toUpperCase()\n  }\n\n  if (typeof Request !== `undefined` && input instanceof Request) {\n    return input.method.toUpperCase()\n  }\n\n  return `GET`\n}\n","import { SerializedExpression, SerializedOrderByClause } from './types'\nimport { quoteIdentifier } from './column-mapper'\n\n/**\n * Compiles a serialized expression into a SQL string.\n * Applies columnMapper transformations to column references.\n *\n * @param expr - The serialized expression to compile\n * @param columnMapper - Optional function to transform column names (e.g., camelCase to snake_case)\n * @returns The compiled SQL string\n *\n * @example\n * ```typescript\n * const expr = { type: 'ref', column: 'userId' }\n * compileExpression(expr, camelToSnake) // '\"user_id\"'\n * ```\n */\nexport function compileExpression(\n  expr: SerializedExpression,\n  columnMapper?: (col: string) => string\n): string {\n  switch (expr.type) {\n    case `ref`: {\n      // Apply columnMapper, then quote\n      const mappedColumn = columnMapper\n        ? columnMapper(expr.column)\n        : expr.column\n      return quoteIdentifier(mappedColumn)\n    }\n    case `val`:\n      return `$${expr.paramIndex}`\n    case `func`:\n      return compileFunction(expr, columnMapper)\n    default: {\n      // TypeScript exhaustiveness check\n      const _exhaustive: never = expr\n      throw new Error(`Unknown expression type: ${JSON.stringify(_exhaustive)}`)\n    }\n  }\n}\n\n/**\n * Compiles a function expression into SQL.\n */\nfunction compileFunction(\n  expr: { type: `func`; name: string; args: SerializedExpression[] },\n  columnMapper?: (col: string) => string\n): string {\n  const args = expr.args.map((arg) => compileExpression(arg, columnMapper))\n\n  switch (expr.name) {\n    // Binary comparison operators\n    case `eq`:\n      return `${args[0]} = ${args[1]}`\n    case `gt`:\n      return `${args[0]} > ${args[1]}`\n    case `gte`:\n      return `${args[0]} >= ${args[1]}`\n    case `lt`:\n      return `${args[0]} < ${args[1]}`\n    case `lte`:\n      return `${args[0]} <= ${args[1]}`\n\n    // Logical operators\n    case `and`:\n      return args.map((a) => `(${a})`).join(` AND `)\n    case `or`:\n      return args.map((a) => `(${a})`).join(` OR `)\n    case `not`:\n      return `NOT (${args[0]})`\n\n    // Special operators\n    case `in`:\n      return `${args[0]} = ANY(${args[1]})`\n    case `like`:\n      return `${args[0]} LIKE ${args[1]}`\n    case `ilike`:\n      return `${args[0]} ILIKE ${args[1]}`\n    case `isNull`:\n    case `isUndefined`:\n      return `${args[0]} IS NULL`\n\n    // String functions\n    case `upper`:\n      return `UPPER(${args[0]})`\n    case `lower`:\n      return `LOWER(${args[0]})`\n    case `length`:\n      return `LENGTH(${args[0]})`\n    case `concat`:\n      return `CONCAT(${args.join(`, `)})`\n\n    // Other functions\n    case `coalesce`:\n      return `COALESCE(${args.join(`, `)})`\n\n    default:\n      throw new Error(`Unknown function: ${expr.name}`)\n  }\n}\n\n/**\n * Compiles serialized ORDER BY clauses into a SQL string.\n * Applies columnMapper transformations to column references.\n *\n * @param clauses - The serialized ORDER BY clauses to compile\n * @param columnMapper - Optional function to transform column names\n * @returns The compiled SQL ORDER BY string\n *\n * @example\n * ```typescript\n * const clauses = [{ column: 'createdAt', direction: 'desc', nulls: 'first' }]\n * compileOrderBy(clauses, camelToSnake) // '\"created_at\" DESC NULLS FIRST'\n * ```\n */\nexport function compileOrderBy(\n  clauses: SerializedOrderByClause[],\n  columnMapper?: (col: string) => string\n): string {\n  return clauses\n    .map((clause) => {\n      const mappedColumn = columnMapper\n        ? columnMapper(clause.column)\n        : clause.column\n      let sql = quoteIdentifier(mappedColumn)\n      if (clause.direction === `desc`) sql += ` DESC`\n      if (clause.nulls === `first`) sql += ` NULLS FIRST`\n      if (clause.nulls === `last`) sql += ` NULLS LAST`\n      return sql\n    })\n    .join(`, `)\n}\n",null,null,"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  delete(shapeUrl: string): void {\n    delete this.data[shapeUrl]\n    this.save()\n  }\n}\n\n// Module-level singleton instance\nexport const expiredShapesCache = new ExpiredShapesCache()\n","interface UpToDateEntry {\n  timestamp: number\n  cursor: string\n}\n\n/**\n * Tracks up-to-date messages to detect when we're replaying cached responses.\n *\n * When a shape receives an up-to-date, we record the timestamp and cursor in localStorage.\n * On page refresh, if we find a recent timestamp (< 60s), we know we'll be replaying\n * cached responses. We suppress their up-to-date notifications until we see a NEW cursor\n * (different from the last recorded one), which indicates fresh data from the server.\n *\n * localStorage writes are throttled to once per 60 seconds to avoid performance issues\n * with frequent updates. In-memory data is always kept current.\n */\nexport class UpToDateTracker {\n  private data: Record<string, UpToDateEntry> = {}\n  private readonly storageKey = `electric_up_to_date_tracker`\n  private readonly cacheTTL = 60_000 // 60s to match typical CDN s-maxage cache duration\n  private readonly maxEntries = 250\n  private readonly writeThrottleMs = 60_000 // Throttle localStorage writes to once per 60s\n  private lastWriteTime = 0\n  private pendingSaveTimer?: ReturnType<typeof setTimeout>\n\n  constructor() {\n    this.load()\n    this.cleanup()\n  }\n\n  /**\n   * Records that a shape received an up-to-date message with a specific cursor.\n   * This timestamp and cursor are used to detect cache replay scenarios.\n   * Updates in-memory immediately, but throttles localStorage writes.\n   */\n  recordUpToDate(shapeKey: string, cursor: string): void {\n    this.data[shapeKey] = {\n      timestamp: Date.now(),\n      cursor,\n    }\n\n    // Implement LRU eviction if we exceed max entries\n    const keys = Object.keys(this.data)\n    if (keys.length > this.maxEntries) {\n      const oldest = keys.reduce((min, k) =>\n        this.data[k].timestamp < this.data[min].timestamp ? k : min\n      )\n      delete this.data[oldest]\n    }\n\n    this.scheduleSave()\n  }\n\n  /**\n   * Schedules a throttled save to localStorage.\n   * Writes immediately if enough time has passed, otherwise schedules for later.\n   */\n  private scheduleSave(): void {\n    const now = Date.now()\n    const timeSinceLastWrite = now - this.lastWriteTime\n\n    if (timeSinceLastWrite >= this.writeThrottleMs) {\n      // Enough time has passed, write immediately\n      this.lastWriteTime = now\n      this.save()\n    } else if (!this.pendingSaveTimer) {\n      // Schedule a write for when the throttle period expires\n      const delay = this.writeThrottleMs - timeSinceLastWrite\n      this.pendingSaveTimer = setTimeout(() => {\n        this.lastWriteTime = Date.now()\n        this.pendingSaveTimer = undefined\n        this.save()\n      }, delay)\n    }\n    // else: a save is already scheduled, no need to do anything\n  }\n\n  /**\n   * Checks if we should enter replay mode for this shape.\n   * Returns the last seen cursor if there's a recent up-to-date (< 60s),\n   * which means we'll likely be replaying cached responses.\n   * Returns null if no recent up-to-date exists.\n   */\n  shouldEnterReplayMode(shapeKey: string): string | null {\n    const entry = this.data[shapeKey]\n    if (!entry) {\n      return null\n    }\n\n    const age = Date.now() - entry.timestamp\n    if (age >= this.cacheTTL) {\n      return null\n    }\n\n    return entry.cursor\n  }\n\n  /**\n   * Cleans up expired entries from the cache.\n   * Called on initialization and can be called periodically.\n   */\n  private cleanup(): void {\n    const now = Date.now()\n    const keys = Object.keys(this.data)\n    let modified = false\n\n    for (const key of keys) {\n      const age = now - this.data[key].timestamp\n      if (age > this.cacheTTL) {\n        delete this.data[key]\n        modified = true\n      }\n    }\n\n    if (modified) {\n      this.save()\n    }\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 (quota exceeded, etc.)\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  /**\n   * Clears all tracked up-to-date timestamps.\n   * Useful for testing or manual cache invalidation.\n   */\n  clear(): void {\n    this.data = {}\n    if (this.pendingSaveTimer) {\n      clearTimeout(this.pendingSaveTimer)\n      this.pendingSaveTimer = undefined\n    }\n    this.save()\n  }\n\n  delete(shapeKey: string): void {\n    delete this.data[shapeKey]\n    this.save()\n  }\n}\n\n// Module-level singleton instance\nexport const upToDateTracker = new UpToDateTracker()\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","/*\n * Shape stream state machine.\n *\n * Class hierarchy:\n *\n *   ShapeStreamState (abstract base)\n *   ├── ActiveState (abstract — shared field storage & helpers)\n *   │   ├── FetchingState (abstract — shared Initial/Syncing/StaleRetry behavior)\n *   │   │   ├── InitialState\n *   │   │   ├── SyncingState\n *   │   │   └── StaleRetryState\n *   │   ├── LiveState\n *   │   └── ReplayingState\n *   ├── PausedState   (delegates to previousState)\n *   └── ErrorState    (delegates to previousState)\n *\n * State transitions:\n *\n *   Initial ─response─► Syncing ─up-to-date─► Live\n *                            │                  │\n *                            └──stale──► StaleRetry\n *                                           │\n *                            Syncing ◄──response──┘\n *\n *   Any state ─pause─► Paused ─resume─► (previous state)\n *   Any state ─error─► Error  ─retry──► (previous state)\n *   Any state ─markMustRefetch─► Initial (offset reset)\n */\nimport { Offset, Schema } from './types'\nimport {\n  OFFSET_QUERY_PARAM,\n  SHAPE_HANDLE_QUERY_PARAM,\n  LIVE_CACHE_BUSTER_QUERY_PARAM,\n  LIVE_QUERY_PARAM,\n  CACHE_BUSTER_QUERY_PARAM,\n} from './constants'\n\nexport type ShapeStreamStateKind =\n  | `initial`\n  | `syncing`\n  | `live`\n  | `replaying`\n  | `stale-retry`\n  | `paused`\n  | `error`\n\n/**\n * Shared fields carried by all active (non-paused, non-error) states.\n */\nexport interface SharedStateFields {\n  readonly handle?: string\n  readonly offset: Offset\n  readonly schema?: Schema\n  readonly liveCacheBuster: string\n  readonly lastSyncedAt?: number\n}\n\ntype ResponseBaseInput = {\n  status: number\n  responseHandle: string | null\n  responseOffset: Offset | null\n  responseCursor: string | null\n  responseSchema?: Schema\n  expiredHandle?: string | null\n  now: number\n}\n\nexport type ResponseMetadataInput = ResponseBaseInput & {\n  maxStaleCacheRetries: number\n  createCacheBuster: () => string\n}\n\nexport type ResponseMetadataTransition =\n  | { action: `accepted`; state: ShapeStreamState }\n  | { action: `ignored`; state: ShapeStreamState }\n  | {\n      action: `stale-retry`\n      state: ShapeStreamState\n      exceededMaxRetries: boolean\n    }\n\nexport interface MessageBatchInput {\n  hasMessages: boolean\n  hasUpToDateMessage: boolean\n  isSse: boolean\n  upToDateOffset?: Offset\n  now: number\n  currentCursor: string\n}\n\nexport interface MessageBatchTransition {\n  state: ShapeStreamState\n  suppressBatch: boolean\n  becameUpToDate: boolean\n}\n\nexport interface SseCloseInput {\n  connectionDuration: number\n  wasAborted: boolean\n  minConnectionDuration: number\n  maxShortConnections: number\n}\n\nexport interface SseCloseTransition {\n  state: ShapeStreamState\n  fellBackToLongPolling: boolean\n  wasShortConnection: boolean\n}\n\nexport interface UrlParamsContext {\n  isSnapshotRequest: boolean\n  canLongPoll: boolean\n}\n\n// ---------------------------------------------------------------------------\n// Abstract base — shared by ALL states (including Paused/Error)\n// ---------------------------------------------------------------------------\n\n/**\n * Abstract base class for all shape stream states.\n *\n * Each concrete state carries only its relevant fields — there is no shared\n * flat context bag. Transitions create new immutable state objects.\n *\n * `isUpToDate` returns true for LiveState and delegating states wrapping LiveState.\n */\nexport abstract class ShapeStreamState {\n  abstract readonly kind: ShapeStreamStateKind\n\n  // --- Shared field getters (all states expose these) ---\n  abstract get handle(): string | undefined\n  abstract get offset(): Offset\n  abstract get schema(): Schema | undefined\n  abstract get liveCacheBuster(): string\n  abstract get lastSyncedAt(): number | undefined\n\n  // --- Derived booleans ---\n  get isUpToDate(): boolean {\n    return false\n  }\n\n  // --- Per-state field defaults ---\n  get staleCacheBuster(): string | undefined {\n    return undefined\n  }\n  get staleCacheRetryCount(): number {\n    return 0\n  }\n  get sseFallbackToLongPolling(): boolean {\n    return false\n  }\n  get consecutiveShortSseConnections(): number {\n    return 0\n  }\n  get replayCursor(): string | undefined {\n    return undefined\n  }\n\n  // --- Default no-op methods ---\n\n  canEnterReplayMode(): boolean {\n    return false\n  }\n\n  enterReplayMode(_cursor: string): ShapeStreamState {\n    return this\n  }\n\n  shouldUseSse(_opts: {\n    liveSseEnabled: boolean\n    isRefreshing: boolean\n    resumingFromPause: boolean\n  }): boolean {\n    return false\n  }\n\n  handleSseConnectionClosed(_input: SseCloseInput): SseCloseTransition {\n    return {\n      state: this,\n      fellBackToLongPolling: false,\n      wasShortConnection: false,\n    }\n  }\n\n  // --- URL param application ---\n\n  /** Adds state-specific query parameters to the fetch URL. */\n  applyUrlParams(_url: URL, _context: UrlParamsContext): void {}\n\n  // --- Default response/message handlers (Paused/Error never receive these) ---\n\n  handleResponseMetadata(\n    _input: ResponseMetadataInput\n  ): ResponseMetadataTransition {\n    return { action: `ignored`, state: this }\n  }\n\n  handleMessageBatch(_input: MessageBatchInput): MessageBatchTransition {\n    return { state: this, suppressBatch: false, becameUpToDate: false }\n  }\n\n  // --- Universal transitions ---\n\n  /** Returns a new state identical to this one but with the handle changed. */\n  abstract withHandle(handle: string): ShapeStreamState\n\n  pause(): PausedState {\n    return new PausedState(this)\n  }\n\n  toErrorState(error: Error): ErrorState {\n    return new ErrorState(this, error)\n  }\n\n  markMustRefetch(handle?: string): InitialState {\n    return new InitialState({\n      handle,\n      offset: `-1`,\n      liveCacheBuster: ``,\n      lastSyncedAt: this.lastSyncedAt,\n      schema: undefined,\n    })\n  }\n}\n\n// ---------------------------------------------------------------------------\n// ActiveState — intermediate base for all non-paused, non-error states\n// ---------------------------------------------------------------------------\n\n/**\n * Holds shared field storage and provides helpers for response/message\n * handling. All five active states extend this (via FetchingState or directly).\n */\nabstract class ActiveState extends ShapeStreamState {\n  readonly #shared: SharedStateFields\n\n  constructor(shared: SharedStateFields) {\n    super()\n    this.#shared = shared\n  }\n\n  get handle() {\n    return this.#shared.handle\n  }\n  get offset() {\n    return this.#shared.offset\n  }\n  get schema() {\n    return this.#shared.schema\n  }\n  get liveCacheBuster() {\n    return this.#shared.liveCacheBuster\n  }\n  get lastSyncedAt() {\n    return this.#shared.lastSyncedAt\n  }\n\n  /** Expose shared fields to subclasses for spreading into new instances. */\n  protected get currentFields(): SharedStateFields {\n    return this.#shared\n  }\n\n  // --- URL param application ---\n\n  applyUrlParams(url: URL, _context: UrlParamsContext): void {\n    url.searchParams.set(OFFSET_QUERY_PARAM, this.#shared.offset)\n    if (this.#shared.handle) {\n      url.searchParams.set(SHAPE_HANDLE_QUERY_PARAM, this.#shared.handle)\n    }\n  }\n\n  // --- Helpers for subclass handleResponseMetadata implementations ---\n\n  /** Extracts updated SharedStateFields from response headers. */\n  protected parseResponseFields(\n    input: ResponseMetadataInput\n  ): SharedStateFields {\n    const responseHandle = input.responseHandle\n    const handle =\n      responseHandle && responseHandle !== input.expiredHandle\n        ? responseHandle\n        : this.#shared.handle\n    const offset = input.responseOffset ?? this.#shared.offset\n    const liveCacheBuster = input.responseCursor ?? this.#shared.liveCacheBuster\n    const schema = this.#shared.schema ?? input.responseSchema\n    const lastSyncedAt =\n      input.status === 204 ? input.now : this.#shared.lastSyncedAt\n\n    return { handle, offset, schema, liveCacheBuster, lastSyncedAt }\n  }\n\n  /**\n   * Stale detection. Returns a transition if the response is stale,\n   * or null if it is not stale and the caller should proceed normally.\n   */\n  protected checkStaleResponse(\n    input: ResponseMetadataInput\n  ): ResponseMetadataTransition | null {\n    const responseHandle = input.responseHandle\n    const expiredHandle = input.expiredHandle\n\n    if (!responseHandle || responseHandle !== expiredHandle) {\n      return null // not stale\n    }\n\n    // Stale response detected — always enter stale-retry to get a cache buster.\n    // Without a cache buster, the CDN will keep serving the same stale response\n    // and the client loops infinitely (the URL never changes).\n    // currentFields preserves the valid local handle when we already have one.\n    const retryCount = this.staleCacheRetryCount + 1\n    return {\n      action: `stale-retry`,\n      state: new StaleRetryState({\n        ...this.currentFields,\n        staleCacheBuster: input.createCacheBuster(),\n        staleCacheRetryCount: retryCount,\n      }),\n      exceededMaxRetries: retryCount > input.maxStaleCacheRetries,\n    }\n  }\n\n  // --- handleMessageBatch: template method with onUpToDate override point ---\n\n  handleMessageBatch(input: MessageBatchInput): MessageBatchTransition {\n    if (!input.hasMessages || !input.hasUpToDateMessage) {\n      return { state: this, suppressBatch: false, becameUpToDate: false }\n    }\n\n    // Has up-to-date message — compute shared fields for the transition\n    let offset = this.#shared.offset\n    if (input.isSse && input.upToDateOffset) {\n      offset = input.upToDateOffset\n    }\n\n    const shared: SharedStateFields = {\n      handle: this.#shared.handle,\n      offset,\n      schema: this.#shared.schema,\n      liveCacheBuster: this.#shared.liveCacheBuster,\n      lastSyncedAt: input.now,\n    }\n\n    return this.onUpToDate(shared, input)\n  }\n\n  /** Override point for up-to-date handling. Default → LiveState. */\n  protected onUpToDate(\n    shared: SharedStateFields,\n    _input: MessageBatchInput\n  ): MessageBatchTransition {\n    return {\n      state: new LiveState(shared),\n      suppressBatch: false,\n      becameUpToDate: true,\n    }\n  }\n}\n\n// ---------------------------------------------------------------------------\n// FetchingState — Common behavior for Initial/Syncing/StaleRetry\n// ---------------------------------------------------------------------------\n\n/**\n * Captures shared behavior of InitialState, SyncingState, StaleRetryState:\n * - handleResponseMetadata: stale check → parse fields → new SyncingState (or LiveState for 204)\n * - enterReplayMode(cursor) → new ReplayingState\n * - canEnterReplayMode(): boolean — returns true (StaleRetryState overrides to return false,\n *   because entering replay would lose the stale-retry count; see C1 in SPEC.md)\n */\nabstract class FetchingState extends ActiveState {\n  handleResponseMetadata(\n    input: ResponseMetadataInput\n  ): ResponseMetadataTransition {\n    const staleResult = this.checkStaleResponse(input)\n    if (staleResult) return staleResult\n\n    const shared = this.parseResponseFields(input)\n\n    // NOTE: 204s are deprecated, the Electric server should not send these\n    // in latest versions but this is here for backwards compatibility.\n    // A 204 means \"no content, you're caught up\" — transition to live.\n    // Skip SSE detection: a 204 gives no indication SSE will work, and\n    // the 3-attempt fallback cycle adds unnecessary latency.\n    if (input.status === 204) {\n      return {\n        action: `accepted`,\n        state: new LiveState(shared, { sseFallbackToLongPolling: true }),\n      }\n    }\n\n    return { action: `accepted`, state: new SyncingState(shared) }\n  }\n\n  canEnterReplayMode(): boolean {\n    return true\n  }\n\n  enterReplayMode(cursor: string): ReplayingState {\n    return new ReplayingState({\n      ...this.currentFields,\n      replayCursor: cursor,\n    })\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Concrete states\n// ---------------------------------------------------------------------------\n\nexport class InitialState extends FetchingState {\n  readonly kind = `initial` as const\n\n  constructor(shared: SharedStateFields) {\n    super(shared)\n  }\n\n  withHandle(handle: string): InitialState {\n    return new InitialState({ ...this.currentFields, handle })\n  }\n}\n\nexport class SyncingState extends FetchingState {\n  readonly kind = `syncing` as const\n\n  constructor(shared: SharedStateFields) {\n    super(shared)\n  }\n\n  withHandle(handle: string): SyncingState {\n    return new SyncingState({ ...this.currentFields, handle })\n  }\n}\n\nexport class StaleRetryState extends FetchingState {\n  readonly kind = `stale-retry` as const\n  readonly #staleCacheBuster: string\n  readonly #staleCacheRetryCount: number\n\n  constructor(\n    fields: SharedStateFields & {\n      staleCacheBuster: string\n      staleCacheRetryCount: number\n    }\n  ) {\n    const { staleCacheBuster, staleCacheRetryCount, ...shared } = fields\n    super(shared)\n    this.#staleCacheBuster = staleCacheBuster\n    this.#staleCacheRetryCount = staleCacheRetryCount\n  }\n\n  get staleCacheBuster() {\n    return this.#staleCacheBuster\n  }\n  get staleCacheRetryCount() {\n    return this.#staleCacheRetryCount\n  }\n\n  // StaleRetryState must not enter replay mode — it would lose the retry count\n  canEnterReplayMode(): boolean {\n    return false\n  }\n\n  withHandle(handle: string): StaleRetryState {\n    return new StaleRetryState({\n      ...this.currentFields,\n      handle,\n      staleCacheBuster: this.#staleCacheBuster,\n      staleCacheRetryCount: this.#staleCacheRetryCount,\n    })\n  }\n\n  applyUrlParams(url: URL, context: UrlParamsContext): void {\n    super.applyUrlParams(url, context)\n    url.searchParams.set(CACHE_BUSTER_QUERY_PARAM, this.#staleCacheBuster)\n  }\n}\n\nexport class LiveState extends ActiveState {\n  readonly kind = `live` as const\n  readonly #consecutiveShortSseConnections: number\n  readonly #sseFallbackToLongPolling: boolean\n\n  constructor(\n    shared: SharedStateFields,\n    sseState?: {\n      consecutiveShortSseConnections?: number\n      sseFallbackToLongPolling?: boolean\n    }\n  ) {\n    super(shared)\n    this.#consecutiveShortSseConnections =\n      sseState?.consecutiveShortSseConnections ?? 0\n    this.#sseFallbackToLongPolling = sseState?.sseFallbackToLongPolling ?? false\n  }\n\n  get isUpToDate(): boolean {\n    return true\n  }\n\n  get consecutiveShortSseConnections(): number {\n    return this.#consecutiveShortSseConnections\n  }\n\n  get sseFallbackToLongPolling(): boolean {\n    return this.#sseFallbackToLongPolling\n  }\n\n  withHandle(handle: string): LiveState {\n    return new LiveState({ ...this.currentFields, handle }, this.sseState)\n  }\n\n  applyUrlParams(url: URL, context: UrlParamsContext): void {\n    super.applyUrlParams(url, context)\n    // Snapshot requests (with subsetParams) should never use live polling\n    if (!context.isSnapshotRequest) {\n      url.searchParams.set(LIVE_CACHE_BUSTER_QUERY_PARAM, this.liveCacheBuster)\n      if (context.canLongPoll) {\n        url.searchParams.set(LIVE_QUERY_PARAM, `true`)\n      }\n    }\n  }\n\n  private get sseState() {\n    return {\n      consecutiveShortSseConnections: this.#consecutiveShortSseConnections,\n      sseFallbackToLongPolling: this.#sseFallbackToLongPolling,\n    }\n  }\n\n  handleResponseMetadata(\n    input: ResponseMetadataInput\n  ): ResponseMetadataTransition {\n    const staleResult = this.checkStaleResponse(input)\n    if (staleResult) return staleResult\n\n    const shared = this.parseResponseFields(input)\n    return {\n      action: `accepted`,\n      state: new LiveState(shared, this.sseState),\n    }\n  }\n\n  protected onUpToDate(\n    shared: SharedStateFields,\n    _input: MessageBatchInput\n  ): MessageBatchTransition {\n    return {\n      state: new LiveState(shared, this.sseState),\n      suppressBatch: false,\n      becameUpToDate: true,\n    }\n  }\n\n  shouldUseSse(opts: {\n    liveSseEnabled: boolean\n    isRefreshing: boolean\n    resumingFromPause: boolean\n  }): boolean {\n    return (\n      opts.liveSseEnabled &&\n      !opts.isRefreshing &&\n      !opts.resumingFromPause &&\n      !this.#sseFallbackToLongPolling\n    )\n  }\n\n  handleSseConnectionClosed(input: SseCloseInput): SseCloseTransition {\n    let nextConsecutiveShort = this.#consecutiveShortSseConnections\n    let nextFallback = this.#sseFallbackToLongPolling\n    let fellBackToLongPolling = false\n    let wasShortConnection = false\n\n    if (\n      input.connectionDuration < input.minConnectionDuration &&\n      !input.wasAborted\n    ) {\n      wasShortConnection = true\n      nextConsecutiveShort = nextConsecutiveShort + 1\n\n      if (nextConsecutiveShort >= input.maxShortConnections) {\n        nextFallback = true\n        fellBackToLongPolling = true\n      }\n    } else if (input.connectionDuration >= input.minConnectionDuration) {\n      nextConsecutiveShort = 0\n    }\n\n    return {\n      state: new LiveState(this.currentFields, {\n        consecutiveShortSseConnections: nextConsecutiveShort,\n        sseFallbackToLongPolling: nextFallback,\n      }),\n      fellBackToLongPolling,\n      wasShortConnection,\n    }\n  }\n}\n\nexport class ReplayingState extends ActiveState {\n  readonly kind = `replaying` as const\n  readonly #replayCursor: string\n\n  constructor(fields: SharedStateFields & { replayCursor: string }) {\n    const { replayCursor, ...shared } = fields\n    super(shared)\n    this.#replayCursor = replayCursor\n  }\n\n  get replayCursor() {\n    return this.#replayCursor\n  }\n\n  withHandle(handle: string): ReplayingState {\n    return new ReplayingState({\n      ...this.currentFields,\n      handle,\n      replayCursor: this.#replayCursor,\n    })\n  }\n\n  handleResponseMetadata(\n    input: ResponseMetadataInput\n  ): ResponseMetadataTransition {\n    const staleResult = this.checkStaleResponse(input)\n    if (staleResult) return staleResult\n\n    const shared = this.parseResponseFields(input)\n    return {\n      action: `accepted`,\n      state: new ReplayingState({\n        ...shared,\n        replayCursor: this.#replayCursor,\n      }),\n    }\n  }\n\n  protected onUpToDate(\n    shared: SharedStateFields,\n    input: MessageBatchInput\n  ): MessageBatchTransition {\n    // Suppress replayed cache data when cursor has not moved since\n    // the previous session (non-SSE only).\n    const suppressBatch =\n      !input.isSse && this.#replayCursor === input.currentCursor\n    return {\n      state: new LiveState(shared),\n      suppressBatch,\n      becameUpToDate: true,\n    }\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Delegating states (Paused / Error)\n// ---------------------------------------------------------------------------\n\n// Union of all non-delegating states — used to type previousState fields so\n// that PausedState.previousState is never another PausedState, and\n// ErrorState.previousState is never another ErrorState.\nexport type ShapeStreamActiveState =\n  | InitialState\n  | SyncingState\n  | LiveState\n  | ReplayingState\n  | StaleRetryState\n\nexport class PausedState extends ShapeStreamState {\n  readonly kind = `paused` as const\n  readonly previousState: ShapeStreamActiveState | ErrorState\n\n  constructor(previousState: ShapeStreamState) {\n    super()\n    this.previousState = (\n      previousState instanceof PausedState\n        ? previousState.previousState\n        : previousState\n    ) as ShapeStreamActiveState | ErrorState\n  }\n\n  get handle(): string | undefined {\n    return this.previousState.handle\n  }\n  get offset(): Offset {\n    return this.previousState.offset\n  }\n  get schema(): Schema | undefined {\n    return this.previousState.schema\n  }\n  get liveCacheBuster(): string {\n    return this.previousState.liveCacheBuster\n  }\n  get lastSyncedAt(): number | undefined {\n    return this.previousState.lastSyncedAt\n  }\n  get isUpToDate(): boolean {\n    return this.previousState.isUpToDate\n  }\n  get staleCacheBuster(): string | undefined {\n    return this.previousState.staleCacheBuster\n  }\n  get staleCacheRetryCount(): number {\n    return this.previousState.staleCacheRetryCount\n  }\n  get sseFallbackToLongPolling(): boolean {\n    return this.previousState.sseFallbackToLongPolling\n  }\n  get consecutiveShortSseConnections(): number {\n    return this.previousState.consecutiveShortSseConnections\n  }\n  get replayCursor(): string | undefined {\n    return this.previousState.replayCursor\n  }\n\n  handleResponseMetadata(\n    input: ResponseMetadataInput\n  ): ResponseMetadataTransition {\n    const transition = this.previousState.handleResponseMetadata(input)\n    if (transition.action === `accepted`) {\n      return { action: `accepted`, state: new PausedState(transition.state) }\n    }\n    if (transition.action === `ignored`) {\n      return { action: `ignored`, state: this }\n    }\n    if (transition.action === `stale-retry`) {\n      return {\n        action: `stale-retry`,\n        state: new PausedState(transition.state),\n        exceededMaxRetries: transition.exceededMaxRetries,\n      }\n    }\n    const _exhaustive: never = transition\n    throw new Error(\n      `PausedState.handleResponseMetadata: unhandled transition action \"${(_exhaustive as ResponseMetadataTransition).action}\"`\n    )\n  }\n\n  withHandle(handle: string): PausedState {\n    return new PausedState(this.previousState.withHandle(handle))\n  }\n\n  applyUrlParams(url: URL, context: UrlParamsContext): void {\n    this.previousState.applyUrlParams(url, context)\n  }\n\n  pause(): PausedState {\n    return this\n  }\n\n  resume(): ShapeStreamState {\n    return this.previousState\n  }\n}\n\nexport class ErrorState extends ShapeStreamState {\n  readonly kind = `error` as const\n  readonly previousState: ShapeStreamActiveState | PausedState\n  readonly error: Error\n\n  constructor(previousState: ShapeStreamState, error: Error) {\n    super()\n    this.previousState = (\n      previousState instanceof ErrorState\n        ? previousState.previousState\n        : previousState\n    ) as ShapeStreamActiveState | PausedState\n    this.error = error\n  }\n\n  get handle(): string | undefined {\n    return this.previousState.handle\n  }\n  get offset(): Offset {\n    return this.previousState.offset\n  }\n  get schema(): Schema | undefined {\n    return this.previousState.schema\n  }\n  get liveCacheBuster(): string {\n    return this.previousState.liveCacheBuster\n  }\n  get lastSyncedAt(): number | undefined {\n    return this.previousState.lastSyncedAt\n  }\n  get isUpToDate(): boolean {\n    return this.previousState.isUpToDate\n  }\n  get staleCacheBuster(): string | undefined {\n    return this.previousState.staleCacheBuster\n  }\n  get staleCacheRetryCount(): number {\n    return this.previousState.staleCacheRetryCount\n  }\n  get sseFallbackToLongPolling(): boolean {\n    return this.previousState.sseFallbackToLongPolling\n  }\n  get consecutiveShortSseConnections(): number {\n    return this.previousState.consecutiveShortSseConnections\n  }\n  get replayCursor(): string | undefined {\n    return this.previousState.replayCursor\n  }\n\n  withHandle(handle: string): ErrorState {\n    return new ErrorState(this.previousState.withHandle(handle), this.error)\n  }\n\n  applyUrlParams(url: URL, context: UrlParamsContext): void {\n    this.previousState.applyUrlParams(url, context)\n  }\n\n  retry(): ShapeStreamState {\n    return this.previousState\n  }\n\n  reset(handle?: string): InitialState {\n    return this.previousState.markMustRefetch(handle)\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Type alias & factory\n// ---------------------------------------------------------------------------\n\nexport function createInitialState(opts: {\n  offset: Offset\n  handle?: string\n}): InitialState {\n  return new InitialState({\n    handle: opts.handle,\n    offset: opts.offset,\n    liveCacheBuster: ``,\n    lastSyncedAt: undefined,\n    schema: undefined,\n  })\n}\n","/**\n * A set-based counting lock for coordinating multiple pause reasons.\n *\n * Multiple independent subsystems (tab visibility, snapshot requests, etc.)\n * may each need the stream paused. A simple boolean flag or counter can't\n * track *why* the stream is paused, leading to bugs where one subsystem's\n * resume overrides another's pause.\n *\n * PauseLock uses a Set of reason strings. The stream is paused when any\n * reason is held, and only resumes when all reasons are released.\n *\n * @example\n * ```ts\n * const lock = new PauseLock({\n *   onAcquired: () => abortController.abort(),\n *   onReleased: () => startRequestLoop(),\n * })\n *\n * // Tab hidden\n * lock.acquire('visibility')  // → onAcquired fires, stream pauses\n *\n * // Snapshot starts while tab hidden\n * lock.acquire('snapshot-1')  // → no-op, already paused\n *\n * // Snapshot finishes\n * lock.release('snapshot-1')  // → no-op, 'visibility' still held\n *\n * // Tab visible\n * lock.release('visibility')  // → onReleased fires, stream resumes\n * ```\n */\nexport class PauseLock {\n  #holders = new Set<string>()\n  #onAcquired: () => void\n  #onReleased: () => void\n\n  constructor(callbacks: { onAcquired: () => void; onReleased: () => void }) {\n    this.#onAcquired = callbacks.onAcquired\n    this.#onReleased = callbacks.onReleased\n  }\n\n  /**\n   * Acquire the lock for a given reason. Idempotent — acquiring the same\n   * reason twice is a no-op (but logs a warning since it likely indicates\n   * a caller bug).\n   *\n   * Fires `onAcquired` when the first reason is acquired (transition from\n   * unlocked to locked).\n   */\n  acquire(reason: string): void {\n    if (this.#holders.has(reason)) {\n      console.warn(\n        `[Electric] PauseLock: \"${reason}\" already held — ignoring duplicate acquire`\n      )\n      return\n    }\n    const wasUnlocked = this.#holders.size === 0\n    this.#holders.add(reason)\n    if (wasUnlocked) {\n      this.#onAcquired()\n    }\n  }\n\n  /**\n   * Release the lock for a given reason. Releasing a reason that isn't\n   * held logs a warning (likely indicates an acquire/release mismatch).\n   *\n   * Fires `onReleased` when the last reason is released (transition from\n   * locked to unlocked).\n   */\n  release(reason: string): void {\n    if (!this.#holders.delete(reason)) {\n      console.warn(\n        `[Electric] PauseLock: \"${reason}\" not held — ignoring release (possible acquire/release mismatch)`\n      )\n      return\n    }\n    if (this.#holders.size === 0) {\n      this.#onReleased()\n    }\n  }\n\n  /**\n   * Whether the lock is currently held by any reason.\n   */\n  get isPaused(): boolean {\n    return this.#holders.size > 0\n  }\n\n  /**\n   * Check if a specific reason is holding the lock.\n   */\n  isHeldBy(reason: string): boolean {\n    return this.#holders.has(reason)\n  }\n\n  /**\n   * Release all reasons matching a prefix. Does NOT fire `onReleased` —\n   * this is for cleanup/reset paths where the stream state is being\n   * managed separately.\n   *\n   * This preserves reasons with different prefixes (e.g., 'visibility'\n   * is preserved when clearing 'snapshot-*' reasons).\n   */\n  releaseAllMatching(prefix: string): void {\n    for (const reason of this.#holders) {\n      if (reason.startsWith(prefix)) {\n        this.#holders.delete(reason)\n      }\n    }\n  }\n}\n","import {\n  Message,\n  Offset,\n  Schema,\n  Row,\n  MaybePromise,\n  GetExtensions,\n  ChangeMessage,\n  SnapshotMetadata,\n  SubsetParams,\n} from './types'\nimport { MessageParser, Parser, TransformFunction } from './parser'\nimport {\n  ColumnMapper,\n  encodeWhereClause,\n  quoteIdentifier,\n} from './column-mapper'\nimport {\n  getOffset,\n  isUpToDateMessage,\n  isChangeMessage,\n  bigintSafeStringify,\n} from './helpers'\nimport {\n  FetchError,\n  FetchBackoffAbortError,\n  MissingShapeUrlError,\n  InvalidSignalError,\n  MissingShapeHandleError,\n  ReservedParamError,\n  MissingHeadersError,\n  StaleCacheError,\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  SYSTEM_WAKE,\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  SUBSET_PARAM_WHERE_EXPR,\n  SUBSET_PARAM_ORDER_BY_EXPR,\n  CACHE_BUSTER_QUERY_PARAM,\n} from './constants'\nimport { compileExpression, compileOrderBy } from './expression-compiler'\nimport {\n  EventSourceMessage,\n  fetchEventSource,\n} from '@microsoft/fetch-event-source'\nimport { expiredShapesCache } from './expired-shapes-cache'\nimport { upToDateTracker } from './up-to-date-tracker'\nimport { SnapshotTracker } from './snapshot-tracker'\nimport {\n  createInitialState,\n  ErrorState,\n  PausedState,\n  ShapeStreamState,\n} from './shape-stream-state'\nimport { PauseLock } from './pause-lock'\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  CACHE_BUSTER_QUERY_PARAM,\n])\n\nconst TROUBLESHOOTING_URL = `https://electric-sql.com/docs/guides/troubleshooting`\n\nfunction createCacheBuster(): string {\n  return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`\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\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  | typeof CACHE_BUSTER_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\n  /**\n   * Function to transform rows after parsing (e.g., for encryption, type coercion).\n   * Applied to data received from Electric.\n   *\n   * **Note**: If you're using `transformer` solely for column name transformation\n   * (e.g., snake_case → camelCase), consider using `columnMapper` instead, which\n   * provides bidirectional transformation and automatically encodes WHERE clauses.\n   *\n   * **Execution order** when both are provided:\n   * 1. `columnMapper.decode` runs first (renames columns)\n   * 2. `transformer` runs second (transforms values)\n   *\n   * @example\n   * ```typescript\n   * // For column renaming only - use columnMapper\n   * import { snakeCamelMapper } from '@electric-sql/client'\n   * const stream = new ShapeStream({ columnMapper: snakeCamelMapper() })\n   * ```\n   *\n   * @example\n   * ```typescript\n   * // For value transformation (encryption, etc.) - use transformer\n   * const stream = new ShapeStream({\n   *   transformer: (row) => ({\n   *     ...row,\n   *     encrypted_field: decrypt(row.encrypted_field)\n   *   })\n   * })\n   * ```\n   *\n   * @example\n   * ```typescript\n   * // Use both together\n   * const stream = new ShapeStream({\n   *   columnMapper: snakeCamelMapper(), // Runs first: renames columns\n   *   transformer: (row) => ({         // Runs second: transforms values\n   *     ...row,\n   *     encryptedData: decrypt(row.encryptedData)\n   *   })\n   * })\n   * ```\n   */\n  transformer?: TransformFunction<T>\n\n  /**\n   * Bidirectional column name mapper for transforming between database column names\n   * (e.g., snake_case) and application column names (e.g., camelCase).\n   *\n   * The mapper handles both:\n   * - **Decoding**: Database → Application (applied to query results)\n   * - **Encoding**: Application → Database (applied to WHERE clauses)\n   *\n   * @example\n   * ```typescript\n   * // Most common case: snake_case ↔ camelCase\n   * import { snakeCamelMapper } from '@electric-sql/client'\n   *\n   * const stream = new ShapeStream({\n   *   url: 'http://localhost:3000/v1/shape',\n   *   params: { table: 'todos' },\n   *   columnMapper: snakeCamelMapper()\n   * })\n   * ```\n   *\n   * @example\n   * ```typescript\n   * // Custom mapping\n   * import { createColumnMapper } from '@electric-sql/client'\n   *\n   * const stream = new ShapeStream({\n   *   columnMapper: createColumnMapper({\n   *     user_id: 'userId',\n   *     project_id: 'projectId',\n   *     created_at: 'createdAt'\n   *   })\n   * })\n   * ```\n   */\n  columnMapper?: ColumnMapper\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  /**\n   * HTTP method to use for subset snapshot requests (`requestSnapshot`/`fetchSnapshot`).\n   *\n   * - `'GET'` (default): Sends subset params as URL query parameters. May fail with\n   *   HTTP 414 errors for large queries with many parameters.\n   * - `'POST'`: Sends subset params in request body as JSON. Recommended for queries\n   *   with large parameter lists (e.g., `WHERE id = ANY($1)` with hundreds of IDs).\n   *\n   * This can be overridden per-request by passing `method` in the subset params.\n   *\n   * @example\n   * ```typescript\n   * const stream = new ShapeStream({\n   *   url: 'http://localhost:3000/v1/shape',\n   *   params: { table: 'items' },\n   *   subsetMethod: 'POST', // Use POST for all subset requests\n   * })\n   * ```\n   */\n  subsetMethod?: `GET` | `POST`\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: SubsetParams): Promise<{\n    metadata: SnapshotMetadata\n    data: Array<Message<T>>\n  }>\n\n  fetchSnapshot(opts: SubsetParams): Promise<{\n    metadata: SnapshotMetadata\n    data: Array<ChangeMessage<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    object,\n    [\n      (messages: Message<T>[]) => MaybePromise<void>,\n      ((error: Error) => void) | undefined,\n    ]\n  >()\n\n  #started = false\n  #syncState: ShapeStreamState\n  #connected: boolean = false\n  #mode: LogMode\n  #onError?: ShapeStreamErrorHandler\n  #requestAbortController?: AbortController\n  #refreshCount = 0\n  #snapshotCounter = 0\n\n  get #isRefreshing(): boolean {\n    return this.#refreshCount > 0\n  }\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  #pauseLock: PauseLock\n  #currentFetchUrl?: URL // Current fetch URL for computing shape key\n  #lastSseConnectionStartTime?: number\n  #minSseConnectionDuration = 1000 // Minimum expected SSE connection duration (1 second)\n  #maxShortSseConnections = 3 // Fall back to long polling after this many short connections\n  #sseBackoffBaseDelay = 100 // Base delay for exponential backoff (ms)\n  #sseBackoffMaxDelay = 5000 // Maximum delay cap (ms)\n  #unsubscribeFromVisibilityChanges?: () => void\n  #unsubscribeFromWakeDetection?: () => void\n  #maxStaleCacheRetries = 3\n  // Fast-loop detection: track recent non-live requests to detect tight retry\n  // loops caused by proxy/CDN misconfiguration or stale client-side caches\n  #recentRequestEntries: Array<{ timestamp: number; offset: string }> = []\n  #fastLoopWindowMs = 500\n  #fastLoopThreshold = 5\n  #fastLoopBackoffBaseMs = 100\n  #fastLoopBackoffMaxMs = 5_000\n  #fastLoopConsecutiveCount = 0\n  #fastLoopMaxCount = 5\n  #pendingRequestShapeCacheBuster?: string\n  #maxSnapshotRetries = 5\n\n  constructor(options: ShapeStreamOptions<GetExtensions<T>>) {\n    this.options = { subscribe: true, ...options }\n    validateOptions(this.options)\n    this.#syncState = createInitialState({\n      offset: this.options.offset ?? `-1`,\n      handle: this.options.handle,\n    })\n\n    this.#pauseLock = new PauseLock({\n      onAcquired: () => {\n        this.#syncState = this.#syncState.pause()\n        if (this.#started) {\n          this.#requestAbortController?.abort(PAUSE_STREAM)\n        }\n      },\n      onReleased: () => {\n        if (!this.#started) return\n        if (this.options.signal?.aborted) return\n        // Don't transition syncState here — let #requestShape handle\n        // the PausedState→previous transition so it can detect\n        // resumingFromPause and avoid live long-polling.\n        this.#start().catch(() => {\n          // Errors from #start are handled internally via onError.\n          // This catch prevents unhandled promise rejection in Node/Bun.\n        })\n      },\n    })\n\n    // Build transformer chain: columnMapper.decode -> transformer\n    // columnMapper transforms column names, transformer transforms values\n    let transformer: TransformFunction<GetExtensions<T>> | undefined\n\n    if (options.columnMapper) {\n      const applyColumnMapper = (\n        row: Row<GetExtensions<T>>\n      ): Row<GetExtensions<T>> => {\n        const result: Record<string, unknown> = {}\n        for (const [dbKey, value] of Object.entries(row)) {\n          const appKey = options.columnMapper!.decode(dbKey)\n          result[appKey] = value\n        }\n        return result as Row<GetExtensions<T>>\n      }\n\n      transformer = options.transformer\n        ? (row: Row<GetExtensions<T>>) =>\n            options.transformer!(applyColumnMapper(row))\n        : applyColumnMapper\n    } else {\n      transformer = options.transformer\n    }\n\n    this.#messageParser = new MessageParser<T>(options.parser, 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.#syncState.handle\n  }\n\n  get error() {\n    return this.#error\n  }\n\n  get isUpToDate() {\n    return this.#syncState.isUpToDate\n  }\n\n  get lastOffset() {\n    return this.#syncState.offset\n  }\n\n  get mode() {\n    return this.#mode\n  }\n\n  async #start(): Promise<void> {\n    this.#started = true\n    this.#subscribeToWakeDetection()\n\n    try {\n      await this.#requestShape()\n    } catch (err) {\n      this.#error = err\n      if (err instanceof Error) {\n        this.#syncState = this.#syncState.toErrorState(err)\n      }\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        const isRetryable = !(err instanceof MissingHeadersError)\n        if (retryOpts && typeof retryOpts === `object` && isRetryable) {\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          if (this.#syncState instanceof ErrorState) {\n            this.#syncState = this.#syncState.retry()\n          }\n          this.#fastLoopConsecutiveCount = 0\n          this.#recentRequestEntries = []\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.#teardown()\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.#teardown()\n      throw err\n    }\n\n    this.#teardown()\n  }\n\n  #teardown() {\n    this.#connected = false\n    this.#tickPromiseRejecter?.()\n    this.#unsubscribeFromWakeDetection?.()\n  }\n\n  async #requestShape(requestShapeCacheBuster?: string): Promise<void> {\n    const activeCacheBuster =\n      requestShapeCacheBuster ?? this.#pendingRequestShapeCacheBuster\n\n    if (this.#pauseLock.isPaused) {\n      if (activeCacheBuster) {\n        this.#pendingRequestShapeCacheBuster = activeCacheBuster\n      }\n      return\n    }\n\n    if (\n      !this.options.subscribe &&\n      (this.options.signal?.aborted || this.#syncState.isUpToDate)\n    ) {\n      return\n    }\n\n    // Only check for fast loops on non-live requests; live polling is expected to be rapid\n    if (!this.#syncState.isUpToDate) {\n      await this.#checkFastLoop()\n    } else {\n      this.#fastLoopConsecutiveCount = 0\n      this.#recentRequestEntries = []\n    }\n\n    let resumingFromPause = false\n    if (this.#syncState instanceof PausedState) {\n      resumingFromPause = true\n      this.#syncState = this.#syncState.resume()\n    }\n\n    const { url, signal } = this.options\n    const { fetchUrl, requestHeaders } = await this.#constructUrl(\n      url,\n      resumingFromPause\n    )\n\n    if (activeCacheBuster) {\n      fetchUrl.searchParams.set(CACHE_BUSTER_QUERY_PARAM, activeCacheBuster)\n      fetchUrl.searchParams.sort()\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    // Re-check after async setup — the lock may have been acquired\n    // during URL construction or abort controller creation (e.g., by\n    // requestSnapshot), when the abort controller didn't exist yet.\n    if (this.#pauseLock.isPaused) {\n      if (abortListener && signal) {\n        signal.removeEventListener(`abort`, abortListener)\n      }\n      if (activeCacheBuster) {\n        this.#pendingRequestShapeCacheBuster = activeCacheBuster\n      }\n      this.#requestAbortController = undefined\n      return\n    }\n\n    this.#pendingRequestShapeCacheBuster = undefined\n\n    try {\n      await this.#fetchShape({\n        fetchUrl,\n        requestAbortController,\n        headers: requestHeaders,\n        resumingFromPause,\n      })\n    } catch (e) {\n      const abortReason = requestAbortController.signal.reason\n      const isRestartAbort =\n        requestAbortController.signal.aborted &&\n        (abortReason === FORCE_DISCONNECT_AND_REFRESH ||\n          abortReason === SYSTEM_WAKE)\n\n      if (\n        (e instanceof FetchError || e instanceof FetchBackoffAbortError) &&\n        isRestartAbort\n      ) {\n        return this.#requestShape()\n      }\n\n      if (e instanceof FetchBackoffAbortError) {\n        return // interrupted\n      }\n\n      if (e instanceof StaleCacheError) {\n        // Received a stale cached response from CDN with an expired handle.\n        // The #staleCacheBuster has been set in #onInitialResponse, so retry\n        // the request which will include a random cache buster to bypass the\n        // misconfigured CDN cache.\n        return this.#requestShape()\n      }\n\n      if (!(e instanceof FetchError)) throw e // should never happen\n\n      if (e.status == 409) {\n        // Upon receiving a 409, start from scratch with the newly\n        // provided shape handle. If the header is missing (e.g. proxy\n        // stripped it), reset without a handle and use a random\n        // cache-buster query param to ensure the retry URL is unique.\n\n        // Store the current shape URL as expired to avoid future 409s\n        if (this.#syncState.handle) {\n          const shapeKey = canonicalShapeKey(fetchUrl)\n          expiredShapesCache.markExpired(shapeKey, this.#syncState.handle)\n        }\n\n        const newShapeHandle = e.headers[SHAPE_HANDLE_HEADER]\n        let nextRequestShapeCacheBuster: string | undefined\n        if (!newShapeHandle) {\n          console.warn(\n            `[Electric] Received 409 response without a shape handle header. ` +\n              `This likely indicates a proxy or CDN stripping required headers.`,\n            new Error(`stack trace`)\n          )\n          nextRequestShapeCacheBuster = createCacheBuster()\n        }\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. The body may\n        // also be null/undefined if a proxy returned an unexpected response.\n        // Handle all cases defensively here.\n        const messages409 = Array.isArray(e.json)\n          ? e.json\n          : e.json != null\n            ? [e.json]\n            : []\n        await this.#publish(messages409 as Message<T>[])\n        return this.#requestShape(nextRequestShapeCacheBuster)\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  /**\n   * Detects tight retry loops (e.g., from stale client-side caches or\n   * proxy/CDN misconfiguration) and attempts recovery. On first detection,\n   * clears client-side caches (in-memory and localStorage) and resets the\n   * stream to fetch from scratch.\n   * If the loop persists, applies exponential backoff and eventually throws.\n   */\n  async #checkFastLoop(): Promise<void> {\n    const now = Date.now()\n    const currentOffset = this.#syncState.offset\n\n    this.#recentRequestEntries = this.#recentRequestEntries.filter(\n      (e) => now - e.timestamp < this.#fastLoopWindowMs\n    )\n    this.#recentRequestEntries.push({ timestamp: now, offset: currentOffset })\n\n    // Only flag as a fast loop if requests are stuck at the same offset.\n    // Normal rapid syncing advances the offset with each response.\n    const sameOffsetCount = this.#recentRequestEntries.filter(\n      (e) => e.offset === currentOffset\n    ).length\n\n    if (sameOffsetCount < this.#fastLoopThreshold) return\n\n    this.#fastLoopConsecutiveCount++\n\n    if (this.#fastLoopConsecutiveCount >= this.#fastLoopMaxCount) {\n      throw new FetchError(\n        502,\n        undefined,\n        undefined,\n        {},\n        this.options.url,\n        `Client is stuck in a fast retry loop ` +\n          `(${this.#fastLoopThreshold} requests in ${this.#fastLoopWindowMs}ms at the same offset, ` +\n          `repeated ${this.#fastLoopMaxCount} times). ` +\n          `Client-side caches were cleared automatically on first detection, but the loop persists. ` +\n          `This usually indicates a proxy or CDN misconfiguration. ` +\n          `Common causes:\\n` +\n          `  - Proxy is not including query parameters (handle, offset) in its cache key\\n` +\n          `  - CDN is serving stale 409 responses\\n` +\n          `  - Proxy is stripping required Electric headers from responses\\n` +\n          `For more information visit the troubleshooting guide: ${TROUBLESHOOTING_URL}`\n      )\n    }\n\n    if (this.#fastLoopConsecutiveCount === 1) {\n      console.warn(\n        `[Electric] Detected fast retry loop ` +\n          `(${this.#fastLoopThreshold} requests in ${this.#fastLoopWindowMs}ms at the same offset). ` +\n          `Clearing client-side caches and resetting stream to recover. ` +\n          `If this persists, check that your proxy includes all query parameters ` +\n          `(especially 'handle' and 'offset') in its cache key, ` +\n          `and that required Electric headers are forwarded to the client. ` +\n          `For more information visit the troubleshooting guide: ${TROUBLESHOOTING_URL}`,\n        new Error(`stack trace`)\n      )\n\n      if (this.#currentFetchUrl) {\n        const shapeKey = canonicalShapeKey(this.#currentFetchUrl)\n        expiredShapesCache.delete(shapeKey)\n        upToDateTracker.delete(shapeKey)\n      } else {\n        expiredShapesCache.clear()\n        upToDateTracker.clear()\n      }\n      this.#reset()\n      this.#recentRequestEntries = []\n      return\n    }\n\n    // Exponential backoff with full jitter\n    const maxDelay = Math.min(\n      this.#fastLoopBackoffMaxMs,\n      this.#fastLoopBackoffBaseMs * Math.pow(2, this.#fastLoopConsecutiveCount)\n    )\n    const delayMs = Math.floor(Math.random() * maxDelay)\n\n    await new Promise((resolve) => setTimeout(resolve, delayMs))\n\n    this.#recentRequestEntries = []\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 && typeof params.where === `string`) {\n        const encodedWhere = encodeWhereClause(\n          params.where,\n          this.options.columnMapper?.encode\n        )\n        setQueryParam(fetchUrl, WHERE_QUERY_PARAM, encodedWhere)\n      }\n      if (params.columns) {\n        // Get original columns array from options (before toInternalParams converted to string)\n        const originalColumns = await resolveValue(this.options.params?.columns)\n        if (Array.isArray(originalColumns)) {\n          // Apply columnMapper encoding if present\n          let encodedColumns = originalColumns.map(String)\n          if (this.options.columnMapper) {\n            encodedColumns = encodedColumns.map(\n              this.options.columnMapper.encode\n            )\n          }\n          // Quote each column name to handle special characters (commas, etc.)\n          const serializedColumns = encodedColumns\n            .map(quoteIdentifier)\n            .join(`,`)\n          setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, serializedColumns)\n        } else {\n          // Fallback: columns was already a string\n          setQueryParam(fetchUrl, COLUMNS_QUERY_PARAM, params.columns)\n        }\n      }\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      // Prefer structured expressions when available (allows proper columnMapper application)\n      // Fall back to legacy string format for backwards compatibility\n      if (subsetParams.whereExpr) {\n        // Compile structured expression with columnMapper applied\n        const compiledWhere = compileExpression(\n          subsetParams.whereExpr,\n          this.options.columnMapper?.encode\n        )\n        setQueryParam(fetchUrl, SUBSET_PARAM_WHERE, compiledWhere)\n        // Also send the structured expression for servers that support it\n        fetchUrl.searchParams.set(\n          SUBSET_PARAM_WHERE_EXPR,\n          JSON.stringify(subsetParams.whereExpr)\n        )\n      } else if (subsetParams.where && typeof subsetParams.where === `string`) {\n        // Legacy string format (no columnMapper applied to already-compiled SQL)\n        const encodedWhere = encodeWhereClause(\n          subsetParams.where,\n          this.options.columnMapper?.encode\n        )\n        setQueryParam(fetchUrl, SUBSET_PARAM_WHERE, encodedWhere)\n      }\n\n      if (subsetParams.params)\n        // Serialize params as JSON to keep the parameter name constant for proxy configs\n        fetchUrl.searchParams.set(\n          SUBSET_PARAM_WHERE_PARAMS,\n          bigintSafeStringify(subsetParams.params)\n        )\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\n      // Prefer structured ORDER BY expressions when available\n      if (subsetParams.orderByExpr) {\n        // Compile structured ORDER BY with columnMapper applied\n        const compiledOrderBy = compileOrderBy(\n          subsetParams.orderByExpr,\n          this.options.columnMapper?.encode\n        )\n        setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, compiledOrderBy)\n        // Also send the structured expression for servers that support it\n        fetchUrl.searchParams.set(\n          SUBSET_PARAM_ORDER_BY_EXPR,\n          JSON.stringify(subsetParams.orderByExpr)\n        )\n      } else if (\n        subsetParams.orderBy &&\n        typeof subsetParams.orderBy === `string`\n      ) {\n        // Legacy string format\n        const encodedOrderBy = encodeWhereClause(\n          subsetParams.orderBy,\n          this.options.columnMapper?.encode\n        )\n        setQueryParam(fetchUrl, SUBSET_PARAM_ORDER_BY, encodedOrderBy)\n      }\n    }\n\n    // Add state-specific parameters (offset, handle, live cache busters, etc.)\n    this.#syncState.applyUrlParams(fetchUrl, {\n      isSnapshotRequest: subsetParams !== undefined,\n      // Don't long-poll when resuming from pause or refreshing — avoids\n      // a 20s hold during which `isConnected` would be false\n      canLongPoll: !this.#isRefreshing && !resumingFromPause,\n    })\n    fetchUrl.searchParams.set(LOG_MODE_QUERY_PARAM, this.#mode)\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  /**\n   * Processes response metadata (headers, status) and updates sync state.\n   * Returns `true` if the response body should be processed by the caller,\n   * or `false` if the response was ignored (stale) and the body should be skipped.\n   * Throws on stale-retry (to trigger a retry with cache buster).\n   */\n  async #onInitialResponse(response: Response): Promise<boolean> {\n    const { headers, status } = response\n    const shapeHandle = headers.get(SHAPE_HANDLE_HEADER)\n    const shapeKey = this.#currentFetchUrl\n      ? canonicalShapeKey(this.#currentFetchUrl)\n      : null\n    const expiredHandle = shapeKey\n      ? expiredShapesCache.getExpiredHandle(shapeKey)\n      : null\n\n    const transition = this.#syncState.handleResponseMetadata({\n      status,\n      responseHandle: shapeHandle,\n      responseOffset: headers.get(CHUNK_LAST_OFFSET_HEADER) as Offset | null,\n      responseCursor: headers.get(LIVE_CACHE_BUSTER_HEADER),\n      responseSchema: getSchemaFromHeaders(headers),\n      expiredHandle,\n      now: Date.now(),\n      maxStaleCacheRetries: this.#maxStaleCacheRetries,\n      createCacheBuster,\n    })\n\n    this.#syncState = transition.state\n\n    if (transition.action === `stale-retry`) {\n      // Cancel the response body to release the connection before retrying.\n      await response.body?.cancel()\n      if (transition.exceededMaxRetries) {\n        throw new FetchError(\n          502,\n          undefined,\n          undefined,\n          {},\n          this.#currentFetchUrl?.toString() ?? ``,\n          `CDN continues serving stale cached responses after ${this.#maxStaleCacheRetries} retry attempts. ` +\n            `This indicates a severe proxy/CDN misconfiguration. ` +\n            `Check that your proxy includes all query parameters (especially 'handle' and 'offset') in its cache key. ` +\n            `For more information visit the troubleshooting guide: ${TROUBLESHOOTING_URL}`\n        )\n      }\n      console.warn(\n        `[Electric] Received stale cached response with expired shape handle. ` +\n          `This should not happen and indicates a proxy/CDN caching misconfiguration. ` +\n          `The response contained handle \"${shapeHandle}\" which was previously marked as expired. ` +\n          `Check that your proxy includes all query parameters (especially 'handle' and 'offset') in its cache key. ` +\n          `For more information visit the troubleshooting guide: ${TROUBLESHOOTING_URL} ` +\n          `Retrying with a random cache buster to bypass the stale cache (attempt ${this.#syncState.staleCacheRetryCount}/${this.#maxStaleCacheRetries}).`,\n        new Error(`stack trace`)\n      )\n      throw new StaleCacheError(\n        `Received stale cached response with expired handle \"${shapeHandle}\". ` +\n          `This indicates a proxy/CDN caching misconfiguration. ` +\n          `Check that your proxy includes all query parameters (especially 'handle' and 'offset') in its cache key.`\n      )\n    }\n\n    if (transition.action === `ignored`) {\n      console.warn(\n        `[Electric] Response was ignored by state \"${this.#syncState.kind}\". ` +\n          `The response body will be skipped. ` +\n          `This may indicate a proxy/CDN caching issue or a client state machine bug.`,\n        new Error(`stack trace`)\n      )\n      return false\n    }\n\n    return true\n  }\n\n  async #onMessages(batch: Array<Message<T>>, isSseMessage = false) {\n    if (!Array.isArray(batch)) {\n      console.warn(\n        `[Electric] #onMessages called with non-array argument (${typeof batch}). ` +\n          `This is a client bug — please report it.`,\n        new Error(`stack trace`)\n      )\n      return\n    }\n    if (batch.length === 0) return\n\n    const lastMessage = batch[batch.length - 1]\n    const hasUpToDateMessage = isUpToDateMessage(lastMessage)\n    const upToDateOffset = hasUpToDateMessage\n      ? getOffset(lastMessage)\n      : undefined\n\n    const transition = this.#syncState.handleMessageBatch({\n      hasMessages: true,\n      hasUpToDateMessage,\n      isSse: isSseMessage,\n      upToDateOffset,\n      now: Date.now(),\n      currentCursor: this.#syncState.liveCacheBuster,\n    })\n    this.#syncState = transition.state\n\n    if (hasUpToDateMessage) {\n      if (transition.suppressBatch) {\n        return\n      }\n\n      if (this.#currentFetchUrl) {\n        const shapeKey = canonicalShapeKey(this.#currentFetchUrl)\n        upToDateTracker.recordUpToDate(\n          shapeKey,\n          this.#syncState.liveCacheBuster\n        )\n      }\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   * Fetches the shape from the server using either long polling or SSE.\n   * Upon receiving a successful 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    // Store current fetch URL for shape key computation\n    this.#currentFetchUrl = opts.fetchUrl\n\n    // Check if we should enter replay mode (replaying cached responses)\n    // This happens when we're starting fresh (offset=-1 or before first up-to-date)\n    // and there's a recent up-to-date in localStorage (< 60s)\n    if (!this.#syncState.isUpToDate && this.#syncState.canEnterReplayMode()) {\n      const shapeKey = canonicalShapeKey(opts.fetchUrl)\n      const lastSeenCursor = upToDateTracker.shouldEnterReplayMode(shapeKey)\n      if (lastSeenCursor) {\n        // Enter replay mode and store the last seen cursor\n        this.#syncState = this.#syncState.enterReplayMode(lastSeenCursor)\n      }\n    }\n\n    const useSse = this.options.liveSse ?? this.options.experimentalLiveSse\n    if (\n      this.#syncState.shouldUseSse({\n        liveSseEnabled: !!useSse,\n        isRefreshing: this.#isRefreshing,\n        resumingFromPause: !!opts.resumingFromPause,\n      })\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    const shouldProcessBody = await this.#onInitialResponse(response)\n    if (!shouldProcessBody) return\n\n    const schema = this.#syncState.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    if (!Array.isArray(batch)) {\n      const preview = bigintSafeStringify(batch)?.slice(0, 200)\n      throw new FetchError(\n        response.status,\n        `Received non-array response body from shape endpoint. ` +\n          `This may indicate a proxy or CDN is returning an unexpected response. ` +\n          `Expected a JSON array, got ${typeof batch}: ${preview}`,\n        undefined,\n        Object.fromEntries(response.headers.entries()),\n        fetchUrl.toString()\n      )\n    }\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    // Add Accept header for SSE requests\n    const sseHeaders = {\n      ...headers,\n      Accept: `text/event-stream`,\n    }\n\n    let ignoredStaleResponse = false\n    try {\n      let buffer: Array<Message<T>> = []\n      await fetchEventSource(fetchUrl.toString(), {\n        headers: sseHeaders,\n        fetch,\n        onopen: async (response: Response) => {\n          this.#connected = true\n          const shouldProcessBody = await this.#onInitialResponse(response)\n          if (!shouldProcessBody) {\n            ignoredStaleResponse = true\n            throw new Error(`stale response ignored`)\n          }\n        },\n        onmessage: (event: EventSourceMessage) => {\n          if (event.data) {\n            // event.data is a single JSON object\n            const schema = this.#syncState.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 (ignoredStaleResponse) {\n        // Stale response was ignored in onopen — let the fetch loop retry\n        return\n      }\n      if (requestAbortController.signal.aborted) {\n        // An abort during SSE stream parsing produces a raw AbortError\n        // instead of going through createFetchWithBackoff -- wrap it so\n        // #start handles it correctly.\n        throw new FetchBackoffAbortError()\n      }\n      // Re-throw known Electric errors so the caller can handle them\n      // (e.g., 409 shape rotation, stale cache retry, missing headers).\n      // Other errors (body parsing, SSE protocol failures, null body)\n      // are SSE connection failures handled by the fallback mechanism\n      // in the finally block below.\n      if (\n        error instanceof FetchError ||\n        error instanceof StaleCacheError ||\n        error instanceof MissingHeadersError\n      ) {\n        throw error\n      }\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      const transition = this.#syncState.handleSseConnectionClosed({\n        connectionDuration,\n        wasAborted,\n        minConnectionDuration: this.#minSseConnectionDuration,\n        maxShortConnections: this.#maxShortSseConnections,\n      })\n      this.#syncState = transition.state\n\n      if (transition.fellBackToLongPolling) {\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          new Error(`stack trace`)\n        )\n      } else if (transition.wasShortConnection) {\n        // Exponential backoff with full jitter: random(0, min(cap, base * 2^attempt))\n        const maxDelay = Math.min(\n          this.#sseBackoffMaxDelay,\n          this.#sseBackoffBaseDelay *\n            Math.pow(2, this.#syncState.consecutiveShortSseConnections)\n        )\n        const delayMs = Math.floor(Math.random() * maxDelay)\n        await new Promise((resolve) => setTimeout(resolve, delayMs))\n      }\n    }\n  }\n\n  subscribe(\n    callback: (messages: Message<T>[]) => MaybePromise<void>,\n    onError: (error: Error) => void = () => {}\n  ) {\n    const subscriptionId = {}\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    this.#unsubscribeFromVisibilityChanges?.()\n    this.#unsubscribeFromWakeDetection?.()\n  }\n\n  /** Unix time at which we last synced. Undefined until first successful up-to-date. */\n  lastSyncedAt(): number | undefined {\n    return this.#syncState.lastSyncedAt\n  }\n\n  /** Time elapsed since last sync (in ms). Infinity if we did not yet sync. */\n  lastSynced(): number {\n    if (this.#syncState.lastSyncedAt === undefined) return Infinity\n    return Date.now() - this.#syncState.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 afterwards.  */\n  isLoading(): boolean {\n    return !this.#syncState.isUpToDate\n  }\n\n  hasStarted(): boolean {\n    return this.#started\n  }\n\n  isPaused(): boolean {\n    return this.#pauseLock.isPaused\n  }\n\n  /** Await the next tick of the request loop */\n  async #nextTick() {\n    if (this.#pauseLock.isPaused) {\n      throw new Error(\n        `Cannot wait for next tick while PauseLock is held — this would deadlock because the request loop is paused`\n      )\n    }\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  /**\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.#refreshCount++\n    try {\n      if (\n        this.#syncState.isUpToDate &&\n        !this.#requestAbortController?.signal.aborted\n      ) {\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    } finally {\n      this.#refreshCount--\n    }\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  #hasBrowserVisibilityAPI(): boolean {\n    return (\n      typeof document === `object` &&\n      typeof document.hidden === `boolean` &&\n      typeof document.addEventListener === `function`\n    )\n  }\n\n  #subscribeToVisibilityChanges() {\n    if (this.#hasBrowserVisibilityAPI()) {\n      const visibilityHandler = () => {\n        if (document.hidden) {\n          this.#pauseLock.acquire(`visibility`)\n        } else {\n          this.#pauseLock.release(`visibility`)\n        }\n      }\n\n      document.addEventListener(`visibilitychange`, visibilityHandler)\n\n      // Store cleanup function to remove the event listener\n      this.#unsubscribeFromVisibilityChanges = () => {\n        document.removeEventListener(`visibilitychange`, visibilityHandler)\n        this.#unsubscribeFromVisibilityChanges = undefined\n      }\n    }\n  }\n\n  /**\n   * Detects system wake from sleep using timer gap detection.\n   * When the system sleeps, setInterval timers are paused. On wake,\n   * the elapsed wall-clock time since the last tick will be much larger\n   * than the interval period, indicating the system was asleep.\n   *\n   * Only active in non-browser environments (Bun, Node.js) where\n   * `document.visibilitychange` is not available. In browsers,\n   * `#subscribeToVisibilityChanges` handles this instead. Without wake\n   * detection, in-flight HTTP requests (long-poll or SSE) may hang until\n   * the OS TCP timeout.\n   */\n  #subscribeToWakeDetection() {\n    if (this.#hasBrowserVisibilityAPI()) return\n    if (this.#unsubscribeFromWakeDetection) return\n\n    const INTERVAL_MS = 2_000\n    const WAKE_THRESHOLD_MS = 4_000\n\n    let lastTickTime = Date.now()\n\n    const timer = setInterval(() => {\n      const now = Date.now()\n      const elapsed = now - lastTickTime\n      lastTickTime = now\n\n      if (elapsed > INTERVAL_MS + WAKE_THRESHOLD_MS) {\n        if (!this.#pauseLock.isPaused && this.#requestAbortController) {\n          this.#refreshCount++\n          this.#requestAbortController.abort(SYSTEM_WAKE)\n          // Wake handler is synchronous (setInterval callback) so we can't\n          // use try/finally + await like forceDisconnectAndRefresh. Instead,\n          // decrement via queueMicrotask — safe because the abort triggers\n          // #requestShape to re-run, which reads #isRefreshing synchronously\n          // before the microtask fires.\n          queueMicrotask(() => {\n            this.#refreshCount--\n          })\n        }\n      }\n    }, INTERVAL_MS)\n\n    // Ensure the timer doesn't prevent the process from exiting\n    if (typeof timer === `object` && `unref` in timer) {\n      timer.unref()\n    }\n\n    this.#unsubscribeFromWakeDetection = () => {\n      clearInterval(timer)\n      this.#unsubscribeFromWakeDetection = undefined\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.#syncState = this.#syncState.markMustRefetch(handle)\n    this.#connected = false\n    // releaseAllMatching intentionally doesn't fire onReleased — it's called\n    // from within the running stream loop (#requestShape's 409 handler), so\n    // the stream is already active and doesn't need a resume signal.\n    this.#pauseLock.releaseAllMatching(`snapshot`)\n  }\n\n  /**\n   * Request a snapshot for subset of data and inject it into the subscribed data stream.\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    // Start the stream if not started — fire-and-forget like subscribe() does.\n    // We must NOT await #start() because it runs the full request loop. The\n    // PauseLock acquire below will abort the in-flight request, and the\n    // re-check guard in #requestShape handles the race.\n    if (!this.#started) {\n      this.#start().catch(() => {})\n    }\n\n    const snapshotReason = `snapshot-${++this.#snapshotCounter}`\n\n    this.#pauseLock.acquire(snapshotReason)\n\n    // Warn if the snapshot holds the pause lock for too long — this likely\n    // indicates a hung fetch or leaked lock. Visibility pauses are\n    // intentionally long-lived so the warning lives here, not in PauseLock.\n    const snapshotWarnTimer = setTimeout(() => {\n      console.warn(\n        `[Electric] Snapshot \"${snapshotReason}\" has held the pause lock for 30s — ` +\n          `possible hung request or leaked lock. ` +\n          `Current holders: ${[...new Set([snapshotReason])].join(`, `)}`,\n        new Error(`stack trace`)\n      )\n    }, 30_000)\n\n    try {\n      const { metadata, data, responseOffset, responseHandle } =\n        await this.fetchSnapshot(opts)\n\n      const dataWithEndBoundary = (data as Array<Message<T>>).concat([\n        { headers: { control: `snapshot-end`, ...metadata } },\n        { headers: { control: `subset-end`, ...opts } },\n      ])\n\n      this.#snapshotTracker.addSnapshot(\n        metadata,\n        new Set(data.map((message) => message.key))\n      )\n      this.#onMessages(dataWithEndBoundary, false)\n\n      // On cold start the stream's offset is still at \"now\". Advance it\n      // to the snapshot's position so no updates are missed in between.\n      if (responseOffset !== null || responseHandle !== null) {\n        const transition = this.#syncState.handleResponseMetadata({\n          status: 200,\n          responseHandle,\n          responseOffset,\n          responseCursor: null,\n          expiredHandle: null,\n          now: Date.now(),\n          maxStaleCacheRetries: this.#maxStaleCacheRetries,\n          createCacheBuster,\n        })\n        if (transition.action === `accepted`) {\n          this.#syncState = transition.state\n        } else {\n          console.warn(\n            `[Electric] Snapshot response metadata was not accepted ` +\n              `by state \"${this.#syncState.kind}\" (action: ${transition.action}). ` +\n              `Stream offset was not advanced from snapshot.`,\n            new Error(`stack trace`)\n          )\n        }\n      }\n\n      return {\n        metadata,\n        data,\n      }\n    } finally {\n      clearTimeout(snapshotWarnTimer)\n      this.#pauseLock.release(snapshotReason)\n    }\n  }\n\n  /**\n   * Fetch a snapshot for subset of data.\n   * Returns the metadata and the data, but does not inject it into the subscribed data stream.\n   *\n   * By default, uses GET to send subset parameters as query parameters. This may hit URL length\n   * limits (HTTP 414) with large WHERE clauses or many parameters. Set `method: 'POST'` or use\n   * `subsetMethod: 'POST'` on the stream to send parameters in the request body instead.\n   *\n   * @param opts - The options for the snapshot request.\n   * @returns The metadata, data, and the response's offset/handle for state advancement.\n   */\n  async fetchSnapshot(opts: SubsetParams): Promise<{\n    metadata: SnapshotMetadata\n    data: Array<ChangeMessage<T>>\n    responseOffset: Offset | null\n    responseHandle: string | null\n  }> {\n    return this.#fetchSnapshotWithRetry(opts, 0)\n  }\n\n  async #fetchSnapshotWithRetry(\n    opts: SubsetParams,\n    retryCount: number,\n    cacheBuster?: string\n  ): Promise<{\n    metadata: SnapshotMetadata\n    data: Array<ChangeMessage<T>>\n    responseOffset: Offset | null\n    responseHandle: string | null\n  }> {\n    const method = opts.method ?? this.options.subsetMethod ?? `GET`\n    const usePost = method === `POST`\n\n    let fetchUrl: URL\n    let fetchOptions: RequestInit\n\n    if (usePost) {\n      const result = await this.#constructUrl(this.options.url, true)\n      fetchUrl = result.fetchUrl\n      fetchOptions = {\n        method: `POST`,\n        headers: {\n          ...result.requestHeaders,\n          'Content-Type': `application/json`,\n        },\n        body: bigintSafeStringify(this.#buildSubsetBody(opts)),\n      }\n    } else {\n      const result = await this.#constructUrl(this.options.url, true, opts)\n      fetchUrl = result.fetchUrl\n      fetchOptions = { headers: result.requestHeaders }\n    }\n\n    // Apply cache buster from same-handle 409 retry\n    if (cacheBuster) {\n      fetchUrl.searchParams.set(CACHE_BUSTER_QUERY_PARAM, cacheBuster)\n      fetchUrl.searchParams.sort()\n    }\n\n    // Capture handle before fetch to avoid race conditions if it changes during the request\n    const usedHandle = this.#syncState.handle\n\n    let response: Response\n    try {\n      response = await this.#fetchClient(fetchUrl.toString(), fetchOptions)\n    } catch (e) {\n      // Handle 409 \"must-refetch\" - shape handle changed/expired.\n      // The fetch wrapper throws FetchError for non-OK responses, so we catch here.\n      // Unlike #requestShape, we don't call #reset() here as that would\n      // clear the pause lock and break requestSnapshot's pause/resume logic.\n      if (e instanceof FetchError && e.status === 409) {\n        const nextRetryCount = retryCount + 1\n        if (nextRetryCount > this.#maxSnapshotRetries) {\n          throw new FetchError(\n            502,\n            undefined,\n            undefined,\n            {},\n            fetchUrl.toString(),\n            `Snapshot request stuck in 409 retry loop after ${this.#maxSnapshotRetries} attempts. ` +\n              `This indicates a proxy/CDN misconfiguration. ` +\n              `For more information visit the troubleshooting guide: ${TROUBLESHOOTING_URL}`\n          )\n        }\n\n        if (usedHandle) {\n          const shapeKey = canonicalShapeKey(fetchUrl)\n          expiredShapesCache.markExpired(shapeKey, usedHandle)\n        }\n\n        // For snapshot 409s, only update the handle — don't reset offset/schema/etc.\n        // The main stream is paused and should not be disturbed.\n        const nextHandle = e.headers[SHAPE_HANDLE_HEADER]\n        let nextCacheBuster: string | undefined\n        if (nextHandle) {\n          this.#syncState = this.#syncState.withHandle(nextHandle)\n          // If 409 returned the same handle, the URL won't change —\n          // pass a cache buster to the next retry to force a unique URL.\n          if (nextHandle === usedHandle) {\n            nextCacheBuster = createCacheBuster()\n          }\n        } else {\n          console.warn(\n            `[Electric] Received 409 response without a shape handle header. ` +\n              `This likely indicates a proxy or CDN stripping required headers.`,\n            new Error(`stack trace`)\n          )\n          nextCacheBuster = createCacheBuster()\n        }\n\n        return this.#fetchSnapshotWithRetry(\n          opts,\n          nextRetryCount,\n          nextCacheBuster\n        )\n      }\n      throw e\n    }\n\n    // Handle non-OK responses from custom fetch clients that bypass the wrapper chain\n    if (!response.ok) {\n      throw await FetchError.fromResponse(response, fetchUrl.toString())\n    }\n\n    const schema: Schema =\n      this.#syncState.schema ??\n      getSchemaFromHeaders(response.headers, {\n        required: true,\n        url: fetchUrl.toString(),\n      })\n\n    const { metadata, data: rawData } = await response.json()\n    const data = this.#messageParser.parseSnapshotData<ChangeMessage<T>>(\n      rawData,\n      schema\n    )\n\n    const responseOffset =\n      (response.headers.get(CHUNK_LAST_OFFSET_HEADER) as Offset) || null\n    const responseHandle = response.headers.get(SHAPE_HANDLE_HEADER)\n\n    return { metadata, data, responseOffset, responseHandle }\n  }\n\n  #buildSubsetBody(opts: SubsetParams): Record<string, unknown> {\n    const body: Record<string, unknown> = {}\n\n    if (opts.whereExpr) {\n      body.where = compileExpression(\n        opts.whereExpr,\n        this.options.columnMapper?.encode\n      )\n      body.where_expr = opts.whereExpr\n    } else if (opts.where && typeof opts.where === `string`) {\n      body.where = encodeWhereClause(\n        opts.where,\n        this.options.columnMapper?.encode\n      )\n    }\n\n    if (opts.params) {\n      body.params = opts.params\n    }\n\n    if (opts.limit !== undefined) {\n      body.limit = opts.limit\n    }\n\n    if (opts.offset !== undefined) {\n      body.offset = opts.offset\n    }\n\n    if (opts.orderByExpr) {\n      body.order_by = compileOrderBy(\n        opts.orderByExpr,\n        this.options.columnMapper?.encode\n      )\n      body.order_by_expr = opts.orderByExpr\n    } else if (opts.orderBy && typeof opts.orderBy === `string`) {\n      body.order_by = encodeWhereClause(\n        opts.orderBy,\n        this.options.columnMapper?.encode\n      )\n    }\n\n    return body\n  }\n}\n\n/**\n * Extracts the schema from response headers.\n * @param headers - The response headers\n * @param options - Options for schema extraction\n * @param options.required - If true, throws MissingHeadersError when header is missing. Defaults to false.\n * @param options.url - The URL to include in the error message if required is true\n * @returns The parsed schema, or an empty object if not required and header is missing\n * @throws {MissingHeadersError} if required is true and the header is missing\n */\nfunction getSchemaFromHeaders(\n  headers: Headers,\n  options?: { required?: boolean; url?: string }\n): Schema {\n  const schemaHeader = headers.get(SHAPE_SCHEMA_HEADER)\n  if (!schemaHeader) {\n    if (options?.required && options?.url) {\n      throw new MissingHeadersError(options.url, [SHAPE_SCHEMA_HEADER])\n    }\n    return {}\n  }\n  return JSON.parse(schemaHeader)\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","import { Message, Offset, Row } from './types'\nimport {\n  isChangeMessage,\n  isControlMessage,\n  bigintSafeStringify,\n} 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<object, 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 = bigintSafeStringify(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 = {}\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":["FetchError","_FetchError","status","text","json","headers","url","message","response","contentType","FetchBackoffAbortError","MissingShapeUrlError","InvalidSignalError","MissingShapeHandleError","ReservedParamError","reservedParams","ParserNullValueError","columnName","MissingHeadersError","url","missingHeaders","msg","h","StaleCacheError","message","parseNumber","value","parseBool","parseBigInt","parseJson","identityParser","v","defaultParser","pgArrayParser","parser","i","char","str","quoted","last","p","extractValue","x","start","end","val","loop","xs","MessageParser","transformer","__spreadValues","messages","schema","key","message","msg","row","_b","columnInfo","_a","typ","dimensions","additionalInfo","__objRest","typeParser","makeNullableParser","_","columnName","isNullable","ParserNullValueError","quoteIdentifier","identifier","snakeToCamel","str","_a","_b","_c","_d","leadingUnderscores","withoutLeading","trailingUnderscores","camelCased","_","letter","camelToSnake","createColumnMapper","mapping","reverseMapping","dbName","appName","dbColumnName","appColumnName","encodeWhereClause","whereClause","encode","sqlKeywords","quotedRanges","pos","ch","start","quoteChar","isInQuotedString","range","identifierPattern","match","_p1","offset","snakeCamelMapper","schema","dbColumn","isChangeMessage","message","isControlMessage","isUpToDateMessage","getOffset","lsn","bigintReplacer","_key","value","bigintSafeStringify","isVisibleInSnapshot","txid","snapshot","xid","xmin","xmax","xip","LIVE_CACHE_BUSTER_HEADER","SHAPE_HANDLE_HEADER","CHUNK_LAST_OFFSET_HEADER","SHAPE_SCHEMA_HEADER","CHUNK_UP_TO_DATE_HEADER","COLUMNS_QUERY_PARAM","LIVE_CACHE_BUSTER_QUERY_PARAM","EXPIRED_HANDLE_QUERY_PARAM","SHAPE_HANDLE_QUERY_PARAM","LIVE_QUERY_PARAM","OFFSET_QUERY_PARAM","TABLE_QUERY_PARAM","WHERE_QUERY_PARAM","REPLICA_PARAM","WHERE_PARAMS_PARAM","EXPERIMENTAL_LIVE_SSE_QUERY_PARAM","LIVE_SSE_QUERY_PARAM","FORCE_DISCONNECT_AND_REFRESH","PAUSE_STREAM","SYSTEM_WAKE","LOG_MODE_QUERY_PARAM","SUBSET_PARAM_WHERE","SUBSET_PARAM_LIMIT","SUBSET_PARAM_OFFSET","SUBSET_PARAM_ORDER_BY","SUBSET_PARAM_WHERE_PARAMS","SUBSET_PARAM_WHERE_EXPR","SUBSET_PARAM_ORDER_BY_EXPR","CACHE_BUSTER_QUERY_PARAM","ELECTRIC_PROTOCOL_QUERY_PARAMS","HTTP_RETRY_STATUS_CODES","BackoffDefaults","parseRetryAfterHeader","retryAfter","retryAfterSec","retryDate","deltaMs","createFetchWithBackoff","fetchClient","backoffOptions","initialDelay","maxDelay","multiplier","debug","onFailedAttempt","maxRetries","args","_a","url","options","delay","attempt","result","FetchError","e","FetchBackoffAbortError","serverMinimumMs","jitter","clientBackoffMs","waitMs","source","resolve","NO_BODY_STATUS_CODES","createFetchWithConsumedMessages","_b","res","text","err","ChunkPrefetchDefaults","createFetchWithChunkBuffer","prefetchOptions","maxChunksToPrefetch","prefetchQueue","getRequestMethod","prefetchedRequest","response","nextUrl","getNextChunkUrl","PrefetchQueue","requiredElectricResponseHeaders","CHUNK_LAST_OFFSET_HEADER","SHAPE_HANDLE_HEADER","requiredLiveResponseHeaders","LIVE_CACHE_BUSTER_HEADER","requiredNonLiveResponseHeaders","SHAPE_SCHEMA_HEADER","createFetchWithResponseHeadersCheck","headers","missingHeaders","addMissingHeaders","requiredHeaders","h","urlString","SUBSET_PARAM_WHERE","SUBSET_PARAM_WHERE_PARAMS","SUBSET_PARAM_LIMIT","SUBSET_PARAM_OFFSET","SUBSET_PARAM_ORDER_BY","p","LIVE_QUERY_PARAM","MissingHeadersError","_fetchClient","_maxPrefetchedRequests","_prefetchQueue","_queueHeadUrl","_queueTailUrl","_PrefetchQueue_instances","prefetch_fn","__privateAdd","__privateSet","__privateGet","__privateMethod","_","aborter","entry","request","signal","cleanup","chainAborter","__spreadProps","__spreadValues","shapeHandle","lastOffset","isUpToDate","CHUNK_UP_TO_DATE_HEADER","expiredHandle","EXPIRED_HANDLE_QUERY_PARAM","SHAPE_HANDLE_QUERY_PARAM","OFFSET_QUERY_PARAM","sourceSignal","noop","abortParent","input","init","compileExpression","expr","columnMapper","mappedColumn","quoteIdentifier","compileFunction","_exhaustive","args","arg","a","compileOrderBy","clauses","clause","sql","getBytes","stream","onChunk","reader","result","getLines","onLine","buffer","position","fieldLength","discardTrailingNewline","arr","concat","bufLength","lineStart","lineEnd","getMessages","onId","onRetry","onMessage","message","newMessage","decoder","line","field","valueOffset","value","retry","a","b","res","EventStreamContentType","DefaultRetryInterval","LastEventId","fetchEventSource","input","_a","inputSignal","inputHeaders","inputOnOpen","onmessage","onclose","onerror","openWhenHidden","inputFetch","rest","__rest","resolve","reject","headers","curRequestController","onVisibilityChange","create","retryInterval","retryTimer","dispose","fetch","onopen","defaultOnOpen","sig","response","getLines","getMessages","id","retry","err","interval","innerErr","ExpiredShapesCache","shapeUrl","entry","handle","keys","oldest","min","k","e","stored","expiredShapesCache","UpToDateTracker","shapeKey","cursor","keys","oldest","min","k","now","timeSinceLastWrite","delay","entry","modified","key","e","stored","upToDateTracker","SnapshotTracker","metadata","keys","_a","_b","_c","_d","xmaxSet","databaseLsnSet","snapshotMark","message","txids","xid","xmax","snapshots","snapshot","x","isVisibleInSnapshot","newDatabaseLsn","dbLsn","ShapeStreamState","_cursor","_opts","_input","_url","_context","PausedState","error","ErrorState","handle","InitialState","_shared","ActiveState","shared","__privateAdd","__privateSet","__privateGet","url","OFFSET_QUERY_PARAM","SHAPE_HANDLE_QUERY_PARAM","input","_a","_b","_c","responseHandle","offset","liveCacheBuster","schema","lastSyncedAt","expiredHandle","retryCount","StaleRetryState","__spreadProps","__spreadValues","LiveState","FetchingState","staleResult","SyncingState","cursor","ReplayingState","_InitialState","_SyncingState","_staleCacheBuster","_staleCacheRetryCount","_StaleRetryState","fields","staleCacheBuster","staleCacheRetryCount","__objRest","context","CACHE_BUSTER_QUERY_PARAM","_consecutiveShortSseConnections","_sseFallbackToLongPolling","_LiveState","sseState","LIVE_CACHE_BUSTER_QUERY_PARAM","LIVE_QUERY_PARAM","opts","nextConsecutiveShort","nextFallback","fellBackToLongPolling","wasShortConnection","_replayCursor","_ReplayingState","replayCursor","suppressBatch","_PausedState","previousState","transition","_exhaustive","_ErrorState","createInitialState","_holders","_onAcquired","_onReleased","PauseLock","callbacks","__privateAdd","__privateSet","reason","__privateGet","wasUnlocked","prefix","RESERVED_PARAMS","LIVE_CACHE_BUSTER_QUERY_PARAM","SHAPE_HANDLE_QUERY_PARAM","LIVE_QUERY_PARAM","OFFSET_QUERY_PARAM","CACHE_BUSTER_QUERY_PARAM","TROUBLESHOOTING_URL","createCacheBuster","resolveValue","value","toInternalParams","params","entries","resolvedEntries","key","resolvedValue","_","resolveHeaders","headers","canonicalShapeKey","url","cleanUrl","ELECTRIC_PROTOCOL_QUERY_PARAMS","_error","_fetchClient","_sseFetchClient","_messageParser","_subscribers","_started","_syncState","_connected","_mode","_onError","_requestAbortController","_refreshCount","_snapshotCounter","_ShapeStream_instances","isRefreshing_get","_tickPromise","_tickPromiseResolver","_tickPromiseRejecter","_messageChain","_snapshotTracker","_pauseLock","_currentFetchUrl","_lastSseConnectionStartTime","_minSseConnectionDuration","_maxShortSseConnections","_sseBackoffBaseDelay","_sseBackoffMaxDelay","_unsubscribeFromVisibilityChanges","_unsubscribeFromWakeDetection","_maxStaleCacheRetries","_recentRequestEntries","_fastLoopWindowMs","_fastLoopThreshold","_fastLoopBackoffBaseMs","_fastLoopBackoffMaxMs","_fastLoopConsecutiveCount","_fastLoopMaxCount","_pendingRequestShapeCacheBuster","_maxSnapshotRetries","start_fn","teardown_fn","requestShape_fn","checkFastLoop_fn","constructUrl_fn","createAbortListener_fn","onInitialResponse_fn","onMessages_fn","fetchShape_fn","requestShapeLongPoll_fn","requestShapeSSE_fn","nextTick_fn","publish_fn","sendErrorToSubscribers_fn","hasBrowserVisibilityAPI_fn","subscribeToVisibilityChanges_fn","subscribeToWakeDetection_fn","reset_fn","fetchSnapshotWithRetry_fn","buildSubsetBody_fn","ShapeStream","options","__privateAdd","SnapshotTracker","_a","_b","_c","_d","__spreadValues","validateOptions","__privateSet","createInitialState","PauseLock","__privateGet","PAUSE_STREAM","__privateMethod","transformer","applyColumnMapper","row","result","dbKey","appKey","MessageParser","baseFetchClient","args","backOffOpts","__spreadProps","BackoffDefaults","fetchWithBackoffClient","createFetchWithBackoff","createFetchWithResponseHeadersCheck","createFetchWithChunkBuffer","createFetchWithConsumedMessages","callback","onError","subscriptionId","__privateWrapper","FORCE_DISCONNECT_AND_REFRESH","opts","snapshotReason","snapshotWarnTimer","metadata","data","responseOffset","responseHandle","dataWithEndBoundary","message","transition","err","retryOpts","isRetryable","MissingHeadersError","ErrorState","requestShapeCacheBuster","activeCacheBuster","resumingFromPause","PausedState","signal","fetchUrl","requestHeaders","abortListener","requestAbortController","e","abortReason","isRestartAbort","SYSTEM_WAKE","FetchError","FetchBackoffAbortError","StaleCacheError","shapeKey","expiredShapesCache","newShapeHandle","SHAPE_HANDLE_HEADER","nextRequestShapeCacheBuster","messages409","now","currentOffset","upToDateTracker","maxDelay","delayMs","resolve","subsetParams","_e","_f","convertWhereParamsToObj","validateParams","setQueryParam","TABLE_QUERY_PARAM","encodedWhere","encodeWhereClause","WHERE_QUERY_PARAM","originalColumns","encodedColumns","serializedColumns","quoteIdentifier","COLUMNS_QUERY_PARAM","REPLICA_PARAM","WHERE_PARAMS_PARAM","customParams","compiledWhere","compileExpression","SUBSET_PARAM_WHERE","SUBSET_PARAM_WHERE_EXPR","SUBSET_PARAM_WHERE_PARAMS","bigintSafeStringify","SUBSET_PARAM_LIMIT","SUBSET_PARAM_OFFSET","compiledOrderBy","compileOrderBy","SUBSET_PARAM_ORDER_BY","SUBSET_PARAM_ORDER_BY_EXPR","encodedOrderBy","LOG_MODE_QUERY_PARAM","expiredHandle","EXPIRED_HANDLE_QUERY_PARAM","response","status","shapeHandle","CHUNK_LAST_OFFSET_HEADER","LIVE_CACHE_BUSTER_HEADER","getSchemaFromHeaders","batch","isSseMessage","lastMessage","hasUpToDateMessage","isUpToDateMessage","upToDateOffset","getOffset","messagesToProcess","isChangeMessage","lastSeenCursor","useSse","EXPERIMENTAL_LIVE_SSE_QUERY_PARAM","LIVE_SSE_QUERY_PARAM","schema","messages","preview","fetch","sseHeaders","ignoredStaleResponse","buffer","fetchEventSource","event","error","connectionDuration","wasAborted","reject","__","errorFn","visibilityHandler","INTERVAL_MS","WAKE_THRESHOLD_MS","lastTickTime","timer","elapsed","handle","retryCount","cacheBuster","usePost","fetchOptions","usedHandle","nextRetryCount","nextHandle","nextCacheBuster","rawData","body","schemaHeader","SHAPE_SCHEMA_HEADER","reservedParams","ReservedParamError","MissingShapeUrlError","InvalidSignalError","MissingShapeHandleError","k","v","allPgParams","i","_data","_subscribers","_insertedKeys","_requestedSubSnapshots","_reexecuteSnapshotsPending","_status","_error","_Shape_instances","process_fn","reexecuteSnapshots_fn","awaitUpToDate_fn","updateShapeStatus_fn","handleError_fn","notify_fn","Shape","stream","__privateAdd","__privateMethod","__privateGet","v","resolve","reject","unsubscribe","value","params","key","bigintSafeStringify","callback","subscriptionId","messages","shouldNotify","message","isChangeMessage","__spreadValues","isControlMessage","__privateSet","jsonParams","snapshot","_","check","interval","unsub","status","stateChanged","e","FetchError"]}