{"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 * - Preserves multi-underscore count for injectivity:\n *     `user__id` → `user_Id`, `user___id` → `user__Id`\n * - Normalizes to lowercase first: `user_Column` → `userColumn`\n *\n * The transform is designed to be injective on lowercase input and\n * round-trippable via `camelToSnake`, so distinct db columns never\n * collide on the same app key.\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') // 'user_Id'\n * snakeToCamel('user___id') // 'user__Id'\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. For a run of n underscores before\n  // a letter, keep (n-1) literal underscores and uppercase the letter.\n  // This preserves underscore count so distinct inputs never collide.\n  const camelCased = normalized.replace(/_+([a-z])/g, (match, letter) => {\n    const extraUnderscores = `_`.repeat(match.length - 2)\n    return extraUnderscores + 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 a\n      // lowercase letter or an underscore. The `_` case preserves the\n      // injective encoding from snakeToCamel: `user_Id` → `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 * Canonical, BigInt-safe stringify. Recursively sorts object keys so that\n * permutation-equivalent inputs produce identical output. Suitable for\n * dedup keys and cache lookups.\n */\nexport function canonicalBigintSafeStringify(value: unknown): string {\n  return JSON.stringify(canonicalize(value))\n}\n\nfunction canonicalize(value: unknown): unknown {\n  if (typeof value === `bigint`) return value.toString()\n  if (value === null || typeof value !== `object`) return value\n  if (Array.isArray(value)) return value.map(canonicalize)\n  const sorted: Record<string, unknown> = {}\n  for (const k of Object.keys(value as Record<string, unknown>).sort()) {\n    sorted[k] = canonicalize((value as Record<string, unknown>)[k])\n  }\n  return sorted\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  EXPERIMENTAL_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    {\n      xmin: bigint\n      xmax: bigint\n      xip_list: bigint[]\n      keys: Set<string>\n      databaseLsn: bigint\n    }\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    // If this mark already exists, drop its reverse-index entries first\n    // so they don't linger with the old (xmax, database_lsn) coordinates.\n    this.#detachFromReverseIndexes(metadata.snapshot_mark)\n\n    const xmax = BigInt(metadata.xmax)\n    const databaseLsn = BigInt(metadata.database_lsn)\n    this.activeSnapshots.set(metadata.snapshot_mark, {\n      xmin: BigInt(metadata.xmin),\n      xmax,\n      xip_list: metadata.xip_list.map(BigInt),\n      keys,\n      databaseLsn,\n    })\n    this.#addToSet(this.xmaxSnapshots, xmax, metadata.snapshot_mark)\n    this.#addToSet(\n      this.snapshotsByDatabaseLsn,\n      databaseLsn,\n      metadata.snapshot_mark\n    )\n  }\n\n  /**\n   * Remove a snapshot from tracking\n   */\n  removeSnapshot(snapshotMark: number): void {\n    this.#detachFromReverseIndexes(snapshotMark)\n    this.activeSnapshots.delete(snapshotMark)\n  }\n\n  #detachFromReverseIndexes(snapshotMark: number): void {\n    const existing = this.activeSnapshots.get(snapshotMark)\n    if (!existing) return\n    this.#removeFromSet(this.xmaxSnapshots, existing.xmax, snapshotMark)\n    this.#removeFromSet(\n      this.snapshotsByDatabaseLsn,\n      existing.databaseLsn,\n      snapshotMark\n    )\n  }\n\n  #addToSet(map: Map<bigint, Set<number>>, key: bigint, value: number): void {\n    const set = map.get(key)\n    if (set) {\n      set.add(value)\n    } else {\n      map.set(key, new Set([value]))\n    }\n  }\n\n  #removeFromSet(\n    map: Map<bigint, Set<number>>,\n    key: bigint,\n    value: number\n  ): void {\n    const set = map.get(key)\n    if (!set) return\n    set.delete(value)\n    if (set.size === 0) map.delete(key)\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 */\nexport function 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  // Use append() so duplicate keys (e.g. ?table=a&table=b) are preserved.\n  for (const [key, value] of url.searchParams) {\n    if (!ELECTRIC_PROTOCOL_QUERY_PARAMS.includes(key)) {\n      cleanUrl.searchParams.append(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  #expiredShapeRecoveryKey: string | null = null\n  #pendingSelfHealCheck: { shapeKey: string; staleHandle: string } | null = null\n  #consecutiveErrorRetries = 0\n  #maxConsecutiveErrorRetries = 50\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          // Bound the onError retry loop to prevent unbounded retries\n          this.#consecutiveErrorRetries++\n          if (\n            this.#consecutiveErrorRetries > this.#maxConsecutiveErrorRetries\n          ) {\n            console.warn(\n              `[Electric] onError retry loop exhausted after ${this.#maxConsecutiveErrorRetries} consecutive retries. ` +\n                `The error was never resolved by the onError handler. ` +\n                `Error: ${err instanceof Error ? err.message : String(err)}`,\n              new Error(`stack trace`)\n            )\n            if (err instanceof Error) {\n              this.#sendErrorToSubscribers(err)\n            }\n            this.#teardown()\n            return\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          return this.#start()\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    // ErrorState should never reach the request loop — re-throw so\n    // #start's catch block can route it through onError properly.\n    if (this.#syncState instanceof ErrorState) {\n      throw this.#syncState.error\n    }\n\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        // Two paths throw StaleCacheError:\n        // 1. Normal stale-retry: response handle matched expired handle,\n        //    #staleCacheBuster set to bypass CDN cache on next request.\n        // 2. Self-healing: stale retries exhausted, expired entry cleared,\n        //    stream reset — retry without expired_handle param.\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 present). An unconditional cache\n        // buster ensures the retry URL is always unique regardless of\n        // whether the server returns a new, same, or missing handle.\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        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        }\n        const nextRequestShapeCacheBuster = createCacheBuster()\n        this.#reset(newShapeHandle)\n\n        // Notify subscribers that data must be re-fetched so they can\n        // clear accumulated state (e.g., Shape clears its row map).\n        // We publish a synthetic control message rather than the raw 409\n        // body to avoid delivering stale data rows to subscribers.\n        await this.#publish([{ headers: { control: `must-refetch` } }])\n\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 !== undefined)\n        setQueryParam(fetchUrl, SUBSET_PARAM_LIMIT, subsetParams.limit)\n      if (subsetParams.offset !== undefined)\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    // If this response is the first one after a self-healing retry, check\n    // whether the proxy/CDN returned the exact handle we just marked expired.\n    // If so, the client is about to accept stale data silently — loudly warn\n    // so operators can detect and fix the proxy misconfiguration.\n    if (this.#pendingSelfHealCheck) {\n      const { shapeKey: healedKey, staleHandle } = this.#pendingSelfHealCheck\n      this.#pendingSelfHealCheck = null\n      if (shapeKey === healedKey && shapeHandle === staleHandle) {\n        console.warn(\n          `[Electric] Self-healing retry received the same handle \"${staleHandle}\" that was just marked expired. ` +\n            `This means your proxy/CDN is serving a stale cached response and ignoring cache-buster query params. ` +\n            `The client will proceed with this stale data to avoid a permanent failure, but it may be out of date until the cache refreshes. ` +\n            `Fix: configure your proxy/CDN to include all query parameters (especially 'handle' and 'offset') in its cache key. ` +\n            `For more information visit the troubleshooting guide: ${TROUBLESHOOTING_URL}`,\n          new Error(`stack trace`)\n        )\n      }\n    }\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    // Clear recovery guard on 204 (no-content), since the empty body means\n    // #onMessages won't run to clear it via the up-to-date path.\n    if (status === 204) {\n      this.#expiredShapeRecoveryKey = null\n    }\n\n    if (transition.action === `accepted` && status === 204) {\n      this.#consecutiveErrorRetries = 0\n    }\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        if (shapeKey) {\n          // Clear the expired entry — keeping it only poisons future sessions.\n          expiredShapesCache.delete(shapeKey)\n\n          // Try one self-healing retry per shape: reset the stream and\n          // retry without the expired_handle param. Since handles are never\n          // reused (see SPEC.md S0), the fresh response will have a new\n          // handle and won't trigger stale detection.\n          if (this.#expiredShapeRecoveryKey !== shapeKey) {\n            console.warn(\n              `[Electric] Stale cache retries exhausted (${this.#maxStaleCacheRetries} attempts). ` +\n                `Clearing expired handle entry and attempting self-healing retry without the expired_handle parameter. ` +\n                `For more information visit the troubleshooting guide: ${TROUBLESHOOTING_URL}`,\n              new Error(`stack trace`)\n            )\n            this.#expiredShapeRecoveryKey = shapeKey\n            // Arm a post-self-heal check: if the next response comes back\n            // with the same handle we just marked expired, the proxy/CDN is\n            // still serving stale data and we'll warn loudly instead of\n            // accepting it silently.\n            if (shapeHandle) {\n              this.#pendingSelfHealCheck = {\n                shapeKey,\n                staleHandle: shapeHandle,\n              }\n            }\n            this.#reset()\n            throw new StaleCacheError(\n              `Expired handle entry evicted for self-healing retry`\n            )\n          }\n        }\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    this.#consecutiveErrorRetries = 0\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        this.#expiredShapeRecoveryKey = null\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 — every caller\n    // (#requestShape's 409 handler, #checkFastLoop, and stale-retry\n    // self-healing in #onInitialResponse) runs inside the active stream loop,\n    // so 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        if (nextHandle) {\n          this.#syncState = this.#syncState.withHandle(nextHandle)\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        }\n        const nextCacheBuster = createCacheBuster()\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  canonicalBigintSafeStringify,\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 * Shape subscriber notification semantics (see SPEC.md → \"Shape\n * notification semantics\" for the canonical contract):\n *\n * - **N1 (no notify while syncing).** Data messages that arrive while\n *   `status === 'syncing'` apply to `#data` but do NOT call `#notify`.\n *   A notification fires only when the shape transitions from\n *   `syncing` to `up-to-date` via an up-to-date control message. This\n *   guarantees that subscribers observing `rows` always see a\n *   consistent snapshot of the shape AND can read a defined\n *   `stream.lastSyncedAt()`.\n *\n * - **N2 (notify on change while up-to-date).** Once\n *   `status === 'up-to-date'`, any data message (insert/update/delete,\n *   subject to `mode === 'changes_only'` filtering) triggers a\n *   notification; the status then transitions back to `syncing` until\n *   the next up-to-date message.\n *\n * A `must-refetch` control message clears `#data` and transitions the\n * status back to `syncing`, which re-engages N1 — subscribers will\n * receive the post-rotation state on the next `up-to-date` without\n * ever observing an intermediate empty-rows notification.\n */\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    // Use canonical stringify so permutation-equivalent params dedup.\n    const key = canonicalBigintSafeStringify(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        const wasUpToDate = this.#status === `up-to-date`\n        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              if (wasUpToDate) shouldNotify = true\n              break\n            case `update`:\n              this.#data.set(message.key, {\n                ...this.#data.get(message.key)!,\n                ...message.value,\n              })\n              if (wasUpToDate) shouldNotify = true\n              break\n            case `delete`:\n              this.#data.delete(message.key)\n              if (wasUpToDate) shouldNotify = true\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              if (wasUpToDate) shouldNotify = true\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                if (wasUpToDate) shouldNotify = true\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                if (wasUpToDate) shouldNotify = true\n              }\n              break\n          }\n        }\n      }\n\n      if (isControlMessage(message)) {\n        switch (message.headers.control) {\n          case `up-to-date`:\n            if (this.#updateShapeStatus(`up-to-date`)) shouldNotify = true\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            this.#updateShapeStatus(`syncing`)\n            this.#reexecuteSnapshotsPending = true\n            break\n        }\n      }\n    })\n\n    if (shouldNotify) this.#notify()\n  }\n\n  async #reexecuteSnapshots(): Promise<void> {\n    try {\n      await this.#awaitUpToDate()\n    } catch (e) {\n      this.#surfaceReexecuteError(e)\n      return\n    }\n\n    const results = 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          return undefined\n        } catch (e) {\n          return e\n        }\n      })\n    )\n\n    const firstError = results.find((e) => e !== undefined)\n    if (firstError !== undefined) this.#surfaceReexecuteError(firstError)\n  }\n\n  #surfaceReexecuteError(e: unknown): void {\n    if (e instanceof FetchError) {\n      this.#error = e\n    } else if (e instanceof Error) {\n      this.#error = new FetchError(0, e.message, undefined, {}, ``, e.message)\n    } else {\n      this.#error = new FetchError(0, String(e), undefined, {}, ``, String(e))\n    }\n    this.#notify()\n  }\n\n  async #awaitUpToDate(): Promise<void> {\n    if (this.#error) throw this.#error\n    if (this.stream.isUpToDate) return\n    if (this.stream.error) throw this.stream.error as Error\n    await new Promise<void>((resolve, reject) => {\n      let settled = false\n      let interval: ReturnType<typeof setInterval>\n      let unsub: (() => void) | undefined\n      const done = (action: () => void) => {\n        if (settled) return\n        settled = true\n        clearInterval(interval)\n        unsub?.()\n        action()\n      }\n      const check = () => {\n        if (this.stream.isUpToDate) return done(resolve)\n        const streamError = this.stream.error as Error | undefined\n        if (streamError) return done(() => reject(streamError))\n        if (this.#error) {\n          const err = this.#error\n          return done(() => reject(err))\n        }\n      }\n      interval = setInterval(check, 10)\n      unsub = this.stream.subscribe(\n        () => check(),\n        (err) => done(() => reject(err))\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":["value","pos","fetch","_a","_fetchClient","_a","_b","fetch","_subscribers","_error"]}