@lark-sh/client 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -28,13 +28,20 @@ declare class OnDisconnect {
28
28
  setWithPriority(value: unknown, priority: number | string): Promise<void>;
29
29
  }
30
30
 
31
- type EventType = 'value' | 'child_added' | 'child_changed' | 'child_removed';
31
+ type EventType = 'value' | 'child_added' | 'child_changed' | 'child_removed' | 'child_moved';
32
32
 
33
33
  /**
34
34
  * DatabaseReference - a reference to a specific path in the database.
35
35
  * Immutable - navigation returns new references.
36
36
  */
37
37
 
38
+ /** Result of a transaction operation */
39
+ interface TransactionResult {
40
+ /** Whether the transaction was committed (always true on success) */
41
+ committed: boolean;
42
+ /** Snapshot of the data after the transaction */
43
+ snapshot: DataSnapshot;
44
+ }
38
45
  type SnapshotCallback$1 = (snapshot: DataSnapshot, previousChildKey?: string | null) => void;
39
46
  interface QueryState {
40
47
  orderBy?: 'key' | 'priority' | 'child' | 'value';
@@ -85,6 +92,22 @@ declare class DatabaseReference {
85
92
  set(value: unknown): Promise<void>;
86
93
  /**
87
94
  * Update specific children at this location without overwriting other children.
95
+ *
96
+ * Also supports Firebase-style multi-path updates when keys look like paths
97
+ * (start with '/'). In this mode, each path is written atomically as a transaction.
98
+ *
99
+ * @example
100
+ * ```javascript
101
+ * // Normal update (merge at single path)
102
+ * await ref.update({ score: 10, name: 'Riley' });
103
+ *
104
+ * // Multi-path update (atomic writes to multiple paths)
105
+ * await db.ref().update({
106
+ * '/users/alice/score': 100,
107
+ * '/users/bob/score': 200,
108
+ * '/leaderboard/alice': null // null = delete
109
+ * });
110
+ * ```
88
111
  */
89
112
  update(values: Record<string, unknown>): Promise<void>;
90
113
  /**
@@ -109,6 +132,29 @@ declare class DatabaseReference {
109
132
  * Set the priority of the data at this location.
110
133
  */
111
134
  setPriority(priority: number | string): Promise<void>;
135
+ /**
136
+ * Atomically modify the data at this location using optimistic concurrency.
137
+ *
138
+ * The update function receives the current value and should return the new
139
+ * value. If the data changed on the server before the write could be
140
+ * committed, the function is called again with the new value, and the
141
+ * process repeats until successful or the maximum retries are exceeded.
142
+ *
143
+ * @example
144
+ * ```javascript
145
+ * // Increment a counter atomically
146
+ * const result = await ref.transaction(currentValue => {
147
+ * return (currentValue || 0) + 1;
148
+ * });
149
+ * console.log('New value:', result.snapshot.val());
150
+ * ```
151
+ *
152
+ * @param updateFunction - Function that receives current value and returns new value.
153
+ * Return undefined to abort the transaction.
154
+ * @param maxRetries - Maximum number of retries (default: 25)
155
+ * @returns TransactionResult with committed status and final snapshot
156
+ */
157
+ transaction(updateFunction: (currentValue: unknown) => unknown, maxRetries?: number): Promise<TransactionResult>;
112
158
  /**
113
159
  * Read the data at this location once.
114
160
  */
@@ -138,12 +184,10 @@ declare class DatabaseReference {
138
184
  orderByPriority(): DatabaseReference;
139
185
  /**
140
186
  * Order results by a child key.
141
- * NOTE: Phase 2 - not yet implemented on server.
142
187
  */
143
188
  orderByChild(path: string): DatabaseReference;
144
189
  /**
145
190
  * Order results by value.
146
- * NOTE: Phase 2 - not yet implemented on server.
147
191
  */
148
192
  orderByValue(): DatabaseReference;
149
193
  /**
@@ -156,17 +200,14 @@ declare class DatabaseReference {
156
200
  limitToLast(limit: number): DatabaseReference;
157
201
  /**
158
202
  * Start at a specific value/key.
159
- * NOTE: Phase 2 - not yet implemented on server.
160
203
  */
161
204
  startAt(value: unknown, key?: string): DatabaseReference;
162
205
  /**
163
206
  * End at a specific value/key.
164
- * NOTE: Phase 2 - not yet implemented on server.
165
207
  */
166
208
  endAt(value: unknown, key?: string): DatabaseReference;
167
209
  /**
168
210
  * Filter to items equal to a specific value.
169
- * NOTE: Phase 2 - not yet implemented on server.
170
211
  */
171
212
  equalTo(value: unknown, key?: string): DatabaseReference;
172
213
  /**
@@ -191,9 +232,11 @@ declare class DataSnapshot {
191
232
  private readonly _db;
192
233
  private readonly _volatile;
193
234
  private readonly _priority;
235
+ private readonly _serverTimestamp;
194
236
  constructor(data: unknown, path: string, db: LarkDatabase, options?: {
195
237
  volatile?: boolean;
196
238
  priority?: number | string | null;
239
+ serverTimestamp?: number | null;
197
240
  });
198
241
  /**
199
242
  * Get a DatabaseReference for the location of this snapshot.
@@ -240,6 +283,13 @@ declare class DataSnapshot {
240
283
  * This is a Lark extension not present in Firebase.
241
284
  */
242
285
  isVolatile(): boolean;
286
+ /**
287
+ * Get the server timestamp for this snapshot (milliseconds since Unix epoch).
288
+ * Only present on volatile value events. Use deltas between timestamps for
289
+ * interpolation rather than absolute times to avoid clock sync issues.
290
+ * This is a Lark extension not present in Firebase.
291
+ */
292
+ getServerTimestamp(): number | null;
243
293
  /**
244
294
  * Export the snapshot data as JSON (alias for val()).
245
295
  */
@@ -247,16 +297,50 @@ declare class DataSnapshot {
247
297
  }
248
298
 
249
299
  interface QueryParams {
250
- ob?: 'k' | 'p';
251
- lf?: number;
252
- ll?: number;
300
+ orderBy?: 'key' | 'priority' | 'child' | 'value';
301
+ orderByChild?: string;
302
+ limitToFirst?: number;
303
+ limitToLast?: number;
304
+ startAt?: unknown;
305
+ startAtKey?: string;
306
+ endAt?: unknown;
307
+ endAtKey?: string;
308
+ equalTo?: unknown;
309
+ equalToKey?: string;
310
+ }
311
+ interface TxSetOp {
312
+ o: 's';
313
+ p: string;
314
+ v: unknown;
315
+ }
316
+ interface TxUpdateOp {
317
+ o: 'u';
318
+ p: string;
319
+ v: Record<string, unknown>;
320
+ }
321
+ interface TxDeleteOp {
322
+ o: 'd';
323
+ p: string;
324
+ }
325
+ interface TxConditionOp {
326
+ o: 'c';
327
+ p: string;
328
+ v: unknown;
329
+ }
330
+ type TxOperation = TxSetOp | TxUpdateOp | TxDeleteOp | TxConditionOp;
331
+ interface MoveEntry {
332
+ k: string;
333
+ ak: string;
253
334
  }
254
335
 
255
336
  /**
256
337
  * SubscriptionManager - tracks active subscriptions and routes events to callbacks.
257
338
  *
258
- * Also manages a local data cache that is populated by subscription events.
259
- * The cache only contains "live" data from active subscriptions.
339
+ * Handles the new delta-based protocol where server sends 'put' and 'patch' events.
340
+ * Client generates child_added, child_changed, child_removed, child_moved events locally.
341
+ *
342
+ * Supports ordered queries: tracks child order from server's `k` (orderedKeys) and `ak` (afterKey)
343
+ * fields, and fires child_moved when positions change via `mv` (moves) array.
260
344
  */
261
345
 
262
346
  type SnapshotCallback = (snapshot: DataSnapshot, previousChildKey?: string | null) => void;
@@ -278,6 +362,33 @@ interface AuthInfo {
278
362
  provider: string;
279
363
  token: Record<string, unknown>;
280
364
  }
365
+ /** A set operation in a transaction */
366
+ interface TransactionSetOp {
367
+ op: 'set';
368
+ path: string;
369
+ value: unknown;
370
+ }
371
+ /** An update (merge) operation in a transaction */
372
+ interface TransactionUpdateOp {
373
+ op: 'update';
374
+ path: string;
375
+ value: Record<string, unknown>;
376
+ }
377
+ /** A delete operation in a transaction */
378
+ interface TransactionDeleteOp {
379
+ op: 'delete';
380
+ path: string;
381
+ }
382
+ /** A condition check in a transaction (for compare-and-swap) */
383
+ interface TransactionConditionOp {
384
+ op: 'condition';
385
+ path: string;
386
+ value: unknown;
387
+ }
388
+ /** A single operation in a transaction (array syntax) */
389
+ type TransactionOp = TransactionSetOp | TransactionUpdateOp | TransactionDeleteOp | TransactionConditionOp;
390
+ /** Object syntax for transactions: path -> value (null = delete) */
391
+ type TransactionObject = Record<string, unknown>;
281
392
  declare class LarkDatabase {
282
393
  private _state;
283
394
  private _auth;
@@ -287,6 +398,7 @@ declare class LarkDatabase {
287
398
  private ws;
288
399
  private messageQueue;
289
400
  private subscriptionManager;
401
+ private pendingWrites;
290
402
  private connectCallbacks;
291
403
  private disconnectCallbacks;
292
404
  private errorCallbacks;
@@ -309,6 +421,20 @@ declare class LarkDatabase {
309
421
  * WebSocket always uses reliable transport, but this is stored for future UDP support.
310
422
  */
311
423
  get volatilePaths(): string[];
424
+ /**
425
+ * Check if there are any pending writes waiting for acknowledgment.
426
+ * Useful for showing "saving..." indicators in UI.
427
+ */
428
+ hasPendingWrites(): boolean;
429
+ /**
430
+ * Get the number of pending writes waiting for acknowledgment.
431
+ */
432
+ getPendingWriteCount(): number;
433
+ /**
434
+ * Clear all pending writes.
435
+ * Call this if you don't want to retry writes on reconnect.
436
+ */
437
+ clearPendingWrites(): void;
312
438
  /**
313
439
  * Connect to a database.
314
440
  *
@@ -329,6 +455,48 @@ declare class LarkDatabase {
329
455
  * Get a reference to a path in the database.
330
456
  */
331
457
  ref(path?: string): DatabaseReference;
458
+ /**
459
+ * Execute an atomic transaction with multiple operations.
460
+ *
461
+ * Supports two syntaxes:
462
+ *
463
+ * **Object syntax** (like Firebase multi-path update):
464
+ * ```javascript
465
+ * await db.transaction({
466
+ * '/users/alice/name': 'Alice',
467
+ * '/users/alice/score': 100,
468
+ * '/temp/data': null // null = delete
469
+ * });
470
+ * ```
471
+ *
472
+ * **Array syntax** (explicit operations):
473
+ * ```javascript
474
+ * await db.transaction([
475
+ * { op: 'set', path: '/users/alice/name', value: 'Alice' },
476
+ * { op: 'update', path: '/metadata', value: { lastUpdated: '...' } },
477
+ * { op: 'delete', path: '/temp/data' },
478
+ * { op: 'condition', path: '/counter', value: 5 } // CAS check
479
+ * ]);
480
+ * ```
481
+ *
482
+ * All operations are atomic: either all succeed or all fail.
483
+ * Conditions are checked first; if any fail, the transaction is rejected
484
+ * with error code 'condition_failed'.
485
+ */
486
+ transaction(operations: TransactionOp[] | TransactionObject): Promise<void>;
487
+ /**
488
+ * Convert a public TransactionOp to wire format TxOperation.
489
+ */
490
+ private convertToTxOp;
491
+ /**
492
+ * Convert object syntax to wire format TxOperations.
493
+ * Each path becomes a set operation, null values become deletes.
494
+ */
495
+ private convertObjectToTxOps;
496
+ /**
497
+ * @internal Send a transaction to the server.
498
+ */
499
+ _sendTransaction(ops: TxOperation[]): Promise<void>;
332
500
  /**
333
501
  * Register a callback for when connection is established.
334
502
  * Returns an unsubscribe function.
@@ -396,7 +564,7 @@ declare class LarkDatabase {
396
564
  /**
397
565
  * @internal Subscribe to events at a path.
398
566
  */
399
- _subscribe(path: string, eventType: EventType, callback: SnapshotCallback): () => void;
567
+ _subscribe(path: string, eventType: EventType, callback: SnapshotCallback, queryParams?: QueryParams): () => void;
400
568
  /**
401
569
  * @internal Unsubscribe from a specific event type at a path.
402
570
  */
@@ -415,6 +583,62 @@ declare class LarkError extends Error {
415
583
  constructor(code: string, message?: string);
416
584
  }
417
585
 
586
+ /**
587
+ * PendingWriteManager - tracks pending write operations for optimistic updates.
588
+ *
589
+ * Each write operation is assigned a unique operation ID (oid). The manager tracks
590
+ * pending writes until they are acknowledged by the server. On reconnect, pending
591
+ * writes can be retried to ensure data consistency.
592
+ */
593
+ type WriteOperation = 'set' | 'update' | 'delete' | 'push' | 'transaction';
594
+ interface PendingWrite {
595
+ oid: string;
596
+ operation: WriteOperation;
597
+ path: string;
598
+ value?: unknown;
599
+ timestamp: number;
600
+ }
601
+ declare class PendingWriteManager {
602
+ private pending;
603
+ /**
604
+ * Track a new pending write operation.
605
+ * Uses the request ID as the tracking key.
606
+ */
607
+ trackWrite(requestId: string, operation: WriteOperation, path: string, value?: unknown): void;
608
+ /**
609
+ * Called when a write is acknowledged by the server.
610
+ * Removes the write from pending tracking.
611
+ */
612
+ onAck(oid: string): boolean;
613
+ /**
614
+ * Called when a write is rejected by the server.
615
+ * Removes the write from pending tracking.
616
+ */
617
+ onNack(oid: string): boolean;
618
+ /**
619
+ * Get all pending writes for retry on reconnect.
620
+ * Returns writes in order of their timestamps (oldest first).
621
+ */
622
+ getPendingWrites(): PendingWrite[];
623
+ /**
624
+ * Check if a specific operation is still pending.
625
+ */
626
+ isPending(oid: string): boolean;
627
+ /**
628
+ * Get the number of pending writes.
629
+ */
630
+ get pendingCount(): number;
631
+ /**
632
+ * Clear all pending writes (e.g., on disconnect when not retrying).
633
+ */
634
+ clear(): void;
635
+ /**
636
+ * Remove writes older than a specified age (in milliseconds).
637
+ * Useful for cleaning up stale pending writes that may never be acked.
638
+ */
639
+ removeStale(maxAgeMs: number): number;
640
+ }
641
+
418
642
  /**
419
643
  * Push ID generation - Firebase-compatible chronologically-sortable IDs.
420
644
  *
@@ -451,4 +675,4 @@ declare function generatePushId(): string;
451
675
  */
452
676
  declare function isVolatilePath(path: string, patterns: string[] | null | undefined): boolean;
453
677
 
454
- export { type AuthInfo, type ConnectOptions, DataSnapshot, DatabaseReference, type EventType, LarkDatabase, LarkError, OnDisconnect, type QueryState, type SnapshotCallback$1 as SnapshotCallback, generatePushId, isVolatilePath };
678
+ export { type AuthInfo, type ConnectOptions, DataSnapshot, DatabaseReference, type EventType, LarkDatabase, LarkError, type MoveEntry, OnDisconnect, type PendingWrite, PendingWriteManager, type QueryParams, type QueryState, type SnapshotCallback$1 as SnapshotCallback, type TransactionConditionOp, type TransactionDeleteOp, type TransactionObject, type TransactionOp, type TransactionResult, type TransactionSetOp, type TransactionUpdateOp, type WriteOperation, generatePushId, isVolatilePath };