@rpcbase/client 0.382.0 → 0.384.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.
@@ -3,12 +3,26 @@ import { jsx } from "react/jsx-runtime";
3
3
  const STATIC_RPCBASE_RTS_HYDRATION_DATA_KEY = "__staticRpcbaseRtsHydrationData";
4
4
  const RtsSsrRuntimeContext = createContext(null);
5
5
  const hydrationDataStore = /* @__PURE__ */ new Map();
6
+ const hydrationPageInfoStore = /* @__PURE__ */ new Map();
6
7
  const makeStoreKey = (modelName, queryKey) => `${modelName}.${queryKey}`;
7
8
  const normalizeStringOrNull = (value) => {
8
9
  if (typeof value !== "string") return null;
9
10
  const normalized = value.trim();
10
11
  return normalized ? normalized : null;
11
12
  };
13
+ const normalizePageInfo$2 = (value) => {
14
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
15
+ const raw = value;
16
+ if (typeof raw.hasNextPage !== "boolean" || typeof raw.hasPrevPage !== "boolean") return void 0;
17
+ const nextCursor = typeof raw.nextCursor === "string" && raw.nextCursor ? raw.nextCursor : void 0;
18
+ const prevCursor = typeof raw.prevCursor === "string" && raw.prevCursor ? raw.prevCursor : void 0;
19
+ return {
20
+ hasNextPage: raw.hasNextPage,
21
+ hasPrevPage: raw.hasPrevPage,
22
+ ...nextCursor ? { nextCursor } : {},
23
+ ...prevCursor ? { prevCursor } : {}
24
+ };
25
+ };
12
26
  const parseHydrationData = (value) => {
13
27
  if (!value || typeof value !== "object") return null;
14
28
  const raw = value;
@@ -22,10 +36,12 @@ const parseHydrationData = (value) => {
22
36
  const queryKey = normalizeStringOrNull(query.queryKey);
23
37
  if (!modelName || !queryKey) continue;
24
38
  if (!Array.isArray(query.data)) continue;
39
+ const pageInfo = normalizePageInfo$2(query.pageInfo);
25
40
  queries.push({
26
41
  modelName,
27
42
  queryKey,
28
- data: query.data
43
+ data: query.data,
44
+ ...pageInfo ? { pageInfo } : {}
29
45
  });
30
46
  }
31
47
  return {
@@ -43,18 +59,26 @@ const hydrateRtsFromWindow = () => {
43
59
  const parsed = parseHydrationData(raw);
44
60
  if (!parsed) return;
45
61
  hydrationDataStore.clear();
62
+ hydrationPageInfoStore.clear();
46
63
  for (const query of parsed.queries) {
47
64
  hydrationDataStore.set(makeStoreKey(query.modelName, query.queryKey), query.data);
65
+ hydrationPageInfoStore.set(makeStoreKey(query.modelName, query.queryKey), query.pageInfo);
48
66
  }
49
67
  };
50
68
  const peekHydratedRtsQueryData = (modelName, queryKey) => {
51
69
  return hydrationDataStore.get(makeStoreKey(modelName, queryKey));
52
70
  };
71
+ const peekHydratedRtsQueryPageInfo = (modelName, queryKey) => {
72
+ return hydrationPageInfoStore.get(makeStoreKey(modelName, queryKey));
73
+ };
53
74
  const consumeHydratedRtsQueryData = (modelName, queryKey) => {
54
- hydrationDataStore.delete(makeStoreKey(modelName, queryKey));
75
+ const key = makeStoreKey(modelName, queryKey);
76
+ hydrationDataStore.delete(key);
77
+ hydrationPageInfoStore.delete(key);
55
78
  };
56
79
  const clearHydratedRtsQueryData = () => {
57
80
  hydrationDataStore.clear();
81
+ hydrationPageInfoStore.clear();
58
82
  };
59
83
  const RtsSsrRuntimeProvider = ({
60
84
  value,
@@ -394,7 +418,8 @@ const computeRtsQueryKey = (query, options) => {
394
418
  const sort = options.sort ? JSON.stringify(options.sort) : "";
395
419
  const limit = typeof options.limit === "number" ? String(options.limit) : "";
396
420
  const populate = options.populate ? JSON.stringify(options.populate) : "";
397
- return `${key}${JSON.stringify(query)}${projection}${sort}${limit}${populate}`;
421
+ const pagination = options.pagination ? JSON.stringify(options.pagination) : "";
422
+ return `${key}${JSON.stringify(query)}${projection}${sort}${limit}${populate}${pagination}`;
398
423
  };
399
424
  const TENANT_ID_QUERY_PARAM = "rb-tenant-id";
400
425
  const RTS_CHANGES_ROUTE = "/api/rb/rts/changes";
@@ -488,15 +513,31 @@ const isDocWithId = (doc) => {
488
513
  if (!doc || typeof doc !== "object") return false;
489
514
  return typeof doc._id === "string";
490
515
  };
516
+ const normalizePageInfo$1 = (value) => {
517
+ if (!value || typeof value !== "object") return void 0;
518
+ if (Array.isArray(value)) return void 0;
519
+ const raw = value;
520
+ if (typeof raw.hasNextPage !== "boolean" || typeof raw.hasPrevPage !== "boolean") return void 0;
521
+ const nextCursor = typeof raw.nextCursor === "string" && raw.nextCursor ? raw.nextCursor : void 0;
522
+ const prevCursor = typeof raw.prevCursor === "string" && raw.prevCursor ? raw.prevCursor : void 0;
523
+ return {
524
+ hasNextPage: raw.hasNextPage,
525
+ hasPrevPage: raw.hasPrevPage,
526
+ ...nextCursor ? { nextCursor } : {},
527
+ ...prevCursor ? { prevCursor } : {}
528
+ };
529
+ };
491
530
  const handleQueryPayload = (payload) => {
492
531
  const { modelName, queryKey, data, error, txnId } = payload;
493
532
  const cbKey = `${modelName}.${queryKey}`;
494
533
  const callbacks = queryCallbacks.get(cbKey);
495
534
  if (!callbacks || !callbacks.size) return;
496
535
  const subscription = subscriptions.get(cbKey);
536
+ const pageInfo = normalizePageInfo$1(payload.pageInfo);
497
537
  const hasPopulate = Boolean(subscription?.options?.populate);
538
+ const hasPagination = Boolean(subscription?.options?.pagination || pageInfo);
498
539
  const isLocal = !!(txnId && localTxnBuf.includes(txnId));
499
- const context = { source: "network", isLocal, txnId };
540
+ const context = { source: "network", isLocal, txnId, ...pageInfo ? { pageInfo } : {} };
500
541
  if (error) {
501
542
  for (const cb of callbacks) cb(error, void 0, context);
502
543
  return;
@@ -506,6 +547,7 @@ const handleQueryPayload = (payload) => {
506
547
  const docs = Array.isArray(data) ? data.filter(isDocWithId) : [];
507
548
  if (!docs.length) return;
508
549
  if (hasPopulate) return;
550
+ if (hasPagination) return;
509
551
  void updateDocs(modelName, docs, currentUid).catch(() => {
510
552
  });
511
553
  };
@@ -750,11 +792,12 @@ const registerQuery = (modelName, query, optionsOrCallback, callbackMaybe, behav
750
792
  const runInitialNetworkQuery = behavior?.runInitialNetworkQuery !== false;
751
793
  const runInitialLocalQuery = behavior?.runInitialLocalQuery !== false;
752
794
  const hasPopulate = Boolean(options.populate);
795
+ const hasPagination = Boolean(options.pagination);
753
796
  const set = queryCallbacks.get(cbKey) ?? /* @__PURE__ */ new Set();
754
797
  set.add(callback);
755
798
  queryCallbacks.set(cbKey, set);
756
799
  subscriptions.set(cbKey, { modelName, query, options, queryKey, runInitialNetworkQuery });
757
- if (currentUid && runInitialLocalQuery && !hasPopulate) {
800
+ if (currentUid && runInitialLocalQuery && !hasPopulate && !hasPagination) {
758
801
  void runQuery({
759
802
  modelName,
760
803
  query,
@@ -780,6 +823,57 @@ const registerQuery = (modelName, query, optionsOrCallback, callbackMaybe, behav
780
823
  }
781
824
  };
782
825
  };
826
+ const makeRunQueryKey = () => `run-query.${Date.now().toString(36)}.${Math.random().toString(36).slice(2, 10)}`;
827
+ const runNetworkQuery = async ({
828
+ modelName,
829
+ query,
830
+ options = {},
831
+ timeoutMs = 1e4
832
+ }) => {
833
+ if (typeof modelName !== "string" || modelName.trim().length === 0) {
834
+ throw new Error("runNetworkQuery: modelName must be a non-empty string");
835
+ }
836
+ if (!socket || socket.readyState !== WebSocket.OPEN) {
837
+ throw new Error("runNetworkQuery: RTS socket is not connected");
838
+ }
839
+ const resolvedOptions = options.key ? options : { ...options, key: makeRunQueryKey() };
840
+ const queryKey = computeRtsQueryKey(query, resolvedOptions);
841
+ const cbKey = `${modelName}.${queryKey}`;
842
+ return await new Promise((resolve, reject) => {
843
+ let settled = false;
844
+ let timeoutId = null;
845
+ const cleanup = () => {
846
+ const callbacks2 = queryCallbacks.get(cbKey);
847
+ callbacks2?.delete(callback);
848
+ if (callbacks2 && callbacks2.size === 0) queryCallbacks.delete(cbKey);
849
+ if (timeoutId !== null && typeof window !== "undefined") {
850
+ window.clearTimeout(timeoutId);
851
+ }
852
+ };
853
+ const settle = (next) => {
854
+ if (settled) return;
855
+ settled = true;
856
+ cleanup();
857
+ next();
858
+ };
859
+ const callback = (error, data, context) => {
860
+ if (error) {
861
+ settle(() => reject(error));
862
+ return;
863
+ }
864
+ settle(() => resolve({ data, context }));
865
+ };
866
+ const callbacks = queryCallbacks.get(cbKey) ?? /* @__PURE__ */ new Set();
867
+ callbacks.add(callback);
868
+ queryCallbacks.set(cbKey, callbacks);
869
+ if (typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0) {
870
+ timeoutId = window.setTimeout(() => {
871
+ settle(() => reject(new Error("runNetworkQuery: request timed out")));
872
+ }, timeoutMs);
873
+ }
874
+ sendToServer({ type: "run-query", modelName, queryKey, query, options: resolvedOptions });
875
+ });
876
+ };
783
877
  const sendMessage = (event, payload) => {
784
878
  sendToServer({ type: "event", event, payload });
785
879
  };
@@ -793,6 +887,43 @@ const onMessage = (event, callback) => {
793
887
  if (callbacks && callbacks.size === 0) messageCallbacks.delete(event);
794
888
  };
795
889
  };
890
+ const normalizePageInfo = (value) => {
891
+ if (!value || typeof value !== "object") return void 0;
892
+ if (Array.isArray(value)) return void 0;
893
+ const raw = value;
894
+ if (typeof raw.hasNextPage !== "boolean" || typeof raw.hasPrevPage !== "boolean") return void 0;
895
+ const nextCursor = typeof raw.nextCursor === "string" && raw.nextCursor ? raw.nextCursor : void 0;
896
+ const prevCursor = typeof raw.prevCursor === "string" && raw.prevCursor ? raw.prevCursor : void 0;
897
+ return {
898
+ hasNextPage: raw.hasNextPage,
899
+ hasPrevPage: raw.hasPrevPage,
900
+ ...nextCursor ? { nextCursor } : {},
901
+ ...prevCursor ? { prevCursor } : {}
902
+ };
903
+ };
904
+ const getDocId = (doc) => {
905
+ if (!doc || typeof doc !== "object") return "";
906
+ const id = doc._id;
907
+ return typeof id === "string" ? id.trim() : "";
908
+ };
909
+ const dedupeById = (docs) => {
910
+ const seen = /* @__PURE__ */ new Set();
911
+ const merged = [];
912
+ for (const doc of docs) {
913
+ const id = getDocId(doc);
914
+ if (id && seen.has(id)) continue;
915
+ if (id) seen.add(id);
916
+ merged.push(doc);
917
+ }
918
+ return merged;
919
+ };
920
+ const flattenLoadedPages = (previousPages, headPage, nextPages) => {
921
+ const merged = [];
922
+ for (const page of previousPages) merged.push(...page.nodes);
923
+ if (headPage) merged.push(...headPage.nodes);
924
+ for (const page of nextPages) merged.push(...page.nodes);
925
+ return dedupeById(merged);
926
+ };
796
927
  const useQuery = (modelName, query = {}, options = {}) => {
797
928
  if (typeof modelName !== "string" || modelName.trim().length === 0) {
798
929
  throw new Error("useQuery: modelName must be a non-empty string");
@@ -807,13 +938,16 @@ const useQuery = (modelName, query = {}, options = {}) => {
807
938
  const sortJson = options.sort ? JSON.stringify(options.sort) : "";
808
939
  const limitStr = typeof options.limit === "number" ? String(options.limit) : "";
809
940
  const populateJson = options.populate ? JSON.stringify(options.populate) : "";
941
+ const paginationJson = options.pagination ? JSON.stringify(options.pagination) : "";
810
942
  const hasPopulate = Boolean(options.populate);
943
+ const isPaginated = Boolean(options.pagination);
811
944
  const queryKey = computeRtsQueryKey(query, {
812
945
  key,
813
946
  projection: options.projection,
814
947
  sort: options.sort,
815
948
  limit: options.limit,
816
- populate: options.populate
949
+ populate: options.populate,
950
+ pagination: options.pagination
817
951
  });
818
952
  const ssrRuntime = useRtsSsrRuntime();
819
953
  if (enabled && ssrEnabled && ssrRuntime) {
@@ -825,7 +959,8 @@ const useQuery = (modelName, query = {}, options = {}) => {
825
959
  projection: options.projection,
826
960
  sort: options.sort,
827
961
  limit: options.limit,
828
- populate: options.populate
962
+ populate: options.populate,
963
+ pagination: options.pagination
829
964
  },
830
965
  queryKey
831
966
  });
@@ -834,8 +969,13 @@ const useQuery = (modelName, query = {}, options = {}) => {
834
969
  () => enabled && ssrEnabled ? ssrRuntime ? ssrRuntime.getQueryData(modelName, queryKey) : peekHydratedRtsQueryData(modelName, queryKey) : void 0,
835
970
  [enabled, ssrEnabled, ssrRuntime, modelName, queryKey]
836
971
  );
972
+ const seedPageInfoRaw = useMemo(
973
+ () => enabled && ssrEnabled ? ssrRuntime ? ssrRuntime.getQueryPageInfo(modelName, queryKey) : peekHydratedRtsQueryPageInfo(modelName, queryKey) : void 0,
974
+ [enabled, ssrEnabled, ssrRuntime, modelName, queryKey]
975
+ );
837
976
  const hasSeedData = Array.isArray(seedDataRaw);
838
977
  const seedData = hasSeedData ? seedDataRaw : void 0;
978
+ const seedPageInfo = normalizePageInfo(seedPageInfoRaw);
839
979
  const seedJson = (() => {
840
980
  if (!hasSeedData) return "";
841
981
  try {
@@ -844,13 +984,33 @@ const useQuery = (modelName, query = {}, options = {}) => {
844
984
  return "";
845
985
  }
846
986
  })();
847
- const [data, setData] = useState(() => seedData);
987
+ const [data, setData] = useState(() => isPaginated ? void 0 : seedData);
988
+ const [headPage, setHeadPage] = useState(() => isPaginated && seedData ? { nodes: seedData, ...seedPageInfo ? { pageInfo: seedPageInfo } : {} } : null);
989
+ const [previousPages, setPreviousPages] = useState([]);
990
+ const [nextPages, setNextPages] = useState([]);
848
991
  const [source, setSource] = useState(() => hasSeedData ? "cache" : void 0);
849
992
  const [error, setError] = useState(void 0);
850
993
  const [loading, setLoading] = useState(enabled && !hasSeedData);
994
+ const [pagingDirection, setPagingDirection] = useState(null);
851
995
  const hasFirstReply = useRef(false);
852
996
  const hasNetworkReply = useRef(false);
853
997
  const lastDataJsonRef = useRef("");
998
+ const previousPagesRef = useRef([]);
999
+ const nextPagesRef = useRef([]);
1000
+ const headPageRef = useRef(null);
1001
+ const pagingDirectionRef = useRef(null);
1002
+ useEffect(() => {
1003
+ previousPagesRef.current = previousPages;
1004
+ }, [previousPages]);
1005
+ useEffect(() => {
1006
+ nextPagesRef.current = nextPages;
1007
+ }, [nextPages]);
1008
+ useEffect(() => {
1009
+ headPageRef.current = headPage;
1010
+ }, [headPage]);
1011
+ useEffect(() => {
1012
+ pagingDirectionRef.current = pagingDirection;
1013
+ }, [pagingDirection]);
854
1014
  useEffect(() => {
855
1015
  if (!ssrRuntime && enabled && ssrEnabled && hasSeedData) {
856
1016
  consumeHydratedRtsQueryData(modelName, queryKey);
@@ -859,24 +1019,39 @@ const useQuery = (modelName, query = {}, options = {}) => {
859
1019
  hasNetworkReply.current = false;
860
1020
  lastDataJsonRef.current = seedJson;
861
1021
  setError(void 0);
1022
+ setPreviousPages([]);
1023
+ setNextPages([]);
862
1024
  if (!enabled) {
863
1025
  setLoading(false);
864
1026
  setData(void 0);
1027
+ setHeadPage(null);
865
1028
  setSource(void 0);
866
1029
  return;
867
1030
  }
868
1031
  if (hasSeedData) {
1032
+ const nextSeedData = seedData;
869
1033
  setLoading(false);
870
- setData(seedData);
871
1034
  setSource("cache");
1035
+ if (isPaginated) {
1036
+ setHeadPage({
1037
+ nodes: nextSeedData,
1038
+ ...seedPageInfo ? { pageInfo: seedPageInfo } : {}
1039
+ });
1040
+ setData(void 0);
1041
+ } else {
1042
+ setData(nextSeedData);
1043
+ setHeadPage(null);
1044
+ }
872
1045
  return;
873
1046
  }
1047
+ setData(void 0);
1048
+ setHeadPage(null);
874
1049
  setLoading(true);
875
- }, [enabled, ssrEnabled, ssrRuntime, modelName, queryKey, hasSeedData, seedData, seedJson]);
1050
+ }, [enabled, ssrEnabled, ssrRuntime, modelName, queryKey, hasSeedData, seedData, seedJson, isPaginated, seedPageInfo]);
876
1051
  useEffect(() => {
877
1052
  if (!enabled) return;
878
1053
  const runInitialNetworkQuery = refreshOnMount || !hasSeedData;
879
- const runInitialLocalQuery = !hasSeedData && !hasPopulate;
1054
+ const runInitialLocalQuery = !hasSeedData && !hasPopulate && !isPaginated;
880
1055
  const unsubscribe = registerQuery(
881
1056
  modelName,
882
1057
  query,
@@ -885,7 +1060,8 @@ const useQuery = (modelName, query = {}, options = {}) => {
885
1060
  projection: options.projection,
886
1061
  sort: options.sort,
887
1062
  limit: options.limit,
888
- populate: options.populate
1063
+ populate: options.populate,
1064
+ pagination: options.pagination
889
1065
  },
890
1066
  (err, result, context) => {
891
1067
  if (context.source === "cache" && hasNetworkReply.current) return;
@@ -902,9 +1078,11 @@ const useQuery = (modelName, query = {}, options = {}) => {
902
1078
  return;
903
1079
  }
904
1080
  hasFirstReply.current = true;
1081
+ const networkPageInfo = context.source === "network" ? context.pageInfo : void 0;
1082
+ const payloadForHash = isPaginated ? { result, pageInfo: networkPageInfo } : result;
905
1083
  let nextJson = "";
906
1084
  try {
907
- nextJson = JSON.stringify(result);
1085
+ nextJson = JSON.stringify(payloadForHash);
908
1086
  } catch {
909
1087
  nextJson = "";
910
1088
  }
@@ -914,6 +1092,14 @@ const useQuery = (modelName, query = {}, options = {}) => {
914
1092
  }
915
1093
  lastDataJsonRef.current = nextJson;
916
1094
  setSource(context.source);
1095
+ setError(void 0);
1096
+ if (isPaginated) {
1097
+ setHeadPage({
1098
+ nodes: result,
1099
+ ...networkPageInfo ? { pageInfo: networkPageInfo } : {}
1100
+ });
1101
+ return;
1102
+ }
917
1103
  setData(result);
918
1104
  },
919
1105
  {
@@ -924,15 +1110,156 @@ const useQuery = (modelName, query = {}, options = {}) => {
924
1110
  return () => {
925
1111
  unsubscribe?.();
926
1112
  };
927
- }, [enabled, modelName, queryKey, queryJson, projectionJson, sortJson, limitStr, populateJson, hasSeedData, refreshOnMount]);
1113
+ }, [
1114
+ enabled,
1115
+ modelName,
1116
+ queryKey,
1117
+ queryJson,
1118
+ projectionJson,
1119
+ sortJson,
1120
+ limitStr,
1121
+ populateJson,
1122
+ paginationJson,
1123
+ hasSeedData,
1124
+ refreshOnMount,
1125
+ isPaginated
1126
+ ]);
1127
+ const effectivePageInfo = useMemo(() => {
1128
+ if (!isPaginated) return void 0;
1129
+ const firstPageInfo = previousPages.length > 0 ? previousPages[0]?.pageInfo : headPage?.pageInfo;
1130
+ const lastPageInfo = nextPages.length > 0 ? nextPages[nextPages.length - 1]?.pageInfo : headPage?.pageInfo;
1131
+ if (!firstPageInfo && !lastPageInfo) return void 0;
1132
+ const hasPrevPage = Boolean(firstPageInfo?.hasPrevPage);
1133
+ const hasNextPage = Boolean(lastPageInfo?.hasNextPage);
1134
+ const prevCursor = firstPageInfo?.prevCursor;
1135
+ const nextCursor = lastPageInfo?.nextCursor;
1136
+ return {
1137
+ hasPrevPage,
1138
+ hasNextPage,
1139
+ ...prevCursor ? { prevCursor } : {},
1140
+ ...nextCursor ? { nextCursor } : {}
1141
+ };
1142
+ }, [headPage, isPaginated, nextPages, previousPages]);
1143
+ const mergedPaginatedData = useMemo(() => {
1144
+ if (!isPaginated) return void 0;
1145
+ if (!headPage && previousPages.length === 0 && nextPages.length === 0) return void 0;
1146
+ return flattenLoadedPages(previousPages, headPage, nextPages);
1147
+ }, [headPage, isPaginated, nextPages, previousPages]);
1148
+ const fetchNext = async () => {
1149
+ if (!enabled || !isPaginated || !options.pagination) return false;
1150
+ if (pagingDirectionRef.current) return false;
1151
+ const currentHead = headPageRef.current;
1152
+ const currentNextPages = nextPagesRef.current;
1153
+ const cursor = currentNextPages.length > 0 ? currentNextPages[currentNextPages.length - 1]?.pageInfo?.nextCursor : currentHead?.pageInfo?.nextCursor;
1154
+ const hasNextPage = currentNextPages.length > 0 ? Boolean(currentNextPages[currentNextPages.length - 1]?.pageInfo?.hasNextPage) : Boolean(currentHead?.pageInfo?.hasNextPage);
1155
+ if (!cursor || !hasNextPage) return false;
1156
+ setPagingDirection("next");
1157
+ setLoading(true);
1158
+ setError(void 0);
1159
+ try {
1160
+ const response = await runNetworkQuery({
1161
+ modelName,
1162
+ query,
1163
+ options: {
1164
+ key,
1165
+ projection: options.projection,
1166
+ sort: options.sort,
1167
+ limit: options.limit,
1168
+ populate: options.populate,
1169
+ pagination: {
1170
+ ...options.pagination,
1171
+ direction: "next",
1172
+ cursor
1173
+ }
1174
+ }
1175
+ });
1176
+ if (!Array.isArray(response.data)) return false;
1177
+ const page = {
1178
+ nodes: response.data,
1179
+ ...response.context.source === "network" && response.context.pageInfo ? { pageInfo: response.context.pageInfo } : {}
1180
+ };
1181
+ setSource("network");
1182
+ setNextPages((current) => [...current, page]);
1183
+ return true;
1184
+ } catch (err) {
1185
+ setError(err);
1186
+ return false;
1187
+ } finally {
1188
+ setPagingDirection(null);
1189
+ setLoading(false);
1190
+ }
1191
+ };
1192
+ const fetchPrevious = async () => {
1193
+ if (!enabled || !isPaginated || !options.pagination) return false;
1194
+ if (pagingDirectionRef.current) return false;
1195
+ const currentHead = headPageRef.current;
1196
+ const currentPreviousPages = previousPagesRef.current;
1197
+ const cursor = currentPreviousPages.length > 0 ? currentPreviousPages[0]?.pageInfo?.prevCursor : currentHead?.pageInfo?.prevCursor;
1198
+ const hasPrevPage = currentPreviousPages.length > 0 ? Boolean(currentPreviousPages[0]?.pageInfo?.hasPrevPage) : Boolean(currentHead?.pageInfo?.hasPrevPage);
1199
+ if (!cursor || !hasPrevPage) return false;
1200
+ setPagingDirection("prev");
1201
+ setLoading(true);
1202
+ setError(void 0);
1203
+ try {
1204
+ const response = await runNetworkQuery({
1205
+ modelName,
1206
+ query,
1207
+ options: {
1208
+ key,
1209
+ projection: options.projection,
1210
+ sort: options.sort,
1211
+ limit: options.limit,
1212
+ populate: options.populate,
1213
+ pagination: {
1214
+ ...options.pagination,
1215
+ direction: "prev",
1216
+ cursor
1217
+ }
1218
+ }
1219
+ });
1220
+ if (!Array.isArray(response.data)) return false;
1221
+ const page = {
1222
+ nodes: response.data,
1223
+ ...response.context.source === "network" && response.context.pageInfo ? { pageInfo: response.context.pageInfo } : {}
1224
+ };
1225
+ setSource("network");
1226
+ setPreviousPages((current) => [page, ...current]);
1227
+ return true;
1228
+ } catch (err) {
1229
+ setError(err);
1230
+ return false;
1231
+ } finally {
1232
+ setPagingDirection(null);
1233
+ setLoading(false);
1234
+ }
1235
+ };
1236
+ const resetPagination = () => {
1237
+ if (!isPaginated) return;
1238
+ setPreviousPages([]);
1239
+ setNextPages([]);
1240
+ };
928
1241
  return useMemo(
929
1242
  () => ({
930
- data,
1243
+ data: isPaginated ? mergedPaginatedData : data,
1244
+ pageInfo: effectivePageInfo,
931
1245
  source,
932
1246
  error,
933
- loading
1247
+ loading,
1248
+ fetchNext,
1249
+ fetchPrevious,
1250
+ resetPagination
934
1251
  }),
935
- [data, source, error, loading]
1252
+ [
1253
+ data,
1254
+ effectivePageInfo,
1255
+ error,
1256
+ fetchNext,
1257
+ fetchPrevious,
1258
+ isPaginated,
1259
+ loading,
1260
+ mergedPaginatedData,
1261
+ source
1262
+ ]
936
1263
  );
937
1264
  };
938
1265
  export {
@@ -949,14 +1276,16 @@ export {
949
1276
  disconnect as i,
950
1277
  reconnect as j,
951
1278
  registerQuery as k,
952
- syncRtsChanges as l,
953
- hydrateRtsFromWindow as m,
954
- clearHydratedRtsQueryData as n,
1279
+ runNetworkQuery as l,
1280
+ syncRtsChanges as m,
1281
+ hydrateRtsFromWindow as n,
955
1282
  onMessage as o,
956
- peekHydratedRtsQueryData as p,
957
- useQuery as q,
1283
+ clearHydratedRtsQueryData as p,
1284
+ peekHydratedRtsQueryData as q,
958
1285
  resetRtsPouchStore as r,
959
1286
  sendMessage as s,
960
- updateDocs as u
1287
+ peekHydratedRtsQueryPageInfo as t,
1288
+ updateDocs as u,
1289
+ useQuery as v
961
1290
  };
962
- //# sourceMappingURL=useQuery-CalZ2p2a.js.map
1291
+ //# sourceMappingURL=useQuery-Ce_EmI2F.js.map