@lark-sh/client 0.1.1 → 0.1.3
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 +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +316 -49
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +316 -49
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -254,6 +254,9 @@ interface QueryParams {
|
|
|
254
254
|
|
|
255
255
|
/**
|
|
256
256
|
* SubscriptionManager - tracks active subscriptions and routes events to callbacks.
|
|
257
|
+
*
|
|
258
|
+
* Also manages a local data cache that is populated by subscription events.
|
|
259
|
+
* The cache only contains "live" data from active subscriptions.
|
|
257
260
|
*/
|
|
258
261
|
|
|
259
262
|
type SnapshotCallback = (snapshot: DataSnapshot, previousChildKey?: string | null) => void;
|
|
@@ -356,6 +359,15 @@ declare class LarkDatabase {
|
|
|
356
359
|
_sendPush(path: string, value: unknown): Promise<string>;
|
|
357
360
|
/**
|
|
358
361
|
* @internal Send a once (read) operation.
|
|
362
|
+
*
|
|
363
|
+
* This method first checks if the data is available in the local cache
|
|
364
|
+
* (from an active subscription). If so, it returns the cached value
|
|
365
|
+
* immediately without a server round-trip.
|
|
366
|
+
*
|
|
367
|
+
* Cache is only used when:
|
|
368
|
+
* - No query parameters are specified (queries may filter/order differently)
|
|
369
|
+
* - The path is covered by an active 'value' subscription
|
|
370
|
+
* - We have cached data available
|
|
359
371
|
*/
|
|
360
372
|
_sendOnce(path: string, query?: QueryParams): Promise<DataSnapshot>;
|
|
361
373
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -254,6 +254,9 @@ interface QueryParams {
|
|
|
254
254
|
|
|
255
255
|
/**
|
|
256
256
|
* SubscriptionManager - tracks active subscriptions and routes events to callbacks.
|
|
257
|
+
*
|
|
258
|
+
* Also manages a local data cache that is populated by subscription events.
|
|
259
|
+
* The cache only contains "live" data from active subscriptions.
|
|
257
260
|
*/
|
|
258
261
|
|
|
259
262
|
type SnapshotCallback = (snapshot: DataSnapshot, previousChildKey?: string | null) => void;
|
|
@@ -356,6 +359,15 @@ declare class LarkDatabase {
|
|
|
356
359
|
_sendPush(path: string, value: unknown): Promise<string>;
|
|
357
360
|
/**
|
|
358
361
|
* @internal Send a once (read) operation.
|
|
362
|
+
*
|
|
363
|
+
* This method first checks if the data is available in the local cache
|
|
364
|
+
* (from an active subscription). If so, it returns the cached value
|
|
365
|
+
* immediately without a server round-trip.
|
|
366
|
+
*
|
|
367
|
+
* Cache is only used when:
|
|
368
|
+
* - No query parameters are specified (queries may filter/order differently)
|
|
369
|
+
* - The path is covered by an active 'value' subscription
|
|
370
|
+
* - We have cached data available
|
|
359
371
|
*/
|
|
360
372
|
_sendOnce(path: string, query?: QueryParams): Promise<DataSnapshot>;
|
|
361
373
|
/**
|
package/dist/index.js
CHANGED
|
@@ -58,7 +58,7 @@ var eventTypeToShort = {
|
|
|
58
58
|
child_changed: "cc",
|
|
59
59
|
child_removed: "cr"
|
|
60
60
|
};
|
|
61
|
-
var DEFAULT_COORDINATOR_URL = "https://db.lark.
|
|
61
|
+
var DEFAULT_COORDINATOR_URL = "https://db.lark.sh";
|
|
62
62
|
|
|
63
63
|
// src/connection/Coordinator.ts
|
|
64
64
|
var Coordinator = class {
|
|
@@ -247,6 +247,234 @@ var MessageQueue = class {
|
|
|
247
247
|
}
|
|
248
248
|
};
|
|
249
249
|
|
|
250
|
+
// src/utils/path.ts
|
|
251
|
+
function normalizePath(path) {
|
|
252
|
+
if (!path || path === "/") return "/";
|
|
253
|
+
const segments = path.split("/").filter((segment) => segment.length > 0);
|
|
254
|
+
if (segments.length === 0) return "/";
|
|
255
|
+
return "/" + segments.join("/");
|
|
256
|
+
}
|
|
257
|
+
function joinPath(...segments) {
|
|
258
|
+
const allParts = [];
|
|
259
|
+
for (const segment of segments) {
|
|
260
|
+
if (!segment || segment === "/") continue;
|
|
261
|
+
const parts = segment.split("/").filter((p) => p.length > 0);
|
|
262
|
+
allParts.push(...parts);
|
|
263
|
+
}
|
|
264
|
+
if (allParts.length === 0) return "/";
|
|
265
|
+
return "/" + allParts.join("/");
|
|
266
|
+
}
|
|
267
|
+
function getParentPath(path) {
|
|
268
|
+
const normalized = normalizePath(path);
|
|
269
|
+
if (normalized === "/") return "/";
|
|
270
|
+
const lastSlash = normalized.lastIndexOf("/");
|
|
271
|
+
if (lastSlash <= 0) return "/";
|
|
272
|
+
return normalized.substring(0, lastSlash);
|
|
273
|
+
}
|
|
274
|
+
function getKey(path) {
|
|
275
|
+
const normalized = normalizePath(path);
|
|
276
|
+
if (normalized === "/") return null;
|
|
277
|
+
const lastSlash = normalized.lastIndexOf("/");
|
|
278
|
+
return normalized.substring(lastSlash + 1);
|
|
279
|
+
}
|
|
280
|
+
function getValueAtPath(obj, path) {
|
|
281
|
+
const normalized = normalizePath(path);
|
|
282
|
+
if (normalized === "/") return obj;
|
|
283
|
+
const segments = normalized.split("/").filter((s) => s.length > 0);
|
|
284
|
+
let current = obj;
|
|
285
|
+
for (const segment of segments) {
|
|
286
|
+
if (current === null || current === void 0) {
|
|
287
|
+
return void 0;
|
|
288
|
+
}
|
|
289
|
+
if (typeof current !== "object") {
|
|
290
|
+
return void 0;
|
|
291
|
+
}
|
|
292
|
+
current = current[segment];
|
|
293
|
+
}
|
|
294
|
+
return current;
|
|
295
|
+
}
|
|
296
|
+
function setValueAtPath(obj, path, value) {
|
|
297
|
+
const normalized = normalizePath(path);
|
|
298
|
+
if (normalized === "/") {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const segments = normalized.split("/").filter((s) => s.length > 0);
|
|
302
|
+
let current = obj;
|
|
303
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
304
|
+
const segment = segments[i];
|
|
305
|
+
if (!(segment in current) || typeof current[segment] !== "object" || current[segment] === null) {
|
|
306
|
+
current[segment] = {};
|
|
307
|
+
}
|
|
308
|
+
current = current[segment];
|
|
309
|
+
}
|
|
310
|
+
const lastSegment = segments[segments.length - 1];
|
|
311
|
+
current[lastSegment] = value;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/cache/DataCache.ts
|
|
315
|
+
var DataCache = class {
|
|
316
|
+
constructor() {
|
|
317
|
+
// path -> cached value
|
|
318
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Store a value at a path.
|
|
322
|
+
* Called when we receive data from a subscription event.
|
|
323
|
+
*/
|
|
324
|
+
set(path, value) {
|
|
325
|
+
const normalized = normalizePath(path);
|
|
326
|
+
this.cache.set(normalized, value);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Get the cached value at a path.
|
|
330
|
+
* Returns undefined if not in cache.
|
|
331
|
+
*
|
|
332
|
+
* This method handles nested lookups:
|
|
333
|
+
* - If /boxes is cached with {0: true, 1: false}
|
|
334
|
+
* - get('/boxes/0') returns true (extracted from parent)
|
|
335
|
+
*/
|
|
336
|
+
get(path) {
|
|
337
|
+
const normalized = normalizePath(path);
|
|
338
|
+
if (this.cache.has(normalized)) {
|
|
339
|
+
return { value: this.cache.get(normalized), found: true };
|
|
340
|
+
}
|
|
341
|
+
const ancestorResult = this.getFromAncestor(normalized);
|
|
342
|
+
if (ancestorResult.found) {
|
|
343
|
+
return ancestorResult;
|
|
344
|
+
}
|
|
345
|
+
return { value: void 0, found: false };
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Check if we have cached data that covers the given path.
|
|
349
|
+
* This includes exact matches and ancestor paths.
|
|
350
|
+
*/
|
|
351
|
+
has(path) {
|
|
352
|
+
return this.get(path).found;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Try to get data from an ancestor path.
|
|
356
|
+
* E.g., if /boxes is cached and we want /boxes/5, extract it.
|
|
357
|
+
*/
|
|
358
|
+
getFromAncestor(path) {
|
|
359
|
+
const segments = path.split("/").filter((s) => s.length > 0);
|
|
360
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
361
|
+
const ancestorPath = i === 0 ? "/" : "/" + segments.slice(0, i).join("/");
|
|
362
|
+
if (this.cache.has(ancestorPath)) {
|
|
363
|
+
const ancestorValue = this.cache.get(ancestorPath);
|
|
364
|
+
const relativePath = "/" + segments.slice(i).join("/");
|
|
365
|
+
const extractedValue = getValueAtPath(ancestorValue, relativePath);
|
|
366
|
+
return { value: extractedValue, found: true };
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (this.cache.has("/")) {
|
|
370
|
+
const rootValue = this.cache.get("/");
|
|
371
|
+
const extractedValue = getValueAtPath(rootValue, path);
|
|
372
|
+
return { value: extractedValue, found: true };
|
|
373
|
+
}
|
|
374
|
+
return { value: void 0, found: false };
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Remove cached data at a path.
|
|
378
|
+
* Called when unsubscribing from a path that's no longer covered.
|
|
379
|
+
*/
|
|
380
|
+
delete(path) {
|
|
381
|
+
const normalized = normalizePath(path);
|
|
382
|
+
this.cache.delete(normalized);
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Remove cached data at a path and all descendant paths.
|
|
386
|
+
* Called when a subscription is removed and no other subscription covers it.
|
|
387
|
+
*/
|
|
388
|
+
deleteTree(path) {
|
|
389
|
+
const normalized = normalizePath(path);
|
|
390
|
+
this.cache.delete(normalized);
|
|
391
|
+
const prefix = normalized === "/" ? "/" : normalized + "/";
|
|
392
|
+
for (const cachedPath of this.cache.keys()) {
|
|
393
|
+
if (cachedPath.startsWith(prefix) || normalized === "/" && cachedPath !== "/") {
|
|
394
|
+
this.cache.delete(cachedPath);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Update cache when a child value changes.
|
|
400
|
+
* This updates both the child path and any cached ancestor that contains it.
|
|
401
|
+
*
|
|
402
|
+
* E.g., if /boxes is cached and /boxes/5 changes:
|
|
403
|
+
* - Update the /boxes cache to reflect the new /boxes/5 value
|
|
404
|
+
*/
|
|
405
|
+
updateChild(path, value) {
|
|
406
|
+
const normalized = normalizePath(path);
|
|
407
|
+
this.cache.set(normalized, value);
|
|
408
|
+
const segments = normalized.split("/").filter((s) => s.length > 0);
|
|
409
|
+
for (let i = segments.length - 1; i >= 1; i--) {
|
|
410
|
+
const ancestorPath = "/" + segments.slice(0, i).join("/");
|
|
411
|
+
if (this.cache.has(ancestorPath)) {
|
|
412
|
+
const ancestorValue = this.cache.get(ancestorPath);
|
|
413
|
+
if (ancestorValue !== null && typeof ancestorValue === "object") {
|
|
414
|
+
const childKey = segments[i];
|
|
415
|
+
const remainingPath = "/" + segments.slice(i).join("/");
|
|
416
|
+
const updatedAncestor = this.deepClone(ancestorValue);
|
|
417
|
+
setValueAtPath(updatedAncestor, remainingPath, value);
|
|
418
|
+
this.cache.set(ancestorPath, updatedAncestor);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
if (this.cache.has("/") && normalized !== "/") {
|
|
423
|
+
const rootValue = this.cache.get("/");
|
|
424
|
+
if (rootValue !== null && typeof rootValue === "object") {
|
|
425
|
+
const updatedRoot = this.deepClone(rootValue);
|
|
426
|
+
setValueAtPath(updatedRoot, normalized, value);
|
|
427
|
+
this.cache.set("/", updatedRoot);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Remove a child from the cache (e.g., on child_removed event).
|
|
433
|
+
*/
|
|
434
|
+
removeChild(path) {
|
|
435
|
+
const normalized = normalizePath(path);
|
|
436
|
+
this.deleteTree(normalized);
|
|
437
|
+
const segments = normalized.split("/").filter((s) => s.length > 0);
|
|
438
|
+
for (let i = segments.length - 1; i >= 1; i--) {
|
|
439
|
+
const ancestorPath = "/" + segments.slice(0, i).join("/");
|
|
440
|
+
if (this.cache.has(ancestorPath)) {
|
|
441
|
+
const ancestorValue = this.cache.get(ancestorPath);
|
|
442
|
+
if (ancestorValue !== null && typeof ancestorValue === "object") {
|
|
443
|
+
const updatedAncestor = this.deepClone(ancestorValue);
|
|
444
|
+
const parentPath = "/" + segments.slice(i, -1).join("/");
|
|
445
|
+
const childKey = segments[segments.length - 1];
|
|
446
|
+
const parent = parentPath === "/" ? updatedAncestor : getValueAtPath(updatedAncestor, parentPath);
|
|
447
|
+
if (parent && typeof parent === "object") {
|
|
448
|
+
delete parent[childKey];
|
|
449
|
+
}
|
|
450
|
+
this.cache.set(ancestorPath, updatedAncestor);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Clear all cached data.
|
|
457
|
+
*/
|
|
458
|
+
clear() {
|
|
459
|
+
this.cache.clear();
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Get the number of cached paths (for testing/debugging).
|
|
463
|
+
*/
|
|
464
|
+
get size() {
|
|
465
|
+
return this.cache.size;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Deep clone a value to avoid mutation issues.
|
|
469
|
+
*/
|
|
470
|
+
deepClone(value) {
|
|
471
|
+
if (value === null || typeof value !== "object") {
|
|
472
|
+
return value;
|
|
473
|
+
}
|
|
474
|
+
return JSON.parse(JSON.stringify(value));
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
|
|
250
478
|
// src/connection/SubscriptionManager.ts
|
|
251
479
|
var SubscriptionManager = class {
|
|
252
480
|
constructor() {
|
|
@@ -258,6 +486,7 @@ var SubscriptionManager = class {
|
|
|
258
486
|
this.sendUnsubscribe = null;
|
|
259
487
|
// Callback to create DataSnapshot from event data
|
|
260
488
|
this.createSnapshot = null;
|
|
489
|
+
this.cache = new DataCache();
|
|
261
490
|
}
|
|
262
491
|
/**
|
|
263
492
|
* Initialize the manager with server communication callbacks.
|
|
@@ -370,6 +599,15 @@ var SubscriptionManager = class {
|
|
|
370
599
|
if (eventType === "value") {
|
|
371
600
|
snapshotPath = path;
|
|
372
601
|
snapshotValue = message.v;
|
|
602
|
+
this.cache.set(path, snapshotValue);
|
|
603
|
+
} else if (eventType === "child_added" || eventType === "child_changed") {
|
|
604
|
+
snapshotPath = path === "/" ? `/${message.k}` : `${path}/${message.k}`;
|
|
605
|
+
snapshotValue = message.v;
|
|
606
|
+
this.cache.updateChild(snapshotPath, snapshotValue);
|
|
607
|
+
} else if (eventType === "child_removed") {
|
|
608
|
+
snapshotPath = path === "/" ? `/${message.k}` : `${path}/${message.k}`;
|
|
609
|
+
snapshotValue = message.v;
|
|
610
|
+
this.cache.removeChild(snapshotPath);
|
|
373
611
|
} else {
|
|
374
612
|
snapshotPath = path === "/" ? `/${message.k}` : `${path}/${message.k}`;
|
|
375
613
|
snapshotValue = message.v;
|
|
@@ -397,6 +635,7 @@ var SubscriptionManager = class {
|
|
|
397
635
|
*/
|
|
398
636
|
clear() {
|
|
399
637
|
this.subscriptions.clear();
|
|
638
|
+
this.cache.clear();
|
|
400
639
|
}
|
|
401
640
|
/**
|
|
402
641
|
* Check if there are any subscriptions at a path.
|
|
@@ -404,6 +643,65 @@ var SubscriptionManager = class {
|
|
|
404
643
|
hasSubscriptions(path) {
|
|
405
644
|
return this.subscriptions.has(path);
|
|
406
645
|
}
|
|
646
|
+
/**
|
|
647
|
+
* Check if a path is "covered" by an active subscription.
|
|
648
|
+
*
|
|
649
|
+
* A path is covered if:
|
|
650
|
+
* - There's an active 'value' subscription at that exact path, OR
|
|
651
|
+
* - There's an active 'value' subscription at an ancestor path
|
|
652
|
+
*
|
|
653
|
+
* Child event subscriptions (child_added, etc.) don't provide full coverage
|
|
654
|
+
* because they only notify of changes, not the complete value.
|
|
655
|
+
*/
|
|
656
|
+
isPathCovered(path) {
|
|
657
|
+
const normalized = normalizePath(path);
|
|
658
|
+
if (this.hasValueSubscription(normalized)) {
|
|
659
|
+
return true;
|
|
660
|
+
}
|
|
661
|
+
const segments = normalized.split("/").filter((s) => s.length > 0);
|
|
662
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
663
|
+
const ancestorPath = i === 0 ? "/" : "/" + segments.slice(0, i).join("/");
|
|
664
|
+
if (this.hasValueSubscription(ancestorPath)) {
|
|
665
|
+
return true;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
if (normalized !== "/" && this.hasValueSubscription("/")) {
|
|
669
|
+
return true;
|
|
670
|
+
}
|
|
671
|
+
return false;
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Check if there's a 'value' subscription at a path.
|
|
675
|
+
*/
|
|
676
|
+
hasValueSubscription(path) {
|
|
677
|
+
const pathSubs = this.subscriptions.get(path);
|
|
678
|
+
if (!pathSubs) return false;
|
|
679
|
+
const valueSubs = pathSubs.get("value");
|
|
680
|
+
return valueSubs !== void 0 && valueSubs.length > 0;
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Get a cached value if the path is covered by an active subscription.
|
|
684
|
+
*
|
|
685
|
+
* Returns { value, found: true } if we have cached data for this path
|
|
686
|
+
* (either exact match or extractable from a cached ancestor).
|
|
687
|
+
*
|
|
688
|
+
* Returns { value: undefined, found: false } if:
|
|
689
|
+
* - The path is not covered by any subscription, OR
|
|
690
|
+
* - We don't have cached data yet
|
|
691
|
+
*/
|
|
692
|
+
getCachedValue(path) {
|
|
693
|
+
const normalized = normalizePath(path);
|
|
694
|
+
if (!this.isPathCovered(normalized)) {
|
|
695
|
+
return { value: void 0, found: false };
|
|
696
|
+
}
|
|
697
|
+
return this.cache.get(normalized);
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Get the cache size (for testing/debugging).
|
|
701
|
+
*/
|
|
702
|
+
get cacheSize() {
|
|
703
|
+
return this.cache.size;
|
|
704
|
+
}
|
|
407
705
|
};
|
|
408
706
|
|
|
409
707
|
// src/connection/WebSocketClient.ts
|
|
@@ -544,53 +842,6 @@ var OnDisconnect = class {
|
|
|
544
842
|
}
|
|
545
843
|
};
|
|
546
844
|
|
|
547
|
-
// src/utils/path.ts
|
|
548
|
-
function normalizePath(path) {
|
|
549
|
-
if (!path || path === "/") return "/";
|
|
550
|
-
const segments = path.split("/").filter((segment) => segment.length > 0);
|
|
551
|
-
if (segments.length === 0) return "/";
|
|
552
|
-
return "/" + segments.join("/");
|
|
553
|
-
}
|
|
554
|
-
function joinPath(...segments) {
|
|
555
|
-
const allParts = [];
|
|
556
|
-
for (const segment of segments) {
|
|
557
|
-
if (!segment || segment === "/") continue;
|
|
558
|
-
const parts = segment.split("/").filter((p) => p.length > 0);
|
|
559
|
-
allParts.push(...parts);
|
|
560
|
-
}
|
|
561
|
-
if (allParts.length === 0) return "/";
|
|
562
|
-
return "/" + allParts.join("/");
|
|
563
|
-
}
|
|
564
|
-
function getParentPath(path) {
|
|
565
|
-
const normalized = normalizePath(path);
|
|
566
|
-
if (normalized === "/") return "/";
|
|
567
|
-
const lastSlash = normalized.lastIndexOf("/");
|
|
568
|
-
if (lastSlash <= 0) return "/";
|
|
569
|
-
return normalized.substring(0, lastSlash);
|
|
570
|
-
}
|
|
571
|
-
function getKey(path) {
|
|
572
|
-
const normalized = normalizePath(path);
|
|
573
|
-
if (normalized === "/") return null;
|
|
574
|
-
const lastSlash = normalized.lastIndexOf("/");
|
|
575
|
-
return normalized.substring(lastSlash + 1);
|
|
576
|
-
}
|
|
577
|
-
function getValueAtPath(obj, path) {
|
|
578
|
-
const normalized = normalizePath(path);
|
|
579
|
-
if (normalized === "/") return obj;
|
|
580
|
-
const segments = normalized.split("/").filter((s) => s.length > 0);
|
|
581
|
-
let current = obj;
|
|
582
|
-
for (const segment of segments) {
|
|
583
|
-
if (current === null || current === void 0) {
|
|
584
|
-
return void 0;
|
|
585
|
-
}
|
|
586
|
-
if (typeof current !== "object") {
|
|
587
|
-
return void 0;
|
|
588
|
-
}
|
|
589
|
-
current = current[segment];
|
|
590
|
-
}
|
|
591
|
-
return current;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
845
|
// src/utils/pushid.ts
|
|
595
846
|
var PUSH_CHARS = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
|
|
596
847
|
var lastPushTime = 0;
|
|
@@ -1296,12 +1547,28 @@ var LarkDatabase = class {
|
|
|
1296
1547
|
}
|
|
1297
1548
|
/**
|
|
1298
1549
|
* @internal Send a once (read) operation.
|
|
1550
|
+
*
|
|
1551
|
+
* This method first checks if the data is available in the local cache
|
|
1552
|
+
* (from an active subscription). If so, it returns the cached value
|
|
1553
|
+
* immediately without a server round-trip.
|
|
1554
|
+
*
|
|
1555
|
+
* Cache is only used when:
|
|
1556
|
+
* - No query parameters are specified (queries may filter/order differently)
|
|
1557
|
+
* - The path is covered by an active 'value' subscription
|
|
1558
|
+
* - We have cached data available
|
|
1299
1559
|
*/
|
|
1300
1560
|
async _sendOnce(path, query) {
|
|
1561
|
+
const normalizedPath = normalizePath(path) || "/";
|
|
1562
|
+
if (!query) {
|
|
1563
|
+
const cached = this.subscriptionManager.getCachedValue(normalizedPath);
|
|
1564
|
+
if (cached.found) {
|
|
1565
|
+
return new DataSnapshot(cached.value, path, this);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1301
1568
|
const requestId = this.messageQueue.nextRequestId();
|
|
1302
1569
|
const message = {
|
|
1303
1570
|
o: "o",
|
|
1304
|
-
p:
|
|
1571
|
+
p: normalizedPath,
|
|
1305
1572
|
r: requestId
|
|
1306
1573
|
};
|
|
1307
1574
|
if (query) {
|