@lark-sh/client 0.1.2 → 0.1.4
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 +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +353 -62
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +351 -61
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -78,10 +78,10 @@ var LarkError = class _LarkError extends Error {
|
|
|
78
78
|
|
|
79
79
|
// src/protocol/messages.ts
|
|
80
80
|
function isAckMessage(msg) {
|
|
81
|
-
return "a" in msg
|
|
81
|
+
return "a" in msg;
|
|
82
82
|
}
|
|
83
|
-
function
|
|
84
|
-
return "
|
|
83
|
+
function isJoinCompleteMessage(msg) {
|
|
84
|
+
return "jc" in msg;
|
|
85
85
|
}
|
|
86
86
|
function isNackMessage(msg) {
|
|
87
87
|
return "n" in msg;
|
|
@@ -137,16 +137,12 @@ var MessageQueue = class {
|
|
|
137
137
|
* @returns true if the message was handled (was a response), false otherwise
|
|
138
138
|
*/
|
|
139
139
|
handleMessage(message) {
|
|
140
|
-
if (
|
|
141
|
-
const pending = this.pending.get(message.
|
|
140
|
+
if (isJoinCompleteMessage(message)) {
|
|
141
|
+
const pending = this.pending.get(message.jc);
|
|
142
142
|
if (pending) {
|
|
143
143
|
clearTimeout(pending.timeout);
|
|
144
|
-
this.pending.delete(message.
|
|
145
|
-
pending.resolve(
|
|
146
|
-
uid: message.uid,
|
|
147
|
-
provider: message.provider,
|
|
148
|
-
token: message.token
|
|
149
|
-
});
|
|
144
|
+
this.pending.delete(message.jc);
|
|
145
|
+
pending.resolve(message.vp || []);
|
|
150
146
|
return true;
|
|
151
147
|
}
|
|
152
148
|
}
|
|
@@ -206,6 +202,234 @@ var MessageQueue = class {
|
|
|
206
202
|
}
|
|
207
203
|
};
|
|
208
204
|
|
|
205
|
+
// src/utils/path.ts
|
|
206
|
+
function normalizePath(path) {
|
|
207
|
+
if (!path || path === "/") return "/";
|
|
208
|
+
const segments = path.split("/").filter((segment) => segment.length > 0);
|
|
209
|
+
if (segments.length === 0) return "/";
|
|
210
|
+
return "/" + segments.join("/");
|
|
211
|
+
}
|
|
212
|
+
function joinPath(...segments) {
|
|
213
|
+
const allParts = [];
|
|
214
|
+
for (const segment of segments) {
|
|
215
|
+
if (!segment || segment === "/") continue;
|
|
216
|
+
const parts = segment.split("/").filter((p) => p.length > 0);
|
|
217
|
+
allParts.push(...parts);
|
|
218
|
+
}
|
|
219
|
+
if (allParts.length === 0) return "/";
|
|
220
|
+
return "/" + allParts.join("/");
|
|
221
|
+
}
|
|
222
|
+
function getParentPath(path) {
|
|
223
|
+
const normalized = normalizePath(path);
|
|
224
|
+
if (normalized === "/") return "/";
|
|
225
|
+
const lastSlash = normalized.lastIndexOf("/");
|
|
226
|
+
if (lastSlash <= 0) return "/";
|
|
227
|
+
return normalized.substring(0, lastSlash);
|
|
228
|
+
}
|
|
229
|
+
function getKey(path) {
|
|
230
|
+
const normalized = normalizePath(path);
|
|
231
|
+
if (normalized === "/") return null;
|
|
232
|
+
const lastSlash = normalized.lastIndexOf("/");
|
|
233
|
+
return normalized.substring(lastSlash + 1);
|
|
234
|
+
}
|
|
235
|
+
function getValueAtPath(obj, path) {
|
|
236
|
+
const normalized = normalizePath(path);
|
|
237
|
+
if (normalized === "/") return obj;
|
|
238
|
+
const segments = normalized.split("/").filter((s) => s.length > 0);
|
|
239
|
+
let current = obj;
|
|
240
|
+
for (const segment of segments) {
|
|
241
|
+
if (current === null || current === void 0) {
|
|
242
|
+
return void 0;
|
|
243
|
+
}
|
|
244
|
+
if (typeof current !== "object") {
|
|
245
|
+
return void 0;
|
|
246
|
+
}
|
|
247
|
+
current = current[segment];
|
|
248
|
+
}
|
|
249
|
+
return current;
|
|
250
|
+
}
|
|
251
|
+
function setValueAtPath(obj, path, value) {
|
|
252
|
+
const normalized = normalizePath(path);
|
|
253
|
+
if (normalized === "/") {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const segments = normalized.split("/").filter((s) => s.length > 0);
|
|
257
|
+
let current = obj;
|
|
258
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
259
|
+
const segment = segments[i];
|
|
260
|
+
if (!(segment in current) || typeof current[segment] !== "object" || current[segment] === null) {
|
|
261
|
+
current[segment] = {};
|
|
262
|
+
}
|
|
263
|
+
current = current[segment];
|
|
264
|
+
}
|
|
265
|
+
const lastSegment = segments[segments.length - 1];
|
|
266
|
+
current[lastSegment] = value;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// src/cache/DataCache.ts
|
|
270
|
+
var DataCache = class {
|
|
271
|
+
constructor() {
|
|
272
|
+
// path -> cached value
|
|
273
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Store a value at a path.
|
|
277
|
+
* Called when we receive data from a subscription event.
|
|
278
|
+
*/
|
|
279
|
+
set(path, value) {
|
|
280
|
+
const normalized = normalizePath(path);
|
|
281
|
+
this.cache.set(normalized, value);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Get the cached value at a path.
|
|
285
|
+
* Returns undefined if not in cache.
|
|
286
|
+
*
|
|
287
|
+
* This method handles nested lookups:
|
|
288
|
+
* - If /boxes is cached with {0: true, 1: false}
|
|
289
|
+
* - get('/boxes/0') returns true (extracted from parent)
|
|
290
|
+
*/
|
|
291
|
+
get(path) {
|
|
292
|
+
const normalized = normalizePath(path);
|
|
293
|
+
if (this.cache.has(normalized)) {
|
|
294
|
+
return { value: this.cache.get(normalized), found: true };
|
|
295
|
+
}
|
|
296
|
+
const ancestorResult = this.getFromAncestor(normalized);
|
|
297
|
+
if (ancestorResult.found) {
|
|
298
|
+
return ancestorResult;
|
|
299
|
+
}
|
|
300
|
+
return { value: void 0, found: false };
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Check if we have cached data that covers the given path.
|
|
304
|
+
* This includes exact matches and ancestor paths.
|
|
305
|
+
*/
|
|
306
|
+
has(path) {
|
|
307
|
+
return this.get(path).found;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Try to get data from an ancestor path.
|
|
311
|
+
* E.g., if /boxes is cached and we want /boxes/5, extract it.
|
|
312
|
+
*/
|
|
313
|
+
getFromAncestor(path) {
|
|
314
|
+
const segments = path.split("/").filter((s) => s.length > 0);
|
|
315
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
316
|
+
const ancestorPath = i === 0 ? "/" : "/" + segments.slice(0, i).join("/");
|
|
317
|
+
if (this.cache.has(ancestorPath)) {
|
|
318
|
+
const ancestorValue = this.cache.get(ancestorPath);
|
|
319
|
+
const relativePath = "/" + segments.slice(i).join("/");
|
|
320
|
+
const extractedValue = getValueAtPath(ancestorValue, relativePath);
|
|
321
|
+
return { value: extractedValue, found: true };
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (this.cache.has("/")) {
|
|
325
|
+
const rootValue = this.cache.get("/");
|
|
326
|
+
const extractedValue = getValueAtPath(rootValue, path);
|
|
327
|
+
return { value: extractedValue, found: true };
|
|
328
|
+
}
|
|
329
|
+
return { value: void 0, found: false };
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Remove cached data at a path.
|
|
333
|
+
* Called when unsubscribing from a path that's no longer covered.
|
|
334
|
+
*/
|
|
335
|
+
delete(path) {
|
|
336
|
+
const normalized = normalizePath(path);
|
|
337
|
+
this.cache.delete(normalized);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Remove cached data at a path and all descendant paths.
|
|
341
|
+
* Called when a subscription is removed and no other subscription covers it.
|
|
342
|
+
*/
|
|
343
|
+
deleteTree(path) {
|
|
344
|
+
const normalized = normalizePath(path);
|
|
345
|
+
this.cache.delete(normalized);
|
|
346
|
+
const prefix = normalized === "/" ? "/" : normalized + "/";
|
|
347
|
+
for (const cachedPath of this.cache.keys()) {
|
|
348
|
+
if (cachedPath.startsWith(prefix) || normalized === "/" && cachedPath !== "/") {
|
|
349
|
+
this.cache.delete(cachedPath);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Update cache when a child value changes.
|
|
355
|
+
* This updates both the child path and any cached ancestor that contains it.
|
|
356
|
+
*
|
|
357
|
+
* E.g., if /boxes is cached and /boxes/5 changes:
|
|
358
|
+
* - Update the /boxes cache to reflect the new /boxes/5 value
|
|
359
|
+
*/
|
|
360
|
+
updateChild(path, value) {
|
|
361
|
+
const normalized = normalizePath(path);
|
|
362
|
+
this.cache.set(normalized, value);
|
|
363
|
+
const segments = normalized.split("/").filter((s) => s.length > 0);
|
|
364
|
+
for (let i = segments.length - 1; i >= 1; i--) {
|
|
365
|
+
const ancestorPath = "/" + segments.slice(0, i).join("/");
|
|
366
|
+
if (this.cache.has(ancestorPath)) {
|
|
367
|
+
const ancestorValue = this.cache.get(ancestorPath);
|
|
368
|
+
if (ancestorValue !== null && typeof ancestorValue === "object") {
|
|
369
|
+
const childKey = segments[i];
|
|
370
|
+
const remainingPath = "/" + segments.slice(i).join("/");
|
|
371
|
+
const updatedAncestor = this.deepClone(ancestorValue);
|
|
372
|
+
setValueAtPath(updatedAncestor, remainingPath, value);
|
|
373
|
+
this.cache.set(ancestorPath, updatedAncestor);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (this.cache.has("/") && normalized !== "/") {
|
|
378
|
+
const rootValue = this.cache.get("/");
|
|
379
|
+
if (rootValue !== null && typeof rootValue === "object") {
|
|
380
|
+
const updatedRoot = this.deepClone(rootValue);
|
|
381
|
+
setValueAtPath(updatedRoot, normalized, value);
|
|
382
|
+
this.cache.set("/", updatedRoot);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Remove a child from the cache (e.g., on child_removed event).
|
|
388
|
+
*/
|
|
389
|
+
removeChild(path) {
|
|
390
|
+
const normalized = normalizePath(path);
|
|
391
|
+
this.deleteTree(normalized);
|
|
392
|
+
const segments = normalized.split("/").filter((s) => s.length > 0);
|
|
393
|
+
for (let i = segments.length - 1; i >= 1; i--) {
|
|
394
|
+
const ancestorPath = "/" + segments.slice(0, i).join("/");
|
|
395
|
+
if (this.cache.has(ancestorPath)) {
|
|
396
|
+
const ancestorValue = this.cache.get(ancestorPath);
|
|
397
|
+
if (ancestorValue !== null && typeof ancestorValue === "object") {
|
|
398
|
+
const updatedAncestor = this.deepClone(ancestorValue);
|
|
399
|
+
const parentPath = "/" + segments.slice(i, -1).join("/");
|
|
400
|
+
const childKey = segments[segments.length - 1];
|
|
401
|
+
const parent = parentPath === "/" ? updatedAncestor : getValueAtPath(updatedAncestor, parentPath);
|
|
402
|
+
if (parent && typeof parent === "object") {
|
|
403
|
+
delete parent[childKey];
|
|
404
|
+
}
|
|
405
|
+
this.cache.set(ancestorPath, updatedAncestor);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Clear all cached data.
|
|
412
|
+
*/
|
|
413
|
+
clear() {
|
|
414
|
+
this.cache.clear();
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Get the number of cached paths (for testing/debugging).
|
|
418
|
+
*/
|
|
419
|
+
get size() {
|
|
420
|
+
return this.cache.size;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Deep clone a value to avoid mutation issues.
|
|
424
|
+
*/
|
|
425
|
+
deepClone(value) {
|
|
426
|
+
if (value === null || typeof value !== "object") {
|
|
427
|
+
return value;
|
|
428
|
+
}
|
|
429
|
+
return JSON.parse(JSON.stringify(value));
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
|
|
209
433
|
// src/connection/SubscriptionManager.ts
|
|
210
434
|
var SubscriptionManager = class {
|
|
211
435
|
constructor() {
|
|
@@ -217,6 +441,7 @@ var SubscriptionManager = class {
|
|
|
217
441
|
this.sendUnsubscribe = null;
|
|
218
442
|
// Callback to create DataSnapshot from event data
|
|
219
443
|
this.createSnapshot = null;
|
|
444
|
+
this.cache = new DataCache();
|
|
220
445
|
}
|
|
221
446
|
/**
|
|
222
447
|
* Initialize the manager with server communication callbacks.
|
|
@@ -329,6 +554,15 @@ var SubscriptionManager = class {
|
|
|
329
554
|
if (eventType === "value") {
|
|
330
555
|
snapshotPath = path;
|
|
331
556
|
snapshotValue = message.v;
|
|
557
|
+
this.cache.set(path, snapshotValue);
|
|
558
|
+
} else if (eventType === "child_added" || eventType === "child_changed") {
|
|
559
|
+
snapshotPath = path === "/" ? `/${message.k}` : `${path}/${message.k}`;
|
|
560
|
+
snapshotValue = message.v;
|
|
561
|
+
this.cache.updateChild(snapshotPath, snapshotValue);
|
|
562
|
+
} else if (eventType === "child_removed") {
|
|
563
|
+
snapshotPath = path === "/" ? `/${message.k}` : `${path}/${message.k}`;
|
|
564
|
+
snapshotValue = message.v;
|
|
565
|
+
this.cache.removeChild(snapshotPath);
|
|
332
566
|
} else {
|
|
333
567
|
snapshotPath = path === "/" ? `/${message.k}` : `${path}/${message.k}`;
|
|
334
568
|
snapshotValue = message.v;
|
|
@@ -356,6 +590,7 @@ var SubscriptionManager = class {
|
|
|
356
590
|
*/
|
|
357
591
|
clear() {
|
|
358
592
|
this.subscriptions.clear();
|
|
593
|
+
this.cache.clear();
|
|
359
594
|
}
|
|
360
595
|
/**
|
|
361
596
|
* Check if there are any subscriptions at a path.
|
|
@@ -363,6 +598,65 @@ var SubscriptionManager = class {
|
|
|
363
598
|
hasSubscriptions(path) {
|
|
364
599
|
return this.subscriptions.has(path);
|
|
365
600
|
}
|
|
601
|
+
/**
|
|
602
|
+
* Check if a path is "covered" by an active subscription.
|
|
603
|
+
*
|
|
604
|
+
* A path is covered if:
|
|
605
|
+
* - There's an active 'value' subscription at that exact path, OR
|
|
606
|
+
* - There's an active 'value' subscription at an ancestor path
|
|
607
|
+
*
|
|
608
|
+
* Child event subscriptions (child_added, etc.) don't provide full coverage
|
|
609
|
+
* because they only notify of changes, not the complete value.
|
|
610
|
+
*/
|
|
611
|
+
isPathCovered(path) {
|
|
612
|
+
const normalized = normalizePath(path);
|
|
613
|
+
if (this.hasValueSubscription(normalized)) {
|
|
614
|
+
return true;
|
|
615
|
+
}
|
|
616
|
+
const segments = normalized.split("/").filter((s) => s.length > 0);
|
|
617
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
618
|
+
const ancestorPath = i === 0 ? "/" : "/" + segments.slice(0, i).join("/");
|
|
619
|
+
if (this.hasValueSubscription(ancestorPath)) {
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if (normalized !== "/" && this.hasValueSubscription("/")) {
|
|
624
|
+
return true;
|
|
625
|
+
}
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Check if there's a 'value' subscription at a path.
|
|
630
|
+
*/
|
|
631
|
+
hasValueSubscription(path) {
|
|
632
|
+
const pathSubs = this.subscriptions.get(path);
|
|
633
|
+
if (!pathSubs) return false;
|
|
634
|
+
const valueSubs = pathSubs.get("value");
|
|
635
|
+
return valueSubs !== void 0 && valueSubs.length > 0;
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Get a cached value if the path is covered by an active subscription.
|
|
639
|
+
*
|
|
640
|
+
* Returns { value, found: true } if we have cached data for this path
|
|
641
|
+
* (either exact match or extractable from a cached ancestor).
|
|
642
|
+
*
|
|
643
|
+
* Returns { value: undefined, found: false } if:
|
|
644
|
+
* - The path is not covered by any subscription, OR
|
|
645
|
+
* - We don't have cached data yet
|
|
646
|
+
*/
|
|
647
|
+
getCachedValue(path) {
|
|
648
|
+
const normalized = normalizePath(path);
|
|
649
|
+
if (!this.isPathCovered(normalized)) {
|
|
650
|
+
return { value: void 0, found: false };
|
|
651
|
+
}
|
|
652
|
+
return this.cache.get(normalized);
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Get the cache size (for testing/debugging).
|
|
656
|
+
*/
|
|
657
|
+
get cacheSize() {
|
|
658
|
+
return this.cache.size;
|
|
659
|
+
}
|
|
366
660
|
};
|
|
367
661
|
|
|
368
662
|
// src/connection/WebSocketClient.ts
|
|
@@ -503,53 +797,6 @@ var OnDisconnect = class {
|
|
|
503
797
|
}
|
|
504
798
|
};
|
|
505
799
|
|
|
506
|
-
// src/utils/path.ts
|
|
507
|
-
function normalizePath(path) {
|
|
508
|
-
if (!path || path === "/") return "/";
|
|
509
|
-
const segments = path.split("/").filter((segment) => segment.length > 0);
|
|
510
|
-
if (segments.length === 0) return "/";
|
|
511
|
-
return "/" + segments.join("/");
|
|
512
|
-
}
|
|
513
|
-
function joinPath(...segments) {
|
|
514
|
-
const allParts = [];
|
|
515
|
-
for (const segment of segments) {
|
|
516
|
-
if (!segment || segment === "/") continue;
|
|
517
|
-
const parts = segment.split("/").filter((p) => p.length > 0);
|
|
518
|
-
allParts.push(...parts);
|
|
519
|
-
}
|
|
520
|
-
if (allParts.length === 0) return "/";
|
|
521
|
-
return "/" + allParts.join("/");
|
|
522
|
-
}
|
|
523
|
-
function getParentPath(path) {
|
|
524
|
-
const normalized = normalizePath(path);
|
|
525
|
-
if (normalized === "/") return "/";
|
|
526
|
-
const lastSlash = normalized.lastIndexOf("/");
|
|
527
|
-
if (lastSlash <= 0) return "/";
|
|
528
|
-
return normalized.substring(0, lastSlash);
|
|
529
|
-
}
|
|
530
|
-
function getKey(path) {
|
|
531
|
-
const normalized = normalizePath(path);
|
|
532
|
-
if (normalized === "/") return null;
|
|
533
|
-
const lastSlash = normalized.lastIndexOf("/");
|
|
534
|
-
return normalized.substring(lastSlash + 1);
|
|
535
|
-
}
|
|
536
|
-
function getValueAtPath(obj, path) {
|
|
537
|
-
const normalized = normalizePath(path);
|
|
538
|
-
if (normalized === "/") return obj;
|
|
539
|
-
const segments = normalized.split("/").filter((s) => s.length > 0);
|
|
540
|
-
let current = obj;
|
|
541
|
-
for (const segment of segments) {
|
|
542
|
-
if (current === null || current === void 0) {
|
|
543
|
-
return void 0;
|
|
544
|
-
}
|
|
545
|
-
if (typeof current !== "object") {
|
|
546
|
-
return void 0;
|
|
547
|
-
}
|
|
548
|
-
current = current[segment];
|
|
549
|
-
}
|
|
550
|
-
return current;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
800
|
// src/utils/pushid.ts
|
|
554
801
|
var PUSH_CHARS = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
|
|
555
802
|
var lastPushTime = 0;
|
|
@@ -987,6 +1234,7 @@ var LarkDatabase = class {
|
|
|
987
1234
|
this._auth = null;
|
|
988
1235
|
this._databaseId = null;
|
|
989
1236
|
this._coordinatorUrl = null;
|
|
1237
|
+
this._volatilePaths = [];
|
|
990
1238
|
this.ws = null;
|
|
991
1239
|
// Event callbacks
|
|
992
1240
|
this.connectCallbacks = /* @__PURE__ */ new Set();
|
|
@@ -1019,6 +1267,14 @@ var LarkDatabase = class {
|
|
|
1019
1267
|
}
|
|
1020
1268
|
return "lark://";
|
|
1021
1269
|
}
|
|
1270
|
+
/**
|
|
1271
|
+
* Get the volatile path patterns from the server.
|
|
1272
|
+
* These patterns indicate which paths should use unreliable transport.
|
|
1273
|
+
* WebSocket always uses reliable transport, but this is stored for future UDP support.
|
|
1274
|
+
*/
|
|
1275
|
+
get volatilePaths() {
|
|
1276
|
+
return this._volatilePaths;
|
|
1277
|
+
}
|
|
1022
1278
|
// ============================================
|
|
1023
1279
|
// Connection Management
|
|
1024
1280
|
// ============================================
|
|
@@ -1059,7 +1315,8 @@ var LarkDatabase = class {
|
|
|
1059
1315
|
r: requestId
|
|
1060
1316
|
};
|
|
1061
1317
|
this.send(joinMessage);
|
|
1062
|
-
await this.messageQueue.registerRequest(requestId);
|
|
1318
|
+
const volatilePaths = await this.messageQueue.registerRequest(requestId);
|
|
1319
|
+
this._volatilePaths = volatilePaths || [];
|
|
1063
1320
|
const jwtPayload = decodeJwtPayload(connectResponse.token);
|
|
1064
1321
|
this._auth = {
|
|
1065
1322
|
uid: jwtPayload.sub,
|
|
@@ -1112,6 +1369,7 @@ var LarkDatabase = class {
|
|
|
1112
1369
|
this._state = "disconnected";
|
|
1113
1370
|
this._auth = null;
|
|
1114
1371
|
this._databaseId = null;
|
|
1372
|
+
this._volatilePaths = [];
|
|
1115
1373
|
this._coordinatorUrl = null;
|
|
1116
1374
|
this.subscriptionManager.clear();
|
|
1117
1375
|
this.messageQueue.rejectAll(new Error("Connection closed"));
|
|
@@ -1255,12 +1513,28 @@ var LarkDatabase = class {
|
|
|
1255
1513
|
}
|
|
1256
1514
|
/**
|
|
1257
1515
|
* @internal Send a once (read) operation.
|
|
1516
|
+
*
|
|
1517
|
+
* This method first checks if the data is available in the local cache
|
|
1518
|
+
* (from an active subscription). If so, it returns the cached value
|
|
1519
|
+
* immediately without a server round-trip.
|
|
1520
|
+
*
|
|
1521
|
+
* Cache is only used when:
|
|
1522
|
+
* - No query parameters are specified (queries may filter/order differently)
|
|
1523
|
+
* - The path is covered by an active 'value' subscription
|
|
1524
|
+
* - We have cached data available
|
|
1258
1525
|
*/
|
|
1259
1526
|
async _sendOnce(path, query) {
|
|
1527
|
+
const normalizedPath = normalizePath(path) || "/";
|
|
1528
|
+
if (!query) {
|
|
1529
|
+
const cached = this.subscriptionManager.getCachedValue(normalizedPath);
|
|
1530
|
+
if (cached.found) {
|
|
1531
|
+
return new DataSnapshot(cached.value, path, this);
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1260
1534
|
const requestId = this.messageQueue.nextRequestId();
|
|
1261
1535
|
const message = {
|
|
1262
1536
|
o: "o",
|
|
1263
|
-
p:
|
|
1537
|
+
p: normalizedPath,
|
|
1264
1538
|
r: requestId
|
|
1265
1539
|
};
|
|
1266
1540
|
if (query) {
|
|
@@ -1345,12 +1619,28 @@ var LarkDatabase = class {
|
|
|
1345
1619
|
this.subscriptionManager.unsubscribeAll(path);
|
|
1346
1620
|
}
|
|
1347
1621
|
};
|
|
1622
|
+
|
|
1623
|
+
// src/utils/volatile.ts
|
|
1624
|
+
function isVolatilePath(path, patterns) {
|
|
1625
|
+
if (!patterns || patterns.length === 0) {
|
|
1626
|
+
return false;
|
|
1627
|
+
}
|
|
1628
|
+
const segments = path.replace(/^\//, "").split("/");
|
|
1629
|
+
return patterns.some((pattern) => {
|
|
1630
|
+
const patternSegments = pattern.split("/");
|
|
1631
|
+
if (segments.length !== patternSegments.length) {
|
|
1632
|
+
return false;
|
|
1633
|
+
}
|
|
1634
|
+
return patternSegments.every((p, i) => p === "*" || p === segments[i]);
|
|
1635
|
+
});
|
|
1636
|
+
}
|
|
1348
1637
|
export {
|
|
1349
1638
|
DataSnapshot,
|
|
1350
1639
|
DatabaseReference,
|
|
1351
1640
|
LarkDatabase,
|
|
1352
1641
|
LarkError,
|
|
1353
1642
|
OnDisconnect,
|
|
1354
|
-
generatePushId
|
|
1643
|
+
generatePushId,
|
|
1644
|
+
isVolatilePath
|
|
1355
1645
|
};
|
|
1356
1646
|
//# sourceMappingURL=index.mjs.map
|