@dittolive/ditto 4.5.1-experimental.aarch64-linux.1.aarch64 → 4.5.2-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 (152) hide show
  1. package/DittoReactNative.podspec +25 -0
  2. package/README.md +2 -2
  3. package/node/ditto.cjs.js +1 -1
  4. package/node/ditto.cjs.js.map +1 -0
  5. package/node/ditto.cjs.pretty.js +9655 -0
  6. package/node/ditto.cjs.pretty.js.map +1 -0
  7. package/node/ditto.darwin-arm64.node +0 -0
  8. package/node/ditto.darwin-x64.node +0 -0
  9. package/node/{ditto.linux-arm64.node → ditto.linux-x64.node} +0 -0
  10. package/node/transports.darwin-arm64.node +0 -0
  11. package/node/transports.darwin-x64.node +0 -0
  12. package/package.json +2 -1
  13. package/react-native/android/CMakeLists.txt +37 -0
  14. package/react-native/android/build.gradle +186 -0
  15. package/react-native/android/cpp-adapter.cpp +254 -0
  16. package/react-native/android/gradle.properties +5 -0
  17. package/react-native/android/src/main/AndroidManifest.xml +4 -0
  18. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +85 -0
  19. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKPackage.java +28 -0
  20. package/react-native/cpp/include/Arc.hpp +141 -0
  21. package/react-native/cpp/include/Attachment.h +16 -0
  22. package/react-native/cpp/include/Authentication.h +23 -0
  23. package/react-native/cpp/include/Collection.h +13 -0
  24. package/react-native/cpp/include/DQL.h +21 -0
  25. package/react-native/cpp/include/Document.h +17 -0
  26. package/react-native/cpp/include/Identity.h +17 -0
  27. package/react-native/cpp/include/Lifecycle.h +17 -0
  28. package/react-native/cpp/include/LiveQuery.h +17 -0
  29. package/react-native/cpp/include/Logger.h +22 -0
  30. package/react-native/cpp/include/Misc.h +27 -0
  31. package/react-native/cpp/include/Presence.h +14 -0
  32. package/react-native/cpp/include/SmallPeerInfo.h +19 -0
  33. package/react-native/cpp/include/Transports.h +25 -0
  34. package/react-native/cpp/include/TypedArray.hpp +167 -0
  35. package/react-native/cpp/include/Utils.h +61 -0
  36. package/react-native/cpp/include/main.h +10 -0
  37. package/react-native/cpp/src/Attachment.cpp +86 -0
  38. package/react-native/cpp/src/Authentication.cpp +227 -0
  39. package/react-native/cpp/src/Collection.cpp +54 -0
  40. package/react-native/cpp/src/DQL.cpp +256 -0
  41. package/react-native/cpp/src/Document.cpp +146 -0
  42. package/react-native/cpp/src/Identity.cpp +123 -0
  43. package/react-native/cpp/src/Lifecycle.cpp +110 -0
  44. package/react-native/cpp/src/LiveQuery.cpp +63 -0
  45. package/react-native/cpp/src/Logger.cpp +200 -0
  46. package/react-native/cpp/src/Misc.cpp +283 -0
  47. package/react-native/cpp/src/Presence.cpp +79 -0
  48. package/react-native/cpp/src/SmallPeerInfo.cpp +142 -0
  49. package/react-native/cpp/src/Transports.cpp +270 -0
  50. package/react-native/cpp/src/TypedArray.cpp +303 -0
  51. package/react-native/cpp/src/Utils.cpp +138 -0
  52. package/react-native/cpp/src/main.cpp +152 -0
  53. package/react-native/dittoffi/dittoffi.h +4700 -0
  54. package/react-native/dittoffi/ifaddrs.cpp +385 -0
  55. package/react-native/dittoffi/ifaddrs.h +206 -0
  56. package/react-native/ios/DittoRNSDK.h +7 -0
  57. package/react-native/ios/DittoRNSDK.mm +107 -0
  58. package/react-native/ios/YeetJSIUtils.h +60 -0
  59. package/react-native/ios/YeetJSIUtils.mm +196 -0
  60. package/react-native/lib/commonjs/ditto.rn.js +92 -0
  61. package/react-native/lib/commonjs/ditto.rn.js.map +1 -0
  62. package/react-native/lib/commonjs/index.js +61 -0
  63. package/react-native/lib/commonjs/index.js.map +1 -0
  64. package/react-native/lib/module/ditto.rn.js +88 -0
  65. package/react-native/lib/module/ditto.rn.js.map +1 -0
  66. package/react-native/lib/module/index.js +27 -0
  67. package/react-native/lib/module/index.js.map +1 -0
  68. package/react-native/lib/typescript/ditto.rn.d.ts +15 -0
  69. package/react-native/lib/typescript/ditto.rn.d.ts.map +1 -0
  70. package/react-native/lib/typescript/index.d.ts +1 -0
  71. package/react-native/lib/typescript/index.d.ts.map +1 -0
  72. package/react-native/src/ditto.rn.ts +91 -0
  73. package/react-native/src/environment/environment.fallback.ts +4 -0
  74. package/react-native/src/index.ts +26 -0
  75. package/react-native/src/sources/@cbor-redux.ts +2 -0
  76. package/react-native/src/sources/@ditto.core.ts +1 -0
  77. package/react-native/src/sources/@environment.ts +1 -0
  78. package/react-native/src/sources/attachment-fetch-event.ts +54 -0
  79. package/react-native/src/sources/attachment-fetcher-manager.ts +144 -0
  80. package/react-native/src/sources/attachment-fetcher.ts +134 -0
  81. package/react-native/src/sources/attachment-token.ts +48 -0
  82. package/react-native/src/sources/attachment.ts +74 -0
  83. package/react-native/src/sources/augment.ts +101 -0
  84. package/react-native/src/sources/authenticator.ts +314 -0
  85. package/react-native/src/sources/base-pending-cursor-operation.ts +239 -0
  86. package/react-native/src/sources/base-pending-id-specific-operation.ts +109 -0
  87. package/react-native/src/sources/bridge.ts +553 -0
  88. package/react-native/src/sources/build-time-constants.ts +8 -0
  89. package/react-native/src/sources/cbor.ts +35 -0
  90. package/react-native/src/sources/collection-interface.ts +67 -0
  91. package/react-native/src/sources/collection.ts +212 -0
  92. package/react-native/src/sources/collections-event.ts +99 -0
  93. package/react-native/src/sources/counter.ts +82 -0
  94. package/react-native/src/sources/ditto.ts +979 -0
  95. package/react-native/src/sources/document-id.ts +159 -0
  96. package/react-native/src/sources/document-path.ts +306 -0
  97. package/react-native/src/sources/document.ts +193 -0
  98. package/react-native/src/sources/epilogue.ts +30 -0
  99. package/react-native/src/sources/error-codes.ts +52 -0
  100. package/react-native/src/sources/error.ts +208 -0
  101. package/react-native/src/sources/essentials.ts +53 -0
  102. package/react-native/src/sources/ffi-error.ts +122 -0
  103. package/react-native/src/sources/ffi.ts +2012 -0
  104. package/react-native/src/sources/identity.ts +163 -0
  105. package/react-native/src/sources/init.ts +71 -0
  106. package/react-native/src/sources/internal.ts +109 -0
  107. package/react-native/src/sources/keep-alive.ts +73 -0
  108. package/react-native/src/sources/key-path.ts +198 -0
  109. package/react-native/src/sources/live-query-event.ts +208 -0
  110. package/react-native/src/sources/live-query-manager.ts +102 -0
  111. package/react-native/src/sources/live-query.ts +166 -0
  112. package/react-native/src/sources/logger.ts +196 -0
  113. package/react-native/src/sources/main.ts +60 -0
  114. package/react-native/src/sources/observer-manager.ts +178 -0
  115. package/react-native/src/sources/observer.ts +79 -0
  116. package/react-native/src/sources/pending-collections-operation.ts +232 -0
  117. package/react-native/src/sources/pending-cursor-operation.ts +218 -0
  118. package/react-native/src/sources/pending-id-specific-operation.ts +218 -0
  119. package/react-native/src/sources/presence-manager.ts +161 -0
  120. package/react-native/src/sources/presence.ts +233 -0
  121. package/react-native/src/sources/query-result-item.ts +116 -0
  122. package/react-native/src/sources/query-result.ts +55 -0
  123. package/react-native/src/sources/register.ts +95 -0
  124. package/react-native/src/sources/small-peer-info.ts +177 -0
  125. package/react-native/src/sources/static-tcp-client.ts +6 -0
  126. package/react-native/src/sources/store-observer.ts +177 -0
  127. package/react-native/src/sources/store.ts +385 -0
  128. package/react-native/src/sources/subscription-manager.ts +99 -0
  129. package/react-native/src/sources/subscription.ts +89 -0
  130. package/react-native/src/sources/sync-subscription.ts +90 -0
  131. package/react-native/src/sources/sync.ts +559 -0
  132. package/react-native/src/sources/test-helpers.ts +24 -0
  133. package/react-native/src/sources/transport-conditions-manager.ts +104 -0
  134. package/react-native/src/sources/transport-config.ts +430 -0
  135. package/react-native/src/sources/update-result.ts +66 -0
  136. package/react-native/src/sources/update-results-map.ts +57 -0
  137. package/react-native/src/sources/websocket-client.ts +7 -0
  138. package/react-native/src/sources/write-transaction-collection.ts +122 -0
  139. package/react-native/src/sources/write-transaction-pending-cursor-operation.ts +101 -0
  140. package/react-native/src/sources/write-transaction-pending-id-specific-operation.ts +74 -0
  141. package/react-native/src/sources/write-transaction.ts +121 -0
  142. package/react-native.config.js +9 -0
  143. package/types/ditto.d.ts.map +1 -0
  144. package/web/ditto.es6.js +1 -1
  145. package/web/ditto.es6.js.map +1 -0
  146. package/web/ditto.es6.pretty.js +12600 -0
  147. package/web/ditto.es6.pretty.js.map +1 -0
  148. package/web/ditto.umd.js +1 -1
  149. package/web/ditto.umd.js.map +1 -0
  150. package/web/ditto.umd.pretty.js +12669 -0
  151. package/web/ditto.umd.pretty.js.map +1 -0
  152. package/web/ditto.wasm +0 -0
@@ -0,0 +1,60 @@
1
+ //
2
+ // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
+ //
4
+
5
+ // IMPORTANT: this file is only for exporting public API, please don't
6
+ // add "significant" logic in here (sort of a "Framework Header" in ObjC).
7
+
8
+ export * from './keep-alive'
9
+ export * from './observer'
10
+
11
+ export * from './essentials'
12
+ export * from './counter'
13
+ export * from './register'
14
+ export * from './attachment-token'
15
+
16
+ export * from './init'
17
+ export * from './logger'
18
+ export * from './document-id'
19
+
20
+ export * from './base-pending-cursor-operation'
21
+ export * from './base-pending-id-specific-operation'
22
+ export * from './authenticator'
23
+ export * from './identity'
24
+ export * from './ditto'
25
+ export * from './store-observer'
26
+ export * from './collection'
27
+ export * from './collection-interface'
28
+ export * from './collections-event'
29
+ export * from './document-path'
30
+ export * from './document'
31
+ export * from './sync'
32
+ export * from './sync-subscription'
33
+ export * from './error'
34
+ export * from './error-codes'
35
+ export * from './query-result-item'
36
+ export * from './query-result'
37
+ export * from './live-query-event'
38
+ export * from './live-query'
39
+ export * from './attachment'
40
+ export * from './attachment-fetcher'
41
+ export * from './attachment-fetch-event'
42
+ export * from './pending-cursor-operation'
43
+ export * from './pending-id-specific-operation'
44
+ export * from './pending-collections-operation'
45
+ export * from './small-peer-info'
46
+ export * from './store'
47
+ export * from './presence'
48
+ export * from './subscription'
49
+ export * from './test-helpers'
50
+ export * from './transport-config'
51
+ export * from './update-result'
52
+ export * from './update-results-map'
53
+ export * from './write-transaction'
54
+ export * from './write-transaction-collection'
55
+ export * from './write-transaction-pending-cursor-operation'
56
+ export * from './write-transaction-pending-id-specific-operation'
57
+ export * from './epilogue'
58
+
59
+ // TEMPORARY: exported to deal with non-canonical IDs.
60
+ export * from './cbor'
@@ -0,0 +1,178 @@
1
+ //
2
+ // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
+ //
4
+
5
+ import { generateEphemeralToken } from './internal'
6
+ import { KeepAlive } from './keep-alive'
7
+
8
+ /** @internal */
9
+ export type ObserverToken = string
10
+
11
+ /** @internal */
12
+ export type ObserverManagerConstructorOptions = {
13
+ keepAlive?: KeepAlive
14
+ register?: (callback: (...args: any[]) => void) => void
15
+ unregister?: () => void
16
+ process?: (...args: any[]) => any[]
17
+ }
18
+
19
+ /** @internal */
20
+ export class ObserverManager {
21
+ /** @internal */
22
+ readonly id: string
23
+
24
+ /** @internal */
25
+ readonly keepAlive: KeepAlive | null
26
+
27
+ /** @internal */
28
+ constructor(id: string, options: ObserverManagerConstructorOptions = {}) {
29
+ const keepAlive = options.keepAlive ?? null
30
+ const register = options.register ?? null
31
+ const unregister = options.unregister ?? null
32
+ const process = options.process ?? null
33
+
34
+ this.id = id
35
+ this.keepAlive = keepAlive
36
+
37
+ this.isClosed = false
38
+ this.isRegistered = false
39
+ this.callbacksByToken = {}
40
+
41
+ if (register !== null) {
42
+ this.register = register
43
+ }
44
+
45
+ if (unregister !== null) {
46
+ this.unregister = unregister
47
+ }
48
+
49
+ if (process !== null) {
50
+ this.process = process
51
+ }
52
+ }
53
+
54
+ /** @internal */
55
+ addObserver(callback: any): ObserverToken {
56
+ if (this.isClosed) {
57
+ throw new Error(`Internal inconsistency, can't add '${this.id}' observer, observer mananger close()-ed.`)
58
+ }
59
+
60
+ this.registerIfNeeded()
61
+
62
+ const token = generateEphemeralToken()
63
+ this.callbacksByToken[token] = callback
64
+
65
+ this.keepAlive?.retain(`${this.id}.${token}`)
66
+ return token
67
+ }
68
+
69
+ /** @internal */
70
+ removeObserver(token: ObserverToken): void {
71
+ const callback = this.callbacksByToken[token]
72
+
73
+ if (typeof callback === 'undefined') {
74
+ throw new Error(`Can't remove '${this.id}' observer, token '${token}' has never been registered before.`)
75
+ }
76
+
77
+ if (callback === null) {
78
+ // Observer has already been removed, no-op.
79
+ return
80
+ }
81
+
82
+ // The value is set to null to be able to discern between
83
+ // observers that have been removed and observers that have
84
+ // never been registered before.
85
+ this.callbacksByToken[token] = null
86
+
87
+ this.keepAlive?.release(`${this.id}.${token}`)
88
+ this.unregisterIfNeeded()
89
+ }
90
+
91
+ hasObserver(token: ObserverToken): boolean {
92
+ return typeof this.callbacksByToken[token] != 'undefined'
93
+ }
94
+
95
+ /** @internal */
96
+ notify(...args: any[]) {
97
+ if (this.isClosed) {
98
+ // NOTE: we don't notify observers after closing and just swallow
99
+ // the event.
100
+ return
101
+ }
102
+
103
+ const processedArgs = this.process(...args)
104
+ for (const token in this.callbacksByToken) {
105
+ const callback = this.callbacksByToken[token]
106
+ if (callback) callback(...processedArgs)
107
+ }
108
+ }
109
+
110
+ /** @internal */
111
+ close() {
112
+ this.isClosed = true
113
+ for (const token in this.callbacksByToken) {
114
+ this.removeObserver(token)
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Can be injected and replaced via constructor options.
120
+ *
121
+ * @abstract
122
+ */
123
+ protected register(callback: (...args: any[]) => void) {
124
+ // No-op, subclasses may override and register.
125
+ }
126
+
127
+ /**
128
+ * Can be injected and replaced via constructor options.
129
+ *
130
+ * @abstract
131
+ */
132
+ protected unregister() {
133
+ // No-op, subclasses may override and unregister.
134
+ }
135
+
136
+ /**
137
+ * Can be injected and replaced via constructor options.
138
+ *
139
+ * @abstract
140
+ */
141
+ protected process(...args: any[]): any[] {
142
+ // No-op, subclasses may override and process/transform the callback parameters.
143
+ return args
144
+ }
145
+
146
+ private isClosed: boolean
147
+ private isRegistered: boolean
148
+ private callbacksByToken: { [key: string]: ((...args: any[]) => void) | null }
149
+ private constructorOptions: ObserverManagerConstructorOptions
150
+
151
+ private hasObservers(): boolean {
152
+ return Object.keys(this.callbacksByToken).length > 0
153
+ }
154
+
155
+ private registerIfNeeded() {
156
+ const needsToRegister = !this.isRegistered
157
+ if (needsToRegister) {
158
+ const weakThis = new WeakRef(this)
159
+ this.isRegistered = true
160
+ this.register(function (...args) {
161
+ const strongThis = weakThis.deref()
162
+ if (!strongThis) {
163
+ return
164
+ }
165
+
166
+ strongThis.notify(...args)
167
+ })
168
+ }
169
+ }
170
+
171
+ private unregisterIfNeeded() {
172
+ const needsToUnregister = !this.hasObservers() && this.isRegistered
173
+ if (needsToUnregister) {
174
+ this.isRegistered = false
175
+ this.unregister()
176
+ }
177
+ }
178
+ }
@@ -0,0 +1,79 @@
1
+ //
2
+ // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
+ //
4
+
5
+ import type { ObserverToken } from './observer-manager'
6
+
7
+ /** @internal */
8
+ interface ObserverManaging {
9
+ hasObserver(token: ObserverToken): boolean
10
+ removeObserver(token: ObserverToken): void
11
+ }
12
+
13
+ /** @internal */
14
+ export type ObserverOptions = {
15
+ stopsWhenFinalized?: boolean
16
+ }
17
+
18
+ /**
19
+ * Generic observer handle returned by various observation APIs. The observation
20
+ * remains active until the {@link stop | stop()} method is called explicitly or
21
+ * the observer instance is garbage collected. Therefore, to keep the observation
22
+ * alive, you have to keep a reference to the corresponding observer.
23
+ */
24
+ export class Observer {
25
+ // NOTE: the core functionality of the observer manager is token-based. We use
26
+ // the `Observer` class merely as a public API wrapper around the token
27
+ // exposing a convenience `stop()` method plus life-cycle tracking.
28
+
29
+ /** @internal */
30
+ readonly observerManager: ObserverManaging
31
+
32
+ /** @internal */
33
+ get token(): ObserverToken | undefined {
34
+ return this._token
35
+ }
36
+
37
+ /** @internal */
38
+ readonly options?: ObserverOptions
39
+
40
+ /** @internal */
41
+ constructor(observerManager: ObserverManaging, token: any, options: ObserverOptions = {}) {
42
+ this.observerManager = observerManager
43
+ this._token = token
44
+ this.options = options
45
+
46
+ if (options.stopsWhenFinalized) {
47
+ Observer.finalizationRegistry.register(this, { observerManager, token }, this)
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Returns `true` if the observer has been explicitly stopped via the `stop()`
53
+ * method. Otherwise returns `false`.
54
+ */
55
+ get isStopped(): boolean {
56
+ return this.token !== undefined && this.observerManager.hasObserver(this.token)
57
+ }
58
+
59
+ /**
60
+ * Stops the observation. Calling this method multiple times has no effect.
61
+ */
62
+ stop() {
63
+ const token = this.token
64
+ if (token) {
65
+ delete this._token
66
+ Observer.finalizationRegistry.unregister(this)
67
+ this.observerManager.removeObserver(token)
68
+ }
69
+ }
70
+
71
+ private static finalizationRegistry = new FinalizationRegistry(Observer.finalize)
72
+
73
+ private _token?: ObserverToken
74
+
75
+ private static finalize(observerManagerAndToken: { observerManager: ObserverManaging; token: ObserverToken }) {
76
+ const { observerManager, token } = observerManagerAndToken
77
+ observerManager.removeObserver(token)
78
+ }
79
+ }
@@ -0,0 +1,232 @@
1
+ //
2
+ // Copyright (c) 2020 - 2021 DittoLive Inc. All rights reserved.
3
+ //
4
+
5
+ import { Collection } from './collection'
6
+ import { Document } from './document'
7
+ import { Store } from './store'
8
+ import { Subscription } from './subscription'
9
+ import { PendingCursorOperation } from './pending-cursor-operation'
10
+
11
+ import { CollectionsEvent } from './collections-event'
12
+ import { LiveQuery } from './live-query'
13
+
14
+ import type { SortDirection } from './essentials'
15
+ // -----------------------------------------------------------------------------
16
+
17
+ /**
18
+ * The closure that is called whenever the collections covered by a live query
19
+ * change.
20
+ */
21
+ export type CollectionsObservationHandler = (event: CollectionsEvent, signalNext?: () => void) => void | Promise<void>
22
+
23
+ // -----------------------------------------------------------------------------
24
+
25
+ /**
26
+ * These objects are returned when calling
27
+ * {@link Store.collections | collections()} on {@link Store}.
28
+ *
29
+ * They allow chaining of further collections-related functions. You can either
30
+ * call {@link exec | exec()} on the object to get an array of
31
+ * {@link Collection}s as an immediate return value, or you can establish either
32
+ * a live query or a subscription, which both work over time.
33
+ *
34
+ * A live query, established by calling
35
+ * {@link PendingCollectionsOperation.observeLocal | observeLocal()}, will
36
+ * notify you every time there's a change in the collections that the device
37
+ * knows about.
38
+ *
39
+ * A subscription, established by calling {@link subscribe | subscribe()}, will
40
+ * act as a signal to other peers that the device connects to that you would
41
+ * like to receive updates from them about the collections that they know about.
42
+ */
43
+ export class PendingCollectionsOperation implements PromiseLike<Collection[]> {
44
+ /**
45
+ * Sort the collections based on a property of the collection.
46
+ *
47
+ * @param propertyPath The property path specifies the logic to be used when
48
+ * sorting the matching collections.
49
+ *
50
+ * @param direction Specify whether you want the sorting order to be
51
+ * `Ascending` or `Descending`.
52
+ *
53
+ * @return A {@link PendingCollectionsOperation} that you can chain further
54
+ * function calls to.
55
+ */
56
+ sort(propertyPath: string, direction: SortDirection = 'ascending'): PendingCollectionsOperation {
57
+ this.pendingCursorOperation.sort(propertyPath, direction)
58
+ return this
59
+ }
60
+
61
+ /**
62
+ * Offset the resulting set of collections.
63
+ *
64
+ * This is useful if you aren't interested in the first N collections for one
65
+ * reason or another. For example, you might already have obtained the first
66
+ * 20 collections and so you might want to get the next 20 collections, and
67
+ * that is when you would use {@link offset | offset()}.
68
+ *
69
+ * @param offset The number of collections that you want the eventual
70
+ * resulting set of collections to be offset by (and thus not include).
71
+ *
72
+ * @return A {@link PendingCollectionsOperation} that you can chain further
73
+ * function calls to.
74
+ */
75
+ offset(offset: number): PendingCollectionsOperation {
76
+ this.pendingCursorOperation.offset(offset)
77
+ return this
78
+ }
79
+
80
+ /**
81
+ * Limit the number of collections that get returned.
82
+ *
83
+ * @param limit The maximum number of collections that will be returned.
84
+ *
85
+ * @return A {@link PendingCollectionsOperation} that you can chain further
86
+ * function calls to.
87
+ */
88
+ limit(limit: number): PendingCollectionsOperation {
89
+ this.pendingCursorOperation.limit(limit)
90
+ return this
91
+ }
92
+
93
+ /**
94
+ * Subscribes the device to updates about collections that other devices know
95
+ * about.
96
+ *
97
+ * The returned {@link Subscription} object must be kept in scope for as long
98
+ * as you want to keep receiving updates.
99
+ *
100
+ * @return A {@link Subscription} object that must be kept in scope for as
101
+ * long as you want to keep receiving updates from other devices about the
102
+ * collections that they know about.
103
+ */
104
+ subscribe(): Subscription {
105
+ return this.pendingCursorOperation.subscribe()
106
+ }
107
+
108
+ /**
109
+ * Enables you to listen for changes that occur in relation to the collections
110
+ * that are known about locally.
111
+ *
112
+ * The returned {@link LiveQuery} object must be kept in scope for as long as
113
+ * you want the provided `handler` to be called when an update occurs.
114
+ *
115
+ * This won't subscribe to receive updates from other devices and so it will
116
+ * only fire when a local change to the known about collections occurs. If
117
+ * you want to receive remote updates as well, then create a subscription via
118
+ * {@link PendingCollectionsOperation.subscribe | subscribe()}.
119
+ *
120
+ * @param handler A closure that will be called every time there is an update
121
+ * about the list of known about collections.
122
+ *
123
+ * @return A {@link LiveQuery} object that must be kept in scope for as long
124
+ * as you want to keep receiving updates.
125
+ */
126
+ observeLocal(handler: CollectionsObservationHandler): LiveQuery {
127
+ return this._observe(handler, false)
128
+ }
129
+
130
+ /**
131
+ * Enables you to listen for changes that occur in relation to the collections
132
+ * that are known about locally.
133
+ *
134
+ * The returned {@link LiveQuery} object must be kept in scope for as long as
135
+ * you want the provided `handler` to be called when an update occurs.
136
+ *
137
+ * This won't subscribe to receive updates from other devices and so it will
138
+ * only fire when a local change to the known about collections occurs. If
139
+ * you want to receive remote updates as well, then create a subscription via
140
+ * {@link PendingCollectionsOperation.subscribe | subscribe()}.
141
+ *
142
+ * @param handler A closure that will be called every time there is an update
143
+ * about the list of known about collections.
144
+ *
145
+ * @return A {@link LiveQuery} object that must be kept in scope for as long
146
+ * as you want to keep receiving updates.
147
+ */
148
+ observeLocalWithNextSignal(handler: CollectionsObservationHandler): LiveQuery {
149
+ return this._observe(handler, true)
150
+ }
151
+
152
+ /**
153
+ * Return the list of collections requested based on the preceding function
154
+ * chaining.
155
+ *
156
+ * @return A list of {@link Collection}s based on the preceding function
157
+ * chaining.
158
+ */
159
+ async exec(): Promise<Collection[]> {
160
+ const documents = await this.pendingCursorOperation.exec()
161
+ return collectionsFromDocuments(documents, this.store)
162
+ }
163
+
164
+ /** @internal */
165
+ readonly store: Store
166
+
167
+ /** @internal */
168
+ constructor(store: Store) {
169
+ this.store = store
170
+ this.pendingCursorOperation = new PendingCursorOperation('true', null, new Collection('__collections', store))
171
+ }
172
+
173
+ /** @internal */
174
+ then<TResult1 = any, TResult2 = never>(onfulfilled?: ((value: any) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined): PromiseLike<TResult1 | TResult2> {
175
+ return this.exec().then(onfulfilled, onrejected)
176
+ }
177
+
178
+ // ----------------------------------------------------------- Internal ------
179
+
180
+ /** @internal */
181
+ _observe(handler: CollectionsObservationHandler, waitForNextSignal: boolean): LiveQuery {
182
+ const weakStore = new WeakRef(this.store)
183
+ const collectionsObservationHandler = function (documents, event, nextSignal) {
184
+ const strongStore = weakStore.deref()
185
+ if (!strongStore) {
186
+ return
187
+ }
188
+
189
+ const collections = collectionsFromDocuments(documents, strongStore)
190
+ let collEvent: CollectionsEvent
191
+
192
+ if (event.isInitial === true) {
193
+ collEvent = CollectionsEvent.initial(collections)
194
+ } else {
195
+ const oldCollections = collectionsFromDocuments(event.oldDocuments, strongStore)
196
+ collEvent = new CollectionsEvent({
197
+ isInitial: false,
198
+ collections,
199
+ oldCollections,
200
+ insertions: event.insertions,
201
+ deletions: event.deletions,
202
+ updates: event.updates,
203
+ moves: event.moves,
204
+ })
205
+ }
206
+
207
+ if (waitForNextSignal) {
208
+ handler(collEvent, nextSignal)
209
+ } else {
210
+ handler(collEvent)
211
+ }
212
+ }
213
+
214
+ return this.pendingCursorOperation._observe(collectionsObservationHandler, waitForNextSignal)
215
+ }
216
+
217
+ // ------------------------------------------------------------ Private ------
218
+
219
+ private readonly pendingCursorOperation: PendingCursorOperation
220
+ }
221
+
222
+ /** @private */
223
+ function collectionsFromDocuments(documents: Document[], store: Store): Collection[] {
224
+ const collections: Collection[] = []
225
+ for (const document of documents) {
226
+ const collectionName = document.at('name').value
227
+ if (collectionName !== undefined && typeof collectionName === 'string') {
228
+ collections.push(new Collection(collectionName, store))
229
+ }
230
+ }
231
+ return collections
232
+ }