@lark-sh/client 0.1.0 → 0.1.1
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 +7 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -136,6 +136,9 @@ function isOnceResponseMessage(msg) {
|
|
|
136
136
|
function isPushAckMessage(msg) {
|
|
137
137
|
return "pa" in msg;
|
|
138
138
|
}
|
|
139
|
+
function isPingMessage(msg) {
|
|
140
|
+
return "o" in msg && msg.o === "pi";
|
|
141
|
+
}
|
|
139
142
|
|
|
140
143
|
// src/connection/MessageQueue.ts
|
|
141
144
|
var MessageQueue = class {
|
|
@@ -1201,6 +1204,10 @@ var LarkDatabase = class {
|
|
|
1201
1204
|
console.error("Failed to parse message:", data);
|
|
1202
1205
|
return;
|
|
1203
1206
|
}
|
|
1207
|
+
if (isPingMessage(message)) {
|
|
1208
|
+
this.ws?.send(JSON.stringify({ o: "po" }));
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1204
1211
|
if (this.messageQueue.handleMessage(message)) {
|
|
1205
1212
|
return;
|
|
1206
1213
|
}
|
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/SubscriptionManager.ts","../src/connection/WebSocketClient.ts","../src/OnDisconnect.ts","../src/utils/path.ts","../src/utils/pushid.ts","../src/DatabaseReference.ts","../src/DataSnapshot.ts","../src/utils/jwt.ts","../src/LarkDatabase.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 { ConnectOptions, AuthInfo } from './LarkDatabase';\n\nexport { DatabaseReference } from './DatabaseReference';\nexport type { SnapshotCallback, QueryState } 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';\n\n// Utility functions (for advanced usage)\nexport { generatePushId } from './utils/pushid';\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} as const;\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 (short form)\nexport const EventTypeShort = {\n VALUE: 'v',\n CHILD_ADDED: 'ca',\n CHILD_CHANGED: 'cc',\n CHILD_REMOVED: 'cr',\n} as const;\n\n// Event types (long form, used in API)\nexport type EventType = 'value' | 'child_added' | 'child_changed' | 'child_removed';\n\n// Map short event types to long form\nexport const eventTypeFromShort: Record<string, EventType> = {\n v: 'value',\n ca: 'child_added',\n cc: 'child_changed',\n cr: 'child_removed',\n};\n\n// Map long event types to short form\nexport const eventTypeToShort: Record<EventType, string> = {\n value: 'v',\n child_added: 'ca',\n child_changed: 'cc',\n child_removed: 'cr',\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} as const;\n\nexport type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];\n\n// Default coordinator URL\nexport const DEFAULT_COORDINATOR_URL = 'https://db.lark.dev';\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.lark.sh/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)\n q?: QueryParams;\n}\n\nexport interface QueryParams {\n ob?: 'k' | 'p'; // orderBy: 'k'=key, 'p'=priority\n lf?: number; // limitToFirst\n ll?: number; // limitToLast\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 q?: QueryParams; // query parameters (optional)\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 type ClientMessage =\n | JoinMessage\n | SetMessage\n | UpdateMessage\n | DeleteMessage\n | PushMessage\n | SubscribeMessage\n | UnsubscribeMessage\n | OnceMessage\n | OnDisconnectMessage\n | LeaveMessage;\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\nexport interface EventMessage {\n ev: string; // event type (short form: v, ca, cc, cr)\n p: string; // path\n v?: unknown; // value (not present for child_removed)\n k?: string; // child key (for child_* events)\n x?: boolean; // volatile flag\n}\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 JoinAckMessage {\n a: string; // ack with request ID\n uid: string; // user ID from auth\n provider: string; // auth provider\n token?: Record<string, unknown>; // custom claims\n}\n\nexport type ServerMessage =\n | AckMessage\n | NackMessage\n | EventMessage\n | OnceResponseMessage\n | PushAckMessage\n | JoinAckMessage;\n\n// ============================================\n// Helper functions\n// ============================================\n\nexport function isAckMessage(msg: ServerMessage): msg is AckMessage {\n return 'a' in msg && !('uid' in msg);\n}\n\nexport function isJoinAckMessage(msg: ServerMessage): msg is JoinAckMessage {\n return 'a' in msg && 'uid' 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 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","/**\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 isJoinAckMessage,\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 ack (includes auth info)\n if (isJoinAckMessage(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({\n uid: message.uid,\n provider: message.provider,\n token: message.token,\n });\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 * SubscriptionManager - tracks active subscriptions and routes events to callbacks.\n */\n\nimport type { DataSnapshot } from '../DataSnapshot';\nimport { EventType, eventTypeFromShort, eventTypeToShort } from '../protocol/constants';\nimport { EventMessage } from '../protocol/messages';\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 // path -> eventType -> array of subscriptions\n private subscriptions = new Map<string, Map<EventType, SubscriptionEntry[]>>();\n\n // Callback to send subscribe message to server\n private sendSubscribe: ((path: string, eventTypes: string[]) => Promise<void>) | null = null;\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: ((path: string, value: unknown, volatile: boolean) => DataSnapshot) | null = null;\n\n /**\n * Initialize the manager with server communication callbacks.\n */\n initialize(options: {\n sendSubscribe: (path: string, eventTypes: string[]) => Promise<void>;\n sendUnsubscribe: (path: string) => Promise<void>;\n createSnapshot: (path: string, value: unknown, volatile: boolean) => 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): () => 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 // 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 const shortEventTypes = allEventTypes.map((et) => eventTypeToShort[et]);\n\n // Fire and forget - we don't wait for the server\n this.sendSubscribe?.(normalizedPath, shortEventTypes).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\n if (pathSubs.size === 0) {\n this.subscriptions.delete(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.sendUnsubscribe?.(normalizedPath).catch((err) => {\n console.error('Failed to unsubscribe:', err);\n });\n } else {\n // Update server with remaining event types\n const remainingEventTypes = this.getEventTypesForPath(normalizedPath);\n const shortEventTypes = remainingEventTypes.map((et) => eventTypeToShort[et]);\n this.sendSubscribe?.(normalizedPath, shortEventTypes).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.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 */\n handleEvent(message: EventMessage): void {\n const eventType = eventTypeFromShort[message.ev];\n if (!eventType) {\n console.warn('Unknown event type:', message.ev);\n return;\n }\n\n const path = message.p;\n const pathSubs = this.subscriptions.get(path);\n if (!pathSubs) return;\n\n const eventSubs = pathSubs.get(eventType);\n if (!eventSubs || eventSubs.length === 0) return;\n\n // Determine the snapshot path and value based on event type\n let snapshotPath: string;\n let snapshotValue: unknown;\n\n if (eventType === 'value') {\n snapshotPath = path;\n snapshotValue = message.v;\n } else {\n // child_* events: the snapshot is for the child\n snapshotPath = path === '/' ? `/${message.k}` : `${path}/${message.k}`;\n snapshotValue = message.v;\n }\n\n // Create snapshot and invoke callbacks\n const snapshot = this.createSnapshot?.(snapshotPath, snapshotValue, message.x ?? false);\n if (!snapshot) return;\n\n for (const entry of eventSubs) {\n try {\n entry.callback(snapshot, undefined);\n } catch (err) {\n console.error('Error in subscription callback:', err);\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 }\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 * 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 * 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 * 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 { OnDisconnect } from './OnDisconnect';\nimport { EventType } from './protocol/constants';\nimport { QueryParams } from './protocol/messages';\nimport { getKey, getParentPath, joinPath, normalizePath } from './utils/path';\nimport { generatePushId } from './utils/pushid';\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 async update(values: Record<string, unknown>): Promise<void> {\n await this._db._sendUpdate(this._path, values);\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 // 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);\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n orderByChild(path: string): DatabaseReference {\n console.warn('orderByChild() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n orderByValue(): DatabaseReference {\n console.warn('orderByValue() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n startAt(value: unknown, key?: string): DatabaseReference {\n console.warn('startAt() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n endAt(value: unknown, key?: string): DatabaseReference {\n console.warn('endAt() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n equalTo(value: unknown, key?: string): DatabaseReference {\n console.warn('equalTo() is not yet implemented');\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 if (this._query.orderBy === 'key') {\n params.ob = 'k';\n hasParams = true;\n } else if (this._query.orderBy === 'priority') {\n params.ob = 'p';\n hasParams = true;\n }\n\n if (this._query.limitToFirst !== undefined) {\n params.lf = this._query.limitToFirst;\n hasParams = true;\n }\n\n if (this._query.limitToLast !== undefined) {\n params.ll = this._query.limitToLast;\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\n constructor(\n data: unknown,\n path: string,\n db: LarkDatabase,\n options: { volatile?: boolean; priority?: number | string | 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 }\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 });\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 * 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 { 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 isEventMessage,\n QueryParams,\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\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\n private ws: WebSocketClient | null = null;\n private messageQueue: MessageQueue;\n private subscriptionManager: SubscriptionManager;\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 }\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 // 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 ack\n await this.messageQueue.registerRequest(requestId);\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._coordinatorUrl = null;\n this.subscriptionManager.clear();\n this.messageQueue.rejectAll(new Error('Connection closed'));\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 // 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 // First, 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 message: ClientMessage = {\n o: 's',\n p: normalizePath(path) || '/',\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 message: ClientMessage = {\n o: 'u',\n p: normalizePath(path) || '/',\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 message: ClientMessage = {\n o: 'd',\n p: normalizePath(path) || '/',\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 message: ClientMessage = {\n o: 'p',\n p: normalizePath(path) || '/',\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 async _sendOnce(path: string, query?: QueryParams): Promise<DataSnapshot> {\n const requestId = this.messageQueue.nextRequestId();\n const message: ClientMessage = {\n o: 'o',\n p: normalizePath(path) || '/',\n r: requestId,\n };\n if (query) {\n message.q = 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[]): 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 };\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(path: string, value: unknown, volatile: boolean): DataSnapshot {\n return new DataSnapshot(value, path, this, { volatile });\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): () => void {\n return this.subscriptionManager.subscribe(path, eventType, callback);\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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACoBO,IAAM,qBAAqB;AAAA,EAChC,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AACV;AAcO,IAAM,qBAAgD;AAAA,EAC3D,GAAG;AAAA,EACH,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGO,IAAM,mBAA8C;AAAA,EACzD,OAAO;AAAA,EACP,aAAa;AAAA,EACb,eAAe;AAAA,EACf,eAAe;AACjB;AAeO,IAAM,0BAA0B;;;AC1ChC,IAAM,cAAN,MAAkB;AAAA,EAGvB,YAAY,UAAkB,yBAAyB;AAErD,SAAK,UAAU,QAAQ,QAAQ,OAAO,EAAE;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QACJ,UACA,UAAmD,CAAC,GAC1B;AAC1B,UAAM,OAAuB,EAAE,SAAS;AAExC,QAAI,QAAQ,OAAO;AACjB,WAAK,QAAQ,QAAQ;AAAA,IACvB,WAAW,QAAQ,WAAW;AAC5B,WAAK,YAAY;AAAA,IACnB,OAAO;AAEL,WAAK,YAAY;AAAA,IACnB;AAEA,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,YAAY;AAAA,MACtD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,UAAI,eAAe,+BAA+B,SAAS,MAAM;AACjE,UAAI;AACF,cAAM,YAAa,MAAM,SAAS,KAAK;AACvC,YAAI,UAAU,SAAS;AACrB,yBAAe,UAAU;AAAA,QAC3B;AAAA,MACF,QAAQ;AAAA,MAER;AACA,YAAM,IAAI,MAAM,YAAY;AAAA,IAC9B;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,WAAO;AAAA,EACT;AACF;;;AC3EO,IAAM,YAAN,MAAM,mBAAkB,MAAM;AAAA,EAGnC,YAAY,MAAc,SAAkB;AAC1C,UAAM,WAAW,IAAI;AACrB,SAAK,OAAO;AACZ,SAAK,OAAO;AAGZ,UAAM,mBAAmB;AAGzB,QAAI,iBAAiB,mBAAmB;AACtC,uBAAiB,kBAAkB,MAAM,UAAS;AAAA,IACpD;AAAA,EACF;AACF;;;ACkIO,SAAS,aAAa,KAAuC;AAClE,SAAO,OAAO,OAAO,EAAE,SAAS;AAClC;AAEO,SAAS,iBAAiB,KAA2C;AAC1E,SAAO,OAAO,OAAO,SAAS;AAChC;AAEO,SAAS,cAAc,KAAwC;AACpE,SAAO,OAAO;AAChB;AAEO,SAAS,eAAe,KAAyC;AACtE,SAAO,QAAQ;AACjB;AAEO,SAAS,sBAAsB,KAAgD;AACpF,SAAO,QAAQ;AACjB;AAEO,SAAS,iBAAiB,KAA2C;AAC1E,SAAO,QAAQ;AACjB;;;ACpJO,IAAM,eAAN,MAAmB;AAAA,EAKxB,YAAY,iBAAyB,KAAO;AAJ5C,SAAQ,SAAS;AACjB,SAAQ,UAAU,oBAAI,IAA4B;AAIhD,SAAK,iBAAiB;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAwB;AACtB,WAAO,OAAO,KAAK,QAAQ;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,WAAmB,SAAoC;AACrE,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,YAAY,WAAW,KAAK;AAElC,YAAM,gBAAgB,WAAW,MAAM;AACrC,aAAK,QAAQ,OAAO,SAAS;AAC7B,eAAO,IAAI,UAAU,WAAW,WAAW,SAAS,oBAAoB,SAAS,IAAI,CAAC;AAAA,MACxF,GAAG,SAAS;AAEZ,WAAK,QAAQ,IAAI,WAAW;AAAA,QAC1B;AAAA,QACA;AAAA,QACA,SAAS;AAAA,MACX,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAc,SAAiC;AAE7C,QAAI,iBAAiB,OAAO,GAAG;AAC7B,YAAM,UAAU,KAAK,QAAQ,IAAI,QAAQ,CAAC;AAC1C,UAAI,SAAS;AACX,qBAAa,QAAQ,OAAO;AAC5B,aAAK,QAAQ,OAAO,QAAQ,CAAC;AAC7B,gBAAQ,QAAQ;AAAA,UACd,KAAK,QAAQ;AAAA,UACb,UAAU,QAAQ;AAAA,UAClB,OAAO,QAAQ;AAAA,QACjB,CAAC;AACD,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI,aAAa,OAAO,GAAG;AACzB,YAAM,UAAU,KAAK,QAAQ,IAAI,QAAQ,CAAC;AAC1C,UAAI,SAAS;AACX,qBAAa,QAAQ,OAAO;AAC5B,aAAK,QAAQ,OAAO,QAAQ,CAAC;AAC7B,gBAAQ,QAAQ,MAAS;AACzB,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI,cAAc,OAAO,GAAG;AAC1B,YAAM,UAAU,KAAK,QAAQ,IAAI,QAAQ,CAAC;AAC1C,UAAI,SAAS;AACX,qBAAa,QAAQ,OAAO;AAC5B,aAAK,QAAQ,OAAO,QAAQ,CAAC;AAC7B,gBAAQ,OAAO,IAAI,UAAU,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAClD,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI,sBAAsB,OAAO,GAAG;AAClC,YAAM,UAAU,KAAK,QAAQ,IAAI,QAAQ,EAAE;AAC3C,UAAI,SAAS;AACX,qBAAa,QAAQ,OAAO;AAC5B,aAAK,QAAQ,OAAO,QAAQ,EAAE;AAC9B,gBAAQ,QAAQ,QAAQ,EAAE;AAC1B,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI,iBAAiB,OAAO,GAAG;AAC7B,YAAM,UAAU,KAAK,QAAQ,IAAI,QAAQ,EAAE;AAC3C,UAAI,SAAS;AACX,qBAAa,QAAQ,OAAO;AAC5B,aAAK,QAAQ,OAAO,QAAQ,EAAE;AAC9B,gBAAQ,QAAQ,QAAQ,EAAE;AAC1B,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,OAAoB;AAC5B,eAAW,CAAC,EAAE,OAAO,KAAK,KAAK,SAAS;AACtC,mBAAa,QAAQ,OAAO;AAC5B,cAAQ,OAAO,KAAK;AAAA,IACtB;AACA,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,eAAuB;AACzB,WAAO,KAAK,QAAQ;AAAA,EACtB;AACF;;;ACpIO,IAAM,sBAAN,MAA0B;AAAA,EAA1B;AAEL;AAAA,SAAQ,gBAAgB,oBAAI,IAAiD;AAG7E;AAAA,SAAQ,gBAAgF;AAGxF;AAAA,SAAQ,kBAA4D;AAGpE;AAAA,SAAQ,iBAA6F;AAAA;AAAA;AAAA;AAAA;AAAA,EAKrG,WAAW,SAIF;AACP,SAAK,gBAAgB,QAAQ;AAC7B,SAAK,kBAAkB,QAAQ;AAC/B,SAAK,iBAAiB,QAAQ;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,MAAc,WAAsB,UAAwC;AAEpF,UAAM,iBAAiB;AAGvB,UAAM,iBAAiB,CAAC,KAAK,cAAc,IAAI,cAAc;AAC7D,UAAM,qBAAqB,KAAK,qBAAqB,cAAc;AACnE,UAAM,sBAAsB,CAAC,mBAAmB,SAAS,SAAS;AAGlE,QAAI,CAAC,KAAK,cAAc,IAAI,cAAc,GAAG;AAC3C,WAAK,cAAc,IAAI,gBAAgB,oBAAI,IAAI,CAAC;AAAA,IAClD;AACA,UAAM,WAAW,KAAK,cAAc,IAAI,cAAc;AAGtD,QAAI,CAAC,SAAS,IAAI,SAAS,GAAG;AAC5B,eAAS,IAAI,WAAW,CAAC,CAAC;AAAA,IAC5B;AACA,UAAM,YAAY,SAAS,IAAI,SAAS;AAGxC,UAAM,cAAc,MAAM;AACxB,WAAK,oBAAoB,gBAAgB,WAAW,QAAQ;AAAA,IAC9D;AAGA,cAAU,KAAK,EAAE,UAAU,YAAY,CAAC;AAGxC,QAAI,kBAAkB,qBAAqB;AACzC,YAAM,gBAAgB,KAAK,qBAAqB,cAAc;AAC9D,YAAM,kBAAkB,cAAc,IAAI,CAAC,OAAO,iBAAiB,EAAE,CAAC;AAGtE,WAAK,gBAAgB,gBAAgB,eAAe,EAAE,MAAM,CAAC,QAAQ;AACnE,gBAAQ,MAAM,wBAAwB,GAAG;AAAA,MAC3C,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,MAAc,WAAsB,UAAkC;AAChG,UAAM,WAAW,KAAK,cAAc,IAAI,IAAI;AAC5C,QAAI,CAAC,SAAU;AAEf,UAAM,YAAY,SAAS,IAAI,SAAS;AACxC,QAAI,CAAC,UAAW;AAGhB,UAAM,QAAQ,UAAU,UAAU,CAAC,UAAU,MAAM,aAAa,QAAQ;AACxE,QAAI,UAAU,IAAI;AAChB,gBAAU,OAAO,OAAO,CAAC;AAAA,IAC3B;AAGA,QAAI,UAAU,WAAW,GAAG;AAC1B,eAAS,OAAO,SAAS;AAAA,IAC3B;AAGA,QAAI,SAAS,SAAS,GAAG;AACvB,WAAK,cAAc,OAAO,IAAI;AAC9B,WAAK,kBAAkB,IAAI,EAAE,MAAM,CAAC,QAAQ;AAC1C,gBAAQ,MAAM,0BAA0B,GAAG;AAAA,MAC7C,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB,MAAc,WAA4B;AAC7D,UAAM,iBAAiB;AACvB,UAAM,WAAW,KAAK,cAAc,IAAI,cAAc;AACtD,QAAI,CAAC,SAAU;AAGf,aAAS,OAAO,SAAS;AAGzB,QAAI,SAAS,SAAS,GAAG;AACvB,WAAK,cAAc,OAAO,cAAc;AACxC,WAAK,kBAAkB,cAAc,EAAE,MAAM,CAAC,QAAQ;AACpD,gBAAQ,MAAM,0BAA0B,GAAG;AAAA,MAC7C,CAAC;AAAA,IACH,OAAO;AAEL,YAAM,sBAAsB,KAAK,qBAAqB,cAAc;AACpE,YAAM,kBAAkB,oBAAoB,IAAI,CAAC,OAAO,iBAAiB,EAAE,CAAC;AAC5E,WAAK,gBAAgB,gBAAgB,eAAe,EAAE,MAAM,CAAC,QAAQ;AACnE,gBAAQ,MAAM,kCAAkC,GAAG;AAAA,MACrD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,MAAoB;AACjC,UAAM,iBAAiB;AACvB,QAAI,CAAC,KAAK,cAAc,IAAI,cAAc,EAAG;AAE7C,SAAK,cAAc,OAAO,cAAc;AACxC,SAAK,kBAAkB,cAAc,EAAE,MAAM,CAAC,QAAQ;AACpD,cAAQ,MAAM,0BAA0B,GAAG;AAAA,IAC7C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,SAA6B;AACvC,UAAM,YAAY,mBAAmB,QAAQ,EAAE;AAC/C,QAAI,CAAC,WAAW;AACd,cAAQ,KAAK,uBAAuB,QAAQ,EAAE;AAC9C;AAAA,IACF;AAEA,UAAM,OAAO,QAAQ;AACrB,UAAM,WAAW,KAAK,cAAc,IAAI,IAAI;AAC5C,QAAI,CAAC,SAAU;AAEf,UAAM,YAAY,SAAS,IAAI,SAAS;AACxC,QAAI,CAAC,aAAa,UAAU,WAAW,EAAG;AAG1C,QAAI;AACJ,QAAI;AAEJ,QAAI,cAAc,SAAS;AACzB,qBAAe;AACf,sBAAgB,QAAQ;AAAA,IAC1B,OAAO;AAEL,qBAAe,SAAS,MAAM,IAAI,QAAQ,CAAC,KAAK,GAAG,IAAI,IAAI,QAAQ,CAAC;AACpE,sBAAgB,QAAQ;AAAA,IAC1B;AAGA,UAAM,WAAW,KAAK,iBAAiB,cAAc,eAAe,QAAQ,KAAK,KAAK;AACtF,QAAI,CAAC,SAAU;AAEf,eAAW,SAAS,WAAW;AAC7B,UAAI;AACF,cAAM,SAAS,UAAU,MAAS;AAAA,MACpC,SAAS,KAAK;AACZ,gBAAQ,MAAM,mCAAmC,GAAG;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,MAA2B;AACtD,UAAM,WAAW,KAAK,cAAc,IAAI,IAAI;AAC5C,QAAI,CAAC,SAAU,QAAO,CAAC;AACvB,WAAO,MAAM,KAAK,SAAS,KAAK,CAAC;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,cAAc,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,MAAuB;AACtC,WAAO,KAAK,cAAc,IAAI,IAAI;AAAA,EACpC;AACF;;;AC1NA,gBAA0B;AAG1B,IAAM,gBACJ,OAAO,cAAc,cAAc,YAAa,UAAAA;AAW3C,IAAM,kBAAN,MAAsB;AAAA,EAK3B,YAAY,SAAiC;AAJ7C,SAAQ,KAAuB;AAE/B,SAAQ,SAAyB;AAG/B,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,IAAI,QAAwB;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,YAAqB;AACvB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,KAA4B;AAClC,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAI,KAAK,WAAW,gBAAgB;AAClC,eAAO,IAAI,MAAM,iCAAiC,CAAC;AACnD;AAAA,MACF;AAEA,WAAK,SAAS;AAEd,UAAI;AACF,aAAK,KAAK,IAAI,cAAc,GAAG;AAAA,MACjC,SAAS,KAAK;AACZ,aAAK,SAAS;AACd,eAAO,GAAG;AACV;AAAA,MACF;AAEA,YAAM,SAAS,MAAM;AACnB,gBAAQ;AACR,aAAK,SAAS;AACd,aAAK,mBAAmB;AACxB,gBAAQ;AACR,aAAK,QAAQ,OAAO;AAAA,MACtB;AAEA,YAAM,UAAU,CAAC,UAAiB;AAChC,gBAAQ;AACR,aAAK,SAAS;AACd,aAAK,KAAK;AACV,eAAO,IAAI,MAAM,6BAA6B,CAAC;AAC/C,aAAK,QAAQ,QAAQ,KAAK;AAAA,MAC5B;AAEA,YAAM,UAAU,CAAC,UAAsB;AACrC,gBAAQ;AACR,aAAK,SAAS;AACd,aAAK,KAAK;AACV,eAAO,IAAI,MAAM,qBAAqB,MAAM,IAAI,IAAI,MAAM,MAAM,EAAE,CAAC;AAAA,MACrE;AAEA,YAAM,UAAU,MAAM;AACpB,aAAK,IAAI,oBAAoB,QAAQ,MAAM;AAC3C,aAAK,IAAI,oBAAoB,SAAS,OAAO;AAC7C,aAAK,IAAI,oBAAoB,SAAS,OAAO;AAAA,MAC/C;AAEA,WAAK,GAAG,iBAAiB,QAAQ,MAAM;AACvC,WAAK,GAAG,iBAAiB,SAAS,OAAO;AACzC,WAAK,GAAG,iBAAiB,SAAS,OAAO;AAAA,IAC3C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAA2B;AACjC,QAAI,CAAC,KAAK,GAAI;AAEd,SAAK,GAAG,iBAAiB,WAAW,CAAC,UAAwB;AAC3D,WAAK,QAAQ,UAAU,MAAM,IAAc;AAAA,IAC7C,CAAC;AAED,SAAK,GAAG,iBAAiB,SAAS,CAAC,UAAsB;AACvD,WAAK,SAAS;AACd,WAAK,KAAK;AACV,WAAK,QAAQ,QAAQ,MAAM,MAAM,MAAM,MAAM;AAAA,IAC/C,CAAC;AAED,SAAK,GAAG,iBAAiB,SAAS,CAAC,UAAiB;AAClD,WAAK,QAAQ,QAAQ,KAAK;AAAA,IAC5B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,MAAoB;AACvB,QAAI,CAAC,KAAK,MAAM,KAAK,WAAW,aAAa;AAC3C,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AACA,SAAK,GAAG,KAAK,IAAI;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAe,KAAM,SAAiB,qBAA2B;AACrE,QAAI,KAAK,IAAI;AACX,WAAK,GAAG,MAAM,MAAM,MAAM;AAC1B,WAAK,KAAK;AAAA,IACZ;AACA,SAAK,SAAS;AAAA,EAChB;AACF;;;AC9HO,IAAM,eAAN,MAAmB;AAAA,EAIxB,YAAY,IAAkB,MAAc;AAC1C,SAAK,MAAM;AACX,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,OAA+B;AACvC,UAAM,KAAK,IAAI,kBAAkB,KAAK,OAAO,mBAAmB,KAAK,KAAK;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,QAAgD;AAC3D,UAAM,KAAK,IAAI,kBAAkB,KAAK,OAAO,mBAAmB,QAAQ,MAAM;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAwB;AAC5B,UAAM,KAAK,IAAI,kBAAkB,KAAK,OAAO,mBAAmB,MAAM;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAwB;AAC5B,UAAM,KAAK,IAAI,kBAAkB,KAAK,OAAO,mBAAmB,MAAM;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAgB,OAAgB,UAA0C;AAC9E,UAAM,KAAK,IAAI,kBAAkB,KAAK,OAAO,mBAAmB,KAAK,OAAO,QAAQ;AAAA,EACtF;AACF;;;ACvCO,SAAS,cAAc,MAAsB;AAClD,MAAI,CAAC,QAAQ,SAAS,IAAK,QAAO;AAGlC,QAAM,WAAW,KAAK,MAAM,GAAG,EAAE,OAAO,CAAC,YAAY,QAAQ,SAAS,CAAC;AACvE,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,SAAO,MAAM,SAAS,KAAK,GAAG;AAChC;AAKO,SAAS,YAAY,UAA4B;AACtD,QAAM,WAAqB,CAAC;AAE5B,aAAW,WAAW,UAAU;AAC9B,QAAI,CAAC,WAAW,YAAY,IAAK;AAEjC,UAAM,QAAQ,QAAQ,MAAM,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAC3D,aAAS,KAAK,GAAG,KAAK;AAAA,EACxB;AAEA,MAAI,SAAS,WAAW,EAAG,QAAO;AAClC,SAAO,MAAM,SAAS,KAAK,GAAG;AAChC;AAKO,SAAS,cAAc,MAAsB;AAClD,QAAM,aAAa,cAAc,IAAI;AACrC,MAAI,eAAe,IAAK,QAAO;AAE/B,QAAM,YAAY,WAAW,YAAY,GAAG;AAC5C,MAAI,aAAa,EAAG,QAAO;AAE3B,SAAO,WAAW,UAAU,GAAG,SAAS;AAC1C;AAKO,SAAS,OAAO,MAA6B;AAClD,QAAM,aAAa,cAAc,IAAI;AACrC,MAAI,eAAe,IAAK,QAAO;AAE/B,QAAM,YAAY,WAAW,YAAY,GAAG;AAC5C,SAAO,WAAW,UAAU,YAAY,CAAC;AAC3C;AAyBO,SAAS,eAAe,KAAc,MAAuB;AAClE,QAAM,aAAa,cAAc,IAAI;AACrC,MAAI,eAAe,IAAK,QAAO;AAG/B,QAAM,WAAW,WAAW,MAAM,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AACjE,MAAI,UAAmB;AAEvB,aAAW,WAAW,UAAU;AAC9B,QAAI,YAAY,QAAQ,YAAY,QAAW;AAC7C,aAAO;AAAA,IACT;AACA,QAAI,OAAO,YAAY,UAAU;AAC/B,aAAO;AAAA,IACT;AACA,cAAW,QAAoC,OAAO;AAAA,EACxD;AAEA,SAAO;AACT;;;AC5FA,IAAM,aAAa;AAGnB,IAAI,eAAe;AACnB,IAAI,gBAA0B,CAAC;AAKxB,SAAS,iBAAyB;AACvC,MAAI,MAAM,KAAK,IAAI;AACnB,QAAM,gBAAgB,QAAQ;AAC9B,iBAAe;AAGf,QAAM,YAAY,IAAI,MAAM,CAAC;AAC7B,WAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,cAAU,CAAC,IAAI,WAAW,OAAO,MAAM,EAAE;AACzC,UAAM,KAAK,MAAM,MAAM,EAAE;AAAA,EAC3B;AAEA,MAAI,KAAK,UAAU,KAAK,EAAE;AAE1B,MAAI,CAAC,eAAe;AAElB,oBAAgB,CAAC;AACjB,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,oBAAc,KAAK,KAAK,MAAM,KAAK,OAAO,IAAI,EAAE,CAAC;AAAA,IACnD;AAAA,EACF,OAAO;AAGL,QAAI,IAAI;AACR,WAAO,KAAK,KAAK,cAAc,CAAC,MAAM,IAAI;AACxC,oBAAc,CAAC,IAAI;AACnB;AAAA,IACF;AACA,QAAI,KAAK,GAAG;AACV,oBAAc,CAAC;AAAA,IACjB;AAAA,EACF;AAGA,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,UAAM,WAAW,OAAO,cAAc,CAAC,CAAC;AAAA,EAC1C;AAEA,SAAO;AACT;;;ACnCO,IAAM,oBAAN,MAAM,mBAAkB;AAAA,EAK7B,YAAY,IAAkB,MAAc,QAAoB,CAAC,GAAG;AAClE,SAAK,MAAM;AACX,SAAK,QAAQ,cAAc,IAAI;AAC/B,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAqB;AACvB,WAAO,OAAO,KAAK,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAmC;AACrC,QAAI,KAAK,UAAU,IAAK,QAAO;AAC/B,UAAM,aAAa,cAAc,KAAK,KAAK;AAC3C,WAAO,IAAI,mBAAkB,KAAK,KAAK,UAAU;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAA0B;AAC5B,WAAO,IAAI,mBAAkB,KAAK,KAAK,EAAE;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,MAAiC;AACrC,UAAM,YAAY,SAAS,KAAK,OAAO,IAAI;AAC3C,WAAO,IAAI,mBAAkB,KAAK,KAAK,SAAS;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,IAAI,OAA+B;AACvC,UAAM,KAAK,IAAI,SAAS,KAAK,OAAO,KAAK;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,QAAgD;AAC3D,UAAM,KAAK,IAAI,YAAY,KAAK,OAAO,MAAM;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAwB;AAC5B,UAAM,KAAK,IAAI,YAAY,KAAK,KAAK;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,KAAK,OAAiE;AACpE,QAAI,UAAU,QAAW;AAEvB,YAAM,MAAM,eAAe;AAC3B,aAAO,KAAK,MAAM,GAAG;AAAA,IACvB;AAGA,WAAO,KAAK,IAAI,UAAU,KAAK,OAAO,KAAK,EAAE,KAAK,CAAC,QAAQ;AACzD,aAAO,KAAK,MAAM,GAAG;AAAA,IACvB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAgB,OAAgB,UAA0C;AAC9E,UAAM,KAAK,IAAI,SAAS,KAAK,OAAO,OAAO,QAAQ;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,UAA0C;AAI1D,YAAQ,KAAK,oDAAoD;AACjE,UAAM,WAAW,MAAM,KAAK,KAAK;AACjC,UAAM,KAAK,gBAAgB,SAAS,IAAI,GAAG,QAAQ;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,KAAK,YAAqB,SAAgC;AAC9D,QAAI,cAAc,SAAS;AACzB,YAAM,IAAI,MAAM,yCAAyC;AAAA,IAC3D;AACA,WAAO,KAAK,IAAI,UAAU,KAAK,OAAO,KAAK,kBAAkB,CAAC;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,GAAG,WAAsB,UAAwC;AAC/D,WAAO,KAAK,IAAI,WAAW,KAAK,OAAO,WAAW,QAAQ;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,WAA6B;AAC/B,QAAI,WAAW;AACb,WAAK,IAAI,sBAAsB,KAAK,OAAO,SAAS;AAAA,IACtD,OAAO;AACL,WAAK,IAAI,gBAAgB,KAAK,KAAK;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,eAA6B;AAC3B,WAAO,IAAI,aAAa,KAAK,KAAK,KAAK,KAAK;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,aAAgC;AAC9B,WAAO,IAAI,mBAAkB,KAAK,KAAK,KAAK,OAAO;AAAA,MACjD,GAAG,KAAK;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAqC;AACnC,WAAO,IAAI,mBAAkB,KAAK,KAAK,KAAK,OAAO;AAAA,MACjD,GAAG,KAAK;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,MAAiC;AAC5C,YAAQ,KAAK,uCAAuC;AACpD,WAAO,IAAI,mBAAkB,KAAK,KAAK,KAAK,OAAO;AAAA,MACjD,GAAG,KAAK;AAAA,MACR,SAAS;AAAA,MACT,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAAkC;AAChC,YAAQ,KAAK,uCAAuC;AACpD,WAAO,IAAI,mBAAkB,KAAK,KAAK,KAAK,OAAO;AAAA,MACjD,GAAG,KAAK;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,OAAkC;AAC7C,WAAO,IAAI,mBAAkB,KAAK,KAAK,KAAK,OAAO;AAAA,MACjD,GAAG,KAAK;AAAA,MACR,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,OAAkC;AAC5C,WAAO,IAAI,mBAAkB,KAAK,KAAK,KAAK,OAAO;AAAA,MACjD,GAAG,KAAK;AAAA,MACR,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,OAAgB,KAAiC;AACvD,YAAQ,KAAK,kCAAkC;AAC/C,WAAO,IAAI,mBAAkB,KAAK,KAAK,KAAK,OAAO;AAAA,MACjD,GAAG,KAAK;AAAA,MACR,SAAS,EAAE,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAgB,KAAiC;AACrD,YAAQ,KAAK,gCAAgC;AAC7C,WAAO,IAAI,mBAAkB,KAAK,KAAK,KAAK,OAAO;AAAA,MACjD,GAAG,KAAK;AAAA,MACR,OAAO,EAAE,OAAO,IAAI;AAAA,IACtB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,OAAgB,KAAiC;AACvD,YAAQ,KAAK,kCAAkC;AAC/C,WAAO,IAAI,mBAAkB,KAAK,KAAK,KAAK,OAAO;AAAA,MACjD,GAAG,KAAK;AAAA,MACR,SAAS,EAAE,OAAO,IAAI;AAAA,IACxB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,oBAA6C;AACnD,UAAM,SAAsB,CAAC;AAC7B,QAAI,YAAY;AAEhB,QAAI,KAAK,OAAO,YAAY,OAAO;AACjC,aAAO,KAAK;AACZ,kBAAY;AAAA,IACd,WAAW,KAAK,OAAO,YAAY,YAAY;AAC7C,aAAO,KAAK;AACZ,kBAAY;AAAA,IACd;AAEA,QAAI,KAAK,OAAO,iBAAiB,QAAW;AAC1C,aAAO,KAAK,KAAK,OAAO;AACxB,kBAAY;AAAA,IACd;AAEA,QAAI,KAAK,OAAO,gBAAgB,QAAW;AACzC,aAAO,KAAK,KAAK,OAAO;AACxB,kBAAY;AAAA,IACd;AAEA,WAAO,YAAY,SAAS;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAmB;AACjB,UAAM,UAAU,KAAK,IAAI,YAAY;AAErC,QAAI,KAAK,UAAU,KAAK;AACtB,aAAO;AAAA,IACT;AACA,WAAO,GAAG,OAAO,GAAG,KAAK,KAAK;AAAA,EAChC;AACF;;;AC9UO,IAAM,eAAN,MAAM,cAAa;AAAA,EAOxB,YACE,MACA,MACA,IACA,UAAqE,CAAC,GACtE;AACA,SAAK,QAAQ;AACb,SAAK,QAAQ,cAAc,IAAI;AAC/B,SAAK,MAAM;AACX,SAAK,YAAY,QAAQ,YAAY;AACrC,SAAK,YAAY,QAAQ,YAAY;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAyB;AAC3B,WAAO,KAAK,IAAI,IAAI,KAAK,KAAK;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAqB;AACvB,WAAO,OAAO,KAAK,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAe;AACb,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,SAAkB;AAChB,WAAO,KAAK,UAAU,QAAQ,KAAK,UAAU;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAA4B;AAChC,UAAM,YAAY,SAAS,KAAK,OAAO,IAAI;AAC3C,UAAM,YAAY,eAAe,KAAK,OAAO,IAAI;AACjD,WAAO,IAAI,cAAa,WAAW,WAAW,KAAK,KAAK;AAAA,MACtD,UAAU,KAAK;AAAA,IACjB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,QAAI,OAAO,KAAK,UAAU,YAAY,KAAK,UAAU,MAAM;AACzD,aAAO;AAAA,IACT;AACA,WAAO,OAAO,KAAK,KAAK,KAAK,EAAE,SAAS;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,MAAuB;AAC9B,UAAM,YAAY,eAAe,KAAK,OAAO,IAAI;AACjD,WAAO,cAAc,UAAa,cAAc;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,cAAsB;AACpB,QAAI,OAAO,KAAK,UAAU,YAAY,KAAK,UAAU,MAAM;AACzD,aAAO;AAAA,IACT;AACA,WAAO,OAAO,KAAK,KAAK,KAAK,EAAE;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,UAAyD;AAC/D,QAAI,OAAO,KAAK,UAAU,YAAY,KAAK,UAAU,MAAM;AACzD;AAAA,IACF;AAEA,UAAM,OAAO,OAAO,KAAK,KAAK,KAAK;AACnC,eAAW,OAAO,MAAM;AACtB,YAAM,YAAY,KAAK,MAAM,GAAG;AAChC,UAAI,SAAS,SAAS,MAAM,MAAM;AAChC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cAAsC;AACpC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAsB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,SAAkB;AAChB,WAAO,KAAK;AAAA,EACd;AACF;;;ACjHO,SAAS,iBAAiB,OAA2B;AAC1D,QAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,IAAI,MAAM,oBAAoB;AAAA,EACtC;AAEA,QAAM,UAAU,MAAM,CAAC;AAGvB,QAAM,SAAS,QAAQ,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG;AAC3D,QAAM,SAAS,SAAS,IAAI,QAAQ,IAAK,OAAO,SAAS,KAAM,CAAC;AAGhE,MAAI;AACJ,MAAI,OAAO,SAAS,YAAY;AAE9B,cAAU,KAAK,MAAM;AAAA,EACvB,OAAO;AAEL,cAAU,OAAO,KAAK,QAAQ,QAAQ,EAAE,SAAS,OAAO;AAAA,EAC1D;AAEA,SAAO,KAAK,MAAM,OAAO;AAC3B;;;ACJO,IAAM,eAAN,MAAmB;AAAA,EAexB,cAAc;AAdd,SAAQ,SAA0B;AAClC,SAAQ,QAAyB;AACjC,SAAQ,cAA6B;AACrC,SAAQ,kBAAiC;AAEzC,SAAQ,KAA6B;AAKrC;AAAA,SAAQ,mBAAmB,oBAAI,IAAgB;AAC/C,SAAQ,sBAAsB,oBAAI,IAAgB;AAClD,SAAQ,iBAAiB,oBAAI,IAA4B;AAGvD,SAAK,eAAe,IAAI,aAAa;AACrC,SAAK,sBAAsB,IAAI,oBAAoB;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAI,YAAqB;AACvB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAwB;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,cAAsB;AACpB,QAAI,KAAK,mBAAmB,KAAK,aAAa;AAC5C,aAAO,GAAG,KAAK,eAAe,IAAI,KAAK,WAAW;AAAA,IACpD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,QAAQ,YAAoB,UAA0B,CAAC,GAAkB;AAC7E,QAAI,KAAK,WAAW,gBAAgB;AAClC,YAAM,IAAI,MAAM,iCAAiC;AAAA,IACnD;AAEA,SAAK,SAAS;AACd,SAAK,cAAc;AACnB,SAAK,kBAAkB,QAAQ,eAAe;AAE9C,QAAI;AAEF,YAAM,iBAAiB,KAAK;AAC5B,YAAM,cAAc,IAAI,YAAY,cAAc;AAElD,YAAM,kBAAkB,MAAM,YAAY,QAAQ,YAAY;AAAA,QAC5D,OAAO,QAAQ;AAAA,QACf,WAAW,QAAQ;AAAA,MACrB,CAAC;AAGD,YAAM,QAAQ,gBAAgB;AAE9B,WAAK,KAAK,IAAI,gBAAgB;AAAA,QAC5B,WAAW,KAAK,cAAc,KAAK,IAAI;AAAA,QACvC,QAAQ,MAAM;AAAA,QAAC;AAAA;AAAA,QACf,SAAS,KAAK,YAAY,KAAK,IAAI;AAAA,QACnC,SAAS,KAAK,YAAY,KAAK,IAAI;AAAA,MACrC,CAAC;AAED,YAAM,KAAK,GAAG,QAAQ,KAAK;AAG3B,YAAM,YAAY,KAAK,aAAa,cAAc;AAClD,YAAM,cAA6B;AAAA,QACjC,GAAG;AAAA,QACH,GAAG,gBAAgB;AAAA,QACnB,GAAG;AAAA,MACL;AAEA,WAAK,KAAK,WAAW;AAGrB,YAAM,KAAK,aAAa,gBAAgB,SAAS;AAGjD,YAAM,aAAa,iBAAiB,gBAAgB,KAAK;AACzD,WAAK,QAAQ;AAAA,QACX,KAAK,WAAW;AAAA,QAChB,UAAU,WAAW;AAAA,QACrB,OAAO,WAAW,UAAU,CAAC;AAAA,MAC/B;AAEA,WAAK,SAAS;AAGd,WAAK,oBAAoB,WAAW;AAAA,QAClC,eAAe,KAAK,qBAAqB,KAAK,IAAI;AAAA,QAClD,iBAAiB,KAAK,uBAAuB,KAAK,IAAI;AAAA,QACtD,gBAAgB,KAAK,eAAe,KAAK,IAAI;AAAA,MAC/C,CAAC;AAGD,WAAK,iBAAiB,QAAQ,CAAC,OAAO,GAAG,CAAC;AAAA,IAC5C,SAAS,OAAO;AACd,WAAK,SAAS;AACd,WAAK,QAAQ;AACb,WAAK,cAAc;AACnB,WAAK,IAAI,MAAM;AACf,WAAK,KAAK;AACV,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAA4B;AAChC,QAAI,KAAK,WAAW,gBAAgB;AAClC;AAAA,IACF;AAGA,QAAI,KAAK,WAAW,eAAe,KAAK,IAAI;AAC1C,UAAI;AACF,cAAM,YAAY,KAAK,aAAa,cAAc;AAClD,aAAK,KAAK,EAAE,GAAG,KAAK,GAAG,UAAU,CAAC;AAElC,cAAM,QAAQ,KAAK;AAAA,UACjB,KAAK,aAAa,gBAAgB,SAAS;AAAA,UAC3C,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAI,CAAC;AAAA,QACpD,CAAC;AAAA,MACH,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAgB;AACtB,SAAK,IAAI,MAAM;AACf,SAAK,KAAK;AACV,SAAK,SAAS;AACd,SAAK,QAAQ;AACb,SAAK,cAAc;AACnB,SAAK,kBAAkB;AACvB,SAAK,oBAAoB,MAAM;AAC/B,SAAK,aAAa,UAAU,IAAI,MAAM,mBAAmB,CAAC;AAAA,EAC5D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAI,OAAe,IAAuB;AACxC,WAAO,IAAI,kBAAkB,MAAM,IAAI;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,UAAU,UAAkC;AAC1C,SAAK,iBAAiB,IAAI,QAAQ;AAClC,WAAO,MAAM,KAAK,iBAAiB,OAAO,QAAQ;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,UAAkC;AAC7C,SAAK,oBAAoB,IAAI,QAAQ;AACrC,WAAO,MAAM,KAAK,oBAAoB,OAAO,QAAQ;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,UAA8C;AACpD,SAAK,eAAe,IAAI,QAAQ;AAChC,WAAO,MAAM,KAAK,eAAe,OAAO,QAAQ;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAc,MAAoB;AACxC,QAAI;AACJ,QAAI;AACF,gBAAU,KAAK,MAAM,IAAI;AAAA,IAC3B,QAAQ;AACN,cAAQ,MAAM,4BAA4B,IAAI;AAC9C;AAAA,IACF;AAGA,QAAI,KAAK,aAAa,cAAc,OAAO,GAAG;AAC5C;AAAA,IACF;AAGA,QAAI,eAAe,OAAO,GAAG;AAC3B,WAAK,oBAAoB,YAAY,OAAO;AAAA,IAC9C;AAAA,EACF;AAAA,EAEQ,YAAY,MAAc,QAAsB;AACtD,UAAM,eAAe,KAAK,WAAW;AACrC,SAAK,QAAQ;AAEb,QAAI,cAAc;AAChB,WAAK,oBAAoB,QAAQ,CAAC,OAAO,GAAG,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA,EAEQ,YAAY,OAAoB;AACtC,UAAM,QAAQ,IAAI,MAAM,iBAAiB;AACzC,SAAK,eAAe,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAMQ,KAAK,SAA8B;AACzC,QAAI,CAAC,KAAK,MAAM,CAAC,KAAK,GAAG,WAAW;AAClC,YAAM,IAAI,UAAU,iBAAiB,2BAA2B;AAAA,IAClE;AACA,SAAK,GAAG,KAAK,KAAK,UAAU,OAAO,CAAC;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,MAAc,OAAgB,UAA2C;AACtF,UAAM,YAAY,KAAK,aAAa,cAAc;AAClD,UAAM,UAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,GAAG,cAAc,IAAI,KAAK;AAAA,MAC1B,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AACA,QAAI,aAAa,QAAW;AAC1B,cAAQ,IAAI;AAAA,IACd;AACA,SAAK,KAAK,OAAO;AACjB,UAAM,KAAK,aAAa,gBAAgB,SAAS;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,MAAc,QAAgD;AAC9E,UAAM,YAAY,KAAK,aAAa,cAAc;AAClD,UAAM,UAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,GAAG,cAAc,IAAI,KAAK;AAAA,MAC1B,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AACA,SAAK,KAAK,OAAO;AACjB,UAAM,KAAK,aAAa,gBAAgB,SAAS;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,MAA6B;AAC7C,UAAM,YAAY,KAAK,aAAa,cAAc;AAClD,UAAM,UAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,GAAG,cAAc,IAAI,KAAK;AAAA,MAC1B,GAAG;AAAA,IACL;AACA,SAAK,KAAK,OAAO;AACjB,UAAM,KAAK,aAAa,gBAAgB,SAAS;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,MAAc,OAAiC;AAC7D,UAAM,YAAY,KAAK,aAAa,cAAc;AAClD,UAAM,UAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,GAAG,cAAc,IAAI,KAAK;AAAA,MAC1B,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AACA,SAAK,KAAK,OAAO;AACjB,UAAM,MAAO,MAAM,KAAK,aAAa,gBAAgB,SAAS;AAC9D,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,MAAc,OAA4C;AACxE,UAAM,YAAY,KAAK,aAAa,cAAc;AAClD,UAAM,UAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,GAAG,cAAc,IAAI,KAAK;AAAA,MAC1B,GAAG;AAAA,IACL;AACA,QAAI,OAAO;AACT,cAAQ,IAAI;AAAA,IACd;AACA,SAAK,KAAK,OAAO;AACjB,UAAM,QAAQ,MAAM,KAAK,aAAa,gBAAgB,SAAS;AAC/D,WAAO,IAAI,aAAa,OAAO,MAAM,IAAI;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBACJ,MACA,QACA,OACA,UACe;AACf,UAAM,YAAY,KAAK,aAAa,cAAc;AAClD,UAAM,UAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,GAAG,cAAc,IAAI,KAAK;AAAA,MAC1B,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AACA,QAAI,UAAU,QAAW;AACvB,cAAQ,IAAI;AAAA,IACd;AACA,QAAI,aAAa,QAAW;AAC1B,cAAQ,IAAI;AAAA,IACd;AACA,SAAK,KAAK,OAAO;AACjB,UAAM,KAAK,aAAa,gBAAgB,SAAS;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,qBAAqB,MAAc,YAAqC;AACpF,UAAM,YAAY,KAAK,aAAa,cAAc;AAClD,UAAM,UAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,GAAG,cAAc,IAAI,KAAK;AAAA,MAC1B,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AACA,SAAK,KAAK,OAAO;AACjB,UAAM,KAAK,aAAa,gBAAgB,SAAS;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,uBAAuB,MAA6B;AAChE,UAAM,YAAY,KAAK,aAAa,cAAc;AAClD,UAAM,UAAyB;AAAA,MAC7B,GAAG;AAAA,MACH,GAAG,cAAc,IAAI,KAAK;AAAA,MAC1B,GAAG;AAAA,IACL;AACA,SAAK,KAAK,OAAO;AACjB,UAAM,KAAK,aAAa,gBAAgB,SAAS;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,MAAc,OAAgB,UAAiC;AACpF,WAAO,IAAI,aAAa,OAAO,MAAM,MAAM,EAAE,SAAS,CAAC;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,WAAW,MAAc,WAAsB,UAAwC;AACrF,WAAO,KAAK,oBAAoB,UAAU,MAAM,WAAW,QAAQ;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,MAAc,WAA4B;AAC9D,SAAK,oBAAoB,qBAAqB,MAAM,SAAS;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,MAAoB;AAClC,SAAK,oBAAoB,eAAe,IAAI;AAAA,EAC9C;AACF;","names":["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/SubscriptionManager.ts","../src/connection/WebSocketClient.ts","../src/OnDisconnect.ts","../src/utils/path.ts","../src/utils/pushid.ts","../src/DatabaseReference.ts","../src/DataSnapshot.ts","../src/utils/jwt.ts","../src/LarkDatabase.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 { ConnectOptions, AuthInfo } from './LarkDatabase';\n\nexport { DatabaseReference } from './DatabaseReference';\nexport type { SnapshotCallback, QueryState } 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';\n\n// Utility functions (for advanced usage)\nexport { generatePushId } from './utils/pushid';\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} as const;\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 (short form)\nexport const EventTypeShort = {\n VALUE: 'v',\n CHILD_ADDED: 'ca',\n CHILD_CHANGED: 'cc',\n CHILD_REMOVED: 'cr',\n} as const;\n\n// Event types (long form, used in API)\nexport type EventType = 'value' | 'child_added' | 'child_changed' | 'child_removed';\n\n// Map short event types to long form\nexport const eventTypeFromShort: Record<string, EventType> = {\n v: 'value',\n ca: 'child_added',\n cc: 'child_changed',\n cr: 'child_removed',\n};\n\n// Map long event types to short form\nexport const eventTypeToShort: Record<EventType, string> = {\n value: 'v',\n child_added: 'ca',\n child_changed: 'cc',\n child_removed: 'cr',\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} as const;\n\nexport type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];\n\n// Default coordinator URL\nexport const DEFAULT_COORDINATOR_URL = 'https://db.lark.dev';\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.lark.sh/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)\n q?: QueryParams;\n}\n\nexport interface QueryParams {\n ob?: 'k' | 'p'; // orderBy: 'k'=key, 'p'=priority\n lf?: number; // limitToFirst\n ll?: number; // limitToLast\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 q?: QueryParams; // query parameters (optional)\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\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\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\nexport interface EventMessage {\n ev: string; // event type (short form: v, ca, cc, cr)\n p: string; // path\n v?: unknown; // value (not present for child_removed)\n k?: string; // child key (for child_* events)\n x?: boolean; // volatile flag\n}\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 JoinAckMessage {\n a: string; // ack with request ID\n uid: string; // user ID from auth\n provider: string; // auth provider\n token?: Record<string, unknown>; // custom claims\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 | JoinAckMessage\n | PingMessage;\n\n// ============================================\n// Helper functions\n// ============================================\n\nexport function isAckMessage(msg: ServerMessage): msg is AckMessage {\n return 'a' in msg && !('uid' in msg);\n}\n\nexport function isJoinAckMessage(msg: ServerMessage): msg is JoinAckMessage {\n return 'a' in msg && 'uid' 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 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 isJoinAckMessage,\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 ack (includes auth info)\n if (isJoinAckMessage(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({\n uid: message.uid,\n provider: message.provider,\n token: message.token,\n });\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 * SubscriptionManager - tracks active subscriptions and routes events to callbacks.\n */\n\nimport type { DataSnapshot } from '../DataSnapshot';\nimport { EventType, eventTypeFromShort, eventTypeToShort } from '../protocol/constants';\nimport { EventMessage } from '../protocol/messages';\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 // path -> eventType -> array of subscriptions\n private subscriptions = new Map<string, Map<EventType, SubscriptionEntry[]>>();\n\n // Callback to send subscribe message to server\n private sendSubscribe: ((path: string, eventTypes: string[]) => Promise<void>) | null = null;\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: ((path: string, value: unknown, volatile: boolean) => DataSnapshot) | null = null;\n\n /**\n * Initialize the manager with server communication callbacks.\n */\n initialize(options: {\n sendSubscribe: (path: string, eventTypes: string[]) => Promise<void>;\n sendUnsubscribe: (path: string) => Promise<void>;\n createSnapshot: (path: string, value: unknown, volatile: boolean) => 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): () => 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 // 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 const shortEventTypes = allEventTypes.map((et) => eventTypeToShort[et]);\n\n // Fire and forget - we don't wait for the server\n this.sendSubscribe?.(normalizedPath, shortEventTypes).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\n if (pathSubs.size === 0) {\n this.subscriptions.delete(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.sendUnsubscribe?.(normalizedPath).catch((err) => {\n console.error('Failed to unsubscribe:', err);\n });\n } else {\n // Update server with remaining event types\n const remainingEventTypes = this.getEventTypesForPath(normalizedPath);\n const shortEventTypes = remainingEventTypes.map((et) => eventTypeToShort[et]);\n this.sendSubscribe?.(normalizedPath, shortEventTypes).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.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 */\n handleEvent(message: EventMessage): void {\n const eventType = eventTypeFromShort[message.ev];\n if (!eventType) {\n console.warn('Unknown event type:', message.ev);\n return;\n }\n\n const path = message.p;\n const pathSubs = this.subscriptions.get(path);\n if (!pathSubs) return;\n\n const eventSubs = pathSubs.get(eventType);\n if (!eventSubs || eventSubs.length === 0) return;\n\n // Determine the snapshot path and value based on event type\n let snapshotPath: string;\n let snapshotValue: unknown;\n\n if (eventType === 'value') {\n snapshotPath = path;\n snapshotValue = message.v;\n } else {\n // child_* events: the snapshot is for the child\n snapshotPath = path === '/' ? `/${message.k}` : `${path}/${message.k}`;\n snapshotValue = message.v;\n }\n\n // Create snapshot and invoke callbacks\n const snapshot = this.createSnapshot?.(snapshotPath, snapshotValue, message.x ?? false);\n if (!snapshot) return;\n\n for (const entry of eventSubs) {\n try {\n entry.callback(snapshot, undefined);\n } catch (err) {\n console.error('Error in subscription callback:', err);\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 }\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 * 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 * 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 * 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 { OnDisconnect } from './OnDisconnect';\nimport { EventType } from './protocol/constants';\nimport { QueryParams } from './protocol/messages';\nimport { getKey, getParentPath, joinPath, normalizePath } from './utils/path';\nimport { generatePushId } from './utils/pushid';\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 async update(values: Record<string, unknown>): Promise<void> {\n await this._db._sendUpdate(this._path, values);\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 // 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);\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n orderByChild(path: string): DatabaseReference {\n console.warn('orderByChild() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n orderByValue(): DatabaseReference {\n console.warn('orderByValue() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n startAt(value: unknown, key?: string): DatabaseReference {\n console.warn('startAt() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n endAt(value: unknown, key?: string): DatabaseReference {\n console.warn('endAt() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n equalTo(value: unknown, key?: string): DatabaseReference {\n console.warn('equalTo() is not yet implemented');\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 if (this._query.orderBy === 'key') {\n params.ob = 'k';\n hasParams = true;\n } else if (this._query.orderBy === 'priority') {\n params.ob = 'p';\n hasParams = true;\n }\n\n if (this._query.limitToFirst !== undefined) {\n params.lf = this._query.limitToFirst;\n hasParams = true;\n }\n\n if (this._query.limitToLast !== undefined) {\n params.ll = this._query.limitToLast;\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\n constructor(\n data: unknown,\n path: string,\n db: LarkDatabase,\n options: { volatile?: boolean; priority?: number | string | 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 }\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 });\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 * 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 { 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 isEventMessage,\n isPingMessage,\n QueryParams,\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\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\n private ws: WebSocketClient | null = null;\n private messageQueue: MessageQueue;\n private subscriptionManager: SubscriptionManager;\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 }\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 // 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 ack\n await this.messageQueue.registerRequest(requestId);\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._coordinatorUrl = null;\n this.subscriptionManager.clear();\n this.messageQueue.rejectAll(new Error('Connection closed'));\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 // 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 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 message: ClientMessage = {\n o: 's',\n p: normalizePath(path) || '/',\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 message: ClientMessage = {\n o: 'u',\n p: normalizePath(path) || '/',\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 message: ClientMessage = {\n o: 'd',\n p: normalizePath(path) || '/',\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 message: ClientMessage = {\n o: 'p',\n p: normalizePath(path) || '/',\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 async _sendOnce(path: string, query?: QueryParams): Promise<DataSnapshot> {\n const requestId = this.messageQueue.nextRequestId();\n const message: ClientMessage = {\n o: 'o',\n p: normalizePath(path) || '/',\n r: requestId,\n };\n if (query) {\n message.q = 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[]): 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 };\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(path: string, value: unknown, volatile: boolean): DataSnapshot {\n return new DataSnapshot(value, path, this, { volatile });\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): () => void {\n return this.subscriptionManager.subscribe(path, eventType, callback);\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"],"mappings":"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","names":["WebSocketNode"]}
|
package/dist/index.mjs
CHANGED
|
@@ -95,6 +95,9 @@ function isOnceResponseMessage(msg) {
|
|
|
95
95
|
function isPushAckMessage(msg) {
|
|
96
96
|
return "pa" in msg;
|
|
97
97
|
}
|
|
98
|
+
function isPingMessage(msg) {
|
|
99
|
+
return "o" in msg && msg.o === "pi";
|
|
100
|
+
}
|
|
98
101
|
|
|
99
102
|
// src/connection/MessageQueue.ts
|
|
100
103
|
var MessageQueue = class {
|
|
@@ -1160,6 +1163,10 @@ var LarkDatabase = class {
|
|
|
1160
1163
|
console.error("Failed to parse message:", data);
|
|
1161
1164
|
return;
|
|
1162
1165
|
}
|
|
1166
|
+
if (isPingMessage(message)) {
|
|
1167
|
+
this.ws?.send(JSON.stringify({ o: "po" }));
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1163
1170
|
if (this.messageQueue.handleMessage(message)) {
|
|
1164
1171
|
return;
|
|
1165
1172
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/protocol/constants.ts","../src/connection/Coordinator.ts","../src/LarkError.ts","../src/protocol/messages.ts","../src/connection/MessageQueue.ts","../src/connection/SubscriptionManager.ts","../src/connection/WebSocketClient.ts","../src/OnDisconnect.ts","../src/utils/path.ts","../src/utils/pushid.ts","../src/DatabaseReference.ts","../src/DataSnapshot.ts","../src/utils/jwt.ts","../src/LarkDatabase.ts"],"sourcesContent":["/**\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} as const;\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 (short form)\nexport const EventTypeShort = {\n VALUE: 'v',\n CHILD_ADDED: 'ca',\n CHILD_CHANGED: 'cc',\n CHILD_REMOVED: 'cr',\n} as const;\n\n// Event types (long form, used in API)\nexport type EventType = 'value' | 'child_added' | 'child_changed' | 'child_removed';\n\n// Map short event types to long form\nexport const eventTypeFromShort: Record<string, EventType> = {\n v: 'value',\n ca: 'child_added',\n cc: 'child_changed',\n cr: 'child_removed',\n};\n\n// Map long event types to short form\nexport const eventTypeToShort: Record<EventType, string> = {\n value: 'v',\n child_added: 'ca',\n child_changed: 'cc',\n child_removed: 'cr',\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} as const;\n\nexport type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];\n\n// Default coordinator URL\nexport const DEFAULT_COORDINATOR_URL = 'https://db.lark.dev';\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.lark.sh/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)\n q?: QueryParams;\n}\n\nexport interface QueryParams {\n ob?: 'k' | 'p'; // orderBy: 'k'=key, 'p'=priority\n lf?: number; // limitToFirst\n ll?: number; // limitToLast\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 q?: QueryParams; // query parameters (optional)\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 type ClientMessage =\n | JoinMessage\n | SetMessage\n | UpdateMessage\n | DeleteMessage\n | PushMessage\n | SubscribeMessage\n | UnsubscribeMessage\n | OnceMessage\n | OnDisconnectMessage\n | LeaveMessage;\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\nexport interface EventMessage {\n ev: string; // event type (short form: v, ca, cc, cr)\n p: string; // path\n v?: unknown; // value (not present for child_removed)\n k?: string; // child key (for child_* events)\n x?: boolean; // volatile flag\n}\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 JoinAckMessage {\n a: string; // ack with request ID\n uid: string; // user ID from auth\n provider: string; // auth provider\n token?: Record<string, unknown>; // custom claims\n}\n\nexport type ServerMessage =\n | AckMessage\n | NackMessage\n | EventMessage\n | OnceResponseMessage\n | PushAckMessage\n | JoinAckMessage;\n\n// ============================================\n// Helper functions\n// ============================================\n\nexport function isAckMessage(msg: ServerMessage): msg is AckMessage {\n return 'a' in msg && !('uid' in msg);\n}\n\nexport function isJoinAckMessage(msg: ServerMessage): msg is JoinAckMessage {\n return 'a' in msg && 'uid' 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 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","/**\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 isJoinAckMessage,\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 ack (includes auth info)\n if (isJoinAckMessage(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({\n uid: message.uid,\n provider: message.provider,\n token: message.token,\n });\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 * SubscriptionManager - tracks active subscriptions and routes events to callbacks.\n */\n\nimport type { DataSnapshot } from '../DataSnapshot';\nimport { EventType, eventTypeFromShort, eventTypeToShort } from '../protocol/constants';\nimport { EventMessage } from '../protocol/messages';\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 // path -> eventType -> array of subscriptions\n private subscriptions = new Map<string, Map<EventType, SubscriptionEntry[]>>();\n\n // Callback to send subscribe message to server\n private sendSubscribe: ((path: string, eventTypes: string[]) => Promise<void>) | null = null;\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: ((path: string, value: unknown, volatile: boolean) => DataSnapshot) | null = null;\n\n /**\n * Initialize the manager with server communication callbacks.\n */\n initialize(options: {\n sendSubscribe: (path: string, eventTypes: string[]) => Promise<void>;\n sendUnsubscribe: (path: string) => Promise<void>;\n createSnapshot: (path: string, value: unknown, volatile: boolean) => 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): () => 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 // 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 const shortEventTypes = allEventTypes.map((et) => eventTypeToShort[et]);\n\n // Fire and forget - we don't wait for the server\n this.sendSubscribe?.(normalizedPath, shortEventTypes).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\n if (pathSubs.size === 0) {\n this.subscriptions.delete(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.sendUnsubscribe?.(normalizedPath).catch((err) => {\n console.error('Failed to unsubscribe:', err);\n });\n } else {\n // Update server with remaining event types\n const remainingEventTypes = this.getEventTypesForPath(normalizedPath);\n const shortEventTypes = remainingEventTypes.map((et) => eventTypeToShort[et]);\n this.sendSubscribe?.(normalizedPath, shortEventTypes).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.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 */\n handleEvent(message: EventMessage): void {\n const eventType = eventTypeFromShort[message.ev];\n if (!eventType) {\n console.warn('Unknown event type:', message.ev);\n return;\n }\n\n const path = message.p;\n const pathSubs = this.subscriptions.get(path);\n if (!pathSubs) return;\n\n const eventSubs = pathSubs.get(eventType);\n if (!eventSubs || eventSubs.length === 0) return;\n\n // Determine the snapshot path and value based on event type\n let snapshotPath: string;\n let snapshotValue: unknown;\n\n if (eventType === 'value') {\n snapshotPath = path;\n snapshotValue = message.v;\n } else {\n // child_* events: the snapshot is for the child\n snapshotPath = path === '/' ? `/${message.k}` : `${path}/${message.k}`;\n snapshotValue = message.v;\n }\n\n // Create snapshot and invoke callbacks\n const snapshot = this.createSnapshot?.(snapshotPath, snapshotValue, message.x ?? false);\n if (!snapshot) return;\n\n for (const entry of eventSubs) {\n try {\n entry.callback(snapshot, undefined);\n } catch (err) {\n console.error('Error in subscription callback:', err);\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 }\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 * 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 * 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 * 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 { OnDisconnect } from './OnDisconnect';\nimport { EventType } from './protocol/constants';\nimport { QueryParams } from './protocol/messages';\nimport { getKey, getParentPath, joinPath, normalizePath } from './utils/path';\nimport { generatePushId } from './utils/pushid';\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 async update(values: Record<string, unknown>): Promise<void> {\n await this._db._sendUpdate(this._path, values);\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 // 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);\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n orderByChild(path: string): DatabaseReference {\n console.warn('orderByChild() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n orderByValue(): DatabaseReference {\n console.warn('orderByValue() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n startAt(value: unknown, key?: string): DatabaseReference {\n console.warn('startAt() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n endAt(value: unknown, key?: string): DatabaseReference {\n console.warn('endAt() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n equalTo(value: unknown, key?: string): DatabaseReference {\n console.warn('equalTo() is not yet implemented');\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 if (this._query.orderBy === 'key') {\n params.ob = 'k';\n hasParams = true;\n } else if (this._query.orderBy === 'priority') {\n params.ob = 'p';\n hasParams = true;\n }\n\n if (this._query.limitToFirst !== undefined) {\n params.lf = this._query.limitToFirst;\n hasParams = true;\n }\n\n if (this._query.limitToLast !== undefined) {\n params.ll = this._query.limitToLast;\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\n constructor(\n data: unknown,\n path: string,\n db: LarkDatabase,\n options: { volatile?: boolean; priority?: number | string | 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 }\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 });\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 * 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 { 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 isEventMessage,\n QueryParams,\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\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\n private ws: WebSocketClient | null = null;\n private messageQueue: MessageQueue;\n private subscriptionManager: SubscriptionManager;\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 }\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 // 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 ack\n await this.messageQueue.registerRequest(requestId);\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._coordinatorUrl = null;\n this.subscriptionManager.clear();\n this.messageQueue.rejectAll(new Error('Connection closed'));\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 // 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 // First, 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 message: ClientMessage = {\n o: 's',\n p: normalizePath(path) || '/',\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 message: ClientMessage = {\n o: 'u',\n p: normalizePath(path) || '/',\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 message: ClientMessage = {\n o: 'd',\n p: normalizePath(path) || '/',\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 message: ClientMessage = {\n o: 'p',\n p: normalizePath(path) || '/',\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 async _sendOnce(path: string, query?: QueryParams): Promise<DataSnapshot> {\n const requestId = this.messageQueue.nextRequestId();\n const message: ClientMessage = {\n o: 'o',\n p: normalizePath(path) || '/',\n r: requestId,\n };\n if (query) {\n message.q = 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[]): 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 };\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(path: string, value: unknown, volatile: boolean): DataSnapshot {\n return new DataSnapshot(value, path, this, { volatile });\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): () => void {\n return this.subscriptionManager.subscribe(path, eventType, callback);\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"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/protocol/constants.ts","../src/connection/Coordinator.ts","../src/LarkError.ts","../src/protocol/messages.ts","../src/connection/MessageQueue.ts","../src/connection/SubscriptionManager.ts","../src/connection/WebSocketClient.ts","../src/OnDisconnect.ts","../src/utils/path.ts","../src/utils/pushid.ts","../src/DatabaseReference.ts","../src/DataSnapshot.ts","../src/utils/jwt.ts","../src/LarkDatabase.ts"],"sourcesContent":["/**\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} as const;\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 (short form)\nexport const EventTypeShort = {\n VALUE: 'v',\n CHILD_ADDED: 'ca',\n CHILD_CHANGED: 'cc',\n CHILD_REMOVED: 'cr',\n} as const;\n\n// Event types (long form, used in API)\nexport type EventType = 'value' | 'child_added' | 'child_changed' | 'child_removed';\n\n// Map short event types to long form\nexport const eventTypeFromShort: Record<string, EventType> = {\n v: 'value',\n ca: 'child_added',\n cc: 'child_changed',\n cr: 'child_removed',\n};\n\n// Map long event types to short form\nexport const eventTypeToShort: Record<EventType, string> = {\n value: 'v',\n child_added: 'ca',\n child_changed: 'cc',\n child_removed: 'cr',\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} as const;\n\nexport type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];\n\n// Default coordinator URL\nexport const DEFAULT_COORDINATOR_URL = 'https://db.lark.dev';\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.lark.sh/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)\n q?: QueryParams;\n}\n\nexport interface QueryParams {\n ob?: 'k' | 'p'; // orderBy: 'k'=key, 'p'=priority\n lf?: number; // limitToFirst\n ll?: number; // limitToLast\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 q?: QueryParams; // query parameters (optional)\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\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\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\nexport interface EventMessage {\n ev: string; // event type (short form: v, ca, cc, cr)\n p: string; // path\n v?: unknown; // value (not present for child_removed)\n k?: string; // child key (for child_* events)\n x?: boolean; // volatile flag\n}\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 JoinAckMessage {\n a: string; // ack with request ID\n uid: string; // user ID from auth\n provider: string; // auth provider\n token?: Record<string, unknown>; // custom claims\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 | JoinAckMessage\n | PingMessage;\n\n// ============================================\n// Helper functions\n// ============================================\n\nexport function isAckMessage(msg: ServerMessage): msg is AckMessage {\n return 'a' in msg && !('uid' in msg);\n}\n\nexport function isJoinAckMessage(msg: ServerMessage): msg is JoinAckMessage {\n return 'a' in msg && 'uid' 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 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 isJoinAckMessage,\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 ack (includes auth info)\n if (isJoinAckMessage(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({\n uid: message.uid,\n provider: message.provider,\n token: message.token,\n });\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 * SubscriptionManager - tracks active subscriptions and routes events to callbacks.\n */\n\nimport type { DataSnapshot } from '../DataSnapshot';\nimport { EventType, eventTypeFromShort, eventTypeToShort } from '../protocol/constants';\nimport { EventMessage } from '../protocol/messages';\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 // path -> eventType -> array of subscriptions\n private subscriptions = new Map<string, Map<EventType, SubscriptionEntry[]>>();\n\n // Callback to send subscribe message to server\n private sendSubscribe: ((path: string, eventTypes: string[]) => Promise<void>) | null = null;\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: ((path: string, value: unknown, volatile: boolean) => DataSnapshot) | null = null;\n\n /**\n * Initialize the manager with server communication callbacks.\n */\n initialize(options: {\n sendSubscribe: (path: string, eventTypes: string[]) => Promise<void>;\n sendUnsubscribe: (path: string) => Promise<void>;\n createSnapshot: (path: string, value: unknown, volatile: boolean) => 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): () => 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 // 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 const shortEventTypes = allEventTypes.map((et) => eventTypeToShort[et]);\n\n // Fire and forget - we don't wait for the server\n this.sendSubscribe?.(normalizedPath, shortEventTypes).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\n if (pathSubs.size === 0) {\n this.subscriptions.delete(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.sendUnsubscribe?.(normalizedPath).catch((err) => {\n console.error('Failed to unsubscribe:', err);\n });\n } else {\n // Update server with remaining event types\n const remainingEventTypes = this.getEventTypesForPath(normalizedPath);\n const shortEventTypes = remainingEventTypes.map((et) => eventTypeToShort[et]);\n this.sendSubscribe?.(normalizedPath, shortEventTypes).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.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 */\n handleEvent(message: EventMessage): void {\n const eventType = eventTypeFromShort[message.ev];\n if (!eventType) {\n console.warn('Unknown event type:', message.ev);\n return;\n }\n\n const path = message.p;\n const pathSubs = this.subscriptions.get(path);\n if (!pathSubs) return;\n\n const eventSubs = pathSubs.get(eventType);\n if (!eventSubs || eventSubs.length === 0) return;\n\n // Determine the snapshot path and value based on event type\n let snapshotPath: string;\n let snapshotValue: unknown;\n\n if (eventType === 'value') {\n snapshotPath = path;\n snapshotValue = message.v;\n } else {\n // child_* events: the snapshot is for the child\n snapshotPath = path === '/' ? `/${message.k}` : `${path}/${message.k}`;\n snapshotValue = message.v;\n }\n\n // Create snapshot and invoke callbacks\n const snapshot = this.createSnapshot?.(snapshotPath, snapshotValue, message.x ?? false);\n if (!snapshot) return;\n\n for (const entry of eventSubs) {\n try {\n entry.callback(snapshot, undefined);\n } catch (err) {\n console.error('Error in subscription callback:', err);\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 }\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 * 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 * 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 * 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 { OnDisconnect } from './OnDisconnect';\nimport { EventType } from './protocol/constants';\nimport { QueryParams } from './protocol/messages';\nimport { getKey, getParentPath, joinPath, normalizePath } from './utils/path';\nimport { generatePushId } from './utils/pushid';\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 async update(values: Record<string, unknown>): Promise<void> {\n await this._db._sendUpdate(this._path, values);\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 // 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);\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n orderByChild(path: string): DatabaseReference {\n console.warn('orderByChild() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n orderByValue(): DatabaseReference {\n console.warn('orderByValue() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n startAt(value: unknown, key?: string): DatabaseReference {\n console.warn('startAt() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n endAt(value: unknown, key?: string): DatabaseReference {\n console.warn('endAt() is not yet implemented');\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 * NOTE: Phase 2 - not yet implemented on server.\n */\n equalTo(value: unknown, key?: string): DatabaseReference {\n console.warn('equalTo() is not yet implemented');\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 if (this._query.orderBy === 'key') {\n params.ob = 'k';\n hasParams = true;\n } else if (this._query.orderBy === 'priority') {\n params.ob = 'p';\n hasParams = true;\n }\n\n if (this._query.limitToFirst !== undefined) {\n params.lf = this._query.limitToFirst;\n hasParams = true;\n }\n\n if (this._query.limitToLast !== undefined) {\n params.ll = this._query.limitToLast;\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\n constructor(\n data: unknown,\n path: string,\n db: LarkDatabase,\n options: { volatile?: boolean; priority?: number | string | 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 }\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 });\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 * 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 { 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 isEventMessage,\n isPingMessage,\n QueryParams,\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\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\n private ws: WebSocketClient | null = null;\n private messageQueue: MessageQueue;\n private subscriptionManager: SubscriptionManager;\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 }\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 // 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 ack\n await this.messageQueue.registerRequest(requestId);\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._coordinatorUrl = null;\n this.subscriptionManager.clear();\n this.messageQueue.rejectAll(new Error('Connection closed'));\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 // 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 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 message: ClientMessage = {\n o: 's',\n p: normalizePath(path) || '/',\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 message: ClientMessage = {\n o: 'u',\n p: normalizePath(path) || '/',\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 message: ClientMessage = {\n o: 'd',\n p: normalizePath(path) || '/',\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 message: ClientMessage = {\n o: 'p',\n p: normalizePath(path) || '/',\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 async _sendOnce(path: string, query?: QueryParams): Promise<DataSnapshot> {\n const requestId = this.messageQueue.nextRequestId();\n const message: ClientMessage = {\n o: 'o',\n p: normalizePath(path) || '/',\n r: requestId,\n };\n if (query) {\n message.q = 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[]): 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 };\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(path: string, value: unknown, volatile: boolean): DataSnapshot {\n return new DataSnapshot(value, path, this, { volatile });\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): () => void {\n return this.subscriptionManager.subscribe(path, eventType, callback);\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"],"mappings":"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","names":[]}
|