@multiplatform.one/frappe 7.7.6 → 7.10.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.
Files changed (182) hide show
  1. package/README.md +31 -1
  2. package/dist/cjs/auth.native.js.map +1 -1
  3. package/dist/cjs/call.native.js.map +1 -1
  4. package/dist/cjs/collection.cjs +4 -1
  5. package/dist/cjs/collection.native.js +4 -1
  6. package/dist/cjs/collection.native.js.map +1 -1
  7. package/dist/cjs/common/types.native.js.map +1 -1
  8. package/dist/cjs/core/http.native.js.map +1 -1
  9. package/dist/cjs/core/types.native.js.map +1 -1
  10. package/dist/cjs/core/wire.native.js.map +1 -1
  11. package/dist/cjs/db.native.js.map +1 -1
  12. package/dist/cjs/devtools/FrappeDevtoolsPanel.native.js.map +1 -1
  13. package/dist/cjs/devtools/index.native.js.map +1 -1
  14. package/dist/cjs/devtools/plugin.native.js.map +1 -1
  15. package/dist/cjs/devtools/theme.native.js.map +1 -1
  16. package/dist/cjs/doctype.cjs +25 -8
  17. package/dist/cjs/doctype.native.js +26 -9
  18. package/dist/cjs/doctype.native.js.map +1 -1
  19. package/dist/cjs/file.native.js.map +1 -1
  20. package/dist/cjs/fixtureDb.native.js.map +1 -1
  21. package/dist/cjs/fixtures.native.js.map +1 -1
  22. package/dist/cjs/frappeApp.native.js.map +1 -1
  23. package/dist/cjs/frappeReact.cjs +1 -0
  24. package/dist/cjs/frappeReact.native.js +2 -1
  25. package/dist/cjs/frappeReact.native.js.map +1 -1
  26. package/dist/cjs/index.cjs +1 -0
  27. package/dist/cjs/index.native.js +3 -2
  28. package/dist/cjs/index.native.js.map +1 -1
  29. package/dist/cjs/optimistic.native.js.map +1 -1
  30. package/dist/cjs/pacer.cjs +1 -0
  31. package/dist/cjs/pacer.native.js +1 -0
  32. package/dist/cjs/pacer.native.js.map +1 -1
  33. package/dist/cjs/plugin/index.native.js.map +1 -1
  34. package/dist/cjs/realtime.native.js.map +1 -1
  35. package/dist/cjs/sync/backfill.native.js.map +1 -1
  36. package/dist/cjs/sync/filters.native.js.map +1 -1
  37. package/dist/cjs/sync/index.cjs +7 -0
  38. package/dist/cjs/sync/index.native.js +9 -0
  39. package/dist/cjs/sync/index.native.js.map +1 -1
  40. package/dist/cjs/sync/merge.native.js.map +1 -1
  41. package/dist/cjs/sync/mutationEngine.native.js.map +1 -1
  42. package/dist/cjs/sync/mutationJournal.native.js.map +1 -1
  43. package/dist/cjs/sync/normalizedCache.native.js.map +1 -1
  44. package/dist/cjs/sync/persistence.native.js.map +1 -1
  45. package/dist/cjs/sync/realtime.native.js.map +1 -1
  46. package/dist/cjs/sync/rehydration.native.js.map +1 -1
  47. package/dist/cjs/sync/storage.native.js.map +1 -1
  48. package/dist/cjs/sync/subscriptionManager.cjs +96 -54
  49. package/dist/cjs/sync/subscriptionManager.native.js +136 -77
  50. package/dist/cjs/sync/subscriptionManager.native.js.map +1 -1
  51. package/dist/cjs/sync/types.cjs +3 -1
  52. package/dist/cjs/sync/types.native.js +3 -1
  53. package/dist/cjs/sync/types.native.js.map +1 -1
  54. package/dist/cjs/sync/virtualPageManager.native.js.map +1 -1
  55. package/dist/cjs/useLiveQuery.native.js.map +1 -1
  56. package/dist/cjs/util.native.js.map +1 -1
  57. package/dist/esm/auth.native.js.map +1 -1
  58. package/dist/esm/call.native.js.map +1 -1
  59. package/dist/esm/collection.mjs +5 -2
  60. package/dist/esm/collection.mjs.map +1 -1
  61. package/dist/esm/collection.native.js +5 -2
  62. package/dist/esm/collection.native.js.map +1 -1
  63. package/dist/esm/common/types.native.js.map +1 -1
  64. package/dist/esm/core/http.native.js.map +1 -1
  65. package/dist/esm/core/types.native.js.map +1 -1
  66. package/dist/esm/core/wire.native.js.map +1 -1
  67. package/dist/esm/db.native.js.map +1 -1
  68. package/dist/esm/devtools/FrappeDevtoolsPanel.native.js.map +1 -1
  69. package/dist/esm/devtools/index.native.js.map +1 -1
  70. package/dist/esm/devtools/plugin.native.js.map +1 -1
  71. package/dist/esm/devtools/theme.native.js.map +1 -1
  72. package/dist/esm/doctype.mjs +25 -8
  73. package/dist/esm/doctype.mjs.map +1 -1
  74. package/dist/esm/doctype.native.js +26 -9
  75. package/dist/esm/doctype.native.js.map +1 -1
  76. package/dist/esm/file.native.js.map +1 -1
  77. package/dist/esm/fixtureDb.native.js.map +1 -1
  78. package/dist/esm/fixtures.native.js.map +1 -1
  79. package/dist/esm/frappeApp.native.js.map +1 -1
  80. package/dist/esm/frappeReact.mjs +1 -0
  81. package/dist/esm/frappeReact.mjs.map +1 -1
  82. package/dist/esm/frappeReact.native.js +1 -0
  83. package/dist/esm/frappeReact.native.js.map +1 -1
  84. package/dist/esm/index.mjs +2 -2
  85. package/dist/esm/index.mjs.map +1 -1
  86. package/dist/esm/index.native.js +2 -2
  87. package/dist/esm/index.native.js.map +1 -1
  88. package/dist/esm/optimistic.native.js.map +1 -1
  89. package/dist/esm/pacer.mjs +1 -0
  90. package/dist/esm/pacer.mjs.map +1 -1
  91. package/dist/esm/pacer.native.js +1 -0
  92. package/dist/esm/pacer.native.js.map +1 -1
  93. package/dist/esm/plugin/index.native.js.map +1 -1
  94. package/dist/esm/realtime.native.js.map +1 -1
  95. package/dist/esm/sync/backfill.native.js.map +1 -1
  96. package/dist/esm/sync/filters.native.js.map +1 -1
  97. package/dist/esm/sync/index.mjs +7 -0
  98. package/dist/esm/sync/index.mjs.map +1 -1
  99. package/dist/esm/sync/index.native.js +9 -0
  100. package/dist/esm/sync/index.native.js.map +1 -1
  101. package/dist/esm/sync/merge.native.js.map +1 -1
  102. package/dist/esm/sync/mutationEngine.native.js.map +1 -1
  103. package/dist/esm/sync/mutationJournal.native.js.map +1 -1
  104. package/dist/esm/sync/normalizedCache.native.js.map +1 -1
  105. package/dist/esm/sync/persistence.native.js.map +1 -1
  106. package/dist/esm/sync/realtime.native.js.map +1 -1
  107. package/dist/esm/sync/rehydration.native.js.map +1 -1
  108. package/dist/esm/sync/storage.native.js.map +1 -1
  109. package/dist/esm/sync/subscriptionManager.mjs +97 -55
  110. package/dist/esm/sync/subscriptionManager.mjs.map +1 -1
  111. package/dist/esm/sync/subscriptionManager.native.js +137 -78
  112. package/dist/esm/sync/subscriptionManager.native.js.map +1 -1
  113. package/dist/esm/sync/types.mjs +2 -1
  114. package/dist/esm/sync/types.mjs.map +1 -1
  115. package/dist/esm/sync/types.native.js +2 -1
  116. package/dist/esm/sync/types.native.js.map +1 -1
  117. package/dist/esm/sync/virtualPageManager.native.js.map +1 -1
  118. package/dist/esm/useLiveQuery.native.js.map +1 -1
  119. package/dist/esm/util.native.js.map +1 -1
  120. package/dist/jsx/collection.mjs +5 -2
  121. package/dist/jsx/collection.mjs.map +1 -1
  122. package/dist/jsx/collection.native.js +4 -1
  123. package/dist/jsx/collection.native.js.map +1 -1
  124. package/dist/jsx/doctype.mjs +25 -8
  125. package/dist/jsx/doctype.mjs.map +1 -1
  126. package/dist/jsx/doctype.native.js +26 -9
  127. package/dist/jsx/doctype.native.js.map +1 -1
  128. package/dist/jsx/frappeReact.mjs +1 -0
  129. package/dist/jsx/frappeReact.mjs.map +1 -1
  130. package/dist/jsx/frappeReact.native.js +1 -0
  131. package/dist/jsx/frappeReact.native.js.map +1 -1
  132. package/dist/jsx/index.js +2 -2
  133. package/dist/jsx/index.js.map +1 -1
  134. package/dist/jsx/index.mjs +2 -2
  135. package/dist/jsx/index.mjs.map +1 -1
  136. package/dist/jsx/index.native.js +1 -0
  137. package/dist/jsx/index.native.js.map +1 -1
  138. package/dist/jsx/pacer.mjs +1 -0
  139. package/dist/jsx/pacer.mjs.map +1 -1
  140. package/dist/jsx/pacer.native.js +1 -0
  141. package/dist/jsx/pacer.native.js.map +1 -1
  142. package/dist/jsx/sync/index.mjs +7 -0
  143. package/dist/jsx/sync/index.mjs.map +1 -1
  144. package/dist/jsx/sync/index.native.js +9 -0
  145. package/dist/jsx/sync/index.native.js.map +1 -1
  146. package/dist/jsx/sync/subscriptionManager.mjs +97 -55
  147. package/dist/jsx/sync/subscriptionManager.mjs.map +1 -1
  148. package/dist/jsx/sync/subscriptionManager.native.js +136 -77
  149. package/dist/jsx/sync/subscriptionManager.native.js.map +1 -1
  150. package/dist/jsx/sync/types.mjs +2 -1
  151. package/dist/jsx/sync/types.mjs.map +1 -1
  152. package/dist/jsx/sync/types.native.js +3 -1
  153. package/dist/jsx/sync/types.native.js.map +1 -1
  154. package/package.json +6 -6
  155. package/src/collection.ts +29 -4
  156. package/src/collectionLimitParity.spec.ts +135 -0
  157. package/src/devtools/FrappeDevtoolsPanel.spec.tsx +4 -2
  158. package/src/doctype.ts +47 -15
  159. package/src/frappeReact.ts +11 -2
  160. package/src/index.ts +6 -2
  161. package/src/pacer.ts +8 -3
  162. package/src/sync/index.ts +12 -0
  163. package/src/sync/refreshSubscriptions.lifecycle.spec.ts +268 -0
  164. package/src/sync/refreshSubscriptions.spec.ts +295 -0
  165. package/src/sync/subscriptionManager.spec.ts +41 -2
  166. package/src/sync/subscriptionManager.ts +115 -55
  167. package/src/sync/types.ts +10 -0
  168. package/types/collection.d.ts +24 -2
  169. package/types/collection.d.ts.map +1 -1
  170. package/types/doctype.d.ts.map +1 -1
  171. package/types/frappeReact.d.ts +6 -2
  172. package/types/frappeReact.d.ts.map +1 -1
  173. package/types/index.d.ts +2 -2
  174. package/types/index.d.ts.map +1 -1
  175. package/types/pacer.d.ts +6 -2
  176. package/types/pacer.d.ts.map +1 -1
  177. package/types/sync/index.d.ts +4 -0
  178. package/types/sync/index.d.ts.map +1 -1
  179. package/types/sync/subscriptionManager.d.ts +13 -10
  180. package/types/sync/subscriptionManager.d.ts.map +1 -1
  181. package/types/sync/types.d.ts +9 -0
  182. package/types/sync/types.d.ts.map +1 -1
@@ -30,6 +30,7 @@ var import_filters = require("./filters.cjs");
30
30
  var import_types = require("./types.cjs");
31
31
  var import_virtualPageManager = require("./virtualPageManager.cjs");
32
32
  class SubscriptionManager {
33
+ refreshes = /* @__PURE__ */new Map();
33
34
  subscriptions = /* @__PURE__ */new Map();
34
35
  virtualPageManager;
35
36
  backfillManager;
@@ -82,6 +83,7 @@ class SubscriptionManager {
82
83
  cursor,
83
84
  checkpoint
84
85
  } = await this.fetchInitialRows(query);
86
+ this.seedRows(query, rows);
85
87
  const subscription = {
86
88
  id: subscriptionId,
87
89
  query,
@@ -96,8 +98,8 @@ class SubscriptionManager {
96
98
  subscription.boundaries = {
97
99
  firstItem: rows[0],
98
100
  lastItem: rows[rows.length - 1],
99
- offset: query.limitStart || 0,
100
- pageSize: query.limit || 20
101
+ offset: query.limitStart ?? 0,
102
+ pageSize: query.limit ?? import_types.defaultPageLength
101
103
  };
102
104
  }
103
105
  subscription.metadata = {
@@ -116,9 +118,89 @@ class SubscriptionManager {
116
118
  checkpoint
117
119
  };
118
120
  }
121
+ async refreshSubscriptions(options = {}) {
122
+ const subscriptions = [...this.subscriptions.values()].filter(subscription => (this.subRefCounts.get(subscription.id) ?? 0) > 0 && (!options.doctypes || options.doctypes.includes(subscription.query.doctype)));
123
+ return Promise.all(subscriptions.map(subscription => this.refreshSubscription(subscription)));
124
+ }
125
+ refreshSubscription(subscription) {
126
+ const subscriptionId = subscription.id;
127
+ if (subscription.query.progressive) {
128
+ return Promise.resolve({
129
+ subscriptionId,
130
+ ok: false,
131
+ error: new Error("Snapshot refresh does not support progressive subscriptions")
132
+ });
133
+ }
134
+ const existing = this.refreshes.get(subscriptionId);
135
+ if (existing) {
136
+ existing.requested = true;
137
+ return existing.promise;
138
+ }
139
+ const state = {
140
+ requested: false,
141
+ promise: Promise.resolve({
142
+ subscriptionId,
143
+ ok: false
144
+ })
145
+ };
146
+ const active = () => this.refreshes.get(subscriptionId) === state && this.subscriptions.get(subscriptionId) === subscription && (this.subRefCounts.get(subscriptionId) ?? 0) > 0;
147
+ state.promise = Promise.resolve().then(async () => {
148
+ try {
149
+ while (true) {
150
+ state.requested = false;
151
+ try {
152
+ const {
153
+ rows,
154
+ cursor,
155
+ checkpoint
156
+ } = await this.fetchInitialRows(subscription.query);
157
+ if (!active()) {
158
+ return {
159
+ subscriptionId,
160
+ ok: false,
161
+ error: new Error("Subscription is no longer active")
162
+ };
163
+ }
164
+ if (state.requested) continue;
165
+ this.seedRows(subscription.query, rows);
166
+ subscription.docIds = rows.map(row => row.name);
167
+ subscription.cursor = cursor;
168
+ subscription.checkpoint = checkpoint;
169
+ subscription.boundaries = rows.length ? {
170
+ firstItem: rows[0],
171
+ lastItem: rows[rows.length - 1],
172
+ offset: subscription.query.limitStart ?? 0,
173
+ pageSize: subscription.query.limit ?? import_types.defaultPageLength
174
+ } : void 0;
175
+ subscription.metadata = {
176
+ itemsBeforePage: 0,
177
+ itemsAfterPage: 0
178
+ };
179
+ subscription.stale = false;
180
+ return {
181
+ subscriptionId,
182
+ ok: true
183
+ };
184
+ } catch (error) {
185
+ if (active() && state.requested) continue;
186
+ if (active()) subscription.stale = true;
187
+ return {
188
+ subscriptionId,
189
+ ok: false,
190
+ error
191
+ };
192
+ }
193
+ }
194
+ } finally {
195
+ if (this.refreshes.get(subscriptionId) === state) this.refreshes.delete(subscriptionId);
196
+ }
197
+ });
198
+ this.refreshes.set(subscriptionId, state);
199
+ return state.promise;
200
+ }
119
201
  /**
120
202
  * Performs the initial subscription fetch (single doc via getDoc, lists via
121
- * getDocList), seeds the normalized cache, and computes the CDC checkpoint
203
+ * getDocList) and computes the CDC checkpoint
122
204
  * as the max `modified` across returned rows. Shared by fresh subscribes
123
205
  * and adopted-subscription refreshes so both have identical semantics.
124
206
  */
@@ -145,10 +227,8 @@ class SubscriptionManager {
145
227
  filters: query.filters,
146
228
  orderBy: query.orderBy
147
229
  };
148
- if (query.limit != null) {
149
- listOptions.limit = query.limit;
150
- if (query.limitStart != null) listOptions.limitStart = query.limitStart;
151
- }
230
+ listOptions.limit = query.limit ?? import_types.defaultPageLength;
231
+ if (query.limitStart != null) listOptions.limitStart = query.limitStart;
152
232
  if (this.options.useCursorPagination) listOptions.cursor = void 0;
153
233
  const response = await this.db.getDocList(query.doctype, listOptions);
154
234
  if (typeof response === "object" && response !== null && "data" in response) {
@@ -158,10 +238,6 @@ class SubscriptionManager {
158
238
  rows = response;
159
239
  }
160
240
  }
161
- for (const row of rows) {
162
- if (!row.doctype) row.doctype = query.doctype;
163
- this.normalizedCache.upsert(row);
164
- }
165
241
  let checkpoint = void 0;
166
242
  for (const row of rows) {
167
243
  if (!row.modified) continue;
@@ -173,6 +249,12 @@ class SubscriptionManager {
173
249
  checkpoint
174
250
  };
175
251
  }
252
+ seedRows(query, rows) {
253
+ for (const row of rows) {
254
+ if (!row.doctype) row.doctype = query.doctype;
255
+ this.normalizedCache.upsert(row);
256
+ }
257
+ }
176
258
  /**
177
259
  * Re-adopts a subscription restored from a persisted snapshot when an
178
260
  * identical query subscribes: the cached membership renders immediately and
@@ -190,7 +272,7 @@ class SubscriptionManager {
190
272
  if (!subscription) return void 0;
191
273
  this.queryKeyToSubId.set(queryKey, restoredId);
192
274
  this.subRefCounts.set(restoredId, 1);
193
- const refresh = this.refreshAdoptedSubscription(subscription);
275
+ const refresh = this.refreshSubscription(subscription);
194
276
  const rows = this.getDocsForSubscription(restoredId);
195
277
  return {
196
278
  subscriptionId: restoredId,
@@ -199,48 +281,6 @@ class SubscriptionManager {
199
281
  refresh
200
282
  };
201
283
  }
202
- /**
203
- * Network refresh for an adopted subscription with fresh-subscribe
204
- * semantics: an authoritative page fetch replaces membership and recomputes
205
- * the checkpoint (identical to what a brand-new subscribe would produce).
206
- * On failure (offline) the cached membership and the restored CDC
207
- * checkpoint are kept and the subscription is marked stale — the next
208
- * backfill trigger drains changes from that checkpoint. Never rejects.
209
- */
210
- async refreshAdoptedSubscription(subscription) {
211
- try {
212
- const {
213
- rows,
214
- cursor,
215
- checkpoint
216
- } = await this.fetchInitialRows(subscription.query);
217
- subscription.checkpoint = checkpoint;
218
- subscription.cursor = cursor;
219
- subscription.docIds = rows.map(row => row.name);
220
- if (rows.length > 0) {
221
- subscription.boundaries = {
222
- firstItem: rows[0],
223
- lastItem: rows[rows.length - 1],
224
- offset: subscription.query.limitStart || 0,
225
- pageSize: subscription.query.limit || 20
226
- };
227
- }
228
- subscription.metadata = {
229
- itemsBeforePage: 0,
230
- itemsAfterPage: 0
231
- };
232
- subscription.stale = false;
233
- return {
234
- ok: true
235
- };
236
- } catch (error) {
237
- subscription.stale = true;
238
- return {
239
- ok: false,
240
- error
241
- };
242
- }
243
- }
244
284
  /**
245
285
  * Registers a subscription restored from a persisted snapshot. Restored
246
286
  * subscriptions are dormant: they hold the persisted query, CDC checkpoint,
@@ -315,6 +355,7 @@ class SubscriptionManager {
315
355
  this.subRefCounts.set(subscriptionId, refCount);
316
356
  return;
317
357
  }
358
+ this.refreshes.delete(subscriptionId);
318
359
  this.subRefCounts.delete(subscriptionId);
319
360
  let queryKey;
320
361
  for (const [key, id] of this.queryKeyToSubId) {
@@ -640,6 +681,7 @@ class SubscriptionManager {
640
681
  return name1 < name2 ? -1 : name1 > name2 ? 1 : 0;
641
682
  }
642
683
  clear() {
684
+ this.refreshes.clear();
643
685
  this.subscriptions.clear();
644
686
  this.queryKeyToSubId.clear();
645
687
  this.subRefCounts.clear();
@@ -75,6 +75,7 @@ var SubscriptionManager = /* @__PURE__ */function () {
75
75
  function SubscriptionManager2(db, normalizedCache) {
76
76
  var options = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {};
77
77
  _class_call_check(this, SubscriptionManager2);
78
+ _define_property(this, "refreshes", /* @__PURE__ */new Map());
78
79
  _define_property(this, "subscriptions", /* @__PURE__ */new Map());
79
80
  _define_property(this, "virtualPageManager", void 0);
80
81
  _define_property(this, "backfillManager", void 0);
@@ -119,6 +120,7 @@ var SubscriptionManager = /* @__PURE__ */function () {
119
120
  cursor,
120
121
  checkpoint: checkpoint1
121
122
  } = await this.fetchInitialRows(query);
123
+ this.seedRows(query, rows1);
122
124
  var subscription = {
123
125
  id: subscriptionId,
124
126
  query,
@@ -132,11 +134,12 @@ var SubscriptionManager = /* @__PURE__ */function () {
132
134
  tombstones: /* @__PURE__ */new Map()
133
135
  };
134
136
  if (rows1.length > 0) {
137
+ var _query_limitStart, _query_limit;
135
138
  subscription.boundaries = {
136
139
  firstItem: rows1[0],
137
140
  lastItem: rows1[rows1.length - 1],
138
- offset: query.limitStart || 0,
139
- pageSize: query.limit || 20
141
+ offset: (_query_limitStart = query.limitStart) !== null && _query_limitStart !== void 0 ? _query_limitStart : 0,
142
+ pageSize: (_query_limit = query.limit) !== null && _query_limit !== void 0 ? _query_limit : import_types.defaultPageLength
140
143
  };
141
144
  }
142
145
  subscription.metadata = {
@@ -155,12 +158,110 @@ var SubscriptionManager = /* @__PURE__ */function () {
155
158
  checkpoint: checkpoint1
156
159
  };
157
160
  }
161
+ }, {
162
+ key: "refreshSubscriptions",
163
+ value: async function refreshSubscriptions() {
164
+ var _this = this;
165
+ var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
166
+ var subscriptions = [...this.subscriptions.values()].filter(function (subscription) {
167
+ var _this_subRefCounts_get;
168
+ return ((_this_subRefCounts_get = _this.subRefCounts.get(subscription.id)) !== null && _this_subRefCounts_get !== void 0 ? _this_subRefCounts_get : 0) > 0 && (!options.doctypes || options.doctypes.includes(subscription.query.doctype));
169
+ });
170
+ return Promise.all(subscriptions.map(function (subscription) {
171
+ return _this.refreshSubscription(subscription);
172
+ }));
173
+ }
174
+ }, {
175
+ key: "refreshSubscription",
176
+ value: function refreshSubscription(subscription) {
177
+ var _this = this;
178
+ var subscriptionId = subscription.id;
179
+ if (subscription.query.progressive) {
180
+ return Promise.resolve({
181
+ subscriptionId,
182
+ ok: false,
183
+ error: new Error("Snapshot refresh does not support progressive subscriptions")
184
+ });
185
+ }
186
+ var existing = this.refreshes.get(subscriptionId);
187
+ if (existing) {
188
+ existing.requested = true;
189
+ return existing.promise;
190
+ }
191
+ var state = {
192
+ requested: false,
193
+ promise: Promise.resolve({
194
+ subscriptionId,
195
+ ok: false
196
+ })
197
+ };
198
+ var active = function active2() {
199
+ var _this_subRefCounts_get;
200
+ return _this.refreshes.get(subscriptionId) === state && _this.subscriptions.get(subscriptionId) === subscription && ((_this_subRefCounts_get = _this.subRefCounts.get(subscriptionId)) !== null && _this_subRefCounts_get !== void 0 ? _this_subRefCounts_get : 0) > 0;
201
+ };
202
+ state.promise = Promise.resolve().then(async function () {
203
+ try {
204
+ while (true) {
205
+ state.requested = false;
206
+ try {
207
+ var _subscription_query_limitStart, _subscription_query_limit;
208
+ var {
209
+ rows,
210
+ cursor,
211
+ checkpoint
212
+ } = await _this.fetchInitialRows(subscription.query);
213
+ if (!active()) {
214
+ return {
215
+ subscriptionId,
216
+ ok: false,
217
+ error: new Error("Subscription is no longer active")
218
+ };
219
+ }
220
+ if (state.requested) continue;
221
+ _this.seedRows(subscription.query, rows);
222
+ subscription.docIds = rows.map(function (row) {
223
+ return row.name;
224
+ });
225
+ subscription.cursor = cursor;
226
+ subscription.checkpoint = checkpoint;
227
+ subscription.boundaries = rows.length ? {
228
+ firstItem: rows[0],
229
+ lastItem: rows[rows.length - 1],
230
+ offset: (_subscription_query_limitStart = subscription.query.limitStart) !== null && _subscription_query_limitStart !== void 0 ? _subscription_query_limitStart : 0,
231
+ pageSize: (_subscription_query_limit = subscription.query.limit) !== null && _subscription_query_limit !== void 0 ? _subscription_query_limit : import_types.defaultPageLength
232
+ } : void 0;
233
+ subscription.metadata = {
234
+ itemsBeforePage: 0,
235
+ itemsAfterPage: 0
236
+ };
237
+ subscription.stale = false;
238
+ return {
239
+ subscriptionId,
240
+ ok: true
241
+ };
242
+ } catch (error) {
243
+ if (active() && state.requested) continue;
244
+ if (active()) subscription.stale = true;
245
+ return {
246
+ subscriptionId,
247
+ ok: false,
248
+ error
249
+ };
250
+ }
251
+ }
252
+ } finally {
253
+ if (_this.refreshes.get(subscriptionId) === state) _this.refreshes.delete(subscriptionId);
254
+ }
255
+ });
256
+ this.refreshes.set(subscriptionId, state);
257
+ return state.promise;
258
+ }
158
259
  }, {
159
260
  key: "fetchInitialRows",
160
261
  value: (
161
262
  /**
162
263
  * Performs the initial subscription fetch (single doc via getDoc, lists via
163
- * getDocList), seeds the normalized cache, and computes the CDC checkpoint
264
+ * getDocList) and computes the CDC checkpoint
164
265
  * as the max `modified` across returned rows. Shared by fresh subscribes
165
266
  * and adopted-subscription refreshes so both have identical semantics.
166
267
  */
@@ -183,15 +284,14 @@ var SubscriptionManager = /* @__PURE__ */function () {
183
284
  }
184
285
  }
185
286
  } else {
287
+ var _query_limit;
186
288
  var listOptions = {
187
289
  fields: queryFields,
188
290
  filters: query.filters,
189
291
  orderBy: query.orderBy
190
292
  };
191
- if (query.limit != null) {
192
- listOptions.limit = query.limit;
193
- if (query.limitStart != null) listOptions.limitStart = query.limitStart;
194
- }
293
+ listOptions.limit = (_query_limit = query.limit) !== null && _query_limit !== void 0 ? _query_limit : import_types.defaultPageLength;
294
+ if (query.limitStart != null) listOptions.limitStart = query.limitStart;
195
295
  if (this.options.useCursorPagination) listOptions.cursor = void 0;
196
296
  var response = await this.db.getDocList(query.doctype, listOptions);
197
297
  if ((typeof response === "undefined" ? "undefined" : _type_of(response)) === "object" && response !== null && "data" in response) {
@@ -201,14 +301,15 @@ var SubscriptionManager = /* @__PURE__ */function () {
201
301
  rows = response;
202
302
  }
203
303
  }
304
+ var checkpoint = void 0;
204
305
  var _iteratorNormalCompletion = true,
205
306
  _didIteratorError = false,
206
307
  _iteratorError = void 0;
207
308
  try {
208
309
  for (var _iterator = rows[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
209
310
  var row = _step.value;
210
- if (!row.doctype) row.doctype = query.doctype;
211
- this.normalizedCache.upsert(row);
311
+ if (!row.modified) continue;
312
+ if (!checkpoint || row.modified > checkpoint) checkpoint = row.modified;
212
313
  }
213
314
  } catch (err) {
214
315
  _didIteratorError = true;
@@ -224,36 +325,39 @@ var SubscriptionManager = /* @__PURE__ */function () {
224
325
  }
225
326
  }
226
327
  }
227
- var checkpoint = void 0;
228
- var _iteratorNormalCompletion1 = true,
229
- _didIteratorError1 = false,
230
- _iteratorError1 = void 0;
328
+ return {
329
+ rows,
330
+ cursor,
331
+ checkpoint
332
+ };
333
+ })
334
+ }, {
335
+ key: "seedRows",
336
+ value: function seedRows(query, rows) {
337
+ var _iteratorNormalCompletion = true,
338
+ _didIteratorError = false,
339
+ _iteratorError = void 0;
231
340
  try {
232
- for (var _iterator1 = rows[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true) {
233
- var row1 = _step1.value;
234
- if (!row1.modified) continue;
235
- if (!checkpoint || row1.modified > checkpoint) checkpoint = row1.modified;
341
+ for (var _iterator = rows[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
342
+ var row = _step.value;
343
+ if (!row.doctype) row.doctype = query.doctype;
344
+ this.normalizedCache.upsert(row);
236
345
  }
237
346
  } catch (err) {
238
- _didIteratorError1 = true;
239
- _iteratorError1 = err;
347
+ _didIteratorError = true;
348
+ _iteratorError = err;
240
349
  } finally {
241
350
  try {
242
- if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
243
- _iterator1.return();
351
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
352
+ _iterator.return();
244
353
  }
245
354
  } finally {
246
- if (_didIteratorError1) {
247
- throw _iteratorError1;
355
+ if (_didIteratorError) {
356
+ throw _iteratorError;
248
357
  }
249
358
  }
250
359
  }
251
- return {
252
- rows,
253
- cursor,
254
- checkpoint
255
- };
256
- })
360
+ }
257
361
  }, {
258
362
  key: "adoptRestoredSubscription",
259
363
  value: (
@@ -274,7 +378,7 @@ var SubscriptionManager = /* @__PURE__ */function () {
274
378
  if (!subscription) return void 0;
275
379
  this.queryKeyToSubId.set(queryKey, restoredId);
276
380
  this.subRefCounts.set(restoredId, 1);
277
- var refresh = this.refreshAdoptedSubscription(subscription);
381
+ var refresh = this.refreshSubscription(subscription);
278
382
  var rows = this.getDocsForSubscription(restoredId);
279
383
  return {
280
384
  subscriptionId: restoredId,
@@ -283,53 +387,6 @@ var SubscriptionManager = /* @__PURE__ */function () {
283
387
  refresh
284
388
  };
285
389
  })
286
- }, {
287
- key: "refreshAdoptedSubscription",
288
- value: (
289
- /**
290
- * Network refresh for an adopted subscription with fresh-subscribe
291
- * semantics: an authoritative page fetch replaces membership and recomputes
292
- * the checkpoint (identical to what a brand-new subscribe would produce).
293
- * On failure (offline) the cached membership and the restored CDC
294
- * checkpoint are kept and the subscription is marked stale — the next
295
- * backfill trigger drains changes from that checkpoint. Never rejects.
296
- */
297
- async function refreshAdoptedSubscription(subscription) {
298
- try {
299
- var {
300
- rows,
301
- cursor,
302
- checkpoint
303
- } = await this.fetchInitialRows(subscription.query);
304
- subscription.checkpoint = checkpoint;
305
- subscription.cursor = cursor;
306
- subscription.docIds = rows.map(function (row) {
307
- return row.name;
308
- });
309
- if (rows.length > 0) {
310
- subscription.boundaries = {
311
- firstItem: rows[0],
312
- lastItem: rows[rows.length - 1],
313
- offset: subscription.query.limitStart || 0,
314
- pageSize: subscription.query.limit || 20
315
- };
316
- }
317
- subscription.metadata = {
318
- itemsBeforePage: 0,
319
- itemsAfterPage: 0
320
- };
321
- subscription.stale = false;
322
- return {
323
- ok: true
324
- };
325
- } catch (error) {
326
- subscription.stale = true;
327
- return {
328
- ok: false,
329
- error
330
- };
331
- }
332
- })
333
390
  }, {
334
391
  /**
335
392
  * Registers a subscription restored from a persisted snapshot. Restored
@@ -453,6 +510,7 @@ var SubscriptionManager = /* @__PURE__ */function () {
453
510
  this.subRefCounts.set(subscriptionId, refCount);
454
511
  return;
455
512
  }
513
+ this.refreshes.delete(subscriptionId);
456
514
  this.subRefCounts.delete(subscriptionId);
457
515
  var queryKey;
458
516
  var _iteratorNormalCompletion = true,
@@ -1083,6 +1141,7 @@ var SubscriptionManager = /* @__PURE__ */function () {
1083
1141
  }, {
1084
1142
  key: "clear",
1085
1143
  value: function clear() {
1144
+ this.refreshes.clear();
1086
1145
  this.subscriptions.clear();
1087
1146
  this.queryKeyToSubId.clear();
1088
1147
  this.subRefCounts.clear();