@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,365 @@
1
+ //
2
+ // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
+ //
4
+
5
+ import * as FFI from './ffi'
6
+ import { Bridge } from './bridge'
7
+
8
+ import { CBOR, documentIDReplacer } from './cbor'
9
+ import { Collection } from './collection'
10
+ import { StoreObserver } from './store-observer'
11
+ import { DocumentID } from './document-id'
12
+ import { DittoError, mapFFIErrors, mapFFIErrorsAsync } from './error'
13
+ import { performAsyncToWorkaroundNonAsyncFFIAPI, step, validateQuery } from './internal'
14
+ import { Logger } from './logger'
15
+ import { PendingCollectionsOperation } from './pending-collections-operation'
16
+ import { QueryResult } from './query-result'
17
+ import { WriteTransaction } from './write-transaction'
18
+
19
+ import type { StoreObservationHandlerWithSignalNext, StoreObservationHandler } from './store-observer'
20
+ import type { Ditto } from './ditto'
21
+ import type { DQLQueryArguments } from './essentials'
22
+ import type { QueryResultItem } from './query-result-item'
23
+ import type { WriteTransactionResult } from './write-transaction'
24
+
25
+ /**
26
+ * The entrypoint for all actions that relate to data stored by Ditto. Provides
27
+ * access to collections, a write transaction API, and a query hash API.
28
+ *
29
+ * You don't create one directly but can access it from a particular
30
+ * {@link Ditto} instance via its {@link Ditto.store | store} property.
31
+ */
32
+ export class Store {
33
+ /** The {@link Ditto} instance this store belongs to. */
34
+ readonly ditto: Ditto
35
+
36
+ /**
37
+ * All currently active store observers.
38
+ *
39
+ * **Note:** Manage store observers using
40
+ * {@link registerObserver | registerObserver()} to register a new store
41
+ * observer and {@link StoreObserver.cancel | StoreObserver.cancel()} to
42
+ * remove an existing store observer.
43
+ */
44
+ readonly observers: Readonly<Array<StoreObserver>> = Object.freeze([])
45
+
46
+ /**
47
+ * Register a handler to be called whenever a query's results change in the
48
+ * local store.
49
+ *
50
+ * Convenience method, same as
51
+ * {@link registerObserverWithSignalNext | registerObserverWithSignalNext()},
52
+ * except that here, the next invocation of the observation handler is
53
+ * triggered automatically instead of having to call the passed in
54
+ * `signalNext` function.
55
+ *
56
+ * @param query a string containing a valid query expressed in DQL.
57
+ * @param observationHandler a function that is called whenever the query's results
58
+ * change. The function is passed a {@link QueryResult} containing a
59
+ * {@link QueryResultItem} for each match.
60
+ * @param queryArguments an object of values keyed by the placeholder name
61
+ * without the leading `:`. Example: `{ "name": "Joanna" }` for a query like
62
+ * `SELECT * FROM people WHERE name = :name`.
63
+ * @returns a {@link StoreObserver} that can be used to cancel the
64
+ * observation.
65
+ * @throws {@link DittoError} `query/invalid`: if `query` argument is not a
66
+ * string or not valid DQL.
67
+ * @throws {@link DittoError} `query/arguments-invalid`: if `queryArguments`
68
+ * argument is invalid (e.g. contains unsupported types).
69
+ * @throws {@link DittoError} `query/unsupported`: if the query is not a
70
+ * `SELECT` query.
71
+ * @throws {@link DittoError} may throw other errors.
72
+ */
73
+ registerObserver(query: string, observationHandler: StoreObservationHandler, queryArguments?: DQLQueryArguments): StoreObserver {
74
+ const changeHandlerWithSignalNext: StoreObservationHandlerWithSignalNext = (queryResult: QueryResult, signalNext: () => void) => {
75
+ observationHandler(queryResult)
76
+ signalNext()
77
+ }
78
+ return this.registerObserverWithSignalNext(query, changeHandlerWithSignalNext, queryArguments)
79
+ }
80
+
81
+ /**
82
+ * Registers and returns a store observer for a query, configuring Ditto to
83
+ * trigger the passed in observation handler whenever documents in the local
84
+ * store change such that the result of the matching query changes. The passed
85
+ * in query must be a `SELECT` query.
86
+ *
87
+ * Here, a function is passed as an additional argument to the observation
88
+ * handler. Call this function as soon as the observation handler is ready to
89
+ * process the the next change event. This allows the observation handler to
90
+ * control how frequently it is called. See
91
+ * {@link registerObserver | registerObserver()} for a convenience method that
92
+ * automatically signals the next invocation.
93
+ *
94
+ * The first invocation of `observationHandler` will always happen after this
95
+ * method has returned.
96
+ *
97
+ * @param query a string containing a valid query expressed in DQL.
98
+ * @param observationHandler an observation handler function that is called
99
+ * whenever the query's results change. The function is passed a
100
+ * {@link QueryResult} containing a {@link QueryResultItem} for each match.
101
+ * @param queryArguments an object of values keyed by the placeholder name
102
+ * without the leading `:`. Example: `{ "name": "Joanna" }` for a query like
103
+ * `SELECT * FROM people WHERE name = :name`.
104
+ * @returns a {@link StoreObserver} that can be used to cancel the
105
+ * observation.
106
+ * @throws {@link DittoError} `query/invalid`: if `query` argument is not a
107
+ * string or not valid DQL.
108
+ * @throws {@link DittoError} `query/arguments-invalid`: if `queryArguments`
109
+ * argument is invalid (e.g. contains unsupported types).
110
+ * @throws {@link DittoError} `query/unsupported`: if the query is not a
111
+ * `SELECT` query.
112
+ * @throws {@link DittoError} may throw other errors.
113
+ */
114
+ registerObserverWithSignalNext(query: string, observationHandler: StoreObservationHandlerWithSignalNext, queryArguments?: DQLQueryArguments): StoreObserver {
115
+ if (typeof query !== 'string') {
116
+ throw new DittoError('query/invalid', `Expected parameter 'query' to be of type 'string', found: ${typeof query}`)
117
+ }
118
+
119
+ const storeObserver = new StoreObserver(this.ditto, query, queryArguments ?? null, observationHandler)
120
+
121
+ this.observers = Object.freeze([...this.observers, storeObserver])
122
+
123
+
124
+ const dittoHandle = Bridge.ditto.handleFor(this.ditto)
125
+ this.ditto.deferCloseAsync(async () => {
126
+ return new Promise<void>((resolve) => {
127
+ step(async () => {
128
+ try {
129
+ // prettier-ignore
130
+ await mapFFIErrorsAsync(
131
+ async () => await FFI.liveQueryStart(dittoHandle.deref(), storeObserver.liveQueryID)
132
+ )
133
+ } catch (error: any) {
134
+
135
+ Logger.error(`Failed to start live query: ${error.message}`)
136
+ }
137
+ resolve()
138
+ })
139
+ })
140
+ })
141
+
142
+ return storeObserver
143
+ }
144
+
145
+ /**
146
+ * Returns the collection for the given name. If the collection doesn't
147
+ * exist yet, it will be created automatically as soon as the first
148
+ * entry is inserted.
149
+ * A collection name is valid if:
150
+ * * its length is less than 100
151
+ * * it is not empty
152
+ * * it does not contain the char '\0'
153
+ * * it does not begin with "$TS_"
154
+ */
155
+ collection(name: string): Collection {
156
+ return new Collection(name, this)
157
+ }
158
+
159
+ /**
160
+ * Returns an object that lets you fetch or observe the collections in the
161
+ * store.
162
+ *
163
+ * @return A {@link PendingCollectionsOperation} object that you can use to
164
+ * fetch or observe the collections in the store
165
+ */
166
+ collections(): PendingCollectionsOperation {
167
+ return new PendingCollectionsOperation(this)
168
+ }
169
+
170
+ /**
171
+ * Returns the names of all available collections in the store of the
172
+ * related {@link Ditto} instance.
173
+ */
174
+ collectionNames(): Promise<string[]> {
175
+ const ditto = this.ditto
176
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
177
+ return ditto.deferClose(() => {
178
+ return mapFFIErrors(() => FFI.dittoGetCollectionNames(dittoHandle.deref()))
179
+ })
180
+ }
181
+
182
+ /**
183
+ * Executes a DQL query and returns matching items as a query result.
184
+ *
185
+ * @param query a string containing a valid query expressed in DQL.
186
+ * @param queryArguments an object of values keyed by the placeholder name
187
+ * without the leading `:`. Example: `{ "name": "John" }` for a query like
188
+ * `SELECT * FROM people WHERE name = :name`.
189
+ * @returns a promise for a {@link QueryResult} containing a
190
+ * {@link QueryResultItem} for each match.
191
+ * @throws {@link DittoError} `query/invalid`: if `query` argument is not a
192
+ * string or not valid DQL.
193
+ * @throws {@link DittoError} `query/arguments-invalid`: if `queryArguments`
194
+ * argument is invalid (e.g. contains unsupported types).
195
+ * @throws {@link DittoError} may throw other errors.
196
+ */
197
+ async execute(query: string, queryArguments?: DQLQueryArguments): Promise<QueryResult> {
198
+ if (typeof query !== 'string') {
199
+ throw new DittoError('query/invalid', `Expected parameter 'query' to be of type 'string', found: ${typeof query}`)
200
+ }
201
+
202
+ const dittoHandle = Bridge.ditto.handleFor(this.ditto)
203
+ return this.ditto.deferCloseAsync(async () => {
204
+ const writeTransaction = null
205
+
206
+ let queryArgumentsCBOR: Uint8Array | null = null
207
+ if (queryArguments != null) {
208
+ try {
209
+ queryArgumentsCBOR = CBOR.encode(queryArguments, documentIDReplacer)
210
+ } catch (error: any) {
211
+ throw new DittoError('query/arguments-invalid', `Unable to encode query arguments: ${error.message}`)
212
+ }
213
+ }
214
+
215
+ const errorContext = { query, queryArguments }
216
+
217
+ const responsePointer: FFI.Pointer<FFI.FFIDqlResponse> = await mapFFIErrorsAsync(
218
+ async () => await performAsyncToWorkaroundNonAsyncFFIAPI(
219
+ () => FFI.tryExperimentalExecQueryStr(dittoHandle.deref(), writeTransaction, query, queryArgumentsCBOR)
220
+ ),
221
+ undefined,
222
+ errorContext
223
+ )
224
+
225
+ return Bridge.dqlResponse.bridge(responsePointer, () => new QueryResult(responsePointer))
226
+ })
227
+ }
228
+
229
+ /**
230
+ * Initiate a write transaction in a callback.
231
+ *
232
+ * Allows you to group multiple operations together that affect multiple documents, potentially across multiple collections.
233
+ *
234
+ * @param callback is given access to a {@link WriteTransaction | write transaction object} that can be used to perform operations on the store.
235
+ * @returns a list of `WriteTransactionResult`s. There is a result for each operation performed as part of the write transaction.
236
+ */
237
+ async write(callback: (transaction: WriteTransaction) => Promise<void>): Promise<WriteTransactionResult[]> {
238
+ return this.ditto.deferCloseAsync(async () => {
239
+ const transaction = await WriteTransaction.init(this.ditto)
240
+
241
+ try {
242
+ await callback(transaction)
243
+ } catch (error: any) {
244
+ await transaction.rollback()
245
+ Logger.warning(`Transaction rolled back due to an error: ${error?.message}`)
246
+ throw error
247
+ }
248
+ await transaction.commit()
249
+
250
+ return transaction.results
251
+ })
252
+ }
253
+
254
+ // ----------------------------------------------------------- Internal ------
255
+
256
+ /** @internal */
257
+ constructor(ditto: Ditto) {
258
+ this.ditto = ditto
259
+ }
260
+
261
+ /**
262
+ * Registers a URL to be called whenever the given `SELECT` query observes
263
+ * changes.
264
+ *
265
+ * No validation is performed on the URL, so it is up to the caller to ensure
266
+ * that the URL is valid and can be reached.
267
+ *
268
+ * @internal
269
+ * @returns a promise for a document id that acts as a webhook id
270
+ * @throws {@link DittoError} `store/query-invalid`: if the query is invalid
271
+ * @throws {@link DittoError} `store/query-arguments-invalid`: if the query arguments
272
+ * are invalid
273
+ * @throws {@link DittoError} `store/query-unsupported`: if the query is not a
274
+ * `SELECT` query
275
+ * @throws {@link DittoError} for any other error that occurs during query execution
276
+ */
277
+ async registerObserverWebhook(query: string, url: string, queryArguments?: DQLQueryArguments): Promise<DocumentID> {
278
+ let queryArgumentsCBOR: Uint8Array | null = null
279
+ if (queryArguments != null) {
280
+ try {
281
+ queryArgumentsCBOR = CBOR.encode(queryArguments, documentIDReplacer)
282
+ } catch (error: any) {
283
+ throw new DittoError('query/arguments-invalid', `Invalid query arguments: ${error.message}`)
284
+ }
285
+ }
286
+
287
+ const errorContext = { query, queryArguments }
288
+
289
+ const dittoHandle = Bridge.ditto.handleFor(this.ditto)
290
+ return this.ditto.deferCloseAsync(async () => {
291
+ const webhookIDCBOR = await mapFFIErrorsAsync(
292
+ async () => await FFI.tryExperimentalWebhookRegisterDqlLiveQuery(dittoHandle.deref(), query, queryArgumentsCBOR, url),
293
+ undefined,
294
+ errorContext
295
+ )
296
+ return new DocumentID(webhookIDCBOR, true)
297
+ })
298
+ }
299
+
300
+ /**
301
+ * Unregister a store observer. No-op if the change observer has already
302
+ * been removed.
303
+ *
304
+ * This must only be called by the store observer itself.
305
+ *
306
+ * @param changeObserver the store observer to unregister
307
+ * @returns true if the store observer was found and removed, false otherwise
308
+ * @throws {@link DittoError} `internal`: if the store observer does not belong to
309
+ * this store
310
+ * @throws {@link DittoError} `internal`: if the store observer has not been
311
+ * cancelled yet
312
+ * @throws {@link DittoError} `internal`: for any other error that occurs while
313
+ * trying to unregister the store observer
314
+ * @internal
315
+ */
316
+ unregisterObserver(storeObserver: StoreObserver): boolean {
317
+ if (storeObserver.ditto !== this.ditto) {
318
+ throw new DittoError('internal', `Internal inconsistency, can't remove store observer that does not belong to this store`)
319
+ }
320
+
321
+ if (!storeObserver.isCancelled) {
322
+ throw new DittoError('internal', "Internal inconsistency, can't remove store observer that has not been cancelled")
323
+ }
324
+
325
+ const indexToDelete = this.observers.findIndex((observer) => observer === storeObserver)
326
+ if (indexToDelete === -1) {
327
+ return false
328
+ }
329
+
330
+ const newObservers = [...this.observers]
331
+ newObservers.splice(indexToDelete, 1)
332
+ this.observers = Object.freeze(newObservers)
333
+
334
+ const dittoHandle = Bridge.ditto.handleFor(this.ditto)
335
+ this.ditto.deferClose(() => {
336
+ mapFFIErrors(
337
+ () => FFI.liveQueryStop(dittoHandle.deref(), storeObserver.liveQueryID)
338
+ )
339
+ })
340
+ return true
341
+ }
342
+
343
+ /** @internal */
344
+ close() {
345
+ for (const observer of this.observers) {
346
+ observer.cancel()
347
+ }
348
+
349
+
350
+ }
351
+
352
+ /**
353
+ * Private method, used only by the Portal https://github.com/getditto/ditto/pull/3652
354
+ * @internal
355
+ */
356
+ async registerLiveQueryWebhook(collectionName: string, query: string, url: string): Promise<DocumentID> {
357
+ const ditto = this.ditto
358
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
359
+ return ditto.deferCloseAsync(async () => {
360
+ const validatedQuery = validateQuery(query)
361
+ const idCBOR = await FFI.liveQueryWebhookRegister(dittoHandle.deref(), collectionName, validatedQuery, [], 0, 0, url)
362
+ return new DocumentID(idCBOR, true)
363
+ })
364
+ }
365
+ }
@@ -0,0 +1,98 @@
1
+ //
2
+ // Copyright © 2023 DittoLive Incorporated. All rights reserved.
3
+ //
4
+
5
+ import * as FFI from './ffi'
6
+ import { Bridge } from './bridge'
7
+
8
+ import type { Ditto } from './ditto'
9
+ import type { Subscription } from './subscription'
10
+
11
+ /** @internal */
12
+ export type SubscriptionContextInfo = {
13
+ id: string
14
+ collectionName: string
15
+ query: string
16
+ queryArgsCBOR: Uint8Array | null
17
+ orderBys: FFI.OrderBy[]
18
+ limit: number
19
+ offset: number
20
+ }
21
+
22
+ /**
23
+ * Tracks `Subscription` instances in order to remove them when Ditto is
24
+ * closed.
25
+ *
26
+ * @internal
27
+ */
28
+ export class SubscriptionManager {
29
+ /** @internal */
30
+ constructor(ditto: Ditto) {
31
+ this.ditto = ditto
32
+ this.subscriptions = {}
33
+ this.finalizationRegistry = new FinalizationRegistry(this.removeWithContextInfo.bind(this))
34
+ }
35
+
36
+ /**
37
+ * Begin tracking a subscription instance and start it.
38
+ *
39
+ * @internal */
40
+ add(subscription: Subscription) {
41
+ const ditto = this.ditto
42
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
43
+ const contextInfo = subscription.contextInfo
44
+ ditto.deferClose(async () => {
45
+ this.subscriptions[contextInfo.id] = new WeakRef(subscription)
46
+ this.finalizationRegistry.register(subscription, subscription.contextInfo, subscription)
47
+ FFI.addSubscription(dittoHandle.deref(), contextInfo.collectionName, contextInfo.query, contextInfo.queryArgsCBOR, contextInfo.orderBys, contextInfo.limit, contextInfo.offset)
48
+ })
49
+ }
50
+
51
+ /**
52
+ * Stop tracking a subscription instance and cancel it.
53
+ *
54
+ * @internal */
55
+ remove(subscription: Subscription) {
56
+ if (this.subscriptions[subscription.contextInfo.id] == null) {
57
+ throw new Error(`Internal inconsistency, tried to remove a subscription that is not tracked: ${subscription.contextInfo.id}`)
58
+ }
59
+ this.finalizationRegistry.unregister(subscription)
60
+ this.removeWithContextInfo(subscription.contextInfo)
61
+ }
62
+
63
+ /**
64
+ * Stop tracking all subscriptions and cancel them.
65
+ *
66
+ * @internal */
67
+ close() {
68
+ this.ditto.deferClose(async () => {
69
+ for (const subscriptionID in this.subscriptions) {
70
+ const subscription = this.subscriptions[subscriptionID].deref()
71
+ if (subscription != null) {
72
+
73
+ this.remove(subscription)
74
+ }
75
+ }
76
+ })
77
+ }
78
+
79
+ // ----------------------------------------------------------- Internal ------
80
+
81
+ private ditto: Ditto
82
+ private subscriptions: { [subscriptionID: string]: WeakRef<Subscription> }
83
+ private finalizationRegistry: FinalizationRegistry<SubscriptionContextInfo>
84
+
85
+ /**
86
+ * Remove tracked subscription without unregistering from finalization
87
+ * registry.
88
+ *
89
+ * @internal */
90
+ private removeWithContextInfo(contextInfo: SubscriptionContextInfo) {
91
+ const ditto = this.ditto
92
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
93
+ ditto.deferClose(() => {
94
+ delete this.subscriptions[contextInfo.id]
95
+ FFI.removeSubscription(dittoHandle.deref(), contextInfo.collectionName, contextInfo.query, contextInfo.queryArgsCBOR, contextInfo.orderBys, contextInfo.limit, contextInfo.offset)
96
+ })
97
+ }
98
+ }
@@ -0,0 +1,88 @@
1
+ //
2
+ // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
+ //
4
+
5
+ import * as FFI from './ffi'
6
+ import { generateEphemeralToken } from './internal'
7
+
8
+ import type { Collection } from './collection'
9
+ import type { SubscriptionManager, SubscriptionContextInfo } from './subscription-manager'
10
+
11
+ /**
12
+ * Used to subscribe to receive updates from remote peers about matching
13
+ * documents.
14
+ *
15
+ * While {@link Subscription} objects remain in scope they ensure that
16
+ * documents in the collection specified and that match the query provided will
17
+ * try to be kept up-to-date with the latest changes from remote peers.
18
+ */
19
+ export class Subscription {
20
+ /**
21
+ * The query that the subscription is based on.
22
+ */
23
+ readonly query: string
24
+
25
+ /**
26
+ * Returns `true` if subscription has been explicitly cancelled, `false`
27
+ * otherwise.
28
+ */
29
+ get isCancelled(): boolean {
30
+ return this._isCancelled
31
+ }
32
+
33
+ /**
34
+ * The name of the collection that the subscription is based on.
35
+ */
36
+ get collectionName() {
37
+ return this.collection.name
38
+ }
39
+
40
+ /**
41
+ * Cancels a subscription and releases all associated resources.
42
+ */
43
+ cancel() {
44
+ if (!this.isCancelled) {
45
+ this._isCancelled = true
46
+ this.manager.remove(this)
47
+ }
48
+ }
49
+
50
+ // ----------------------------------------------------------- Internal ------
51
+
52
+ /** @internal */
53
+ constructor(collection: Collection, query: string, queryArgsCBOR: Uint8Array | null, orderBys: FFI.OrderBy[], limit: number, offset: number) {
54
+ this.query = query
55
+ this.queryArgsCBOR = queryArgsCBOR
56
+ this.collection = collection
57
+ this.contextInfo = {
58
+ id: generateEphemeralToken(),
59
+ collectionName: collection.name,
60
+ query,
61
+ queryArgsCBOR,
62
+ orderBys,
63
+ limit,
64
+ offset,
65
+ }
66
+ this.manager = collection.store.ditto.subscriptionManager
67
+ this.manager.add(this)
68
+ }
69
+
70
+ /**
71
+ * The collection this subscription belongs to.
72
+ * @internal Because not exposed in any of the other SDKs (yet?).
73
+ */
74
+ readonly collection: Collection
75
+
76
+ /**
77
+ * The corresponding named arguments for {@link query}, if any.
78
+ * @internal Because not exposed in any of the other SDKs (yet?).
79
+ */
80
+ readonly queryArgsCBOR: Uint8Array | null
81
+
82
+ /** @internal */
83
+ readonly contextInfo: SubscriptionContextInfo
84
+
85
+ private readonly manager: SubscriptionManager
86
+
87
+ private _isCancelled = false
88
+ }
@@ -0,0 +1,90 @@
1
+ //
2
+ // Copyright © 2023 DittoLive Incorporated. All rights reserved.
3
+ //
4
+
5
+ import { DittoError } from './error'
6
+
7
+ import type { DQLQueryArguments } from './essentials'
8
+ import type { Ditto } from './ditto'
9
+ import type { Sync } from './sync'
10
+
11
+ /**
12
+ * A sync subscription configures Ditto to receive updates from remote peers
13
+ * about documents matching the subscription's query.
14
+ *
15
+ * The sync subscription will remain active until it is
16
+ * {@link SyncSubscription.cancel | cancelled}, or the Ditto instance managing
17
+ * the subscription has been {@link Ditto.close | closed}.
18
+ *
19
+ * Create a sync subscription by calling
20
+ * {@link Sync.registerSubscription | `ditto.sync.registerSubscription()`}.
21
+ */
22
+ export class SyncSubscription {
23
+ /**
24
+ * Documents matching this query will be included in the sync subscription.
25
+ */
26
+ readonly queryString: string
27
+
28
+ /**
29
+ * The query arguments of the sync subscription (as passed when
30
+ * adding it to the store).
31
+ */
32
+ readonly queryArguments?: Readonly<DQLQueryArguments>
33
+
34
+ /**
35
+ * The {@link Ditto} instance this sync subscription belongs to.
36
+ */
37
+ readonly ditto: Ditto
38
+
39
+ /**
40
+ * `true` when the sync subscription has been cancelled or the {@link Ditto}
41
+ * instance managing this subscription has been closed.
42
+ */
43
+ get isCancelled() {
44
+ return this._isCancelled
45
+ }
46
+
47
+ /**
48
+ * Cancels the sync subscription and unregisters it. No-op
49
+ * if the sync subscription has already been cancelled or the {@link Ditto}
50
+ * instance managing this subscription has been closed.
51
+ */
52
+ cancel() {
53
+ if (this._isCancelled) return
54
+ this._isCancelled = true
55
+ this.ditto.sync.unregisterSubscription(this)
56
+ }
57
+
58
+ // --------------------------- Internal --------------------------------------
59
+
60
+ /** @internal */
61
+ constructor(ditto: Ditto, query: string, queryArguments: DQLQueryArguments | null, queryArgumentsCBOR: Uint8Array | null) {
62
+ if ((queryArguments == null) !== (queryArgumentsCBOR == null)) {
63
+ throw new DittoError('internal', 'Internal inconsistency, query arguments and query arguments CBOR must be both null or both non-null', { queryArguments, queryArgumentsCBOR })
64
+ }
65
+
66
+ this.ditto = ditto
67
+ this.queryString = query
68
+ this.queryArguments = queryArguments ? Object.freeze({ ...queryArguments }) : undefined
69
+ this.queryArgumentsCBOR = queryArgumentsCBOR
70
+ }
71
+
72
+ /**
73
+ * The CBOR-encoded query arguments, or `null` if no query arguments were
74
+ * passed in.
75
+ *
76
+ * @internal
77
+ */
78
+ readonly queryArgumentsCBOR: Uint8Array | null
79
+
80
+ // --------------------------- Private --------------------------------------
81
+
82
+ /**
83
+ * `true` when the ssync ubscription has been cancelled.
84
+ *
85
+ * We mark the sync subscription as cancelled here as an optimization to avoid
86
+ * a scan of all subscriptions in the store whenever the `isCancelled`
87
+ * property is checked.
88
+ */
89
+ private _isCancelled = false
90
+ }