@dittolive/ditto 4.7.4 → 4.7.5-rc.2

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 (160) hide show
  1. package/README.md +2 -2
  2. package/node/ditto.cjs.js +1 -1
  3. package/node/ditto.darwin-arm64.node +0 -0
  4. package/node/ditto.darwin-x64.node +0 -0
  5. package/node/ditto.linux-arm.node +0 -0
  6. package/node/ditto.linux-arm64.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 +2 -5
  12. package/web/ditto.es6.js +1 -1
  13. package/web/ditto.umd.js +1 -1
  14. package/web/ditto.wasm +0 -0
  15. package/DittoReactNative.podspec +0 -27
  16. package/react-native/android/.gradle/8.9/checksums/checksums.lock +0 -0
  17. package/react-native/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  18. package/react-native/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  19. package/react-native/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  20. package/react-native/android/.gradle/8.9/gc.properties +0 -0
  21. package/react-native/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  22. package/react-native/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  23. package/react-native/android/.gradle/vcs-1/gc.properties +0 -0
  24. package/react-native/android/CMakeLists.txt +0 -36
  25. package/react-native/android/build.gradle +0 -190
  26. package/react-native/android/cpp-adapter.cpp +0 -259
  27. package/react-native/android/gradle.properties +0 -5
  28. package/react-native/android/src/main/AndroidManifest.xml +0 -4
  29. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +0 -120
  30. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKPackage.java +0 -28
  31. package/react-native/cpp/include/Arc.hpp +0 -159
  32. package/react-native/cpp/include/Attachment.h +0 -20
  33. package/react-native/cpp/include/Authentication.h +0 -23
  34. package/react-native/cpp/include/Collection.h +0 -13
  35. package/react-native/cpp/include/ConnectionRequest.h +0 -18
  36. package/react-native/cpp/include/DQL.h +0 -21
  37. package/react-native/cpp/include/Document.h +0 -17
  38. package/react-native/cpp/include/FFIUtils.h +0 -16
  39. package/react-native/cpp/include/IO.h +0 -13
  40. package/react-native/cpp/include/Identity.h +0 -17
  41. package/react-native/cpp/include/Lifecycle.h +0 -16
  42. package/react-native/cpp/include/LiveQuery.h +0 -17
  43. package/react-native/cpp/include/Logger.h +0 -22
  44. package/react-native/cpp/include/Misc.h +0 -30
  45. package/react-native/cpp/include/Presence.h +0 -18
  46. package/react-native/cpp/include/SmallPeerInfo.h +0 -19
  47. package/react-native/cpp/include/Transports.h +0 -25
  48. package/react-native/cpp/include/TypedArray.hpp +0 -167
  49. package/react-native/cpp/include/Utils.h +0 -70
  50. package/react-native/cpp/include/main.h +0 -10
  51. package/react-native/cpp/src/Attachment.cpp +0 -272
  52. package/react-native/cpp/src/Authentication.cpp +0 -227
  53. package/react-native/cpp/src/Collection.cpp +0 -56
  54. package/react-native/cpp/src/ConnectionRequest.cpp +0 -123
  55. package/react-native/cpp/src/DQL.cpp +0 -256
  56. package/react-native/cpp/src/Document.cpp +0 -146
  57. package/react-native/cpp/src/FFIUtils.cpp +0 -122
  58. package/react-native/cpp/src/IO.cpp +0 -35
  59. package/react-native/cpp/src/Identity.cpp +0 -122
  60. package/react-native/cpp/src/Lifecycle.cpp +0 -93
  61. package/react-native/cpp/src/LiveQuery.cpp +0 -63
  62. package/react-native/cpp/src/Logger.cpp +0 -199
  63. package/react-native/cpp/src/Misc.cpp +0 -322
  64. package/react-native/cpp/src/Presence.cpp +0 -166
  65. package/react-native/cpp/src/SmallPeerInfo.cpp +0 -142
  66. package/react-native/cpp/src/Transports.cpp +0 -275
  67. package/react-native/cpp/src/TypedArray.cpp +0 -303
  68. package/react-native/cpp/src/Utils.cpp +0 -139
  69. package/react-native/cpp/src/main.cpp +0 -178
  70. package/react-native/dittoffi/dittoffi.h +0 -4873
  71. package/react-native/dittoffi/ifaddrs.cpp +0 -385
  72. package/react-native/dittoffi/ifaddrs.h +0 -206
  73. package/react-native/ios/DittoRNSDK.h +0 -7
  74. package/react-native/ios/DittoRNSDK.mm +0 -159
  75. package/react-native/ios/YeetJSIUtils.h +0 -60
  76. package/react-native/ios/YeetJSIUtils.mm +0 -196
  77. package/react-native/lib/commonjs/ditto.rn.js +0 -93
  78. package/react-native/lib/commonjs/ditto.rn.js.map +0 -1
  79. package/react-native/lib/commonjs/index.js +0 -61
  80. package/react-native/lib/commonjs/index.js.map +0 -1
  81. package/react-native/lib/module/ditto.rn.js +0 -89
  82. package/react-native/lib/module/ditto.rn.js.map +0 -1
  83. package/react-native/lib/module/index.js +0 -27
  84. package/react-native/lib/module/index.js.map +0 -1
  85. package/react-native/lib/typescript/ditto.rn.d.ts +0 -15
  86. package/react-native/lib/typescript/ditto.rn.d.ts.map +0 -1
  87. package/react-native/lib/typescript/index.d.ts +0 -1
  88. package/react-native/lib/typescript/index.d.ts.map +0 -1
  89. package/react-native/src/ditto.rn.ts +0 -123
  90. package/react-native/src/environment/environment.fallback.ts +0 -4
  91. package/react-native/src/index.ts +0 -29
  92. package/react-native/src/sources/@cbor-redux.ts +0 -2
  93. package/react-native/src/sources/@ditto.core.ts +0 -1
  94. package/react-native/src/sources/@environment.ts +0 -1
  95. package/react-native/src/sources/attachment-fetch-event.ts +0 -54
  96. package/react-native/src/sources/attachment-fetcher-manager.ts +0 -145
  97. package/react-native/src/sources/attachment-fetcher.ts +0 -265
  98. package/react-native/src/sources/attachment-token.ts +0 -129
  99. package/react-native/src/sources/attachment.ts +0 -121
  100. package/react-native/src/sources/augment.ts +0 -108
  101. package/react-native/src/sources/authenticator.ts +0 -314
  102. package/react-native/src/sources/base-pending-cursor-operation.ts +0 -255
  103. package/react-native/src/sources/base-pending-id-specific-operation.ts +0 -112
  104. package/react-native/src/sources/bridge.ts +0 -557
  105. package/react-native/src/sources/build-time-constants.ts +0 -8
  106. package/react-native/src/sources/cbor.ts +0 -20
  107. package/react-native/src/sources/collection-interface.ts +0 -73
  108. package/react-native/src/sources/collection.ts +0 -219
  109. package/react-native/src/sources/collections-event.ts +0 -99
  110. package/react-native/src/sources/connection-request.ts +0 -142
  111. package/react-native/src/sources/counter.ts +0 -82
  112. package/react-native/src/sources/ditto.ts +0 -991
  113. package/react-native/src/sources/document-id.ts +0 -163
  114. package/react-native/src/sources/document-path.ts +0 -308
  115. package/react-native/src/sources/document.ts +0 -237
  116. package/react-native/src/sources/epilogue.ts +0 -32
  117. package/react-native/src/sources/error-codes.ts +0 -114
  118. package/react-native/src/sources/error.ts +0 -256
  119. package/react-native/src/sources/essentials.ts +0 -81
  120. package/react-native/src/sources/ffi-error.ts +0 -134
  121. package/react-native/src/sources/ffi.ts +0 -2190
  122. package/react-native/src/sources/identity.ts +0 -163
  123. package/react-native/src/sources/init.ts +0 -71
  124. package/react-native/src/sources/internal.ts +0 -143
  125. package/react-native/src/sources/keep-alive.ts +0 -73
  126. package/react-native/src/sources/key-path.ts +0 -198
  127. package/react-native/src/sources/live-query-event.ts +0 -208
  128. package/react-native/src/sources/live-query-manager.ts +0 -110
  129. package/react-native/src/sources/live-query.ts +0 -167
  130. package/react-native/src/sources/logger.ts +0 -196
  131. package/react-native/src/sources/main.ts +0 -61
  132. package/react-native/src/sources/observer-manager.ts +0 -185
  133. package/react-native/src/sources/observer.ts +0 -79
  134. package/react-native/src/sources/pending-collections-operation.ts +0 -241
  135. package/react-native/src/sources/pending-cursor-operation.ts +0 -218
  136. package/react-native/src/sources/pending-id-specific-operation.ts +0 -218
  137. package/react-native/src/sources/presence-manager.ts +0 -170
  138. package/react-native/src/sources/presence.ts +0 -427
  139. package/react-native/src/sources/query-result-item.ts +0 -131
  140. package/react-native/src/sources/query-result.ts +0 -55
  141. package/react-native/src/sources/register.ts +0 -95
  142. package/react-native/src/sources/small-peer-info.ts +0 -166
  143. package/react-native/src/sources/static-tcp-client.ts +0 -8
  144. package/react-native/src/sources/store-observer.ts +0 -170
  145. package/react-native/src/sources/store.ts +0 -630
  146. package/react-native/src/sources/subscription-manager.ts +0 -99
  147. package/react-native/src/sources/subscription.ts +0 -89
  148. package/react-native/src/sources/sync-subscription.ts +0 -90
  149. package/react-native/src/sources/sync.ts +0 -561
  150. package/react-native/src/sources/test-helpers.ts +0 -24
  151. package/react-native/src/sources/transport-conditions-manager.ts +0 -104
  152. package/react-native/src/sources/transport-config.ts +0 -430
  153. package/react-native/src/sources/update-result.ts +0 -66
  154. package/react-native/src/sources/update-results-map.ts +0 -65
  155. package/react-native/src/sources/websocket-client.ts +0 -7
  156. package/react-native/src/sources/write-transaction-collection.ts +0 -122
  157. package/react-native/src/sources/write-transaction-pending-cursor-operation.ts +0 -101
  158. package/react-native/src/sources/write-transaction-pending-id-specific-operation.ts +0 -74
  159. package/react-native/src/sources/write-transaction.ts +0 -121
  160. package/react-native.config.js +0 -9
@@ -1,218 +0,0 @@
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
- async function wrappedHandler(documents, event, nextSignal) {
206
- try {
207
- return await 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
- }
@@ -1,218 +0,0 @@
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
- // REFACTOR: turn null into undefined for consistency.
20
-
21
- /**
22
- * The closure that is called whenever a single documunent covered by a
23
- * live query changes.
24
- */
25
- export type SingleObservationHandler = (document: Document | null, event: SingleDocumentLiveQueryEvent, signalNext?: () => void) => void | Promise<void>
26
-
27
- // -----------------------------------------------------------------------------
28
-
29
- /**
30
- * These objects are returned when using {@link Collection.findByID | findByID()}
31
- * functionality on {@link Collection | collections}.
32
- *
33
- * You can either call {@link exec | exec()} on the object to get an immediate
34
- * return value, or you can establish either a live query or a subscription,
35
- * which both work over time.
36
- *
37
- * A live query, established by calling
38
- * {@link PendingIDSpecificOperation.observeLocal | observeLocal()}, will notify
39
- * you every time there's an update to the document with the ID you provided in
40
- * the preceding {@link Collection.findByID | findByID()} call.
41
- *
42
- * A subscription, established by calling {@link PendingIDSpecificOperation.subscribe | subscribe()}, will
43
- * act as a signal to other peers that you would like to receive updates from
44
- * them about the document with the ID you provided in the preceding
45
- * {@link Collection.findByID | findByID()} call.
46
- *
47
- * Update and remove functionality is also exposed through this object.
48
- */
49
- export class PendingIDSpecificOperation extends BasePendingIDSpecificOperation {
50
- async remove(): Promise<boolean> {
51
- const ditto = this.collection.store.ditto
52
- const dittoHandle = Bridge.ditto.handleFor(ditto)
53
-
54
- return ditto.deferCloseAsync(async () => {
55
- return await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
56
- const writeTransactionX = await FFI.writeTransaction(dittoHandle.deref())
57
- const didRemove = await FFI.collectionRemove(dittoHandle.deref(), this.collection.name, writeTransactionX, this.documentIDCBOR)
58
- await FFI.writeTransactionCommit(dittoHandle.deref(), writeTransactionX)
59
- return didRemove
60
- })
61
- })
62
- }
63
-
64
- async evict(): Promise<boolean> {
65
- const ditto = this.collection.store.ditto
66
- const dittoHandle = Bridge.ditto.handleFor(ditto)
67
-
68
- return ditto.deferCloseAsync(async () => {
69
- return await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
70
- const writeTransactionX = await FFI.writeTransaction(dittoHandle.deref())
71
- const didEvict = await FFI.collectionEvict(dittoHandle.deref(), this.collection.name, writeTransactionX, this.documentIDCBOR)
72
- await FFI.writeTransactionCommit(dittoHandle.deref(), writeTransactionX)
73
- return didEvict
74
- })
75
- })
76
- }
77
-
78
- async update(closure: (document: MutableDocument) => void): Promise<UpdateResult[]> {
79
- const ditto = this.collection.store.ditto
80
- const dittoHandle = Bridge.ditto.handleFor(ditto)
81
-
82
- return ditto.deferCloseAsync(async () => {
83
- const readTransactionX = await FFI.readTransaction(dittoHandle.deref())
84
- const documentX = await FFI.collectionGet(dittoHandle.deref(), this.collection.name, this.documentIDCBOR, readTransactionX)
85
- FFI.readTransactionFree(readTransactionX)
86
-
87
- if (!documentX) throw new Error(`Can't update, document with ID '${this.documentID.toString()}' not found in collection named '${this.collection.name}'`)
88
-
89
- const mutableDocument = Bridge.mutableDocument.bridge(documentX, () => new MutableDocument())
90
- closure(mutableDocument)
91
-
92
- // Ownership is transferred back to the FFI layer via collectionUpdate(),
93
- // we therefore need to explicitly unregister the instance.
94
- Bridge.mutableDocument.unregister(mutableDocument)
95
-
96
- const writeTransactionX = await FFI.writeTransaction(dittoHandle.deref())
97
- await FFI.collectionUpdate(dittoHandle.deref(), this.collection.name, writeTransactionX, documentX)
98
- await FFI.writeTransactionCommit(dittoHandle.deref(), writeTransactionX)
99
-
100
- return mutableDocument['@ditto.updateResults'].slice()
101
- })
102
- }
103
-
104
- /**
105
- * Enables you to subscribe to changes that occur in relation to a document
106
- * remotely.
107
- *
108
- * Having a subscription acts as a signal to other peers that you are
109
- * interested in receiving updates when local or remote changes are made to
110
- * the relevant document.
111
- *
112
- * The returned {@link Subscription} object must be kept in scope for as long
113
- * as you want to keep receiving updates.
114
- *
115
- * @returns A {@link Subscription} object that must be kept in scope for as
116
- * long as you want to keep receiving updates for the document.
117
- */
118
- subscribe(): Subscription {
119
- const subscription = new Subscription(this.collection as Collection, this.query, null, [], -1, 0)
120
- this.collection.store.ditto.subscriptionManager.add(subscription)
121
- return subscription
122
- }
123
-
124
- /**
125
- * Enables you to listen for changes that occur in relation to a document
126
- * locally.
127
- *
128
- * This won't subscribe to receive changes made remotely by others and so it
129
- * will only fire updates when a local change is made. If you want to receive
130
- * remotely performed updates as well, you'll have to create a subscription
131
- * via {@link PendingIDSpecificOperation.subscribe | subscribe()} for the same
132
- * document ID.
133
- *
134
- * The returned {@link LiveQuery} object must be kept in scope for as long
135
- * as you want the provided `handler` to be called when an update
136
- * occurs.
137
- *
138
- * @param handler A block that will be called every time there is a
139
- * transaction committed to the store that involves a modification to the
140
- * document with the relevant ID in the collection that
141
- * {@link PendingIDSpecificOperation.observeLocal | observeLocal()} was called on.
142
- *
143
- * @returns A {@link LiveQuery} object that must be kept in scope for as long
144
- * as you want to keep receiving updates.
145
- */
146
- observeLocal(handler: SingleObservationHandler): LiveQuery {
147
- return this._observe(handler, false)
148
- }
149
-
150
- /**
151
- * Enables you to listen for changes that occur in relation to a document
152
- * locally and to signal when you are ready for the live query to deliver
153
- * the next event.
154
- *
155
- * This won't subscribe to receive changes made remotely by others and so it
156
- * will only fire updates when a local change is made. If you want to receive
157
- * remotely performed updates as well, you'll have to create a subscription
158
- * via {@link PendingIDSpecificOperation.subscribe | subscribe()} for the same
159
- * document ID.
160
- *
161
- * The returned {@link LiveQuery} object must be kept in scope for as long
162
- * as you want the provided `handler` to be called when an update
163
- * occurs.
164
- *
165
- * @param handler A block that will be called every time there is a
166
- * transaction committed to the store that involves a modification to the
167
- * document with the relevant ID in the collection that
168
- * {@link PendingIDSpecificOperation.observeLocal | observeLocal()} was called on.
169
- *
170
- * @returns A {@link LiveQuery} object that must be kept in scope for as long
171
- * as you want to keep receiving updates.
172
- */
173
- observeLocalWithNextSignal(handler: SingleObservationHandler): LiveQuery {
174
- return this._observe(handler, true)
175
- }
176
-
177
- /** @internal */
178
- constructor(documentID: DocumentID, collection: Collection) {
179
- super(documentID, collection)
180
- }
181
-
182
- /** @internal */
183
- _observe(handler: SingleObservationHandler, waitForNextSignal: boolean): LiveQuery {
184
- const liveQuery = new LiveQuery(this.query, null, null, [], -1, 0, this.collection as Collection, async (documents, event, signalNext) => {
185
- if (documents.length > 1) {
186
- throw new Error(`Internal inconsistency, single document live query returned more than one document. Query: ${this.query}}.`)
187
- }
188
-
189
- 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}.`)
190
- 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}.`)
191
- 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}.`)
192
- 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}.`)
193
- 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}.`)
194
-
195
- const totalNumberOfManipulations = event.isInitial === true ? 0 : event.insertions.length + event.deletions.length + event.updates.length
196
- 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}.`)
197
-
198
- // IDEA: use `undefined` instead of `null` and
199
- // adapt Wasm variant plus API definition.
200
- const document = documents[0] || null
201
- const oldDocument = event.isInitial === true ? undefined : event.oldDocuments[0]
202
-
203
- const singleDocumentEvent = new SingleDocumentLiveQueryEvent(event.isInitial, oldDocument)
204
- if (waitForNextSignal) {
205
- void handler(document, singleDocumentEvent, signalNext)
206
- } else {
207
- try {
208
- await handler(document, singleDocumentEvent)
209
- } finally {
210
- signalNext()
211
- }
212
- }
213
- })
214
-
215
- this.collection.store.ditto.liveQueryManager.startLiveQuery(liveQuery)
216
- return liveQuery
217
- }
218
- }
@@ -1,170 +0,0 @@
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
- // REFACTOR: make subclass of Observer and adapt this one.
20
- readonly ditto: Ditto
21
-
22
- constructor(ditto: Ditto) {
23
- this.ditto = ditto
24
- this.isClosed = false
25
- this.isRegistered = false
26
- this.currentRemotePeers = []
27
- this.callbacksByPresenceToken = {}
28
- }
29
-
30
- /** @internal */
31
- addObserver(callback: (remotePeers: RemotePeer[]) => void): PresenceToken {
32
- if (this.isClosed) {
33
- // REFACTOR: throw a catchable error here, such that calling code
34
- // can be more specific when forwarding it to the user.
35
- throw new Error(`Internal inconsistency, can't add presence observer, observer mananger close()-ed.`)
36
- }
37
-
38
- this.registerIfNeeded()
39
-
40
- const token = generateEphemeralToken()
41
- this.callbacksByPresenceToken[token] = callback
42
- this.ditto.keepAlive.retain(`PresenceObservation.${token}`)
43
-
44
- // REFACTOR: make the initial callback call async, too (othewise we'd be
45
- // mixing sync with async, which is a bit problematic in general but might
46
- // be OK with single-threaded JS). This is a bit tricky, simply
47
- // setTimeout(..., 0) here could lead us to a situation where the initial
48
- // call would be sent AFTER the regular notification.
49
- callback(this.currentRemotePeers)
50
-
51
- return token
52
- }
53
-
54
- /** @internal */
55
- async removeObserver(token: PresenceToken): Promise<void> {
56
- const callback = this.callbacksByPresenceToken[token]
57
-
58
- if (typeof callback === 'undefined') {
59
- throw new Error(`Can't remove presence observer, token '${token}' has never been registered before.`)
60
- }
61
-
62
- if (callback === null) {
63
- // Observer has already been removed, no-op.
64
- return
65
- }
66
-
67
- if (typeof this.callbacksByPresenceToken[token] != 'undefined') {
68
- this.ditto.keepAlive.release(`PresenceObservation.${token}`)
69
- // REFACTOR: not deleting the token here will keep eating up
70
- // memory over long periods of time. We actually need to track
71
- // the observer objects themselves and remove it from the table
72
- // as soon as the observer object is garbage collected.
73
- this.callbacksByPresenceToken[token] = null
74
- return this.unregisterIfNeeded()
75
- }
76
- }
77
-
78
- /** @internal */
79
- hasObserver(token: PresenceToken): boolean {
80
- return typeof this.callbacksByPresenceToken[token] != 'undefined'
81
- }
82
-
83
- /** @internal */
84
- async close() {
85
- this.isClosed = true
86
- const tokens = Object.keys(this.callbacksByPresenceToken)
87
- return Promise.all(tokens.map((token) => this.removeObserver(token)))
88
- }
89
-
90
- // ------------------------------------------------------------ Private ------
91
-
92
- private isClosed: boolean
93
- private isRegistered: boolean
94
- private currentRemotePeers: RemotePeer[]
95
- private callbacksByPresenceToken: { [key: string]: ((remotePeers: RemotePeer[]) => void) | null }
96
-
97
- private hasObservers(): boolean {
98
- return Object.keys(this.callbacksByPresenceToken).length > 0
99
- }
100
-
101
- private registerIfNeeded() {
102
- const ditto = this.ditto
103
- const dittoHandle = Bridge.ditto.handleFor(this.ditto)
104
- ditto.deferClose(() => {
105
- const needsToRegister = !this.isRegistered
106
- if (needsToRegister) {
107
- this.isRegistered = true
108
- const remotePeersJSONString = FFI.dittoPresenceV1(dittoHandle.deref())
109
- this.currentRemotePeers = this.decode(remotePeersJSONString).sort(this.compareRemotePeers)
110
- FFI.dittoRegisterPresenceV1Callback(dittoHandle.deref(), this.handlePresenceV1Callback.bind(this))
111
- }
112
- })
113
- }
114
-
115
- private unregisterIfNeeded(): Promise<void> {
116
- const ditto = this.ditto
117
- const dittoHandle = Bridge.ditto.handleFor(ditto)
118
- return this.ditto.deferCloseAsync(async () => {
119
- const needsToUnregister = !this.hasObservers() && this.isRegistered
120
- if (needsToUnregister) {
121
- this.isRegistered = false
122
- await FFI.dittoClearPresenceCallback(dittoHandle.deref())
123
- this.currentRemotePeers = []
124
- }
125
- })
126
- }
127
-
128
- private handlePresenceV1Callback(remotePeersJSONString: string) {
129
- const remotePeers = this.decode(remotePeersJSONString).sort(this.compareRemotePeers)
130
- this.currentRemotePeers = remotePeers
131
- this.notify()
132
- }
133
-
134
- private notify() {
135
- if (this.isClosed) {
136
- // NOTE: we don't notify observers after closing.
137
- return
138
- }
139
-
140
- for (const token in this.callbacksByPresenceToken) {
141
- const callback = this.callbacksByPresenceToken[token]
142
- if (callback) callback(this.currentRemotePeers)
143
- }
144
- }
145
-
146
- private decode(remotePeersJSONString: string): RemotePeer[] {
147
- const remotePeersJSON: any[] = JSON.parse(remotePeersJSONString)
148
- return remotePeersJSON.map((remotePeerJSON) => {
149
- return {
150
- networkID: remotePeerJSON['network_id'],
151
- deviceName: remotePeerJSON['device_name'],
152
- rssi: remotePeerJSON['rssi'] ?? undefined,
153
- approximateDistanceInMeters: remotePeerJSON['approximate_distance_in_meters'] ?? undefined,
154
- connections: remotePeerJSON['connections'],
155
- }
156
- })
157
- }
158
-
159
- private compareRemotePeers(left: RemotePeer, right: RemotePeer) {
160
- // NOTE: we use the exact same sort order here as in the ObjC version.
161
-
162
- if (left.connections.length === 0 && right.connections.length > 0) return +1
163
- if (left.connections.length > 0 && right.connections.length === 0) return -1
164
-
165
- if (left.deviceName < right.deviceName) return -1
166
- if (left.deviceName > right.deviceName) return +1
167
-
168
- return 0
169
- }
170
- }