@dittolive/ditto 4.4.4 → 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,216 @@
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 { LiveQuery } from './live-query'
10
+ import { Document, MutableDocument } from './document'
11
+ import { performAsyncToWorkaroundNonAsyncFFIAPI } from './internal'
12
+ import { BasePendingIDSpecificOperation } from './base-pending-id-specific-operation'
13
+ import { SingleDocumentLiveQueryEvent } from './live-query-event'
14
+
15
+ import type { DocumentID } from './document-id'
16
+ import type { UpdateResult } from './update-result'
17
+ import type { Collection } from './collection'
18
+
19
+
20
+ /**
21
+ * The closure that is called whenever a single documunent covered by a
22
+ * live query changes.
23
+ */
24
+ export type SingleObservationHandler = (document: Document | null, event: SingleDocumentLiveQueryEvent, signalNext?: () => void) => void | Promise<void>
25
+
26
+ // -----------------------------------------------------------------------------
27
+
28
+ /**
29
+ * These objects are returned when using {@link Collection.findByID | findByID()}
30
+ * functionality on {@link Collection | collections}.
31
+ *
32
+ * You can either call {@link exec | exec()} on the object to get an immediate
33
+ * return value, or you can establish either a live query or a subscription,
34
+ * which both work over time.
35
+ *
36
+ * A live query, established by calling
37
+ * {@link PendingIDSpecificOperation.observeLocal | observeLocal()}, will notify
38
+ * you every time there's an update to the document with the ID you provided in
39
+ * the preceding {@link Collection.findByID | findByID()} call.
40
+ *
41
+ * A subscription, established by calling {@link PendingIDSpecificOperation.subscribe | subscribe()}, will
42
+ * act as a signal to other peers that you would like to receive updates from
43
+ * them about the document with the ID you provided in the preceding
44
+ * {@link Collection.findByID | findByID()} call.
45
+ *
46
+ * Update and remove functionality is also exposed through this object.
47
+ */
48
+ export class PendingIDSpecificOperation extends BasePendingIDSpecificOperation {
49
+ async remove(): Promise<boolean> {
50
+ const ditto = this.collection.store.ditto
51
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
52
+
53
+ return ditto.deferCloseAsync(async () => {
54
+ return await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
55
+ const writeTransactionX = await FFI.writeTransaction(dittoHandle.deref())
56
+ const didRemove = await FFI.collectionRemove(dittoHandle.deref(), this.collection.name, writeTransactionX, this.documentIDCBOR)
57
+ await FFI.writeTransactionCommit(dittoHandle.deref(), writeTransactionX)
58
+ return didRemove
59
+ })
60
+ })
61
+ }
62
+
63
+ async evict(): Promise<boolean> {
64
+ const ditto = this.collection.store.ditto
65
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
66
+
67
+ return ditto.deferCloseAsync(async () => {
68
+ return await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
69
+ const writeTransactionX = await FFI.writeTransaction(dittoHandle.deref())
70
+ const didEvict = await FFI.collectionEvict(dittoHandle.deref(), this.collection.name, writeTransactionX, this.documentIDCBOR)
71
+ await FFI.writeTransactionCommit(dittoHandle.deref(), writeTransactionX)
72
+ return didEvict
73
+ })
74
+ })
75
+ }
76
+
77
+ async update(closure: (document: MutableDocument) => void): Promise<UpdateResult[]> {
78
+ const ditto = this.collection.store.ditto
79
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
80
+
81
+ return ditto.deferCloseAsync(async () => {
82
+ const readTransactionX = await FFI.readTransaction(dittoHandle.deref())
83
+ const documentX = await FFI.collectionGet(dittoHandle.deref(), this.collection.name, this.documentIDCBOR, readTransactionX)
84
+ FFI.readTransactionFree(readTransactionX)
85
+
86
+ if (!documentX) throw new Error(`Can't update, document with ID '${this.documentID.toString()}' not found in collection named '${this.collection.name}'`)
87
+
88
+ const mutableDocument = Bridge.mutableDocument.bridge(documentX, () => new MutableDocument())
89
+ closure(mutableDocument)
90
+
91
+
92
+ Bridge.mutableDocument.unregister(mutableDocument)
93
+
94
+ const writeTransactionX = await FFI.writeTransaction(dittoHandle.deref())
95
+ await FFI.collectionUpdate(dittoHandle.deref(), this.collection.name, writeTransactionX, documentX)
96
+ await FFI.writeTransactionCommit(dittoHandle.deref(), writeTransactionX)
97
+
98
+ return mutableDocument['@ditto.updateResults'].slice()
99
+ })
100
+ }
101
+
102
+ /**
103
+ * Enables you to subscribe to changes that occur in relation to a document
104
+ * remotely.
105
+ *
106
+ * Having a subscription acts as a signal to other peers that you are
107
+ * interested in receiving updates when local or remote changes are made to
108
+ * the relevant document.
109
+ *
110
+ * The returned {@link Subscription} object must be kept in scope for as long
111
+ * as you want to keep receiving updates.
112
+ *
113
+ * @returns A {@link Subscription} object that must be kept in scope for as
114
+ * long as you want to keep receiving updates for the document.
115
+ */
116
+ subscribe(): Subscription {
117
+ const subscription = new Subscription(this.collection as Collection, this.query, null, [], -1, 0)
118
+ this.collection.store.ditto.subscriptionManager.add(subscription)
119
+ return subscription
120
+ }
121
+
122
+ /**
123
+ * Enables you to listen for changes that occur in relation to a document
124
+ * locally.
125
+ *
126
+ * This won't subscribe to receive changes made remotely by others and so it
127
+ * will only fire updates when a local change is made. If you want to receive
128
+ * remotely performed updates as well, you'll have to create a subscription
129
+ * via {@link PendingIDSpecificOperation.subscribe | subscribe()} for the same
130
+ * document ID.
131
+ *
132
+ * The returned {@link LiveQuery} object must be kept in scope for as long
133
+ * as you want the provided `handler` to be called when an update
134
+ * occurs.
135
+ *
136
+ * @param handler A block that will be called every time there is a
137
+ * transaction committed to the store that involves a modification to the
138
+ * document with the relevant ID in the collection that
139
+ * {@link PendingIDSpecificOperation.observeLocal | observeLocal()} was called on.
140
+ *
141
+ * @returns A {@link LiveQuery} object that must be kept in scope for as long
142
+ * as you want to keep receiving updates.
143
+ */
144
+ observeLocal(handler: SingleObservationHandler): LiveQuery {
145
+ return this._observe(handler, false)
146
+ }
147
+
148
+ /**
149
+ * Enables you to listen for changes that occur in relation to a document
150
+ * locally and to signal when you are ready for the live query to deliver
151
+ * the next event.
152
+ *
153
+ * This won't subscribe to receive changes made remotely by others and so it
154
+ * will only fire updates when a local change is made. If you want to receive
155
+ * remotely performed updates as well, you'll have to create a subscription
156
+ * via {@link PendingIDSpecificOperation.subscribe | subscribe()} for the same
157
+ * document ID.
158
+ *
159
+ * The returned {@link LiveQuery} object must be kept in scope for as long
160
+ * as you want the provided `handler` to be called when an update
161
+ * occurs.
162
+ *
163
+ * @param handler A block that will be called every time there is a
164
+ * transaction committed to the store that involves a modification to the
165
+ * document with the relevant ID in the collection that
166
+ * {@link PendingIDSpecificOperation.observeLocal | observeLocal()} was called on.
167
+ *
168
+ * @returns A {@link LiveQuery} object that must be kept in scope for as long
169
+ * as you want to keep receiving updates.
170
+ */
171
+ observeLocalWithNextSignal(handler: SingleObservationHandler): LiveQuery {
172
+ return this._observe(handler, true)
173
+ }
174
+
175
+ /** @internal */
176
+ constructor(documentID: DocumentID, collection: Collection) {
177
+ super(documentID, collection)
178
+ }
179
+
180
+ /** @internal */
181
+ _observe(handler: SingleObservationHandler, waitForNextSignal: boolean): LiveQuery {
182
+ const liveQuery = new LiveQuery(this.query, null, null, [], -1, 0, this.collection as Collection, (documents, event, signalNext) => {
183
+ if (documents.length > 1) {
184
+ const documentIDsAsBase64Strings = documents.map((document) => document.id.toBase64String())
185
+ throw new Error(`Internal inconsistency, single document live query returned more than one document. Query: ${this.query}, documentIDs: ${documentIDsAsBase64Strings.join(', ')}.`)
186
+ }
187
+
188
+ if (event.isInitial === false && event.oldDocuments.length > 1) throw new Error(`Internal inconsistency, single document live query returned an update event with more than one old documents. Query ${this.query}.`)
189
+ if (event.isInitial === false && event.insertions.length > 1) throw new Error(`Internal inconsistency, single document live query returned an update event with more than one insertion, which doesn't make sense for single document observations. Query ${this.query}.`)
190
+ if (event.isInitial === false && event.deletions.length > 1) throw new Error(`Internal inconsistency, single document live query returned an update event with more than one deletion, which doesn't make sense for single document observations. Query ${this.query}.`)
191
+ if (event.isInitial === false && event.updates.length > 1) throw new Error(`Internal inconsistency, single document live query returned an update event with more than one update, which doesn't make sense for single document observations. Query ${this.query}.`)
192
+ if (event.isInitial === false && event.moves.length > 0) throw new Error(`Internal inconsistency, single document live query returned an update event with moves, which doesn't make sense for single document observations. Query ${this.query}.`)
193
+
194
+ const totalNumberOfManipulations = event.isInitial === true ? 0 : event.insertions.length + event.deletions.length + event.updates.length
195
+ if (totalNumberOfManipulations > 1) throw new Error(`Internal inconsistency, single document live query returned a combination of inserts, updates, and/or deletes, which doesn't make sense for single document observation. Query ${this.query}.`)
196
+
197
+
198
+ const document = documents[0] || null
199
+ const oldDocument = event.isInitial === true ? undefined : event.oldDocuments[0]
200
+
201
+ const singleDocumentEvent = new SingleDocumentLiveQueryEvent(event.isInitial, oldDocument)
202
+ if (waitForNextSignal) {
203
+ handler(document, singleDocumentEvent, signalNext)
204
+ } else {
205
+ try {
206
+ handler(document, singleDocumentEvent)
207
+ } finally {
208
+ signalNext()
209
+ }
210
+ }
211
+ })
212
+
213
+ this.collection.store.ditto.liveQueryManager.startLiveQuery(liveQuery)
214
+ return liveQuery
215
+ }
216
+ }
@@ -0,0 +1,160 @@
1
+ //
2
+ // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
+ //
4
+
5
+ import * as FFI from './ffi'
6
+ import { Bridge } from './bridge'
7
+ import { generateEphemeralToken } from './internal'
8
+
9
+ import type { Ditto, RemotePeer } from './ditto'
10
+
11
+ /** @internal */
12
+ export type PresenceToken = string
13
+
14
+ /**
15
+ * @internal
16
+ * @deprecated Replaced by `Presence`.
17
+ */
18
+ export class PresenceManager {
19
+ readonly ditto: Ditto
20
+
21
+ constructor(ditto: Ditto) {
22
+ this.ditto = ditto
23
+ this.isClosed = false
24
+ this.isRegistered = false
25
+ this.currentRemotePeers = []
26
+ this.callbacksByPresenceToken = {}
27
+ }
28
+
29
+ /** @internal */
30
+ addObserver(callback: (remotePeers: RemotePeer[]) => void): PresenceToken {
31
+ if (this.isClosed) {
32
+
33
+ throw new Error(`Internal inconsistency, can't add presence observer, observer mananger close()-ed.`)
34
+ }
35
+
36
+ this.registerIfNeeded()
37
+
38
+ const token = generateEphemeralToken()
39
+ this.callbacksByPresenceToken[token] = callback
40
+ this.ditto.keepAlive.retain(`PresenceObservation.${token}`)
41
+
42
+
43
+ callback(this.currentRemotePeers)
44
+
45
+ return token
46
+ }
47
+
48
+ /** @internal */
49
+ removeObserver(token: PresenceToken) {
50
+ const callback = this.callbacksByPresenceToken[token]
51
+
52
+ if (typeof callback === 'undefined') {
53
+ throw new Error(`Can't remove presence observer, token '${token}' has never been registered before.`)
54
+ }
55
+
56
+ if (callback === null) {
57
+ // Observer has already been removed, no-op.
58
+ return
59
+ }
60
+
61
+ if (typeof this.callbacksByPresenceToken[token] != 'undefined') {
62
+ this.ditto.keepAlive.release(`PresenceObservation.${token}`)
63
+
64
+ this.callbacksByPresenceToken[token] = null
65
+ this.unregisterIfNeeded()
66
+ }
67
+ }
68
+
69
+ /** @internal */
70
+ hasObserver(token: PresenceToken): boolean {
71
+ return typeof this.callbacksByPresenceToken[token] != 'undefined'
72
+ }
73
+
74
+ /** @internal */
75
+ close() {
76
+ this.isClosed = true
77
+ for (const token in this.callbacksByPresenceToken) {
78
+ this.removeObserver(token)
79
+ }
80
+ }
81
+
82
+ // ------------------------------------------------------------ Private ------
83
+
84
+ private isClosed: boolean
85
+ private isRegistered: boolean
86
+ private currentRemotePeers: RemotePeer[]
87
+ private callbacksByPresenceToken: { [key: string]: ((remotePeers: RemotePeer[]) => void) | null }
88
+
89
+ private hasObservers(): boolean {
90
+ return Object.keys(this.callbacksByPresenceToken).length > 0
91
+ }
92
+
93
+ private registerIfNeeded() {
94
+ const ditto = this.ditto
95
+ const dittoHandle = Bridge.ditto.handleFor(this.ditto)
96
+ ditto.deferClose(() => {
97
+ const needsToRegister = !this.isRegistered
98
+ if (needsToRegister) {
99
+ this.isRegistered = true
100
+ const remotePeersJSONString = FFI.dittoPresenceV1(dittoHandle.deref())
101
+ this.currentRemotePeers = this.decode(remotePeersJSONString).sort(this.compareRemotePeers)
102
+ FFI.dittoRegisterPresenceV1Callback(dittoHandle.deref(), this.handlePresenceV1Callback.bind(this))
103
+ }
104
+ })
105
+ }
106
+
107
+ private unregisterIfNeeded() {
108
+ const ditto = this.ditto
109
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
110
+ ditto.deferClose(() => {
111
+ const needsToUnregister = !this.hasObservers() && this.isRegistered
112
+ if (needsToUnregister) {
113
+ this.isRegistered = false
114
+ FFI.dittoClearPresenceCallback(dittoHandle.deref())
115
+ this.currentRemotePeers = []
116
+ }
117
+ })
118
+ }
119
+
120
+ private handlePresenceV1Callback(remotePeersJSONString: string) {
121
+ const remotePeers = this.decode(remotePeersJSONString).sort(this.compareRemotePeers)
122
+ this.currentRemotePeers = remotePeers
123
+ this.notify()
124
+ }
125
+
126
+ private notify() {
127
+ if (this.isClosed) {
128
+ return
129
+ }
130
+
131
+ for (const token in this.callbacksByPresenceToken) {
132
+ const callback = this.callbacksByPresenceToken[token]
133
+ if (callback) callback(this.currentRemotePeers)
134
+ }
135
+ }
136
+
137
+ private decode(remotePeersJSONString: string): RemotePeer[] {
138
+ const remotePeersJSON: any[] = JSON.parse(remotePeersJSONString)
139
+ return remotePeersJSON.map((remotePeerJSON) => {
140
+ return {
141
+ networkID: remotePeerJSON['network_id'],
142
+ deviceName: remotePeerJSON['device_name'],
143
+ rssi: remotePeerJSON['rssi'] ?? undefined,
144
+ approximateDistanceInMeters: remotePeerJSON['approximate_distance_in_meters'] ?? undefined,
145
+ connections: remotePeerJSON['connections'],
146
+ }
147
+ })
148
+ }
149
+
150
+ private compareRemotePeers(left: RemotePeer, right: RemotePeer) {
151
+
152
+ if (left.connections.length === 0 && right.connections.length > 0) return +1
153
+ if (left.connections.length > 0 && right.connections.length === 0) return -1
154
+
155
+ if (left.deviceName < right.deviceName) return -1
156
+ if (left.deviceName > right.deviceName) return +1
157
+
158
+ return 0
159
+ }
160
+ }
@@ -0,0 +1,238 @@
1
+ //
2
+ // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
+ //
4
+
5
+ import * as FFI from './ffi'
6
+ import { Bridge } from './bridge'
7
+ import { Observer } from './observer'
8
+ import { ObserverManager } from './observer-manager'
9
+ import type { Ditto } from './ditto'
10
+
11
+ /** Types of connections that can be established between two peers. */
12
+ export type ConnectionType = 'P2PWiFi' | 'WebSocket' | 'AccessPoint' | 'Bluetooth'
13
+
14
+ // -----------------------------------------------------------------------------
15
+
16
+ /**
17
+ * An opaque address uniquely identifying another peer on the Ditto mesh
18
+ * network.
19
+ *
20
+ * IMPORTANT: You should not rely on the individual components of the address,
21
+ * those can change at any time. Please use
22
+ * {@link addressToString | addressToString()} to compare individual addresses
23
+ * with each other.
24
+ */
25
+ export type Address = {
26
+ siteId: number | BigInt
27
+ pubkey: Uint8Array
28
+ }
29
+
30
+ // -----------------------------------------------------------------------------
31
+
32
+ /**
33
+ * Returns a string representation of the given address. Use this function
34
+ * to compare multiple addresses or whenever you need the address to be a key
35
+ * in a hash object.
36
+ */
37
+ export function addressToString(address: Address) {
38
+ return `${address.siteId}-${address.pubkey}`
39
+ }
40
+
41
+ // -----------------------------------------------------------------------------
42
+
43
+ /** Represents a connection between two peers on the Ditto mesh network. */
44
+ export type Connection = {
45
+ /** Unique identifier for the connection.
46
+ *
47
+ * These IDs are stable for any two peer keys and a given connection type.
48
+ *
49
+ * **Example ID**
50
+ *
51
+ * "1<->2:Bluetooth"
52
+ */
53
+ id: string
54
+
55
+ /** Type of transport enabling this connection. */
56
+ connectionType: ConnectionType
57
+
58
+ /**
59
+ * Peer key of the peer at one end of the connection.
60
+ *
61
+ * This peer key is lexicographically smaller than `peer2`.
62
+ */
63
+ peer1: Uint8Array
64
+
65
+ /**
66
+ * Peer key of the peer at the other end of the connection.
67
+ *
68
+ * This peer key is lexicographically larger than `peer1`.
69
+ */
70
+ peer2: Uint8Array
71
+
72
+ /*
73
+ * Gets an estimate of distance to the remote peer. This value is inaccurate.
74
+ * The environment, hardware, and several other factors can greatly affect
75
+ * this value. It is currently derived from RSSI. Can be (yet) unknown and
76
+ * therefore not set.
77
+ */
78
+ approximateDistanceInMeters?: number
79
+ }
80
+
81
+ // -----------------------------------------------------------------------------
82
+
83
+ /** An instance of Ditto taking part in the Ditto mesh network. */
84
+ export type Peer = {
85
+ /**
86
+ * Address to contact this peer via Ditto Bus, unique with a Ditto mesh
87
+ * network.
88
+ */
89
+ address: Address
90
+
91
+ /**
92
+ * The peer key is a unique identifier for a given peer, equal to or derived
93
+ * from the cryptographic public key used to authenticate it.
94
+ *
95
+ * NOTE: This will be be empty when a peer is not updated to the latest
96
+ * version of the SDK.
97
+ */
98
+ peerKey: Uint8Array
99
+
100
+ /**
101
+ * The human-readable device name of the peer. This defaults to the hostname
102
+ * but can be manually set by the application developer of the other peer.
103
+ * It is not necessarily unique.
104
+ */
105
+ deviceName: string
106
+
107
+ /**
108
+ * Currently active connections of the peer.
109
+ */
110
+ connections: Connection[]
111
+
112
+ /**
113
+ * Indicates whether the peer is connected to Ditto Cloud.
114
+ */
115
+ isConnectedToDittoCloud: boolean
116
+
117
+ /** The operating system the peer is running on, `undefined` if (yet) unknown. */
118
+ os?: string
119
+
120
+ /** The Ditto SDK version the peer is running with, `undefined` if (yet) unknown. */
121
+ dittoSDKVersion?: string
122
+ }
123
+
124
+ // -----------------------------------------------------------------------------
125
+
126
+ /**
127
+ * Represents the Ditto mesh network of peers and their connections between each
128
+ * other. The `localPeer` is the entry point, all others are remote peers known
129
+ * by the local peer (either directly or via other remote peers).
130
+ */
131
+ export type PresenceGraph = {
132
+ /**
133
+ * Returns the local peer (usually the peer that is represented by the
134
+ * currently running Ditto instance). The `localPeer` is the entry point, all
135
+ * others are remote peers known by the local peer (either directly or via
136
+ * other remote peers).
137
+ */
138
+ localPeer: Peer
139
+
140
+ /**
141
+ * Returns all remote peers known by the `localPeer`, either directly or via
142
+ * other remote peers.
143
+ */
144
+ remotePeers: Peer[]
145
+
146
+ /**
147
+ * Returns the underlying CBOR data if the presence graph has been initialized
148
+ * with CBOR. All of Ditto API returning a presence graph has this property
149
+ * set.
150
+ */
151
+ underlyingCBOR?: Uint8Array
152
+ }
153
+
154
+ // -----------------------------------------------------------------------------
155
+
156
+ /**
157
+ * The entrypoint for all actions that relate presence of other peers known by
158
+ * the current peer, either directly or through other peers.
159
+ *
160
+ * You don't create one directly but can access it from a particular `Ditto`
161
+ * instance via its `presence` property.
162
+ */
163
+ export class Presence {
164
+ /** The Ditto instance this object belongs to. */
165
+ readonly ditto: Ditto
166
+
167
+ /**
168
+ * Returns the current presence graph capturing all known peers and
169
+ * connections between them.
170
+ */
171
+ get graph(): PresenceGraph {
172
+ const ditto = this.ditto
173
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
174
+ return ditto.deferClose(() => {
175
+ const graphJSONString = FFI.dittoPresenceV3(dittoHandle.deref())
176
+ return JSON.parse(graphJSONString)
177
+ })
178
+ }
179
+
180
+ /**
181
+ * Request information about Ditto peers in range of this device.
182
+ *
183
+ * This method returns an observer which should be held as long as updates are
184
+ * required. A newly registered observer will have a peers update delivered to
185
+ * it immediately. From then on it will be invoked repeatedly when Ditto
186
+ * devices come and go, or the active connections to them change.
187
+ */
188
+ observe(didChangeHandler: (presenceGraph: PresenceGraph) => void): Observer {
189
+ const observerToken = this.observerManager.addObserver(didChangeHandler)
190
+ const observer = new Observer(this.observerManager, observerToken, { stopsWhenFinalized: true })
191
+
192
+ // REFACTOR: make the initial callback call async, too (othewise we'd be
193
+ // mixing sync with async, which is a bit problematic in general but might
194
+ // be OK with single-threaded JS). This is a bit tricky, simply
195
+ // setTimeout(..., 0) here could lead us to a situation where the initial
196
+ // call would be sent AFTER the regular notification.
197
+ didChangeHandler(this.graph)
198
+
199
+ return observer
200
+ }
201
+
202
+ /** @internal */
203
+ constructor(ditto: Ditto) {
204
+ this.ditto = ditto
205
+
206
+ this.observerManager = new ObserverManager('PresenceObservation', {
207
+ keepAlive: ditto.keepAlive,
208
+
209
+ register: (callback) => {
210
+ const ditto = this.ditto
211
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
212
+ ditto.deferClose(() => {
213
+ FFI.dittoRegisterPresenceV3Callback(dittoHandle.deref(), callback)
214
+ })
215
+ },
216
+
217
+ unregister: () => {
218
+ const ditto = this.ditto
219
+ const dittoHandle = Bridge.ditto.handleFor(ditto)
220
+ ditto.deferClose(() => {
221
+ FFI.dittoClearPresenceV3Callback(dittoHandle.deref())
222
+ })
223
+ },
224
+
225
+ process: (presenceGraphJSONString) => {
226
+ const presenceGraph = JSON.parse(presenceGraphJSONString)
227
+ return [presenceGraph]
228
+ },
229
+ })
230
+ }
231
+
232
+ /** @internal */
233
+ close() {
234
+ this.observerManager.close()
235
+ }
236
+
237
+ private observerManager: ObserverManager
238
+ }