@rpcbase/client 0.455.0 → 0.456.0
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 +2 -2
- package/dist/rts/index.d.ts +1 -1
- package/dist/rts/index.d.ts.map +1 -1
- package/dist/rts/index.js +10 -2
- package/dist/rts/index.js.map +1 -1
- package/dist/rts/pouchStore.d.ts +35 -0
- package/dist/rts/pouchStore.d.ts.map +1 -1
- package/dist/rts/queryKey.d.ts.map +1 -1
- package/dist/rts/queryWindow.d.ts +2 -0
- package/dist/rts/queryWindow.d.ts.map +1 -0
- package/dist/rts/useCountQuery.d.ts.map +1 -1
- package/dist/rts/useQuery.d.ts.map +1 -1
- package/dist/rts/wsClient.d.ts +15 -0
- package/dist/rts/wsClient.d.ts.map +1 -1
- package/dist/{useQuery-BOjtIBwv.js → useQuery-DZqYIJog.js} +840 -238
- package/dist/useQuery-DZqYIJog.js.map +1 -0
- package/package.json +1 -1
- package/dist/useQuery-BOjtIBwv.js.map +0 -1
|
@@ -152,6 +152,7 @@ const RtsSsrRuntimeProvider = (t0) => {
|
|
|
152
152
|
const useRtsSsrRuntime = () => {
|
|
153
153
|
return useContext(RtsSsrRuntimeContext);
|
|
154
154
|
};
|
|
155
|
+
const RTS_QUERY_WINDOW_MAX_COUNT = 4096;
|
|
155
156
|
const memoryStore = /* @__PURE__ */ new Map();
|
|
156
157
|
let reactNativeStorage = null;
|
|
157
158
|
const MMKV_STORAGE_ID = "rpcbase-rts";
|
|
@@ -239,6 +240,11 @@ const UNDERSCORE_PREFIX = "$_";
|
|
|
239
240
|
const DEFAULT_FIND_LIMIT = 4096;
|
|
240
241
|
const INDEXED_DB_ADAPTER = "indexeddb";
|
|
241
242
|
const REACT_NATIVE_SQLITE_ADAPTER = "react-native-sqlite";
|
|
243
|
+
const QUERY_WINDOW_COLLECTION = "$query-windows-v1";
|
|
244
|
+
const QUERY_WINDOW_DOC_TYPE = "rts-query-window";
|
|
245
|
+
const QUERY_WINDOW_SCHEMA_VERSION = 1;
|
|
246
|
+
const QUERY_WINDOW_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
247
|
+
const QUERY_WINDOW_WRITE_ATTEMPTS = 4;
|
|
242
248
|
let storeConfig = null;
|
|
243
249
|
let pouchDbPromise = null;
|
|
244
250
|
let lastAppliedPrefix = null;
|
|
@@ -374,8 +380,7 @@ const getPouchDb = async () => {
|
|
|
374
380
|
}
|
|
375
381
|
return pouchDbPromise;
|
|
376
382
|
};
|
|
377
|
-
const applyPrefix = (PouchDB) => {
|
|
378
|
-
const prefix = getPrefix();
|
|
383
|
+
const applyPrefix = (PouchDB, prefix = getPrefix()) => {
|
|
379
384
|
if (prefix === lastAppliedPrefix) return;
|
|
380
385
|
PouchDB.prefix = prefix;
|
|
381
386
|
lastAppliedPrefix = prefix;
|
|
@@ -386,9 +391,9 @@ const configureRtsPouchStore = (config) => {
|
|
|
386
391
|
collections.clear();
|
|
387
392
|
};
|
|
388
393
|
const getCollection = async (modelName, options) => {
|
|
389
|
-
const PouchDB = await getPouchDb();
|
|
390
|
-
applyPrefix(PouchDB);
|
|
391
394
|
const prefix = getPrefix();
|
|
395
|
+
const PouchDB = await getPouchDb();
|
|
396
|
+
applyPrefix(PouchDB, prefix);
|
|
392
397
|
const dbName = `${options.uid}/${modelName}`;
|
|
393
398
|
const dbKey = `${prefix}${dbName}`;
|
|
394
399
|
const existing = collections.get(dbKey);
|
|
@@ -401,6 +406,284 @@ const getCollection = async (modelName, options) => {
|
|
|
401
406
|
collections.set(dbKey, db);
|
|
402
407
|
return db;
|
|
403
408
|
};
|
|
409
|
+
const getQueryWindowScope = (uid) => {
|
|
410
|
+
if (!storeConfig) {
|
|
411
|
+
throw new Error("RTS PouchDB store is not configured");
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
appName: storeConfig.appName ?? "",
|
|
415
|
+
tenantId: storeConfig.tenantId,
|
|
416
|
+
uid
|
|
417
|
+
};
|
|
418
|
+
};
|
|
419
|
+
const getQueryWindowFingerprint = (scope, modelName, queryKey) => JSON.stringify([QUERY_WINDOW_SCHEMA_VERSION, scope.appName, scope.tenantId, scope.uid, modelName, queryKey]);
|
|
420
|
+
const getQueryWindowDocumentId = (fingerprint) => `${QUERY_WINDOW_DOC_TYPE}:${encodeURIComponent(fingerprint)}`;
|
|
421
|
+
const getPouchErrorStatus = (error) => {
|
|
422
|
+
if (!error || typeof error !== "object") return void 0;
|
|
423
|
+
const status = error.status;
|
|
424
|
+
return typeof status === "number" && Number.isFinite(status) ? status : void 0;
|
|
425
|
+
};
|
|
426
|
+
const getPouchDocument = async (collection, id) => {
|
|
427
|
+
try {
|
|
428
|
+
return await collection.get(id);
|
|
429
|
+
} catch (error) {
|
|
430
|
+
if (getPouchErrorStatus(error) === 404) return null;
|
|
431
|
+
throw error;
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
const normalizeQueryWindowPageInfo = (value) => {
|
|
435
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
436
|
+
const raw = value;
|
|
437
|
+
if (typeof raw.hasNextPage !== "boolean" || typeof raw.hasPrevPage !== "boolean") return null;
|
|
438
|
+
if (raw.nextCursor !== void 0 && typeof raw.nextCursor !== "string") return null;
|
|
439
|
+
if (raw.prevCursor !== void 0 && typeof raw.prevCursor !== "string") return null;
|
|
440
|
+
const nextCursor = typeof raw.nextCursor === "string" && raw.nextCursor ? raw.nextCursor : void 0;
|
|
441
|
+
const prevCursor = typeof raw.prevCursor === "string" && raw.prevCursor ? raw.prevCursor : void 0;
|
|
442
|
+
return {
|
|
443
|
+
hasNextPage: raw.hasNextPage,
|
|
444
|
+
hasPrevPage: raw.hasPrevPage,
|
|
445
|
+
...nextCursor ? {
|
|
446
|
+
nextCursor
|
|
447
|
+
} : {},
|
|
448
|
+
...prevCursor ? {
|
|
449
|
+
prevCursor
|
|
450
|
+
} : {}
|
|
451
|
+
};
|
|
452
|
+
};
|
|
453
|
+
const isValidQueryWindowServerVersion = (value) => {
|
|
454
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
455
|
+
};
|
|
456
|
+
const isQueryWindowData = (value) => Array.isArray(value) && value.every((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
|
|
457
|
+
const parseQueryWindowSnapshot = (doc, expected) => {
|
|
458
|
+
if (doc.type !== QUERY_WINDOW_DOC_TYPE || doc.schemaVersion !== QUERY_WINDOW_SCHEMA_VERSION) return null;
|
|
459
|
+
if (doc.fingerprint !== expected.fingerprint) return null;
|
|
460
|
+
if (doc.modelName !== expected.modelName || doc.queryKey !== expected.queryKey) return null;
|
|
461
|
+
const scope = doc.scope;
|
|
462
|
+
if (!scope || typeof scope !== "object" || Array.isArray(scope)) return null;
|
|
463
|
+
const rawScope = scope;
|
|
464
|
+
if (rawScope.appName !== expected.scope.appName || rawScope.tenantId !== expected.scope.tenantId || rawScope.uid !== expected.scope.uid) {
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
if (!isQueryWindowData(doc.data)) return null;
|
|
468
|
+
const pageInfo = normalizeQueryWindowPageInfo(doc.pageInfo);
|
|
469
|
+
if (!pageInfo) return null;
|
|
470
|
+
const requestedCount = doc.requestedCount;
|
|
471
|
+
if (!Number.isSafeInteger(requestedCount) || requestedCount <= 0 || requestedCount > RTS_QUERY_WINDOW_MAX_COUNT || doc.data.length > requestedCount) {
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
const storedAt = doc.storedAt;
|
|
475
|
+
if (typeof storedAt !== "number" || !Number.isFinite(storedAt) || storedAt < 0) return null;
|
|
476
|
+
const totalCount = doc.totalCount;
|
|
477
|
+
if (totalCount !== void 0 && (!Number.isSafeInteger(totalCount) || totalCount < 0)) {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
const serverVersion = doc.serverVersion;
|
|
481
|
+
if (serverVersion !== void 0 && !isValidQueryWindowServerVersion(serverVersion)) return null;
|
|
482
|
+
const serverEpoch = doc.serverEpoch;
|
|
483
|
+
if (serverEpoch !== void 0 && (typeof serverEpoch !== "string" || !serverEpoch)) return null;
|
|
484
|
+
if (serverEpoch === void 0 !== (serverVersion === void 0)) return null;
|
|
485
|
+
return {
|
|
486
|
+
data: doc.data,
|
|
487
|
+
pageInfo,
|
|
488
|
+
...typeof totalCount === "number" ? {
|
|
489
|
+
totalCount
|
|
490
|
+
} : {},
|
|
491
|
+
requestedCount,
|
|
492
|
+
...serverEpoch !== void 0 ? {
|
|
493
|
+
serverEpoch
|
|
494
|
+
} : {},
|
|
495
|
+
...serverVersion !== void 0 ? {
|
|
496
|
+
serverVersion
|
|
497
|
+
} : {},
|
|
498
|
+
storedAt
|
|
499
|
+
};
|
|
500
|
+
};
|
|
501
|
+
const deleteQueryWindowDocument = async (collection, doc) => {
|
|
502
|
+
const id = typeof doc._id === "string" ? doc._id : "";
|
|
503
|
+
const rev = typeof doc._rev === "string" ? doc._rev : "";
|
|
504
|
+
if (!id || !rev) return;
|
|
505
|
+
await collection.put({
|
|
506
|
+
_id: id,
|
|
507
|
+
_rev: rev,
|
|
508
|
+
_deleted: true
|
|
509
|
+
}).catch(() => void 0);
|
|
510
|
+
};
|
|
511
|
+
const readQueryWindowSnapshot = async ({
|
|
512
|
+
modelName,
|
|
513
|
+
queryKey,
|
|
514
|
+
uid,
|
|
515
|
+
now = Date.now()
|
|
516
|
+
}) => {
|
|
517
|
+
const scope = getQueryWindowScope(uid);
|
|
518
|
+
const fingerprint = getQueryWindowFingerprint(scope, modelName, queryKey);
|
|
519
|
+
const id = getQueryWindowDocumentId(fingerprint);
|
|
520
|
+
const collection = await getCollection(QUERY_WINDOW_COLLECTION, {
|
|
521
|
+
uid
|
|
522
|
+
});
|
|
523
|
+
const doc = await getPouchDocument(collection, id);
|
|
524
|
+
if (!doc) return {
|
|
525
|
+
hit: false
|
|
526
|
+
};
|
|
527
|
+
const snapshot = parseQueryWindowSnapshot(doc, {
|
|
528
|
+
fingerprint,
|
|
529
|
+
scope,
|
|
530
|
+
modelName,
|
|
531
|
+
queryKey
|
|
532
|
+
});
|
|
533
|
+
if (!snapshot || now - snapshot.storedAt >= QUERY_WINDOW_TTL_MS) {
|
|
534
|
+
await deleteQueryWindowDocument(collection, doc);
|
|
535
|
+
return {
|
|
536
|
+
hit: false
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
return {
|
|
540
|
+
hit: true,
|
|
541
|
+
snapshot
|
|
542
|
+
};
|
|
543
|
+
};
|
|
544
|
+
const writeQueryWindowSnapshot = async ({
|
|
545
|
+
modelName,
|
|
546
|
+
queryKey,
|
|
547
|
+
uid,
|
|
548
|
+
data,
|
|
549
|
+
pageInfo: rawPageInfo,
|
|
550
|
+
totalCount,
|
|
551
|
+
requestedCount,
|
|
552
|
+
serverEpoch,
|
|
553
|
+
serverVersion,
|
|
554
|
+
storedAt: rawStoredAt
|
|
555
|
+
}) => {
|
|
556
|
+
if (!modelName.trim()) throw new Error("writeQueryWindowSnapshot: modelName must be a non-empty string");
|
|
557
|
+
if (!queryKey) throw new Error("writeQueryWindowSnapshot: queryKey must be a non-empty string");
|
|
558
|
+
if (!uid.trim()) throw new Error("writeQueryWindowSnapshot: uid must be a non-empty string");
|
|
559
|
+
if (!isQueryWindowData(data)) throw new Error("writeQueryWindowSnapshot: data must contain objects");
|
|
560
|
+
const pageInfo = normalizeQueryWindowPageInfo(rawPageInfo);
|
|
561
|
+
if (!pageInfo) throw new Error("writeQueryWindowSnapshot: invalid pageInfo");
|
|
562
|
+
if (!Number.isSafeInteger(requestedCount) || requestedCount <= 0 || requestedCount > RTS_QUERY_WINDOW_MAX_COUNT || data.length > requestedCount) {
|
|
563
|
+
throw new Error("writeQueryWindowSnapshot: requestedCount must cover data and be between 1 and 4096");
|
|
564
|
+
}
|
|
565
|
+
if (totalCount !== void 0 && (!Number.isSafeInteger(totalCount) || totalCount < 0)) {
|
|
566
|
+
throw new Error("writeQueryWindowSnapshot: totalCount must be a non-negative integer");
|
|
567
|
+
}
|
|
568
|
+
if (serverVersion !== void 0 && !isValidQueryWindowServerVersion(serverVersion)) {
|
|
569
|
+
throw new Error("writeQueryWindowSnapshot: invalid serverVersion");
|
|
570
|
+
}
|
|
571
|
+
if (serverEpoch !== void 0 && (typeof serverEpoch !== "string" || !serverEpoch)) {
|
|
572
|
+
throw new Error("writeQueryWindowSnapshot: invalid serverEpoch");
|
|
573
|
+
}
|
|
574
|
+
if (serverEpoch === void 0 !== (serverVersion === void 0)) {
|
|
575
|
+
throw new Error("writeQueryWindowSnapshot: serverEpoch and serverVersion must be provided together");
|
|
576
|
+
}
|
|
577
|
+
const storedAt = rawStoredAt ?? Date.now();
|
|
578
|
+
if (!Number.isFinite(storedAt) || storedAt < 0) {
|
|
579
|
+
throw new Error("writeQueryWindowSnapshot: storedAt must be a non-negative finite number");
|
|
580
|
+
}
|
|
581
|
+
const scope = getQueryWindowScope(uid);
|
|
582
|
+
const fingerprint = getQueryWindowFingerprint(scope, modelName, queryKey);
|
|
583
|
+
const id = getQueryWindowDocumentId(fingerprint);
|
|
584
|
+
const collection = await getCollection(QUERY_WINDOW_COLLECTION, {
|
|
585
|
+
uid
|
|
586
|
+
});
|
|
587
|
+
const snapshot = {
|
|
588
|
+
data,
|
|
589
|
+
pageInfo,
|
|
590
|
+
...totalCount !== void 0 ? {
|
|
591
|
+
totalCount
|
|
592
|
+
} : {},
|
|
593
|
+
requestedCount,
|
|
594
|
+
...serverEpoch !== void 0 ? {
|
|
595
|
+
serverEpoch
|
|
596
|
+
} : {},
|
|
597
|
+
...serverVersion !== void 0 ? {
|
|
598
|
+
serverVersion
|
|
599
|
+
} : {},
|
|
600
|
+
storedAt
|
|
601
|
+
};
|
|
602
|
+
let lastConflict;
|
|
603
|
+
for (let attempt = 0; attempt < QUERY_WINDOW_WRITE_ATTEMPTS; attempt += 1) {
|
|
604
|
+
const current = await getPouchDocument(collection, id);
|
|
605
|
+
const currentSnapshot = current ? parseQueryWindowSnapshot(current, {
|
|
606
|
+
fingerprint,
|
|
607
|
+
scope,
|
|
608
|
+
modelName,
|
|
609
|
+
queryKey
|
|
610
|
+
}) : null;
|
|
611
|
+
if (currentSnapshot && (currentSnapshot.serverEpoch === serverEpoch && currentSnapshot.serverVersion !== void 0 && serverVersion !== void 0 && currentSnapshot.serverVersion >= serverVersion || (!serverEpoch || currentSnapshot.serverEpoch !== serverEpoch) && currentSnapshot.storedAt > storedAt)) {
|
|
612
|
+
return currentSnapshot;
|
|
613
|
+
}
|
|
614
|
+
const rev = typeof current?._rev === "string" ? current._rev : void 0;
|
|
615
|
+
const doc = {
|
|
616
|
+
_id: id,
|
|
617
|
+
...rev ? {
|
|
618
|
+
_rev: rev
|
|
619
|
+
} : {},
|
|
620
|
+
type: QUERY_WINDOW_DOC_TYPE,
|
|
621
|
+
schemaVersion: QUERY_WINDOW_SCHEMA_VERSION,
|
|
622
|
+
fingerprint,
|
|
623
|
+
scope,
|
|
624
|
+
modelName,
|
|
625
|
+
queryKey,
|
|
626
|
+
data,
|
|
627
|
+
pageInfo,
|
|
628
|
+
...totalCount !== void 0 ? {
|
|
629
|
+
totalCount
|
|
630
|
+
} : {},
|
|
631
|
+
requestedCount,
|
|
632
|
+
...serverEpoch !== void 0 ? {
|
|
633
|
+
serverEpoch
|
|
634
|
+
} : {},
|
|
635
|
+
...serverVersion !== void 0 ? {
|
|
636
|
+
serverVersion
|
|
637
|
+
} : {},
|
|
638
|
+
storedAt
|
|
639
|
+
};
|
|
640
|
+
try {
|
|
641
|
+
await collection.put(doc);
|
|
642
|
+
return snapshot;
|
|
643
|
+
} catch (error) {
|
|
644
|
+
if (getPouchErrorStatus(error) !== 409) throw error;
|
|
645
|
+
lastConflict = error;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
throw lastConflict ?? new Error("writeQueryWindowSnapshot: failed to persist snapshot");
|
|
649
|
+
};
|
|
650
|
+
const invalidateQueryWindowSnapshots = async ({
|
|
651
|
+
uid,
|
|
652
|
+
modelName
|
|
653
|
+
}) => {
|
|
654
|
+
const collection = await getCollection(QUERY_WINDOW_COLLECTION, {
|
|
655
|
+
uid
|
|
656
|
+
});
|
|
657
|
+
const selector = {
|
|
658
|
+
type: QUERY_WINDOW_DOC_TYPE,
|
|
659
|
+
...modelName ? {
|
|
660
|
+
modelName
|
|
661
|
+
} : {}
|
|
662
|
+
};
|
|
663
|
+
for (let batch = 0; batch < 32; batch += 1) {
|
|
664
|
+
const {
|
|
665
|
+
docs
|
|
666
|
+
} = await collection.find({
|
|
667
|
+
selector,
|
|
668
|
+
fields: ["_id", "_rev"],
|
|
669
|
+
limit: DEFAULT_FIND_LIMIT
|
|
670
|
+
});
|
|
671
|
+
const deletions = docs.map((doc) => ({
|
|
672
|
+
_id: typeof doc._id === "string" ? doc._id : "",
|
|
673
|
+
_rev: typeof doc._rev === "string" ? doc._rev : "",
|
|
674
|
+
_deleted: true
|
|
675
|
+
})).filter((doc) => doc._id && doc._rev);
|
|
676
|
+
if (!deletions.length) return;
|
|
677
|
+
const results = await collection.bulkDocs(deletions);
|
|
678
|
+
const hasConflict = Array.isArray(results) && results.some((result) => {
|
|
679
|
+
if (!result || typeof result !== "object") return false;
|
|
680
|
+
const record = result;
|
|
681
|
+
return record.error === true || record.status === 409;
|
|
682
|
+
});
|
|
683
|
+
if (hasConflict) continue;
|
|
684
|
+
if (docs.length < DEFAULT_FIND_LIMIT) return;
|
|
685
|
+
}
|
|
686
|
+
};
|
|
404
687
|
const replaceQueryKeys = (value, replaceKey) => {
|
|
405
688
|
if (typeof value !== "object" || value === null) {
|
|
406
689
|
return value;
|
|
@@ -1288,13 +1571,16 @@ const serializeRtsQueryValue = (value) => {
|
|
|
1288
1571
|
}) ?? "";
|
|
1289
1572
|
};
|
|
1290
1573
|
const computeRtsQueryKey = (query, options) => {
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1574
|
+
return serializeRtsQueryValue({
|
|
1575
|
+
version: 2,
|
|
1576
|
+
key: options.key ?? null,
|
|
1577
|
+
query,
|
|
1578
|
+
projection: options.projection ?? null,
|
|
1579
|
+
sort: options.sort ?? null,
|
|
1580
|
+
limit: typeof options.limit === "number" ? options.limit : null,
|
|
1581
|
+
populate: options.populate ?? null,
|
|
1582
|
+
pagination: options.pagination ?? null
|
|
1583
|
+
});
|
|
1298
1584
|
};
|
|
1299
1585
|
const hasSnapshotError = (snapshot) => {
|
|
1300
1586
|
return snapshot?.error !== null && snapshot?.error !== void 0;
|
|
@@ -1306,11 +1592,15 @@ const SERVER_RECONNECT_DELAY_MAX_MS = 15e3;
|
|
|
1306
1592
|
const RUN_NETWORK_QUERY_TIMEOUT_ERROR = "runNetworkQuery: request timed out";
|
|
1307
1593
|
const RUN_NETWORK_COUNT_TIMEOUT_ERROR = "runNetworkCount: request timed out";
|
|
1308
1594
|
let socket = null;
|
|
1595
|
+
let socketReadyForMessages = false;
|
|
1309
1596
|
let connectPromise = null;
|
|
1597
|
+
let pendingConnectionAttempt = null;
|
|
1310
1598
|
let explicitDisconnect = false;
|
|
1311
1599
|
let currentTenantId = null;
|
|
1312
1600
|
let currentUid = null;
|
|
1313
1601
|
let connectOptions = {};
|
|
1602
|
+
let connectionGeneration = 0;
|
|
1603
|
+
let connectionEpoch = null;
|
|
1314
1604
|
const localTxnBuf = [];
|
|
1315
1605
|
const queryCallbacks = /* @__PURE__ */ new Map();
|
|
1316
1606
|
const countCallbacks = /* @__PURE__ */ new Map();
|
|
@@ -1318,9 +1608,11 @@ const subscriptions = /* @__PURE__ */ new Map();
|
|
|
1318
1608
|
const countSubscriptions = /* @__PURE__ */ new Map();
|
|
1319
1609
|
const messageCallbacks = /* @__PURE__ */ new Map();
|
|
1320
1610
|
const rtsMessageCallbacks = /* @__PURE__ */ new Map();
|
|
1611
|
+
const pendingWindowRequests = /* @__PURE__ */ new Map();
|
|
1321
1612
|
let reconnectTimer = null;
|
|
1322
1613
|
let reconnectAttempts = 0;
|
|
1323
1614
|
let hasEstablishedConnection = false;
|
|
1615
|
+
let forceInitialQueryOnNextConnection = false;
|
|
1324
1616
|
let pendingServerReconnectJitter = false;
|
|
1325
1617
|
let syncPromise = null;
|
|
1326
1618
|
let syncKey = null;
|
|
@@ -1422,10 +1714,33 @@ const buildSocketUrl = (_tenantId, _uid, options) => {
|
|
|
1422
1714
|
return base.toString();
|
|
1423
1715
|
};
|
|
1424
1716
|
const sendToServer = (message) => {
|
|
1425
|
-
if (!socket) return;
|
|
1717
|
+
if (!socket || !socketReadyForMessages) return;
|
|
1426
1718
|
if (socket.readyState !== WebSocket.OPEN) return;
|
|
1427
1719
|
socket.send(JSON.stringify(message));
|
|
1428
1720
|
};
|
|
1721
|
+
const isSocketReady = () => Boolean(socket && socketReadyForMessages && socket.readyState === WebSocket.OPEN);
|
|
1722
|
+
const normalizeRequestedCount = (value) => {
|
|
1723
|
+
if (!Number.isSafeInteger(value)) return void 0;
|
|
1724
|
+
if (value < 1 || value > RTS_QUERY_WINDOW_MAX_COUNT) return void 0;
|
|
1725
|
+
return value;
|
|
1726
|
+
};
|
|
1727
|
+
const getSubscriptionServerOptions = (subscription) => {
|
|
1728
|
+
if (!subscription.options.pagination || !subscription.requestedCount) {
|
|
1729
|
+
return subscription.options;
|
|
1730
|
+
}
|
|
1731
|
+
const {
|
|
1732
|
+
cursor: _cursor,
|
|
1733
|
+
direction: _direction,
|
|
1734
|
+
...pagination
|
|
1735
|
+
} = subscription.options.pagination;
|
|
1736
|
+
return {
|
|
1737
|
+
...subscription.options,
|
|
1738
|
+
pagination: {
|
|
1739
|
+
...pagination,
|
|
1740
|
+
limit: subscription.requestedCount
|
|
1741
|
+
}
|
|
1742
|
+
};
|
|
1743
|
+
};
|
|
1429
1744
|
const resubscribeAll = ({
|
|
1430
1745
|
forceInitialQuery
|
|
1431
1746
|
}) => {
|
|
@@ -1436,7 +1751,7 @@ const resubscribeAll = ({
|
|
|
1436
1751
|
modelName: sub.modelName,
|
|
1437
1752
|
queryKey: sub.queryKey,
|
|
1438
1753
|
query: sub.query,
|
|
1439
|
-
options: sub
|
|
1754
|
+
options: getSubscriptionServerOptions(sub),
|
|
1440
1755
|
runInitialQuery
|
|
1441
1756
|
});
|
|
1442
1757
|
}
|
|
@@ -1457,6 +1772,12 @@ const clearReconnectTimer = () => {
|
|
|
1457
1772
|
clearRuntimeTimeout(reconnectTimer);
|
|
1458
1773
|
reconnectTimer = null;
|
|
1459
1774
|
};
|
|
1775
|
+
const rejectPendingConnectionAttempt = () => {
|
|
1776
|
+
const attempt = pendingConnectionAttempt;
|
|
1777
|
+
if (!attempt) return;
|
|
1778
|
+
pendingConnectionAttempt = null;
|
|
1779
|
+
attempt.reject(new Error("RTS WebSocket connection attempt superseded"));
|
|
1780
|
+
};
|
|
1460
1781
|
const scheduleReconnect = () => {
|
|
1461
1782
|
clearReconnectTimer();
|
|
1462
1783
|
if (explicitDisconnect) {
|
|
@@ -1509,9 +1830,68 @@ const normalizeTotalCount$1 = (value) => {
|
|
|
1509
1830
|
if (!Number.isFinite(value) || value < 0) return void 0;
|
|
1510
1831
|
return Math.floor(value);
|
|
1511
1832
|
};
|
|
1833
|
+
const normalizeQueryWindow = (value) => {
|
|
1834
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1835
|
+
const raw = value;
|
|
1836
|
+
const requestedCount = normalizeRequestedCount(raw.requestedCount);
|
|
1837
|
+
if (!requestedCount) return void 0;
|
|
1838
|
+
const version = Number.isSafeInteger(raw.version) && raw.version >= 0 ? raw.version : void 0;
|
|
1839
|
+
return {
|
|
1840
|
+
requestedCount,
|
|
1841
|
+
...version !== void 0 ? {
|
|
1842
|
+
version
|
|
1843
|
+
} : {}
|
|
1844
|
+
};
|
|
1845
|
+
};
|
|
1846
|
+
const settlePendingWindowRequests = (cbKey, requestedCount, success) => {
|
|
1847
|
+
const pending = pendingWindowRequests.get(cbKey);
|
|
1848
|
+
if (!pending?.size) return;
|
|
1849
|
+
for (const request of Array.from(pending)) {
|
|
1850
|
+
if (request.requestedCount !== requestedCount) continue;
|
|
1851
|
+
clearRuntimeTimeout(request.timeoutId);
|
|
1852
|
+
pending.delete(request);
|
|
1853
|
+
if (!success) {
|
|
1854
|
+
const subscription = subscriptions.get(cbKey);
|
|
1855
|
+
if (subscription?.requestedCount === request.requestedCount) {
|
|
1856
|
+
const snapshotRequestedCount = subscription.lastSnapshot && !hasSnapshotError(subscription.lastSnapshot) ? subscription.lastSnapshot.context.window?.requestedCount : void 0;
|
|
1857
|
+
const rollbackRequestedCount = snapshotRequestedCount ?? request.previousRequestedCount;
|
|
1858
|
+
subscription.windowIntentVersion += 1;
|
|
1859
|
+
subscription.requestedCount = rollbackRequestedCount;
|
|
1860
|
+
sendToServer({
|
|
1861
|
+
type: "set-query-window",
|
|
1862
|
+
modelName: subscription.modelName,
|
|
1863
|
+
queryKey: subscription.queryKey,
|
|
1864
|
+
requestedCount: rollbackRequestedCount
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
request.resolve(success);
|
|
1869
|
+
}
|
|
1870
|
+
if (!pending.size) pendingWindowRequests.delete(cbKey);
|
|
1871
|
+
};
|
|
1872
|
+
const failPendingWindowRequests = (cbKey) => {
|
|
1873
|
+
const pending = pendingWindowRequests.get(cbKey);
|
|
1874
|
+
if (!pending?.size) return;
|
|
1875
|
+
for (const request of Array.from(pending)) {
|
|
1876
|
+
settlePendingWindowRequests(cbKey, request.requestedCount, false);
|
|
1877
|
+
}
|
|
1878
|
+
};
|
|
1879
|
+
const cancelPendingWindowRequests = (cbKey) => {
|
|
1880
|
+
const entries = cbKey ? [[cbKey, pendingWindowRequests.get(cbKey)]] : Array.from(pendingWindowRequests.entries());
|
|
1881
|
+
for (const [key, pending] of entries) {
|
|
1882
|
+
if (!pending) continue;
|
|
1883
|
+
for (const request of pending) {
|
|
1884
|
+
clearRuntimeTimeout(request.timeoutId);
|
|
1885
|
+
request.resolve(false);
|
|
1886
|
+
}
|
|
1887
|
+
pendingWindowRequests.delete(key);
|
|
1888
|
+
}
|
|
1889
|
+
};
|
|
1512
1890
|
const updateQuerySubscriptionSnapshot = (subscription, snapshot) => {
|
|
1513
1891
|
if (snapshot.context.source === "cache" && subscription.lastSnapshot?.context.source === "network") {
|
|
1514
|
-
|
|
1892
|
+
const cachedCount = snapshot.context.window?.requestedCount;
|
|
1893
|
+
const networkCount = subscription.lastSnapshot.context.window?.requestedCount;
|
|
1894
|
+
if (!cachedCount || !networkCount || cachedCount <= networkCount) return false;
|
|
1515
1895
|
}
|
|
1516
1896
|
subscription.lastSnapshot = snapshot;
|
|
1517
1897
|
return true;
|
|
@@ -1548,12 +1928,21 @@ const dispatchCountSnapshotToOneshotCallbacks = (cbKey, snapshot) => {
|
|
|
1548
1928
|
}
|
|
1549
1929
|
};
|
|
1550
1930
|
const requestRegisteredQueryRefresh = (subscription) => {
|
|
1931
|
+
if (subscription.options.pagination && subscription.requestedCount) {
|
|
1932
|
+
sendToServer({
|
|
1933
|
+
type: "set-query-window",
|
|
1934
|
+
modelName: subscription.modelName,
|
|
1935
|
+
queryKey: subscription.queryKey,
|
|
1936
|
+
requestedCount: subscription.requestedCount
|
|
1937
|
+
});
|
|
1938
|
+
return;
|
|
1939
|
+
}
|
|
1551
1940
|
sendToServer({
|
|
1552
1941
|
type: "run-query",
|
|
1553
1942
|
modelName: subscription.modelName,
|
|
1554
1943
|
queryKey: subscription.queryKey,
|
|
1555
1944
|
query: subscription.query,
|
|
1556
|
-
options: subscription
|
|
1945
|
+
options: getSubscriptionServerOptions(subscription)
|
|
1557
1946
|
});
|
|
1558
1947
|
};
|
|
1559
1948
|
const requestRegisteredCountRefresh = (subscription) => {
|
|
@@ -1566,7 +1955,61 @@ const requestRegisteredCountRefresh = (subscription) => {
|
|
|
1566
1955
|
});
|
|
1567
1956
|
};
|
|
1568
1957
|
const requestSubscriptionLocalQuery = (cbKey, subscription) => {
|
|
1569
|
-
if (!currentUid
|
|
1958
|
+
if (!currentUid) return false;
|
|
1959
|
+
const uid = currentUid;
|
|
1960
|
+
const generation = connectionGeneration;
|
|
1961
|
+
if (subscription.options.pagination) {
|
|
1962
|
+
const requestedCountAtStart = subscription.requestedCount;
|
|
1963
|
+
const windowIntentVersionAtStart = subscription.windowIntentVersion;
|
|
1964
|
+
const localQueryPromise = readQueryWindowSnapshot({
|
|
1965
|
+
uid,
|
|
1966
|
+
modelName: subscription.modelName,
|
|
1967
|
+
queryKey: subscription.queryKey
|
|
1968
|
+
}).then((result) => {
|
|
1969
|
+
if (!result.hit || generation !== connectionGeneration) return;
|
|
1970
|
+
const currentSubscription = subscriptions.get(cbKey);
|
|
1971
|
+
if (!currentSubscription) return;
|
|
1972
|
+
const requestedCount = normalizeRequestedCount(result.snapshot.requestedCount);
|
|
1973
|
+
if (!requestedCount) return;
|
|
1974
|
+
if (currentSubscription.windowIntentVersion !== windowIntentVersionAtStart) return;
|
|
1975
|
+
if (currentSubscription.requestedCount !== requestedCountAtStart) return;
|
|
1976
|
+
const snapshot = {
|
|
1977
|
+
error: null,
|
|
1978
|
+
data: result.snapshot.data,
|
|
1979
|
+
context: {
|
|
1980
|
+
source: "cache",
|
|
1981
|
+
pageInfo: result.snapshot.pageInfo,
|
|
1982
|
+
...result.snapshot.totalCount !== void 0 ? {
|
|
1983
|
+
totalCount: result.snapshot.totalCount
|
|
1984
|
+
} : {},
|
|
1985
|
+
window: {
|
|
1986
|
+
requestedCount
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
};
|
|
1990
|
+
if (!updateQuerySubscriptionSnapshot(currentSubscription, snapshot)) return;
|
|
1991
|
+
currentSubscription.requestedCount = requestedCount;
|
|
1992
|
+
currentSubscription.windowIntentVersion += 1;
|
|
1993
|
+
if (requestedCount !== requestedCountAtStart) {
|
|
1994
|
+
sendToServer({
|
|
1995
|
+
type: "set-query-window",
|
|
1996
|
+
modelName: currentSubscription.modelName,
|
|
1997
|
+
queryKey: currentSubscription.queryKey,
|
|
1998
|
+
requestedCount
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
dispatchQuerySnapshotToSubscription(currentSubscription, snapshot);
|
|
2002
|
+
}).catch(() => {
|
|
2003
|
+
});
|
|
2004
|
+
subscription.localQueryPromise = localQueryPromise;
|
|
2005
|
+
void localQueryPromise.finally(() => {
|
|
2006
|
+
const currentSubscription = subscriptions.get(cbKey);
|
|
2007
|
+
if (currentSubscription?.localQueryPromise === localQueryPromise) {
|
|
2008
|
+
delete currentSubscription.localQueryPromise;
|
|
2009
|
+
}
|
|
2010
|
+
});
|
|
2011
|
+
return true;
|
|
2012
|
+
}
|
|
1570
2013
|
const populateCache = subscription.populateCache;
|
|
1571
2014
|
const hasPopulate = Boolean(populateCache);
|
|
1572
2015
|
if (hasPopulate && populateCache) {
|
|
@@ -1574,7 +2017,7 @@ const requestSubscriptionLocalQuery = (cbKey, subscription) => {
|
|
|
1574
2017
|
modelName: subscription.modelName,
|
|
1575
2018
|
query: subscription.query,
|
|
1576
2019
|
options: {
|
|
1577
|
-
uid
|
|
2020
|
+
uid,
|
|
1578
2021
|
projection: populateCache.rootProjection,
|
|
1579
2022
|
sort: subscription.options.sort,
|
|
1580
2023
|
limit: subscription.options.limit,
|
|
@@ -1586,6 +2029,7 @@ const requestSubscriptionLocalQuery = (cbKey, subscription) => {
|
|
|
1586
2029
|
context
|
|
1587
2030
|
}) => {
|
|
1588
2031
|
if (!hit) return;
|
|
2032
|
+
if (generation !== connectionGeneration) return;
|
|
1589
2033
|
const currentSubscription = subscriptions.get(cbKey);
|
|
1590
2034
|
if (!currentSubscription) return;
|
|
1591
2035
|
const snapshot = {
|
|
@@ -1597,13 +2041,13 @@ const requestSubscriptionLocalQuery = (cbKey, subscription) => {
|
|
|
1597
2041
|
dispatchQuerySnapshotToSubscription(currentSubscription, snapshot);
|
|
1598
2042
|
}).catch(() => {
|
|
1599
2043
|
});
|
|
1600
|
-
return;
|
|
2044
|
+
return true;
|
|
1601
2045
|
}
|
|
1602
2046
|
void runQuery({
|
|
1603
2047
|
modelName: subscription.modelName,
|
|
1604
2048
|
query: subscription.query,
|
|
1605
2049
|
options: {
|
|
1606
|
-
uid
|
|
2050
|
+
uid,
|
|
1607
2051
|
projection: subscription.options.projection,
|
|
1608
2052
|
sort: subscription.options.sort,
|
|
1609
2053
|
limit: subscription.options.limit
|
|
@@ -1612,6 +2056,7 @@ const requestSubscriptionLocalQuery = (cbKey, subscription) => {
|
|
|
1612
2056
|
data,
|
|
1613
2057
|
context
|
|
1614
2058
|
}) => {
|
|
2059
|
+
if (generation !== connectionGeneration) return;
|
|
1615
2060
|
const currentSubscription = subscriptions.get(cbKey);
|
|
1616
2061
|
if (!currentSubscription) return;
|
|
1617
2062
|
const snapshot = {
|
|
@@ -1623,6 +2068,7 @@ const requestSubscriptionLocalQuery = (cbKey, subscription) => {
|
|
|
1623
2068
|
dispatchQuerySnapshotToSubscription(currentSubscription, snapshot);
|
|
1624
2069
|
}).catch(() => {
|
|
1625
2070
|
});
|
|
2071
|
+
return true;
|
|
1626
2072
|
};
|
|
1627
2073
|
const handleQueryPayload = (payload) => {
|
|
1628
2074
|
const {
|
|
@@ -1639,9 +2085,17 @@ const handleQueryPayload = (payload) => {
|
|
|
1639
2085
|
if (!hasSubscriptionCallbacks && !hasOneshotCallbacks) return;
|
|
1640
2086
|
const pageInfo = normalizePageInfo$1(payload.pageInfo);
|
|
1641
2087
|
const totalCount = normalizeTotalCount$1(payload.totalCount);
|
|
2088
|
+
const queryWindow = normalizeQueryWindow(payload.window);
|
|
1642
2089
|
const populateCache = subscription?.populateCache;
|
|
1643
2090
|
const hasPopulate = Boolean(populateCache);
|
|
1644
2091
|
const hasPagination = Boolean(subscription?.options?.pagination || pageInfo || totalCount !== void 0);
|
|
2092
|
+
if (subscription?.options.pagination && queryWindow) {
|
|
2093
|
+
if (queryWindow.requestedCount !== subscription.requestedCount) return;
|
|
2094
|
+
if (queryWindow.version !== void 0 && queryWindow.version <= subscription.lastNetworkVersion) return;
|
|
2095
|
+
if (queryWindow.version !== void 0) {
|
|
2096
|
+
subscription.lastNetworkVersion = queryWindow.version;
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
1645
2099
|
const isLocal = !!(txnId && localTxnBuf.includes(txnId));
|
|
1646
2100
|
const context = {
|
|
1647
2101
|
source: "network",
|
|
@@ -1652,6 +2106,9 @@ const handleQueryPayload = (payload) => {
|
|
|
1652
2106
|
} : {},
|
|
1653
2107
|
...totalCount !== void 0 ? {
|
|
1654
2108
|
totalCount
|
|
2109
|
+
} : {},
|
|
2110
|
+
...queryWindow ? {
|
|
2111
|
+
window: queryWindow
|
|
1655
2112
|
} : {}
|
|
1656
2113
|
};
|
|
1657
2114
|
const snapshot = {
|
|
@@ -1664,13 +2121,50 @@ const handleQueryPayload = (payload) => {
|
|
|
1664
2121
|
dispatchQuerySnapshotToSubscription(subscription, snapshot);
|
|
1665
2122
|
}
|
|
1666
2123
|
dispatchQuerySnapshotToOneshotCallbacks(cbKey, snapshot);
|
|
2124
|
+
if (queryWindow) {
|
|
2125
|
+
settlePendingWindowRequests(cbKey, queryWindow.requestedCount, false);
|
|
2126
|
+
} else if (subscription?.options.pagination) {
|
|
2127
|
+
failPendingWindowRequests(cbKey);
|
|
2128
|
+
}
|
|
1667
2129
|
return;
|
|
1668
2130
|
}
|
|
1669
2131
|
if (subscription && updateQuerySubscriptionSnapshot(subscription, snapshot)) {
|
|
1670
2132
|
dispatchQuerySnapshotToSubscription(subscription, snapshot);
|
|
1671
2133
|
}
|
|
1672
2134
|
dispatchQuerySnapshotToOneshotCallbacks(cbKey, snapshot);
|
|
2135
|
+
if (queryWindow) {
|
|
2136
|
+
settlePendingWindowRequests(cbKey, queryWindow.requestedCount, true);
|
|
2137
|
+
}
|
|
1673
2138
|
if (!currentUid) return;
|
|
2139
|
+
if (subscription?.options.pagination && queryWindow && pageInfo && Array.isArray(data) && connectionEpoch) {
|
|
2140
|
+
const uid = currentUid;
|
|
2141
|
+
const generation = connectionGeneration;
|
|
2142
|
+
const serverEpoch = connectionEpoch;
|
|
2143
|
+
const localQueryPromise = subscription.localQueryPromise;
|
|
2144
|
+
void Promise.resolve().then(async () => {
|
|
2145
|
+
await localQueryPromise;
|
|
2146
|
+
if (generation !== connectionGeneration || serverEpoch !== connectionEpoch) return;
|
|
2147
|
+
const currentSubscription = subscriptions.get(cbKey);
|
|
2148
|
+
if (!currentSubscription || currentSubscription.requestedCount !== queryWindow.requestedCount) return;
|
|
2149
|
+
await writeQueryWindowSnapshot({
|
|
2150
|
+
uid,
|
|
2151
|
+
modelName,
|
|
2152
|
+
queryKey,
|
|
2153
|
+
data,
|
|
2154
|
+
pageInfo,
|
|
2155
|
+
...totalCount !== void 0 ? {
|
|
2156
|
+
totalCount
|
|
2157
|
+
} : {},
|
|
2158
|
+
requestedCount: queryWindow.requestedCount,
|
|
2159
|
+
...queryWindow.version !== void 0 ? {
|
|
2160
|
+
serverEpoch,
|
|
2161
|
+
serverVersion: queryWindow.version
|
|
2162
|
+
} : {}
|
|
2163
|
+
});
|
|
2164
|
+
}).catch(() => {
|
|
2165
|
+
});
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
1674
2168
|
const docs = Array.isArray(data) ? data.filter(isDocWithId) : [];
|
|
1675
2169
|
if (hasPagination) return;
|
|
1676
2170
|
if (!docs.length) return;
|
|
@@ -1789,7 +2283,7 @@ const writeStoredSeq = (key, value) => {
|
|
|
1789
2283
|
return;
|
|
1790
2284
|
}
|
|
1791
2285
|
};
|
|
1792
|
-
const applyChangeBatch = async (changes, uid) => {
|
|
2286
|
+
const applyChangeBatch = async (changes, uid, isCurrent) => {
|
|
1793
2287
|
const resetModels = /* @__PURE__ */ new Set();
|
|
1794
2288
|
const deletesByModel = /* @__PURE__ */ new Map();
|
|
1795
2289
|
for (const change of changes) {
|
|
@@ -1808,24 +2302,35 @@ const applyChangeBatch = async (changes, uid) => {
|
|
|
1808
2302
|
}
|
|
1809
2303
|
}
|
|
1810
2304
|
for (const modelName of resetModels) {
|
|
2305
|
+
if (!isCurrent()) return false;
|
|
1811
2306
|
await destroyCollection(modelName, uid).catch(() => {
|
|
1812
2307
|
});
|
|
1813
2308
|
}
|
|
1814
2309
|
for (const [modelName, ids] of deletesByModel.entries()) {
|
|
1815
2310
|
if (resetModels.has(modelName)) continue;
|
|
2311
|
+
if (!isCurrent()) return false;
|
|
1816
2312
|
await deleteDocs(modelName, ids, uid).catch(() => {
|
|
1817
2313
|
});
|
|
1818
2314
|
}
|
|
2315
|
+
if (resetModels.size || deletesByModel.size) {
|
|
2316
|
+
if (!isCurrent()) return false;
|
|
2317
|
+
await invalidateQueryWindowSnapshots({
|
|
2318
|
+
uid
|
|
2319
|
+
}).catch(() => {
|
|
2320
|
+
});
|
|
2321
|
+
}
|
|
2322
|
+
return true;
|
|
1819
2323
|
};
|
|
1820
|
-
const
|
|
2324
|
+
const syncRtsChangesWithResult = async (tenantId, uid, options = {}, isCurrent = () => true) => {
|
|
1821
2325
|
ensureSyncRuntime();
|
|
1822
|
-
if (!tenantId || !uid) return;
|
|
2326
|
+
if (!tenantId || !uid) return false;
|
|
1823
2327
|
const storageKey = getSyncStorageKey({
|
|
1824
2328
|
tenantId,
|
|
1825
2329
|
uid,
|
|
1826
2330
|
appName: options.appName
|
|
1827
2331
|
});
|
|
1828
2332
|
let sinceSeq = readStoredSeq(storageKey);
|
|
2333
|
+
let cacheInvalidated = false;
|
|
1829
2334
|
const syncUrl = buildSyncChangesUrl(tenantId, {
|
|
1830
2335
|
url: options.url
|
|
1831
2336
|
});
|
|
@@ -1841,21 +2346,23 @@ const syncRtsChanges = async (tenantId, uid, options = {}) => {
|
|
|
1841
2346
|
limit: 2e3
|
|
1842
2347
|
})
|
|
1843
2348
|
});
|
|
1844
|
-
if (!
|
|
2349
|
+
if (!isCurrent()) return false;
|
|
2350
|
+
if (!response.ok) return cacheInvalidated;
|
|
1845
2351
|
const payload = await response.json().catch(() => null);
|
|
1846
|
-
if (!payload || typeof payload !== "object") return;
|
|
2352
|
+
if (!payload || typeof payload !== "object") return cacheInvalidated;
|
|
1847
2353
|
const payloadObj = payload;
|
|
1848
2354
|
const ok = payloadObj.ok;
|
|
1849
|
-
if (ok !== true) return;
|
|
2355
|
+
if (ok !== true) return cacheInvalidated;
|
|
1850
2356
|
const latestSeq = Number(payloadObj.latestSeq ?? 0);
|
|
1851
2357
|
const needsFullResync = Boolean(payloadObj.needsFullResync);
|
|
1852
2358
|
if (needsFullResync) {
|
|
2359
|
+
if (!isCurrent()) return false;
|
|
1853
2360
|
resetRtsPouchStore({
|
|
1854
2361
|
tenantId,
|
|
1855
2362
|
appName: options.appName
|
|
1856
2363
|
});
|
|
1857
2364
|
writeStoredSeq(storageKey, latestSeq);
|
|
1858
|
-
return;
|
|
2365
|
+
return true;
|
|
1859
2366
|
}
|
|
1860
2367
|
const changesRaw = payloadObj.changes;
|
|
1861
2368
|
const changes = Array.isArray(changesRaw) ? changesRaw : [];
|
|
@@ -1877,31 +2384,37 @@ const syncRtsChanges = async (tenantId, uid, options = {}) => {
|
|
|
1877
2384
|
}).filter((c2) => c2 !== null).filter((c2) => Number.isFinite(c2.seq) && c2.seq > 0 && c2.modelName && (c2.op === "reset_model" || !!c2.docId));
|
|
1878
2385
|
if (!normalized.length) {
|
|
1879
2386
|
writeStoredSeq(storageKey, latestSeq);
|
|
1880
|
-
return;
|
|
2387
|
+
return cacheInvalidated;
|
|
1881
2388
|
}
|
|
1882
|
-
await applyChangeBatch(normalized, uid);
|
|
2389
|
+
const applied = await applyChangeBatch(normalized, uid, isCurrent);
|
|
2390
|
+
if (!applied) return false;
|
|
2391
|
+
cacheInvalidated = true;
|
|
1883
2392
|
const lastSeq = normalized.reduce((max, c2) => c2.seq > max ? c2.seq : max, sinceSeq);
|
|
1884
2393
|
sinceSeq = lastSeq;
|
|
1885
2394
|
writeStoredSeq(storageKey, sinceSeq);
|
|
1886
2395
|
if (latestSeq > 0 && sinceSeq >= latestSeq) {
|
|
1887
|
-
return;
|
|
2396
|
+
return cacheInvalidated;
|
|
1888
2397
|
}
|
|
1889
2398
|
}
|
|
2399
|
+
return cacheInvalidated;
|
|
2400
|
+
};
|
|
2401
|
+
const syncRtsChanges = async (tenantId, uid, options = {}) => {
|
|
2402
|
+
await syncRtsChangesWithResult(tenantId, uid, options);
|
|
1890
2403
|
};
|
|
1891
2404
|
const ensureSynced = (tenantId, uid, options) => {
|
|
1892
|
-
if (options.syncChanges === false) return;
|
|
2405
|
+
if (options.syncChanges === false) return Promise.resolve(false);
|
|
1893
2406
|
const key = `${options.appName ?? ""}:${tenantId}:${uid}`;
|
|
1894
|
-
if (syncPromise && syncKey === key) return;
|
|
2407
|
+
if (syncPromise && syncKey === key) return syncPromise;
|
|
1895
2408
|
syncKey = key;
|
|
1896
|
-
syncPromise =
|
|
2409
|
+
syncPromise = syncRtsChangesWithResult(tenantId, uid, {
|
|
1897
2410
|
appName: options.appName,
|
|
1898
2411
|
url: options.url
|
|
1899
|
-
}).catch(() => {
|
|
1900
|
-
}).finally(() => {
|
|
2412
|
+
}, () => currentTenantId === tenantId && currentUid === uid && (connectOptions.appName ?? "") === (options.appName ?? "")).catch(() => false).finally(() => {
|
|
1901
2413
|
if (syncKey === key) {
|
|
1902
2414
|
syncPromise = null;
|
|
1903
2415
|
}
|
|
1904
2416
|
});
|
|
2417
|
+
return syncPromise;
|
|
1905
2418
|
};
|
|
1906
2419
|
const connectInternal = (tenantId, uid, options, {
|
|
1907
2420
|
resetReconnectAttempts
|
|
@@ -1918,37 +2431,84 @@ const connectInternal = (tenantId, uid, options, {
|
|
|
1918
2431
|
appName: options.appName
|
|
1919
2432
|
});
|
|
1920
2433
|
}
|
|
1921
|
-
ensureSynced(tenantId, uid, options);
|
|
1922
2434
|
if (socket && (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING)) {
|
|
1923
2435
|
return connectPromise ?? Promise.resolve();
|
|
1924
2436
|
}
|
|
2437
|
+
const synchronization = ensureSynced(tenantId, uid, options);
|
|
1925
2438
|
explicitDisconnect = false;
|
|
1926
2439
|
clearReconnectTimer();
|
|
2440
|
+
socketReadyForMessages = false;
|
|
1927
2441
|
const url = buildSocketUrl(tenantId, uid, options);
|
|
1928
2442
|
connectPromise = new Promise((resolve, reject) => {
|
|
1929
2443
|
if (resetReconnectAttempts) reconnectAttempts = 0;
|
|
1930
2444
|
let opened = false;
|
|
1931
2445
|
let settled = false;
|
|
2446
|
+
let subscriptionsStarted = false;
|
|
2447
|
+
let cacheInvalidatedBeforeSubscriptions = false;
|
|
2448
|
+
const generation = ++connectionGeneration;
|
|
2449
|
+
const epoch = `${Date.now().toString(36)}.${generation.toString(36)}.${Math.random().toString(36).slice(2, 10)}`;
|
|
2450
|
+
connectionEpoch = epoch;
|
|
2451
|
+
pendingConnectionAttempt = {
|
|
2452
|
+
generation,
|
|
2453
|
+
reject: (error) => {
|
|
2454
|
+
if (settled) return;
|
|
2455
|
+
settled = true;
|
|
2456
|
+
reject(error);
|
|
2457
|
+
}
|
|
2458
|
+
};
|
|
1932
2459
|
setConnectionStatus("connecting");
|
|
1933
|
-
|
|
1934
|
-
socket
|
|
2460
|
+
const nextSocket = new WebSocket(url);
|
|
2461
|
+
socket = nextSocket;
|
|
2462
|
+
if (options.syncChanges !== false) {
|
|
2463
|
+
void synchronization.then((cacheInvalidated) => {
|
|
2464
|
+
if (!cacheInvalidated || generation !== connectionGeneration) return;
|
|
2465
|
+
if (!subscriptionsStarted) {
|
|
2466
|
+
cacheInvalidatedBeforeSubscriptions = true;
|
|
2467
|
+
return;
|
|
2468
|
+
}
|
|
2469
|
+
if (nextSocket.readyState !== WebSocket.OPEN) return;
|
|
2470
|
+
for (const subscription of subscriptions.values()) {
|
|
2471
|
+
if (!subscription.options.pagination) continue;
|
|
2472
|
+
requestRegisteredQueryRefresh(subscription);
|
|
2473
|
+
}
|
|
2474
|
+
});
|
|
2475
|
+
}
|
|
2476
|
+
nextSocket.addEventListener("open", () => {
|
|
2477
|
+
if (generation !== connectionGeneration) return;
|
|
1935
2478
|
opened = true;
|
|
1936
2479
|
settled = true;
|
|
2480
|
+
if (pendingConnectionAttempt?.generation === generation) pendingConnectionAttempt = null;
|
|
1937
2481
|
reconnectAttempts = 0;
|
|
1938
2482
|
pendingServerReconnectJitter = false;
|
|
2483
|
+
socketReadyForMessages = true;
|
|
1939
2484
|
setConnectionStatus("connected");
|
|
1940
|
-
const
|
|
2485
|
+
for (const subscription of subscriptions.values()) {
|
|
2486
|
+
subscription.lastNetworkVersion = 0;
|
|
2487
|
+
if (subscription.runInitialLocalQuery && !subscription.hasRequestedInitialLocalQuery) {
|
|
2488
|
+
const cbKey = `${subscription.modelName}.${subscription.queryKey}`;
|
|
2489
|
+
subscription.hasRequestedInitialLocalQuery = requestSubscriptionLocalQuery(cbKey, subscription);
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
const forceInitialQuery = hasEstablishedConnection || forceInitialQueryOnNextConnection || cacheInvalidatedBeforeSubscriptions;
|
|
1941
2493
|
resubscribeAll({
|
|
1942
2494
|
forceInitialQuery
|
|
1943
2495
|
});
|
|
2496
|
+
forceInitialQueryOnNextConnection = false;
|
|
2497
|
+
subscriptionsStarted = true;
|
|
1944
2498
|
hasEstablishedConnection = true;
|
|
1945
2499
|
resolve();
|
|
1946
2500
|
});
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
2501
|
+
nextSocket.addEventListener("message", (event) => {
|
|
2502
|
+
if (generation !== connectionGeneration) return;
|
|
2503
|
+
handleMessage(event);
|
|
2504
|
+
});
|
|
2505
|
+
nextSocket.addEventListener("close", (event) => {
|
|
2506
|
+
if (generation !== connectionGeneration) return;
|
|
2507
|
+
socketReadyForMessages = false;
|
|
2508
|
+
if (!settled) {
|
|
1950
2509
|
settled = true;
|
|
1951
|
-
|
|
2510
|
+
if (pendingConnectionAttempt?.generation === generation) pendingConnectionAttempt = null;
|
|
2511
|
+
const error = new Error(`RTS WebSocket closed before becoming ready (code=${event.code})`);
|
|
1952
2512
|
setConnectionStatus("error", error);
|
|
1953
2513
|
reject(error);
|
|
1954
2514
|
}
|
|
@@ -1962,9 +2522,12 @@ const connectInternal = (tenantId, uid, options, {
|
|
|
1962
2522
|
connectPromise = null;
|
|
1963
2523
|
scheduleReconnect();
|
|
1964
2524
|
});
|
|
1965
|
-
|
|
2525
|
+
nextSocket.addEventListener("error", (err) => {
|
|
2526
|
+
if (generation !== connectionGeneration) return;
|
|
1966
2527
|
if (settled) return;
|
|
1967
2528
|
settled = true;
|
|
2529
|
+
if (pendingConnectionAttempt?.generation === generation) pendingConnectionAttempt = null;
|
|
2530
|
+
socketReadyForMessages = false;
|
|
1968
2531
|
const error = err instanceof Error ? err : new Error("RTS WebSocket error");
|
|
1969
2532
|
setConnectionStatus("error", error);
|
|
1970
2533
|
reject(error);
|
|
@@ -1973,14 +2536,19 @@ const connectInternal = (tenantId, uid, options, {
|
|
|
1973
2536
|
return connectPromise;
|
|
1974
2537
|
};
|
|
1975
2538
|
const connect = (tenantId, uid, options = {}) => {
|
|
2539
|
+
const identityChanged = currentTenantId !== null && (currentTenantId !== tenantId || currentUid !== uid || (connectOptions.appName ?? "") !== (options.appName ?? ""));
|
|
2540
|
+
if (identityChanged) return reconnect(tenantId, uid, options);
|
|
1976
2541
|
return connectInternal(tenantId, uid, options, {
|
|
1977
2542
|
resetReconnectAttempts: true
|
|
1978
2543
|
});
|
|
1979
2544
|
};
|
|
1980
2545
|
const disconnect = () => {
|
|
1981
2546
|
explicitDisconnect = true;
|
|
2547
|
+
connectionGeneration += 1;
|
|
2548
|
+
rejectPendingConnectionAttempt();
|
|
1982
2549
|
clearReconnectTimer();
|
|
1983
2550
|
hasEstablishedConnection = false;
|
|
2551
|
+
forceInitialQueryOnNextConnection = false;
|
|
1984
2552
|
pendingServerReconnectJitter = false;
|
|
1985
2553
|
if (socket) {
|
|
1986
2554
|
try {
|
|
@@ -1989,11 +2557,54 @@ const disconnect = () => {
|
|
|
1989
2557
|
}
|
|
1990
2558
|
}
|
|
1991
2559
|
socket = null;
|
|
2560
|
+
socketReadyForMessages = false;
|
|
1992
2561
|
connectPromise = null;
|
|
2562
|
+
connectionEpoch = null;
|
|
2563
|
+
cancelPendingWindowRequests();
|
|
1993
2564
|
setConnectionStatus("idle");
|
|
1994
2565
|
};
|
|
1995
2566
|
const reconnect = (tenantId, uid, options = {}) => {
|
|
2567
|
+
const hasPreviousIdentity = currentTenantId !== null && currentUid !== null;
|
|
2568
|
+
const identityChanged = hasPreviousIdentity && (currentTenantId !== tenantId || currentUid !== uid || (connectOptions.appName ?? "") !== (options.appName ?? ""));
|
|
2569
|
+
if (identityChanged) {
|
|
2570
|
+
cancelPendingWindowRequests();
|
|
2571
|
+
for (const subscription of subscriptions.values()) {
|
|
2572
|
+
subscription.hasRequestedInitialLocalQuery = false;
|
|
2573
|
+
subscription.lastSnapshot = void 0;
|
|
2574
|
+
subscription.lastNetworkVersion = 0;
|
|
2575
|
+
subscription.windowIntentVersion += 1;
|
|
2576
|
+
subscription.requestedCount = subscription.initialWindowSize;
|
|
2577
|
+
delete subscription.localQueryPromise;
|
|
2578
|
+
dispatchQuerySnapshotToSubscription(subscription, {
|
|
2579
|
+
error: null,
|
|
2580
|
+
data: void 0,
|
|
2581
|
+
context: {
|
|
2582
|
+
source: "cache",
|
|
2583
|
+
reset: true,
|
|
2584
|
+
...subscription.initialWindowSize ? {
|
|
2585
|
+
window: {
|
|
2586
|
+
requestedCount: subscription.initialWindowSize
|
|
2587
|
+
}
|
|
2588
|
+
} : {}
|
|
2589
|
+
}
|
|
2590
|
+
});
|
|
2591
|
+
}
|
|
2592
|
+
for (const subscription of countSubscriptions.values()) {
|
|
2593
|
+
subscription.lastSnapshot = void 0;
|
|
2594
|
+
dispatchCountSnapshotToSubscription(subscription, {
|
|
2595
|
+
error: null,
|
|
2596
|
+
count: void 0,
|
|
2597
|
+
context: {
|
|
2598
|
+
source: "cache",
|
|
2599
|
+
reset: true
|
|
2600
|
+
}
|
|
2601
|
+
});
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
forceInitialQueryOnNextConnection = hasEstablishedConnection || identityChanged;
|
|
1996
2605
|
explicitDisconnect = true;
|
|
2606
|
+
connectionGeneration += 1;
|
|
2607
|
+
rejectPendingConnectionAttempt();
|
|
1997
2608
|
clearReconnectTimer();
|
|
1998
2609
|
pendingServerReconnectJitter = false;
|
|
1999
2610
|
if (socket) {
|
|
@@ -2003,8 +2614,12 @@ const reconnect = (tenantId, uid, options = {}) => {
|
|
|
2003
2614
|
}
|
|
2004
2615
|
}
|
|
2005
2616
|
socket = null;
|
|
2617
|
+
socketReadyForMessages = false;
|
|
2006
2618
|
connectPromise = null;
|
|
2007
|
-
|
|
2619
|
+
connectionEpoch = null;
|
|
2620
|
+
return connectInternal(tenantId, uid, options, {
|
|
2621
|
+
resetReconnectAttempts: true
|
|
2622
|
+
});
|
|
2008
2623
|
};
|
|
2009
2624
|
const getConnectionStatus = () => {
|
|
2010
2625
|
return connectionStatus;
|
|
@@ -2041,7 +2656,7 @@ const registerQuery = (modelName, query, optionsOrCallback, callbackMaybe, behav
|
|
|
2041
2656
|
projection: options.projection,
|
|
2042
2657
|
populate: options.populate
|
|
2043
2658
|
}, "registerQuery");
|
|
2044
|
-
const
|
|
2659
|
+
const initialWindowSize = options.pagination ? normalizeRequestedCount(options.pagination.limit) : void 0;
|
|
2045
2660
|
const existingSubscription = subscriptions.get(cbKey);
|
|
2046
2661
|
const subscription = existingSubscription ?? {
|
|
2047
2662
|
modelName,
|
|
@@ -2050,7 +2665,14 @@ const registerQuery = (modelName, query, optionsOrCallback, callbackMaybe, behav
|
|
|
2050
2665
|
queryKey,
|
|
2051
2666
|
callbacks: /* @__PURE__ */ new Set(),
|
|
2052
2667
|
runInitialNetworkQuery,
|
|
2668
|
+
runInitialLocalQuery,
|
|
2053
2669
|
hasRequestedInitialLocalQuery: false,
|
|
2670
|
+
lastNetworkVersion: 0,
|
|
2671
|
+
windowIntentVersion: 0,
|
|
2672
|
+
...initialWindowSize ? {
|
|
2673
|
+
initialWindowSize,
|
|
2674
|
+
requestedCount: initialWindowSize
|
|
2675
|
+
} : {},
|
|
2054
2676
|
...populateCache ? {
|
|
2055
2677
|
populateCache
|
|
2056
2678
|
} : {}
|
|
@@ -2061,6 +2683,9 @@ const registerQuery = (modelName, query, optionsOrCallback, callbackMaybe, behav
|
|
|
2061
2683
|
if (runInitialNetworkQuery) {
|
|
2062
2684
|
subscription.runInitialNetworkQuery = true;
|
|
2063
2685
|
}
|
|
2686
|
+
if (runInitialLocalQuery) {
|
|
2687
|
+
subscription.runInitialLocalQuery = true;
|
|
2688
|
+
}
|
|
2064
2689
|
subscriptions.set(cbKey, subscription);
|
|
2065
2690
|
let seeded = false;
|
|
2066
2691
|
if (behavior?.seedSnapshot && updateQuerySubscriptionSnapshot(subscription, behavior.seedSnapshot)) {
|
|
@@ -2071,22 +2696,20 @@ const registerQuery = (modelName, query, optionsOrCallback, callbackMaybe, behav
|
|
|
2071
2696
|
callback(subscription.lastSnapshot.error, subscription.lastSnapshot.data, subscription.lastSnapshot.context);
|
|
2072
2697
|
}
|
|
2073
2698
|
if (!hadCallbacks) {
|
|
2074
|
-
if (runInitialLocalQuery
|
|
2075
|
-
subscription.hasRequestedInitialLocalQuery =
|
|
2076
|
-
requestSubscriptionLocalQuery(cbKey, subscription);
|
|
2699
|
+
if (runInitialLocalQuery) {
|
|
2700
|
+
subscription.hasRequestedInitialLocalQuery = requestSubscriptionLocalQuery(cbKey, subscription);
|
|
2077
2701
|
}
|
|
2078
2702
|
sendToServer({
|
|
2079
2703
|
type: "register-query",
|
|
2080
2704
|
modelName,
|
|
2081
2705
|
queryKey,
|
|
2082
2706
|
query,
|
|
2083
|
-
options,
|
|
2707
|
+
options: getSubscriptionServerOptions(subscription),
|
|
2084
2708
|
runInitialQuery: runInitialNetworkQuery
|
|
2085
2709
|
});
|
|
2086
2710
|
} else {
|
|
2087
|
-
if (runInitialLocalQuery && !subscription.hasRequestedInitialLocalQuery
|
|
2088
|
-
subscription.hasRequestedInitialLocalQuery =
|
|
2089
|
-
requestSubscriptionLocalQuery(cbKey, subscription);
|
|
2711
|
+
if (runInitialLocalQuery && !subscription.hasRequestedInitialLocalQuery) {
|
|
2712
|
+
subscription.hasRequestedInitialLocalQuery = requestSubscriptionLocalQuery(cbKey, subscription);
|
|
2090
2713
|
}
|
|
2091
2714
|
if (forceRefreshOnMount || runInitialNetworkQuery && (!hadInitialNetworkQuery || hasSnapshotError(subscription.lastSnapshot))) {
|
|
2092
2715
|
requestRegisteredQueryRefresh(subscription);
|
|
@@ -2097,6 +2720,7 @@ const registerQuery = (modelName, query, optionsOrCallback, callbackMaybe, behav
|
|
|
2097
2720
|
currentSubscription?.callbacks.delete(callback);
|
|
2098
2721
|
if (currentSubscription && currentSubscription.callbacks.size === 0) {
|
|
2099
2722
|
subscriptions.delete(cbKey);
|
|
2723
|
+
cancelPendingWindowRequests(cbKey);
|
|
2100
2724
|
sendToServer({
|
|
2101
2725
|
type: "remove-query",
|
|
2102
2726
|
modelName,
|
|
@@ -2105,6 +2729,63 @@ const registerQuery = (modelName, query, optionsOrCallback, callbackMaybe, behav
|
|
|
2105
2729
|
}
|
|
2106
2730
|
};
|
|
2107
2731
|
};
|
|
2732
|
+
const setQueryWindowSize = async ({
|
|
2733
|
+
modelName,
|
|
2734
|
+
query,
|
|
2735
|
+
options,
|
|
2736
|
+
requestedCount,
|
|
2737
|
+
timeoutMs = 1e4
|
|
2738
|
+
}) => {
|
|
2739
|
+
const normalizedRequestedCount = normalizeRequestedCount(requestedCount);
|
|
2740
|
+
if (!normalizedRequestedCount || !options.pagination) return false;
|
|
2741
|
+
const queryKey = computeRtsQueryKey(query, options);
|
|
2742
|
+
const cbKey = `${modelName}.${queryKey}`;
|
|
2743
|
+
const subscription = subscriptions.get(cbKey);
|
|
2744
|
+
if (!subscription?.options.pagination) return false;
|
|
2745
|
+
const currentNetworkWindow = subscription.lastSnapshot?.context.source === "network" ? subscription.lastSnapshot.context.window : void 0;
|
|
2746
|
+
if (subscription.requestedCount === normalizedRequestedCount && currentNetworkWindow?.requestedCount === normalizedRequestedCount) {
|
|
2747
|
+
return true;
|
|
2748
|
+
}
|
|
2749
|
+
const previousRequestedCount = subscription.requestedCount ?? subscription.initialWindowSize ?? normalizedRequestedCount;
|
|
2750
|
+
subscription.windowIntentVersion += 1;
|
|
2751
|
+
subscription.requestedCount = normalizedRequestedCount;
|
|
2752
|
+
let request;
|
|
2753
|
+
const response = new Promise((resolve) => {
|
|
2754
|
+
const timeoutId = setRuntimeTimeout(() => {
|
|
2755
|
+
settlePendingWindowRequests(cbKey, request.requestedCount, false);
|
|
2756
|
+
}, timeoutMs);
|
|
2757
|
+
request = {
|
|
2758
|
+
requestedCount: normalizedRequestedCount,
|
|
2759
|
+
previousRequestedCount,
|
|
2760
|
+
resolve,
|
|
2761
|
+
timeoutId
|
|
2762
|
+
};
|
|
2763
|
+
const pending = pendingWindowRequests.get(cbKey) ?? /* @__PURE__ */ new Set();
|
|
2764
|
+
pending.add(request);
|
|
2765
|
+
pendingWindowRequests.set(cbKey, pending);
|
|
2766
|
+
});
|
|
2767
|
+
try {
|
|
2768
|
+
if (!isSocketReady()) {
|
|
2769
|
+
if (!currentTenantId || !currentUid) {
|
|
2770
|
+
settlePendingWindowRequests(cbKey, normalizedRequestedCount, false);
|
|
2771
|
+
return false;
|
|
2772
|
+
}
|
|
2773
|
+
await connectInternal(currentTenantId, currentUid, connectOptions, {
|
|
2774
|
+
resetReconnectAttempts: false
|
|
2775
|
+
});
|
|
2776
|
+
}
|
|
2777
|
+
sendToServer({
|
|
2778
|
+
type: "set-query-window",
|
|
2779
|
+
modelName,
|
|
2780
|
+
queryKey,
|
|
2781
|
+
requestedCount: normalizedRequestedCount
|
|
2782
|
+
});
|
|
2783
|
+
} catch {
|
|
2784
|
+
settlePendingWindowRequests(cbKey, normalizedRequestedCount, false);
|
|
2785
|
+
return false;
|
|
2786
|
+
}
|
|
2787
|
+
return await response;
|
|
2788
|
+
};
|
|
2108
2789
|
const registerCount = (modelName, query, optionsOrCallback, callbackMaybe, behavior) => {
|
|
2109
2790
|
let options;
|
|
2110
2791
|
let callback;
|
|
@@ -2188,7 +2869,7 @@ const runNetworkQuery = async ({
|
|
|
2188
2869
|
}, "runNetworkQuery");
|
|
2189
2870
|
const hasTimeout = typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0;
|
|
2190
2871
|
const timeoutStartedAt = hasTimeout ? Date.now() : 0;
|
|
2191
|
-
if (!
|
|
2872
|
+
if (!isSocketReady()) {
|
|
2192
2873
|
if (currentTenantId && currentUid) {
|
|
2193
2874
|
try {
|
|
2194
2875
|
const connectAttempt = connectInternal(currentTenantId, currentUid, connectOptions, {
|
|
@@ -2197,7 +2878,7 @@ const runNetworkQuery = async ({
|
|
|
2197
2878
|
if (hasTimeout) {
|
|
2198
2879
|
await new Promise((resolve, reject) => {
|
|
2199
2880
|
const timeoutId = setRuntimeTimeout(() => {
|
|
2200
|
-
reject(new Error(
|
|
2881
|
+
reject(new Error(RUN_NETWORK_QUERY_TIMEOUT_ERROR));
|
|
2201
2882
|
}, timeoutMs);
|
|
2202
2883
|
connectAttempt.then(() => {
|
|
2203
2884
|
clearRuntimeTimeout(timeoutId);
|
|
@@ -2214,7 +2895,7 @@ const runNetworkQuery = async ({
|
|
|
2214
2895
|
}
|
|
2215
2896
|
}
|
|
2216
2897
|
}
|
|
2217
|
-
if (!
|
|
2898
|
+
if (!isSocketReady()) {
|
|
2218
2899
|
if (hasTimeout && Date.now() - timeoutStartedAt >= timeoutMs) {
|
|
2219
2900
|
throw new Error(RUN_NETWORK_QUERY_TIMEOUT_ERROR);
|
|
2220
2901
|
}
|
|
@@ -2224,7 +2905,7 @@ const runNetworkQuery = async ({
|
|
|
2224
2905
|
if (remainingTimeoutMs !== null && remainingTimeoutMs <= 0) {
|
|
2225
2906
|
throw new Error(RUN_NETWORK_QUERY_TIMEOUT_ERROR);
|
|
2226
2907
|
}
|
|
2227
|
-
const resolvedOptions =
|
|
2908
|
+
const resolvedOptions = {
|
|
2228
2909
|
...options,
|
|
2229
2910
|
key: makeRunQueryKey()
|
|
2230
2911
|
};
|
|
@@ -2285,7 +2966,7 @@ const runNetworkCount = async ({
|
|
|
2285
2966
|
}
|
|
2286
2967
|
const hasTimeout = typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0;
|
|
2287
2968
|
const timeoutStartedAt = hasTimeout ? Date.now() : 0;
|
|
2288
|
-
if (!
|
|
2969
|
+
if (!isSocketReady()) {
|
|
2289
2970
|
if (currentTenantId && currentUid) {
|
|
2290
2971
|
try {
|
|
2291
2972
|
const connectAttempt = connectInternal(currentTenantId, currentUid, connectOptions, {
|
|
@@ -2294,7 +2975,7 @@ const runNetworkCount = async ({
|
|
|
2294
2975
|
if (hasTimeout) {
|
|
2295
2976
|
await new Promise((resolve, reject) => {
|
|
2296
2977
|
const timeoutId = setRuntimeTimeout(() => {
|
|
2297
|
-
reject(new Error(
|
|
2978
|
+
reject(new Error(RUN_NETWORK_COUNT_TIMEOUT_ERROR));
|
|
2298
2979
|
}, timeoutMs);
|
|
2299
2980
|
connectAttempt.then(() => {
|
|
2300
2981
|
clearRuntimeTimeout(timeoutId);
|
|
@@ -2311,7 +2992,7 @@ const runNetworkCount = async ({
|
|
|
2311
2992
|
}
|
|
2312
2993
|
}
|
|
2313
2994
|
}
|
|
2314
|
-
if (!
|
|
2995
|
+
if (!isSocketReady()) {
|
|
2315
2996
|
if (hasTimeout && Date.now() - timeoutStartedAt >= timeoutMs) {
|
|
2316
2997
|
throw new Error(RUN_NETWORK_COUNT_TIMEOUT_ERROR);
|
|
2317
2998
|
}
|
|
@@ -2321,7 +3002,7 @@ const runNetworkCount = async ({
|
|
|
2321
3002
|
if (remainingTimeoutMs !== null && remainingTimeoutMs <= 0) {
|
|
2322
3003
|
throw new Error(RUN_NETWORK_COUNT_TIMEOUT_ERROR);
|
|
2323
3004
|
}
|
|
2324
|
-
const resolvedOptions =
|
|
3005
|
+
const resolvedOptions = {
|
|
2325
3006
|
...options,
|
|
2326
3007
|
key: makeRunQueryKey()
|
|
2327
3008
|
};
|
|
@@ -2432,28 +3113,9 @@ const normalizeTotalCount = (value) => {
|
|
|
2432
3113
|
if (!Number.isFinite(value) || value < 0) return void 0;
|
|
2433
3114
|
return Math.floor(value);
|
|
2434
3115
|
};
|
|
2435
|
-
const
|
|
2436
|
-
if (
|
|
2437
|
-
|
|
2438
|
-
return typeof id === "string" ? id.trim() : "";
|
|
2439
|
-
};
|
|
2440
|
-
const dedupeById = (docs) => {
|
|
2441
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2442
|
-
const merged = [];
|
|
2443
|
-
for (const doc of docs) {
|
|
2444
|
-
const id = getDocId(doc);
|
|
2445
|
-
if (id && seen.has(id)) continue;
|
|
2446
|
-
if (id) seen.add(id);
|
|
2447
|
-
merged.push(doc);
|
|
2448
|
-
}
|
|
2449
|
-
return merged;
|
|
2450
|
-
};
|
|
2451
|
-
const flattenLoadedPages = (previousPages, headPage, nextPages) => {
|
|
2452
|
-
const merged = [];
|
|
2453
|
-
for (const page of previousPages) merged.push(...page.nodes);
|
|
2454
|
-
if (headPage) merged.push(...headPage.nodes);
|
|
2455
|
-
for (const page of nextPages) merged.push(...page.nodes);
|
|
2456
|
-
return dedupeById(merged);
|
|
3116
|
+
const normalizeWindowSize = (value) => {
|
|
3117
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 1;
|
|
3118
|
+
return Math.max(1, Math.min(RTS_QUERY_WINDOW_MAX_COUNT, Math.floor(value)));
|
|
2457
3119
|
};
|
|
2458
3120
|
const assertIncludeOnlyProjection = (projection) => {
|
|
2459
3121
|
if (!projection) return;
|
|
@@ -2484,6 +3146,13 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
2484
3146
|
populate: options.populate
|
|
2485
3147
|
}, "useQuery");
|
|
2486
3148
|
const isPaginated = Boolean(options.pagination);
|
|
3149
|
+
if (options.pagination && (!Number.isInteger(options.pagination.limit) || options.pagination.limit < 1 || options.pagination.limit > RTS_QUERY_WINDOW_MAX_COUNT)) {
|
|
3150
|
+
throw new Error("useQuery: pagination limit must be an integer between 1 and 4096");
|
|
3151
|
+
}
|
|
3152
|
+
if (options.pagination?.cursor || options.pagination?.direction) {
|
|
3153
|
+
throw new Error("useQuery: cursor and direction are not supported by virtual query windows");
|
|
3154
|
+
}
|
|
3155
|
+
const initialWindowSize = isPaginated ? normalizeWindowSize(options.pagination?.limit) : void 0;
|
|
2487
3156
|
const queryKey = computeRtsQueryKey(query, {
|
|
2488
3157
|
key,
|
|
2489
3158
|
projection: options.projection,
|
|
@@ -2513,7 +3182,7 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
2513
3182
|
const seedTotalCountRaw = useMemo(() => enabled && ssrEnabled ? ssrRuntime ? ssrRuntime.getQueryTotalCount(modelName, queryKey) : peekHydratedRtsQueryTotalCount(modelName, queryKey) : void 0, [enabled, ssrEnabled, ssrRuntime, modelName, queryKey]);
|
|
2514
3183
|
const hasSeedData = Array.isArray(seedDataRaw);
|
|
2515
3184
|
const seedData = hasSeedData ? seedDataRaw : void 0;
|
|
2516
|
-
const seedPageInfo = normalizePageInfo(seedPageInfoRaw);
|
|
3185
|
+
const seedPageInfo = useMemo(() => normalizePageInfo(seedPageInfoRaw), [seedPageInfoRaw]);
|
|
2517
3186
|
const seedTotalCount = normalizeTotalCount(seedTotalCountRaw);
|
|
2518
3187
|
const seedJson = (() => {
|
|
2519
3188
|
if (!hasSeedData) return "";
|
|
@@ -2533,38 +3202,21 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
2533
3202
|
})();
|
|
2534
3203
|
const seedTotalCountStr = seedTotalCount !== void 0 ? String(seedTotalCount) : "";
|
|
2535
3204
|
const [data, setData] = useState(() => isPaginated ? void 0 : seedData);
|
|
2536
|
-
const [
|
|
2537
|
-
|
|
2538
|
-
...seedPageInfo ? {
|
|
2539
|
-
pageInfo: seedPageInfo
|
|
2540
|
-
} : {}
|
|
2541
|
-
} : null);
|
|
3205
|
+
const [paginatedData, setPaginatedData] = useState(() => isPaginated ? seedData : void 0);
|
|
3206
|
+
const [pageInfo, setPageInfo] = useState(() => isPaginated ? seedPageInfo : void 0);
|
|
2542
3207
|
const [totalCount, setTotalCount] = useState(() => isPaginated ? seedTotalCount : void 0);
|
|
2543
|
-
const [previousPages, setPreviousPages] = useState([]);
|
|
2544
|
-
const [nextPages, setNextPages] = useState([]);
|
|
2545
3208
|
const [source, setSource] = useState(() => hasSeedData ? "cache" : void 0);
|
|
2546
3209
|
const [error, setError] = useState(void 0);
|
|
2547
3210
|
const [loading, setLoading] = useState(enabled && !hasSeedData);
|
|
2548
|
-
const [pagingDirection, setPagingDirection] = useState(null);
|
|
2549
3211
|
const hasFirstReply = useRef(false);
|
|
2550
3212
|
const hasNetworkReply = useRef(false);
|
|
2551
3213
|
const lastDataJsonRef = useRef("");
|
|
2552
|
-
const
|
|
2553
|
-
const
|
|
2554
|
-
const
|
|
2555
|
-
const pagingDirectionRef = useRef(null);
|
|
3214
|
+
const pageInfoRef = useRef(seedPageInfo);
|
|
3215
|
+
const requestedCountRef = useRef(initialWindowSize ?? 1);
|
|
3216
|
+
const pagingRef = useRef(false);
|
|
2556
3217
|
useEffect(() => {
|
|
2557
|
-
|
|
2558
|
-
}, [
|
|
2559
|
-
useEffect(() => {
|
|
2560
|
-
nextPagesRef.current = nextPages;
|
|
2561
|
-
}, [nextPages]);
|
|
2562
|
-
useEffect(() => {
|
|
2563
|
-
headPageRef.current = headPage;
|
|
2564
|
-
}, [headPage]);
|
|
2565
|
-
useEffect(() => {
|
|
2566
|
-
pagingDirectionRef.current = pagingDirection;
|
|
2567
|
-
}, [pagingDirection]);
|
|
3218
|
+
pageInfoRef.current = pageInfo;
|
|
3219
|
+
}, [pageInfo]);
|
|
2568
3220
|
useEffect(() => {
|
|
2569
3221
|
if (!ssrRuntime && enabled && ssrEnabled && hasSeedData) {
|
|
2570
3222
|
consumeHydratedRtsQueryData(modelName, queryKey);
|
|
@@ -2572,13 +3224,14 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
2572
3224
|
hasFirstReply.current = hasSeedData;
|
|
2573
3225
|
hasNetworkReply.current = false;
|
|
2574
3226
|
lastDataJsonRef.current = seedJson;
|
|
3227
|
+
requestedCountRef.current = initialWindowSize ?? 1;
|
|
3228
|
+
pagingRef.current = false;
|
|
2575
3229
|
setError(void 0);
|
|
2576
|
-
setPreviousPages([]);
|
|
2577
|
-
setNextPages([]);
|
|
2578
3230
|
if (!enabled) {
|
|
2579
3231
|
setLoading(false);
|
|
2580
3232
|
setData(void 0);
|
|
2581
|
-
|
|
3233
|
+
setPaginatedData(void 0);
|
|
3234
|
+
setPageInfo(void 0);
|
|
2582
3235
|
setTotalCount(void 0);
|
|
2583
3236
|
setSource(void 0);
|
|
2584
3237
|
return;
|
|
@@ -2588,30 +3241,28 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
2588
3241
|
setLoading(false);
|
|
2589
3242
|
setSource("cache");
|
|
2590
3243
|
if (isPaginated) {
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
...seedPageInfo ? {
|
|
2594
|
-
pageInfo: seedPageInfo
|
|
2595
|
-
} : {}
|
|
2596
|
-
});
|
|
3244
|
+
setPaginatedData(nextSeedData);
|
|
3245
|
+
setPageInfo(seedPageInfo);
|
|
2597
3246
|
setTotalCount(seedTotalCount);
|
|
2598
3247
|
setData(void 0);
|
|
2599
3248
|
} else {
|
|
2600
3249
|
setData(nextSeedData);
|
|
2601
3250
|
setTotalCount(void 0);
|
|
2602
|
-
|
|
3251
|
+
setPaginatedData(void 0);
|
|
3252
|
+
setPageInfo(void 0);
|
|
2603
3253
|
}
|
|
2604
3254
|
return;
|
|
2605
3255
|
}
|
|
2606
3256
|
setData(void 0);
|
|
2607
|
-
|
|
3257
|
+
setPaginatedData(void 0);
|
|
3258
|
+
setPageInfo(void 0);
|
|
2608
3259
|
setTotalCount(void 0);
|
|
2609
3260
|
setLoading(true);
|
|
2610
|
-
}, [enabled, ssrEnabled, ssrRuntime, modelName, queryKey, hasSeedData, seedJson, seedPageInfoJson, seedTotalCountStr, isPaginated]);
|
|
3261
|
+
}, [enabled, ssrEnabled, ssrRuntime, modelName, queryKey, hasSeedData, seedData, seedJson, seedPageInfo, seedPageInfoJson, seedTotalCount, seedTotalCountStr, isPaginated, initialWindowSize]);
|
|
2611
3262
|
useEffect(() => {
|
|
2612
3263
|
if (!enabled) return;
|
|
2613
|
-
const runInitialNetworkQuery = refreshOnMount || !hasSeedData;
|
|
2614
|
-
const runInitialLocalQuery = !hasSeedData
|
|
3264
|
+
const runInitialNetworkQuery = isPaginated || refreshOnMount || !hasSeedData;
|
|
3265
|
+
const runInitialLocalQuery = !hasSeedData;
|
|
2615
3266
|
const unsubscribe = registerQuery(modelName, query, {
|
|
2616
3267
|
key,
|
|
2617
3268
|
projection: options.projection,
|
|
@@ -2620,7 +3271,23 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
2620
3271
|
populate: options.populate,
|
|
2621
3272
|
pagination: options.pagination
|
|
2622
3273
|
}, (err, result, context) => {
|
|
2623
|
-
if (context.source === "cache" &&
|
|
3274
|
+
if (context.source === "cache" && context.reset) {
|
|
3275
|
+
hasFirstReply.current = false;
|
|
3276
|
+
hasNetworkReply.current = false;
|
|
3277
|
+
lastDataJsonRef.current = "";
|
|
3278
|
+
pageInfoRef.current = void 0;
|
|
3279
|
+
requestedCountRef.current = initialWindowSize ?? 1;
|
|
3280
|
+
pagingRef.current = false;
|
|
3281
|
+
setData(void 0);
|
|
3282
|
+
setPaginatedData(void 0);
|
|
3283
|
+
setPageInfo(void 0);
|
|
3284
|
+
setTotalCount(void 0);
|
|
3285
|
+
setSource(void 0);
|
|
3286
|
+
setError(void 0);
|
|
3287
|
+
setLoading(true);
|
|
3288
|
+
return;
|
|
3289
|
+
}
|
|
3290
|
+
if (context.source === "cache" && hasNetworkReply.current && (!isPaginated || !context.window || context.window.requestedCount <= requestedCountRef.current)) return;
|
|
2624
3291
|
if (context.source === "network") {
|
|
2625
3292
|
hasNetworkReply.current = true;
|
|
2626
3293
|
}
|
|
@@ -2636,10 +3303,15 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
2636
3303
|
hasFirstReply.current = true;
|
|
2637
3304
|
const nextPageInfo = context.pageInfo;
|
|
2638
3305
|
const nextTotalCount = context.totalCount;
|
|
3306
|
+
const nextRequestedCount = context.window?.requestedCount;
|
|
3307
|
+
if (isPaginated && nextRequestedCount !== void 0) {
|
|
3308
|
+
requestedCountRef.current = nextRequestedCount;
|
|
3309
|
+
}
|
|
2639
3310
|
const payloadForHash = isPaginated ? {
|
|
2640
3311
|
result,
|
|
2641
3312
|
pageInfo: nextPageInfo,
|
|
2642
|
-
totalCount: nextTotalCount
|
|
3313
|
+
totalCount: nextTotalCount,
|
|
3314
|
+
requestedCount: nextRequestedCount
|
|
2643
3315
|
} : result;
|
|
2644
3316
|
let nextJson = "";
|
|
2645
3317
|
try {
|
|
@@ -2655,13 +3327,9 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
2655
3327
|
setSource(context.source);
|
|
2656
3328
|
setError(void 0);
|
|
2657
3329
|
if (isPaginated) {
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
pageInfo: nextPageInfo
|
|
2662
|
-
} : {}
|
|
2663
|
-
});
|
|
2664
|
-
setTotalCount((current) => nextTotalCount === void 0 ? current : nextTotalCount);
|
|
3330
|
+
setPaginatedData(result);
|
|
3331
|
+
setPageInfo(nextPageInfo);
|
|
3332
|
+
setTotalCount(nextTotalCount);
|
|
2665
3333
|
return;
|
|
2666
3334
|
}
|
|
2667
3335
|
setData(result);
|
|
@@ -2681,6 +3349,11 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
2681
3349
|
} : {},
|
|
2682
3350
|
...seedTotalCount !== void 0 ? {
|
|
2683
3351
|
totalCount: seedTotalCount
|
|
3352
|
+
} : {},
|
|
3353
|
+
...initialWindowSize ? {
|
|
3354
|
+
window: {
|
|
3355
|
+
requestedCount: initialWindowSize
|
|
3356
|
+
}
|
|
2684
3357
|
} : {}
|
|
2685
3358
|
}
|
|
2686
3359
|
}
|
|
@@ -2689,45 +3362,18 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
2689
3362
|
return () => {
|
|
2690
3363
|
unsubscribe?.();
|
|
2691
3364
|
};
|
|
2692
|
-
}, [enabled, modelName, queryKey, queryJson, projectionJson, sortJson, limitStr, populateJson, paginationJson, hasSeedData, refreshOnMount, isPaginated]);
|
|
2693
|
-
const effectivePageInfo = useMemo(() => {
|
|
2694
|
-
if (!isPaginated) return void 0;
|
|
2695
|
-
const firstPageInfo = previousPages.length > 0 ? previousPages[0]?.pageInfo : headPage?.pageInfo;
|
|
2696
|
-
const lastPageInfo = nextPages.length > 0 ? nextPages[nextPages.length - 1]?.pageInfo : headPage?.pageInfo;
|
|
2697
|
-
if (!firstPageInfo && !lastPageInfo) return void 0;
|
|
2698
|
-
const hasPrevPage = Boolean(firstPageInfo?.hasPrevPage);
|
|
2699
|
-
const hasNextPage = Boolean(lastPageInfo?.hasNextPage);
|
|
2700
|
-
const prevCursor = firstPageInfo?.prevCursor;
|
|
2701
|
-
const nextCursor = lastPageInfo?.nextCursor;
|
|
2702
|
-
return {
|
|
2703
|
-
hasPrevPage,
|
|
2704
|
-
hasNextPage,
|
|
2705
|
-
...prevCursor ? {
|
|
2706
|
-
prevCursor
|
|
2707
|
-
} : {},
|
|
2708
|
-
...nextCursor ? {
|
|
2709
|
-
nextCursor
|
|
2710
|
-
} : {}
|
|
2711
|
-
};
|
|
2712
|
-
}, [headPage, isPaginated, nextPages, previousPages]);
|
|
2713
|
-
const mergedPaginatedData = useMemo(() => {
|
|
2714
|
-
if (!isPaginated) return void 0;
|
|
2715
|
-
if (!headPage && previousPages.length === 0 && nextPages.length === 0) return void 0;
|
|
2716
|
-
return flattenLoadedPages(previousPages, headPage, nextPages);
|
|
2717
|
-
}, [headPage, isPaginated, nextPages, previousPages]);
|
|
3365
|
+
}, [enabled, modelName, queryKey, queryJson, projectionJson, sortJson, limitStr, populateJson, paginationJson, hasSeedData, refreshOnMount, isPaginated, initialWindowSize]);
|
|
2718
3366
|
const fetchNext = async () => {
|
|
2719
3367
|
if (!enabled || !isPaginated || !options.pagination) return false;
|
|
2720
|
-
if (
|
|
2721
|
-
const
|
|
2722
|
-
const
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
if (!cursor || !hasNextPage_0) return false;
|
|
2726
|
-
setPagingDirection("next");
|
|
3368
|
+
if (pagingRef.current || !pageInfoRef.current?.hasNextPage) return false;
|
|
3369
|
+
const pageSize = initialWindowSize ?? normalizeWindowSize(options.pagination.limit);
|
|
3370
|
+
const nextRequestedCount_0 = Math.min(RTS_QUERY_WINDOW_MAX_COUNT, requestedCountRef.current + pageSize);
|
|
3371
|
+
if (nextRequestedCount_0 === requestedCountRef.current) return false;
|
|
3372
|
+
pagingRef.current = true;
|
|
2727
3373
|
setLoading(true);
|
|
2728
3374
|
setError(void 0);
|
|
2729
3375
|
try {
|
|
2730
|
-
|
|
3376
|
+
return await setQueryWindowSize({
|
|
2731
3377
|
modelName,
|
|
2732
3378
|
query,
|
|
2733
3379
|
options: {
|
|
@@ -2736,91 +3382,47 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
2736
3382
|
sort: options.sort,
|
|
2737
3383
|
limit: options.limit,
|
|
2738
3384
|
populate: options.populate,
|
|
2739
|
-
pagination:
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
cursor
|
|
2743
|
-
}
|
|
2744
|
-
}
|
|
3385
|
+
pagination: options.pagination
|
|
3386
|
+
},
|
|
3387
|
+
requestedCount: nextRequestedCount_0
|
|
2745
3388
|
});
|
|
2746
|
-
if (!Array.isArray(response.data)) return false;
|
|
2747
|
-
const page = {
|
|
2748
|
-
nodes: response.data,
|
|
2749
|
-
...response.context.source === "network" && response.context.pageInfo ? {
|
|
2750
|
-
pageInfo: response.context.pageInfo
|
|
2751
|
-
} : {}
|
|
2752
|
-
};
|
|
2753
|
-
setSource("network");
|
|
2754
|
-
if (response.context.source === "network" && response.context.totalCount !== void 0) {
|
|
2755
|
-
setTotalCount(response.context.totalCount);
|
|
2756
|
-
}
|
|
2757
|
-
setNextPages((current_0) => [...current_0, page]);
|
|
2758
|
-
return true;
|
|
2759
3389
|
} catch (err_0) {
|
|
2760
3390
|
setError(err_0);
|
|
2761
3391
|
return false;
|
|
2762
3392
|
} finally {
|
|
2763
|
-
|
|
3393
|
+
pagingRef.current = false;
|
|
2764
3394
|
setLoading(false);
|
|
2765
3395
|
}
|
|
2766
3396
|
};
|
|
2767
3397
|
const fetchPrevious = async () => {
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
if (!cursor_0 || !hasPrevPage_0) return false;
|
|
2775
|
-
setPagingDirection("prev");
|
|
3398
|
+
return false;
|
|
3399
|
+
};
|
|
3400
|
+
const resetPagination = () => {
|
|
3401
|
+
if (!enabled || !isPaginated || !options.pagination || !initialWindowSize) return;
|
|
3402
|
+
if (pagingRef.current || requestedCountRef.current === initialWindowSize) return;
|
|
3403
|
+
pagingRef.current = true;
|
|
2776
3404
|
setLoading(true);
|
|
2777
3405
|
setError(void 0);
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
}
|
|
2793
|
-
}
|
|
2794
|
-
});
|
|
2795
|
-
if (!Array.isArray(response_0.data)) return false;
|
|
2796
|
-
const page_0 = {
|
|
2797
|
-
nodes: response_0.data,
|
|
2798
|
-
...response_0.context.source === "network" && response_0.context.pageInfo ? {
|
|
2799
|
-
pageInfo: response_0.context.pageInfo
|
|
2800
|
-
} : {}
|
|
2801
|
-
};
|
|
2802
|
-
setSource("network");
|
|
2803
|
-
if (response_0.context.source === "network" && response_0.context.totalCount !== void 0) {
|
|
2804
|
-
setTotalCount(response_0.context.totalCount);
|
|
2805
|
-
}
|
|
2806
|
-
setPreviousPages((current_1) => [page_0, ...current_1]);
|
|
2807
|
-
return true;
|
|
2808
|
-
} catch (err_1) {
|
|
2809
|
-
setError(err_1);
|
|
2810
|
-
return false;
|
|
2811
|
-
} finally {
|
|
2812
|
-
setPagingDirection(null);
|
|
3406
|
+
void setQueryWindowSize({
|
|
3407
|
+
modelName,
|
|
3408
|
+
query,
|
|
3409
|
+
options: {
|
|
3410
|
+
key,
|
|
3411
|
+
projection: options.projection,
|
|
3412
|
+
sort: options.sort,
|
|
3413
|
+
limit: options.limit,
|
|
3414
|
+
populate: options.populate,
|
|
3415
|
+
pagination: options.pagination
|
|
3416
|
+
},
|
|
3417
|
+
requestedCount: initialWindowSize
|
|
3418
|
+
}).finally(() => {
|
|
3419
|
+
pagingRef.current = false;
|
|
2813
3420
|
setLoading(false);
|
|
2814
|
-
}
|
|
2815
|
-
};
|
|
2816
|
-
const resetPagination = () => {
|
|
2817
|
-
if (!isPaginated) return;
|
|
2818
|
-
setPreviousPages([]);
|
|
2819
|
-
setNextPages([]);
|
|
3421
|
+
});
|
|
2820
3422
|
};
|
|
2821
|
-
return
|
|
2822
|
-
data: isPaginated ?
|
|
2823
|
-
pageInfo:
|
|
3423
|
+
return {
|
|
3424
|
+
data: isPaginated ? paginatedData : data,
|
|
3425
|
+
pageInfo: isPaginated ? pageInfo : void 0,
|
|
2824
3426
|
totalCount: isPaginated ? totalCount : void 0,
|
|
2825
3427
|
source,
|
|
2826
3428
|
error,
|
|
@@ -2828,7 +3430,7 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
2828
3430
|
fetchNext,
|
|
2829
3431
|
fetchPrevious,
|
|
2830
3432
|
resetPagination
|
|
2831
|
-
}
|
|
3433
|
+
};
|
|
2832
3434
|
};
|
|
2833
3435
|
export {
|
|
2834
3436
|
registerQuery as A,
|
|
@@ -2869,4 +3471,4 @@ export {
|
|
|
2869
3471
|
onMessage as y,
|
|
2870
3472
|
onRtsMessage as z
|
|
2871
3473
|
};
|
|
2872
|
-
//# sourceMappingURL=useQuery-
|
|
3474
|
+
//# sourceMappingURL=useQuery-DZqYIJog.js.map
|