@lark-sh/client 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/protocol/constants.ts","../src/connection/Coordinator.ts","../src/LarkError.ts","../src/protocol/messages.ts","../src/connection/MessageQueue.ts","../src/connection/PendingWriteManager.ts","../src/utils/path.ts","../src/cache/DataCache.ts","../src/connection/SubscriptionManager.ts","../src/connection/WebSocketClient.ts","../src/OnDisconnect.ts","../src/utils/pushid.ts","../src/DatabaseReference.ts","../src/DataSnapshot.ts","../src/utils/jwt.ts","../src/LarkDatabase.ts","../src/utils/volatile.ts"],"sourcesContent":["/**\n * @lark-sh/client - JavaScript client for Lark real-time database\n *\n * @example\n * ```typescript\n * import { LarkDatabase } from '@lark-sh/client';\n *\n * const db = new LarkDatabase();\n * await db.connect('my-project/my-database', { anonymous: true });\n *\n * // Write data\n * await db.ref('players/abc').set({ name: 'Riley', score: 0 });\n *\n * // Subscribe to changes\n * const unsubscribe = db.ref('players').on('child_changed', (snap) => {\n * console.log(`Player ${snap.key} changed:`, snap.val());\n * });\n *\n * // Later: unsubscribe\n * unsubscribe();\n *\n * // Disconnect\n * await db.disconnect();\n * ```\n */\n\n// Main classes\nexport { LarkDatabase } from './LarkDatabase';\nexport type {\n ConnectOptions,\n AuthInfo,\n TransactionOp,\n TransactionSetOp,\n TransactionUpdateOp,\n TransactionDeleteOp,\n TransactionConditionOp,\n TransactionObject,\n} from './LarkDatabase';\n\nexport { DatabaseReference } from './DatabaseReference';\nexport type { SnapshotCallback, QueryState, TransactionResult } from './DatabaseReference';\n\nexport { DataSnapshot } from './DataSnapshot';\n\nexport { OnDisconnect } from './OnDisconnect';\n\nexport { LarkError } from './LarkError';\n\n// Protocol types (for advanced usage)\nexport type { EventType } from './protocol/constants';\nexport type { QueryParams, MoveEntry } from './protocol/messages';\n\n// Connection utilities (for advanced usage)\nexport { PendingWriteManager } from './connection/PendingWriteManager';\nexport type { WriteOperation, PendingWrite } from './connection/PendingWriteManager';\n\n// Utility functions (for advanced usage)\nexport { generatePushId } from './utils/pushid';\nexport { isVolatilePath } from './utils/volatile';\n","/**\n * Wire protocol constants.\n * Keys are shortened for bandwidth efficiency.\n */\n\n// Client -> Server operations\nexport const Op = {\n JOIN: 'j',\n SET: 's',\n UPDATE: 'u',\n DELETE: 'd',\n PUSH: 'p',\n SUBSCRIBE: 'sb',\n UNSUBSCRIBE: 'us',\n ONCE: 'o',\n ON_DISCONNECT: 'od',\n LEAVE: 'l',\n TRANSACTION: 'tx',\n} as const;\n\n// Transaction operation types (used within tx ops array)\nexport const TxOp = {\n SET: 's',\n UPDATE: 'u',\n DELETE: 'd',\n CONDITION: 'c',\n} as const;\n\nexport type TxOpType = (typeof TxOp)[keyof typeof TxOp];\n\n// OnDisconnect actions\nexport const OnDisconnectAction = {\n SET: 's',\n UPDATE: 'u',\n DELETE: 'd',\n CANCEL: 'c',\n} as const;\n\n// Server -> Client event types (wire format)\n// Server now sends 'put' and 'patch' events; client generates child_* events locally\nexport const ServerEventType = {\n PUT: 'put',\n PATCH: 'patch',\n} as const;\n\nexport type ServerEventTypeValue = (typeof ServerEventType)[keyof typeof ServerEventType];\n\n// Client-side event types (API-facing)\n// These are generated by the client from put/patch events\nexport type EventType = 'value' | 'child_added' | 'child_changed' | 'child_removed' | 'child_moved';\n\n// Map client event types to short form for subscribe message\nexport const eventTypeToShort: Record<EventType, string> = {\n value: 'v',\n child_added: 'ca',\n child_changed: 'cc',\n child_removed: 'cr',\n child_moved: 'cm',\n};\n\n// Error codes\nexport const ErrorCode = {\n PERMISSION_DENIED: 'permission_denied',\n INVALID_DATA: 'invalid_data',\n NOT_FOUND: 'not_found',\n INVALID_PATH: 'invalid_path',\n INVALID_OPERATION: 'invalid_operation',\n INTERNAL_ERROR: 'internal_error',\n CONDITION_FAILED: 'condition_failed',\n} as const;\n\nexport type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];\n\n// Default coordinator URL\nexport const DEFAULT_COORDINATOR_URL = 'https://db.lark.sh';\n","/**\n * Coordinator client - handles HTTP requests to the coordinator service\n * to get connection details for a specific database.\n */\n\nimport { DEFAULT_COORDINATOR_URL } from '../protocol/constants';\n\nexport interface ConnectRequest {\n database: string;\n token?: string;\n anonymous?: boolean;\n}\n\nexport interface ConnectResponse {\n ws_url: string; // Full WebSocket URL (e.g., \"wss://smash-1.larksh.com/ws\")\n udp_host: string; // Direct IP for UDP connections\n udp_port: number; // UDP port\n token: string; // Connection JWT to use with the server\n}\n\nexport interface CoordinatorError {\n error: string;\n message: string;\n}\n\nexport class Coordinator {\n private readonly baseUrl: string;\n\n constructor(baseUrl: string = DEFAULT_COORDINATOR_URL) {\n // Remove trailing slash if present\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n }\n\n /**\n * Request connection details from the coordinator.\n *\n * @param database - Database ID in format \"project/database\"\n * @param options - Either a user token or anonymous flag\n * @returns Connection details including host, port, and connection token\n */\n async connect(\n database: string,\n options: { token?: string; anonymous?: boolean } = {}\n ): Promise<ConnectResponse> {\n const body: ConnectRequest = { database };\n\n if (options.token) {\n body.token = options.token;\n } else if (options.anonymous) {\n body.anonymous = true;\n } else {\n // Default to anonymous if nothing specified\n body.anonymous = true;\n }\n\n const response = await fetch(`${this.baseUrl}/connect`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n let errorMessage = `Coordinator request failed: ${response.status}`;\n try {\n const errorBody = (await response.json()) as CoordinatorError;\n if (errorBody.message) {\n errorMessage = errorBody.message;\n }\n } catch {\n // Ignore JSON parse errors\n }\n throw new Error(errorMessage);\n }\n\n const data = (await response.json()) as ConnectResponse;\n return data;\n }\n}\n","/**\n * LarkError - custom error class for Lark operations.\n */\n\nexport class LarkError extends Error {\n readonly code: string;\n\n constructor(code: string, message?: string) {\n super(message || code);\n this.code = code;\n this.name = 'LarkError';\n\n // Maintain proper stack trace in V8 environments\n const ErrorWithCapture = Error as typeof Error & {\n captureStackTrace?: (target: object, constructor: Function) => void;\n };\n if (ErrorWithCapture.captureStackTrace) {\n ErrorWithCapture.captureStackTrace(this, LarkError);\n }\n }\n}\n","/**\n * Wire protocol message types.\n * All communication uses JSON over WebSocket with shortened keys.\n */\n\nimport { EventType } from './constants';\n\n// ============================================\n// Client -> Server Messages\n// ============================================\n\nexport interface JoinMessage {\n o: 'j'; // operation: join\n t: string; // token (JWT from coordinator)\n r: string; // request ID\n}\n\nexport interface SetMessage {\n o: 's'; // operation: set\n p: string; // path\n v: unknown; // value\n r: string; // request ID\n y?: number | string; // priority (optional)\n oid?: string; // optimistic write ID for retry tracking\n}\n\nexport interface UpdateMessage {\n o: 'u'; // operation: update\n p: string; // path\n v: Record<string, unknown>; // values to merge\n r: string; // request ID\n oid?: string; // optimistic write ID for retry tracking\n}\n\nexport interface DeleteMessage {\n o: 'd'; // operation: delete\n p: string; // path\n r: string; // request ID\n oid?: string; // optimistic write ID for retry tracking\n}\n\nexport interface PushMessage {\n o: 'p'; // operation: push\n p: string; // path\n v: unknown; // value\n r: string; // request ID\n oid?: string; // optimistic write ID for retry tracking\n}\n\nexport interface SubscribeMessage {\n o: 'sb'; // operation: subscribe\n p: string; // path\n e: string[]; // event types (short form)\n r: string; // request ID\n // Query parameters (optional) - at top level per VIEW_REFACTOR.md\n orderBy?: string;\n orderByChild?: string;\n limitToFirst?: number;\n limitToLast?: number;\n startAt?: unknown;\n startAtKey?: string;\n endAt?: unknown;\n endAtKey?: string;\n equalTo?: unknown;\n equalToKey?: string;\n}\n\nexport interface QueryParams {\n orderBy?: 'key' | 'priority' | 'child' | 'value';\n orderByChild?: string; // child path (when orderBy='child')\n limitToFirst?: number;\n limitToLast?: number;\n startAt?: unknown; // startAt value\n startAtKey?: string; // startAt key tie-breaker\n endAt?: unknown; // endAt value\n endAtKey?: string; // endAt key tie-breaker\n equalTo?: unknown; // equalTo value\n equalToKey?: string; // equalTo key tie-breaker\n}\n\nexport interface UnsubscribeMessage {\n o: 'us'; // operation: unsubscribe\n p: string; // path\n r: string; // request ID\n}\n\nexport interface OnceMessage {\n o: 'o'; // operation: once\n p: string; // path\n r: string; // request ID\n // Query parameters (optional) - at top level (same as SubscribeMessage)\n orderBy?: string;\n orderByChild?: string;\n limitToFirst?: number;\n limitToLast?: number;\n startAt?: unknown;\n startAtKey?: string;\n endAt?: unknown;\n endAtKey?: string;\n equalTo?: unknown;\n equalToKey?: string;\n}\n\nexport interface OnDisconnectMessage {\n o: 'od'; // operation: onDisconnect\n p: string; // path\n a: 's' | 'u' | 'd' | 'c'; // action: set, update, delete, cancel\n v?: unknown; // value (for set/update)\n r: string; // request ID\n y?: number | string; // priority (optional, for set)\n}\n\nexport interface LeaveMessage {\n o: 'l'; // operation: leave\n r: string; // request ID\n}\n\nexport interface PongMessage {\n o: 'po'; // operation: pong (response to server ping)\n}\n\n// Transaction operation types (used in ops array)\nexport interface TxSetOp {\n o: 's'; // set\n p: string; // path\n v: unknown; // value\n}\n\nexport interface TxUpdateOp {\n o: 'u'; // update (merge)\n p: string; // path\n v: Record<string, unknown>; // values to merge\n}\n\nexport interface TxDeleteOp {\n o: 'd'; // delete\n p: string; // path\n}\n\nexport interface TxConditionOp {\n o: 'c'; // condition (compare-and-swap check)\n p: string; // path\n v: unknown; // expected value\n}\n\nexport type TxOperation = TxSetOp | TxUpdateOp | TxDeleteOp | TxConditionOp;\n\nexport interface TransactionMessage {\n o: 'tx'; // operation: transaction\n ops: TxOperation[]; // array of operations\n r: string; // request ID\n oid?: string; // optimistic write ID for retry tracking\n}\n\nexport type ClientMessage =\n | JoinMessage\n | SetMessage\n | UpdateMessage\n | DeleteMessage\n | PushMessage\n | SubscribeMessage\n | UnsubscribeMessage\n | OnceMessage\n | OnDisconnectMessage\n | LeaveMessage\n | PongMessage\n | TransactionMessage;\n\n// ============================================\n// Server -> Client Messages\n// ============================================\n\nexport interface AckMessage {\n a: string; // ack with request ID\n oid?: string; // echoed operation ID (for optimistic write tracking)\n}\n\nexport interface NackMessage {\n n: string; // nack with request ID\n e: string; // error code\n m?: string; // human-readable message\n oid?: string; // echoed operation ID (for optimistic write tracking)\n}\n\n// New delta-based event format\n// Server sends 'put' for single-path changes, 'patch' for multi-path changes\n// Client generates child_* events locally from these deltas\n\nexport interface PutEventMessage {\n ev: 'put'; // event type: single-path delta\n sp: string; // subscription path (absolute) - identifies which subscription\n p: string; // delta path (relative to sp), \"/\" means full snapshot\n v?: unknown; // value, null for deletion (omitted for move-only events)\n x?: boolean; // volatile flag\n ts?: number; // server timestamp in ms (for volatile events)\n ak?: string; // afterKey - previous sibling for positioning (empty string = first)\n k?: string[]; // orderedKeys - full key order for initial snapshot\n}\n\n// Move entry for ordered queries - represents a child that changed position\nexport interface MoveEntry {\n k: string; // key that moved\n ak: string; // new afterKey (empty string = first position)\n}\n\nexport interface PatchEventMessage {\n ev: 'patch'; // event type: multi-path delta\n sp: string; // subscription path (absolute)\n p: string; // base path (usually \"/\")\n v?: Record<string, unknown>; // multiple path:value pairs (relative to sp+p)\n x?: boolean; // volatile flag\n ts?: number; // server timestamp in ms (for volatile events)\n k?: string[]; // orderedKeys - full key order for batch reorder\n mv?: MoveEntry[]; // moves array - items that changed position\n}\n\nexport type EventMessage = PutEventMessage | PatchEventMessage;\n\nexport interface OnceResponseMessage {\n oc: string; // once response with request ID\n ov: unknown; // value\n}\n\nexport interface PushAckMessage {\n pa: string; // push ack with request ID\n pk: string; // generated push key\n}\n\nexport interface JoinCompleteMessage {\n jc: string; // join complete with request ID\n vp?: string[] | null; // volatile path patterns (e.g., [\"players/*/position\"])\n}\n\nexport interface PingMessage {\n o: 'pi'; // operation: ping (keepalive from server)\n}\n\nexport type ServerMessage =\n | AckMessage\n | NackMessage\n | EventMessage\n | OnceResponseMessage\n | PushAckMessage\n | JoinCompleteMessage\n | PingMessage;\n\n// ============================================\n// Helper functions\n// ============================================\n\nexport function isAckMessage(msg: ServerMessage): msg is AckMessage {\n return 'a' in msg;\n}\n\nexport function isJoinCompleteMessage(msg: ServerMessage): msg is JoinCompleteMessage {\n return 'jc' in msg;\n}\n\nexport function isNackMessage(msg: ServerMessage): msg is NackMessage {\n return 'n' in msg;\n}\n\nexport function isEventMessage(msg: ServerMessage): msg is EventMessage {\n return 'ev' in msg;\n}\n\nexport function isPutEventMessage(msg: ServerMessage): msg is PutEventMessage {\n return 'ev' in msg && (msg as EventMessage).ev === 'put';\n}\n\nexport function isPatchEventMessage(msg: ServerMessage): msg is PatchEventMessage {\n return 'ev' in msg && (msg as EventMessage).ev === 'patch';\n}\n\nexport function isOnceResponseMessage(msg: ServerMessage): msg is OnceResponseMessage {\n return 'oc' in msg;\n}\n\nexport function isPushAckMessage(msg: ServerMessage): msg is PushAckMessage {\n return 'pa' in msg;\n}\n\nexport function isPingMessage(msg: ServerMessage): msg is PingMessage {\n return 'o' in msg && (msg as PingMessage).o === 'pi';\n}\n","/**\n * MessageQueue - handles request/response correlation for WebSocket messages.\n *\n * Every reliable operation gets a unique request ID. When we send a message,\n * we create a promise and store it. When we receive an ack/nack, we resolve/reject\n * the corresponding promise.\n */\n\nimport { LarkError } from '../LarkError';\nimport {\n ServerMessage,\n isAckMessage,\n isJoinCompleteMessage,\n isNackMessage,\n isOnceResponseMessage,\n isPushAckMessage,\n} from '../protocol/messages';\n\ninterface PendingRequest {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n}\n\nexport class MessageQueue {\n private nextId = 1;\n private pending = new Map<string, PendingRequest>();\n private defaultTimeout: number;\n\n constructor(defaultTimeout: number = 30000) {\n this.defaultTimeout = defaultTimeout;\n }\n\n /**\n * Generate a new unique request ID.\n */\n nextRequestId(): string {\n return String(this.nextId++);\n }\n\n /**\n * Register a pending request that expects a response.\n * Returns a promise that resolves when ack is received, or rejects on nack/timeout.\n */\n registerRequest(requestId: string, timeout?: number): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const timeoutMs = timeout ?? this.defaultTimeout;\n\n const timeoutHandle = setTimeout(() => {\n this.pending.delete(requestId);\n reject(new LarkError('timeout', `Request ${requestId} timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n\n this.pending.set(requestId, {\n resolve,\n reject,\n timeout: timeoutHandle,\n });\n });\n }\n\n /**\n * Handle an incoming server message. If it's a response to a pending request,\n * resolve or reject the corresponding promise.\n *\n * @returns true if the message was handled (was a response), false otherwise\n */\n handleMessage(message: ServerMessage): boolean {\n // Join complete (includes volatile paths)\n if (isJoinCompleteMessage(message)) {\n const pending = this.pending.get(message.jc);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(message.jc);\n // Resolve with volatile paths array (may be null/undefined)\n pending.resolve(message.vp || []);\n return true;\n }\n }\n\n // Regular ack\n if (isAckMessage(message)) {\n const pending = this.pending.get(message.a);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(message.a);\n pending.resolve(undefined);\n return true;\n }\n }\n\n // Nack (error)\n if (isNackMessage(message)) {\n const pending = this.pending.get(message.n);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(message.n);\n pending.reject(new LarkError(message.e, message.m));\n return true;\n }\n }\n\n // Once response\n if (isOnceResponseMessage(message)) {\n const pending = this.pending.get(message.oc);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(message.oc);\n pending.resolve(message.ov);\n return true;\n }\n }\n\n // Push ack\n if (isPushAckMessage(message)) {\n const pending = this.pending.get(message.pa);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(message.pa);\n pending.resolve(message.pk);\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Reject all pending requests (e.g., on disconnect).\n */\n rejectAll(error: Error): void {\n for (const [, pending] of this.pending) {\n clearTimeout(pending.timeout);\n pending.reject(error);\n }\n this.pending.clear();\n }\n\n /**\n * Get the number of pending requests.\n */\n get pendingCount(): number {\n return this.pending.size;\n }\n}\n","/**\n * PendingWriteManager - tracks pending write operations for optimistic updates.\n *\n * Each write operation is assigned a unique operation ID (oid). The manager tracks\n * pending writes until they are acknowledged by the server. On reconnect, pending\n * writes can be retried to ensure data consistency.\n */\n\nexport type WriteOperation = 'set' | 'update' | 'delete' | 'push' | 'transaction';\n\nexport interface PendingWrite {\n oid: string;\n operation: WriteOperation;\n path: string;\n value?: unknown;\n timestamp: number;\n}\n\nexport class PendingWriteManager {\n private pending = new Map<string, PendingWrite>();\n private counter = 0;\n\n /**\n * Generate a unique operation ID.\n * Format: op_{timestamp}_{counter}_{random}\n */\n generateOid(): string {\n this.counter++;\n const random = Math.random().toString(36).slice(2, 8);\n return `op_${Date.now()}_${this.counter}_${random}`;\n }\n\n /**\n * Track a new pending write operation.\n */\n trackWrite(oid: string, operation: WriteOperation, path: string, value?: unknown): void {\n this.pending.set(oid, {\n oid,\n operation,\n path,\n value,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Called when a write is acknowledged by the server.\n * Removes the write from pending tracking.\n */\n onAck(oid: string): boolean {\n return this.pending.delete(oid);\n }\n\n /**\n * Called when a write is rejected by the server.\n * Removes the write from pending tracking.\n */\n onNack(oid: string): boolean {\n return this.pending.delete(oid);\n }\n\n /**\n * Get all pending writes for retry on reconnect.\n * Returns writes in order of their timestamps (oldest first).\n */\n getPendingWrites(): PendingWrite[] {\n const writes = Array.from(this.pending.values());\n writes.sort((a, b) => a.timestamp - b.timestamp);\n return writes;\n }\n\n /**\n * Check if a specific operation is still pending.\n */\n isPending(oid: string): boolean {\n return this.pending.has(oid);\n }\n\n /**\n * Get the number of pending writes.\n */\n get pendingCount(): number {\n return this.pending.size;\n }\n\n /**\n * Clear all pending writes (e.g., on disconnect when not retrying).\n */\n clear(): void {\n this.pending.clear();\n }\n\n /**\n * Remove writes older than a specified age (in milliseconds).\n * Useful for cleaning up stale pending writes that may never be acked.\n */\n removeStale(maxAgeMs: number): number {\n const cutoff = Date.now() - maxAgeMs;\n let removed = 0;\n\n for (const [oid, write] of this.pending) {\n if (write.timestamp < cutoff) {\n this.pending.delete(oid);\n removed++;\n }\n }\n\n return removed;\n }\n}\n","/**\n * Path utilities for database paths.\n * Paths are Unix-style: /players/abc/score\n */\n\n/**\n * Normalize a path to match server format:\n * - Root is \"/\"\n * - All other paths start with \"/\" and have no trailing slash\n * - Multiple slashes are collapsed\n */\nexport function normalizePath(path: string): string {\n if (!path || path === '/') return '/';\n\n // Split, filter empty segments, rejoin with leading slash\n const segments = path.split('/').filter((segment) => segment.length > 0);\n if (segments.length === 0) return '/';\n\n return '/' + segments.join('/');\n}\n\n/**\n * Join path segments together.\n */\nexport function joinPath(...segments: string[]): string {\n const allParts: string[] = [];\n\n for (const segment of segments) {\n if (!segment || segment === '/') continue;\n // Split each segment and add non-empty parts\n const parts = segment.split('/').filter((p) => p.length > 0);\n allParts.push(...parts);\n }\n\n if (allParts.length === 0) return '/';\n return '/' + allParts.join('/');\n}\n\n/**\n * Get the parent path. Returns \"/\" for paths one level deep, \"/\" for root.\n */\nexport function getParentPath(path: string): string {\n const normalized = normalizePath(path);\n if (normalized === '/') return '/';\n\n const lastSlash = normalized.lastIndexOf('/');\n if (lastSlash <= 0) return '/';\n\n return normalized.substring(0, lastSlash);\n}\n\n/**\n * Get the last segment of a path (the \"key\").\n */\nexport function getKey(path: string): string | null {\n const normalized = normalizePath(path);\n if (normalized === '/') return null;\n\n const lastSlash = normalized.lastIndexOf('/');\n return normalized.substring(lastSlash + 1);\n}\n\n/**\n * Check if a path is valid (no invalid characters).\n */\nexport function isValidPath(path: string): boolean {\n if (path === '' || path === '/') return true;\n\n const normalized = normalizePath(path);\n // Filter out empty segments from leading slash\n const segments = normalized.split('/').filter((s) => s.length > 0);\n\n for (const segment of segments) {\n // Check for invalid characters: . $ # [ ]\n if (/[.\\$#\\[\\]]/.test(segment)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Get a nested value from an object by path.\n */\nexport function getValueAtPath(obj: unknown, path: string): unknown {\n const normalized = normalizePath(path);\n if (normalized === '/') return obj;\n\n // Split and filter empty segments (from leading slash)\n const segments = normalized.split('/').filter((s) => s.length > 0);\n let current: unknown = obj;\n\n for (const segment of segments) {\n if (current === null || current === undefined) {\n return undefined;\n }\n if (typeof current !== 'object') {\n return undefined;\n }\n current = (current as Record<string, unknown>)[segment];\n }\n\n return current;\n}\n\n/**\n * Set a nested value in an object by path. Mutates the object.\n * Creates intermediate objects as needed.\n */\nexport function setValueAtPath(obj: Record<string, unknown>, path: string, value: unknown): void {\n const normalized = normalizePath(path);\n if (normalized === '/') {\n // Can't set root on an object\n return;\n }\n\n // Split and filter empty segments (from leading slash)\n const segments = normalized.split('/').filter((s) => s.length > 0);\n let current: Record<string, unknown> = obj;\n\n for (let i = 0; i < segments.length - 1; i++) {\n const segment = segments[i];\n if (!(segment in current) || typeof current[segment] !== 'object' || current[segment] === null) {\n current[segment] = {};\n }\n current = current[segment] as Record<string, unknown>;\n }\n\n const lastSegment = segments[segments.length - 1];\n current[lastSegment] = value;\n}\n","/**\n * DataCache - local data store for caching subscription data.\n *\n * Only stores data from active subscriptions (not from once() calls).\n * Data is considered \"live\" if covered by an active subscription.\n */\n\nimport { getValueAtPath, normalizePath, setValueAtPath } from '../utils/path';\n\nexport class DataCache {\n // path -> cached value\n private cache = new Map<string, unknown>();\n\n /**\n * Store a value at a path.\n * Called when we receive data from a subscription event.\n */\n set(path: string, value: unknown): void {\n const normalized = normalizePath(path);\n this.cache.set(normalized, value);\n }\n\n /**\n * Get the cached value at a path.\n * Returns undefined if not in cache.\n *\n * This method handles nested lookups:\n * - If /boxes is cached with {0: true, 1: false}\n * - get('/boxes/0') returns true (extracted from parent)\n */\n get(path: string): { value: unknown; found: boolean } {\n const normalized = normalizePath(path);\n\n // First, check for exact match\n if (this.cache.has(normalized)) {\n return { value: this.cache.get(normalized), found: true };\n }\n\n // Next, check if any ancestor path has cached data we can extract from\n const ancestorResult = this.getFromAncestor(normalized);\n if (ancestorResult.found) {\n return ancestorResult;\n }\n\n return { value: undefined, found: false };\n }\n\n /**\n * Check if we have cached data that covers the given path.\n * This includes exact matches and ancestor paths.\n */\n has(path: string): boolean {\n return this.get(path).found;\n }\n\n /**\n * Try to get data from an ancestor path.\n * E.g., if /boxes is cached and we want /boxes/5, extract it.\n */\n private getFromAncestor(path: string): { value: unknown; found: boolean } {\n // Walk up the path tree looking for cached ancestors\n const segments = path.split('/').filter((s) => s.length > 0);\n\n for (let i = segments.length - 1; i >= 0; i--) {\n const ancestorPath = i === 0 ? '/' : '/' + segments.slice(0, i).join('/');\n\n if (this.cache.has(ancestorPath)) {\n const ancestorValue = this.cache.get(ancestorPath);\n // Calculate the relative path from ancestor to target\n const relativePath = '/' + segments.slice(i).join('/');\n const extractedValue = getValueAtPath(ancestorValue, relativePath);\n return { value: extractedValue, found: true };\n }\n }\n\n // Also check root\n if (this.cache.has('/')) {\n const rootValue = this.cache.get('/');\n const extractedValue = getValueAtPath(rootValue, path);\n return { value: extractedValue, found: true };\n }\n\n return { value: undefined, found: false };\n }\n\n /**\n * Remove cached data at a path.\n * Called when unsubscribing from a path that's no longer covered.\n */\n delete(path: string): void {\n const normalized = normalizePath(path);\n this.cache.delete(normalized);\n }\n\n /**\n * Remove cached data at a path and all descendant paths.\n * Called when a subscription is removed and no other subscription covers it.\n */\n deleteTree(path: string): void {\n const normalized = normalizePath(path);\n\n // Delete exact match\n this.cache.delete(normalized);\n\n // Delete all descendants\n const prefix = normalized === '/' ? '/' : normalized + '/';\n for (const cachedPath of this.cache.keys()) {\n if (cachedPath.startsWith(prefix) || (normalized === '/' && cachedPath !== '/')) {\n this.cache.delete(cachedPath);\n }\n }\n }\n\n /**\n * Update cache when a child value changes.\n * This updates both the child path and any cached ancestor that contains it.\n *\n * E.g., if /boxes is cached and /boxes/5 changes:\n * - Update the /boxes cache to reflect the new /boxes/5 value\n *\n * If an ancestor is null, it creates a new object to hold the child.\n */\n updateChild(path: string, value: unknown): void {\n const normalized = normalizePath(path);\n\n // Set the exact path\n this.cache.set(normalized, value);\n\n // Also update any cached ancestors that would contain this data\n const segments = normalized.split('/').filter((s) => s.length > 0);\n\n for (let i = segments.length - 1; i >= 1; i--) {\n const ancestorPath = '/' + segments.slice(0, i).join('/');\n\n if (this.cache.has(ancestorPath)) {\n const ancestorValue = this.cache.get(ancestorPath);\n // If ancestor is null, create a new object to hold the child\n const baseValue = (ancestorValue !== null && typeof ancestorValue === 'object')\n ? this.deepClone(ancestorValue)\n : {};\n const remainingPath = '/' + segments.slice(i).join('/');\n setValueAtPath(baseValue as Record<string, unknown>, remainingPath, value);\n this.cache.set(ancestorPath, baseValue);\n }\n }\n\n // Check root as well\n if (this.cache.has('/') && normalized !== '/') {\n const rootValue = this.cache.get('/');\n const baseValue = (rootValue !== null && typeof rootValue === 'object')\n ? this.deepClone(rootValue)\n : {};\n setValueAtPath(baseValue as Record<string, unknown>, normalized, value);\n this.cache.set('/', baseValue);\n }\n }\n\n /**\n * Remove a child from the cache (e.g., on child_removed event).\n */\n removeChild(path: string): void {\n const normalized = normalizePath(path);\n\n // Delete the exact path and any descendants\n this.deleteTree(normalized);\n\n // Also update any cached ancestors\n const segments = normalized.split('/').filter((s) => s.length > 0);\n\n for (let i = segments.length - 1; i >= 1; i--) {\n const ancestorPath = '/' + segments.slice(0, i).join('/');\n\n if (this.cache.has(ancestorPath)) {\n const ancestorValue = this.cache.get(ancestorPath);\n if (ancestorValue !== null && typeof ancestorValue === 'object') {\n const updatedAncestor = this.deepClone(ancestorValue);\n // Navigate to parent and delete the child key\n const parentPath = '/' + segments.slice(i, -1).join('/');\n const childKey = segments[segments.length - 1];\n const parent = parentPath === '/'\n ? updatedAncestor\n : getValueAtPath(updatedAncestor, parentPath);\n if (parent && typeof parent === 'object') {\n delete (parent as Record<string, unknown>)[childKey];\n }\n this.cache.set(ancestorPath, updatedAncestor);\n }\n }\n }\n }\n\n /**\n * Clear all cached data.\n */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Get the number of cached paths (for testing/debugging).\n */\n get size(): number {\n return this.cache.size;\n }\n\n /**\n * Deep clone a value to avoid mutation issues.\n */\n private deepClone<T>(value: T): T {\n if (value === null || typeof value !== 'object') {\n return value;\n }\n return JSON.parse(JSON.stringify(value));\n }\n}\n","/**\n * SubscriptionManager - tracks active subscriptions and routes events to callbacks.\n *\n * Handles the new delta-based protocol where server sends 'put' and 'patch' events.\n * Client generates child_added, child_changed, child_removed, child_moved events locally.\n *\n * Supports ordered queries: tracks child order from server's `k` (orderedKeys) and `ak` (afterKey)\n * fields, and fires child_moved when positions change via `mv` (moves) array.\n */\n\nimport type { DataSnapshot } from '../DataSnapshot';\nimport { DataCache } from '../cache/DataCache';\nimport { EventType } from '../protocol/constants';\nimport { EventMessage, PutEventMessage, PatchEventMessage, QueryParams, MoveEntry } from '../protocol/messages';\nimport { joinPath, normalizePath } from '../utils/path';\n\nexport type SnapshotCallback = (snapshot: DataSnapshot, previousChildKey?: string | null) => void;\n\ninterface SubscriptionEntry {\n callback: SnapshotCallback;\n unsubscribe: () => void;\n}\n\nexport class SubscriptionManager {\n // subscriptionPath -> eventType -> array of subscriptions\n private subscriptions = new Map<string, Map<EventType, SubscriptionEntry[]>>();\n\n // Local data cache for subscription data\n private cache: DataCache;\n\n // Ordered child keys for each subscription path (for ordered queries)\n // subscriptionPath -> ordered array of child keys\n private orderedChildren = new Map<string, string[]>();\n\n // Callback to send subscribe message to server\n private sendSubscribe: ((path: string, eventTypes: string[], queryParams?: QueryParams) => Promise<void>) | null = null;\n\n // Query params for each subscription path\n private queryParams = new Map<string, QueryParams | undefined>();\n\n // Callback to send unsubscribe message to server\n private sendUnsubscribe: ((path: string) => Promise<void>) | null = null;\n\n // Callback to create DataSnapshot from event data\n private createSnapshot:\n | ((path: string, value: unknown, volatile: boolean, serverTimestamp?: number) => DataSnapshot)\n | null = null;\n\n constructor() {\n this.cache = new DataCache();\n }\n\n /**\n * Initialize the manager with server communication callbacks.\n */\n initialize(options: {\n sendSubscribe: (path: string, eventTypes: string[], queryParams?: QueryParams) => Promise<void>;\n sendUnsubscribe: (path: string) => Promise<void>;\n createSnapshot: (path: string, value: unknown, volatile: boolean, serverTimestamp?: number) => DataSnapshot;\n }): void {\n this.sendSubscribe = options.sendSubscribe;\n this.sendUnsubscribe = options.sendUnsubscribe;\n this.createSnapshot = options.createSnapshot;\n }\n\n /**\n * Subscribe to events at a path.\n * Returns an unsubscribe function.\n */\n subscribe(path: string, eventType: EventType, callback: SnapshotCallback, queryParams?: QueryParams): () => void {\n // Path should already be normalized by DatabaseReference\n const normalizedPath = path;\n\n // Check if this is the first subscription to this path\n const isFirstForPath = !this.subscriptions.has(normalizedPath);\n const existingEventTypes = this.getEventTypesForPath(normalizedPath);\n const isFirstForEventType = !existingEventTypes.includes(eventType);\n\n // Create path map if needed\n if (!this.subscriptions.has(normalizedPath)) {\n this.subscriptions.set(normalizedPath, new Map());\n }\n const pathSubs = this.subscriptions.get(normalizedPath)!;\n\n // Create event type array if needed\n if (!pathSubs.has(eventType)) {\n pathSubs.set(eventType, []);\n }\n const eventSubs = pathSubs.get(eventType)!;\n\n // Store query params for this path (first subscription wins)\n if (isFirstForPath && queryParams) {\n this.queryParams.set(normalizedPath, queryParams);\n }\n\n // Create unsubscribe function\n const unsubscribe = () => {\n this.unsubscribeCallback(normalizedPath, eventType, callback);\n };\n\n // Add subscription\n eventSubs.push({ callback, unsubscribe });\n\n // If this is a new event type for this path, update server subscription\n if (isFirstForPath || isFirstForEventType) {\n const allEventTypes = this.getEventTypesForPath(normalizedPath);\n // Send full event type names (server expects 'child_added', not 'ca')\n const storedQueryParams = this.queryParams.get(normalizedPath);\n\n // Fire and forget - we don't wait for the server\n this.sendSubscribe?.(normalizedPath, allEventTypes, storedQueryParams).catch((err) => {\n console.error('Failed to subscribe:', err);\n });\n }\n\n return unsubscribe;\n }\n\n /**\n * Remove a specific callback from a subscription.\n */\n private unsubscribeCallback(path: string, eventType: EventType, callback: SnapshotCallback): void {\n const pathSubs = this.subscriptions.get(path);\n if (!pathSubs) return;\n\n const eventSubs = pathSubs.get(eventType);\n if (!eventSubs) return;\n\n // Find and remove the callback\n const index = eventSubs.findIndex((entry) => entry.callback === callback);\n if (index !== -1) {\n eventSubs.splice(index, 1);\n }\n\n // Clean up empty arrays\n if (eventSubs.length === 0) {\n pathSubs.delete(eventType);\n }\n\n // If no more subscriptions for this path, unsubscribe from server and clear cache\n if (pathSubs.size === 0) {\n this.subscriptions.delete(path);\n this.orderedChildren.delete(path);\n this.queryParams.delete(path);\n this.cache.deleteTree(path);\n this.sendUnsubscribe?.(path).catch((err) => {\n console.error('Failed to unsubscribe:', err);\n });\n }\n }\n\n /**\n * Remove all subscriptions of a specific event type at a path.\n */\n unsubscribeEventType(path: string, eventType: EventType): void {\n const normalizedPath = path;\n const pathSubs = this.subscriptions.get(normalizedPath);\n if (!pathSubs) return;\n\n // Remove all callbacks for this event type\n pathSubs.delete(eventType);\n\n // If no more subscriptions for this path, unsubscribe from server\n if (pathSubs.size === 0) {\n this.subscriptions.delete(normalizedPath);\n this.orderedChildren.delete(normalizedPath);\n this.queryParams.delete(normalizedPath);\n this.cache.deleteTree(normalizedPath);\n this.sendUnsubscribe?.(normalizedPath).catch((err) => {\n console.error('Failed to unsubscribe:', err);\n });\n } else {\n // Update server with remaining event types (full names)\n const remainingEventTypes = this.getEventTypesForPath(normalizedPath);\n const storedQueryParams = this.queryParams.get(normalizedPath);\n this.sendSubscribe?.(normalizedPath, remainingEventTypes, storedQueryParams).catch((err) => {\n console.error('Failed to update subscription:', err);\n });\n }\n }\n\n /**\n * Remove ALL subscriptions at a path.\n */\n unsubscribeAll(path: string): void {\n const normalizedPath = path;\n if (!this.subscriptions.has(normalizedPath)) return;\n\n this.subscriptions.delete(normalizedPath);\n this.orderedChildren.delete(normalizedPath);\n this.queryParams.delete(normalizedPath);\n this.cache.deleteTree(normalizedPath);\n this.sendUnsubscribe?.(normalizedPath).catch((err) => {\n console.error('Failed to unsubscribe:', err);\n });\n }\n\n /**\n * Handle an incoming event message from the server.\n * Server sends 'put' or 'patch' events; we generate child_* events client-side.\n */\n handleEvent(message: EventMessage): void {\n if (message.ev === 'put') {\n this.handlePutEvent(message);\n } else if (message.ev === 'patch') {\n this.handlePatchEvent(message);\n } else {\n console.warn('Unknown event type:', (message as { ev: string }).ev);\n }\n }\n\n /**\n * Handle a 'put' event - single path change.\n */\n private handlePutEvent(message: PutEventMessage): void {\n const subscriptionPath = message.sp;\n const relativePath = message.p;\n const value = message.v;\n const isVolatile = message.x ?? false;\n const serverTimestamp = message.ts;\n const afterKey = message.ak;\n const orderedKeys = message.k;\n\n // Look up subscriptions by subscription path\n const pathSubs = this.subscriptions.get(subscriptionPath);\n if (!pathSubs) return;\n\n // Convert relative path to absolute\n const absolutePath = relativePath === '/'\n ? subscriptionPath\n : joinPath(subscriptionPath, relativePath);\n\n // Get previous ordered children before updating\n const previousOrder = this.orderedChildren.get(subscriptionPath) ?? [];\n const previousChildSet = new Set(previousOrder);\n\n // Update cache (if value provided - may be omitted for move-only events)\n if (value !== undefined) {\n if (relativePath === '/') {\n // Full snapshot (initial or reconnect)\n this.cache.set(subscriptionPath, value);\n } else if (value === null) {\n // Deletion\n this.cache.removeChild(absolutePath);\n } else {\n // Delta update\n this.cache.updateChild(absolutePath, value);\n }\n }\n\n // Update ordered children tracking\n if (relativePath === '/') {\n // Full snapshot - use server's ordered keys if provided, otherwise extract from value\n if (orderedKeys) {\n this.orderedChildren.set(subscriptionPath, [...orderedKeys]);\n } else if (value && typeof value === 'object' && value !== null) {\n // No explicit order, use object keys\n this.orderedChildren.set(subscriptionPath, Object.keys(value as Record<string, unknown>));\n } else {\n this.orderedChildren.set(subscriptionPath, []);\n }\n } else {\n // Delta update - parse child key from relative path\n const segments = relativePath.split('/').filter(s => s.length > 0);\n if (segments.length > 0) {\n const childKey = segments[0];\n const currentOrder = this.orderedChildren.get(subscriptionPath) ?? [];\n\n if (value === null) {\n // Remove from order\n const newOrder = currentOrder.filter(k => k !== childKey);\n this.orderedChildren.set(subscriptionPath, newOrder);\n } else if (!previousChildSet.has(childKey)) {\n // New child - insert at position based on afterKey\n const newOrder = [...currentOrder];\n this.insertAfterKey(newOrder, childKey, afterKey);\n this.orderedChildren.set(subscriptionPath, newOrder);\n }\n // For existing children, order doesn't change from put (moves come via patch.mv)\n }\n }\n\n // Get current ordered children after update\n const currentOrder = this.orderedChildren.get(subscriptionPath) ?? [];\n const currentChildSet = new Set(currentOrder);\n\n // Fire callbacks based on subscribed event types\n this.fireCallbacks(\n subscriptionPath,\n pathSubs,\n relativePath,\n value,\n previousOrder,\n currentOrder,\n previousChildSet,\n currentChildSet,\n afterKey,\n isVolatile,\n serverTimestamp\n );\n }\n\n /**\n * Handle a 'patch' event - multi-path change and/or moves.\n */\n private handlePatchEvent(message: PatchEventMessage): void {\n const subscriptionPath = message.sp;\n const basePath = message.p;\n const patches = message.v;\n const moves = message.mv;\n const orderedKeys = message.k;\n const isVolatile = message.x ?? false;\n const serverTimestamp = message.ts;\n\n const pathSubs = this.subscriptions.get(subscriptionPath);\n if (!pathSubs) return;\n\n // Get previous ordered children before updating\n const previousOrder = this.orderedChildren.get(subscriptionPath) ?? [];\n const previousChildSet = new Set(previousOrder);\n\n // Track which immediate children are affected by patches\n const affectedChildren = new Set<string>();\n\n // Apply all patches to cache (if any)\n if (patches) {\n for (const [relativePath, value] of Object.entries(patches)) {\n const fullRelativePath = basePath === '/'\n ? '/' + relativePath\n : joinPath(basePath, relativePath);\n const absolutePath = joinPath(subscriptionPath, fullRelativePath);\n\n // Extract immediate child key from the patch path\n const segments = fullRelativePath.split('/').filter(s => s.length > 0);\n if (segments.length > 0) {\n affectedChildren.add(segments[0]);\n }\n\n if (value === null) {\n this.cache.removeChild(absolutePath);\n } else {\n this.cache.updateChild(absolutePath, value);\n }\n }\n }\n\n // Handle moves array\n if (moves && moves.length > 0) {\n this.handleMoves(subscriptionPath, pathSubs, moves, isVolatile, serverTimestamp);\n }\n\n // Handle full reorder via k field\n if (orderedKeys) {\n this.orderedChildren.set(subscriptionPath, [...orderedKeys]);\n }\n\n // Get current ordered children after update\n const currentOrder = this.orderedChildren.get(subscriptionPath) ?? [];\n const currentChildSet = new Set(currentOrder);\n\n // Fire value callbacks\n const valueSubs = pathSubs.get('value');\n if (valueSubs && valueSubs.length > 0) {\n const fullValue = this.cache.get(subscriptionPath).value;\n const snapshot = this.createSnapshot?.(subscriptionPath, fullValue, isVolatile, serverTimestamp);\n if (snapshot) {\n for (const entry of valueSubs) {\n try {\n entry.callback(snapshot, undefined);\n } catch (err) {\n console.error('Error in value subscription callback:', err);\n }\n }\n }\n }\n\n // Fire child_* events for each affected child\n if (patches && affectedChildren.size > 0) {\n const childAddedSubs = pathSubs.get('child_added') ?? [];\n const childChangedSubs = pathSubs.get('child_changed') ?? [];\n const childRemovedSubs = pathSubs.get('child_removed') ?? [];\n\n for (const childKey of affectedChildren) {\n const wasPresent = previousChildSet.has(childKey);\n const isPresent = currentChildSet.has(childKey);\n\n if (!wasPresent && isPresent) {\n // New child added\n const prevKey = this.getPreviousChildKey(currentOrder, childKey);\n this.fireChildAdded(subscriptionPath, childKey, childAddedSubs, prevKey, isVolatile, serverTimestamp);\n } else if (wasPresent && !isPresent) {\n // Child removed\n this.fireChildRemoved(subscriptionPath, childKey, childRemovedSubs, isVolatile, serverTimestamp);\n } else if (wasPresent && isPresent) {\n // Existing child changed\n const prevKey = this.getPreviousChildKey(currentOrder, childKey);\n this.fireChildChanged(subscriptionPath, childKey, childChangedSubs, prevKey, isVolatile, serverTimestamp);\n }\n }\n }\n }\n\n /**\n * Handle moves array - update order and fire child_moved events.\n */\n private handleMoves(\n subscriptionPath: string,\n pathSubs: Map<EventType, SubscriptionEntry[]>,\n moves: MoveEntry[],\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n const childMovedSubs = pathSubs.get('child_moved') ?? [];\n const currentOrder = this.orderedChildren.get(subscriptionPath) ?? [];\n\n for (const move of moves) {\n const { k: childKey, ak: afterKey } = move;\n\n // Remove from current position\n const idx = currentOrder.indexOf(childKey);\n if (idx !== -1) {\n currentOrder.splice(idx, 1);\n }\n\n // Insert at new position\n this.insertAfterKey(currentOrder, childKey, afterKey);\n\n // Fire child_moved event\n if (childMovedSubs.length > 0) {\n const previousChildKey = afterKey === '' ? null : afterKey;\n this.fireChildMoved(subscriptionPath, childKey, childMovedSubs, previousChildKey, isVolatile, serverTimestamp);\n }\n }\n\n // Update stored order\n this.orderedChildren.set(subscriptionPath, currentOrder);\n }\n\n /**\n * Insert a key into an ordered array after a specific key.\n * If afterKey is empty string or undefined, insert at beginning.\n * If afterKey is not found, append at end.\n */\n private insertAfterKey(order: string[], key: string, afterKey?: string): void {\n if (afterKey === '' || afterKey === undefined) {\n // Insert at beginning\n order.unshift(key);\n } else {\n const afterIdx = order.indexOf(afterKey);\n if (afterIdx === -1) {\n // afterKey not found, append at end\n order.push(key);\n } else {\n // Insert after afterKey\n order.splice(afterIdx + 1, 0, key);\n }\n }\n }\n\n /**\n * Get the previous sibling key for a given key in the ordered array.\n */\n private getPreviousChildKey(order: string[], key: string): string | null {\n const idx = order.indexOf(key);\n if (idx <= 0) return null;\n return order[idx - 1];\n }\n\n /**\n * Fire callbacks for subscribed event types.\n */\n private fireCallbacks(\n subscriptionPath: string,\n pathSubs: Map<EventType, SubscriptionEntry[]>,\n relativePath: string,\n value: unknown,\n previousOrder: string[],\n currentOrder: string[],\n previousChildSet: Set<string>,\n currentChildSet: Set<string>,\n afterKey: string | undefined,\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n // Fire 'value' callbacks with full snapshot\n const valueSubs = pathSubs.get('value');\n if (valueSubs && valueSubs.length > 0) {\n const fullValue = this.cache.get(subscriptionPath).value;\n const snapshot = this.createSnapshot?.(subscriptionPath, fullValue, isVolatile, serverTimestamp);\n if (snapshot) {\n for (const entry of valueSubs) {\n try {\n entry.callback(snapshot, undefined);\n } catch (err) {\n console.error('Error in value subscription callback:', err);\n }\n }\n }\n }\n\n // Generate and fire child_* events\n this.fireChildEvents(\n subscriptionPath,\n pathSubs,\n relativePath,\n value,\n previousOrder,\n currentOrder,\n previousChildSet,\n currentChildSet,\n afterKey,\n isVolatile,\n serverTimestamp\n );\n }\n\n /**\n * Generate and fire child_added, child_changed, child_removed events.\n * child_moved is handled separately via handleMoves().\n */\n private fireChildEvents(\n subscriptionPath: string,\n pathSubs: Map<EventType, SubscriptionEntry[]>,\n relativePath: string,\n value: unknown,\n previousOrder: string[],\n currentOrder: string[],\n previousChildSet: Set<string>,\n currentChildSet: Set<string>,\n afterKey: string | undefined,\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n const childAddedSubs = pathSubs.get('child_added') ?? [];\n const childChangedSubs = pathSubs.get('child_changed') ?? [];\n const childRemovedSubs = pathSubs.get('child_removed') ?? [];\n\n // No child subscriptions, skip\n if (childAddedSubs.length === 0 && childChangedSubs.length === 0 && childRemovedSubs.length === 0) {\n return;\n }\n\n if (relativePath === '/') {\n // Full snapshot - compare old and new children\n // Find added children (fire in order)\n for (const key of currentOrder) {\n if (!previousChildSet.has(key)) {\n const prevKey = this.getPreviousChildKey(currentOrder, key);\n this.fireChildAdded(subscriptionPath, key, childAddedSubs, prevKey, isVolatile, serverTimestamp);\n }\n }\n\n // Find removed children\n for (const key of previousOrder) {\n if (!currentChildSet.has(key)) {\n this.fireChildRemoved(subscriptionPath, key, childRemovedSubs, isVolatile, serverTimestamp);\n }\n }\n } else {\n // Delta update - parse relative path to find immediate child\n const segments = relativePath.split('/').filter(s => s.length > 0);\n if (segments.length === 0) return;\n\n const childKey = segments[0];\n\n if (value === null) {\n // Child was deleted\n if (previousChildSet.has(childKey) && !currentChildSet.has(childKey)) {\n this.fireChildRemoved(subscriptionPath, childKey, childRemovedSubs, isVolatile, serverTimestamp);\n }\n } else if (!previousChildSet.has(childKey)) {\n // New child - use afterKey if provided, otherwise compute from current order\n const prevKey = afterKey !== undefined\n ? (afterKey === '' ? null : afterKey)\n : this.getPreviousChildKey(currentOrder, childKey);\n this.fireChildAdded(subscriptionPath, childKey, childAddedSubs, prevKey, isVolatile, serverTimestamp);\n } else {\n // Existing child changed\n const prevKey = this.getPreviousChildKey(currentOrder, childKey);\n this.fireChildChanged(subscriptionPath, childKey, childChangedSubs, prevKey, isVolatile, serverTimestamp);\n }\n }\n }\n\n /**\n * Fire child_added callbacks for a child key.\n */\n private fireChildAdded(\n subscriptionPath: string,\n childKey: string,\n subs: SubscriptionEntry[],\n previousChildKey: string | null,\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n if (subs.length === 0) return;\n\n const childPath = joinPath(subscriptionPath, childKey);\n const childValue = this.cache.get(childPath).value;\n const snapshot = this.createSnapshot?.(childPath, childValue, isVolatile, serverTimestamp);\n\n if (snapshot) {\n for (const entry of subs) {\n try {\n entry.callback(snapshot, previousChildKey);\n } catch (err) {\n console.error('Error in child_added subscription callback:', err);\n }\n }\n }\n }\n\n /**\n * Fire child_changed callbacks for a child key.\n */\n private fireChildChanged(\n subscriptionPath: string,\n childKey: string,\n subs: SubscriptionEntry[],\n previousChildKey: string | null,\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n if (subs.length === 0) return;\n\n const childPath = joinPath(subscriptionPath, childKey);\n const childValue = this.cache.get(childPath).value;\n const snapshot = this.createSnapshot?.(childPath, childValue, isVolatile, serverTimestamp);\n\n if (snapshot) {\n for (const entry of subs) {\n try {\n entry.callback(snapshot, previousChildKey);\n } catch (err) {\n console.error('Error in child_changed subscription callback:', err);\n }\n }\n }\n }\n\n /**\n * Fire child_removed callbacks for a child key.\n */\n private fireChildRemoved(\n subscriptionPath: string,\n childKey: string,\n subs: SubscriptionEntry[],\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n if (subs.length === 0) return;\n\n const childPath = joinPath(subscriptionPath, childKey);\n // For removed children, we may not have the value anymore\n // Create snapshot with null value\n const snapshot = this.createSnapshot?.(childPath, null, isVolatile, serverTimestamp);\n\n if (snapshot) {\n for (const entry of subs) {\n try {\n // previousChildKey is not meaningful for removed children\n entry.callback(snapshot, undefined);\n } catch (err) {\n console.error('Error in child_removed subscription callback:', err);\n }\n }\n }\n }\n\n /**\n * Fire child_moved callbacks for a child key.\n */\n private fireChildMoved(\n subscriptionPath: string,\n childKey: string,\n subs: SubscriptionEntry[],\n previousChildKey: string | null,\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n if (subs.length === 0) return;\n\n const childPath = joinPath(subscriptionPath, childKey);\n const childValue = this.cache.get(childPath).value;\n const snapshot = this.createSnapshot?.(childPath, childValue, isVolatile, serverTimestamp);\n\n if (snapshot) {\n for (const entry of subs) {\n try {\n entry.callback(snapshot, previousChildKey);\n } catch (err) {\n console.error('Error in child_moved subscription callback:', err);\n }\n }\n }\n }\n\n /**\n * Get all event types currently subscribed at a path.\n */\n private getEventTypesForPath(path: string): EventType[] {\n const pathSubs = this.subscriptions.get(path);\n if (!pathSubs) return [];\n return Array.from(pathSubs.keys());\n }\n\n /**\n * Clear all subscriptions (e.g., on disconnect).\n */\n clear(): void {\n this.subscriptions.clear();\n this.orderedChildren.clear();\n this.queryParams.clear();\n this.cache.clear();\n }\n\n /**\n * Check if there are any subscriptions at a path.\n */\n hasSubscriptions(path: string): boolean {\n return this.subscriptions.has(path);\n }\n\n /**\n * Check if a path is \"covered\" by an active subscription.\n *\n * A path is covered if:\n * - There's an active 'value' subscription at that exact path, OR\n * - There's an active 'value' subscription at an ancestor path\n *\n * Child event subscriptions (child_added, etc.) don't provide full coverage\n * because they only notify of changes, not the complete value.\n */\n isPathCovered(path: string): boolean {\n const normalized = normalizePath(path);\n\n // Check exact match - must have 'value' subscription\n if (this.hasValueSubscription(normalized)) {\n return true;\n }\n\n // Check ancestors - walk up the path tree\n const segments = normalized.split('/').filter((s) => s.length > 0);\n\n for (let i = segments.length - 1; i >= 0; i--) {\n const ancestorPath = i === 0 ? '/' : '/' + segments.slice(0, i).join('/');\n if (this.hasValueSubscription(ancestorPath)) {\n return true;\n }\n }\n\n // Check root\n if (normalized !== '/' && this.hasValueSubscription('/')) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Check if there's a 'value' subscription at a path.\n */\n private hasValueSubscription(path: string): boolean {\n const pathSubs = this.subscriptions.get(path);\n if (!pathSubs) return false;\n const valueSubs = pathSubs.get('value');\n return valueSubs !== undefined && valueSubs.length > 0;\n }\n\n /**\n * Get a cached value if the path is covered by an active subscription.\n *\n * Returns { value, found: true } if we have cached data for this path\n * (either exact match or extractable from a cached ancestor).\n *\n * Returns { value: undefined, found: false } if:\n * - The path is not covered by any subscription, OR\n * - We don't have cached data yet\n */\n getCachedValue(path: string): { value: unknown; found: boolean } {\n const normalized = normalizePath(path);\n\n // First check if the path is covered by a subscription\n if (!this.isPathCovered(normalized)) {\n return { value: undefined, found: false };\n }\n\n // Path is covered, try to get from cache\n return this.cache.get(normalized);\n }\n\n /**\n * Get the cache size (for testing/debugging).\n */\n get cacheSize(): number {\n return this.cache.size;\n }\n}\n","/**\n * WebSocketClient - wrapper around WebSocket with event handling and reconnection support.\n * Works in both browser (native WebSocket) and Node.js (ws package).\n */\n\nimport WebSocketNode from 'ws';\n\n// Use native WebSocket in browser, ws package in Node.js\nconst WebSocketImpl: typeof WebSocket =\n typeof WebSocket !== 'undefined' ? WebSocket : (WebSocketNode as unknown as typeof WebSocket);\n\nexport type WebSocketState = 'disconnected' | 'connecting' | 'connected';\n\nexport interface WebSocketClientOptions {\n onMessage: (data: string) => void;\n onOpen: () => void;\n onClose: (code: number, reason: string) => void;\n onError: (error: Event) => void;\n}\n\nexport class WebSocketClient {\n private ws: WebSocket | null = null;\n private options: WebSocketClientOptions;\n private _state: WebSocketState = 'disconnected';\n\n constructor(options: WebSocketClientOptions) {\n this.options = options;\n }\n\n get state(): WebSocketState {\n return this._state;\n }\n\n get connected(): boolean {\n return this._state === 'connected';\n }\n\n /**\n * Connect to a WebSocket server.\n */\n connect(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this._state !== 'disconnected') {\n reject(new Error('Already connected or connecting'));\n return;\n }\n\n this._state = 'connecting';\n\n try {\n this.ws = new WebSocketImpl(url) as WebSocket;\n } catch (err) {\n this._state = 'disconnected';\n reject(err);\n return;\n }\n\n const onOpen = () => {\n cleanup();\n this._state = 'connected';\n this.setupEventHandlers();\n resolve();\n this.options.onOpen();\n };\n\n const onError = (event: Event) => {\n cleanup();\n this._state = 'disconnected';\n this.ws = null;\n reject(new Error('WebSocket connection failed'));\n this.options.onError(event);\n };\n\n const onClose = (event: CloseEvent) => {\n cleanup();\n this._state = 'disconnected';\n this.ws = null;\n reject(new Error(`WebSocket closed: ${event.code} ${event.reason}`));\n };\n\n const cleanup = () => {\n this.ws?.removeEventListener('open', onOpen);\n this.ws?.removeEventListener('error', onError);\n this.ws?.removeEventListener('close', onClose);\n };\n\n this.ws.addEventListener('open', onOpen);\n this.ws.addEventListener('error', onError);\n this.ws.addEventListener('close', onClose);\n });\n }\n\n /**\n * Set up persistent event handlers after connection is established.\n */\n private setupEventHandlers(): void {\n if (!this.ws) return;\n\n this.ws.addEventListener('message', (event: MessageEvent) => {\n this.options.onMessage(event.data as string);\n });\n\n this.ws.addEventListener('close', (event: CloseEvent) => {\n this._state = 'disconnected';\n this.ws = null;\n this.options.onClose(event.code, event.reason);\n });\n\n this.ws.addEventListener('error', (event: Event) => {\n this.options.onError(event);\n });\n }\n\n /**\n * Send a message over the WebSocket.\n */\n send(data: string): void {\n if (!this.ws || this._state !== 'connected') {\n throw new Error('WebSocket not connected');\n }\n this.ws.send(data);\n }\n\n /**\n * Close the WebSocket connection.\n */\n close(code: number = 1000, reason: string = 'Client disconnect'): void {\n if (this.ws) {\n this.ws.close(code, reason);\n this.ws = null;\n }\n this._state = 'disconnected';\n }\n}\n","/**\n * OnDisconnect - registers operations to perform on the server when this client disconnects.\n */\n\nimport type { LarkDatabase } from './LarkDatabase';\nimport { OnDisconnectAction } from './protocol/constants';\n\nexport class OnDisconnect {\n private readonly _db: LarkDatabase;\n private readonly _path: string;\n\n constructor(db: LarkDatabase, path: string) {\n this._db = db;\n this._path = path;\n }\n\n /**\n * Set a value when disconnected.\n */\n async set(value: unknown): Promise<void> {\n await this._db._sendOnDisconnect(this._path, OnDisconnectAction.SET, value);\n }\n\n /**\n * Update values when disconnected.\n */\n async update(values: Record<string, unknown>): Promise<void> {\n await this._db._sendOnDisconnect(this._path, OnDisconnectAction.UPDATE, values);\n }\n\n /**\n * Remove data when disconnected.\n */\n async remove(): Promise<void> {\n await this._db._sendOnDisconnect(this._path, OnDisconnectAction.DELETE);\n }\n\n /**\n * Cancel any pending onDisconnect handlers at this location.\n */\n async cancel(): Promise<void> {\n await this._db._sendOnDisconnect(this._path, OnDisconnectAction.CANCEL);\n }\n\n /**\n * Set a value with priority when disconnected.\n */\n async setWithPriority(value: unknown, priority: number | string): Promise<void> {\n await this._db._sendOnDisconnect(this._path, OnDisconnectAction.SET, value, priority);\n }\n}\n","/**\n * Push ID generation - Firebase-compatible chronologically-sortable IDs.\n *\n * Format: 20 characters\n * - First 8 chars: timestamp (milliseconds since epoch, base64-encoded)\n * - Last 12 chars: random suffix (incremented on same-millisecond calls)\n *\n * This ensures:\n * - IDs created later sort after IDs created earlier\n * - IDs created in the same millisecond are unique and still sort correctly\n */\n\nconst PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';\n\n// Persistent state for generating unique IDs within the same millisecond\nlet lastPushTime = 0;\nlet lastRandChars: number[] = [];\n\n/**\n * Generate a Firebase-compatible push ID.\n */\nexport function generatePushId(): string {\n let now = Date.now();\n const duplicateTime = now === lastPushTime;\n lastPushTime = now;\n\n // Encode timestamp in first 8 characters\n const timeChars = new Array(8);\n for (let i = 7; i >= 0; i--) {\n timeChars[i] = PUSH_CHARS.charAt(now % 64);\n now = Math.floor(now / 64);\n }\n\n let id = timeChars.join('');\n\n if (!duplicateTime) {\n // New timestamp - generate fresh random suffix\n lastRandChars = [];\n for (let i = 0; i < 12; i++) {\n lastRandChars.push(Math.floor(Math.random() * 64));\n }\n } else {\n // Same timestamp - increment the random suffix\n // This ensures uniqueness even with multiple calls in the same millisecond\n let i = 11;\n while (i >= 0 && lastRandChars[i] === 63) {\n lastRandChars[i] = 0;\n i--;\n }\n if (i >= 0) {\n lastRandChars[i]++;\n }\n }\n\n // Append random suffix\n for (let i = 0; i < 12; i++) {\n id += PUSH_CHARS.charAt(lastRandChars[i]);\n }\n\n return id;\n}\n","/**\n * DatabaseReference - a reference to a specific path in the database.\n * Immutable - navigation returns new references.\n */\n\nimport type { DataSnapshot } from './DataSnapshot';\nimport type { LarkDatabase } from './LarkDatabase';\nimport { LarkError } from './LarkError';\nimport { OnDisconnect } from './OnDisconnect';\nimport { ErrorCode, EventType } from './protocol/constants';\nimport { QueryParams, TxOperation } from './protocol/messages';\nimport { getKey, getParentPath, joinPath, normalizePath } from './utils/path';\nimport { generatePushId } from './utils/pushid';\n\n/** Result of a transaction operation */\nexport interface TransactionResult {\n /** Whether the transaction was committed (always true on success) */\n committed: boolean;\n /** Snapshot of the data after the transaction */\n snapshot: DataSnapshot;\n}\n\n/** Default maximum retries for optimistic transactions */\nconst DEFAULT_MAX_RETRIES = 25;\n\nexport type SnapshotCallback = (snapshot: DataSnapshot, previousChildKey?: string | null) => void;\n\nexport interface QueryState {\n orderBy?: 'key' | 'priority' | 'child' | 'value';\n orderByChildPath?: string;\n limitToFirst?: number;\n limitToLast?: number;\n startAt?: { value: unknown; key?: string };\n endAt?: { value: unknown; key?: string };\n equalTo?: { value: unknown; key?: string };\n}\n\nexport class DatabaseReference {\n private readonly _db: LarkDatabase;\n private readonly _path: string;\n private readonly _query: QueryState;\n\n constructor(db: LarkDatabase, path: string, query: QueryState = {}) {\n this._db = db;\n this._path = normalizePath(path);\n this._query = query;\n }\n\n /**\n * The path of this reference.\n */\n get path(): string {\n return this._path;\n }\n\n /**\n * The last segment of the path (the \"key\"), or null for root.\n */\n get key(): string | null {\n return getKey(this._path);\n }\n\n /**\n * Get a reference to the parent node, or null if this is root.\n */\n get parent(): DatabaseReference | null {\n if (this._path === '/') return null;\n const parentPath = getParentPath(this._path);\n return new DatabaseReference(this._db, parentPath);\n }\n\n /**\n * Get a reference to the root of the database.\n */\n get root(): DatabaseReference {\n return new DatabaseReference(this._db, '');\n }\n\n // ============================================\n // Navigation\n // ============================================\n\n /**\n * Get a reference to a child path.\n */\n child(path: string): DatabaseReference {\n const childPath = joinPath(this._path, path);\n return new DatabaseReference(this._db, childPath);\n }\n\n // ============================================\n // Write Operations\n // ============================================\n\n /**\n * Set the data at this location, overwriting any existing data.\n */\n async set(value: unknown): Promise<void> {\n await this._db._sendSet(this._path, value);\n }\n\n /**\n * Update specific children at this location without overwriting other children.\n *\n * Also supports Firebase-style multi-path updates when keys look like paths\n * (start with '/'). In this mode, each path is written atomically as a transaction.\n *\n * @example\n * ```javascript\n * // Normal update (merge at single path)\n * await ref.update({ score: 10, name: 'Riley' });\n *\n * // Multi-path update (atomic writes to multiple paths)\n * await db.ref().update({\n * '/users/alice/score': 100,\n * '/users/bob/score': 200,\n * '/leaderboard/alice': null // null = delete\n * });\n * ```\n */\n async update(values: Record<string, unknown>): Promise<void> {\n // Check if any key looks like a path (starts with '/')\n const hasPathKeys = Object.keys(values).some((key) => key.startsWith('/'));\n\n if (hasPathKeys) {\n // Multi-path mode: use transaction for atomic writes\n const ops: TxOperation[] = [];\n\n for (const [key, value] of Object.entries(values)) {\n // Resolve path relative to this ref\n const fullPath = key.startsWith('/')\n ? joinPath(this._path, key)\n : joinPath(this._path, key);\n const normalizedPath = normalizePath(fullPath) || '/';\n\n if (value === null) {\n // null = delete\n ops.push({ o: 'd', p: normalizedPath });\n } else {\n // set the value (not merge, matching Firebase behavior)\n ops.push({ o: 's', p: normalizedPath, v: value });\n }\n }\n\n await this._db._sendTransaction(ops);\n } else {\n // Normal update (merge at single path)\n await this._db._sendUpdate(this._path, values);\n }\n }\n\n /**\n * Remove the data at this location.\n */\n async remove(): Promise<void> {\n await this._db._sendDelete(this._path);\n }\n\n /**\n * Generate a new child location with a unique key and optionally set its value.\n *\n * If value is provided, sets the value and returns a Promise that resolves\n * to the new reference.\n *\n * If no value is provided, returns a reference immediately with a client-generated\n * push key (you can then call set() on it).\n */\n push(value?: unknown): DatabaseReference | Promise<DatabaseReference> {\n if (value === undefined) {\n // No value - return reference with client-generated key immediately\n const key = generatePushId();\n return this.child(key);\n }\n\n // Value provided - send to server and return promise\n return this._db._sendPush(this._path, value).then((key) => {\n return this.child(key);\n });\n }\n\n /**\n * Set the data with a priority value for ordering.\n */\n async setWithPriority(value: unknown, priority: number | string): Promise<void> {\n await this._db._sendSet(this._path, value, priority);\n }\n\n /**\n * Set the priority of the data at this location.\n */\n async setPriority(priority: number | string): Promise<void> {\n // To set only priority, we need to set .priority on the special path\n // For now, we'll use setWithPriority with the current value\n // This is a simplified implementation\n console.warn('setPriority: fetching current value to preserve it');\n const snapshot = await this.once();\n await this.setWithPriority(snapshot.val(), priority);\n }\n\n /**\n * Atomically modify the data at this location using optimistic concurrency.\n *\n * The update function receives the current value and should return the new\n * value. If the data changed on the server before the write could be\n * committed, the function is called again with the new value, and the\n * process repeats until successful or the maximum retries are exceeded.\n *\n * @example\n * ```javascript\n * // Increment a counter atomically\n * const result = await ref.transaction(currentValue => {\n * return (currentValue || 0) + 1;\n * });\n * console.log('New value:', result.snapshot.val());\n * ```\n *\n * @param updateFunction - Function that receives current value and returns new value.\n * Return undefined to abort the transaction.\n * @param maxRetries - Maximum number of retries (default: 25)\n * @returns TransactionResult with committed status and final snapshot\n */\n async transaction(\n updateFunction: (currentValue: unknown) => unknown,\n maxRetries: number = DEFAULT_MAX_RETRIES\n ): Promise<TransactionResult> {\n let retries = 0;\n\n while (retries < maxRetries) {\n // Step 1: Read current value\n const currentSnapshot = await this.once();\n const currentValue = currentSnapshot.val();\n\n // Step 2: Call update function\n const newValue = updateFunction(currentValue);\n\n // Step 3: If undefined returned, abort\n if (newValue === undefined) {\n return {\n committed: false,\n snapshot: currentSnapshot,\n };\n }\n\n // Step 4: Build transaction with condition + set\n const ops: TxOperation[] = [\n { o: 'c', p: this._path, v: currentValue },\n { o: 's', p: this._path, v: newValue },\n ];\n\n try {\n // Step 5: Try to commit\n await this._db._sendTransaction(ops);\n\n // Success! Read back the value for the result snapshot\n const finalSnapshot = await this.once();\n return {\n committed: true,\n snapshot: finalSnapshot,\n };\n } catch (error) {\n // Step 6: If condition failed, retry\n if (error instanceof LarkError && error.code === ErrorCode.CONDITION_FAILED) {\n retries++;\n continue;\n }\n // Other errors should propagate\n throw error;\n }\n }\n\n // Max retries exceeded\n throw new LarkError(\n 'max_retries_exceeded',\n `Transaction failed after ${maxRetries} retries`\n );\n }\n\n // ============================================\n // Read Operations\n // ============================================\n\n /**\n * Read the data at this location once.\n */\n async once(eventType: 'value' = 'value'): Promise<DataSnapshot> {\n if (eventType !== 'value') {\n throw new Error('once() only supports \"value\" event type');\n }\n return this._db._sendOnce(this._path, this._buildQueryParams());\n }\n\n // ============================================\n // Subscriptions\n // ============================================\n\n /**\n * Subscribe to events at this location.\n * Returns an unsubscribe function.\n */\n on(eventType: EventType, callback: SnapshotCallback): () => void {\n return this._db._subscribe(this._path, eventType, callback, this._buildQueryParams());\n }\n\n /**\n * Unsubscribe from events.\n * If eventType is specified, removes all listeners of that type.\n * If no eventType, removes ALL listeners at this path.\n */\n off(eventType?: EventType): void {\n if (eventType) {\n this._db._unsubscribeEventType(this._path, eventType);\n } else {\n this._db._unsubscribeAll(this._path);\n }\n }\n\n // ============================================\n // OnDisconnect\n // ============================================\n\n /**\n * Get an OnDisconnect handler for this location.\n */\n onDisconnect(): OnDisconnect {\n return new OnDisconnect(this._db, this._path);\n }\n\n // ============================================\n // Query Modifiers\n // ============================================\n\n /**\n * Order results by key.\n */\n orderByKey(): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n orderBy: 'key',\n });\n }\n\n /**\n * Order results by priority.\n */\n orderByPriority(): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n orderBy: 'priority',\n });\n }\n\n /**\n * Order results by a child key.\n */\n orderByChild(path: string): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n orderBy: 'child',\n orderByChildPath: path,\n });\n }\n\n /**\n * Order results by value.\n */\n orderByValue(): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n orderBy: 'value',\n });\n }\n\n /**\n * Limit to the first N results.\n */\n limitToFirst(limit: number): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n limitToFirst: limit,\n });\n }\n\n /**\n * Limit to the last N results.\n */\n limitToLast(limit: number): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n limitToLast: limit,\n });\n }\n\n /**\n * Start at a specific value/key.\n */\n startAt(value: unknown, key?: string): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n startAt: { value, key },\n });\n }\n\n /**\n * End at a specific value/key.\n */\n endAt(value: unknown, key?: string): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n endAt: { value, key },\n });\n }\n\n /**\n * Filter to items equal to a specific value.\n */\n equalTo(value: unknown, key?: string): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n equalTo: { value, key },\n });\n }\n\n // ============================================\n // Internal Helpers\n // ============================================\n\n /**\n * Build query parameters for wire protocol.\n */\n private _buildQueryParams(): QueryParams | undefined {\n const params: QueryParams = {};\n let hasParams = false;\n\n // Order by\n if (this._query.orderBy === 'key') {\n params.orderBy = 'key';\n hasParams = true;\n } else if (this._query.orderBy === 'priority') {\n params.orderBy = 'priority';\n hasParams = true;\n } else if (this._query.orderBy === 'child') {\n params.orderBy = 'child';\n if (this._query.orderByChildPath) {\n params.orderByChild = this._query.orderByChildPath;\n }\n hasParams = true;\n } else if (this._query.orderBy === 'value') {\n params.orderBy = 'value';\n hasParams = true;\n }\n\n // Limits\n if (this._query.limitToFirst !== undefined) {\n params.limitToFirst = this._query.limitToFirst;\n hasParams = true;\n }\n\n if (this._query.limitToLast !== undefined) {\n params.limitToLast = this._query.limitToLast;\n hasParams = true;\n }\n\n // Range queries\n if (this._query.startAt !== undefined) {\n params.startAt = this._query.startAt.value;\n if (this._query.startAt.key !== undefined) {\n params.startAtKey = this._query.startAt.key;\n }\n hasParams = true;\n }\n\n if (this._query.endAt !== undefined) {\n params.endAt = this._query.endAt.value;\n if (this._query.endAt.key !== undefined) {\n params.endAtKey = this._query.endAt.key;\n }\n hasParams = true;\n }\n\n if (this._query.equalTo !== undefined) {\n params.equalTo = this._query.equalTo.value;\n if (this._query.equalTo.key !== undefined) {\n params.equalToKey = this._query.equalTo.key;\n }\n hasParams = true;\n }\n\n return hasParams ? params : undefined;\n }\n\n /**\n * Returns the absolute URL for this database location.\n * Format: https://db.lark.sh/project/database/path/to/data\n */\n toString(): string {\n const baseUrl = this._db._getBaseUrl();\n // For root, just return base URL; otherwise append path (path already has leading slash)\n if (this._path === '/') {\n return baseUrl;\n }\n return `${baseUrl}${this._path}`;\n }\n}\n","/**\n * DataSnapshot - an immutable snapshot of data at a location.\n * Received in event callbacks and from once() operations.\n */\n\nimport type { DatabaseReference } from './DatabaseReference';\nimport type { LarkDatabase } from './LarkDatabase';\nimport { getKey, getValueAtPath, joinPath, normalizePath } from './utils/path';\n\nexport class DataSnapshot {\n private readonly _data: unknown;\n private readonly _path: string;\n private readonly _db: LarkDatabase;\n private readonly _volatile: boolean;\n private readonly _priority: number | string | null;\n private readonly _serverTimestamp: number | null;\n\n constructor(\n data: unknown,\n path: string,\n db: LarkDatabase,\n options: { volatile?: boolean; priority?: number | string | null; serverTimestamp?: number | null } = {}\n ) {\n this._data = data;\n this._path = normalizePath(path);\n this._db = db;\n this._volatile = options.volatile ?? false;\n this._priority = options.priority ?? null;\n this._serverTimestamp = options.serverTimestamp ?? null;\n }\n\n /**\n * Get a DatabaseReference for the location of this snapshot.\n */\n get ref(): DatabaseReference {\n return this._db.ref(this._path);\n }\n\n /**\n * Get the last segment of the path (the \"key\"), or null for root.\n */\n get key(): string | null {\n return getKey(this._path);\n }\n\n /**\n * Get the raw data value.\n */\n val(): unknown {\n return this._data;\n }\n\n /**\n * Check if data exists at this location (is not null/undefined).\n */\n exists(): boolean {\n return this._data !== null && this._data !== undefined;\n }\n\n /**\n * Get a child snapshot at the specified path.\n */\n child(path: string): DataSnapshot {\n const childPath = joinPath(this._path, path);\n const childData = getValueAtPath(this._data, path);\n return new DataSnapshot(childData, childPath, this._db, {\n volatile: this._volatile,\n serverTimestamp: this._serverTimestamp,\n });\n }\n\n /**\n * Check if this snapshot has any children.\n */\n hasChildren(): boolean {\n if (typeof this._data !== 'object' || this._data === null) {\n return false;\n }\n return Object.keys(this._data).length > 0;\n }\n\n /**\n * Check if this snapshot has a specific child.\n */\n hasChild(path: string): boolean {\n const childData = getValueAtPath(this._data, path);\n return childData !== undefined && childData !== null;\n }\n\n /**\n * Get the number of children.\n */\n numChildren(): number {\n if (typeof this._data !== 'object' || this._data === null) {\n return 0;\n }\n return Object.keys(this._data).length;\n }\n\n /**\n * Iterate over children. Return true from callback to stop iteration.\n */\n forEach(callback: (child: DataSnapshot) => boolean | void): void {\n if (typeof this._data !== 'object' || this._data === null) {\n return;\n }\n\n const keys = Object.keys(this._data);\n for (const key of keys) {\n const childSnap = this.child(key);\n if (callback(childSnap) === true) {\n break;\n }\n }\n }\n\n /**\n * Get the priority of the data at this location.\n */\n getPriority(): number | string | null {\n return this._priority;\n }\n\n /**\n * Check if this snapshot was from a volatile (high-frequency) update.\n * This is a Lark extension not present in Firebase.\n */\n isVolatile(): boolean {\n return this._volatile;\n }\n\n /**\n * Get the server timestamp for this snapshot (milliseconds since Unix epoch).\n * Only present on volatile value events. Use deltas between timestamps for\n * interpolation rather than absolute times to avoid clock sync issues.\n * This is a Lark extension not present in Firebase.\n */\n getServerTimestamp(): number | null {\n return this._serverTimestamp;\n }\n\n /**\n * Export the snapshot data as JSON (alias for val()).\n */\n toJSON(): unknown {\n return this._data;\n }\n}\n","/**\n * Simple JWT payload decoder (no verification - server validates).\n * JWTs are three base64url-encoded parts separated by dots: header.payload.signature\n */\n\nexport interface JwtPayload {\n sub: string; // User ID\n aud: string; // Database ID\n project: string; // Project ID\n server: string; // Server ID\n provider: string; // Auth provider\n claims: Record<string, unknown>; // Custom claims\n iss: string; // Issuer\n iat: number; // Issued at\n exp: number; // Expiration\n}\n\n/**\n * Decode a JWT payload without verification.\n * The server validates the token - we just need to read the claims.\n */\nexport function decodeJwtPayload(token: string): JwtPayload {\n const parts = token.split('.');\n if (parts.length !== 3) {\n throw new Error('Invalid JWT format');\n }\n\n const payload = parts[1];\n\n // Base64url decode (replace - with +, _ with /, add padding)\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n\n // Decode - works in both browser and Node.js\n let decoded: string;\n if (typeof atob === 'function') {\n // Browser\n decoded = atob(padded);\n } else {\n // Node.js\n decoded = Buffer.from(padded, 'base64').toString('utf-8');\n }\n\n return JSON.parse(decoded) as JwtPayload;\n}\n","/**\n * LarkDatabase - the main entry point for connecting to a Lark database.\n */\n\nimport { Coordinator } from './connection/Coordinator';\nimport { MessageQueue } from './connection/MessageQueue';\nimport { PendingWriteManager } from './connection/PendingWriteManager';\nimport { SubscriptionManager, SnapshotCallback } from './connection/SubscriptionManager';\nimport { WebSocketClient } from './connection/WebSocketClient';\nimport { DatabaseReference } from './DatabaseReference';\nimport { DataSnapshot } from './DataSnapshot';\nimport { LarkError } from './LarkError';\nimport { DEFAULT_COORDINATOR_URL, EventType } from './protocol/constants';\nimport {\n ClientMessage,\n ServerMessage,\n isAckMessage,\n isEventMessage,\n isNackMessage,\n isPingMessage,\n QueryParams,\n TxOperation,\n TransactionMessage,\n} from './protocol/messages';\nimport { decodeJwtPayload } from './utils/jwt';\nimport { normalizePath } from './utils/path';\n\nexport interface ConnectOptions {\n /** User's auth token (from your auth system) */\n token?: string;\n\n /** Connect anonymously (server assigns a UID) */\n anonymous?: boolean;\n\n /** Coordinator URL (default: https://db.lark.dev) */\n coordinator?: string;\n}\n\nexport interface AuthInfo {\n uid: string;\n provider: string;\n token: Record<string, unknown>;\n}\n\n// ============================================\n// Transaction Types (Public API)\n// ============================================\n\n/** A set operation in a transaction */\nexport interface TransactionSetOp {\n op: 'set';\n path: string;\n value: unknown;\n}\n\n/** An update (merge) operation in a transaction */\nexport interface TransactionUpdateOp {\n op: 'update';\n path: string;\n value: Record<string, unknown>;\n}\n\n/** A delete operation in a transaction */\nexport interface TransactionDeleteOp {\n op: 'delete';\n path: string;\n}\n\n/** A condition check in a transaction (for compare-and-swap) */\nexport interface TransactionConditionOp {\n op: 'condition';\n path: string;\n value: unknown;\n}\n\n/** A single operation in a transaction (array syntax) */\nexport type TransactionOp =\n | TransactionSetOp\n | TransactionUpdateOp\n | TransactionDeleteOp\n | TransactionConditionOp;\n\n/** Object syntax for transactions: path -> value (null = delete) */\nexport type TransactionObject = Record<string, unknown>;\n\ntype ConnectionState = 'disconnected' | 'connecting' | 'connected';\n\nexport class LarkDatabase {\n private _state: ConnectionState = 'disconnected';\n private _auth: AuthInfo | null = null;\n private _databaseId: string | null = null;\n private _coordinatorUrl: string | null = null;\n private _volatilePaths: string[] = [];\n\n private ws: WebSocketClient | null = null;\n private messageQueue: MessageQueue;\n private subscriptionManager: SubscriptionManager;\n private pendingWrites: PendingWriteManager;\n\n // Event callbacks\n private connectCallbacks = new Set<() => void>();\n private disconnectCallbacks = new Set<() => void>();\n private errorCallbacks = new Set<(error: Error) => void>();\n\n constructor() {\n this.messageQueue = new MessageQueue();\n this.subscriptionManager = new SubscriptionManager();\n this.pendingWrites = new PendingWriteManager();\n }\n\n // ============================================\n // Connection State\n // ============================================\n\n /**\n * Whether the database is currently connected.\n */\n get connected(): boolean {\n return this._state === 'connected';\n }\n\n /**\n * Current auth info, or null if not connected.\n */\n get auth(): AuthInfo | null {\n return this._auth;\n }\n\n /**\n * @internal Get the base URL for reference toString().\n */\n _getBaseUrl(): string {\n if (this._coordinatorUrl && this._databaseId) {\n return `${this._coordinatorUrl}/${this._databaseId}`;\n }\n return 'lark://';\n }\n\n /**\n * Get the volatile path patterns from the server.\n * These patterns indicate which paths should use unreliable transport.\n * WebSocket always uses reliable transport, but this is stored for future UDP support.\n */\n get volatilePaths(): string[] {\n return this._volatilePaths;\n }\n\n /**\n * Check if there are any pending writes waiting for acknowledgment.\n * Useful for showing \"saving...\" indicators in UI.\n */\n hasPendingWrites(): boolean {\n return this.pendingWrites.pendingCount > 0;\n }\n\n /**\n * Get the number of pending writes waiting for acknowledgment.\n */\n getPendingWriteCount(): number {\n return this.pendingWrites.pendingCount;\n }\n\n /**\n * Clear all pending writes.\n * Call this if you don't want to retry writes on reconnect.\n */\n clearPendingWrites(): void {\n this.pendingWrites.clear();\n }\n\n // ============================================\n // Connection Management\n // ============================================\n\n /**\n * Connect to a database.\n *\n * @param databaseId - Database ID in format \"project/database\"\n * @param options - Connection options (token, anonymous, coordinator URL)\n */\n async connect(databaseId: string, options: ConnectOptions = {}): Promise<void> {\n if (this._state !== 'disconnected') {\n throw new Error('Already connected or connecting');\n }\n\n this._state = 'connecting';\n this._databaseId = databaseId;\n this._coordinatorUrl = options.coordinator || DEFAULT_COORDINATOR_URL;\n\n try {\n // Step 1: Get connection details from coordinator\n const coordinatorUrl = this._coordinatorUrl;\n const coordinator = new Coordinator(coordinatorUrl);\n\n const connectResponse = await coordinator.connect(databaseId, {\n token: options.token,\n anonymous: options.anonymous,\n });\n\n // Step 2: Connect to the server via WebSocket\n const wsUrl = connectResponse.ws_url;\n\n this.ws = new WebSocketClient({\n onMessage: this.handleMessage.bind(this),\n onOpen: () => {}, // Handled in connect flow\n onClose: this.handleClose.bind(this),\n onError: this.handleError.bind(this),\n });\n\n await this.ws.connect(wsUrl);\n\n // Step 3: Send join message\n const requestId = this.messageQueue.nextRequestId();\n const joinMessage: ClientMessage = {\n o: 'j',\n t: connectResponse.token,\n r: requestId,\n };\n\n this.send(joinMessage);\n\n // Wait for join complete (returns volatile path patterns)\n const volatilePaths = (await this.messageQueue.registerRequest(requestId)) as string[];\n this._volatilePaths = volatilePaths || [];\n\n // Step 4: Extract auth info from JWT and update state\n const jwtPayload = decodeJwtPayload(connectResponse.token);\n this._auth = {\n uid: jwtPayload.sub,\n provider: jwtPayload.provider,\n token: jwtPayload.claims || {},\n };\n\n this._state = 'connected';\n\n // Initialize subscription manager\n this.subscriptionManager.initialize({\n sendSubscribe: this.sendSubscribeMessage.bind(this),\n sendUnsubscribe: this.sendUnsubscribeMessage.bind(this),\n createSnapshot: this.createSnapshot.bind(this),\n });\n\n // Notify listeners\n this.connectCallbacks.forEach((cb) => cb());\n } catch (error) {\n this._state = 'disconnected';\n this._auth = null;\n this._databaseId = null;\n this.ws?.close();\n this.ws = null;\n throw error;\n }\n }\n\n /**\n * Disconnect from the database.\n * This triggers onDisconnect hooks on the server.\n */\n async disconnect(): Promise<void> {\n if (this._state === 'disconnected') {\n return;\n }\n\n // Send leave message for graceful disconnect\n if (this._state === 'connected' && this.ws) {\n try {\n const requestId = this.messageQueue.nextRequestId();\n this.send({ o: 'l', r: requestId });\n // Wait briefly for ack, but don't block\n await Promise.race([\n this.messageQueue.registerRequest(requestId),\n new Promise((resolve) => setTimeout(resolve, 1000)),\n ]);\n } catch {\n // Ignore errors during disconnect\n }\n }\n\n this.cleanup();\n }\n\n /**\n * Clean up connection state.\n */\n private cleanup(): void {\n this.ws?.close();\n this.ws = null;\n this._state = 'disconnected';\n this._auth = null;\n this._databaseId = null;\n this._volatilePaths = [];\n this._coordinatorUrl = null;\n this.subscriptionManager.clear();\n this.messageQueue.rejectAll(new Error('Connection closed'));\n // Note: We intentionally do NOT clear pendingWrites here.\n // They are kept for potential retry on reconnect.\n // Call pendingWrites.clear() explicitly if you don't want to retry.\n }\n\n // ============================================\n // Reference Access\n // ============================================\n\n /**\n * Get a reference to a path in the database.\n */\n ref(path: string = ''): DatabaseReference {\n return new DatabaseReference(this, path);\n }\n\n // ============================================\n // Transactions\n // ============================================\n\n /**\n * Execute an atomic transaction with multiple operations.\n *\n * Supports two syntaxes:\n *\n * **Object syntax** (like Firebase multi-path update):\n * ```javascript\n * await db.transaction({\n * '/users/alice/name': 'Alice',\n * '/users/alice/score': 100,\n * '/temp/data': null // null = delete\n * });\n * ```\n *\n * **Array syntax** (explicit operations):\n * ```javascript\n * await db.transaction([\n * { op: 'set', path: '/users/alice/name', value: 'Alice' },\n * { op: 'update', path: '/metadata', value: { lastUpdated: '...' } },\n * { op: 'delete', path: '/temp/data' },\n * { op: 'condition', path: '/counter', value: 5 } // CAS check\n * ]);\n * ```\n *\n * All operations are atomic: either all succeed or all fail.\n * Conditions are checked first; if any fail, the transaction is rejected\n * with error code 'condition_failed'.\n */\n async transaction(operations: TransactionOp[] | TransactionObject): Promise<void> {\n let txOps: TxOperation[];\n\n if (Array.isArray(operations)) {\n // Array syntax - convert to wire format\n txOps = operations.map((op) => this.convertToTxOp(op));\n } else {\n // Object syntax - convert paths to set/delete operations\n txOps = this.convertObjectToTxOps(operations);\n }\n\n await this._sendTransaction(txOps);\n }\n\n /**\n * Convert a public TransactionOp to wire format TxOperation.\n */\n private convertToTxOp(op: TransactionOp): TxOperation {\n const path = normalizePath(op.path) || '/';\n\n switch (op.op) {\n case 'set':\n return { o: 's', p: path, v: op.value };\n case 'update':\n return { o: 'u', p: path, v: op.value };\n case 'delete':\n return { o: 'd', p: path };\n case 'condition':\n return { o: 'c', p: path, v: op.value };\n default:\n throw new Error(`Unknown transaction operation: ${(op as TransactionOp).op}`);\n }\n }\n\n /**\n * Convert object syntax to wire format TxOperations.\n * Each path becomes a set operation, null values become deletes.\n */\n private convertObjectToTxOps(obj: TransactionObject): TxOperation[] {\n const ops: TxOperation[] = [];\n\n for (const [path, value] of Object.entries(obj)) {\n const normalizedPath = normalizePath(path) || '/';\n\n if (value === null) {\n // null = delete\n ops.push({ o: 'd', p: normalizedPath });\n } else {\n // set the value\n ops.push({ o: 's', p: normalizedPath, v: value });\n }\n }\n\n return ops;\n }\n\n /**\n * @internal Send a transaction to the server.\n */\n async _sendTransaction(ops: TxOperation[]): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const oid = this.pendingWrites.generateOid();\n\n // Track the pending write (store ops as value for potential retry)\n this.pendingWrites.trackWrite(oid, 'transaction', '/', ops);\n\n const message: TransactionMessage = {\n o: 'tx',\n ops,\n r: requestId,\n oid,\n };\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n // ============================================\n // Connection Events\n // ============================================\n\n /**\n * Register a callback for when connection is established.\n * Returns an unsubscribe function.\n */\n onConnect(callback: () => void): () => void {\n this.connectCallbacks.add(callback);\n return () => this.connectCallbacks.delete(callback);\n }\n\n /**\n * Register a callback for when connection is lost.\n * Returns an unsubscribe function.\n */\n onDisconnect(callback: () => void): () => void {\n this.disconnectCallbacks.add(callback);\n return () => this.disconnectCallbacks.delete(callback);\n }\n\n /**\n * Register a callback for connection errors.\n * Returns an unsubscribe function.\n */\n onError(callback: (error: Error) => void): () => void {\n this.errorCallbacks.add(callback);\n return () => this.errorCallbacks.delete(callback);\n }\n\n // ============================================\n // Internal: Message Handling\n // ============================================\n\n private handleMessage(data: string): void {\n let message: ServerMessage;\n try {\n message = JSON.parse(data) as ServerMessage;\n } catch {\n console.error('Failed to parse message:', data);\n return;\n }\n\n // Handle ping - respond with pong immediately\n if (isPingMessage(message)) {\n this.ws?.send(JSON.stringify({ o: 'po' }));\n return;\n }\n\n // Check for oid on ack/nack messages and clear from pending writes\n if (isAckMessage(message) && message.oid) {\n this.pendingWrites.onAck(message.oid);\n } else if (isNackMessage(message) && message.oid) {\n this.pendingWrites.onNack(message.oid);\n }\n\n // Check if this is a response to a pending request\n if (this.messageQueue.handleMessage(message)) {\n return;\n }\n\n // Otherwise, check if it's an event\n if (isEventMessage(message)) {\n this.subscriptionManager.handleEvent(message);\n }\n }\n\n private handleClose(code: number, reason: string): void {\n const wasConnected = this._state === 'connected';\n this.cleanup();\n\n if (wasConnected) {\n this.disconnectCallbacks.forEach((cb) => cb());\n }\n }\n\n private handleError(event: Event): void {\n const error = new Error('WebSocket error');\n this.errorCallbacks.forEach((cb) => cb(error));\n }\n\n // ============================================\n // Internal: Sending Messages\n // ============================================\n\n private send(message: ClientMessage): void {\n if (!this.ws || !this.ws.connected) {\n throw new LarkError('not_connected', 'Not connected to database');\n }\n this.ws.send(JSON.stringify(message));\n }\n\n /**\n * @internal Send a set operation.\n */\n async _sendSet(path: string, value: unknown, priority?: number | string): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const oid = this.pendingWrites.generateOid();\n const normalizedPath = normalizePath(path) || '/';\n\n // Track the pending write\n this.pendingWrites.trackWrite(oid, 'set', normalizedPath, value);\n\n const message: ClientMessage = {\n o: 's',\n p: normalizedPath,\n v: value,\n r: requestId,\n oid,\n };\n if (priority !== undefined) {\n message.y = priority;\n }\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n /**\n * @internal Send an update operation.\n */\n async _sendUpdate(path: string, values: Record<string, unknown>): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const oid = this.pendingWrites.generateOid();\n const normalizedPath = normalizePath(path) || '/';\n\n // Track the pending write\n this.pendingWrites.trackWrite(oid, 'update', normalizedPath, values);\n\n const message: ClientMessage = {\n o: 'u',\n p: normalizedPath,\n v: values,\n r: requestId,\n oid,\n };\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n /**\n * @internal Send a delete operation.\n */\n async _sendDelete(path: string): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const oid = this.pendingWrites.generateOid();\n const normalizedPath = normalizePath(path) || '/';\n\n // Track the pending write\n this.pendingWrites.trackWrite(oid, 'delete', normalizedPath);\n\n const message: ClientMessage = {\n o: 'd',\n p: normalizedPath,\n r: requestId,\n oid,\n };\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n /**\n * @internal Send a push operation. Returns the generated key.\n */\n async _sendPush(path: string, value: unknown): Promise<string> {\n const requestId = this.messageQueue.nextRequestId();\n const oid = this.pendingWrites.generateOid();\n const normalizedPath = normalizePath(path) || '/';\n\n // Track the pending write\n this.pendingWrites.trackWrite(oid, 'push', normalizedPath, value);\n\n const message: ClientMessage = {\n o: 'p',\n p: normalizedPath,\n v: value,\n r: requestId,\n oid,\n };\n this.send(message);\n const key = (await this.messageQueue.registerRequest(requestId)) as string;\n return key;\n }\n\n /**\n * @internal Send a once (read) operation.\n *\n * This method first checks if the data is available in the local cache\n * (from an active subscription). If so, it returns the cached value\n * immediately without a server round-trip.\n *\n * Cache is only used when:\n * - No query parameters are specified (queries may filter/order differently)\n * - The path is covered by an active 'value' subscription\n * - We have cached data available\n */\n async _sendOnce(path: string, query?: QueryParams): Promise<DataSnapshot> {\n const normalizedPath = normalizePath(path) || '/';\n\n // Try cache first (only for non-query requests)\n if (!query) {\n const cached = this.subscriptionManager.getCachedValue(normalizedPath);\n if (cached.found) {\n return new DataSnapshot(cached.value, path, this);\n }\n }\n\n // Cache miss or query specified - fetch from server\n const requestId = this.messageQueue.nextRequestId();\n const message: ClientMessage = {\n o: 'o',\n p: normalizedPath,\n r: requestId,\n // Spread query params at top level (not nested in 'q')\n ...query,\n };\n this.send(message);\n const value = await this.messageQueue.registerRequest(requestId);\n return new DataSnapshot(value, path, this);\n }\n\n /**\n * @internal Send an onDisconnect operation.\n */\n async _sendOnDisconnect(\n path: string,\n action: string,\n value?: unknown,\n priority?: number | string\n ): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const message: ClientMessage = {\n o: 'od',\n p: normalizePath(path) || '/',\n a: action as 's' | 'u' | 'd' | 'c',\n r: requestId,\n };\n if (value !== undefined) {\n message.v = value;\n }\n if (priority !== undefined) {\n message.y = priority;\n }\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n /**\n * @internal Send a subscribe message to server.\n */\n private async sendSubscribeMessage(path: string, eventTypes: string[], queryParams?: QueryParams): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const message: ClientMessage = {\n o: 'sb',\n p: normalizePath(path) || '/',\n e: eventTypes,\n r: requestId,\n ...queryParams,\n };\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n /**\n * @internal Send an unsubscribe message to server.\n */\n private async sendUnsubscribeMessage(path: string): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const message: ClientMessage = {\n o: 'us',\n p: normalizePath(path) || '/',\n r: requestId,\n };\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n /**\n * @internal Create a DataSnapshot from event data.\n */\n private createSnapshot(\n path: string,\n value: unknown,\n volatile: boolean,\n serverTimestamp?: number\n ): DataSnapshot {\n return new DataSnapshot(value, path, this, {\n volatile,\n serverTimestamp: serverTimestamp ?? null,\n });\n }\n\n // ============================================\n // Internal: Subscription Management\n // ============================================\n\n /**\n * @internal Subscribe to events at a path.\n */\n _subscribe(path: string, eventType: EventType, callback: SnapshotCallback, queryParams?: QueryParams): () => void {\n return this.subscriptionManager.subscribe(path, eventType, callback, queryParams);\n }\n\n /**\n * @internal Unsubscribe from a specific event type at a path.\n */\n _unsubscribeEventType(path: string, eventType: EventType): void {\n this.subscriptionManager.unsubscribeEventType(path, eventType);\n }\n\n /**\n * @internal Unsubscribe from all events at a path.\n */\n _unsubscribeAll(path: string): void {\n this.subscriptionManager.unsubscribeAll(path);\n }\n}\n","/**\n * Volatile path matching utilities.\n *\n * Volatile paths are patterns where a wildcard matches exactly one path segment.\n * These paths use unreliable transport for better performance (UDP when available).\n */\n\n/**\n * Check if a path matches any of the volatile path patterns.\n *\n * Pattern matching rules:\n * - Wildcard matches exactly one path segment (not zero, not multiple)\n * - Patterns and paths are compared segment by segment\n * - Path must have the same number of segments as the pattern\n *\n * @param path - The path to check (e.g., \"/players/abc/position\")\n * @param patterns - Array of volatile patterns with wildcards\n * @returns true if the path matches any pattern\n */\nexport function isVolatilePath(path: string, patterns: string[] | null | undefined): boolean {\n if (!patterns || patterns.length === 0) {\n return false;\n }\n\n // Remove leading slash and split into segments\n const segments = path.replace(/^\\//, '').split('/');\n\n return patterns.some((pattern) => {\n const patternSegments = pattern.split('/');\n\n // Must have same number of segments\n if (segments.length !== patternSegments.length) {\n return false;\n }\n\n // Each segment must match (or pattern segment is wildcard)\n return patternSegments.every((p, i) => p === '*' || p === segments[i]);\n });\n}\n"],"mappings":"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","names":["currentOrder","WebSocketNode"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/protocol/constants.ts","../src/connection/Coordinator.ts","../src/LarkError.ts","../src/protocol/messages.ts","../src/connection/MessageQueue.ts","../src/connection/PendingWriteManager.ts","../src/utils/path.ts","../src/cache/DataCache.ts","../src/connection/SubscriptionManager.ts","../src/connection/WebSocketClient.ts","../src/OnDisconnect.ts","../src/utils/pushid.ts","../src/DatabaseReference.ts","../src/DataSnapshot.ts","../src/utils/jwt.ts","../src/LarkDatabase.ts","../src/utils/volatile.ts"],"sourcesContent":["/**\n * @lark-sh/client - JavaScript client for Lark real-time database\n *\n * @example\n * ```typescript\n * import { LarkDatabase } from '@lark-sh/client';\n *\n * const db = new LarkDatabase();\n * await db.connect('my-project/my-database', { anonymous: true });\n *\n * // Write data\n * await db.ref('players/abc').set({ name: 'Riley', score: 0 });\n *\n * // Subscribe to changes\n * const unsubscribe = db.ref('players').on('child_changed', (snap) => {\n * console.log(`Player ${snap.key} changed:`, snap.val());\n * });\n *\n * // Later: unsubscribe\n * unsubscribe();\n *\n * // Disconnect\n * await db.disconnect();\n * ```\n */\n\n// Main classes\nexport { LarkDatabase } from './LarkDatabase';\nexport type {\n ConnectOptions,\n AuthInfo,\n TransactionOp,\n TransactionSetOp,\n TransactionUpdateOp,\n TransactionDeleteOp,\n TransactionConditionOp,\n TransactionObject,\n} from './LarkDatabase';\n\nexport { DatabaseReference } from './DatabaseReference';\nexport type { SnapshotCallback, QueryState, TransactionResult } from './DatabaseReference';\n\nexport { DataSnapshot } from './DataSnapshot';\n\nexport { OnDisconnect } from './OnDisconnect';\n\nexport { LarkError } from './LarkError';\n\n// Protocol types (for advanced usage)\nexport type { EventType } from './protocol/constants';\nexport type { QueryParams, MoveEntry } from './protocol/messages';\n\n// Connection utilities (for advanced usage)\nexport { PendingWriteManager } from './connection/PendingWriteManager';\nexport type { WriteOperation, PendingWrite } from './connection/PendingWriteManager';\n\n// Utility functions (for advanced usage)\nexport { generatePushId } from './utils/pushid';\nexport { isVolatilePath } from './utils/volatile';\n","/**\n * Wire protocol constants.\n * Keys are shortened for bandwidth efficiency.\n */\n\n// Client -> Server operations\nexport const Op = {\n JOIN: 'j',\n SET: 's',\n UPDATE: 'u',\n DELETE: 'd',\n PUSH: 'p',\n SUBSCRIBE: 'sb',\n UNSUBSCRIBE: 'us',\n ONCE: 'o',\n ON_DISCONNECT: 'od',\n LEAVE: 'l',\n TRANSACTION: 'tx',\n} as const;\n\n// Transaction operation types (used within tx ops array)\nexport const TxOp = {\n SET: 's',\n UPDATE: 'u',\n DELETE: 'd',\n CONDITION: 'c',\n} as const;\n\nexport type TxOpType = (typeof TxOp)[keyof typeof TxOp];\n\n// OnDisconnect actions\nexport const OnDisconnectAction = {\n SET: 's',\n UPDATE: 'u',\n DELETE: 'd',\n CANCEL: 'c',\n} as const;\n\n// Server -> Client event types (wire format)\n// Server now sends 'put' and 'patch' events; client generates child_* events locally\nexport const ServerEventType = {\n PUT: 'put',\n PATCH: 'patch',\n} as const;\n\nexport type ServerEventTypeValue = (typeof ServerEventType)[keyof typeof ServerEventType];\n\n// Client-side event types (API-facing)\n// These are generated by the client from put/patch events\nexport type EventType = 'value' | 'child_added' | 'child_changed' | 'child_removed' | 'child_moved';\n\n// Map client event types to short form for subscribe message\nexport const eventTypeToShort: Record<EventType, string> = {\n value: 'v',\n child_added: 'ca',\n child_changed: 'cc',\n child_removed: 'cr',\n child_moved: 'cm',\n};\n\n// Error codes\nexport const ErrorCode = {\n PERMISSION_DENIED: 'permission_denied',\n INVALID_DATA: 'invalid_data',\n NOT_FOUND: 'not_found',\n INVALID_PATH: 'invalid_path',\n INVALID_OPERATION: 'invalid_operation',\n INTERNAL_ERROR: 'internal_error',\n CONDITION_FAILED: 'condition_failed',\n} as const;\n\nexport type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];\n\n// Default coordinator URL\nexport const DEFAULT_COORDINATOR_URL = 'https://db.lark.sh';\n","/**\n * Coordinator client - handles HTTP requests to the coordinator service\n * to get connection details for a specific database.\n */\n\nimport { DEFAULT_COORDINATOR_URL } from '../protocol/constants';\n\nexport interface ConnectRequest {\n database: string;\n token?: string;\n anonymous?: boolean;\n}\n\nexport interface ConnectResponse {\n ws_url: string; // Full WebSocket URL (e.g., \"wss://smash-1.larksh.com/ws\")\n udp_host: string; // Direct IP for UDP connections\n udp_port: number; // UDP port\n token: string; // Connection JWT to use with the server\n}\n\nexport interface CoordinatorError {\n error: string;\n message: string;\n}\n\nexport class Coordinator {\n private readonly baseUrl: string;\n\n constructor(baseUrl: string = DEFAULT_COORDINATOR_URL) {\n // Remove trailing slash if present\n this.baseUrl = baseUrl.replace(/\\/$/, '');\n }\n\n /**\n * Request connection details from the coordinator.\n *\n * @param database - Database ID in format \"project/database\"\n * @param options - Either a user token or anonymous flag\n * @returns Connection details including host, port, and connection token\n */\n async connect(\n database: string,\n options: { token?: string; anonymous?: boolean } = {}\n ): Promise<ConnectResponse> {\n const body: ConnectRequest = { database };\n\n if (options.token) {\n body.token = options.token;\n } else if (options.anonymous) {\n body.anonymous = true;\n } else {\n // Default to anonymous if nothing specified\n body.anonymous = true;\n }\n\n const response = await fetch(`${this.baseUrl}/connect`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n let errorMessage = `Coordinator request failed: ${response.status}`;\n try {\n const errorBody = (await response.json()) as CoordinatorError;\n if (errorBody.message) {\n errorMessage = errorBody.message;\n }\n } catch {\n // Ignore JSON parse errors\n }\n throw new Error(errorMessage);\n }\n\n const data = (await response.json()) as ConnectResponse;\n return data;\n }\n}\n","/**\n * LarkError - custom error class for Lark operations.\n */\n\nexport class LarkError extends Error {\n readonly code: string;\n\n constructor(code: string, message?: string) {\n super(message || code);\n this.code = code;\n this.name = 'LarkError';\n\n // Maintain proper stack trace in V8 environments\n const ErrorWithCapture = Error as typeof Error & {\n captureStackTrace?: (target: object, constructor: Function) => void;\n };\n if (ErrorWithCapture.captureStackTrace) {\n ErrorWithCapture.captureStackTrace(this, LarkError);\n }\n }\n}\n","/**\n * Wire protocol message types.\n * All communication uses JSON over WebSocket with shortened keys.\n */\n\nimport { EventType } from './constants';\n\n// ============================================\n// Client -> Server Messages\n// ============================================\n\nexport interface JoinMessage {\n o: 'j'; // operation: join\n t: string; // token (JWT from coordinator)\n r: string; // request ID\n}\n\nexport interface SetMessage {\n o: 's'; // operation: set\n p: string; // path\n v: unknown; // value\n r: string; // request ID\n y?: number | string; // priority (optional)\n}\n\nexport interface UpdateMessage {\n o: 'u'; // operation: update\n p: string; // path\n v: Record<string, unknown>; // values to merge\n r: string; // request ID\n}\n\nexport interface DeleteMessage {\n o: 'd'; // operation: delete\n p: string; // path\n r: string; // request ID\n}\n\nexport interface PushMessage {\n o: 'p'; // operation: push\n p: string; // path\n v: unknown; // value\n r: string; // request ID\n}\n\nexport interface SubscribeMessage {\n o: 'sb'; // operation: subscribe\n p: string; // path\n e: string[]; // event types (short form)\n r: string; // request ID\n // Query parameters (optional) - at top level per VIEW_REFACTOR.md\n orderBy?: string;\n orderByChild?: string;\n limitToFirst?: number;\n limitToLast?: number;\n startAt?: unknown;\n startAtKey?: string;\n endAt?: unknown;\n endAtKey?: string;\n equalTo?: unknown;\n equalToKey?: string;\n}\n\nexport interface QueryParams {\n orderBy?: 'key' | 'priority' | 'child' | 'value';\n orderByChild?: string; // child path (when orderBy='child')\n limitToFirst?: number;\n limitToLast?: number;\n startAt?: unknown; // startAt value\n startAtKey?: string; // startAt key tie-breaker\n endAt?: unknown; // endAt value\n endAtKey?: string; // endAt key tie-breaker\n equalTo?: unknown; // equalTo value\n equalToKey?: string; // equalTo key tie-breaker\n}\n\nexport interface UnsubscribeMessage {\n o: 'us'; // operation: unsubscribe\n p: string; // path\n r: string; // request ID\n}\n\nexport interface OnceMessage {\n o: 'o'; // operation: once\n p: string; // path\n r: string; // request ID\n // Query parameters (optional) - at top level (same as SubscribeMessage)\n orderBy?: string;\n orderByChild?: string;\n limitToFirst?: number;\n limitToLast?: number;\n startAt?: unknown;\n startAtKey?: string;\n endAt?: unknown;\n endAtKey?: string;\n equalTo?: unknown;\n equalToKey?: string;\n}\n\nexport interface OnDisconnectMessage {\n o: 'od'; // operation: onDisconnect\n p: string; // path\n a: 's' | 'u' | 'd' | 'c'; // action: set, update, delete, cancel\n v?: unknown; // value (for set/update)\n r: string; // request ID\n y?: number | string; // priority (optional, for set)\n}\n\nexport interface LeaveMessage {\n o: 'l'; // operation: leave\n r: string; // request ID\n}\n\nexport interface PongMessage {\n o: 'po'; // operation: pong (response to server ping)\n}\n\n// Transaction operation types (used in ops array)\nexport interface TxSetOp {\n o: 's'; // set\n p: string; // path\n v: unknown; // value\n}\n\nexport interface TxUpdateOp {\n o: 'u'; // update (merge)\n p: string; // path\n v: Record<string, unknown>; // values to merge\n}\n\nexport interface TxDeleteOp {\n o: 'd'; // delete\n p: string; // path\n}\n\nexport interface TxConditionOp {\n o: 'c'; // condition (compare-and-swap check)\n p: string; // path\n v: unknown; // expected value\n}\n\nexport type TxOperation = TxSetOp | TxUpdateOp | TxDeleteOp | TxConditionOp;\n\nexport interface TransactionMessage {\n o: 'tx'; // operation: transaction\n ops: TxOperation[]; // array of operations\n r: string; // request ID\n}\n\nexport type ClientMessage =\n | JoinMessage\n | SetMessage\n | UpdateMessage\n | DeleteMessage\n | PushMessage\n | SubscribeMessage\n | UnsubscribeMessage\n | OnceMessage\n | OnDisconnectMessage\n | LeaveMessage\n | PongMessage\n | TransactionMessage;\n\n// ============================================\n// Server -> Client Messages\n// ============================================\n\nexport interface AckMessage {\n a: string; // ack with request ID\n}\n\nexport interface NackMessage {\n n: string; // nack with request ID\n e: string; // error code\n m?: string; // human-readable message\n}\n\n// New delta-based event format\n// Server sends 'put' for single-path changes, 'patch' for multi-path changes\n// Client generates child_* events locally from these deltas\n\nexport interface PutEventMessage {\n ev: 'put'; // event type: single-path delta\n sp: string; // subscription path (absolute) - identifies which subscription\n p: string; // delta path (relative to sp), \"/\" means full snapshot\n v?: unknown; // value, null for deletion (omitted for move-only events)\n x?: boolean; // volatile flag\n ts?: number; // server timestamp in ms (for volatile events)\n ak?: string; // afterKey - previous sibling for positioning (empty string = first)\n k?: string[]; // orderedKeys - full key order for initial snapshot\n}\n\n// Move entry for ordered queries - represents a child that changed position\nexport interface MoveEntry {\n k: string; // key that moved\n ak: string; // new afterKey (empty string = first position)\n}\n\nexport interface PatchEventMessage {\n ev: 'patch'; // event type: multi-path delta\n sp: string; // subscription path (absolute)\n p: string; // base path (usually \"/\")\n v?: Record<string, unknown>; // multiple path:value pairs (relative to sp+p)\n x?: boolean; // volatile flag\n ts?: number; // server timestamp in ms (for volatile events)\n k?: string[]; // orderedKeys - full key order for batch reorder\n mv?: MoveEntry[]; // moves array - items that changed position\n}\n\nexport type EventMessage = PutEventMessage | PatchEventMessage;\n\nexport interface OnceResponseMessage {\n oc: string; // once response with request ID\n ov: unknown; // value\n}\n\nexport interface PushAckMessage {\n pa: string; // push ack with request ID\n pk: string; // generated push key\n}\n\nexport interface JoinCompleteMessage {\n jc: string; // join complete with request ID\n vp?: string[] | null; // volatile path patterns (e.g., [\"players/*/position\"])\n}\n\nexport interface PingMessage {\n o: 'pi'; // operation: ping (keepalive from server)\n}\n\nexport type ServerMessage =\n | AckMessage\n | NackMessage\n | EventMessage\n | OnceResponseMessage\n | PushAckMessage\n | JoinCompleteMessage\n | PingMessage;\n\n// ============================================\n// Helper functions\n// ============================================\n\nexport function isAckMessage(msg: ServerMessage): msg is AckMessage {\n return 'a' in msg;\n}\n\nexport function isJoinCompleteMessage(msg: ServerMessage): msg is JoinCompleteMessage {\n return 'jc' in msg;\n}\n\nexport function isNackMessage(msg: ServerMessage): msg is NackMessage {\n return 'n' in msg;\n}\n\nexport function isEventMessage(msg: ServerMessage): msg is EventMessage {\n return 'ev' in msg;\n}\n\nexport function isPutEventMessage(msg: ServerMessage): msg is PutEventMessage {\n return 'ev' in msg && (msg as EventMessage).ev === 'put';\n}\n\nexport function isPatchEventMessage(msg: ServerMessage): msg is PatchEventMessage {\n return 'ev' in msg && (msg as EventMessage).ev === 'patch';\n}\n\nexport function isOnceResponseMessage(msg: ServerMessage): msg is OnceResponseMessage {\n return 'oc' in msg;\n}\n\nexport function isPushAckMessage(msg: ServerMessage): msg is PushAckMessage {\n return 'pa' in msg;\n}\n\nexport function isPingMessage(msg: ServerMessage): msg is PingMessage {\n return 'o' in msg && (msg as PingMessage).o === 'pi';\n}\n","/**\n * MessageQueue - handles request/response correlation for WebSocket messages.\n *\n * Every reliable operation gets a unique request ID. When we send a message,\n * we create a promise and store it. When we receive an ack/nack, we resolve/reject\n * the corresponding promise.\n */\n\nimport { LarkError } from '../LarkError';\nimport {\n ServerMessage,\n isAckMessage,\n isJoinCompleteMessage,\n isNackMessage,\n isOnceResponseMessage,\n isPushAckMessage,\n} from '../protocol/messages';\n\ninterface PendingRequest {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n}\n\nexport class MessageQueue {\n private nextId = 1;\n private pending = new Map<string, PendingRequest>();\n private defaultTimeout: number;\n\n constructor(defaultTimeout: number = 30000) {\n this.defaultTimeout = defaultTimeout;\n }\n\n /**\n * Generate a new unique request ID.\n */\n nextRequestId(): string {\n return String(this.nextId++);\n }\n\n /**\n * Register a pending request that expects a response.\n * Returns a promise that resolves when ack is received, or rejects on nack/timeout.\n */\n registerRequest(requestId: string, timeout?: number): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const timeoutMs = timeout ?? this.defaultTimeout;\n\n const timeoutHandle = setTimeout(() => {\n this.pending.delete(requestId);\n reject(new LarkError('timeout', `Request ${requestId} timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n\n this.pending.set(requestId, {\n resolve,\n reject,\n timeout: timeoutHandle,\n });\n });\n }\n\n /**\n * Handle an incoming server message. If it's a response to a pending request,\n * resolve or reject the corresponding promise.\n *\n * @returns true if the message was handled (was a response), false otherwise\n */\n handleMessage(message: ServerMessage): boolean {\n // Join complete (includes volatile paths)\n if (isJoinCompleteMessage(message)) {\n const pending = this.pending.get(message.jc);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(message.jc);\n // Resolve with volatile paths array (may be null/undefined)\n pending.resolve(message.vp || []);\n return true;\n }\n }\n\n // Regular ack\n if (isAckMessage(message)) {\n const pending = this.pending.get(message.a);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(message.a);\n pending.resolve(undefined);\n return true;\n }\n }\n\n // Nack (error)\n if (isNackMessage(message)) {\n const pending = this.pending.get(message.n);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(message.n);\n pending.reject(new LarkError(message.e, message.m));\n return true;\n }\n }\n\n // Once response\n if (isOnceResponseMessage(message)) {\n const pending = this.pending.get(message.oc);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(message.oc);\n pending.resolve(message.ov);\n return true;\n }\n }\n\n // Push ack\n if (isPushAckMessage(message)) {\n const pending = this.pending.get(message.pa);\n if (pending) {\n clearTimeout(pending.timeout);\n this.pending.delete(message.pa);\n pending.resolve(message.pk);\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Reject all pending requests (e.g., on disconnect).\n */\n rejectAll(error: Error): void {\n for (const [, pending] of this.pending) {\n clearTimeout(pending.timeout);\n pending.reject(error);\n }\n this.pending.clear();\n }\n\n /**\n * Get the number of pending requests.\n */\n get pendingCount(): number {\n return this.pending.size;\n }\n}\n","/**\n * PendingWriteManager - tracks pending write operations for optimistic updates.\n *\n * Each write operation is assigned a unique operation ID (oid). The manager tracks\n * pending writes until they are acknowledged by the server. On reconnect, pending\n * writes can be retried to ensure data consistency.\n */\n\nexport type WriteOperation = 'set' | 'update' | 'delete' | 'push' | 'transaction';\n\nexport interface PendingWrite {\n oid: string;\n operation: WriteOperation;\n path: string;\n value?: unknown;\n timestamp: number;\n}\n\nexport class PendingWriteManager {\n private pending = new Map<string, PendingWrite>();\n\n /**\n * Track a new pending write operation.\n * Uses the request ID as the tracking key.\n */\n trackWrite(requestId: string, operation: WriteOperation, path: string, value?: unknown): void {\n this.pending.set(requestId, {\n oid: requestId,\n operation,\n path,\n value,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Called when a write is acknowledged by the server.\n * Removes the write from pending tracking.\n */\n onAck(oid: string): boolean {\n return this.pending.delete(oid);\n }\n\n /**\n * Called when a write is rejected by the server.\n * Removes the write from pending tracking.\n */\n onNack(oid: string): boolean {\n return this.pending.delete(oid);\n }\n\n /**\n * Get all pending writes for retry on reconnect.\n * Returns writes in order of their timestamps (oldest first).\n */\n getPendingWrites(): PendingWrite[] {\n const writes = Array.from(this.pending.values());\n writes.sort((a, b) => a.timestamp - b.timestamp);\n return writes;\n }\n\n /**\n * Check if a specific operation is still pending.\n */\n isPending(oid: string): boolean {\n return this.pending.has(oid);\n }\n\n /**\n * Get the number of pending writes.\n */\n get pendingCount(): number {\n return this.pending.size;\n }\n\n /**\n * Clear all pending writes (e.g., on disconnect when not retrying).\n */\n clear(): void {\n this.pending.clear();\n }\n\n /**\n * Remove writes older than a specified age (in milliseconds).\n * Useful for cleaning up stale pending writes that may never be acked.\n */\n removeStale(maxAgeMs: number): number {\n const cutoff = Date.now() - maxAgeMs;\n let removed = 0;\n\n for (const [oid, write] of this.pending) {\n if (write.timestamp < cutoff) {\n this.pending.delete(oid);\n removed++;\n }\n }\n\n return removed;\n }\n}\n","/**\n * Path utilities for database paths.\n * Paths are Unix-style: /players/abc/score\n */\n\n/**\n * Normalize a path to match server format:\n * - Root is \"/\"\n * - All other paths start with \"/\" and have no trailing slash\n * - Multiple slashes are collapsed\n */\nexport function normalizePath(path: string): string {\n if (!path || path === '/') return '/';\n\n // Split, filter empty segments, rejoin with leading slash\n const segments = path.split('/').filter((segment) => segment.length > 0);\n if (segments.length === 0) return '/';\n\n return '/' + segments.join('/');\n}\n\n/**\n * Join path segments together.\n */\nexport function joinPath(...segments: string[]): string {\n const allParts: string[] = [];\n\n for (const segment of segments) {\n if (!segment || segment === '/') continue;\n // Split each segment and add non-empty parts\n const parts = segment.split('/').filter((p) => p.length > 0);\n allParts.push(...parts);\n }\n\n if (allParts.length === 0) return '/';\n return '/' + allParts.join('/');\n}\n\n/**\n * Get the parent path. Returns \"/\" for paths one level deep, \"/\" for root.\n */\nexport function getParentPath(path: string): string {\n const normalized = normalizePath(path);\n if (normalized === '/') return '/';\n\n const lastSlash = normalized.lastIndexOf('/');\n if (lastSlash <= 0) return '/';\n\n return normalized.substring(0, lastSlash);\n}\n\n/**\n * Get the last segment of a path (the \"key\").\n */\nexport function getKey(path: string): string | null {\n const normalized = normalizePath(path);\n if (normalized === '/') return null;\n\n const lastSlash = normalized.lastIndexOf('/');\n return normalized.substring(lastSlash + 1);\n}\n\n/**\n * Check if a path is valid (no invalid characters).\n */\nexport function isValidPath(path: string): boolean {\n if (path === '' || path === '/') return true;\n\n const normalized = normalizePath(path);\n // Filter out empty segments from leading slash\n const segments = normalized.split('/').filter((s) => s.length > 0);\n\n for (const segment of segments) {\n // Check for invalid characters: . $ # [ ]\n if (/[.\\$#\\[\\]]/.test(segment)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Get a nested value from an object by path.\n */\nexport function getValueAtPath(obj: unknown, path: string): unknown {\n const normalized = normalizePath(path);\n if (normalized === '/') return obj;\n\n // Split and filter empty segments (from leading slash)\n const segments = normalized.split('/').filter((s) => s.length > 0);\n let current: unknown = obj;\n\n for (const segment of segments) {\n if (current === null || current === undefined) {\n return undefined;\n }\n if (typeof current !== 'object') {\n return undefined;\n }\n current = (current as Record<string, unknown>)[segment];\n }\n\n return current;\n}\n\n/**\n * Set a nested value in an object by path. Mutates the object.\n * Creates intermediate objects as needed.\n */\nexport function setValueAtPath(obj: Record<string, unknown>, path: string, value: unknown): void {\n const normalized = normalizePath(path);\n if (normalized === '/') {\n // Can't set root on an object\n return;\n }\n\n // Split and filter empty segments (from leading slash)\n const segments = normalized.split('/').filter((s) => s.length > 0);\n let current: Record<string, unknown> = obj;\n\n for (let i = 0; i < segments.length - 1; i++) {\n const segment = segments[i];\n if (!(segment in current) || typeof current[segment] !== 'object' || current[segment] === null) {\n current[segment] = {};\n }\n current = current[segment] as Record<string, unknown>;\n }\n\n const lastSegment = segments[segments.length - 1];\n current[lastSegment] = value;\n}\n","/**\n * DataCache - local data store for caching subscription data.\n *\n * Only stores data from active subscriptions (not from once() calls).\n * Data is considered \"live\" if covered by an active subscription.\n */\n\nimport { getValueAtPath, normalizePath, setValueAtPath } from '../utils/path';\n\nexport class DataCache {\n // path -> cached value\n private cache = new Map<string, unknown>();\n\n /**\n * Store a value at a path.\n * Called when we receive data from a subscription event.\n */\n set(path: string, value: unknown): void {\n const normalized = normalizePath(path);\n this.cache.set(normalized, value);\n }\n\n /**\n * Get the cached value at a path.\n * Returns undefined if not in cache.\n *\n * This method handles nested lookups:\n * - If /boxes is cached with {0: true, 1: false}\n * - get('/boxes/0') returns true (extracted from parent)\n */\n get(path: string): { value: unknown; found: boolean } {\n const normalized = normalizePath(path);\n\n // First, check for exact match\n if (this.cache.has(normalized)) {\n return { value: this.cache.get(normalized), found: true };\n }\n\n // Next, check if any ancestor path has cached data we can extract from\n const ancestorResult = this.getFromAncestor(normalized);\n if (ancestorResult.found) {\n return ancestorResult;\n }\n\n return { value: undefined, found: false };\n }\n\n /**\n * Check if we have cached data that covers the given path.\n * This includes exact matches and ancestor paths.\n */\n has(path: string): boolean {\n return this.get(path).found;\n }\n\n /**\n * Try to get data from an ancestor path.\n * E.g., if /boxes is cached and we want /boxes/5, extract it.\n */\n private getFromAncestor(path: string): { value: unknown; found: boolean } {\n // Walk up the path tree looking for cached ancestors\n const segments = path.split('/').filter((s) => s.length > 0);\n\n for (let i = segments.length - 1; i >= 0; i--) {\n const ancestorPath = i === 0 ? '/' : '/' + segments.slice(0, i).join('/');\n\n if (this.cache.has(ancestorPath)) {\n const ancestorValue = this.cache.get(ancestorPath);\n // Calculate the relative path from ancestor to target\n const relativePath = '/' + segments.slice(i).join('/');\n const extractedValue = getValueAtPath(ancestorValue, relativePath);\n return { value: extractedValue, found: true };\n }\n }\n\n // Also check root\n if (this.cache.has('/')) {\n const rootValue = this.cache.get('/');\n const extractedValue = getValueAtPath(rootValue, path);\n return { value: extractedValue, found: true };\n }\n\n return { value: undefined, found: false };\n }\n\n /**\n * Remove cached data at a path.\n * Called when unsubscribing from a path that's no longer covered.\n */\n delete(path: string): void {\n const normalized = normalizePath(path);\n this.cache.delete(normalized);\n }\n\n /**\n * Remove cached data at a path and all descendant paths.\n * Called when a subscription is removed and no other subscription covers it.\n */\n deleteTree(path: string): void {\n const normalized = normalizePath(path);\n\n // Delete exact match\n this.cache.delete(normalized);\n\n // Delete all descendants\n const prefix = normalized === '/' ? '/' : normalized + '/';\n for (const cachedPath of this.cache.keys()) {\n if (cachedPath.startsWith(prefix) || (normalized === '/' && cachedPath !== '/')) {\n this.cache.delete(cachedPath);\n }\n }\n }\n\n /**\n * Update cache when a child value changes.\n * This updates both the child path and any cached ancestor that contains it.\n *\n * E.g., if /boxes is cached and /boxes/5 changes:\n * - Update the /boxes cache to reflect the new /boxes/5 value\n *\n * If an ancestor is null, it creates a new object to hold the child.\n */\n updateChild(path: string, value: unknown): void {\n const normalized = normalizePath(path);\n\n // Set the exact path\n this.cache.set(normalized, value);\n\n // Also update any cached ancestors that would contain this data\n const segments = normalized.split('/').filter((s) => s.length > 0);\n\n for (let i = segments.length - 1; i >= 1; i--) {\n const ancestorPath = '/' + segments.slice(0, i).join('/');\n\n if (this.cache.has(ancestorPath)) {\n const ancestorValue = this.cache.get(ancestorPath);\n // If ancestor is null, create a new object to hold the child\n const baseValue = (ancestorValue !== null && typeof ancestorValue === 'object')\n ? this.deepClone(ancestorValue)\n : {};\n const remainingPath = '/' + segments.slice(i).join('/');\n setValueAtPath(baseValue as Record<string, unknown>, remainingPath, value);\n this.cache.set(ancestorPath, baseValue);\n }\n }\n\n // Check root as well\n if (this.cache.has('/') && normalized !== '/') {\n const rootValue = this.cache.get('/');\n const baseValue = (rootValue !== null && typeof rootValue === 'object')\n ? this.deepClone(rootValue)\n : {};\n setValueAtPath(baseValue as Record<string, unknown>, normalized, value);\n this.cache.set('/', baseValue);\n }\n }\n\n /**\n * Remove a child from the cache (e.g., on child_removed event).\n */\n removeChild(path: string): void {\n const normalized = normalizePath(path);\n\n // Delete the exact path and any descendants\n this.deleteTree(normalized);\n\n // Also update any cached ancestors\n const segments = normalized.split('/').filter((s) => s.length > 0);\n\n for (let i = segments.length - 1; i >= 1; i--) {\n const ancestorPath = '/' + segments.slice(0, i).join('/');\n\n if (this.cache.has(ancestorPath)) {\n const ancestorValue = this.cache.get(ancestorPath);\n if (ancestorValue !== null && typeof ancestorValue === 'object') {\n const updatedAncestor = this.deepClone(ancestorValue);\n // Navigate to parent and delete the child key\n const parentPath = '/' + segments.slice(i, -1).join('/');\n const childKey = segments[segments.length - 1];\n const parent = parentPath === '/'\n ? updatedAncestor\n : getValueAtPath(updatedAncestor, parentPath);\n if (parent && typeof parent === 'object') {\n delete (parent as Record<string, unknown>)[childKey];\n }\n this.cache.set(ancestorPath, updatedAncestor);\n }\n }\n }\n }\n\n /**\n * Clear all cached data.\n */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Get the number of cached paths (for testing/debugging).\n */\n get size(): number {\n return this.cache.size;\n }\n\n /**\n * Deep clone a value to avoid mutation issues.\n */\n private deepClone<T>(value: T): T {\n if (value === null || typeof value !== 'object') {\n return value;\n }\n return JSON.parse(JSON.stringify(value));\n }\n}\n","/**\n * SubscriptionManager - tracks active subscriptions and routes events to callbacks.\n *\n * Handles the new delta-based protocol where server sends 'put' and 'patch' events.\n * Client generates child_added, child_changed, child_removed, child_moved events locally.\n *\n * Supports ordered queries: tracks child order from server's `k` (orderedKeys) and `ak` (afterKey)\n * fields, and fires child_moved when positions change via `mv` (moves) array.\n */\n\nimport type { DataSnapshot } from '../DataSnapshot';\nimport { DataCache } from '../cache/DataCache';\nimport { EventType } from '../protocol/constants';\nimport { EventMessage, PutEventMessage, PatchEventMessage, QueryParams, MoveEntry } from '../protocol/messages';\nimport { joinPath, normalizePath } from '../utils/path';\n\nexport type SnapshotCallback = (snapshot: DataSnapshot, previousChildKey?: string | null) => void;\n\ninterface SubscriptionEntry {\n callback: SnapshotCallback;\n unsubscribe: () => void;\n}\n\nexport class SubscriptionManager {\n // subscriptionPath -> eventType -> array of subscriptions\n private subscriptions = new Map<string, Map<EventType, SubscriptionEntry[]>>();\n\n // Local data cache for subscription data\n private cache: DataCache;\n\n // Ordered child keys for each subscription path (for ordered queries)\n // subscriptionPath -> ordered array of child keys\n private orderedChildren = new Map<string, string[]>();\n\n // Callback to send subscribe message to server\n private sendSubscribe: ((path: string, eventTypes: string[], queryParams?: QueryParams) => Promise<void>) | null = null;\n\n // Query params for each subscription path\n private queryParams = new Map<string, QueryParams | undefined>();\n\n // Callback to send unsubscribe message to server\n private sendUnsubscribe: ((path: string) => Promise<void>) | null = null;\n\n // Callback to create DataSnapshot from event data\n private createSnapshot:\n | ((path: string, value: unknown, volatile: boolean, serverTimestamp?: number) => DataSnapshot)\n | null = null;\n\n constructor() {\n this.cache = new DataCache();\n }\n\n /**\n * Initialize the manager with server communication callbacks.\n */\n initialize(options: {\n sendSubscribe: (path: string, eventTypes: string[], queryParams?: QueryParams) => Promise<void>;\n sendUnsubscribe: (path: string) => Promise<void>;\n createSnapshot: (path: string, value: unknown, volatile: boolean, serverTimestamp?: number) => DataSnapshot;\n }): void {\n this.sendSubscribe = options.sendSubscribe;\n this.sendUnsubscribe = options.sendUnsubscribe;\n this.createSnapshot = options.createSnapshot;\n }\n\n /**\n * Subscribe to events at a path.\n * Returns an unsubscribe function.\n */\n subscribe(path: string, eventType: EventType, callback: SnapshotCallback, queryParams?: QueryParams): () => void {\n // Path should already be normalized by DatabaseReference\n const normalizedPath = path;\n\n // Check if this is the first subscription to this path\n const isFirstForPath = !this.subscriptions.has(normalizedPath);\n const existingEventTypes = this.getEventTypesForPath(normalizedPath);\n const isFirstForEventType = !existingEventTypes.includes(eventType);\n\n // Create path map if needed\n if (!this.subscriptions.has(normalizedPath)) {\n this.subscriptions.set(normalizedPath, new Map());\n }\n const pathSubs = this.subscriptions.get(normalizedPath)!;\n\n // Create event type array if needed\n if (!pathSubs.has(eventType)) {\n pathSubs.set(eventType, []);\n }\n const eventSubs = pathSubs.get(eventType)!;\n\n // Store query params for this path (first subscription wins)\n if (isFirstForPath && queryParams) {\n this.queryParams.set(normalizedPath, queryParams);\n }\n\n // Create unsubscribe function\n const unsubscribe = () => {\n this.unsubscribeCallback(normalizedPath, eventType, callback);\n };\n\n // Add subscription\n eventSubs.push({ callback, unsubscribe });\n\n // If this is a new event type for this path, update server subscription\n if (isFirstForPath || isFirstForEventType) {\n const allEventTypes = this.getEventTypesForPath(normalizedPath);\n // Send full event type names (server expects 'child_added', not 'ca')\n const storedQueryParams = this.queryParams.get(normalizedPath);\n\n // Fire and forget - we don't wait for the server\n this.sendSubscribe?.(normalizedPath, allEventTypes, storedQueryParams).catch((err) => {\n console.error('Failed to subscribe:', err);\n });\n }\n\n return unsubscribe;\n }\n\n /**\n * Remove a specific callback from a subscription.\n */\n private unsubscribeCallback(path: string, eventType: EventType, callback: SnapshotCallback): void {\n const pathSubs = this.subscriptions.get(path);\n if (!pathSubs) return;\n\n const eventSubs = pathSubs.get(eventType);\n if (!eventSubs) return;\n\n // Find and remove the callback\n const index = eventSubs.findIndex((entry) => entry.callback === callback);\n if (index !== -1) {\n eventSubs.splice(index, 1);\n }\n\n // Clean up empty arrays\n if (eventSubs.length === 0) {\n pathSubs.delete(eventType);\n }\n\n // If no more subscriptions for this path, unsubscribe from server and clear cache\n if (pathSubs.size === 0) {\n this.subscriptions.delete(path);\n this.orderedChildren.delete(path);\n this.queryParams.delete(path);\n this.cache.deleteTree(path);\n this.sendUnsubscribe?.(path).catch((err) => {\n console.error('Failed to unsubscribe:', err);\n });\n }\n }\n\n /**\n * Remove all subscriptions of a specific event type at a path.\n */\n unsubscribeEventType(path: string, eventType: EventType): void {\n const normalizedPath = path;\n const pathSubs = this.subscriptions.get(normalizedPath);\n if (!pathSubs) return;\n\n // Remove all callbacks for this event type\n pathSubs.delete(eventType);\n\n // If no more subscriptions for this path, unsubscribe from server\n if (pathSubs.size === 0) {\n this.subscriptions.delete(normalizedPath);\n this.orderedChildren.delete(normalizedPath);\n this.queryParams.delete(normalizedPath);\n this.cache.deleteTree(normalizedPath);\n this.sendUnsubscribe?.(normalizedPath).catch((err) => {\n console.error('Failed to unsubscribe:', err);\n });\n } else {\n // Update server with remaining event types (full names)\n const remainingEventTypes = this.getEventTypesForPath(normalizedPath);\n const storedQueryParams = this.queryParams.get(normalizedPath);\n this.sendSubscribe?.(normalizedPath, remainingEventTypes, storedQueryParams).catch((err) => {\n console.error('Failed to update subscription:', err);\n });\n }\n }\n\n /**\n * Remove ALL subscriptions at a path.\n */\n unsubscribeAll(path: string): void {\n const normalizedPath = path;\n if (!this.subscriptions.has(normalizedPath)) return;\n\n this.subscriptions.delete(normalizedPath);\n this.orderedChildren.delete(normalizedPath);\n this.queryParams.delete(normalizedPath);\n this.cache.deleteTree(normalizedPath);\n this.sendUnsubscribe?.(normalizedPath).catch((err) => {\n console.error('Failed to unsubscribe:', err);\n });\n }\n\n /**\n * Handle an incoming event message from the server.\n * Server sends 'put' or 'patch' events; we generate child_* events client-side.\n */\n handleEvent(message: EventMessage): void {\n if (message.ev === 'put') {\n this.handlePutEvent(message);\n } else if (message.ev === 'patch') {\n this.handlePatchEvent(message);\n } else {\n console.warn('Unknown event type:', (message as { ev: string }).ev);\n }\n }\n\n /**\n * Handle a 'put' event - single path change.\n */\n private handlePutEvent(message: PutEventMessage): void {\n const subscriptionPath = message.sp;\n const relativePath = message.p;\n const value = message.v;\n const isVolatile = message.x ?? false;\n const serverTimestamp = message.ts;\n const afterKey = message.ak;\n const orderedKeys = message.k;\n\n // Look up subscriptions by subscription path\n const pathSubs = this.subscriptions.get(subscriptionPath);\n if (!pathSubs) return;\n\n // Convert relative path to absolute\n const absolutePath = relativePath === '/'\n ? subscriptionPath\n : joinPath(subscriptionPath, relativePath);\n\n // Get previous ordered children before updating\n const previousOrder = this.orderedChildren.get(subscriptionPath) ?? [];\n const previousChildSet = new Set(previousOrder);\n\n // Update cache (if value provided - may be omitted for move-only events)\n if (value !== undefined) {\n if (relativePath === '/') {\n // Full snapshot (initial or reconnect)\n this.cache.set(subscriptionPath, value);\n } else if (value === null) {\n // Deletion\n this.cache.removeChild(absolutePath);\n } else {\n // Delta update\n this.cache.updateChild(absolutePath, value);\n }\n }\n\n // Update ordered children tracking\n if (relativePath === '/') {\n // Full snapshot - use server's ordered keys if provided, otherwise extract from value\n if (orderedKeys) {\n this.orderedChildren.set(subscriptionPath, [...orderedKeys]);\n } else if (value && typeof value === 'object' && value !== null) {\n // No explicit order, use object keys\n this.orderedChildren.set(subscriptionPath, Object.keys(value as Record<string, unknown>));\n } else {\n this.orderedChildren.set(subscriptionPath, []);\n }\n } else {\n // Delta update - parse child key from relative path\n const segments = relativePath.split('/').filter(s => s.length > 0);\n if (segments.length > 0) {\n const childKey = segments[0];\n const currentOrder = this.orderedChildren.get(subscriptionPath) ?? [];\n\n if (value === null) {\n // Remove from order\n const newOrder = currentOrder.filter(k => k !== childKey);\n this.orderedChildren.set(subscriptionPath, newOrder);\n } else if (!previousChildSet.has(childKey)) {\n // New child - insert at position based on afterKey\n const newOrder = [...currentOrder];\n this.insertAfterKey(newOrder, childKey, afterKey);\n this.orderedChildren.set(subscriptionPath, newOrder);\n }\n // For existing children, order doesn't change from put (moves come via patch.mv)\n }\n }\n\n // Get current ordered children after update\n const currentOrder = this.orderedChildren.get(subscriptionPath) ?? [];\n const currentChildSet = new Set(currentOrder);\n\n // Fire callbacks based on subscribed event types\n this.fireCallbacks(\n subscriptionPath,\n pathSubs,\n relativePath,\n value,\n previousOrder,\n currentOrder,\n previousChildSet,\n currentChildSet,\n afterKey,\n isVolatile,\n serverTimestamp\n );\n }\n\n /**\n * Handle a 'patch' event - multi-path change and/or moves.\n */\n private handlePatchEvent(message: PatchEventMessage): void {\n const subscriptionPath = message.sp;\n const basePath = message.p;\n const patches = message.v;\n const moves = message.mv;\n const orderedKeys = message.k;\n const isVolatile = message.x ?? false;\n const serverTimestamp = message.ts;\n\n const pathSubs = this.subscriptions.get(subscriptionPath);\n if (!pathSubs) return;\n\n // Get previous ordered children before updating\n const previousOrder = this.orderedChildren.get(subscriptionPath) ?? [];\n const previousChildSet = new Set(previousOrder);\n\n // Track which immediate children are affected by patches\n const affectedChildren = new Set<string>();\n\n // Apply all patches to cache (if any)\n if (patches) {\n for (const [relativePath, value] of Object.entries(patches)) {\n const fullRelativePath = basePath === '/'\n ? '/' + relativePath\n : joinPath(basePath, relativePath);\n const absolutePath = joinPath(subscriptionPath, fullRelativePath);\n\n // Extract immediate child key from the patch path\n const segments = fullRelativePath.split('/').filter(s => s.length > 0);\n if (segments.length > 0) {\n affectedChildren.add(segments[0]);\n }\n\n if (value === null) {\n this.cache.removeChild(absolutePath);\n } else {\n this.cache.updateChild(absolutePath, value);\n }\n }\n }\n\n // Handle moves array\n if (moves && moves.length > 0) {\n this.handleMoves(subscriptionPath, pathSubs, moves, isVolatile, serverTimestamp);\n }\n\n // Handle full reorder via k field\n if (orderedKeys) {\n this.orderedChildren.set(subscriptionPath, [...orderedKeys]);\n }\n\n // Get current ordered children after update\n const currentOrder = this.orderedChildren.get(subscriptionPath) ?? [];\n const currentChildSet = new Set(currentOrder);\n\n // Fire value callbacks\n const valueSubs = pathSubs.get('value');\n if (valueSubs && valueSubs.length > 0) {\n const fullValue = this.cache.get(subscriptionPath).value;\n const snapshot = this.createSnapshot?.(subscriptionPath, fullValue, isVolatile, serverTimestamp);\n if (snapshot) {\n for (const entry of valueSubs) {\n try {\n entry.callback(snapshot, undefined);\n } catch (err) {\n console.error('Error in value subscription callback:', err);\n }\n }\n }\n }\n\n // Fire child_* events for each affected child\n if (patches && affectedChildren.size > 0) {\n const childAddedSubs = pathSubs.get('child_added') ?? [];\n const childChangedSubs = pathSubs.get('child_changed') ?? [];\n const childRemovedSubs = pathSubs.get('child_removed') ?? [];\n\n for (const childKey of affectedChildren) {\n const wasPresent = previousChildSet.has(childKey);\n const isPresent = currentChildSet.has(childKey);\n\n if (!wasPresent && isPresent) {\n // New child added\n const prevKey = this.getPreviousChildKey(currentOrder, childKey);\n this.fireChildAdded(subscriptionPath, childKey, childAddedSubs, prevKey, isVolatile, serverTimestamp);\n } else if (wasPresent && !isPresent) {\n // Child removed\n this.fireChildRemoved(subscriptionPath, childKey, childRemovedSubs, isVolatile, serverTimestamp);\n } else if (wasPresent && isPresent) {\n // Existing child changed\n const prevKey = this.getPreviousChildKey(currentOrder, childKey);\n this.fireChildChanged(subscriptionPath, childKey, childChangedSubs, prevKey, isVolatile, serverTimestamp);\n }\n }\n }\n }\n\n /**\n * Handle moves array - update order and fire child_moved events.\n */\n private handleMoves(\n subscriptionPath: string,\n pathSubs: Map<EventType, SubscriptionEntry[]>,\n moves: MoveEntry[],\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n const childMovedSubs = pathSubs.get('child_moved') ?? [];\n const currentOrder = this.orderedChildren.get(subscriptionPath) ?? [];\n\n for (const move of moves) {\n const { k: childKey, ak: afterKey } = move;\n\n // Remove from current position\n const idx = currentOrder.indexOf(childKey);\n if (idx !== -1) {\n currentOrder.splice(idx, 1);\n }\n\n // Insert at new position\n this.insertAfterKey(currentOrder, childKey, afterKey);\n\n // Fire child_moved event\n if (childMovedSubs.length > 0) {\n const previousChildKey = afterKey === '' ? null : afterKey;\n this.fireChildMoved(subscriptionPath, childKey, childMovedSubs, previousChildKey, isVolatile, serverTimestamp);\n }\n }\n\n // Update stored order\n this.orderedChildren.set(subscriptionPath, currentOrder);\n }\n\n /**\n * Insert a key into an ordered array after a specific key.\n * If afterKey is empty string or undefined, insert at beginning.\n * If afterKey is not found, append at end.\n */\n private insertAfterKey(order: string[], key: string, afterKey?: string): void {\n if (afterKey === '' || afterKey === undefined) {\n // Insert at beginning\n order.unshift(key);\n } else {\n const afterIdx = order.indexOf(afterKey);\n if (afterIdx === -1) {\n // afterKey not found, append at end\n order.push(key);\n } else {\n // Insert after afterKey\n order.splice(afterIdx + 1, 0, key);\n }\n }\n }\n\n /**\n * Get the previous sibling key for a given key in the ordered array.\n */\n private getPreviousChildKey(order: string[], key: string): string | null {\n const idx = order.indexOf(key);\n if (idx <= 0) return null;\n return order[idx - 1];\n }\n\n /**\n * Fire callbacks for subscribed event types.\n */\n private fireCallbacks(\n subscriptionPath: string,\n pathSubs: Map<EventType, SubscriptionEntry[]>,\n relativePath: string,\n value: unknown,\n previousOrder: string[],\n currentOrder: string[],\n previousChildSet: Set<string>,\n currentChildSet: Set<string>,\n afterKey: string | undefined,\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n // Fire 'value' callbacks with full snapshot\n const valueSubs = pathSubs.get('value');\n if (valueSubs && valueSubs.length > 0) {\n const fullValue = this.cache.get(subscriptionPath).value;\n const snapshot = this.createSnapshot?.(subscriptionPath, fullValue, isVolatile, serverTimestamp);\n if (snapshot) {\n for (const entry of valueSubs) {\n try {\n entry.callback(snapshot, undefined);\n } catch (err) {\n console.error('Error in value subscription callback:', err);\n }\n }\n }\n }\n\n // Generate and fire child_* events\n this.fireChildEvents(\n subscriptionPath,\n pathSubs,\n relativePath,\n value,\n previousOrder,\n currentOrder,\n previousChildSet,\n currentChildSet,\n afterKey,\n isVolatile,\n serverTimestamp\n );\n }\n\n /**\n * Generate and fire child_added, child_changed, child_removed events.\n * child_moved is handled separately via handleMoves().\n */\n private fireChildEvents(\n subscriptionPath: string,\n pathSubs: Map<EventType, SubscriptionEntry[]>,\n relativePath: string,\n value: unknown,\n previousOrder: string[],\n currentOrder: string[],\n previousChildSet: Set<string>,\n currentChildSet: Set<string>,\n afterKey: string | undefined,\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n const childAddedSubs = pathSubs.get('child_added') ?? [];\n const childChangedSubs = pathSubs.get('child_changed') ?? [];\n const childRemovedSubs = pathSubs.get('child_removed') ?? [];\n\n // No child subscriptions, skip\n if (childAddedSubs.length === 0 && childChangedSubs.length === 0 && childRemovedSubs.length === 0) {\n return;\n }\n\n if (relativePath === '/') {\n // Full snapshot - compare old and new children\n // Find added children (fire in order)\n for (const key of currentOrder) {\n if (!previousChildSet.has(key)) {\n const prevKey = this.getPreviousChildKey(currentOrder, key);\n this.fireChildAdded(subscriptionPath, key, childAddedSubs, prevKey, isVolatile, serverTimestamp);\n }\n }\n\n // Find removed children\n for (const key of previousOrder) {\n if (!currentChildSet.has(key)) {\n this.fireChildRemoved(subscriptionPath, key, childRemovedSubs, isVolatile, serverTimestamp);\n }\n }\n } else {\n // Delta update - parse relative path to find immediate child\n const segments = relativePath.split('/').filter(s => s.length > 0);\n if (segments.length === 0) return;\n\n const childKey = segments[0];\n\n if (value === null) {\n // Child was deleted\n if (previousChildSet.has(childKey) && !currentChildSet.has(childKey)) {\n this.fireChildRemoved(subscriptionPath, childKey, childRemovedSubs, isVolatile, serverTimestamp);\n }\n } else if (!previousChildSet.has(childKey)) {\n // New child - use afterKey if provided, otherwise compute from current order\n const prevKey = afterKey !== undefined\n ? (afterKey === '' ? null : afterKey)\n : this.getPreviousChildKey(currentOrder, childKey);\n this.fireChildAdded(subscriptionPath, childKey, childAddedSubs, prevKey, isVolatile, serverTimestamp);\n } else {\n // Existing child changed\n const prevKey = this.getPreviousChildKey(currentOrder, childKey);\n this.fireChildChanged(subscriptionPath, childKey, childChangedSubs, prevKey, isVolatile, serverTimestamp);\n }\n }\n }\n\n /**\n * Fire child_added callbacks for a child key.\n */\n private fireChildAdded(\n subscriptionPath: string,\n childKey: string,\n subs: SubscriptionEntry[],\n previousChildKey: string | null,\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n if (subs.length === 0) return;\n\n const childPath = joinPath(subscriptionPath, childKey);\n const childValue = this.cache.get(childPath).value;\n const snapshot = this.createSnapshot?.(childPath, childValue, isVolatile, serverTimestamp);\n\n if (snapshot) {\n for (const entry of subs) {\n try {\n entry.callback(snapshot, previousChildKey);\n } catch (err) {\n console.error('Error in child_added subscription callback:', err);\n }\n }\n }\n }\n\n /**\n * Fire child_changed callbacks for a child key.\n */\n private fireChildChanged(\n subscriptionPath: string,\n childKey: string,\n subs: SubscriptionEntry[],\n previousChildKey: string | null,\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n if (subs.length === 0) return;\n\n const childPath = joinPath(subscriptionPath, childKey);\n const childValue = this.cache.get(childPath).value;\n const snapshot = this.createSnapshot?.(childPath, childValue, isVolatile, serverTimestamp);\n\n if (snapshot) {\n for (const entry of subs) {\n try {\n entry.callback(snapshot, previousChildKey);\n } catch (err) {\n console.error('Error in child_changed subscription callback:', err);\n }\n }\n }\n }\n\n /**\n * Fire child_removed callbacks for a child key.\n */\n private fireChildRemoved(\n subscriptionPath: string,\n childKey: string,\n subs: SubscriptionEntry[],\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n if (subs.length === 0) return;\n\n const childPath = joinPath(subscriptionPath, childKey);\n // For removed children, we may not have the value anymore\n // Create snapshot with null value\n const snapshot = this.createSnapshot?.(childPath, null, isVolatile, serverTimestamp);\n\n if (snapshot) {\n for (const entry of subs) {\n try {\n // previousChildKey is not meaningful for removed children\n entry.callback(snapshot, undefined);\n } catch (err) {\n console.error('Error in child_removed subscription callback:', err);\n }\n }\n }\n }\n\n /**\n * Fire child_moved callbacks for a child key.\n */\n private fireChildMoved(\n subscriptionPath: string,\n childKey: string,\n subs: SubscriptionEntry[],\n previousChildKey: string | null,\n isVolatile: boolean,\n serverTimestamp?: number\n ): void {\n if (subs.length === 0) return;\n\n const childPath = joinPath(subscriptionPath, childKey);\n const childValue = this.cache.get(childPath).value;\n const snapshot = this.createSnapshot?.(childPath, childValue, isVolatile, serverTimestamp);\n\n if (snapshot) {\n for (const entry of subs) {\n try {\n entry.callback(snapshot, previousChildKey);\n } catch (err) {\n console.error('Error in child_moved subscription callback:', err);\n }\n }\n }\n }\n\n /**\n * Get all event types currently subscribed at a path.\n */\n private getEventTypesForPath(path: string): EventType[] {\n const pathSubs = this.subscriptions.get(path);\n if (!pathSubs) return [];\n return Array.from(pathSubs.keys());\n }\n\n /**\n * Clear all subscriptions (e.g., on disconnect).\n */\n clear(): void {\n this.subscriptions.clear();\n this.orderedChildren.clear();\n this.queryParams.clear();\n this.cache.clear();\n }\n\n /**\n * Check if there are any subscriptions at a path.\n */\n hasSubscriptions(path: string): boolean {\n return this.subscriptions.has(path);\n }\n\n /**\n * Check if a path is \"covered\" by an active subscription.\n *\n * A path is covered if:\n * - There's an active 'value' subscription at that exact path, OR\n * - There's an active 'value' subscription at an ancestor path\n *\n * Child event subscriptions (child_added, etc.) don't provide full coverage\n * because they only notify of changes, not the complete value.\n */\n isPathCovered(path: string): boolean {\n const normalized = normalizePath(path);\n\n // Check exact match - must have 'value' subscription\n if (this.hasValueSubscription(normalized)) {\n return true;\n }\n\n // Check ancestors - walk up the path tree\n const segments = normalized.split('/').filter((s) => s.length > 0);\n\n for (let i = segments.length - 1; i >= 0; i--) {\n const ancestorPath = i === 0 ? '/' : '/' + segments.slice(0, i).join('/');\n if (this.hasValueSubscription(ancestorPath)) {\n return true;\n }\n }\n\n // Check root\n if (normalized !== '/' && this.hasValueSubscription('/')) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Check if there's a 'value' subscription at a path.\n */\n private hasValueSubscription(path: string): boolean {\n const pathSubs = this.subscriptions.get(path);\n if (!pathSubs) return false;\n const valueSubs = pathSubs.get('value');\n return valueSubs !== undefined && valueSubs.length > 0;\n }\n\n /**\n * Get a cached value if the path is covered by an active subscription.\n *\n * Returns { value, found: true } if we have cached data for this path\n * (either exact match or extractable from a cached ancestor).\n *\n * Returns { value: undefined, found: false } if:\n * - The path is not covered by any subscription, OR\n * - We don't have cached data yet\n */\n getCachedValue(path: string): { value: unknown; found: boolean } {\n const normalized = normalizePath(path);\n\n // First check if the path is covered by a subscription\n if (!this.isPathCovered(normalized)) {\n return { value: undefined, found: false };\n }\n\n // Path is covered, try to get from cache\n return this.cache.get(normalized);\n }\n\n /**\n * Get the cache size (for testing/debugging).\n */\n get cacheSize(): number {\n return this.cache.size;\n }\n}\n","/**\n * WebSocketClient - wrapper around WebSocket with event handling and reconnection support.\n * Works in both browser (native WebSocket) and Node.js (ws package).\n */\n\nimport WebSocketNode from 'ws';\n\n// Use native WebSocket in browser, ws package in Node.js\nconst WebSocketImpl: typeof WebSocket =\n typeof WebSocket !== 'undefined' ? WebSocket : (WebSocketNode as unknown as typeof WebSocket);\n\nexport type WebSocketState = 'disconnected' | 'connecting' | 'connected';\n\nexport interface WebSocketClientOptions {\n onMessage: (data: string) => void;\n onOpen: () => void;\n onClose: (code: number, reason: string) => void;\n onError: (error: Event) => void;\n}\n\nexport class WebSocketClient {\n private ws: WebSocket | null = null;\n private options: WebSocketClientOptions;\n private _state: WebSocketState = 'disconnected';\n\n constructor(options: WebSocketClientOptions) {\n this.options = options;\n }\n\n get state(): WebSocketState {\n return this._state;\n }\n\n get connected(): boolean {\n return this._state === 'connected';\n }\n\n /**\n * Connect to a WebSocket server.\n */\n connect(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this._state !== 'disconnected') {\n reject(new Error('Already connected or connecting'));\n return;\n }\n\n this._state = 'connecting';\n\n try {\n this.ws = new WebSocketImpl(url) as WebSocket;\n } catch (err) {\n this._state = 'disconnected';\n reject(err);\n return;\n }\n\n const onOpen = () => {\n cleanup();\n this._state = 'connected';\n this.setupEventHandlers();\n resolve();\n this.options.onOpen();\n };\n\n const onError = (event: Event) => {\n cleanup();\n this._state = 'disconnected';\n this.ws = null;\n reject(new Error('WebSocket connection failed'));\n this.options.onError(event);\n };\n\n const onClose = (event: CloseEvent) => {\n cleanup();\n this._state = 'disconnected';\n this.ws = null;\n reject(new Error(`WebSocket closed: ${event.code} ${event.reason}`));\n };\n\n const cleanup = () => {\n this.ws?.removeEventListener('open', onOpen);\n this.ws?.removeEventListener('error', onError);\n this.ws?.removeEventListener('close', onClose);\n };\n\n this.ws.addEventListener('open', onOpen);\n this.ws.addEventListener('error', onError);\n this.ws.addEventListener('close', onClose);\n });\n }\n\n /**\n * Set up persistent event handlers after connection is established.\n */\n private setupEventHandlers(): void {\n if (!this.ws) return;\n\n this.ws.addEventListener('message', (event: MessageEvent) => {\n this.options.onMessage(event.data as string);\n });\n\n this.ws.addEventListener('close', (event: CloseEvent) => {\n this._state = 'disconnected';\n this.ws = null;\n this.options.onClose(event.code, event.reason);\n });\n\n this.ws.addEventListener('error', (event: Event) => {\n this.options.onError(event);\n });\n }\n\n /**\n * Send a message over the WebSocket.\n */\n send(data: string): void {\n if (!this.ws || this._state !== 'connected') {\n throw new Error('WebSocket not connected');\n }\n this.ws.send(data);\n }\n\n /**\n * Close the WebSocket connection.\n */\n close(code: number = 1000, reason: string = 'Client disconnect'): void {\n if (this.ws) {\n this.ws.close(code, reason);\n this.ws = null;\n }\n this._state = 'disconnected';\n }\n}\n","/**\n * OnDisconnect - registers operations to perform on the server when this client disconnects.\n */\n\nimport type { LarkDatabase } from './LarkDatabase';\nimport { OnDisconnectAction } from './protocol/constants';\n\nexport class OnDisconnect {\n private readonly _db: LarkDatabase;\n private readonly _path: string;\n\n constructor(db: LarkDatabase, path: string) {\n this._db = db;\n this._path = path;\n }\n\n /**\n * Set a value when disconnected.\n */\n async set(value: unknown): Promise<void> {\n await this._db._sendOnDisconnect(this._path, OnDisconnectAction.SET, value);\n }\n\n /**\n * Update values when disconnected.\n */\n async update(values: Record<string, unknown>): Promise<void> {\n await this._db._sendOnDisconnect(this._path, OnDisconnectAction.UPDATE, values);\n }\n\n /**\n * Remove data when disconnected.\n */\n async remove(): Promise<void> {\n await this._db._sendOnDisconnect(this._path, OnDisconnectAction.DELETE);\n }\n\n /**\n * Cancel any pending onDisconnect handlers at this location.\n */\n async cancel(): Promise<void> {\n await this._db._sendOnDisconnect(this._path, OnDisconnectAction.CANCEL);\n }\n\n /**\n * Set a value with priority when disconnected.\n */\n async setWithPriority(value: unknown, priority: number | string): Promise<void> {\n await this._db._sendOnDisconnect(this._path, OnDisconnectAction.SET, value, priority);\n }\n}\n","/**\n * Push ID generation - Firebase-compatible chronologically-sortable IDs.\n *\n * Format: 20 characters\n * - First 8 chars: timestamp (milliseconds since epoch, base64-encoded)\n * - Last 12 chars: random suffix (incremented on same-millisecond calls)\n *\n * This ensures:\n * - IDs created later sort after IDs created earlier\n * - IDs created in the same millisecond are unique and still sort correctly\n */\n\nconst PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';\n\n// Persistent state for generating unique IDs within the same millisecond\nlet lastPushTime = 0;\nlet lastRandChars: number[] = [];\n\n/**\n * Generate a Firebase-compatible push ID.\n */\nexport function generatePushId(): string {\n let now = Date.now();\n const duplicateTime = now === lastPushTime;\n lastPushTime = now;\n\n // Encode timestamp in first 8 characters\n const timeChars = new Array(8);\n for (let i = 7; i >= 0; i--) {\n timeChars[i] = PUSH_CHARS.charAt(now % 64);\n now = Math.floor(now / 64);\n }\n\n let id = timeChars.join('');\n\n if (!duplicateTime) {\n // New timestamp - generate fresh random suffix\n lastRandChars = [];\n for (let i = 0; i < 12; i++) {\n lastRandChars.push(Math.floor(Math.random() * 64));\n }\n } else {\n // Same timestamp - increment the random suffix\n // This ensures uniqueness even with multiple calls in the same millisecond\n let i = 11;\n while (i >= 0 && lastRandChars[i] === 63) {\n lastRandChars[i] = 0;\n i--;\n }\n if (i >= 0) {\n lastRandChars[i]++;\n }\n }\n\n // Append random suffix\n for (let i = 0; i < 12; i++) {\n id += PUSH_CHARS.charAt(lastRandChars[i]);\n }\n\n return id;\n}\n","/**\n * DatabaseReference - a reference to a specific path in the database.\n * Immutable - navigation returns new references.\n */\n\nimport type { DataSnapshot } from './DataSnapshot';\nimport type { LarkDatabase } from './LarkDatabase';\nimport { LarkError } from './LarkError';\nimport { OnDisconnect } from './OnDisconnect';\nimport { ErrorCode, EventType } from './protocol/constants';\nimport { QueryParams, TxOperation } from './protocol/messages';\nimport { getKey, getParentPath, joinPath, normalizePath } from './utils/path';\nimport { generatePushId } from './utils/pushid';\n\n/** Result of a transaction operation */\nexport interface TransactionResult {\n /** Whether the transaction was committed (always true on success) */\n committed: boolean;\n /** Snapshot of the data after the transaction */\n snapshot: DataSnapshot;\n}\n\n/** Default maximum retries for optimistic transactions */\nconst DEFAULT_MAX_RETRIES = 25;\n\nexport type SnapshotCallback = (snapshot: DataSnapshot, previousChildKey?: string | null) => void;\n\nexport interface QueryState {\n orderBy?: 'key' | 'priority' | 'child' | 'value';\n orderByChildPath?: string;\n limitToFirst?: number;\n limitToLast?: number;\n startAt?: { value: unknown; key?: string };\n endAt?: { value: unknown; key?: string };\n equalTo?: { value: unknown; key?: string };\n}\n\nexport class DatabaseReference {\n private readonly _db: LarkDatabase;\n private readonly _path: string;\n private readonly _query: QueryState;\n\n constructor(db: LarkDatabase, path: string, query: QueryState = {}) {\n this._db = db;\n this._path = normalizePath(path);\n this._query = query;\n }\n\n /**\n * The path of this reference.\n */\n get path(): string {\n return this._path;\n }\n\n /**\n * The last segment of the path (the \"key\"), or null for root.\n */\n get key(): string | null {\n return getKey(this._path);\n }\n\n /**\n * Get a reference to the parent node, or null if this is root.\n */\n get parent(): DatabaseReference | null {\n if (this._path === '/') return null;\n const parentPath = getParentPath(this._path);\n return new DatabaseReference(this._db, parentPath);\n }\n\n /**\n * Get a reference to the root of the database.\n */\n get root(): DatabaseReference {\n return new DatabaseReference(this._db, '');\n }\n\n // ============================================\n // Navigation\n // ============================================\n\n /**\n * Get a reference to a child path.\n */\n child(path: string): DatabaseReference {\n const childPath = joinPath(this._path, path);\n return new DatabaseReference(this._db, childPath);\n }\n\n // ============================================\n // Write Operations\n // ============================================\n\n /**\n * Set the data at this location, overwriting any existing data.\n */\n async set(value: unknown): Promise<void> {\n await this._db._sendSet(this._path, value);\n }\n\n /**\n * Update specific children at this location without overwriting other children.\n *\n * Also supports Firebase-style multi-path updates when keys look like paths\n * (start with '/'). In this mode, each path is written atomically as a transaction.\n *\n * @example\n * ```javascript\n * // Normal update (merge at single path)\n * await ref.update({ score: 10, name: 'Riley' });\n *\n * // Multi-path update (atomic writes to multiple paths)\n * await db.ref().update({\n * '/users/alice/score': 100,\n * '/users/bob/score': 200,\n * '/leaderboard/alice': null // null = delete\n * });\n * ```\n */\n async update(values: Record<string, unknown>): Promise<void> {\n // Check if any key looks like a path (starts with '/')\n const hasPathKeys = Object.keys(values).some((key) => key.startsWith('/'));\n\n if (hasPathKeys) {\n // Multi-path mode: use transaction for atomic writes\n const ops: TxOperation[] = [];\n\n for (const [key, value] of Object.entries(values)) {\n // Resolve path relative to this ref\n const fullPath = key.startsWith('/')\n ? joinPath(this._path, key)\n : joinPath(this._path, key);\n const normalizedPath = normalizePath(fullPath) || '/';\n\n if (value === null) {\n // null = delete\n ops.push({ o: 'd', p: normalizedPath });\n } else {\n // set the value (not merge, matching Firebase behavior)\n ops.push({ o: 's', p: normalizedPath, v: value });\n }\n }\n\n await this._db._sendTransaction(ops);\n } else {\n // Normal update (merge at single path)\n await this._db._sendUpdate(this._path, values);\n }\n }\n\n /**\n * Remove the data at this location.\n */\n async remove(): Promise<void> {\n await this._db._sendDelete(this._path);\n }\n\n /**\n * Generate a new child location with a unique key and optionally set its value.\n *\n * If value is provided, sets the value and returns a Promise that resolves\n * to the new reference.\n *\n * If no value is provided, returns a reference immediately with a client-generated\n * push key (you can then call set() on it).\n */\n push(value?: unknown): DatabaseReference | Promise<DatabaseReference> {\n if (value === undefined) {\n // No value - return reference with client-generated key immediately\n const key = generatePushId();\n return this.child(key);\n }\n\n // Value provided - send to server and return promise\n return this._db._sendPush(this._path, value).then((key) => {\n return this.child(key);\n });\n }\n\n /**\n * Set the data with a priority value for ordering.\n */\n async setWithPriority(value: unknown, priority: number | string): Promise<void> {\n await this._db._sendSet(this._path, value, priority);\n }\n\n /**\n * Set the priority of the data at this location.\n */\n async setPriority(priority: number | string): Promise<void> {\n // To set only priority, we need to set .priority on the special path\n // For now, we'll use setWithPriority with the current value\n // This is a simplified implementation\n console.warn('setPriority: fetching current value to preserve it');\n const snapshot = await this.once();\n await this.setWithPriority(snapshot.val(), priority);\n }\n\n /**\n * Atomically modify the data at this location using optimistic concurrency.\n *\n * The update function receives the current value and should return the new\n * value. If the data changed on the server before the write could be\n * committed, the function is called again with the new value, and the\n * process repeats until successful or the maximum retries are exceeded.\n *\n * @example\n * ```javascript\n * // Increment a counter atomically\n * const result = await ref.transaction(currentValue => {\n * return (currentValue || 0) + 1;\n * });\n * console.log('New value:', result.snapshot.val());\n * ```\n *\n * @param updateFunction - Function that receives current value and returns new value.\n * Return undefined to abort the transaction.\n * @param maxRetries - Maximum number of retries (default: 25)\n * @returns TransactionResult with committed status and final snapshot\n */\n async transaction(\n updateFunction: (currentValue: unknown) => unknown,\n maxRetries: number = DEFAULT_MAX_RETRIES\n ): Promise<TransactionResult> {\n let retries = 0;\n\n while (retries < maxRetries) {\n // Step 1: Read current value\n const currentSnapshot = await this.once();\n const currentValue = currentSnapshot.val();\n\n // Step 2: Call update function\n const newValue = updateFunction(currentValue);\n\n // Step 3: If undefined returned, abort\n if (newValue === undefined) {\n return {\n committed: false,\n snapshot: currentSnapshot,\n };\n }\n\n // Step 4: Build transaction with condition + set\n const ops: TxOperation[] = [\n { o: 'c', p: this._path, v: currentValue },\n { o: 's', p: this._path, v: newValue },\n ];\n\n try {\n // Step 5: Try to commit\n await this._db._sendTransaction(ops);\n\n // Success! Read back the value for the result snapshot\n const finalSnapshot = await this.once();\n return {\n committed: true,\n snapshot: finalSnapshot,\n };\n } catch (error) {\n // Step 6: If condition failed, retry\n if (error instanceof LarkError && error.code === ErrorCode.CONDITION_FAILED) {\n retries++;\n continue;\n }\n // Other errors should propagate\n throw error;\n }\n }\n\n // Max retries exceeded\n throw new LarkError(\n 'max_retries_exceeded',\n `Transaction failed after ${maxRetries} retries`\n );\n }\n\n // ============================================\n // Read Operations\n // ============================================\n\n /**\n * Read the data at this location once.\n */\n async once(eventType: 'value' = 'value'): Promise<DataSnapshot> {\n if (eventType !== 'value') {\n throw new Error('once() only supports \"value\" event type');\n }\n return this._db._sendOnce(this._path, this._buildQueryParams());\n }\n\n // ============================================\n // Subscriptions\n // ============================================\n\n /**\n * Subscribe to events at this location.\n * Returns an unsubscribe function.\n */\n on(eventType: EventType, callback: SnapshotCallback): () => void {\n return this._db._subscribe(this._path, eventType, callback, this._buildQueryParams());\n }\n\n /**\n * Unsubscribe from events.\n * If eventType is specified, removes all listeners of that type.\n * If no eventType, removes ALL listeners at this path.\n */\n off(eventType?: EventType): void {\n if (eventType) {\n this._db._unsubscribeEventType(this._path, eventType);\n } else {\n this._db._unsubscribeAll(this._path);\n }\n }\n\n // ============================================\n // OnDisconnect\n // ============================================\n\n /**\n * Get an OnDisconnect handler for this location.\n */\n onDisconnect(): OnDisconnect {\n return new OnDisconnect(this._db, this._path);\n }\n\n // ============================================\n // Query Modifiers\n // ============================================\n\n /**\n * Order results by key.\n */\n orderByKey(): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n orderBy: 'key',\n });\n }\n\n /**\n * Order results by priority.\n */\n orderByPriority(): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n orderBy: 'priority',\n });\n }\n\n /**\n * Order results by a child key.\n */\n orderByChild(path: string): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n orderBy: 'child',\n orderByChildPath: path,\n });\n }\n\n /**\n * Order results by value.\n */\n orderByValue(): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n orderBy: 'value',\n });\n }\n\n /**\n * Limit to the first N results.\n */\n limitToFirst(limit: number): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n limitToFirst: limit,\n });\n }\n\n /**\n * Limit to the last N results.\n */\n limitToLast(limit: number): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n limitToLast: limit,\n });\n }\n\n /**\n * Start at a specific value/key.\n */\n startAt(value: unknown, key?: string): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n startAt: { value, key },\n });\n }\n\n /**\n * End at a specific value/key.\n */\n endAt(value: unknown, key?: string): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n endAt: { value, key },\n });\n }\n\n /**\n * Filter to items equal to a specific value.\n */\n equalTo(value: unknown, key?: string): DatabaseReference {\n return new DatabaseReference(this._db, this._path, {\n ...this._query,\n equalTo: { value, key },\n });\n }\n\n // ============================================\n // Internal Helpers\n // ============================================\n\n /**\n * Build query parameters for wire protocol.\n */\n private _buildQueryParams(): QueryParams | undefined {\n const params: QueryParams = {};\n let hasParams = false;\n\n // Order by\n if (this._query.orderBy === 'key') {\n params.orderBy = 'key';\n hasParams = true;\n } else if (this._query.orderBy === 'priority') {\n params.orderBy = 'priority';\n hasParams = true;\n } else if (this._query.orderBy === 'child') {\n params.orderBy = 'child';\n if (this._query.orderByChildPath) {\n params.orderByChild = this._query.orderByChildPath;\n }\n hasParams = true;\n } else if (this._query.orderBy === 'value') {\n params.orderBy = 'value';\n hasParams = true;\n }\n\n // Limits\n if (this._query.limitToFirst !== undefined) {\n params.limitToFirst = this._query.limitToFirst;\n hasParams = true;\n }\n\n if (this._query.limitToLast !== undefined) {\n params.limitToLast = this._query.limitToLast;\n hasParams = true;\n }\n\n // Range queries\n if (this._query.startAt !== undefined) {\n params.startAt = this._query.startAt.value;\n if (this._query.startAt.key !== undefined) {\n params.startAtKey = this._query.startAt.key;\n }\n hasParams = true;\n }\n\n if (this._query.endAt !== undefined) {\n params.endAt = this._query.endAt.value;\n if (this._query.endAt.key !== undefined) {\n params.endAtKey = this._query.endAt.key;\n }\n hasParams = true;\n }\n\n if (this._query.equalTo !== undefined) {\n params.equalTo = this._query.equalTo.value;\n if (this._query.equalTo.key !== undefined) {\n params.equalToKey = this._query.equalTo.key;\n }\n hasParams = true;\n }\n\n return hasParams ? params : undefined;\n }\n\n /**\n * Returns the absolute URL for this database location.\n * Format: https://db.lark.sh/project/database/path/to/data\n */\n toString(): string {\n const baseUrl = this._db._getBaseUrl();\n // For root, just return base URL; otherwise append path (path already has leading slash)\n if (this._path === '/') {\n return baseUrl;\n }\n return `${baseUrl}${this._path}`;\n }\n}\n","/**\n * DataSnapshot - an immutable snapshot of data at a location.\n * Received in event callbacks and from once() operations.\n */\n\nimport type { DatabaseReference } from './DatabaseReference';\nimport type { LarkDatabase } from './LarkDatabase';\nimport { getKey, getValueAtPath, joinPath, normalizePath } from './utils/path';\n\nexport class DataSnapshot {\n private readonly _data: unknown;\n private readonly _path: string;\n private readonly _db: LarkDatabase;\n private readonly _volatile: boolean;\n private readonly _priority: number | string | null;\n private readonly _serverTimestamp: number | null;\n\n constructor(\n data: unknown,\n path: string,\n db: LarkDatabase,\n options: { volatile?: boolean; priority?: number | string | null; serverTimestamp?: number | null } = {}\n ) {\n this._data = data;\n this._path = normalizePath(path);\n this._db = db;\n this._volatile = options.volatile ?? false;\n this._priority = options.priority ?? null;\n this._serverTimestamp = options.serverTimestamp ?? null;\n }\n\n /**\n * Get a DatabaseReference for the location of this snapshot.\n */\n get ref(): DatabaseReference {\n return this._db.ref(this._path);\n }\n\n /**\n * Get the last segment of the path (the \"key\"), or null for root.\n */\n get key(): string | null {\n return getKey(this._path);\n }\n\n /**\n * Get the raw data value.\n */\n val(): unknown {\n return this._data;\n }\n\n /**\n * Check if data exists at this location (is not null/undefined).\n */\n exists(): boolean {\n return this._data !== null && this._data !== undefined;\n }\n\n /**\n * Get a child snapshot at the specified path.\n */\n child(path: string): DataSnapshot {\n const childPath = joinPath(this._path, path);\n const childData = getValueAtPath(this._data, path);\n return new DataSnapshot(childData, childPath, this._db, {\n volatile: this._volatile,\n serverTimestamp: this._serverTimestamp,\n });\n }\n\n /**\n * Check if this snapshot has any children.\n */\n hasChildren(): boolean {\n if (typeof this._data !== 'object' || this._data === null) {\n return false;\n }\n return Object.keys(this._data).length > 0;\n }\n\n /**\n * Check if this snapshot has a specific child.\n */\n hasChild(path: string): boolean {\n const childData = getValueAtPath(this._data, path);\n return childData !== undefined && childData !== null;\n }\n\n /**\n * Get the number of children.\n */\n numChildren(): number {\n if (typeof this._data !== 'object' || this._data === null) {\n return 0;\n }\n return Object.keys(this._data).length;\n }\n\n /**\n * Iterate over children. Return true from callback to stop iteration.\n */\n forEach(callback: (child: DataSnapshot) => boolean | void): void {\n if (typeof this._data !== 'object' || this._data === null) {\n return;\n }\n\n const keys = Object.keys(this._data);\n for (const key of keys) {\n const childSnap = this.child(key);\n if (callback(childSnap) === true) {\n break;\n }\n }\n }\n\n /**\n * Get the priority of the data at this location.\n */\n getPriority(): number | string | null {\n return this._priority;\n }\n\n /**\n * Check if this snapshot was from a volatile (high-frequency) update.\n * This is a Lark extension not present in Firebase.\n */\n isVolatile(): boolean {\n return this._volatile;\n }\n\n /**\n * Get the server timestamp for this snapshot (milliseconds since Unix epoch).\n * Only present on volatile value events. Use deltas between timestamps for\n * interpolation rather than absolute times to avoid clock sync issues.\n * This is a Lark extension not present in Firebase.\n */\n getServerTimestamp(): number | null {\n return this._serverTimestamp;\n }\n\n /**\n * Export the snapshot data as JSON (alias for val()).\n */\n toJSON(): unknown {\n return this._data;\n }\n}\n","/**\n * Simple JWT payload decoder (no verification - server validates).\n * JWTs are three base64url-encoded parts separated by dots: header.payload.signature\n */\n\nexport interface JwtPayload {\n sub: string; // User ID\n aud: string; // Database ID\n project: string; // Project ID\n server: string; // Server ID\n provider: string; // Auth provider\n claims: Record<string, unknown>; // Custom claims\n iss: string; // Issuer\n iat: number; // Issued at\n exp: number; // Expiration\n}\n\n/**\n * Decode a JWT payload without verification.\n * The server validates the token - we just need to read the claims.\n */\nexport function decodeJwtPayload(token: string): JwtPayload {\n const parts = token.split('.');\n if (parts.length !== 3) {\n throw new Error('Invalid JWT format');\n }\n\n const payload = parts[1];\n\n // Base64url decode (replace - with +, _ with /, add padding)\n const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);\n\n // Decode - works in both browser and Node.js\n let decoded: string;\n if (typeof atob === 'function') {\n // Browser\n decoded = atob(padded);\n } else {\n // Node.js\n decoded = Buffer.from(padded, 'base64').toString('utf-8');\n }\n\n return JSON.parse(decoded) as JwtPayload;\n}\n","/**\n * LarkDatabase - the main entry point for connecting to a Lark database.\n */\n\nimport { Coordinator } from './connection/Coordinator';\nimport { MessageQueue } from './connection/MessageQueue';\nimport { PendingWriteManager } from './connection/PendingWriteManager';\nimport { SubscriptionManager, SnapshotCallback } from './connection/SubscriptionManager';\nimport { WebSocketClient } from './connection/WebSocketClient';\nimport { DatabaseReference } from './DatabaseReference';\nimport { DataSnapshot } from './DataSnapshot';\nimport { LarkError } from './LarkError';\nimport { DEFAULT_COORDINATOR_URL, EventType } from './protocol/constants';\nimport {\n ClientMessage,\n ServerMessage,\n isAckMessage,\n isEventMessage,\n isNackMessage,\n isPingMessage,\n QueryParams,\n TxOperation,\n TransactionMessage,\n} from './protocol/messages';\nimport { decodeJwtPayload } from './utils/jwt';\nimport { normalizePath } from './utils/path';\n\nexport interface ConnectOptions {\n /** User's auth token (from your auth system) */\n token?: string;\n\n /** Connect anonymously (server assigns a UID) */\n anonymous?: boolean;\n\n /** Coordinator URL (default: https://db.lark.dev) */\n coordinator?: string;\n}\n\nexport interface AuthInfo {\n uid: string;\n provider: string;\n token: Record<string, unknown>;\n}\n\n// ============================================\n// Transaction Types (Public API)\n// ============================================\n\n/** A set operation in a transaction */\nexport interface TransactionSetOp {\n op: 'set';\n path: string;\n value: unknown;\n}\n\n/** An update (merge) operation in a transaction */\nexport interface TransactionUpdateOp {\n op: 'update';\n path: string;\n value: Record<string, unknown>;\n}\n\n/** A delete operation in a transaction */\nexport interface TransactionDeleteOp {\n op: 'delete';\n path: string;\n}\n\n/** A condition check in a transaction (for compare-and-swap) */\nexport interface TransactionConditionOp {\n op: 'condition';\n path: string;\n value: unknown;\n}\n\n/** A single operation in a transaction (array syntax) */\nexport type TransactionOp =\n | TransactionSetOp\n | TransactionUpdateOp\n | TransactionDeleteOp\n | TransactionConditionOp;\n\n/** Object syntax for transactions: path -> value (null = delete) */\nexport type TransactionObject = Record<string, unknown>;\n\ntype ConnectionState = 'disconnected' | 'connecting' | 'connected';\n\nexport class LarkDatabase {\n private _state: ConnectionState = 'disconnected';\n private _auth: AuthInfo | null = null;\n private _databaseId: string | null = null;\n private _coordinatorUrl: string | null = null;\n private _volatilePaths: string[] = [];\n\n private ws: WebSocketClient | null = null;\n private messageQueue: MessageQueue;\n private subscriptionManager: SubscriptionManager;\n private pendingWrites: PendingWriteManager;\n\n // Event callbacks\n private connectCallbacks = new Set<() => void>();\n private disconnectCallbacks = new Set<() => void>();\n private errorCallbacks = new Set<(error: Error) => void>();\n\n constructor() {\n this.messageQueue = new MessageQueue();\n this.subscriptionManager = new SubscriptionManager();\n this.pendingWrites = new PendingWriteManager();\n }\n\n // ============================================\n // Connection State\n // ============================================\n\n /**\n * Whether the database is currently connected.\n */\n get connected(): boolean {\n return this._state === 'connected';\n }\n\n /**\n * Current auth info, or null if not connected.\n */\n get auth(): AuthInfo | null {\n return this._auth;\n }\n\n /**\n * @internal Get the base URL for reference toString().\n */\n _getBaseUrl(): string {\n if (this._coordinatorUrl && this._databaseId) {\n return `${this._coordinatorUrl}/${this._databaseId}`;\n }\n return 'lark://';\n }\n\n /**\n * Get the volatile path patterns from the server.\n * These patterns indicate which paths should use unreliable transport.\n * WebSocket always uses reliable transport, but this is stored for future UDP support.\n */\n get volatilePaths(): string[] {\n return this._volatilePaths;\n }\n\n /**\n * Check if there are any pending writes waiting for acknowledgment.\n * Useful for showing \"saving...\" indicators in UI.\n */\n hasPendingWrites(): boolean {\n return this.pendingWrites.pendingCount > 0;\n }\n\n /**\n * Get the number of pending writes waiting for acknowledgment.\n */\n getPendingWriteCount(): number {\n return this.pendingWrites.pendingCount;\n }\n\n /**\n * Clear all pending writes.\n * Call this if you don't want to retry writes on reconnect.\n */\n clearPendingWrites(): void {\n this.pendingWrites.clear();\n }\n\n // ============================================\n // Connection Management\n // ============================================\n\n /**\n * Connect to a database.\n *\n * @param databaseId - Database ID in format \"project/database\"\n * @param options - Connection options (token, anonymous, coordinator URL)\n */\n async connect(databaseId: string, options: ConnectOptions = {}): Promise<void> {\n if (this._state !== 'disconnected') {\n throw new Error('Already connected or connecting');\n }\n\n this._state = 'connecting';\n this._databaseId = databaseId;\n this._coordinatorUrl = options.coordinator || DEFAULT_COORDINATOR_URL;\n\n try {\n // Step 1: Get connection details from coordinator\n const coordinatorUrl = this._coordinatorUrl;\n const coordinator = new Coordinator(coordinatorUrl);\n\n const connectResponse = await coordinator.connect(databaseId, {\n token: options.token,\n anonymous: options.anonymous,\n });\n\n // Step 2: Connect to the server via WebSocket\n const wsUrl = connectResponse.ws_url;\n\n this.ws = new WebSocketClient({\n onMessage: this.handleMessage.bind(this),\n onOpen: () => {}, // Handled in connect flow\n onClose: this.handleClose.bind(this),\n onError: this.handleError.bind(this),\n });\n\n await this.ws.connect(wsUrl);\n\n // Step 3: Send join message\n const requestId = this.messageQueue.nextRequestId();\n const joinMessage: ClientMessage = {\n o: 'j',\n t: connectResponse.token,\n r: requestId,\n };\n\n this.send(joinMessage);\n\n // Wait for join complete (returns volatile path patterns)\n const volatilePaths = (await this.messageQueue.registerRequest(requestId)) as string[];\n this._volatilePaths = volatilePaths || [];\n\n // Step 4: Extract auth info from JWT and update state\n const jwtPayload = decodeJwtPayload(connectResponse.token);\n this._auth = {\n uid: jwtPayload.sub,\n provider: jwtPayload.provider,\n token: jwtPayload.claims || {},\n };\n\n this._state = 'connected';\n\n // Initialize subscription manager\n this.subscriptionManager.initialize({\n sendSubscribe: this.sendSubscribeMessage.bind(this),\n sendUnsubscribe: this.sendUnsubscribeMessage.bind(this),\n createSnapshot: this.createSnapshot.bind(this),\n });\n\n // Notify listeners\n this.connectCallbacks.forEach((cb) => cb());\n } catch (error) {\n this._state = 'disconnected';\n this._auth = null;\n this._databaseId = null;\n this.ws?.close();\n this.ws = null;\n throw error;\n }\n }\n\n /**\n * Disconnect from the database.\n * This triggers onDisconnect hooks on the server.\n */\n async disconnect(): Promise<void> {\n if (this._state === 'disconnected') {\n return;\n }\n\n // Send leave message for graceful disconnect\n if (this._state === 'connected' && this.ws) {\n try {\n const requestId = this.messageQueue.nextRequestId();\n this.send({ o: 'l', r: requestId });\n // Wait briefly for ack, but don't block\n await Promise.race([\n this.messageQueue.registerRequest(requestId),\n new Promise((resolve) => setTimeout(resolve, 1000)),\n ]);\n } catch {\n // Ignore errors during disconnect\n }\n }\n\n this.cleanup();\n }\n\n /**\n * Clean up connection state.\n */\n private cleanup(): void {\n this.ws?.close();\n this.ws = null;\n this._state = 'disconnected';\n this._auth = null;\n this._databaseId = null;\n this._volatilePaths = [];\n this._coordinatorUrl = null;\n this.subscriptionManager.clear();\n this.messageQueue.rejectAll(new Error('Connection closed'));\n // Note: We intentionally do NOT clear pendingWrites here.\n // They are kept for potential retry on reconnect.\n // Call pendingWrites.clear() explicitly if you don't want to retry.\n }\n\n // ============================================\n // Reference Access\n // ============================================\n\n /**\n * Get a reference to a path in the database.\n */\n ref(path: string = ''): DatabaseReference {\n return new DatabaseReference(this, path);\n }\n\n // ============================================\n // Transactions\n // ============================================\n\n /**\n * Execute an atomic transaction with multiple operations.\n *\n * Supports two syntaxes:\n *\n * **Object syntax** (like Firebase multi-path update):\n * ```javascript\n * await db.transaction({\n * '/users/alice/name': 'Alice',\n * '/users/alice/score': 100,\n * '/temp/data': null // null = delete\n * });\n * ```\n *\n * **Array syntax** (explicit operations):\n * ```javascript\n * await db.transaction([\n * { op: 'set', path: '/users/alice/name', value: 'Alice' },\n * { op: 'update', path: '/metadata', value: { lastUpdated: '...' } },\n * { op: 'delete', path: '/temp/data' },\n * { op: 'condition', path: '/counter', value: 5 } // CAS check\n * ]);\n * ```\n *\n * All operations are atomic: either all succeed or all fail.\n * Conditions are checked first; if any fail, the transaction is rejected\n * with error code 'condition_failed'.\n */\n async transaction(operations: TransactionOp[] | TransactionObject): Promise<void> {\n let txOps: TxOperation[];\n\n if (Array.isArray(operations)) {\n // Array syntax - convert to wire format\n txOps = operations.map((op) => this.convertToTxOp(op));\n } else {\n // Object syntax - convert paths to set/delete operations\n txOps = this.convertObjectToTxOps(operations);\n }\n\n await this._sendTransaction(txOps);\n }\n\n /**\n * Convert a public TransactionOp to wire format TxOperation.\n */\n private convertToTxOp(op: TransactionOp): TxOperation {\n const path = normalizePath(op.path) || '/';\n\n switch (op.op) {\n case 'set':\n return { o: 's', p: path, v: op.value };\n case 'update':\n return { o: 'u', p: path, v: op.value };\n case 'delete':\n return { o: 'd', p: path };\n case 'condition':\n return { o: 'c', p: path, v: op.value };\n default:\n throw new Error(`Unknown transaction operation: ${(op as TransactionOp).op}`);\n }\n }\n\n /**\n * Convert object syntax to wire format TxOperations.\n * Each path becomes a set operation, null values become deletes.\n */\n private convertObjectToTxOps(obj: TransactionObject): TxOperation[] {\n const ops: TxOperation[] = [];\n\n for (const [path, value] of Object.entries(obj)) {\n const normalizedPath = normalizePath(path) || '/';\n\n if (value === null) {\n // null = delete\n ops.push({ o: 'd', p: normalizedPath });\n } else {\n // set the value\n ops.push({ o: 's', p: normalizedPath, v: value });\n }\n }\n\n return ops;\n }\n\n /**\n * @internal Send a transaction to the server.\n */\n async _sendTransaction(ops: TxOperation[]): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n\n // Track the pending write using request ID (store ops as value for potential retry)\n this.pendingWrites.trackWrite(requestId, 'transaction', '/', ops);\n\n const message: TransactionMessage = {\n o: 'tx',\n ops,\n r: requestId,\n };\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n // ============================================\n // Connection Events\n // ============================================\n\n /**\n * Register a callback for when connection is established.\n * Returns an unsubscribe function.\n */\n onConnect(callback: () => void): () => void {\n this.connectCallbacks.add(callback);\n return () => this.connectCallbacks.delete(callback);\n }\n\n /**\n * Register a callback for when connection is lost.\n * Returns an unsubscribe function.\n */\n onDisconnect(callback: () => void): () => void {\n this.disconnectCallbacks.add(callback);\n return () => this.disconnectCallbacks.delete(callback);\n }\n\n /**\n * Register a callback for connection errors.\n * Returns an unsubscribe function.\n */\n onError(callback: (error: Error) => void): () => void {\n this.errorCallbacks.add(callback);\n return () => this.errorCallbacks.delete(callback);\n }\n\n // ============================================\n // Internal: Message Handling\n // ============================================\n\n private handleMessage(data: string): void {\n let message: ServerMessage;\n try {\n message = JSON.parse(data) as ServerMessage;\n } catch {\n console.error('Failed to parse message:', data);\n return;\n }\n\n // Handle ping - respond with pong immediately\n if (isPingMessage(message)) {\n this.ws?.send(JSON.stringify({ o: 'po' }));\n return;\n }\n\n // Clear pending writes on ack/nack using request ID\n if (isAckMessage(message)) {\n this.pendingWrites.onAck(message.a);\n } else if (isNackMessage(message)) {\n this.pendingWrites.onNack(message.n);\n }\n\n // Check if this is a response to a pending request\n if (this.messageQueue.handleMessage(message)) {\n return;\n }\n\n // Otherwise, check if it's an event\n if (isEventMessage(message)) {\n this.subscriptionManager.handleEvent(message);\n }\n }\n\n private handleClose(code: number, reason: string): void {\n const wasConnected = this._state === 'connected';\n this.cleanup();\n\n if (wasConnected) {\n this.disconnectCallbacks.forEach((cb) => cb());\n }\n }\n\n private handleError(event: Event): void {\n const error = new Error('WebSocket error');\n this.errorCallbacks.forEach((cb) => cb(error));\n }\n\n // ============================================\n // Internal: Sending Messages\n // ============================================\n\n private send(message: ClientMessage): void {\n if (!this.ws || !this.ws.connected) {\n throw new LarkError('not_connected', 'Not connected to database');\n }\n this.ws.send(JSON.stringify(message));\n }\n\n /**\n * @internal Send a set operation.\n */\n async _sendSet(path: string, value: unknown, priority?: number | string): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const normalizedPath = normalizePath(path) || '/';\n\n // Track the pending write using request ID\n this.pendingWrites.trackWrite(requestId, 'set', normalizedPath, value);\n\n const message: ClientMessage = {\n o: 's',\n p: normalizedPath,\n v: value,\n r: requestId,\n };\n if (priority !== undefined) {\n message.y = priority;\n }\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n /**\n * @internal Send an update operation.\n */\n async _sendUpdate(path: string, values: Record<string, unknown>): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const normalizedPath = normalizePath(path) || '/';\n\n // Track the pending write using request ID\n this.pendingWrites.trackWrite(requestId, 'update', normalizedPath, values);\n\n const message: ClientMessage = {\n o: 'u',\n p: normalizedPath,\n v: values,\n r: requestId,\n };\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n /**\n * @internal Send a delete operation.\n */\n async _sendDelete(path: string): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const normalizedPath = normalizePath(path) || '/';\n\n // Track the pending write using request ID\n this.pendingWrites.trackWrite(requestId, 'delete', normalizedPath);\n\n const message: ClientMessage = {\n o: 'd',\n p: normalizedPath,\n r: requestId,\n };\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n /**\n * @internal Send a push operation. Returns the generated key.\n */\n async _sendPush(path: string, value: unknown): Promise<string> {\n const requestId = this.messageQueue.nextRequestId();\n const normalizedPath = normalizePath(path) || '/';\n\n // Track the pending write using request ID\n this.pendingWrites.trackWrite(requestId, 'push', normalizedPath, value);\n\n const message: ClientMessage = {\n o: 'p',\n p: normalizedPath,\n v: value,\n r: requestId,\n };\n this.send(message);\n const key = (await this.messageQueue.registerRequest(requestId)) as string;\n return key;\n }\n\n /**\n * @internal Send a once (read) operation.\n *\n * This method first checks if the data is available in the local cache\n * (from an active subscription). If so, it returns the cached value\n * immediately without a server round-trip.\n *\n * Cache is only used when:\n * - No query parameters are specified (queries may filter/order differently)\n * - The path is covered by an active 'value' subscription\n * - We have cached data available\n */\n async _sendOnce(path: string, query?: QueryParams): Promise<DataSnapshot> {\n const normalizedPath = normalizePath(path) || '/';\n\n // Try cache first (only for non-query requests)\n if (!query) {\n const cached = this.subscriptionManager.getCachedValue(normalizedPath);\n if (cached.found) {\n return new DataSnapshot(cached.value, path, this);\n }\n }\n\n // Cache miss or query specified - fetch from server\n const requestId = this.messageQueue.nextRequestId();\n const message: ClientMessage = {\n o: 'o',\n p: normalizedPath,\n r: requestId,\n // Spread query params at top level (not nested in 'q')\n ...query,\n };\n this.send(message);\n const value = await this.messageQueue.registerRequest(requestId);\n return new DataSnapshot(value, path, this);\n }\n\n /**\n * @internal Send an onDisconnect operation.\n */\n async _sendOnDisconnect(\n path: string,\n action: string,\n value?: unknown,\n priority?: number | string\n ): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const message: ClientMessage = {\n o: 'od',\n p: normalizePath(path) || '/',\n a: action as 's' | 'u' | 'd' | 'c',\n r: requestId,\n };\n if (value !== undefined) {\n message.v = value;\n }\n if (priority !== undefined) {\n message.y = priority;\n }\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n /**\n * @internal Send a subscribe message to server.\n */\n private async sendSubscribeMessage(path: string, eventTypes: string[], queryParams?: QueryParams): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const message: ClientMessage = {\n o: 'sb',\n p: normalizePath(path) || '/',\n e: eventTypes,\n r: requestId,\n ...queryParams,\n };\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n /**\n * @internal Send an unsubscribe message to server.\n */\n private async sendUnsubscribeMessage(path: string): Promise<void> {\n const requestId = this.messageQueue.nextRequestId();\n const message: ClientMessage = {\n o: 'us',\n p: normalizePath(path) || '/',\n r: requestId,\n };\n this.send(message);\n await this.messageQueue.registerRequest(requestId);\n }\n\n /**\n * @internal Create a DataSnapshot from event data.\n */\n private createSnapshot(\n path: string,\n value: unknown,\n volatile: boolean,\n serverTimestamp?: number\n ): DataSnapshot {\n return new DataSnapshot(value, path, this, {\n volatile,\n serverTimestamp: serverTimestamp ?? null,\n });\n }\n\n // ============================================\n // Internal: Subscription Management\n // ============================================\n\n /**\n * @internal Subscribe to events at a path.\n */\n _subscribe(path: string, eventType: EventType, callback: SnapshotCallback, queryParams?: QueryParams): () => void {\n return this.subscriptionManager.subscribe(path, eventType, callback, queryParams);\n }\n\n /**\n * @internal Unsubscribe from a specific event type at a path.\n */\n _unsubscribeEventType(path: string, eventType: EventType): void {\n this.subscriptionManager.unsubscribeEventType(path, eventType);\n }\n\n /**\n * @internal Unsubscribe from all events at a path.\n */\n _unsubscribeAll(path: string): void {\n this.subscriptionManager.unsubscribeAll(path);\n }\n}\n","/**\n * Volatile path matching utilities.\n *\n * Volatile paths are patterns where a wildcard matches exactly one path segment.\n * These paths use unreliable transport for better performance (UDP when available).\n */\n\n/**\n * Check if a path matches any of the volatile path patterns.\n *\n * Pattern matching rules:\n * - Wildcard matches exactly one path segment (not zero, not multiple)\n * - Patterns and paths are compared segment by segment\n * - Path must have the same number of segments as the pattern\n *\n * @param path - The path to check (e.g., \"/players/abc/position\")\n * @param patterns - Array of volatile patterns with wildcards\n * @returns true if the path matches any pattern\n */\nexport function isVolatilePath(path: string, patterns: string[] | null | undefined): boolean {\n if (!patterns || patterns.length === 0) {\n return false;\n }\n\n // Remove leading slash and split into segments\n const segments = path.replace(/^\\//, '').split('/');\n\n return patterns.some((pattern) => {\n const patternSegments = pattern.split('/');\n\n // Must have same number of segments\n if (segments.length !== patternSegments.length) {\n return false;\n }\n\n // Each segment must match (or pattern segment is wildcard)\n return patternSegments.every((p, i) => p === '*' || p === segments[i]);\n });\n}\n"],"mappings":"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","names":["currentOrder","WebSocketNode"]}