@multiplatform.one/frappe 6.1.0 → 6.4.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 (792) hide show
  1. package/README.md +38 -12
  2. package/dist/cjs/auth.cjs +1 -1
  3. package/dist/cjs/auth.native.js.map +1 -1
  4. package/dist/cjs/call.cjs +1 -1
  5. package/dist/cjs/call.native.js.map +1 -1
  6. package/dist/cjs/collection.cjs +18 -4
  7. package/dist/cjs/collection.native.js +18 -4
  8. package/dist/cjs/collection.native.js.map +1 -1
  9. package/dist/cjs/core/http.cjs +92 -9
  10. package/dist/cjs/core/http.native.js +96 -7
  11. package/dist/cjs/core/http.native.js.map +1 -1
  12. package/dist/cjs/db.cjs +7 -7
  13. package/dist/cjs/db.native.js +4 -4
  14. package/dist/cjs/db.native.js.map +1 -1
  15. package/dist/cjs/doctype.cjs +97 -39
  16. package/dist/cjs/doctype.native.js +116 -46
  17. package/dist/cjs/doctype.native.js.map +1 -1
  18. package/dist/cjs/file.cjs +1 -1
  19. package/dist/cjs/file.native.js.map +1 -1
  20. package/dist/cjs/fixtureDb.cjs +3 -2
  21. package/dist/cjs/fixtureDb.native.js +2 -1
  22. package/dist/cjs/fixtureDb.native.js.map +1 -1
  23. package/dist/cjs/frappeApp.cjs +15 -14
  24. package/dist/cjs/frappeApp.native.js +16 -14
  25. package/dist/cjs/frappeApp.native.js.map +1 -1
  26. package/dist/cjs/frappeReact.cjs +198 -18
  27. package/dist/cjs/frappeReact.native.js +241 -18
  28. package/dist/cjs/frappeReact.native.js.map +1 -1
  29. package/dist/cjs/index.cjs +9 -4
  30. package/dist/cjs/index.native.js +9 -4
  31. package/dist/cjs/index.native.js.map +1 -1
  32. package/dist/cjs/pacer.cjs +2 -2
  33. package/dist/cjs/pacer.native.js +2 -2
  34. package/dist/cjs/pacer.native.js.map +1 -1
  35. package/dist/cjs/realtime.cjs +186 -46
  36. package/dist/cjs/realtime.native.js +268 -48
  37. package/dist/cjs/realtime.native.js.map +1 -1
  38. package/dist/cjs/sync/backfill.cjs +32 -27
  39. package/dist/cjs/sync/backfill.native.js +49 -43
  40. package/dist/cjs/sync/backfill.native.js.map +1 -1
  41. package/dist/cjs/sync/index.cjs +90 -24
  42. package/dist/cjs/sync/index.native.js +112 -10
  43. package/dist/cjs/sync/index.native.js.map +1 -1
  44. package/dist/cjs/sync/merge.cjs +0 -3
  45. package/dist/cjs/sync/merge.native.js +0 -3
  46. package/dist/cjs/sync/merge.native.js.map +1 -1
  47. package/dist/cjs/sync/mutationEngine.cjs +25 -19
  48. package/dist/cjs/sync/mutationEngine.native.js +16 -13
  49. package/dist/cjs/sync/mutationEngine.native.js.map +1 -1
  50. package/dist/cjs/sync/mutationJournal.cjs +9 -4
  51. package/dist/cjs/sync/mutationJournal.native.js +7 -4
  52. package/dist/cjs/sync/mutationJournal.native.js.map +1 -1
  53. package/dist/cjs/sync/normalizedCache.cjs +7 -3
  54. package/dist/cjs/sync/normalizedCache.native.js +7 -2
  55. package/dist/cjs/sync/normalizedCache.native.js.map +1 -1
  56. package/dist/cjs/sync/persistence.cjs +63 -31
  57. package/dist/cjs/sync/persistence.native.js +120 -63
  58. package/dist/cjs/sync/persistence.native.js.map +1 -1
  59. package/dist/cjs/sync/realtime.cjs +124 -13
  60. package/dist/cjs/sync/realtime.native.js +163 -20
  61. package/dist/cjs/sync/realtime.native.js.map +1 -1
  62. package/dist/cjs/sync/rehydration.cjs +16 -10
  63. package/dist/cjs/sync/rehydration.native.js +16 -14
  64. package/dist/cjs/sync/rehydration.native.js.map +1 -1
  65. package/dist/cjs/sync/storage.cjs +3 -3
  66. package/dist/cjs/sync/storage.native.js +1 -1
  67. package/dist/cjs/sync/storage.native.js.map +1 -1
  68. package/dist/cjs/sync/subscriptionManager.cjs +255 -65
  69. package/dist/cjs/sync/subscriptionManager.native.js +330 -93
  70. package/dist/cjs/sync/subscriptionManager.native.js.map +1 -1
  71. package/dist/cjs/sync/types.cjs +2 -0
  72. package/dist/cjs/sync/types.native.js +2 -0
  73. package/dist/cjs/sync/types.native.js.map +1 -1
  74. package/dist/cjs/sync/virtualPageManager.cjs +9 -9
  75. package/dist/cjs/sync/virtualPageManager.native.js +5 -9
  76. package/dist/cjs/sync/virtualPageManager.native.js.map +1 -1
  77. package/dist/cjs/useLiveQuery.cjs +52 -0
  78. package/dist/cjs/useLiveQuery.native.js +59 -0
  79. package/dist/cjs/useLiveQuery.native.js.map +1 -0
  80. package/dist/cjs/util.cjs +11 -2
  81. package/dist/cjs/util.native.js +16 -2
  82. package/dist/cjs/util.native.js.map +1 -1
  83. package/dist/esm/auth.mjs +1 -1
  84. package/dist/esm/auth.mjs.map +1 -1
  85. package/dist/esm/auth.native.js.map +1 -1
  86. package/dist/esm/call.mjs +1 -1
  87. package/dist/esm/call.mjs.map +1 -1
  88. package/dist/esm/call.native.js.map +1 -1
  89. package/dist/esm/collection.mjs +18 -4
  90. package/dist/esm/collection.mjs.map +1 -1
  91. package/dist/esm/collection.native.js +18 -4
  92. package/dist/esm/collection.native.js.map +1 -1
  93. package/dist/esm/core/http.mjs +93 -10
  94. package/dist/esm/core/http.mjs.map +1 -1
  95. package/dist/esm/core/http.native.js +97 -8
  96. package/dist/esm/core/http.native.js.map +1 -1
  97. package/dist/esm/db.mjs +7 -7
  98. package/dist/esm/db.mjs.map +1 -1
  99. package/dist/esm/db.native.js +4 -4
  100. package/dist/esm/db.native.js.map +1 -1
  101. package/dist/esm/doctype.mjs +96 -39
  102. package/dist/esm/doctype.mjs.map +1 -1
  103. package/dist/esm/doctype.native.js +115 -46
  104. package/dist/esm/doctype.native.js.map +1 -1
  105. package/dist/esm/file.mjs +1 -1
  106. package/dist/esm/file.mjs.map +1 -1
  107. package/dist/esm/file.native.js.map +1 -1
  108. package/dist/esm/fixtureDb.mjs +3 -2
  109. package/dist/esm/fixtureDb.mjs.map +1 -1
  110. package/dist/esm/fixtureDb.native.js +2 -1
  111. package/dist/esm/fixtureDb.native.js.map +1 -1
  112. package/dist/esm/frappeApp.mjs +15 -14
  113. package/dist/esm/frappeApp.mjs.map +1 -1
  114. package/dist/esm/frappeApp.native.js +16 -14
  115. package/dist/esm/frappeApp.native.js.map +1 -1
  116. package/dist/esm/frappeReact.mjs +197 -19
  117. package/dist/esm/frappeReact.mjs.map +1 -1
  118. package/dist/esm/frappeReact.native.js +240 -19
  119. package/dist/esm/frappeReact.native.js.map +1 -1
  120. package/dist/esm/index.mjs +5 -4
  121. package/dist/esm/index.mjs.map +1 -1
  122. package/dist/esm/index.native.js +5 -4
  123. package/dist/esm/index.native.js.map +1 -1
  124. package/dist/esm/pacer.mjs +1 -1
  125. package/dist/esm/pacer.native.js +1 -1
  126. package/dist/esm/realtime.mjs +187 -47
  127. package/dist/esm/realtime.mjs.map +1 -1
  128. package/dist/esm/realtime.native.js +269 -49
  129. package/dist/esm/realtime.native.js.map +1 -1
  130. package/dist/esm/sync/backfill.mjs +32 -27
  131. package/dist/esm/sync/backfill.mjs.map +1 -1
  132. package/dist/esm/sync/backfill.native.js +49 -43
  133. package/dist/esm/sync/backfill.native.js.map +1 -1
  134. package/dist/esm/sync/index.mjs +90 -24
  135. package/dist/esm/sync/index.mjs.map +1 -1
  136. package/dist/esm/sync/index.native.js +112 -10
  137. package/dist/esm/sync/index.native.js.map +1 -1
  138. package/dist/esm/sync/merge.mjs +1 -1
  139. package/dist/esm/sync/merge.mjs.map +1 -1
  140. package/dist/esm/sync/merge.native.js +1 -1
  141. package/dist/esm/sync/merge.native.js.map +1 -1
  142. package/dist/esm/sync/mutationEngine.mjs +25 -19
  143. package/dist/esm/sync/mutationEngine.mjs.map +1 -1
  144. package/dist/esm/sync/mutationEngine.native.js +16 -13
  145. package/dist/esm/sync/mutationEngine.native.js.map +1 -1
  146. package/dist/esm/sync/mutationJournal.mjs +9 -4
  147. package/dist/esm/sync/mutationJournal.mjs.map +1 -1
  148. package/dist/esm/sync/mutationJournal.native.js +7 -4
  149. package/dist/esm/sync/mutationJournal.native.js.map +1 -1
  150. package/dist/esm/sync/normalizedCache.mjs +7 -3
  151. package/dist/esm/sync/normalizedCache.mjs.map +1 -1
  152. package/dist/esm/sync/normalizedCache.native.js +7 -2
  153. package/dist/esm/sync/normalizedCache.native.js.map +1 -1
  154. package/dist/esm/sync/persistence.mjs +64 -32
  155. package/dist/esm/sync/persistence.mjs.map +1 -1
  156. package/dist/esm/sync/persistence.native.js +121 -64
  157. package/dist/esm/sync/persistence.native.js.map +1 -1
  158. package/dist/esm/sync/realtime.mjs +124 -13
  159. package/dist/esm/sync/realtime.mjs.map +1 -1
  160. package/dist/esm/sync/realtime.native.js +163 -20
  161. package/dist/esm/sync/realtime.native.js.map +1 -1
  162. package/dist/esm/sync/rehydration.mjs +16 -10
  163. package/dist/esm/sync/rehydration.mjs.map +1 -1
  164. package/dist/esm/sync/rehydration.native.js +16 -14
  165. package/dist/esm/sync/rehydration.native.js.map +1 -1
  166. package/dist/esm/sync/storage.mjs +3 -3
  167. package/dist/esm/sync/storage.mjs.map +1 -1
  168. package/dist/esm/sync/storage.native.js +1 -1
  169. package/dist/esm/sync/storage.native.js.map +1 -1
  170. package/dist/esm/sync/subscriptionManager.mjs +255 -65
  171. package/dist/esm/sync/subscriptionManager.mjs.map +1 -1
  172. package/dist/esm/sync/subscriptionManager.native.js +330 -93
  173. package/dist/esm/sync/subscriptionManager.native.js.map +1 -1
  174. package/dist/esm/sync/types.mjs +2 -0
  175. package/dist/esm/sync/types.mjs.map +1 -1
  176. package/dist/esm/sync/types.native.js +2 -0
  177. package/dist/esm/sync/types.native.js.map +1 -1
  178. package/dist/esm/sync/virtualPageManager.mjs +9 -9
  179. package/dist/esm/sync/virtualPageManager.mjs.map +1 -1
  180. package/dist/esm/sync/virtualPageManager.native.js +5 -9
  181. package/dist/esm/sync/virtualPageManager.native.js.map +1 -1
  182. package/dist/esm/useLiveQuery.mjs +26 -0
  183. package/dist/esm/useLiveQuery.mjs.map +1 -0
  184. package/dist/esm/useLiveQuery.native.js +30 -0
  185. package/dist/esm/useLiveQuery.native.js.map +1 -0
  186. package/dist/esm/util.mjs +10 -2
  187. package/dist/esm/util.mjs.map +1 -1
  188. package/dist/esm/util.native.js +15 -2
  189. package/dist/esm/util.native.js.map +1 -1
  190. package/dist/jsx/auth.mjs +1 -1
  191. package/dist/jsx/auth.mjs.map +1 -1
  192. package/dist/jsx/auth.native.js.map +1 -1
  193. package/dist/jsx/call.mjs +1 -1
  194. package/dist/jsx/call.mjs.map +1 -1
  195. package/dist/jsx/call.native.js.map +1 -1
  196. package/dist/jsx/collection.mjs +18 -4
  197. package/dist/jsx/collection.mjs.map +1 -1
  198. package/dist/jsx/collection.native.js +18 -4
  199. package/dist/jsx/collection.native.js.map +1 -1
  200. package/dist/jsx/core/http.mjs +93 -10
  201. package/dist/jsx/core/http.mjs.map +1 -1
  202. package/dist/jsx/core/http.native.js +96 -7
  203. package/dist/jsx/core/http.native.js.map +1 -1
  204. package/dist/jsx/db.mjs +7 -7
  205. package/dist/jsx/db.mjs.map +1 -1
  206. package/dist/jsx/db.native.js +4 -4
  207. package/dist/jsx/db.native.js.map +1 -1
  208. package/dist/jsx/doctype.mjs +96 -39
  209. package/dist/jsx/doctype.mjs.map +1 -1
  210. package/dist/jsx/doctype.native.js +116 -46
  211. package/dist/jsx/doctype.native.js.map +1 -1
  212. package/dist/jsx/file.mjs +1 -1
  213. package/dist/jsx/file.mjs.map +1 -1
  214. package/dist/jsx/file.native.js.map +1 -1
  215. package/dist/jsx/fixtureDb.mjs +3 -2
  216. package/dist/jsx/fixtureDb.mjs.map +1 -1
  217. package/dist/jsx/fixtureDb.native.js +2 -1
  218. package/dist/jsx/fixtureDb.native.js.map +1 -1
  219. package/dist/jsx/frappeApp.mjs +15 -14
  220. package/dist/jsx/frappeApp.mjs.map +1 -1
  221. package/dist/jsx/frappeApp.native.js +16 -14
  222. package/dist/jsx/frappeApp.native.js.map +1 -1
  223. package/dist/jsx/frappeReact.mjs +197 -19
  224. package/dist/jsx/frappeReact.mjs.map +1 -1
  225. package/dist/jsx/frappeReact.native.js +241 -18
  226. package/dist/jsx/frappeReact.native.js.map +1 -1
  227. package/dist/jsx/index.js +5 -4
  228. package/dist/jsx/index.js.map +1 -1
  229. package/dist/jsx/index.mjs +5 -4
  230. package/dist/jsx/index.mjs.map +1 -1
  231. package/dist/jsx/index.native.js +9 -4
  232. package/dist/jsx/index.native.js.map +1 -1
  233. package/dist/jsx/pacer.mjs +1 -1
  234. package/dist/jsx/pacer.native.js +2 -2
  235. package/dist/jsx/pacer.native.js.map +1 -1
  236. package/dist/jsx/realtime.mjs +187 -47
  237. package/dist/jsx/realtime.mjs.map +1 -1
  238. package/dist/jsx/realtime.native.js +268 -48
  239. package/dist/jsx/realtime.native.js.map +1 -1
  240. package/dist/jsx/sync/backfill.mjs +32 -27
  241. package/dist/jsx/sync/backfill.mjs.map +1 -1
  242. package/dist/jsx/sync/backfill.native.js +49 -43
  243. package/dist/jsx/sync/backfill.native.js.map +1 -1
  244. package/dist/jsx/sync/index.mjs +90 -24
  245. package/dist/jsx/sync/index.mjs.map +1 -1
  246. package/dist/jsx/sync/index.native.js +112 -10
  247. package/dist/jsx/sync/index.native.js.map +1 -1
  248. package/dist/jsx/sync/merge.mjs +1 -1
  249. package/dist/jsx/sync/merge.mjs.map +1 -1
  250. package/dist/jsx/sync/merge.native.js +0 -3
  251. package/dist/jsx/sync/merge.native.js.map +1 -1
  252. package/dist/jsx/sync/mutationEngine.mjs +25 -19
  253. package/dist/jsx/sync/mutationEngine.mjs.map +1 -1
  254. package/dist/jsx/sync/mutationEngine.native.js +16 -13
  255. package/dist/jsx/sync/mutationEngine.native.js.map +1 -1
  256. package/dist/jsx/sync/mutationJournal.mjs +9 -4
  257. package/dist/jsx/sync/mutationJournal.mjs.map +1 -1
  258. package/dist/jsx/sync/mutationJournal.native.js +7 -4
  259. package/dist/jsx/sync/mutationJournal.native.js.map +1 -1
  260. package/dist/jsx/sync/normalizedCache.mjs +7 -3
  261. package/dist/jsx/sync/normalizedCache.mjs.map +1 -1
  262. package/dist/jsx/sync/normalizedCache.native.js +7 -2
  263. package/dist/jsx/sync/normalizedCache.native.js.map +1 -1
  264. package/dist/jsx/sync/persistence.mjs +64 -32
  265. package/dist/jsx/sync/persistence.mjs.map +1 -1
  266. package/dist/jsx/sync/persistence.native.js +120 -63
  267. package/dist/jsx/sync/persistence.native.js.map +1 -1
  268. package/dist/jsx/sync/realtime.mjs +124 -13
  269. package/dist/jsx/sync/realtime.mjs.map +1 -1
  270. package/dist/jsx/sync/realtime.native.js +163 -20
  271. package/dist/jsx/sync/realtime.native.js.map +1 -1
  272. package/dist/jsx/sync/rehydration.mjs +16 -10
  273. package/dist/jsx/sync/rehydration.mjs.map +1 -1
  274. package/dist/jsx/sync/rehydration.native.js +16 -14
  275. package/dist/jsx/sync/rehydration.native.js.map +1 -1
  276. package/dist/jsx/sync/storage.mjs +3 -3
  277. package/dist/jsx/sync/storage.mjs.map +1 -1
  278. package/dist/jsx/sync/storage.native.js +1 -1
  279. package/dist/jsx/sync/storage.native.js.map +1 -1
  280. package/dist/jsx/sync/subscriptionManager.mjs +255 -65
  281. package/dist/jsx/sync/subscriptionManager.mjs.map +1 -1
  282. package/dist/jsx/sync/subscriptionManager.native.js +330 -93
  283. package/dist/jsx/sync/subscriptionManager.native.js.map +1 -1
  284. package/dist/jsx/sync/types.mjs +2 -0
  285. package/dist/jsx/sync/types.mjs.map +1 -1
  286. package/dist/jsx/sync/types.native.js +2 -0
  287. package/dist/jsx/sync/types.native.js.map +1 -1
  288. package/dist/jsx/sync/virtualPageManager.mjs +9 -9
  289. package/dist/jsx/sync/virtualPageManager.mjs.map +1 -1
  290. package/dist/jsx/sync/virtualPageManager.native.js +5 -9
  291. package/dist/jsx/sync/virtualPageManager.native.js.map +1 -1
  292. package/dist/jsx/useLiveQuery.mjs +26 -0
  293. package/dist/jsx/useLiveQuery.mjs.map +1 -0
  294. package/dist/jsx/useLiveQuery.native.js +59 -0
  295. package/dist/jsx/useLiveQuery.native.js.map +1 -0
  296. package/dist/jsx/util.mjs +10 -2
  297. package/dist/jsx/util.mjs.map +1 -1
  298. package/dist/jsx/util.native.js +16 -2
  299. package/dist/jsx/util.native.js.map +1 -1
  300. package/package.json +20 -17
  301. package/src/auth.ts +5 -1
  302. package/src/call.ts +5 -1
  303. package/src/collection.spec.ts +55 -0
  304. package/src/collection.ts +33 -4
  305. package/src/core/http.spec.ts +66 -0
  306. package/src/core/http.ts +115 -9
  307. package/src/core/httpNative.spec.ts +234 -0
  308. package/src/core/types.ts +2 -0
  309. package/src/db.spec.ts +91 -51
  310. package/src/db.ts +27 -8
  311. package/src/doctype.spec.ts +247 -39
  312. package/src/doctype.ts +203 -53
  313. package/src/file.ts +5 -1
  314. package/src/fixtureDb.ts +13 -2
  315. package/src/frappeApp.ts +18 -19
  316. package/src/frappeReact.spec.ts +565 -1
  317. package/src/frappeReact.ts +445 -37
  318. package/src/frappeReactLiveQueryGc.spec.ts +320 -0
  319. package/src/frappeReactNative.spec.ts +65 -0
  320. package/src/index.ts +10 -9
  321. package/src/pacer.ts +1 -1
  322. package/src/realtime.spec.ts +464 -20
  323. package/src/realtime.ts +284 -46
  324. package/src/sync/backfill.spec.ts +43 -0
  325. package/src/sync/backfill.ts +59 -39
  326. package/src/sync/debug.spec.ts +36 -0
  327. package/src/sync/filterValidation.spec.ts +197 -0
  328. package/src/sync/index.ts +98 -7
  329. package/src/sync/merge.ts +3 -3
  330. package/src/sync/mutationEngine.spec.ts +36 -4
  331. package/src/sync/mutationEngine.ts +30 -11
  332. package/src/sync/mutationJournal.ts +18 -4
  333. package/src/sync/normalizedCache.spec.ts +102 -0
  334. package/src/sync/normalizedCache.ts +19 -3
  335. package/src/sync/offlineRestore.spec.ts +423 -0
  336. package/src/sync/persistence.spec.ts +39 -7
  337. package/src/sync/persistence.ts +90 -18
  338. package/src/sync/persistenceGjs.spec.ts +143 -0
  339. package/src/sync/persistenceNative.spec.ts +139 -0
  340. package/src/sync/realtime.spec.ts +18 -1
  341. package/src/sync/realtime.ts +161 -13
  342. package/src/sync/rehydration.ts +23 -5
  343. package/src/sync/storage.ts +5 -4
  344. package/src/sync/subscriptionManager.spec.ts +94 -0
  345. package/src/sync/subscriptionManager.ts +304 -82
  346. package/src/sync/syncModule.spec.ts +137 -0
  347. package/src/sync/types.ts +39 -0
  348. package/src/sync/virtualPageManager.ts +8 -4
  349. package/src/useLiveQuery.ts +58 -0
  350. package/src/util.spec.ts +35 -4
  351. package/src/util.ts +34 -7
  352. package/types/auth.d.ts +13 -0
  353. package/types/auth.d.ts.map +1 -0
  354. package/types/call.d.ts +10 -0
  355. package/types/call.d.ts.map +1 -0
  356. package/types/collection.d.ts +127 -0
  357. package/types/collection.d.ts.map +1 -0
  358. package/types/common/types.d.ts +35 -0
  359. package/types/common/types.d.ts.map +1 -0
  360. package/types/core/http.d.ts +86 -0
  361. package/types/core/http.d.ts.map +1 -0
  362. package/types/core/types.d.ts +74 -0
  363. package/types/core/types.d.ts.map +1 -0
  364. package/types/core/wire.d.ts +405 -0
  365. package/types/core/wire.d.ts.map +1 -0
  366. package/types/db.d.ts +244 -0
  367. package/types/db.d.ts.map +1 -0
  368. package/types/devtools/FrappeDevtoolsPanel.d.ts +7 -0
  369. package/types/devtools/FrappeDevtoolsPanel.d.ts.map +1 -0
  370. package/types/devtools/index.d.ts +4 -0
  371. package/types/devtools/index.d.ts.map +1 -0
  372. package/types/devtools/plugin.d.ts +9 -0
  373. package/types/devtools/plugin.d.ts.map +1 -0
  374. package/types/devtools/theme.d.ts +15 -0
  375. package/types/devtools/theme.d.ts.map +1 -0
  376. package/types/doctype.d.ts +256 -0
  377. package/types/doctype.d.ts.map +1 -0
  378. package/types/file.d.ts +15 -0
  379. package/types/file.d.ts.map +1 -0
  380. package/types/fixtureDb.d.ts +76 -0
  381. package/types/fixtureDb.d.ts.map +1 -0
  382. package/types/fixtures.d.ts +55 -0
  383. package/types/fixtures.d.ts.map +1 -0
  384. package/types/frappeApp.d.ts +45 -0
  385. package/types/frappeApp.d.ts.map +1 -0
  386. package/types/frappeReact.d.ts +270 -0
  387. package/types/frappeReact.d.ts.map +1 -0
  388. package/types/index.d.ts +44 -0
  389. package/types/index.d.ts.map +1 -0
  390. package/types/optimistic.d.ts +38 -0
  391. package/types/optimistic.d.ts.map +1 -0
  392. package/types/pacer.d.ts +193 -0
  393. package/types/pacer.d.ts.map +1 -0
  394. package/types/plugin/index.d.ts +11 -0
  395. package/types/plugin/index.d.ts.map +1 -0
  396. package/types/realtime.d.ts +121 -0
  397. package/types/realtime.d.ts.map +1 -0
  398. package/types/sync/backfill.d.ts +60 -0
  399. package/types/sync/backfill.d.ts.map +1 -0
  400. package/types/sync/filters.d.ts +101 -0
  401. package/types/sync/filters.d.ts.map +1 -0
  402. package/types/sync/index.d.ts +181 -0
  403. package/types/sync/index.d.ts.map +1 -0
  404. package/types/sync/merge.d.ts +59 -0
  405. package/types/sync/merge.d.ts.map +1 -0
  406. package/types/sync/mutationEngine.d.ts +117 -0
  407. package/types/sync/mutationEngine.d.ts.map +1 -0
  408. package/types/sync/mutationJournal.d.ts +60 -0
  409. package/types/sync/mutationJournal.d.ts.map +1 -0
  410. package/types/sync/normalizedCache.d.ts +59 -0
  411. package/types/sync/normalizedCache.d.ts.map +1 -0
  412. package/types/sync/persistence.d.ts +185 -0
  413. package/types/sync/persistence.d.ts.map +1 -0
  414. package/types/sync/realtime.d.ts +121 -0
  415. package/types/sync/realtime.d.ts.map +1 -0
  416. package/types/sync/rehydration.d.ts +109 -0
  417. package/types/sync/rehydration.d.ts.map +1 -0
  418. package/types/sync/storage.d.ts +65 -0
  419. package/types/sync/storage.d.ts.map +1 -0
  420. package/types/sync/subscriptionManager.d.ts +161 -0
  421. package/types/sync/subscriptionManager.d.ts.map +1 -0
  422. package/types/sync/types.d.ts +435 -0
  423. package/types/sync/types.d.ts.map +1 -0
  424. package/types/sync/virtualPageManager.d.ts +190 -0
  425. package/types/sync/virtualPageManager.d.ts.map +1 -0
  426. package/types/useLiveQuery.d.ts +16 -0
  427. package/types/useLiveQuery.d.ts.map +1 -0
  428. package/types/util.d.ts +24 -0
  429. package/types/util.d.ts.map +1 -0
  430. package/dist/cjs/auth.spec.cjs +0 -322
  431. package/dist/cjs/auth.spec.native.js +0 -329
  432. package/dist/cjs/auth.spec.native.js.map +0 -1
  433. package/dist/cjs/call.spec.cjs +0 -427
  434. package/dist/cjs/call.spec.native.js +0 -430
  435. package/dist/cjs/call.spec.native.js.map +0 -1
  436. package/dist/cjs/collection.spec.cjs +0 -186
  437. package/dist/cjs/collection.spec.native.js +0 -216
  438. package/dist/cjs/collection.spec.native.js.map +0 -1
  439. package/dist/cjs/common/types.spec.cjs +0 -266
  440. package/dist/cjs/common/types.spec.native.js +0 -271
  441. package/dist/cjs/common/types.spec.native.js.map +0 -1
  442. package/dist/cjs/core/http.spec.cjs +0 -1259
  443. package/dist/cjs/core/http.spec.native.js +0 -1401
  444. package/dist/cjs/core/http.spec.native.js.map +0 -1
  445. package/dist/cjs/core/wire.spec.cjs +0 -478
  446. package/dist/cjs/core/wire.spec.native.js +0 -482
  447. package/dist/cjs/core/wire.spec.native.js.map +0 -1
  448. package/dist/cjs/db.spec.cjs +0 -862
  449. package/dist/cjs/db.spec.native.js +0 -865
  450. package/dist/cjs/db.spec.native.js.map +0 -1
  451. package/dist/cjs/doctype.spec.cjs +0 -460
  452. package/dist/cjs/doctype.spec.native.js +0 -538
  453. package/dist/cjs/doctype.spec.native.js.map +0 -1
  454. package/dist/cjs/file.spec.cjs +0 -315
  455. package/dist/cjs/file.spec.native.js +0 -342
  456. package/dist/cjs/file.spec.native.js.map +0 -1
  457. package/dist/cjs/frappeApp.spec.cjs +0 -306
  458. package/dist/cjs/frappeApp.spec.native.js +0 -308
  459. package/dist/cjs/frappeApp.spec.native.js.map +0 -1
  460. package/dist/cjs/frappeReact.spec.cjs +0 -531
  461. package/dist/cjs/frappeReact.spec.native.js +0 -670
  462. package/dist/cjs/frappeReact.spec.native.js.map +0 -1
  463. package/dist/cjs/optimistic.spec.cjs +0 -11
  464. package/dist/cjs/optimistic.spec.native.js +0 -19
  465. package/dist/cjs/optimistic.spec.native.js.map +0 -1
  466. package/dist/cjs/pacer.spec.cjs +0 -470
  467. package/dist/cjs/pacer.spec.native.js +0 -537
  468. package/dist/cjs/pacer.spec.native.js.map +0 -1
  469. package/dist/cjs/realtime.spec.cjs +0 -326
  470. package/dist/cjs/realtime.spec.native.js +0 -392
  471. package/dist/cjs/realtime.spec.native.js.map +0 -1
  472. package/dist/cjs/sync/backfill.spec.cjs +0 -586
  473. package/dist/cjs/sync/backfill.spec.native.js +0 -712
  474. package/dist/cjs/sync/backfill.spec.native.js.map +0 -1
  475. package/dist/cjs/sync/debug.spec.cjs +0 -125
  476. package/dist/cjs/sync/debug.spec.native.js +0 -133
  477. package/dist/cjs/sync/debug.spec.native.js.map +0 -1
  478. package/dist/cjs/sync/filters.spec.cjs +0 -168
  479. package/dist/cjs/sync/filters.spec.native.js +0 -173
  480. package/dist/cjs/sync/filters.spec.native.js.map +0 -1
  481. package/dist/cjs/sync/merge.spec.cjs +0 -908
  482. package/dist/cjs/sync/merge.spec.native.js +0 -937
  483. package/dist/cjs/sync/merge.spec.native.js.map +0 -1
  484. package/dist/cjs/sync/multiOrderBy.spec.cjs +0 -165
  485. package/dist/cjs/sync/multiOrderBy.spec.native.js +0 -229
  486. package/dist/cjs/sync/multiOrderBy.spec.native.js.map +0 -1
  487. package/dist/cjs/sync/mutationEngine.spec.cjs +0 -1158
  488. package/dist/cjs/sync/mutationEngine.spec.native.js +0 -1173
  489. package/dist/cjs/sync/mutationEngine.spec.native.js.map +0 -1
  490. package/dist/cjs/sync/mutationJournal.spec.cjs +0 -330
  491. package/dist/cjs/sync/mutationJournal.spec.native.js +0 -333
  492. package/dist/cjs/sync/mutationJournal.spec.native.js.map +0 -1
  493. package/dist/cjs/sync/mutations.spec.cjs +0 -327
  494. package/dist/cjs/sync/mutations.spec.native.js +0 -330
  495. package/dist/cjs/sync/mutations.spec.native.js.map +0 -1
  496. package/dist/cjs/sync/normalizedCache.spec.cjs +0 -302
  497. package/dist/cjs/sync/normalizedCache.spec.native.js +0 -311
  498. package/dist/cjs/sync/normalizedCache.spec.native.js.map +0 -1
  499. package/dist/cjs/sync/persistence.spec.cjs +0 -562
  500. package/dist/cjs/sync/persistence.spec.native.js +0 -572
  501. package/dist/cjs/sync/persistence.spec.native.js.map +0 -1
  502. package/dist/cjs/sync/realtime.spec.cjs +0 -499
  503. package/dist/cjs/sync/realtime.spec.native.js +0 -512
  504. package/dist/cjs/sync/realtime.spec.native.js.map +0 -1
  505. package/dist/cjs/sync/rehydration.spec.cjs +0 -731
  506. package/dist/cjs/sync/rehydration.spec.native.js +0 -736
  507. package/dist/cjs/sync/rehydration.spec.native.js.map +0 -1
  508. package/dist/cjs/sync/storage.spec.cjs +0 -446
  509. package/dist/cjs/sync/storage.spec.native.js +0 -470
  510. package/dist/cjs/sync/storage.spec.native.js.map +0 -1
  511. package/dist/cjs/sync/subscriptionManager.spec.cjs +0 -1102
  512. package/dist/cjs/sync/subscriptionManager.spec.native.js +0 -1136
  513. package/dist/cjs/sync/subscriptionManager.spec.native.js.map +0 -1
  514. package/dist/cjs/sync/subscriptions.spec.cjs +0 -937
  515. package/dist/cjs/sync/subscriptions.spec.native.js +0 -969
  516. package/dist/cjs/sync/subscriptions.spec.native.js.map +0 -1
  517. package/dist/cjs/sync/syncModule.spec.cjs +0 -206
  518. package/dist/cjs/sync/syncModule.spec.native.js +0 -222
  519. package/dist/cjs/sync/syncModule.spec.native.js.map +0 -1
  520. package/dist/cjs/sync/types.spec.cjs +0 -246
  521. package/dist/cjs/sync/types.spec.native.js +0 -256
  522. package/dist/cjs/sync/types.spec.native.js.map +0 -1
  523. package/dist/cjs/sync/virtualPageManager.spec.cjs +0 -801
  524. package/dist/cjs/sync/virtualPageManager.spec.native.js +0 -873
  525. package/dist/cjs/sync/virtualPageManager.spec.native.js.map +0 -1
  526. package/dist/cjs/util.spec.cjs +0 -43
  527. package/dist/cjs/util.spec.native.js +0 -48
  528. package/dist/cjs/util.spec.native.js.map +0 -1
  529. package/dist/esm/auth.spec.mjs +0 -323
  530. package/dist/esm/auth.spec.mjs.map +0 -1
  531. package/dist/esm/auth.spec.native.js +0 -327
  532. package/dist/esm/auth.spec.native.js.map +0 -1
  533. package/dist/esm/call.spec.mjs +0 -428
  534. package/dist/esm/call.spec.mjs.map +0 -1
  535. package/dist/esm/call.spec.native.js +0 -428
  536. package/dist/esm/call.spec.native.js.map +0 -1
  537. package/dist/esm/collection.spec.mjs +0 -187
  538. package/dist/esm/collection.spec.mjs.map +0 -1
  539. package/dist/esm/collection.spec.native.js +0 -214
  540. package/dist/esm/collection.spec.native.js.map +0 -1
  541. package/dist/esm/common/types.spec.mjs +0 -267
  542. package/dist/esm/common/types.spec.mjs.map +0 -1
  543. package/dist/esm/common/types.spec.native.js +0 -269
  544. package/dist/esm/common/types.spec.native.js.map +0 -1
  545. package/dist/esm/core/http.spec.mjs +0 -1260
  546. package/dist/esm/core/http.spec.mjs.map +0 -1
  547. package/dist/esm/core/http.spec.native.js +0 -1399
  548. package/dist/esm/core/http.spec.native.js.map +0 -1
  549. package/dist/esm/core/wire.spec.mjs +0 -479
  550. package/dist/esm/core/wire.spec.mjs.map +0 -1
  551. package/dist/esm/core/wire.spec.native.js +0 -480
  552. package/dist/esm/core/wire.spec.native.js.map +0 -1
  553. package/dist/esm/db.spec.mjs +0 -863
  554. package/dist/esm/db.spec.mjs.map +0 -1
  555. package/dist/esm/db.spec.native.js +0 -863
  556. package/dist/esm/db.spec.native.js.map +0 -1
  557. package/dist/esm/doctype.spec.mjs +0 -461
  558. package/dist/esm/doctype.spec.mjs.map +0 -1
  559. package/dist/esm/doctype.spec.native.js +0 -536
  560. package/dist/esm/doctype.spec.native.js.map +0 -1
  561. package/dist/esm/file.spec.mjs +0 -316
  562. package/dist/esm/file.spec.mjs.map +0 -1
  563. package/dist/esm/file.spec.native.js +0 -340
  564. package/dist/esm/file.spec.native.js.map +0 -1
  565. package/dist/esm/frappeApp.spec.mjs +0 -307
  566. package/dist/esm/frappeApp.spec.mjs.map +0 -1
  567. package/dist/esm/frappeApp.spec.native.js +0 -306
  568. package/dist/esm/frappeApp.spec.native.js.map +0 -1
  569. package/dist/esm/frappeReact.spec.mjs +0 -532
  570. package/dist/esm/frappeReact.spec.mjs.map +0 -1
  571. package/dist/esm/frappeReact.spec.native.js +0 -668
  572. package/dist/esm/frappeReact.spec.native.js.map +0 -1
  573. package/dist/esm/optimistic.spec.mjs +0 -12
  574. package/dist/esm/optimistic.spec.mjs.map +0 -1
  575. package/dist/esm/optimistic.spec.native.js +0 -17
  576. package/dist/esm/optimistic.spec.native.js.map +0 -1
  577. package/dist/esm/pacer.spec.mjs +0 -447
  578. package/dist/esm/pacer.spec.mjs.map +0 -1
  579. package/dist/esm/pacer.spec.native.js +0 -511
  580. package/dist/esm/pacer.spec.native.js.map +0 -1
  581. package/dist/esm/realtime.spec.mjs +0 -327
  582. package/dist/esm/realtime.spec.mjs.map +0 -1
  583. package/dist/esm/realtime.spec.native.js +0 -390
  584. package/dist/esm/realtime.spec.native.js.map +0 -1
  585. package/dist/esm/sync/backfill.spec.mjs +0 -563
  586. package/dist/esm/sync/backfill.spec.mjs.map +0 -1
  587. package/dist/esm/sync/backfill.spec.native.js +0 -686
  588. package/dist/esm/sync/backfill.spec.native.js.map +0 -1
  589. package/dist/esm/sync/debug.spec.mjs +0 -102
  590. package/dist/esm/sync/debug.spec.mjs.map +0 -1
  591. package/dist/esm/sync/debug.spec.native.js +0 -107
  592. package/dist/esm/sync/debug.spec.native.js.map +0 -1
  593. package/dist/esm/sync/filters.spec.mjs +0 -169
  594. package/dist/esm/sync/filters.spec.mjs.map +0 -1
  595. package/dist/esm/sync/filters.spec.native.js +0 -171
  596. package/dist/esm/sync/filters.spec.native.js.map +0 -1
  597. package/dist/esm/sync/merge.spec.mjs +0 -909
  598. package/dist/esm/sync/merge.spec.mjs.map +0 -1
  599. package/dist/esm/sync/merge.spec.native.js +0 -935
  600. package/dist/esm/sync/merge.spec.native.js.map +0 -1
  601. package/dist/esm/sync/multiOrderBy.spec.mjs +0 -166
  602. package/dist/esm/sync/multiOrderBy.spec.mjs.map +0 -1
  603. package/dist/esm/sync/multiOrderBy.spec.native.js +0 -227
  604. package/dist/esm/sync/multiOrderBy.spec.native.js.map +0 -1
  605. package/dist/esm/sync/mutationEngine.spec.mjs +0 -1159
  606. package/dist/esm/sync/mutationEngine.spec.mjs.map +0 -1
  607. package/dist/esm/sync/mutationEngine.spec.native.js +0 -1171
  608. package/dist/esm/sync/mutationEngine.spec.native.js.map +0 -1
  609. package/dist/esm/sync/mutationJournal.spec.mjs +0 -331
  610. package/dist/esm/sync/mutationJournal.spec.mjs.map +0 -1
  611. package/dist/esm/sync/mutationJournal.spec.native.js +0 -331
  612. package/dist/esm/sync/mutationJournal.spec.native.js.map +0 -1
  613. package/dist/esm/sync/mutations.spec.mjs +0 -328
  614. package/dist/esm/sync/mutations.spec.mjs.map +0 -1
  615. package/dist/esm/sync/mutations.spec.native.js +0 -328
  616. package/dist/esm/sync/mutations.spec.native.js.map +0 -1
  617. package/dist/esm/sync/normalizedCache.spec.mjs +0 -303
  618. package/dist/esm/sync/normalizedCache.spec.mjs.map +0 -1
  619. package/dist/esm/sync/normalizedCache.spec.native.js +0 -309
  620. package/dist/esm/sync/normalizedCache.spec.native.js.map +0 -1
  621. package/dist/esm/sync/persistence.spec.mjs +0 -563
  622. package/dist/esm/sync/persistence.spec.mjs.map +0 -1
  623. package/dist/esm/sync/persistence.spec.native.js +0 -570
  624. package/dist/esm/sync/persistence.spec.native.js.map +0 -1
  625. package/dist/esm/sync/realtime.spec.mjs +0 -500
  626. package/dist/esm/sync/realtime.spec.mjs.map +0 -1
  627. package/dist/esm/sync/realtime.spec.native.js +0 -510
  628. package/dist/esm/sync/realtime.spec.native.js.map +0 -1
  629. package/dist/esm/sync/rehydration.spec.mjs +0 -732
  630. package/dist/esm/sync/rehydration.spec.mjs.map +0 -1
  631. package/dist/esm/sync/rehydration.spec.native.js +0 -734
  632. package/dist/esm/sync/rehydration.spec.native.js.map +0 -1
  633. package/dist/esm/sync/storage.spec.mjs +0 -423
  634. package/dist/esm/sync/storage.spec.mjs.map +0 -1
  635. package/dist/esm/sync/storage.spec.native.js +0 -444
  636. package/dist/esm/sync/storage.spec.native.js.map +0 -1
  637. package/dist/esm/sync/subscriptionManager.spec.mjs +0 -1079
  638. package/dist/esm/sync/subscriptionManager.spec.mjs.map +0 -1
  639. package/dist/esm/sync/subscriptionManager.spec.native.js +0 -1110
  640. package/dist/esm/sync/subscriptionManager.spec.native.js.map +0 -1
  641. package/dist/esm/sync/subscriptions.spec.mjs +0 -914
  642. package/dist/esm/sync/subscriptions.spec.mjs.map +0 -1
  643. package/dist/esm/sync/subscriptions.spec.native.js +0 -943
  644. package/dist/esm/sync/subscriptions.spec.native.js.map +0 -1
  645. package/dist/esm/sync/syncModule.spec.mjs +0 -207
  646. package/dist/esm/sync/syncModule.spec.mjs.map +0 -1
  647. package/dist/esm/sync/syncModule.spec.native.js +0 -220
  648. package/dist/esm/sync/syncModule.spec.native.js.map +0 -1
  649. package/dist/esm/sync/types.spec.mjs +0 -247
  650. package/dist/esm/sync/types.spec.mjs.map +0 -1
  651. package/dist/esm/sync/types.spec.native.js +0 -254
  652. package/dist/esm/sync/types.spec.native.js.map +0 -1
  653. package/dist/esm/sync/virtualPageManager.spec.mjs +0 -802
  654. package/dist/esm/sync/virtualPageManager.spec.mjs.map +0 -1
  655. package/dist/esm/sync/virtualPageManager.spec.native.js +0 -871
  656. package/dist/esm/sync/virtualPageManager.spec.native.js.map +0 -1
  657. package/dist/esm/util.spec.mjs +0 -20
  658. package/dist/esm/util.spec.mjs.map +0 -1
  659. package/dist/esm/util.spec.native.js +0 -22
  660. package/dist/esm/util.spec.native.js.map +0 -1
  661. package/dist/jsx/auth.spec.mjs +0 -323
  662. package/dist/jsx/auth.spec.mjs.map +0 -1
  663. package/dist/jsx/auth.spec.native.js +0 -329
  664. package/dist/jsx/auth.spec.native.js.map +0 -1
  665. package/dist/jsx/call.spec.mjs +0 -428
  666. package/dist/jsx/call.spec.mjs.map +0 -1
  667. package/dist/jsx/call.spec.native.js +0 -430
  668. package/dist/jsx/call.spec.native.js.map +0 -1
  669. package/dist/jsx/collection.spec.mjs +0 -187
  670. package/dist/jsx/collection.spec.mjs.map +0 -1
  671. package/dist/jsx/collection.spec.native.js +0 -216
  672. package/dist/jsx/collection.spec.native.js.map +0 -1
  673. package/dist/jsx/common/types.spec.mjs +0 -267
  674. package/dist/jsx/common/types.spec.mjs.map +0 -1
  675. package/dist/jsx/common/types.spec.native.js +0 -271
  676. package/dist/jsx/common/types.spec.native.js.map +0 -1
  677. package/dist/jsx/core/http.spec.mjs +0 -1260
  678. package/dist/jsx/core/http.spec.mjs.map +0 -1
  679. package/dist/jsx/core/http.spec.native.js +0 -1401
  680. package/dist/jsx/core/http.spec.native.js.map +0 -1
  681. package/dist/jsx/core/wire.spec.mjs +0 -479
  682. package/dist/jsx/core/wire.spec.mjs.map +0 -1
  683. package/dist/jsx/core/wire.spec.native.js +0 -482
  684. package/dist/jsx/core/wire.spec.native.js.map +0 -1
  685. package/dist/jsx/db.spec.mjs +0 -863
  686. package/dist/jsx/db.spec.mjs.map +0 -1
  687. package/dist/jsx/db.spec.native.js +0 -865
  688. package/dist/jsx/db.spec.native.js.map +0 -1
  689. package/dist/jsx/doctype.spec.mjs +0 -461
  690. package/dist/jsx/doctype.spec.mjs.map +0 -1
  691. package/dist/jsx/doctype.spec.native.js +0 -538
  692. package/dist/jsx/doctype.spec.native.js.map +0 -1
  693. package/dist/jsx/file.spec.mjs +0 -316
  694. package/dist/jsx/file.spec.mjs.map +0 -1
  695. package/dist/jsx/file.spec.native.js +0 -342
  696. package/dist/jsx/file.spec.native.js.map +0 -1
  697. package/dist/jsx/frappeApp.spec.mjs +0 -307
  698. package/dist/jsx/frappeApp.spec.mjs.map +0 -1
  699. package/dist/jsx/frappeApp.spec.native.js +0 -308
  700. package/dist/jsx/frappeApp.spec.native.js.map +0 -1
  701. package/dist/jsx/frappeReact.spec.mjs +0 -532
  702. package/dist/jsx/frappeReact.spec.mjs.map +0 -1
  703. package/dist/jsx/frappeReact.spec.native.js +0 -670
  704. package/dist/jsx/frappeReact.spec.native.js.map +0 -1
  705. package/dist/jsx/optimistic.spec.mjs +0 -12
  706. package/dist/jsx/optimistic.spec.mjs.map +0 -1
  707. package/dist/jsx/optimistic.spec.native.js +0 -19
  708. package/dist/jsx/optimistic.spec.native.js.map +0 -1
  709. package/dist/jsx/pacer.spec.mjs +0 -447
  710. package/dist/jsx/pacer.spec.mjs.map +0 -1
  711. package/dist/jsx/pacer.spec.native.js +0 -537
  712. package/dist/jsx/pacer.spec.native.js.map +0 -1
  713. package/dist/jsx/realtime.spec.mjs +0 -327
  714. package/dist/jsx/realtime.spec.mjs.map +0 -1
  715. package/dist/jsx/realtime.spec.native.js +0 -392
  716. package/dist/jsx/realtime.spec.native.js.map +0 -1
  717. package/dist/jsx/sync/backfill.spec.mjs +0 -563
  718. package/dist/jsx/sync/backfill.spec.mjs.map +0 -1
  719. package/dist/jsx/sync/backfill.spec.native.js +0 -712
  720. package/dist/jsx/sync/backfill.spec.native.js.map +0 -1
  721. package/dist/jsx/sync/debug.spec.mjs +0 -102
  722. package/dist/jsx/sync/debug.spec.mjs.map +0 -1
  723. package/dist/jsx/sync/debug.spec.native.js +0 -133
  724. package/dist/jsx/sync/debug.spec.native.js.map +0 -1
  725. package/dist/jsx/sync/filters.spec.mjs +0 -169
  726. package/dist/jsx/sync/filters.spec.mjs.map +0 -1
  727. package/dist/jsx/sync/filters.spec.native.js +0 -173
  728. package/dist/jsx/sync/filters.spec.native.js.map +0 -1
  729. package/dist/jsx/sync/merge.spec.mjs +0 -909
  730. package/dist/jsx/sync/merge.spec.mjs.map +0 -1
  731. package/dist/jsx/sync/merge.spec.native.js +0 -937
  732. package/dist/jsx/sync/merge.spec.native.js.map +0 -1
  733. package/dist/jsx/sync/multiOrderBy.spec.mjs +0 -166
  734. package/dist/jsx/sync/multiOrderBy.spec.mjs.map +0 -1
  735. package/dist/jsx/sync/multiOrderBy.spec.native.js +0 -229
  736. package/dist/jsx/sync/multiOrderBy.spec.native.js.map +0 -1
  737. package/dist/jsx/sync/mutationEngine.spec.mjs +0 -1159
  738. package/dist/jsx/sync/mutationEngine.spec.mjs.map +0 -1
  739. package/dist/jsx/sync/mutationEngine.spec.native.js +0 -1173
  740. package/dist/jsx/sync/mutationEngine.spec.native.js.map +0 -1
  741. package/dist/jsx/sync/mutationJournal.spec.mjs +0 -331
  742. package/dist/jsx/sync/mutationJournal.spec.mjs.map +0 -1
  743. package/dist/jsx/sync/mutationJournal.spec.native.js +0 -333
  744. package/dist/jsx/sync/mutationJournal.spec.native.js.map +0 -1
  745. package/dist/jsx/sync/mutations.spec.mjs +0 -328
  746. package/dist/jsx/sync/mutations.spec.mjs.map +0 -1
  747. package/dist/jsx/sync/mutations.spec.native.js +0 -330
  748. package/dist/jsx/sync/mutations.spec.native.js.map +0 -1
  749. package/dist/jsx/sync/normalizedCache.spec.mjs +0 -303
  750. package/dist/jsx/sync/normalizedCache.spec.mjs.map +0 -1
  751. package/dist/jsx/sync/normalizedCache.spec.native.js +0 -311
  752. package/dist/jsx/sync/normalizedCache.spec.native.js.map +0 -1
  753. package/dist/jsx/sync/persistence.spec.mjs +0 -563
  754. package/dist/jsx/sync/persistence.spec.mjs.map +0 -1
  755. package/dist/jsx/sync/persistence.spec.native.js +0 -572
  756. package/dist/jsx/sync/persistence.spec.native.js.map +0 -1
  757. package/dist/jsx/sync/realtime.spec.mjs +0 -500
  758. package/dist/jsx/sync/realtime.spec.mjs.map +0 -1
  759. package/dist/jsx/sync/realtime.spec.native.js +0 -512
  760. package/dist/jsx/sync/realtime.spec.native.js.map +0 -1
  761. package/dist/jsx/sync/rehydration.spec.mjs +0 -732
  762. package/dist/jsx/sync/rehydration.spec.mjs.map +0 -1
  763. package/dist/jsx/sync/rehydration.spec.native.js +0 -736
  764. package/dist/jsx/sync/rehydration.spec.native.js.map +0 -1
  765. package/dist/jsx/sync/storage.spec.mjs +0 -423
  766. package/dist/jsx/sync/storage.spec.mjs.map +0 -1
  767. package/dist/jsx/sync/storage.spec.native.js +0 -470
  768. package/dist/jsx/sync/storage.spec.native.js.map +0 -1
  769. package/dist/jsx/sync/subscriptionManager.spec.mjs +0 -1079
  770. package/dist/jsx/sync/subscriptionManager.spec.mjs.map +0 -1
  771. package/dist/jsx/sync/subscriptionManager.spec.native.js +0 -1136
  772. package/dist/jsx/sync/subscriptionManager.spec.native.js.map +0 -1
  773. package/dist/jsx/sync/subscriptions.spec.mjs +0 -914
  774. package/dist/jsx/sync/subscriptions.spec.mjs.map +0 -1
  775. package/dist/jsx/sync/subscriptions.spec.native.js +0 -969
  776. package/dist/jsx/sync/subscriptions.spec.native.js.map +0 -1
  777. package/dist/jsx/sync/syncModule.spec.mjs +0 -207
  778. package/dist/jsx/sync/syncModule.spec.mjs.map +0 -1
  779. package/dist/jsx/sync/syncModule.spec.native.js +0 -222
  780. package/dist/jsx/sync/syncModule.spec.native.js.map +0 -1
  781. package/dist/jsx/sync/types.spec.mjs +0 -247
  782. package/dist/jsx/sync/types.spec.mjs.map +0 -1
  783. package/dist/jsx/sync/types.spec.native.js +0 -256
  784. package/dist/jsx/sync/types.spec.native.js.map +0 -1
  785. package/dist/jsx/sync/virtualPageManager.spec.mjs +0 -802
  786. package/dist/jsx/sync/virtualPageManager.spec.mjs.map +0 -1
  787. package/dist/jsx/sync/virtualPageManager.spec.native.js +0 -873
  788. package/dist/jsx/sync/virtualPageManager.spec.native.js.map +0 -1
  789. package/dist/jsx/util.spec.mjs +0 -20
  790. package/dist/jsx/util.spec.mjs.map +0 -1
  791. package/dist/jsx/util.spec.native.js +0 -48
  792. package/dist/jsx/util.spec.native.js.map +0 -1
package/src/realtime.ts CHANGED
@@ -1,7 +1,8 @@
1
+ import { isNative } from "@multiplatform.one/platform";
1
2
  import type { ManagerOptions, Socket, SocketOptions } from "socket.io-client";
2
3
  import { io } from "socket.io-client";
3
4
  import type { AuthConfig } from "./core/types";
4
- import { isBrowser } from "./util";
5
+ import { isBrowser, isGjs } from "./util";
5
6
 
6
7
  export type Handler = (payload: unknown) => void;
7
8
 
@@ -27,10 +28,30 @@ export interface RealtimeConfig {
27
28
  * `/socket.io` to the SocketIO backend.
28
29
  */
29
30
  socketPort?: number;
31
+ /**
32
+ * Frappe site name, used as the Socket.IO namespace.
33
+ *
34
+ * Frappe's realtime server is multi-tenant: every site lives on its own
35
+ * Socket.IO namespace (`/<sitename>`) guarded by the auth middleware, and
36
+ * server events are only emitted to that namespace. Connecting to the
37
+ * root namespace `/` silently succeeds but never receives any events.
38
+ *
39
+ * Defaults to the hostname of `baseURL`, which matches Frappe's own
40
+ * site-name resolution for host-served sites (and the `default_site` of a
41
+ * standard dev bench on localhost).
42
+ */
43
+ siteName?: string;
30
44
  platform?: RealtimePlatform;
31
45
  socketOptions?: Partial<ManagerOptions & SocketOptions>;
32
46
  }
33
47
 
48
+ type DocRoom = { doctype: string; name: string };
49
+ type ListRoom = { doctype: string; filters?: Record<string, unknown> };
50
+
51
+ function docRoomKey(doctype: string, name: string) {
52
+ return `${doctype}\0${name}`;
53
+ }
54
+
34
55
  export class RealtimeModule {
35
56
  private socket: Socket | undefined;
36
57
  private handlerMap = new Map<string, Set<Handler>>();
@@ -38,9 +59,16 @@ export class RealtimeModule {
38
59
  private attachedSocketEvents = new Set<string>();
39
60
  /** Stored socket event handler references for proper cleanup. */
40
61
  private socketEventHandlers = new Map<string, (payload: unknown) => void>();
62
+ /** Active doc rooms — re-emitted on every (re)connect. */
63
+ private docRooms = new Map<string, DocRoom>();
64
+ /** Active list rooms — re-emitted on every (re)connect. */
65
+ private listRooms = new Map<string, ListRoom>();
41
66
  private socketHealthy = false;
42
67
  private isConnecting = false;
68
+ private healthyWaiters = new Set<(ok: boolean) => void>();
43
69
  private config: RealtimeConfig;
70
+ /** In-flight credential re-resolution (deduped across triggers). */
71
+ private authRefreshInflight?: Promise<void>;
44
72
 
45
73
  constructor(config: RealtimeConfig) {
46
74
  this.config = {
@@ -50,28 +78,76 @@ export class RealtimeModule {
50
78
  }
51
79
 
52
80
  private detectPlatform() {
53
- if (!isBrowser()) return RealtimePlatform.Node;
54
- if (typeof navigator !== "undefined" && navigator.userAgent?.includes("ReactNative")) {
81
+ // GJS (GNOME desktop) FIRST: isBrowser() is true there (the sync engine
82
+ // runs), but the Web classification would be wrong — GJS has no XHR for
83
+ // a polling-first handshake, and its WebSocket comes from an
84
+ // entry-installed libsoup polyfill that DOES accept custom handshake
85
+ // headers (RN-style `{ headers }` third argument). Classify like Node:
86
+ // websocket-first transports + the extraHeaders auth path.
87
+ if (isGjs()) return RealtimePlatform.Node;
88
+ // React Native next: RN sets navigator.product === "ReactNative" but no
89
+ // userAgent, so a UA-only sniff misclassifies RN as Web — skipping the
90
+ // extraHeaders auth path (sid cookie / Origin) and connecting cookie-auth
91
+ // sockets as guest. The platform package's static isNative flag is the
92
+ // canonical signal; the navigator checks are runtime fallbacks (kept for
93
+ // environments that fake a RN UA, e.g. tests).
94
+ if (
95
+ isNative ||
96
+ (typeof navigator !== "undefined" &&
97
+ (navigator.product === "ReactNative" || navigator.userAgent?.includes("ReactNative")))
98
+ ) {
55
99
  return RealtimePlatform.ReactNative;
56
100
  }
101
+ if (!isBrowser()) return RealtimePlatform.Node;
57
102
  return RealtimePlatform.Web;
58
103
  }
59
104
 
60
105
  private getSocketURL(): string {
61
106
  const base = this.config.baseURL.replace(/\/$/, "");
62
- if (!this.config.socketPort) return base;
63
107
  try {
64
108
  const url = new URL(base);
65
- url.port = String(this.config.socketPort);
66
- return url.toString().replace(/\/$/, "");
109
+ // Assemble origin from parts instead of mutating url.port and reading
110
+ // url.origin: minimal URL polyfills (e.g. the GJS/react-gnome shim)
111
+ // parse host at construction and never recompute origin from a port
112
+ // assignment — which silently dropped socketPort and pointed the
113
+ // socket at the web server.
114
+ const port = this.config.socketPort ? String(this.config.socketPort) : url.port;
115
+ const host = port ? `${url.hostname}:${port}` : url.hostname;
116
+ // The path portion of the URL passed to io() is the Socket.IO
117
+ // namespace — frappe requires it to be the site name (see siteName).
118
+ const siteName = this.config.siteName || url.hostname;
119
+ return `${url.protocol}//${host}/${siteName}`;
67
120
  } catch {
68
- // Fallback: replace port via regex when URL constructor isn't available
69
- return base.replace(/(:\d+)/, `:${this.config.socketPort}`);
121
+ // Fallback: string manipulation when URL constructor isn't available
122
+ let result = base;
123
+ if (this.config.socketPort) {
124
+ result = result.replace(/(:\d+)/, `:${this.config.socketPort}`);
125
+ }
126
+ const siteName = this.config.siteName || result.replace(/^https?:\/\//, "").split(/[/:]/)[0];
127
+ return `${result}/${siteName}`;
70
128
  }
71
129
  }
72
130
 
73
131
  private async getAuthOptions(): Promise<Partial<ManagerOptions & SocketOptions>> {
74
132
  const authOptions: Partial<ManagerOptions & SocketOptions> = {};
133
+ if (this.config.platform !== RealtimePlatform.Web) {
134
+ // Non-browser clients must send an Origin header themselves: frappe's
135
+ // socketio middleware rejects mismatched Origin/Host hostnames AND uses
136
+ // the Origin as the base URL for its can_subscribe_* permission
137
+ // callbacks to the web server — so it must point at the WEB base URL
138
+ // (baseURL), not the socketio port. The Web platform must NEVER set it:
139
+ // Origin is a forbidden header in browsers (they always send the page
140
+ // origin themselves), and attempting it makes engine.io's XHR transport
141
+ // log "Attempt to set a forbidden header was denied: Origin" on every
142
+ // polling request. Browser-like TEST runtimes (happy-dom/jsdom over
143
+ // node transports) that need a bench-pointing Origin opt in via
144
+ // `platform: RealtimePlatform.Node` or `socketOptions.extraHeaders`.
145
+ try {
146
+ authOptions.extraHeaders = { Origin: new URL(this.config.baseURL).origin };
147
+ } catch {
148
+ authOptions.extraHeaders = { Origin: this.config.baseURL.replace(/\/$/, "") };
149
+ }
150
+ }
75
151
  if (this.config.platform !== RealtimePlatform.Web && this.config.auth?.sessionId) {
76
152
  const sessionId =
77
153
  typeof this.config.auth.sessionId === "function"
@@ -79,40 +155,125 @@ export class RealtimeModule {
79
155
  : this.config.auth.sessionId;
80
156
  const Cookie = `sid=${sessionId}`;
81
157
  authOptions.extraHeaders = {
158
+ ...authOptions.extraHeaders,
82
159
  Cookie,
83
160
  };
84
- authOptions.transportOptions = {
85
- websocket: {
86
- extraHeaders: {
87
- Cookie,
88
- },
89
- },
90
- polling: {
91
- extraHeaders: {
92
- Cookie,
93
- },
94
- },
95
- };
96
161
  }
97
162
  if (this.config.auth?.useToken && this.config.auth.token) {
98
163
  const token =
99
164
  typeof this.config.auth.token === "function"
100
165
  ? await this.config.auth.token()
101
166
  : this.config.auth.token;
102
- const authType = this.config.auth.type || "Bearer";
103
- if (!authOptions.extraHeaders) authOptions.extraHeaders = {};
104
- authOptions.extraHeaders.Authorization =
105
- authType === "Bearer" ? `Bearer ${token}` : `token ${token}`;
167
+ // Skip when the getter resolves empty (signed out): a bare
168
+ // "Bearer " header would fail frappe's auth instead of falling
169
+ // back to guest.
170
+ if (token) {
171
+ const authType = this.config.auth.type || "Bearer";
172
+ if (!authOptions.extraHeaders) authOptions.extraHeaders = {};
173
+ authOptions.extraHeaders.Authorization =
174
+ authType === "Bearer" ? `Bearer ${token}` : `token ${token}`;
175
+ }
176
+ }
177
+ if (authOptions.extraHeaders) {
178
+ // Mirror headers into per-transport options: node websocket reads
179
+ // transportOptions.websocket.extraHeaders, browser polling reads the
180
+ // top-level extraHeaders — covering both keeps every handshake
181
+ // (initial, upgrade, reconnect) authenticated.
182
+ authOptions.transportOptions = {
183
+ websocket: { extraHeaders: { ...authOptions.extraHeaders } },
184
+ polling: { extraHeaders: { ...authOptions.extraHeaders } },
185
+ };
106
186
  }
107
187
  return authOptions;
108
188
  }
109
189
 
190
+ /**
191
+ * Re-resolve credentials (token function / session id) and swap them into
192
+ * the LIVE manager options in place. Socket.IO constructs a fresh engine
193
+ * from `manager.opts` on every (re)connect attempt, so mutating the opts
194
+ * makes the next handshake carry the refreshed token — without tearing
195
+ * down handlers or room subscriptions. Called on disconnect and before
196
+ * reconnect attempts so a token that rotated mid-session (e.g. Keycloak
197
+ * refresh) never strands the socket in an auth-rejected retry loop.
198
+ */
199
+ private refreshSocketAuth(): Promise<void> {
200
+ const socket = this.socket;
201
+ if (!socket) return Promise.resolve();
202
+ if (this.authRefreshInflight) return this.authRefreshInflight;
203
+ this.authRefreshInflight = (async () => {
204
+ try {
205
+ const authOptions = await this.getAuthOptions();
206
+ const manager = (socket as { io?: { opts?: Record<string, unknown> } }).io;
207
+ if (manager?.opts) Object.assign(manager.opts, authOptions);
208
+ } catch {
209
+ // Keep the previous credentials; the next disconnect/reconnect
210
+ // cycle retries the refresh.
211
+ } finally {
212
+ this.authRefreshInflight = undefined;
213
+ }
214
+ })();
215
+ return this.authRefreshInflight;
216
+ }
217
+
218
+ private resolveHealthyWaiters(ok: boolean) {
219
+ for (const resolve of this.healthyWaiters) resolve(ok);
220
+ this.healthyWaiters.clear();
221
+ }
222
+
223
+ private waitUntilHealthy(timeoutMs = 20_000): Promise<boolean> {
224
+ if (this.socketHealthy && this.socket?.connected) return Promise.resolve(true);
225
+ return new Promise((resolve) => {
226
+ const timer = setTimeout(() => {
227
+ this.healthyWaiters.delete(onReady);
228
+ resolve(false);
229
+ }, timeoutMs);
230
+ const onReady = (ok: boolean) => {
231
+ clearTimeout(timer);
232
+ resolve(ok);
233
+ };
234
+ this.healthyWaiters.add(onReady);
235
+ });
236
+ }
237
+
238
+ private async ensureConnected(): Promise<void> {
239
+ if (this.socketHealthy && this.socket?.connected) return;
240
+ if (!this.socket && !this.isConnecting) {
241
+ await this.connect();
242
+ }
243
+ await this.waitUntilHealthy();
244
+ }
245
+
246
+ private resubscribeRooms(): void {
247
+ if (!this.socket || !this.socketHealthy) return;
248
+ // Frappe's socketio handlers take POSITIONAL args (doctype, docname) —
249
+ // not an object payload — and list-level subscription is doctype_subscribe.
250
+ for (const room of this.docRooms.values()) {
251
+ this.socket.emit("doc_subscribe", room.doctype, room.name);
252
+ }
253
+ for (const room of this.listRooms.values()) {
254
+ this.socket.emit("doctype_subscribe", room.doctype);
255
+ }
256
+ }
257
+
110
258
  private async connect() {
111
259
  if (this.socket || this.isConnecting) return;
112
260
  this.isConnecting = true;
113
261
  try {
114
262
  const authOptions = await this.getAuthOptions();
115
263
  const socketURL = this.getSocketURL();
264
+ // Browsers always handshake over polling first (Socket.IO's default
265
+ // ordering): custom headers only attach to the XHR handshake (token
266
+ // auth), session-cookie auth and reverse-proxy-injected Authorization
267
+ // only apply to HTTP requests, and ws-upgrade-hostile dev proxies
268
+ // (e.g. Vite in middleware mode — the Storybook dev server) hang raw
269
+ // websocket upgrades forever, so a websocket-first browser client
270
+ // stalls ~20s per attempt and never connects. Socket.IO upgrades the
271
+ // established session to websocket when the path supports it.
272
+ // Everywhere else (Node, React Native) websocket-first is fine.
273
+ const transports =
274
+ this.config.platform === RealtimePlatform.Web
275
+ ? ["polling", "websocket"]
276
+ : ["websocket", "polling"];
116
277
  this.socket = io(socketURL, {
117
278
  autoConnect: false,
118
279
  path: "/socket.io",
@@ -122,7 +283,7 @@ export class RealtimeModule {
122
283
  reconnectionDelay: 1000,
123
284
  reconnectionDelayMax: 5000,
124
285
  timeout: 20000,
125
- transports: ["websocket", "polling"],
286
+ transports,
126
287
  withCredentials: true,
127
288
  ...authOptions,
128
289
  ...this.config.socketOptions,
@@ -131,10 +292,31 @@ export class RealtimeModule {
131
292
  this.socket.connect();
132
293
  } catch (err) {
133
294
  this.isConnecting = false;
295
+ this.resolveHealthyWaiters(false);
134
296
  throw err;
135
297
  }
136
298
  }
137
299
 
300
+ /**
301
+ * Tear down the socket without clearing app handlers or room subscriptions.
302
+ * Used by auth refresh so listeners/rooms survive credential rotation.
303
+ */
304
+ private softDisconnect(): void {
305
+ if (this.socket) {
306
+ // Prefer removeAllListeners when available (real socket.io); mocks may omit it.
307
+ if (typeof this.socket.removeAllListeners === "function") {
308
+ this.socket.removeAllListeners();
309
+ }
310
+ this.socket.disconnect();
311
+ this.socket = undefined;
312
+ }
313
+ this.attachedSocketEvents.clear();
314
+ this.socketEventHandlers.clear();
315
+ this.socketHealthy = false;
316
+ this.isConnecting = false;
317
+ this.resolveHealthyWaiters(false);
318
+ }
319
+
138
320
  private initHandlers(): void {
139
321
  if (!this.socket) return;
140
322
  // New socket instance: reset attached event tracking so listeners are re-registered fresh
@@ -143,14 +325,31 @@ export class RealtimeModule {
143
325
  this.socket.on("connect", () => {
144
326
  this.isConnecting = false;
145
327
  this.socketHealthy = true;
328
+ this.resubscribeRooms();
146
329
  this.emitToHandlers("connected", { sid: this.socket?.id });
330
+ this.resolveHealthyWaiters(true);
147
331
  });
148
332
  this.socket.on("disconnect", (reason) => {
149
333
  this.socketHealthy = false;
334
+ // Refresh credentials right away so the first reconnect attempt
335
+ // (>=1s later) already handshakes with a fresh token.
336
+ void this.refreshSocketAuth();
150
337
  this.emitToHandlers("disconnect", { reason });
151
338
  });
152
- this.socket.on("connect_error", (_error) => {
339
+ this.socket.on("connect_error", (error) => {
153
340
  this.isConnecting = false;
341
+ // Auth-rejected handshakes (e.g. expired token) land here rather than
342
+ // in "disconnect" — refresh before the manager's next retry.
343
+ void this.refreshSocketAuth();
344
+ this.emitToHandlers("connect_error", error);
345
+ this.resolveHealthyWaiters(false);
346
+ });
347
+ // Manager-level safety net: re-resolve before every scheduled reconnect
348
+ // attempt (covers timeouts and transport errors that skip the socket
349
+ // level events above). Mock sockets in tests may not expose `.io`.
350
+ const manager = (this.socket as { io?: { on?: (ev: string, fn: () => void) => void } }).io;
351
+ manager?.on?.("reconnect_attempt", () => {
352
+ void this.refreshSocketAuth();
154
353
  });
155
354
  // Attach listeners for existing handler events, avoiding duplicates
156
355
  for (const event of this.handlerMap.keys()) {
@@ -201,10 +400,14 @@ export class RealtimeModule {
201
400
  this.handlerMap.set(event, handlerSet);
202
401
  }
203
402
  handlerSet.add(handler);
204
- if (!this.socket && !this.isConnecting) {
205
- await this.connect();
206
- }
207
- // Attach socket listener for this event (safe to call multiple times)
403
+ // Registering a handler does NOT open the socket. The socket lifecycle
404
+ // is driven by room membership (subscribeDoc/subscribeList →
405
+ // ensureConnected): handlers registered before the first room join are
406
+ // attached by initHandlers() when that join connects. Connecting here
407
+ // meant merely CONSTRUCTING the sync engine (which registers its event
408
+ // handlers up front) booted a socket that nothing would ever close —
409
+ // against an unreachable host that is an infinite reconnect-poll loop
410
+ // surviving unmount (the fixture/mock-story socket leak).
208
411
  this.attachSocketListener(event);
209
412
  }
210
413
 
@@ -219,28 +422,61 @@ export class RealtimeModule {
219
422
  }
220
423
 
221
424
  async subscribeDoc(doctype: string, name: string): Promise<void> {
222
- if (!this.socket) await this.connect();
425
+ this.docRooms.set(docRoomKey(doctype, name), { doctype, name });
426
+ await this.ensureConnected();
223
427
  if (this.socket && this.socketHealthy) {
224
- this.socket.emit("doc_subscribe", { doctype, name });
428
+ // Positional args — frappe's handler signature is (doctype, docname).
429
+ this.socket.emit("doc_subscribe", doctype, name);
225
430
  }
226
431
  }
227
432
 
228
433
  unsubscribeDoc(doctype: string, name: string): void {
434
+ this.docRooms.delete(docRoomKey(doctype, name));
229
435
  if (this.socket && this.socketHealthy) {
230
- this.socket.emit("doc_unsubscribe", { doctype, name });
436
+ this.socket.emit("doc_unsubscribe", doctype, name);
231
437
  }
438
+ this.teardownWhenIdle();
232
439
  }
233
440
 
441
+ /**
442
+ * Subscribe to list-level updates for a doctype (`list_update` events).
443
+ *
444
+ * `filters` are tracked client-side only: frappe's realtime server has a
445
+ * single room per doctype (`doctype_subscribe`) and does not support
446
+ * filtered list rooms.
447
+ */
234
448
  async subscribeList(doctype: string, filters?: Record<string, unknown>): Promise<void> {
235
- if (!this.socket) await this.connect();
449
+ this.listRooms.set(doctype, { doctype, filters });
450
+ await this.ensureConnected();
236
451
  if (this.socket && this.socketHealthy) {
237
- this.socket.emit("list_subscribe", { doctype, filters });
452
+ this.socket.emit("doctype_subscribe", doctype);
238
453
  }
239
454
  }
455
+
240
456
  unsubscribeList(doctype: string): void {
457
+ this.listRooms.delete(doctype);
241
458
  if (this.socket && this.socketHealthy) {
242
- this.socket.emit("list_unsubscribe", { doctype });
459
+ this.socket.emit("doctype_unsubscribe", doctype);
243
460
  }
461
+ this.teardownWhenIdle();
462
+ }
463
+
464
+ /**
465
+ * Tears the socket down when the last room is released. Room membership is
466
+ * the socket's reason to exist: while any subscription holds a room, the
467
+ * infinite Socket.IO reconnection loop is the reconnect catch-up protocol
468
+ * working as designed — but once nothing is subscribed, that same loop is
469
+ * a leak (unmounted consumers leaving a dead-host socket reconnect-polling
470
+ * forever). Handlers and any re-added rooms survive: the next
471
+ * subscribeDoc/subscribeList reconnects and re-attaches everything.
472
+ */
473
+ private teardownWhenIdle(): void {
474
+ if (this.docRooms.size > 0 || this.listRooms.size > 0) return;
475
+ if (!this.socket && !this.isConnecting) return;
476
+ // Surface the teardown to lifecycle listeners (connection indicators)
477
+ // before the listeners are detached from the socket.
478
+ this.emitToHandlers("disconnect", { reason: "idle-teardown" });
479
+ this.softDisconnect();
244
480
  }
245
481
 
246
482
  isHealthy() {
@@ -248,21 +484,23 @@ export class RealtimeModule {
248
484
  }
249
485
 
250
486
  disconnect(): void {
251
- if (this.socket) {
252
- this.socket.disconnect();
253
- this.socket = undefined;
254
- }
487
+ this.softDisconnect();
255
488
  this.handlerMap.clear();
256
- this.attachedSocketEvents.clear();
257
- this.socketEventHandlers.clear();
258
- this.socketHealthy = false;
259
- this.isConnecting = false;
489
+ this.docRooms.clear();
490
+ this.listRooms.clear();
260
491
  }
261
492
 
262
493
  async updateAuth(auth: AuthConfig) {
263
494
  this.config.auth = auth;
264
- this.disconnect();
265
- if (this.handlerMap.size > 0) {
495
+ // Reconnect only when room subscriptions exist — rooms are what the
496
+ // socket serves. Handlers alone (registered eagerly by the sync engine)
497
+ // don't warrant a socket: an idle module stays idle across credential
498
+ // rotation, and the next room join connects with the fresh auth.
499
+ const shouldReconnect = this.docRooms.size > 0 || this.listRooms.size > 0;
500
+ // Soft disconnect preserves handlers + rooms; hard disconnect() would wipe them
501
+ // and make the post-check always false (previous production bug).
502
+ this.softDisconnect();
503
+ if (shouldReconnect) {
266
504
  await this.connect();
267
505
  }
268
506
  }
@@ -532,6 +532,49 @@ describe("BackfillManager", () => {
532
532
  expect(mockDb.getDocList).toHaveBeenCalled();
533
533
  expect(subscription.testProgressiveCache.docIds.length).toBeGreaterThan(0);
534
534
  });
535
+
536
+ const mockEndlessCdcPages = () => {
537
+ // Server always reports truncation with an advancing checkpoint, so
538
+ // only the page cap can stop the drain.
539
+ let page = 0;
540
+ (mockDb.backfill as any).mockImplementation(async () => {
541
+ page += 1;
542
+ return {
543
+ rows: [
544
+ { name: `cdc-doc-${page}`, modified: new Date(2024, 0, 2, 0, 0, page).toISOString() },
545
+ ],
546
+ deleted: [],
547
+ checkpoint: `2024-01-02 00:00:${String(page).padStart(2, "0")}.000000|cdc-doc-${page}`,
548
+ has_more: true,
549
+ };
550
+ });
551
+ };
552
+
553
+ it("should stop draining at the configured maxPages cap", async () => {
554
+ const cappedManager = new BackfillManager(mockDb, mockNormalizedCache, {
555
+ pageSize: 50,
556
+ maxPages: 2,
557
+ });
558
+ const subscription = createMockSubscription({
559
+ checkpoint: new Date(2024, 0, 1).toISOString(),
560
+ });
561
+ mockEndlessCdcPages();
562
+
563
+ await cappedManager.backfill(subscription, BackfillReason.Periodic);
564
+
565
+ expect(mockDb.backfill).toHaveBeenCalledTimes(2);
566
+ });
567
+
568
+ it("should default the drain cap to 20 pages when maxPages is not set", async () => {
569
+ const subscription = createMockSubscription({
570
+ checkpoint: new Date(2024, 0, 1).toISOString(),
571
+ });
572
+ mockEndlessCdcPages();
573
+
574
+ await backfillManager.backfill(subscription, BackfillReason.Periodic);
575
+
576
+ expect(mockDb.backfill).toHaveBeenCalledTimes(20);
577
+ });
535
578
  });
536
579
 
537
580
  describe("cursor-based fetching", () => {
@@ -63,17 +63,26 @@ export interface BackfillOptions {
63
63
  pageSize?: number;
64
64
  retryDelay?: number;
65
65
  batchSize?: number;
66
+ /**
67
+ * Max CDC pages drained per incremental backfill when the server reports
68
+ * has_more (default: 20). Fed from SyncOptions.backfillMaxPages so one
69
+ * knob bounds both drain paths.
70
+ */
71
+ maxPages?: number;
66
72
  }
67
73
 
68
74
  export class BackfillManager {
69
75
  private activeBackfills = new Map<string, Promise<void>>();
70
76
  private backfillQueue = new Map<string, BackfillReason[]>();
71
-
72
- constructor(
73
- private db: DbModule,
74
- private normalizedCache: NormalizedCache,
75
- private options: BackfillOptions = {},
76
- ) {}
77
+ private db: DbModule;
78
+ private normalizedCache: NormalizedCache;
79
+ private options: BackfillOptions;
80
+
81
+ constructor(db: DbModule, normalizedCache: NormalizedCache, options: BackfillOptions = {}) {
82
+ this.db = db;
83
+ this.normalizedCache = normalizedCache;
84
+ this.options = options;
85
+ }
77
86
 
78
87
  async backfill(subscription: VirtualSubscription, reason: BackfillReason): Promise<void> {
79
88
  const subscriptionId = subscription.id;
@@ -250,45 +259,56 @@ export class BackfillManager {
250
259
  }
251
260
 
252
261
  try {
253
- // Use CDC backfill API
254
- const response = await this.db.backfill({
255
- doctype: subscription.query.doctype,
256
- fields: subscription.query.fields,
257
- filters: subscription.query.filters,
258
- modifiedAfter: subscription.checkpoint,
259
- limit: this.options.pageSize || 200,
260
- });
262
+ // Drain CDC pages while the server reports truncation (bounded) so
263
+ // catch-up after a long gap is complete, not one page deep.
264
+ const maxPages = this.options.maxPages ?? 20;
265
+ for (let page = 0; page < maxPages; page++) {
266
+ const response = await this.db.backfill({
267
+ doctype: subscription.query.doctype,
268
+ fields: subscription.query.fields,
269
+ filters: subscription.query.filters,
270
+ modifiedAfter: subscription.checkpoint,
271
+ limit: this.options.pageSize || 200,
272
+ });
261
273
 
262
- // Process deletions using shared utility
263
- if ("deleted" in response && Array.isArray(response.deleted)) {
264
- const deletedDocIds = (response.deleted as any[])
265
- .filter((deletion) => deletion?.name)
266
- .map((deletion) => deletion.name);
274
+ // Process deletions using shared utility
275
+ if ("deleted" in response && Array.isArray(response.deleted)) {
276
+ const deletedDocIds = (response.deleted as any[])
277
+ .filter((deletion) => deletion?.name)
278
+ .map((deletion) => deletion.name);
267
279
 
268
- if (deletedDocIds.length > 0) {
269
- subscription.removeDocuments(deletedDocIds, this.normalizedCache);
280
+ if (deletedDocIds.length > 0) {
281
+ subscription.removeDocuments(deletedDocIds, this.normalizedCache);
282
+ }
270
283
  }
271
- }
272
284
 
273
- // Process updates and creates
274
- for (const doc of response.rows) {
275
- const exists = subscription.getProgressiveCache().docIds.includes(doc.name);
276
- const matches = matchesFilters(doc as FrappeDoc<FrappeDocData>, subscription.query.filters);
277
-
278
- if (exists && !matches) {
279
- // Remove - no longer matches
280
- subscription.removeDocuments([doc.name], this.normalizedCache);
281
- } else if (!exists && matches) {
282
- // Add - now matches (but we don't know where)
283
- subscription.needsRehydration = true;
284
- } else if (exists) {
285
- // Update existing
286
- this.normalizedCache.upsert(doc);
285
+ // Process updates and creates
286
+ for (const doc of response.rows) {
287
+ const exists = subscription.getProgressiveCache().docIds.includes(doc.name);
288
+ const matches = matchesFilters(
289
+ doc as FrappeDoc<FrappeDocData>,
290
+ subscription.query.filters,
291
+ );
292
+
293
+ if (exists && !matches) {
294
+ // Remove - no longer matches
295
+ subscription.removeDocuments([doc.name], this.normalizedCache);
296
+ } else if (!exists && matches) {
297
+ // Add - now matches (but we don't know where)
298
+ subscription.needsRehydration = true;
299
+ } else if (exists) {
300
+ // Update existing
301
+ this.normalizedCache.upsert(doc);
302
+ }
287
303
  }
288
- }
289
304
 
290
- // Update checkpoint
291
- subscription.checkpoint = calculateCheckpointFromDocs(response.rows);
305
+ // Advance the checkpoint: prefer the server's exact resume cursor
306
+ // ("ts|name"); fall back to the max modified for older servers.
307
+ subscription.checkpoint = response.checkpoint ?? calculateCheckpointFromDocs(response.rows);
308
+
309
+ const madeProgress = response.rows.length > 0 || (response.deleted?.length ?? 0) > 0;
310
+ if (!response.has_more || !response.checkpoint || !madeProgress) break;
311
+ }
292
312
  } catch (error) {
293
313
  console.error("Incremental backfill failed:", error);
294
314
  // Fall back to full refresh