@dittolive/ditto 4.4.5 → 4.5.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 (289) hide show
  1. package/DittoReactNative.podspec +27 -0
  2. package/README.md +68 -51
  3. package/node/ditto.cjs.js +1639 -851
  4. package/node/ditto.darwin-arm64.node +0 -0
  5. package/node/ditto.darwin-x64.node +0 -0
  6. package/node/ditto.linux-arm.node +0 -0
  7. package/node/ditto.linux-x64.node +0 -0
  8. package/node/ditto.win32-x64.node +0 -0
  9. package/node/transports.darwin-arm64.node +0 -0
  10. package/node/transports.darwin-x64.node +0 -0
  11. package/package.json +34 -38
  12. package/react-native/android/CMakeLists.txt +37 -0
  13. package/react-native/android/build.gradle +203 -0
  14. package/react-native/android/cpp-adapter.cpp +254 -0
  15. package/react-native/android/gradle.properties +5 -0
  16. package/react-native/android/src/main/AndroidManifest.xml +4 -0
  17. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +85 -0
  18. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKPackage.java +28 -0
  19. package/react-native/boost/boost/assert.hpp +85 -0
  20. package/react-native/boost/boost/config/abi/borland_prefix.hpp +27 -0
  21. package/react-native/boost/boost/config/abi/borland_suffix.hpp +12 -0
  22. package/react-native/boost/boost/config/abi/msvc_prefix.hpp +22 -0
  23. package/react-native/boost/boost/config/abi/msvc_suffix.hpp +8 -0
  24. package/react-native/boost/boost/config/abi_prefix.hpp +25 -0
  25. package/react-native/boost/boost/config/abi_suffix.hpp +25 -0
  26. package/react-native/boost/boost/config/assert_cxx03.hpp +211 -0
  27. package/react-native/boost/boost/config/assert_cxx11.hpp +209 -0
  28. package/react-native/boost/boost/config/assert_cxx14.hpp +47 -0
  29. package/react-native/boost/boost/config/assert_cxx17.hpp +62 -0
  30. package/react-native/boost/boost/config/assert_cxx20.hpp +59 -0
  31. package/react-native/boost/boost/config/assert_cxx98.hpp +23 -0
  32. package/react-native/boost/boost/config/auto_link.hpp +525 -0
  33. package/react-native/boost/boost/config/compiler/borland.hpp +339 -0
  34. package/react-native/boost/boost/config/compiler/clang.hpp +366 -0
  35. package/react-native/boost/boost/config/compiler/clang_version.hpp +83 -0
  36. package/react-native/boost/boost/config/compiler/codegear.hpp +385 -0
  37. package/react-native/boost/boost/config/compiler/comeau.hpp +59 -0
  38. package/react-native/boost/boost/config/compiler/common_edg.hpp +183 -0
  39. package/react-native/boost/boost/config/compiler/compaq_cxx.hpp +19 -0
  40. package/react-native/boost/boost/config/compiler/cray.hpp +446 -0
  41. package/react-native/boost/boost/config/compiler/diab.hpp +26 -0
  42. package/react-native/boost/boost/config/compiler/digitalmars.hpp +143 -0
  43. package/react-native/boost/boost/config/compiler/gcc.hpp +383 -0
  44. package/react-native/boost/boost/config/compiler/gcc_xml.hpp +114 -0
  45. package/react-native/boost/boost/config/compiler/greenhills.hpp +28 -0
  46. package/react-native/boost/boost/config/compiler/hp_acc.hpp +149 -0
  47. package/react-native/boost/boost/config/compiler/intel.hpp +577 -0
  48. package/react-native/boost/boost/config/compiler/kai.hpp +33 -0
  49. package/react-native/boost/boost/config/compiler/metrowerks.hpp +198 -0
  50. package/react-native/boost/boost/config/compiler/mpw.hpp +140 -0
  51. package/react-native/boost/boost/config/compiler/nvcc.hpp +61 -0
  52. package/react-native/boost/boost/config/compiler/pathscale.hpp +138 -0
  53. package/react-native/boost/boost/config/compiler/pgi.hpp +23 -0
  54. package/react-native/boost/boost/config/compiler/sgi_mipspro.hpp +29 -0
  55. package/react-native/boost/boost/config/compiler/sunpro_cc.hpp +222 -0
  56. package/react-native/boost/boost/config/compiler/vacpp.hpp +186 -0
  57. package/react-native/boost/boost/config/compiler/visualc.hpp +391 -0
  58. package/react-native/boost/boost/config/compiler/xlcpp.hpp +299 -0
  59. package/react-native/boost/boost/config/compiler/xlcpp_zos.hpp +173 -0
  60. package/react-native/boost/boost/config/detail/cxx_composite.hpp +203 -0
  61. package/react-native/boost/boost/config/detail/posix_features.hpp +95 -0
  62. package/react-native/boost/boost/config/detail/select_compiler_config.hpp +157 -0
  63. package/react-native/boost/boost/config/detail/select_platform_config.hpp +147 -0
  64. package/react-native/boost/boost/config/detail/select_stdlib_config.hpp +121 -0
  65. package/react-native/boost/boost/config/detail/suffix.hpp +1294 -0
  66. package/react-native/boost/boost/config/header_deprecated.hpp +26 -0
  67. package/react-native/boost/boost/config/helper_macros.hpp +37 -0
  68. package/react-native/boost/boost/config/no_tr1/cmath.hpp +28 -0
  69. package/react-native/boost/boost/config/no_tr1/complex.hpp +28 -0
  70. package/react-native/boost/boost/config/no_tr1/functional.hpp +28 -0
  71. package/react-native/boost/boost/config/no_tr1/memory.hpp +28 -0
  72. package/react-native/boost/boost/config/no_tr1/utility.hpp +28 -0
  73. package/react-native/boost/boost/config/platform/aix.hpp +33 -0
  74. package/react-native/boost/boost/config/platform/amigaos.hpp +15 -0
  75. package/react-native/boost/boost/config/platform/beos.hpp +26 -0
  76. package/react-native/boost/boost/config/platform/bsd.hpp +83 -0
  77. package/react-native/boost/boost/config/platform/cloudabi.hpp +18 -0
  78. package/react-native/boost/boost/config/platform/cray.hpp +18 -0
  79. package/react-native/boost/boost/config/platform/cygwin.hpp +71 -0
  80. package/react-native/boost/boost/config/platform/haiku.hpp +31 -0
  81. package/react-native/boost/boost/config/platform/hpux.hpp +87 -0
  82. package/react-native/boost/boost/config/platform/irix.hpp +31 -0
  83. package/react-native/boost/boost/config/platform/linux.hpp +106 -0
  84. package/react-native/boost/boost/config/platform/macos.hpp +87 -0
  85. package/react-native/boost/boost/config/platform/qnxnto.hpp +31 -0
  86. package/react-native/boost/boost/config/platform/solaris.hpp +31 -0
  87. package/react-native/boost/boost/config/platform/symbian.hpp +97 -0
  88. package/react-native/boost/boost/config/platform/vms.hpp +25 -0
  89. package/react-native/boost/boost/config/platform/vxworks.hpp +422 -0
  90. package/react-native/boost/boost/config/platform/wasm.hpp +23 -0
  91. package/react-native/boost/boost/config/platform/win32.hpp +90 -0
  92. package/react-native/boost/boost/config/platform/zos.hpp +32 -0
  93. package/react-native/boost/boost/config/pragma_message.hpp +31 -0
  94. package/react-native/boost/boost/config/requires_threads.hpp +92 -0
  95. package/react-native/boost/boost/config/stdlib/dinkumware.hpp +324 -0
  96. package/react-native/boost/boost/config/stdlib/libcomo.hpp +93 -0
  97. package/react-native/boost/boost/config/stdlib/libcpp.hpp +180 -0
  98. package/react-native/boost/boost/config/stdlib/libstdcpp3.hpp +482 -0
  99. package/react-native/boost/boost/config/stdlib/modena.hpp +79 -0
  100. package/react-native/boost/boost/config/stdlib/msl.hpp +98 -0
  101. package/react-native/boost/boost/config/stdlib/roguewave.hpp +208 -0
  102. package/react-native/boost/boost/config/stdlib/sgi.hpp +168 -0
  103. package/react-native/boost/boost/config/stdlib/stlport.hpp +258 -0
  104. package/react-native/boost/boost/config/stdlib/vacpp.hpp +74 -0
  105. package/react-native/boost/boost/config/stdlib/xlcpp_zos.hpp +61 -0
  106. package/react-native/boost/boost/config/user.hpp +133 -0
  107. package/react-native/boost/boost/config/warning_disable.hpp +47 -0
  108. package/react-native/boost/boost/config/workaround.hpp +305 -0
  109. package/react-native/boost/boost/config.hpp +67 -0
  110. package/react-native/boost/boost/cstdint.hpp +556 -0
  111. package/react-native/boost/boost/intrusive_ptr.hpp +18 -0
  112. package/react-native/boost/boost/smart_ptr/detail/atomic_count.hpp +103 -0
  113. package/react-native/boost/boost/smart_ptr/detail/atomic_count_gcc.hpp +79 -0
  114. package/react-native/boost/boost/smart_ptr/detail/atomic_count_gcc_atomic.hpp +63 -0
  115. package/react-native/boost/boost/smart_ptr/detail/atomic_count_gcc_x86.hpp +88 -0
  116. package/react-native/boost/boost/smart_ptr/detail/atomic_count_nt.hpp +66 -0
  117. package/react-native/boost/boost/smart_ptr/detail/atomic_count_pt.hpp +104 -0
  118. package/react-native/boost/boost/smart_ptr/detail/atomic_count_spin.hpp +69 -0
  119. package/react-native/boost/boost/smart_ptr/detail/atomic_count_std_atomic.hpp +67 -0
  120. package/react-native/boost/boost/smart_ptr/detail/atomic_count_sync.hpp +72 -0
  121. package/react-native/boost/boost/smart_ptr/detail/atomic_count_win32.hpp +70 -0
  122. package/react-native/boost/boost/smart_ptr/detail/local_counted_base.hpp +148 -0
  123. package/react-native/boost/boost/smart_ptr/detail/local_sp_deleter.hpp +91 -0
  124. package/react-native/boost/boost/smart_ptr/detail/operator_bool.hpp +64 -0
  125. package/react-native/boost/boost/smart_ptr/detail/requires_cxx11.hpp +23 -0
  126. package/react-native/boost/boost/smart_ptr/detail/shared_count.hpp +707 -0
  127. package/react-native/boost/boost/smart_ptr/detail/sp_convertible.hpp +92 -0
  128. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base.hpp +92 -0
  129. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp +163 -0
  130. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_aix.hpp +152 -0
  131. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp +185 -0
  132. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_atomic.hpp +148 -0
  133. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp +170 -0
  134. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp +200 -0
  135. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp +194 -0
  136. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp +179 -0
  137. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp +186 -0
  138. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_nt.hpp +119 -0
  139. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_pt.hpp +147 -0
  140. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_snc_ps3.hpp +174 -0
  141. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_spin.hpp +141 -0
  142. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp +147 -0
  143. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_sync.hpp +165 -0
  144. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_vacpp_ppc.hpp +163 -0
  145. package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_w32.hpp +140 -0
  146. package/react-native/boost/boost/smart_ptr/detail/sp_counted_impl.hpp +309 -0
  147. package/react-native/boost/boost/smart_ptr/detail/sp_disable_deprecated.hpp +40 -0
  148. package/react-native/boost/boost/smart_ptr/detail/sp_forward.hpp +52 -0
  149. package/react-native/boost/boost/smart_ptr/detail/sp_has_gcc_intrinsics.hpp +27 -0
  150. package/react-native/boost/boost/smart_ptr/detail/sp_has_sync_intrinsics.hpp +69 -0
  151. package/react-native/boost/boost/smart_ptr/detail/sp_interlocked.hpp +173 -0
  152. package/react-native/boost/boost/smart_ptr/detail/sp_noexcept.hpp +48 -0
  153. package/react-native/boost/boost/smart_ptr/detail/sp_nullptr_t.hpp +45 -0
  154. package/react-native/boost/boost/smart_ptr/detail/sp_obsolete.hpp +32 -0
  155. package/react-native/boost/boost/smart_ptr/detail/sp_thread_pause.hpp +51 -0
  156. package/react-native/boost/boost/smart_ptr/detail/sp_thread_sleep.hpp +104 -0
  157. package/react-native/boost/boost/smart_ptr/detail/sp_thread_yield.hpp +100 -0
  158. package/react-native/boost/boost/smart_ptr/detail/sp_typeinfo_.hpp +58 -0
  159. package/react-native/boost/boost/smart_ptr/detail/sp_win32_sleep.hpp +49 -0
  160. package/react-native/boost/boost/smart_ptr/intrusive_ptr.hpp +409 -0
  161. package/react-native/boost/boost/smart_ptr/intrusive_ref_counter.hpp +188 -0
  162. package/react-native/cpp/include/Attachment.h +16 -0
  163. package/react-native/cpp/include/Authentication.h +23 -0
  164. package/react-native/cpp/include/Collection.h +13 -0
  165. package/react-native/cpp/include/DQL.h +21 -0
  166. package/react-native/cpp/include/Document.h +17 -0
  167. package/react-native/cpp/include/Identity.h +17 -0
  168. package/react-native/cpp/include/Lifecycle.h +16 -0
  169. package/react-native/cpp/include/LiveQuery.h +17 -0
  170. package/react-native/cpp/include/Logger.h +22 -0
  171. package/react-native/cpp/include/Misc.h +26 -0
  172. package/react-native/cpp/include/Presence.h +14 -0
  173. package/react-native/cpp/include/RetainableState.h +24 -0
  174. package/react-native/cpp/include/SmallPeerInfo.h +17 -0
  175. package/react-native/cpp/include/Transports.h +25 -0
  176. package/react-native/cpp/include/TypedArray.hpp +167 -0
  177. package/react-native/cpp/include/Utils.h +61 -0
  178. package/react-native/cpp/include/main.h +10 -0
  179. package/react-native/cpp/src/Attachment.cpp +86 -0
  180. package/react-native/cpp/src/Authentication.cpp +224 -0
  181. package/react-native/cpp/src/Collection.cpp +54 -0
  182. package/react-native/cpp/src/DQL.cpp +254 -0
  183. package/react-native/cpp/src/Document.cpp +146 -0
  184. package/react-native/cpp/src/Identity.cpp +123 -0
  185. package/react-native/cpp/src/Lifecycle.cpp +75 -0
  186. package/react-native/cpp/src/LiveQuery.cpp +64 -0
  187. package/react-native/cpp/src/Logger.cpp +200 -0
  188. package/react-native/cpp/src/Misc.cpp +271 -0
  189. package/react-native/cpp/src/Presence.cpp +77 -0
  190. package/react-native/cpp/src/RetainableState.cpp +15 -0
  191. package/react-native/cpp/src/SmallPeerInfo.cpp +108 -0
  192. package/react-native/cpp/src/Transports.cpp +270 -0
  193. package/react-native/cpp/src/TypedArray.cpp +303 -0
  194. package/react-native/cpp/src/Utils.cpp +138 -0
  195. package/react-native/cpp/src/main.cpp +149 -0
  196. package/react-native/dittoffi/dittoffi.h +4698 -0
  197. package/react-native/dittoffi/ifaddrs.cpp +385 -0
  198. package/react-native/dittoffi/ifaddrs.h +206 -0
  199. package/react-native/ios/DittoRNSDK.h +7 -0
  200. package/react-native/ios/DittoRNSDK.mm +107 -0
  201. package/react-native/ios/YeetJSIUtils.h +60 -0
  202. package/react-native/ios/YeetJSIUtils.mm +196 -0
  203. package/react-native/lib/commonjs/ditto.rn.js +93 -0
  204. package/react-native/lib/commonjs/ditto.rn.js.map +1 -0
  205. package/react-native/lib/commonjs/index.js +14 -0
  206. package/react-native/lib/commonjs/index.js.map +1 -0
  207. package/react-native/lib/module/ditto.rn.js +83 -0
  208. package/react-native/lib/module/ditto.rn.js.map +1 -0
  209. package/react-native/lib/module/index.js +13 -0
  210. package/react-native/lib/module/index.js.map +1 -0
  211. package/react-native/lib/typescript/ditto.rn.d.ts +15 -0
  212. package/react-native/lib/typescript/ditto.rn.d.ts.map +1 -0
  213. package/react-native/lib/typescript/index.d.ts +1 -0
  214. package/react-native/lib/typescript/index.d.ts.map +1 -0
  215. package/react-native/scripts/ruby/include_local_boost.rb +78 -0
  216. package/react-native/src/ditto.rn.ts +91 -0
  217. package/react-native/src/environment/environment.fallback.ts +4 -0
  218. package/react-native/src/index.ts +26 -0
  219. package/react-native/src/sources/@cbor-redux.ts +2 -0
  220. package/react-native/src/sources/@ditto.core.ts +1 -0
  221. package/react-native/src/sources/@environment.ts +2 -0
  222. package/react-native/src/sources/attachment-fetch-event.ts +54 -0
  223. package/react-native/src/sources/attachment-fetcher-manager.ts +129 -0
  224. package/react-native/src/sources/attachment-fetcher.ts +124 -0
  225. package/react-native/src/sources/attachment-token.ts +48 -0
  226. package/react-native/src/sources/attachment.ts +59 -0
  227. package/react-native/src/sources/augment.ts +89 -0
  228. package/react-native/src/sources/authenticator.ts +314 -0
  229. package/react-native/src/sources/base-pending-cursor-operation.ts +237 -0
  230. package/react-native/src/sources/base-pending-id-specific-operation.ts +109 -0
  231. package/react-native/src/sources/bridge.ts +549 -0
  232. package/react-native/src/sources/build-time-constants.ts +4 -0
  233. package/react-native/src/sources/cbor.ts +35 -0
  234. package/react-native/src/sources/collection-interface.ts +67 -0
  235. package/react-native/src/sources/collection.ts +212 -0
  236. package/react-native/src/sources/collections-event.ts +99 -0
  237. package/react-native/src/sources/counter.ts +77 -0
  238. package/react-native/src/sources/ditto.ts +945 -0
  239. package/react-native/src/sources/document-id.ts +159 -0
  240. package/react-native/src/sources/document-path.ts +303 -0
  241. package/react-native/src/sources/document.ts +192 -0
  242. package/react-native/src/sources/epilogue.ts +24 -0
  243. package/react-native/src/sources/error-codes.ts +52 -0
  244. package/react-native/src/sources/error.ts +203 -0
  245. package/react-native/src/sources/essentials.ts +53 -0
  246. package/react-native/src/sources/ffi-error.ts +117 -0
  247. package/react-native/src/sources/ffi.ts +1972 -0
  248. package/react-native/src/sources/identity.ts +163 -0
  249. package/react-native/src/sources/init.ts +70 -0
  250. package/react-native/src/sources/internal.ts +113 -0
  251. package/react-native/src/sources/keep-alive.ts +69 -0
  252. package/react-native/src/sources/key-path.ts +195 -0
  253. package/react-native/src/sources/live-query-event.ts +208 -0
  254. package/react-native/src/sources/live-query-manager.ts +101 -0
  255. package/react-native/src/sources/live-query.ts +164 -0
  256. package/react-native/src/sources/logger.ts +196 -0
  257. package/react-native/src/sources/observer-manager.ts +175 -0
  258. package/react-native/src/sources/observer.ts +77 -0
  259. package/react-native/src/sources/pending-collections-operation.ts +232 -0
  260. package/react-native/src/sources/pending-cursor-operation.ts +218 -0
  261. package/react-native/src/sources/pending-id-specific-operation.ts +216 -0
  262. package/react-native/src/sources/presence-manager.ts +160 -0
  263. package/react-native/src/sources/presence.ts +238 -0
  264. package/react-native/src/sources/query-result-item.ts +116 -0
  265. package/react-native/src/sources/query-result.ts +55 -0
  266. package/react-native/src/sources/register.ts +92 -0
  267. package/react-native/src/sources/small-peer-info.ts +176 -0
  268. package/react-native/src/sources/static-tcp-client.ts +6 -0
  269. package/react-native/src/sources/store-observer.ts +176 -0
  270. package/react-native/src/sources/store.ts +365 -0
  271. package/react-native/src/sources/subscription-manager.ts +98 -0
  272. package/react-native/src/sources/subscription.ts +88 -0
  273. package/react-native/src/sources/sync-subscription.ts +90 -0
  274. package/react-native/src/sources/sync.ts +495 -0
  275. package/react-native/src/sources/test-helpers.ts +24 -0
  276. package/react-native/src/sources/transport-conditions-manager.ts +104 -0
  277. package/react-native/src/sources/transport-config.ts +428 -0
  278. package/react-native/src/sources/update-result.ts +66 -0
  279. package/react-native/src/sources/update-results-map.ts +57 -0
  280. package/react-native/src/sources/websocket-client.ts +6 -0
  281. package/react-native/src/sources/write-transaction-collection.ts +122 -0
  282. package/react-native/src/sources/write-transaction-pending-cursor-operation.ts +101 -0
  283. package/react-native/src/sources/write-transaction-pending-id-specific-operation.ts +72 -0
  284. package/react-native/src/sources/write-transaction.ts +119 -0
  285. package/react-native.config.js +9 -0
  286. package/types/ditto.d.ts +1230 -798
  287. package/web/ditto.es6.js +1 -1
  288. package/web/ditto.umd.js +1 -1
  289. package/web/ditto.wasm +0 -0
@@ -0,0 +1,175 @@
1
+ //
2
+ // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
+ //
4
+
5
+ import { generateEphemeralToken } from './internal'
6
+ import { KeepAlive } from './keep-alive'
7
+
8
+ /** @internal */
9
+ export type ObserverToken = string
10
+
11
+ /** @internal */
12
+ export type ObserverManagerConstructorOptions = {
13
+ keepAlive?: KeepAlive
14
+ register?: (callback: (...args: any[]) => void) => void
15
+ unregister?: () => void
16
+ process?: (...args: any[]) => any[]
17
+ }
18
+
19
+ /** @internal */
20
+ export class ObserverManager {
21
+ /** @internal */
22
+ readonly id: string
23
+
24
+ /** @internal */
25
+ readonly keepAlive: KeepAlive | null
26
+
27
+ /** @internal */
28
+ constructor(id: string, options: ObserverManagerConstructorOptions = {}) {
29
+ const keepAlive = options.keepAlive ?? null
30
+ const register = options.register ?? null
31
+ const unregister = options.unregister ?? null
32
+ const process = options.process ?? null
33
+
34
+ this.id = id
35
+ this.keepAlive = keepAlive
36
+
37
+ this.isClosed = false
38
+ this.isRegistered = false
39
+ this.callbacksByToken = {}
40
+
41
+ if (register !== null) {
42
+ this.register = register
43
+ }
44
+
45
+ if (unregister !== null) {
46
+ this.unregister = unregister
47
+ }
48
+
49
+ if (process !== null) {
50
+ this.process = process
51
+ }
52
+ }
53
+
54
+ /** @internal */
55
+ addObserver(callback: any): ObserverToken {
56
+ if (this.isClosed) {
57
+
58
+ throw new Error(`Internal inconsistency, can't add '${this.id}' observer, observer mananger close()-ed.`)
59
+ }
60
+
61
+ this.registerIfNeeded()
62
+
63
+ const token = generateEphemeralToken()
64
+ this.callbacksByToken[token] = callback
65
+
66
+ this.keepAlive?.retain(`${this.id}.${token}`)
67
+ return token
68
+ }
69
+
70
+ /** @internal */
71
+ removeObserver(token: ObserverToken): void {
72
+ const callback = this.callbacksByToken[token]
73
+
74
+ if (typeof callback === 'undefined') {
75
+ throw new Error(`Can't remove '${this.id}' observer, token '${token}' has never been registered before.`)
76
+ }
77
+
78
+ if (callback === null) {
79
+ // Observer has already been removed, no-op.
80
+ return
81
+ }
82
+
83
+ this.callbacksByToken[token] = null
84
+
85
+ this.keepAlive?.release(`${this.id}.${token}`)
86
+ this.unregisterIfNeeded()
87
+ }
88
+
89
+ hasObserver(token: ObserverToken): boolean {
90
+ return typeof this.callbacksByToken[token] != 'undefined'
91
+ }
92
+
93
+ /** @internal */
94
+ notify(...args: any[]) {
95
+ if (this.isClosed) {
96
+
97
+ return
98
+ }
99
+
100
+ const processedArgs = this.process(...args)
101
+ for (const token in this.callbacksByToken) {
102
+ const callback = this.callbacksByToken[token]
103
+ if (callback) callback(...processedArgs)
104
+ }
105
+ }
106
+
107
+ /** @internal */
108
+ close() {
109
+ this.isClosed = true
110
+ for (const token in this.callbacksByToken) {
111
+ this.removeObserver(token)
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Can be injected and replaced via constructor options.
117
+ *
118
+ * @abstract
119
+ */
120
+ protected register(callback: (...args: any[]) => void) {
121
+ // No-op, subclasses may override and register.
122
+ }
123
+
124
+ /**
125
+ * Can be injected and replaced via constructor options.
126
+ *
127
+ * @abstract
128
+ */
129
+ protected unregister() {
130
+ // No-op, subclasses may override and unregister.
131
+ }
132
+
133
+ /**
134
+ * Can be injected and replaced via constructor options.
135
+ *
136
+ * @abstract
137
+ */
138
+ protected process(...args: any[]): any[] {
139
+ // No-op, subclasses may override and process/transform the callback parameters.
140
+ return args
141
+ }
142
+
143
+ private isClosed: boolean
144
+ private isRegistered: boolean
145
+ private callbacksByToken: { [key: string]: ((...args: any[]) => void) | null }
146
+ private constructorOptions: ObserverManagerConstructorOptions
147
+
148
+ private hasObservers(): boolean {
149
+ return Object.keys(this.callbacksByToken).length > 0
150
+ }
151
+
152
+ private registerIfNeeded() {
153
+ const needsToRegister = !this.isRegistered
154
+ if (needsToRegister) {
155
+ const weakThis = new WeakRef(this)
156
+ this.isRegistered = true
157
+ this.register(function (...args) {
158
+ const strongThis = weakThis.deref()
159
+ if (!strongThis) {
160
+ return
161
+ }
162
+
163
+ strongThis.notify(...args)
164
+ })
165
+ }
166
+ }
167
+
168
+ private unregisterIfNeeded() {
169
+ const needsToUnregister = !this.hasObservers() && this.isRegistered
170
+ if (needsToUnregister) {
171
+ this.isRegistered = false
172
+ this.unregister()
173
+ }
174
+ }
175
+ }
@@ -0,0 +1,77 @@
1
+ //
2
+ // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
+ //
4
+
5
+ import type { ObserverToken } from './observer-manager'
6
+
7
+ /** @internal */
8
+ interface ObserverManaging {
9
+ hasObserver(token: ObserverToken): boolean
10
+ removeObserver(token: ObserverToken): void
11
+ }
12
+
13
+ /** @internal */
14
+ export type ObserverOptions = {
15
+ stopsWhenFinalized?: boolean
16
+ }
17
+
18
+ /**
19
+ * Generic observer handle returned by various observation APIs. The observation
20
+ * remains active until the {@link stop | stop()} method is called explicitly or
21
+ * the observer instance is garbage collected. Therefore, to keep the observation
22
+ * alive, you have to keep a reference to the corresponding observer.
23
+ */
24
+ export class Observer {
25
+
26
+
27
+ /** @internal */
28
+ readonly observerManager: ObserverManaging
29
+
30
+ /** @internal */
31
+ get token(): ObserverToken | undefined {
32
+ return this._token
33
+ }
34
+
35
+ /** @internal */
36
+ readonly options?: ObserverOptions
37
+
38
+ /** @internal */
39
+ constructor(observerManager: ObserverManaging, token: any, options: ObserverOptions = {}) {
40
+ this.observerManager = observerManager
41
+ this._token = token
42
+ this.options = options
43
+
44
+ if (options.stopsWhenFinalized) {
45
+ Observer.finalizationRegistry.register(this, { observerManager, token }, this)
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Returns `true` if the observer has been explicitly stopped via the `stop()`
51
+ * method. Otherwise returns `false`.
52
+ */
53
+ get isStopped(): boolean {
54
+ return this.token !== undefined && this.observerManager.hasObserver(this.token)
55
+ }
56
+
57
+ /**
58
+ * Stops the observation. Calling this method multiple times has no effect.
59
+ */
60
+ stop() {
61
+ const token = this.token
62
+ if (token) {
63
+ delete this._token
64
+ Observer.finalizationRegistry.unregister(this)
65
+ this.observerManager.removeObserver(token)
66
+ }
67
+ }
68
+
69
+ private static finalizationRegistry = new FinalizationRegistry(Observer.finalize)
70
+
71
+ private _token?: ObserverToken
72
+
73
+ private static finalize(observerManagerAndToken: { observerManager: ObserverManaging; token: ObserverToken }) {
74
+ const { observerManager, token } = observerManagerAndToken
75
+ observerManager.removeObserver(token)
76
+ }
77
+ }
@@ -0,0 +1,232 @@
1
+ //
2
+ // Copyright (c) 2020 - 2021 DittoLive Inc. All rights reserved.
3
+ //
4
+
5
+ import { Collection } from './collection'
6
+ import { Document } from './document'
7
+ import { Store } from './store'
8
+ import { Subscription } from './subscription'
9
+ import { PendingCursorOperation } from './pending-cursor-operation'
10
+
11
+ import { CollectionsEvent } from './collections-event'
12
+ import { LiveQuery } from './live-query'
13
+
14
+ import type { SortDirection } from './essentials'
15
+ // -----------------------------------------------------------------------------
16
+
17
+ /**
18
+ * The closure that is called whenever the collections covered by a live query
19
+ * change.
20
+ */
21
+ export type CollectionsObservationHandler = (event: CollectionsEvent, signalNext?: () => void) => void | Promise<void>
22
+
23
+ // -----------------------------------------------------------------------------
24
+
25
+ /**
26
+ * These objects are returned when calling
27
+ * {@link Store.collections | collections()} on {@link Store}.
28
+ *
29
+ * They allow chaining of further collections-related functions. You can either
30
+ * call {@link exec | exec()} on the object to get an array of
31
+ * {@link Collection}s as an immediate return value, or you can establish either
32
+ * a live query or a subscription, which both work over time.
33
+ *
34
+ * A live query, established by calling
35
+ * {@link PendingCollectionsOperation.observeLocal | observeLocal()}, will
36
+ * notify you every time there's a change in the collections that the device
37
+ * knows about.
38
+ *
39
+ * A subscription, established by calling {@link subscribe | subscribe()}, will
40
+ * act as a signal to other peers that the device connects to that you would
41
+ * like to receive updates from them about the collections that they know about.
42
+ */
43
+ export class PendingCollectionsOperation implements PromiseLike<Collection[]> {
44
+ /**
45
+ * Sort the collections based on a property of the collection.
46
+ *
47
+ * @param propertyPath The property path specifies the logic to be used when
48
+ * sorting the matching collections.
49
+ *
50
+ * @param direction Specify whether you want the sorting order to be
51
+ * `Ascending` or `Descending`.
52
+ *
53
+ * @return A {@link PendingCollectionsOperation} that you can chain further
54
+ * function calls to.
55
+ */
56
+ sort(propertyPath: string, direction: SortDirection = 'ascending'): PendingCollectionsOperation {
57
+ this.pendingCursorOperation.sort(propertyPath, direction)
58
+ return this
59
+ }
60
+
61
+ /**
62
+ * Offset the resulting set of collections.
63
+ *
64
+ * This is useful if you aren't interested in the first N collections for one
65
+ * reason or another. For example, you might already have obtained the first
66
+ * 20 collections and so you might want to get the next 20 collections, and
67
+ * that is when you would use {@link offset | offset()}.
68
+ *
69
+ * @param offset The number of collections that you want the eventual
70
+ * resulting set of collections to be offset by (and thus not include).
71
+ *
72
+ * @return A {@link PendingCollectionsOperation} that you can chain further
73
+ * function calls to.
74
+ */
75
+ offset(offset: number): PendingCollectionsOperation {
76
+ this.pendingCursorOperation.offset(offset)
77
+ return this
78
+ }
79
+
80
+ /**
81
+ * Limit the number of collections that get returned.
82
+ *
83
+ * @param limit The maximum number of collections that will be returned.
84
+ *
85
+ * @return A {@link PendingCollectionsOperation} that you can chain further
86
+ * function calls to.
87
+ */
88
+ limit(limit: number): PendingCollectionsOperation {
89
+ this.pendingCursorOperation.limit(limit)
90
+ return this
91
+ }
92
+
93
+ /**
94
+ * Subscribes the device to updates about collections that other devices know
95
+ * about.
96
+ *
97
+ * The returned {@link Subscription} object must be kept in scope for as long
98
+ * as you want to keep receiving updates.
99
+ *
100
+ * @return A {@link Subscription} object that must be kept in scope for as
101
+ * long as you want to keep receiving updates from other devices about the
102
+ * collections that they know about.
103
+ */
104
+ subscribe(): Subscription {
105
+ return this.pendingCursorOperation.subscribe()
106
+ }
107
+
108
+ /**
109
+ * Enables you to listen for changes that occur in relation to the collections
110
+ * that are known about locally.
111
+ *
112
+ * The returned {@link LiveQuery} object must be kept in scope for as long as
113
+ * you want the provided `handler` to be called when an update occurs.
114
+ *
115
+ * This won't subscribe to receive updates from other devices and so it will
116
+ * only fire when a local change to the known about collections occurs. If
117
+ * you want to receive remote updates as well, then create a subscription via
118
+ * {@link PendingCollectionsOperation.subscribe | subscribe()}.
119
+ *
120
+ * @param handler A closure that will be called every time there is an update
121
+ * about the list of known about collections.
122
+ *
123
+ * @return A {@link LiveQuery} object that must be kept in scope for as long
124
+ * as you want to keep receiving updates.
125
+ */
126
+ observeLocal(handler: CollectionsObservationHandler): LiveQuery {
127
+ return this._observe(handler, false)
128
+ }
129
+
130
+ /**
131
+ * Enables you to listen for changes that occur in relation to the collections
132
+ * that are known about locally.
133
+ *
134
+ * The returned {@link LiveQuery} object must be kept in scope for as long as
135
+ * you want the provided `handler` to be called when an update occurs.
136
+ *
137
+ * This won't subscribe to receive updates from other devices and so it will
138
+ * only fire when a local change to the known about collections occurs. If
139
+ * you want to receive remote updates as well, then create a subscription via
140
+ * {@link PendingCollectionsOperation.subscribe | subscribe()}.
141
+ *
142
+ * @param handler A closure that will be called every time there is an update
143
+ * about the list of known about collections.
144
+ *
145
+ * @return A {@link LiveQuery} object that must be kept in scope for as long
146
+ * as you want to keep receiving updates.
147
+ */
148
+ observeLocalWithNextSignal(handler: CollectionsObservationHandler): LiveQuery {
149
+ return this._observe(handler, true)
150
+ }
151
+
152
+ /**
153
+ * Return the list of collections requested based on the preceding function
154
+ * chaining.
155
+ *
156
+ * @return A list of {@link Collection}s based on the preceding function
157
+ * chaining.
158
+ */
159
+ async exec(): Promise<Collection[]> {
160
+ const documents = await this.pendingCursorOperation.exec()
161
+ return collectionsFromDocuments(documents, this.store)
162
+ }
163
+
164
+ /** @internal */
165
+ readonly store: Store
166
+
167
+ /** @internal */
168
+ constructor(store: Store) {
169
+ this.store = store
170
+ this.pendingCursorOperation = new PendingCursorOperation('true', null, new Collection('__collections', store))
171
+ }
172
+
173
+ /** @internal */
174
+ then<TResult1 = any, TResult2 = never>(onfulfilled?: ((value: any) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined): PromiseLike<TResult1 | TResult2> {
175
+ return this.exec().then(onfulfilled, onrejected)
176
+ }
177
+
178
+ // ----------------------------------------------------------- Internal ------
179
+
180
+ /** @internal */
181
+ _observe(handler: CollectionsObservationHandler, waitForNextSignal: boolean): LiveQuery {
182
+ const weakStore = new WeakRef(this.store)
183
+ const collectionsObservationHandler = function (documents, event, nextSignal) {
184
+ const strongStore = weakStore.deref()
185
+ if (!strongStore) {
186
+ return
187
+ }
188
+
189
+ const collections = collectionsFromDocuments(documents, strongStore)
190
+ let collEvent: CollectionsEvent
191
+
192
+ if (event.isInitial === true) {
193
+ collEvent = CollectionsEvent.initial(collections)
194
+ } else {
195
+ const oldCollections = collectionsFromDocuments(event.oldDocuments, strongStore)
196
+ collEvent = new CollectionsEvent({
197
+ isInitial: false,
198
+ collections,
199
+ oldCollections,
200
+ insertions: event.insertions,
201
+ deletions: event.deletions,
202
+ updates: event.updates,
203
+ moves: event.moves,
204
+ })
205
+ }
206
+
207
+ if (waitForNextSignal) {
208
+ handler(collEvent, nextSignal)
209
+ } else {
210
+ handler(collEvent)
211
+ }
212
+ }
213
+
214
+ return this.pendingCursorOperation._observe(collectionsObservationHandler, waitForNextSignal)
215
+ }
216
+
217
+ // ------------------------------------------------------------ Private ------
218
+
219
+ private readonly pendingCursorOperation: PendingCursorOperation
220
+ }
221
+
222
+ /** @private */
223
+ function collectionsFromDocuments(documents: Document[], store: Store): Collection[] {
224
+ const collections: Collection[] = []
225
+ for (const document of documents) {
226
+ const collectionName = document.at('name').value
227
+ if (collectionName !== undefined && typeof collectionName === 'string') {
228
+ collections.push(new Collection(collectionName, store))
229
+ }
230
+ }
231
+ return collections
232
+ }
@@ -0,0 +1,218 @@
1
+ //
2
+ // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
+ //
4
+
5
+ import * as FFI from './ffi'
6
+
7
+ import { Bridge } from './bridge'
8
+ import { Subscription } from './subscription'
9
+ import { DocumentID } from './document-id'
10
+ import { LiveQuery } from './live-query'
11
+ import { performAsyncToWorkaroundNonAsyncFFIAPI } from './internal'
12
+ import { BasePendingCursorOperation } from './base-pending-cursor-operation'
13
+
14
+ import type { QueryArguments, SortDirection } from './essentials'
15
+ import type { Document, MutableDocument } from './document'
16
+ import type { UpdateResultsMap } from './update-results-map'
17
+ import type { LiveQueryEvent } from './live-query-event'
18
+ import type { Collection } from './collection'
19
+
20
+ // -----------------------------------------------------------------------------
21
+
22
+ /**
23
+ * The closure that is called whenever the documents covered by a live query
24
+ * change.
25
+ */
26
+ export type QueryObservationHandler = (documents: Document[], event: LiveQueryEvent, signalNext?: () => void) => void | Promise<void>
27
+
28
+ // -----------------------------------------------------------------------------
29
+
30
+ /**
31
+ * These objects are returned when using `find`-like functionality on
32
+ * {@link Collection}.
33
+ *
34
+ * They allow chaining of further query-related functions to do things like add
35
+ * a limit to the number of documents you want returned or specify how you want
36
+ * the documents to be sorted and ordered.
37
+ *
38
+ * You can either call {@link exec | exec()} on the object to get an array of
39
+ * {@link Document | documents} as an immediate return value, or you can
40
+ * establish either a live query or a subscription, which both work over time.
41
+ *
42
+ * A live query, established by calling
43
+ * {@link PendingCursorOperation.observeLocal | observeLocal()}, will notify you
44
+ * every time there's an update to a document that matches the query you
45
+ * provided in the preceding `find`-like call.
46
+ *
47
+ * A subscription, established by calling
48
+ * {@link PendingCursorOperation.subscribe | subscribe()}, will act as a signal
49
+ * to other peers that the device connects to that you would like to receive
50
+ * updates from them about documents that match the query you provided in the
51
+ * preceding `find`-like call.
52
+ *
53
+ * Update and remove functionality is also exposed through this object.
54
+ */
55
+ export class PendingCursorOperation extends BasePendingCursorOperation {
56
+ sort(propertyPath: string, direction: SortDirection = 'ascending'): PendingCursorOperation {
57
+ return super.sort(propertyPath, direction) as PendingCursorOperation
58
+ }
59
+
60
+ offset(offset: number): PendingCursorOperation {
61
+ return super.offset(offset) as PendingCursorOperation
62
+ }
63
+
64
+ limit(limit: number): PendingCursorOperation {
65
+ return super.limit(limit) as PendingCursorOperation
66
+ }
67
+
68
+ async remove(): Promise<DocumentID[]> {
69
+ const ditto = this.collection.store.ditto
70
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
71
+ return ditto.deferCloseAsync(async () => {
72
+ const query = this.query
73
+ const documentsX = await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
74
+ const writeTransactionX = await FFI.writeTransaction(dittoHandle.deref())
75
+ const results = await FFI.collectionRemoveQueryStr(dittoHandle.deref(), this.collection.name, writeTransactionX, query, this.queryArgsCBOR, this.orderBys, this.currentLimit, this.currentOffset)
76
+ await FFI.writeTransactionCommit(dittoHandle.deref(), writeTransactionX)
77
+ return results
78
+ })
79
+
80
+ return documentsX.map((idCBOR: Uint8Array) => {
81
+ return new DocumentID(idCBOR, true)
82
+ })
83
+ })
84
+ }
85
+
86
+ async evict(): Promise<DocumentID[]> {
87
+ const ditto = this.collection.store.ditto
88
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
89
+ return ditto.deferCloseAsync(async () => {
90
+ const query = this.query
91
+ const documentsX = await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
92
+ const writeTransactionX = await FFI.writeTransaction(dittoHandle.deref())
93
+ const results = await FFI.collectionEvictQueryStr(dittoHandle.deref(), this.collection.name, writeTransactionX, query, this.queryArgsCBOR, this.orderBys, this.currentLimit, this.currentOffset)
94
+ await FFI.writeTransactionCommit(dittoHandle.deref(), writeTransactionX)
95
+ return results
96
+ })
97
+
98
+ return documentsX.map((idCBOR: Uint8Array) => {
99
+ return new DocumentID(idCBOR, true)
100
+ })
101
+ })
102
+ }
103
+
104
+ async update(closure: (documents: MutableDocument[]) => void): Promise<UpdateResultsMap> {
105
+ const ditto = this.collection.store.ditto
106
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
107
+ return ditto.deferCloseAsync(async () => {
108
+ return await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
109
+ const writeTransactionX = await FFI.writeTransaction(dittoHandle.deref())
110
+ const results = await super.updateWithTransaction(closure, writeTransactionX)
111
+ await FFI.writeTransactionCommit(dittoHandle.deref(), writeTransactionX)
112
+ return results
113
+ })
114
+ })
115
+ }
116
+
117
+ /**
118
+ * Enables you to subscribe to changes that occur in a collection remotely.
119
+ *
120
+ * Having a subscription acts as a signal to other peers that you are
121
+ * interested in receiving updates when local or remote changes are made to
122
+ * documents that match the query generated by the chain of operations that
123
+ * precedes the call to {@link subscribe | subscribe()}.
124
+ *
125
+ * The returned {@link Subscription} object must be kept in scope for as long
126
+ * as you want to keep receiving updates.
127
+ *
128
+ * @returns A {@link Subscription} object that must be kept in scope for as
129
+ * long as you want to keep receiving updates for documents that match the
130
+ * query specified in the preceding chain.
131
+ */
132
+ subscribe(): Subscription {
133
+ const subscription = new Subscription(this.collection as Collection, this.query, this.queryArgsCBOR, this.orderBys, this.currentLimit, this.currentOffset)
134
+ this.collection.store.ditto.subscriptionManager.add(subscription)
135
+ return subscription
136
+ }
137
+
138
+ /**
139
+ * Enables you to listen for changes that occur in a collection locally.
140
+ *
141
+ * The `handler` block will be called when local changes are
142
+ * made to documents that match the query generated by the chain of operations
143
+ * that precedes the call to {@link PendingCursorOperation.observeLocal | observeLocal()}.
144
+ * The returned {@link LiveQuery} object must be kept in scope for as long as
145
+ * you want the provided `handler` to be called when an update occurs.
146
+ *
147
+ * This won't subscribe to receive changes made remotely by others and so it
148
+ * will only fire updates when a local change is made. If you want to receive
149
+ * remotely performed updates as well, you'll have to create a subscription
150
+ * via {@link PendingCursorOperation.subscribe | subscribe()} with the
151
+ * relevant query. The returned {@link LiveQuery} object must be kept in scope
152
+ * for as long as you want the provided `eventHandler` to be called when an
153
+ * update occurs.
154
+ *
155
+ * @param handler A closure that will be called every time there is a
156
+ * transaction committed to the store that involves modifications to documents
157
+ * matching the query in the collection this method was called on.
158
+ *
159
+ * @return A {@link LiveQuery} object that must be kept in scope for as long
160
+ * as you want to keep receiving updates.
161
+ */
162
+ observeLocal(handler: QueryObservationHandler): LiveQuery {
163
+ return this._observe(handler, false)
164
+ }
165
+
166
+ /**
167
+ * Enables you to listen for changes that occur in a collection locally and
168
+ * to signal when you are ready for the live query to deliver the next event.
169
+ *
170
+ * The `handler` block will be called when local changes are
171
+ * made to documents that match the query generated by the chain of operations
172
+ * that precedes the call to {@link PendingCursorOperation.observeLocalWithNextSignal | observeLocalWithNextSignal()}.
173
+ * The returned {@link LiveQuery} object must be kept in scope for as long as
174
+ * you want the provided `handler` to be called when an update occurs.
175
+ *
176
+ * This won't subscribe to receive changes made remotely by others and so it
177
+ * will only fire updates when a local change is made. If you want to receive
178
+ * remotely performed updates as well, you'll have to create a subscription
179
+ * via {@link PendingCursorOperation.subscribe | subscribe()} with the
180
+ * relevant query. The returned {@link LiveQuery} object must be kept in scope
181
+ * for as long as you want the provided `eventHandler` to be called when an
182
+ * update occurs.
183
+ *
184
+ * @param handler A closure that will be called every time there is a
185
+ * transaction committed to the store that involves modifications to
186
+ * documents matching the query in the collection that this method was called
187
+ * on.
188
+ *
189
+ * @return A {@link LiveQuery} object that must be kept in scope for as long
190
+ * as you want to keep receiving updates.
191
+ */
192
+ observeLocalWithNextSignal(handler: QueryObservationHandler): LiveQuery {
193
+ return this._observe(handler, true)
194
+ }
195
+
196
+ // ----------------------------------------------------------- Internal ------
197
+
198
+ /** @internal */
199
+ constructor(query: string, queryArgs: QueryArguments | null, collection: Collection) {
200
+ super(query, queryArgs, collection)
201
+ }
202
+
203
+ /** @internal */
204
+ _observe(handler: QueryObservationHandler, waitForNextSignal: boolean): LiveQuery {
205
+ function wrappedHandler(documents, event, nextSignal) {
206
+ try {
207
+ return handler.call(this, documents, event)
208
+ } finally {
209
+ nextSignal()
210
+ }
211
+ }
212
+
213
+ const handlerOrWrapped: QueryObservationHandler = waitForNextSignal ? handler : wrappedHandler
214
+ const liveQuery = new LiveQuery(this.query, this.queryArgs, this.queryArgsCBOR, this.orderBys, this.currentLimit, this.currentOffset, this.collection as Collection, handlerOrWrapped)
215
+ this.collection.store.ditto.liveQueryManager.startLiveQuery(liveQuery)
216
+ return liveQuery
217
+ }
218
+ }