@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.
- package/README.md +2 -2
- package/node/ditto.cjs.js +1 -1
- package/node/ditto.darwin-arm64.node +0 -0
- package/node/ditto.darwin-x64.node +0 -0
- package/node/ditto.linux-arm.node +0 -0
- package/node/ditto.linux-arm64.node +0 -0
- package/node/ditto.linux-x64.node +0 -0
- package/node/ditto.win32-x64.node +0 -0
- package/node/transports.darwin-arm64.node +0 -0
- package/node/transports.darwin-x64.node +0 -0
- package/package.json +2 -5
- package/web/ditto.es6.js +1 -1
- package/web/ditto.umd.js +1 -1
- package/web/ditto.wasm +0 -0
- package/DittoReactNative.podspec +0 -27
- package/react-native/android/.gradle/8.9/checksums/checksums.lock +0 -0
- package/react-native/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
- package/react-native/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
- package/react-native/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
- package/react-native/android/.gradle/8.9/gc.properties +0 -0
- package/react-native/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/react-native/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/react-native/android/.gradle/vcs-1/gc.properties +0 -0
- package/react-native/android/CMakeLists.txt +0 -36
- package/react-native/android/build.gradle +0 -190
- package/react-native/android/cpp-adapter.cpp +0 -259
- package/react-native/android/gradle.properties +0 -5
- package/react-native/android/src/main/AndroidManifest.xml +0 -4
- package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +0 -120
- package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKPackage.java +0 -28
- package/react-native/cpp/include/Arc.hpp +0 -159
- package/react-native/cpp/include/Attachment.h +0 -20
- package/react-native/cpp/include/Authentication.h +0 -23
- package/react-native/cpp/include/Collection.h +0 -13
- package/react-native/cpp/include/ConnectionRequest.h +0 -18
- package/react-native/cpp/include/DQL.h +0 -21
- package/react-native/cpp/include/Document.h +0 -17
- package/react-native/cpp/include/FFIUtils.h +0 -16
- package/react-native/cpp/include/IO.h +0 -13
- package/react-native/cpp/include/Identity.h +0 -17
- package/react-native/cpp/include/Lifecycle.h +0 -16
- package/react-native/cpp/include/LiveQuery.h +0 -17
- package/react-native/cpp/include/Logger.h +0 -22
- package/react-native/cpp/include/Misc.h +0 -30
- package/react-native/cpp/include/Presence.h +0 -18
- package/react-native/cpp/include/SmallPeerInfo.h +0 -19
- package/react-native/cpp/include/Transports.h +0 -25
- package/react-native/cpp/include/TypedArray.hpp +0 -167
- package/react-native/cpp/include/Utils.h +0 -70
- package/react-native/cpp/include/main.h +0 -10
- package/react-native/cpp/src/Attachment.cpp +0 -272
- package/react-native/cpp/src/Authentication.cpp +0 -227
- package/react-native/cpp/src/Collection.cpp +0 -56
- package/react-native/cpp/src/ConnectionRequest.cpp +0 -123
- package/react-native/cpp/src/DQL.cpp +0 -256
- package/react-native/cpp/src/Document.cpp +0 -146
- package/react-native/cpp/src/FFIUtils.cpp +0 -122
- package/react-native/cpp/src/IO.cpp +0 -35
- package/react-native/cpp/src/Identity.cpp +0 -122
- package/react-native/cpp/src/Lifecycle.cpp +0 -93
- package/react-native/cpp/src/LiveQuery.cpp +0 -63
- package/react-native/cpp/src/Logger.cpp +0 -199
- package/react-native/cpp/src/Misc.cpp +0 -322
- package/react-native/cpp/src/Presence.cpp +0 -166
- package/react-native/cpp/src/SmallPeerInfo.cpp +0 -142
- package/react-native/cpp/src/Transports.cpp +0 -275
- package/react-native/cpp/src/TypedArray.cpp +0 -303
- package/react-native/cpp/src/Utils.cpp +0 -139
- package/react-native/cpp/src/main.cpp +0 -178
- package/react-native/dittoffi/dittoffi.h +0 -4873
- package/react-native/dittoffi/ifaddrs.cpp +0 -385
- package/react-native/dittoffi/ifaddrs.h +0 -206
- package/react-native/ios/DittoRNSDK.h +0 -7
- package/react-native/ios/DittoRNSDK.mm +0 -159
- package/react-native/ios/YeetJSIUtils.h +0 -60
- package/react-native/ios/YeetJSIUtils.mm +0 -196
- package/react-native/lib/commonjs/ditto.rn.js +0 -93
- package/react-native/lib/commonjs/ditto.rn.js.map +0 -1
- package/react-native/lib/commonjs/index.js +0 -61
- package/react-native/lib/commonjs/index.js.map +0 -1
- package/react-native/lib/module/ditto.rn.js +0 -89
- package/react-native/lib/module/ditto.rn.js.map +0 -1
- package/react-native/lib/module/index.js +0 -27
- package/react-native/lib/module/index.js.map +0 -1
- package/react-native/lib/typescript/ditto.rn.d.ts +0 -15
- package/react-native/lib/typescript/ditto.rn.d.ts.map +0 -1
- package/react-native/lib/typescript/index.d.ts +0 -1
- package/react-native/lib/typescript/index.d.ts.map +0 -1
- package/react-native/src/ditto.rn.ts +0 -123
- package/react-native/src/environment/environment.fallback.ts +0 -4
- package/react-native/src/index.ts +0 -29
- package/react-native/src/sources/@cbor-redux.ts +0 -2
- package/react-native/src/sources/@ditto.core.ts +0 -1
- package/react-native/src/sources/@environment.ts +0 -1
- package/react-native/src/sources/attachment-fetch-event.ts +0 -54
- package/react-native/src/sources/attachment-fetcher-manager.ts +0 -145
- package/react-native/src/sources/attachment-fetcher.ts +0 -265
- package/react-native/src/sources/attachment-token.ts +0 -129
- package/react-native/src/sources/attachment.ts +0 -121
- package/react-native/src/sources/augment.ts +0 -108
- package/react-native/src/sources/authenticator.ts +0 -314
- package/react-native/src/sources/base-pending-cursor-operation.ts +0 -255
- package/react-native/src/sources/base-pending-id-specific-operation.ts +0 -112
- package/react-native/src/sources/bridge.ts +0 -557
- package/react-native/src/sources/build-time-constants.ts +0 -8
- package/react-native/src/sources/cbor.ts +0 -20
- package/react-native/src/sources/collection-interface.ts +0 -73
- package/react-native/src/sources/collection.ts +0 -219
- package/react-native/src/sources/collections-event.ts +0 -99
- package/react-native/src/sources/connection-request.ts +0 -142
- package/react-native/src/sources/counter.ts +0 -82
- package/react-native/src/sources/ditto.ts +0 -991
- package/react-native/src/sources/document-id.ts +0 -163
- package/react-native/src/sources/document-path.ts +0 -308
- package/react-native/src/sources/document.ts +0 -237
- package/react-native/src/sources/epilogue.ts +0 -32
- package/react-native/src/sources/error-codes.ts +0 -114
- package/react-native/src/sources/error.ts +0 -256
- package/react-native/src/sources/essentials.ts +0 -81
- package/react-native/src/sources/ffi-error.ts +0 -134
- package/react-native/src/sources/ffi.ts +0 -2190
- package/react-native/src/sources/identity.ts +0 -163
- package/react-native/src/sources/init.ts +0 -71
- package/react-native/src/sources/internal.ts +0 -143
- package/react-native/src/sources/keep-alive.ts +0 -73
- package/react-native/src/sources/key-path.ts +0 -198
- package/react-native/src/sources/live-query-event.ts +0 -208
- package/react-native/src/sources/live-query-manager.ts +0 -110
- package/react-native/src/sources/live-query.ts +0 -167
- package/react-native/src/sources/logger.ts +0 -196
- package/react-native/src/sources/main.ts +0 -61
- package/react-native/src/sources/observer-manager.ts +0 -185
- package/react-native/src/sources/observer.ts +0 -79
- package/react-native/src/sources/pending-collections-operation.ts +0 -241
- package/react-native/src/sources/pending-cursor-operation.ts +0 -218
- package/react-native/src/sources/pending-id-specific-operation.ts +0 -218
- package/react-native/src/sources/presence-manager.ts +0 -170
- package/react-native/src/sources/presence.ts +0 -427
- package/react-native/src/sources/query-result-item.ts +0 -131
- package/react-native/src/sources/query-result.ts +0 -55
- package/react-native/src/sources/register.ts +0 -95
- package/react-native/src/sources/small-peer-info.ts +0 -166
- package/react-native/src/sources/static-tcp-client.ts +0 -8
- package/react-native/src/sources/store-observer.ts +0 -170
- package/react-native/src/sources/store.ts +0 -630
- package/react-native/src/sources/subscription-manager.ts +0 -99
- package/react-native/src/sources/subscription.ts +0 -89
- package/react-native/src/sources/sync-subscription.ts +0 -90
- package/react-native/src/sources/sync.ts +0 -561
- package/react-native/src/sources/test-helpers.ts +0 -24
- package/react-native/src/sources/transport-conditions-manager.ts +0 -104
- package/react-native/src/sources/transport-config.ts +0 -430
- package/react-native/src/sources/update-result.ts +0 -66
- package/react-native/src/sources/update-results-map.ts +0 -65
- package/react-native/src/sources/websocket-client.ts +0 -7
- package/react-native/src/sources/write-transaction-collection.ts +0 -122
- package/react-native/src/sources/write-transaction-pending-cursor-operation.ts +0 -101
- package/react-native/src/sources/write-transaction-pending-id-specific-operation.ts +0 -74
- package/react-native/src/sources/write-transaction.ts +0 -121
- 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
|
-
}
|