@dittolive/ditto 4.7.3 → 4.7.4-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/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 +10 -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/CMakeLists.txt +0 -36
  17. package/react-native/android/build.gradle +0 -190
  18. package/react-native/android/cpp-adapter.cpp +0 -259
  19. package/react-native/android/gradle.properties +0 -5
  20. package/react-native/android/src/main/AndroidManifest.xml +0 -4
  21. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +0 -120
  22. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKPackage.java +0 -28
  23. package/react-native/cpp/include/Arc.hpp +0 -159
  24. package/react-native/cpp/include/Attachment.h +0 -20
  25. package/react-native/cpp/include/Authentication.h +0 -23
  26. package/react-native/cpp/include/Collection.h +0 -13
  27. package/react-native/cpp/include/ConnectionRequest.h +0 -18
  28. package/react-native/cpp/include/DQL.h +0 -21
  29. package/react-native/cpp/include/Document.h +0 -17
  30. package/react-native/cpp/include/FFIUtils.h +0 -16
  31. package/react-native/cpp/include/IO.h +0 -13
  32. package/react-native/cpp/include/Identity.h +0 -17
  33. package/react-native/cpp/include/Lifecycle.h +0 -16
  34. package/react-native/cpp/include/LiveQuery.h +0 -17
  35. package/react-native/cpp/include/Logger.h +0 -22
  36. package/react-native/cpp/include/Misc.h +0 -30
  37. package/react-native/cpp/include/Presence.h +0 -18
  38. package/react-native/cpp/include/SmallPeerInfo.h +0 -19
  39. package/react-native/cpp/include/Transports.h +0 -25
  40. package/react-native/cpp/include/TypedArray.hpp +0 -167
  41. package/react-native/cpp/include/Utils.h +0 -70
  42. package/react-native/cpp/include/main.h +0 -10
  43. package/react-native/cpp/src/Attachment.cpp +0 -272
  44. package/react-native/cpp/src/Authentication.cpp +0 -227
  45. package/react-native/cpp/src/Collection.cpp +0 -56
  46. package/react-native/cpp/src/ConnectionRequest.cpp +0 -123
  47. package/react-native/cpp/src/DQL.cpp +0 -256
  48. package/react-native/cpp/src/Document.cpp +0 -146
  49. package/react-native/cpp/src/FFIUtils.cpp +0 -122
  50. package/react-native/cpp/src/IO.cpp +0 -35
  51. package/react-native/cpp/src/Identity.cpp +0 -122
  52. package/react-native/cpp/src/Lifecycle.cpp +0 -93
  53. package/react-native/cpp/src/LiveQuery.cpp +0 -63
  54. package/react-native/cpp/src/Logger.cpp +0 -199
  55. package/react-native/cpp/src/Misc.cpp +0 -322
  56. package/react-native/cpp/src/Presence.cpp +0 -166
  57. package/react-native/cpp/src/SmallPeerInfo.cpp +0 -142
  58. package/react-native/cpp/src/Transports.cpp +0 -275
  59. package/react-native/cpp/src/TypedArray.cpp +0 -303
  60. package/react-native/cpp/src/Utils.cpp +0 -139
  61. package/react-native/cpp/src/main.cpp +0 -178
  62. package/react-native/dittoffi/dittoffi.h +0 -4873
  63. package/react-native/dittoffi/ifaddrs.cpp +0 -385
  64. package/react-native/dittoffi/ifaddrs.h +0 -206
  65. package/react-native/ios/DittoRNSDK.h +0 -7
  66. package/react-native/ios/DittoRNSDK.mm +0 -159
  67. package/react-native/ios/YeetJSIUtils.h +0 -60
  68. package/react-native/ios/YeetJSIUtils.mm +0 -196
  69. package/react-native/lib/commonjs/ditto.rn.js +0 -93
  70. package/react-native/lib/commonjs/ditto.rn.js.map +0 -1
  71. package/react-native/lib/commonjs/index.js +0 -61
  72. package/react-native/lib/commonjs/index.js.map +0 -1
  73. package/react-native/lib/module/ditto.rn.js +0 -89
  74. package/react-native/lib/module/ditto.rn.js.map +0 -1
  75. package/react-native/lib/module/index.js +0 -27
  76. package/react-native/lib/module/index.js.map +0 -1
  77. package/react-native/lib/typescript/ditto.rn.d.ts +0 -15
  78. package/react-native/lib/typescript/ditto.rn.d.ts.map +0 -1
  79. package/react-native/lib/typescript/index.d.ts +0 -1
  80. package/react-native/lib/typescript/index.d.ts.map +0 -1
  81. package/react-native/src/ditto.rn.ts +0 -123
  82. package/react-native/src/environment/environment.fallback.ts +0 -4
  83. package/react-native/src/index.ts +0 -29
  84. package/react-native/src/sources/@cbor-redux.ts +0 -2
  85. package/react-native/src/sources/@ditto.core.ts +0 -1
  86. package/react-native/src/sources/@environment.ts +0 -1
  87. package/react-native/src/sources/attachment-fetch-event.ts +0 -54
  88. package/react-native/src/sources/attachment-fetcher-manager.ts +0 -145
  89. package/react-native/src/sources/attachment-fetcher.ts +0 -265
  90. package/react-native/src/sources/attachment-token.ts +0 -129
  91. package/react-native/src/sources/attachment.ts +0 -121
  92. package/react-native/src/sources/augment.ts +0 -108
  93. package/react-native/src/sources/authenticator.ts +0 -314
  94. package/react-native/src/sources/base-pending-cursor-operation.ts +0 -255
  95. package/react-native/src/sources/base-pending-id-specific-operation.ts +0 -112
  96. package/react-native/src/sources/bridge.ts +0 -557
  97. package/react-native/src/sources/build-time-constants.ts +0 -8
  98. package/react-native/src/sources/cbor.ts +0 -20
  99. package/react-native/src/sources/collection-interface.ts +0 -73
  100. package/react-native/src/sources/collection.ts +0 -219
  101. package/react-native/src/sources/collections-event.ts +0 -99
  102. package/react-native/src/sources/connection-request.ts +0 -142
  103. package/react-native/src/sources/counter.ts +0 -82
  104. package/react-native/src/sources/ditto.ts +0 -991
  105. package/react-native/src/sources/document-id.ts +0 -163
  106. package/react-native/src/sources/document-path.ts +0 -308
  107. package/react-native/src/sources/document.ts +0 -237
  108. package/react-native/src/sources/epilogue.ts +0 -32
  109. package/react-native/src/sources/error-codes.ts +0 -114
  110. package/react-native/src/sources/error.ts +0 -256
  111. package/react-native/src/sources/essentials.ts +0 -81
  112. package/react-native/src/sources/ffi-error.ts +0 -134
  113. package/react-native/src/sources/ffi.ts +0 -2190
  114. package/react-native/src/sources/identity.ts +0 -163
  115. package/react-native/src/sources/init.ts +0 -71
  116. package/react-native/src/sources/internal.ts +0 -143
  117. package/react-native/src/sources/keep-alive.ts +0 -73
  118. package/react-native/src/sources/key-path.ts +0 -198
  119. package/react-native/src/sources/live-query-event.ts +0 -208
  120. package/react-native/src/sources/live-query-manager.ts +0 -110
  121. package/react-native/src/sources/live-query.ts +0 -167
  122. package/react-native/src/sources/logger.ts +0 -196
  123. package/react-native/src/sources/main.ts +0 -61
  124. package/react-native/src/sources/observer-manager.ts +0 -185
  125. package/react-native/src/sources/observer.ts +0 -79
  126. package/react-native/src/sources/pending-collections-operation.ts +0 -241
  127. package/react-native/src/sources/pending-cursor-operation.ts +0 -218
  128. package/react-native/src/sources/pending-id-specific-operation.ts +0 -218
  129. package/react-native/src/sources/presence-manager.ts +0 -170
  130. package/react-native/src/sources/presence.ts +0 -427
  131. package/react-native/src/sources/query-result-item.ts +0 -131
  132. package/react-native/src/sources/query-result.ts +0 -55
  133. package/react-native/src/sources/register.ts +0 -95
  134. package/react-native/src/sources/small-peer-info.ts +0 -166
  135. package/react-native/src/sources/static-tcp-client.ts +0 -8
  136. package/react-native/src/sources/store-observer.ts +0 -170
  137. package/react-native/src/sources/store.ts +0 -630
  138. package/react-native/src/sources/subscription-manager.ts +0 -99
  139. package/react-native/src/sources/subscription.ts +0 -89
  140. package/react-native/src/sources/sync-subscription.ts +0 -90
  141. package/react-native/src/sources/sync.ts +0 -561
  142. package/react-native/src/sources/test-helpers.ts +0 -24
  143. package/react-native/src/sources/transport-conditions-manager.ts +0 -104
  144. package/react-native/src/sources/transport-config.ts +0 -430
  145. package/react-native/src/sources/update-result.ts +0 -66
  146. package/react-native/src/sources/update-results-map.ts +0 -65
  147. package/react-native/src/sources/websocket-client.ts +0 -7
  148. package/react-native/src/sources/write-transaction-collection.ts +0 -122
  149. package/react-native/src/sources/write-transaction-pending-cursor-operation.ts +0 -101
  150. package/react-native/src/sources/write-transaction-pending-id-specific-operation.ts +0 -74
  151. package/react-native/src/sources/write-transaction.ts +0 -121
  152. package/react-native.config.js +0 -9
@@ -1,265 +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 { Attachment } from './attachment'
8
- import { AttachmentToken } from './attachment-token'
9
- import { DittoError, mapFFIErrorsAsync } from './error'
10
- import { generateEphemeralToken, step } from './internal'
11
- import { Logger } from './logger'
12
-
13
- import type { AttachmentFetchEvent } from './attachment-fetch-event'
14
- import type { Ditto } from './ditto'
15
- import type { AttachmentFetcherManager } from './attachment-fetcher-manager'
16
- import type { Store } from './store'
17
- import type { Collection } from './collection'
18
-
19
- /**
20
- * These objects are returned by calls to
21
- * {@link Store.fetchAttachment | ditto.store.fetchAttachment()}
22
- * and allow you to stop an in-flight attachment fetch.
23
- */
24
- export class AttachmentFetcher implements PromiseLike<Attachment | null> {
25
- /**
26
- * Returns a promise for the attachment that you can `await`.
27
- *
28
- * The promise is rejected if an error occurs during the fetch. Note that the
29
- * `AttachmentFetcher` itself implements `PromiseLike`, so you can `await` it
30
- * directly.
31
- *
32
- * If this attachment fetcher has been initiated through {@link
33
- * Collection.fetchAttachment | `Collection.fetchAttachment()`}, the promise
34
- * resolves to `null` if the attachment could not be found instead of being
35
- * rejected.
36
- */
37
- readonly attachment: Promise<Attachment | null>
38
-
39
- /**
40
- * Stops fetching the associated attachment and cleans up any associated
41
- * resources.
42
- *
43
- * Note that you are not required to call `stop()` once your attachment fetch
44
- * operation has finished. The method primarily exists to allow you to cancel
45
- * an attachment fetch request while it is ongoing if you no longer wish for
46
- * the attachment to be made available locally to the device.
47
- */
48
- stop() {
49
- // No need for synchronicity here: we let the "stop promise" float / run in
50
- // a detached fashion since there is no point in awaiting the "stop
51
- // signaling" itself.
52
-
53
- if (this.manager == null) {
54
- // Case where the fetcher was started from `Store.fetchAttachment()`.
55
- if (!this.isStopped) {
56
- this.rejectPendingFetch()
57
- this.rejectPendingFetch = null
58
- }
59
-
60
- this.ditto.store.removeAttachmentFetcher(this)
61
-
62
- const dittoHandle = Bridge.ditto.handleFor(this.ditto)
63
- void this.ditto.deferCloseAsync(async () => {
64
- // Cancel the fetcher if it is still running.
65
- const cancelToken = await this.cancelTokenPromise
66
- if (cancelToken) {
67
- FFI.dittoCancelResolveAttachment(dittoHandle.deref(), this.token.idBytes, cancelToken)
68
- }
69
- })
70
- } else {
71
- // Legacy case where the fetcher was started from `Collection.fetchAttachment()`.
72
-
73
- void step(async () => {
74
- await this.manager.stopAttachmentFetcher(this)
75
- if (this.rejectPendingFetch != null) {
76
- this.rejectPendingFetch()
77
- this.rejectPendingFetch = null
78
- }
79
- })
80
- }
81
- }
82
-
83
- // --------------------------------------- Internal ------------------------
84
-
85
- /** @internal */
86
- readonly cancelTokenPromise: Promise<number | BigInt | null> | null = null
87
-
88
- /** @internal */
89
- readonly ditto: Ditto
90
-
91
- /** @internal */
92
- readonly id: string
93
-
94
- /**
95
- * Defined when the fetcher was started from `Collection.fetchAttachment()`.
96
- * Otherwise, the fetcher was started from `Store.fetchAttachment()`.
97
- *
98
- * @internal
99
- */
100
- readonly manager?: AttachmentFetcherManager
101
-
102
- /** @internal */
103
- readonly token: AttachmentToken
104
-
105
- /** @internal */
106
- then<TResult1 = any, TResult2 = never>(onfulfilled?: ((value: any) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined): PromiseLike<TResult1 | TResult2> {
107
- return this.attachment.then(onfulfilled, onrejected)
108
- }
109
-
110
- /** @internal */
111
- constructor(ditto: Ditto, token: AttachmentToken, manager?: AttachmentFetcherManager, eventHandler?: (attachmentFetchEvent: AttachmentFetchEvent) => void) {
112
- this.ditto = ditto
113
- this.token = token
114
- this.manager = manager
115
- this.id = generateEphemeralToken()
116
-
117
- const eventHandlerOrNoOp = eventHandler || function () {}
118
- const dittoHandle = Bridge.ditto.handleFor(ditto)
119
-
120
- this.attachment = new Promise((resolve, reject) => {
121
- // REFACTOR: The callbacks hold quite a bunch of objects with most
122
- // probably lead to retain cycles and therefore memory leaks. This needs
123
- // to be
124
- // fixed.
125
- const onComplete = (attachmentHandlePointer: FFI.Pointer<FFI.AttachmentHandle>) => {
126
- const attachment = new Attachment(this.ditto, this.token)
127
- Bridge.attachment.bridge(attachmentHandlePointer, () => attachment)
128
-
129
- eventHandlerOrNoOp({ type: 'Completed', attachment })
130
-
131
- this.rejectPendingFetch = null
132
- resolve(attachment)
133
- }
134
-
135
- const onProgress = (downloaded: number | BigInt, toDownload: number | BigInt) => {
136
- eventHandlerOrNoOp({ type: 'Progress', totalBytes: toDownload, downloadedBytes: downloaded })
137
- }
138
-
139
- const onDelete = () => {
140
- eventHandlerOrNoOp({ type: 'Deleted' })
141
-
142
- if (this.manager != null) {
143
- // Legacy behavior: when the attachment is deleted while being fetched
144
- // the fetcher is stopped and the promise is resolved to `null`.
145
- this.rejectPendingFetch = null
146
- resolve(null)
147
- } else {
148
- this.rejectPendingFetch = null
149
- reject(new DittoError('store/attachment-not-found', 'The attachment was deleted while being fetched.'))
150
- }
151
- }
152
-
153
- const onError = () => {
154
- ;(err: any) => {
155
- this.rejectPendingFetch = null
156
- reject(err)
157
- }
158
- }
159
-
160
- // The core doesn't call any of the handlers defined above when a fetch is
161
- // cancelled through `this.stop()` so we use this function to reject the
162
- // promise from the outside.
163
- this.rejectPendingFetch = () => {
164
- const err = this.manager != null ? new Error('Attachment fetch was canceled') : new DittoError('store/failed-to-fetch-attachment', 'Attachment fetch was canceled')
165
- reject(err)
166
- }
167
-
168
- // `cancelTokenPromise` resolves once the fetcher has been initialised in
169
- // core. This constructor is sync and thus can't await the promise. That
170
- // only happens when the cancel token is used, either in `stop()` (for
171
- // fetchers started from `Store.fetchAttachment()`) or in
172
- // `AttachmentFetcherManager.stopWithContextInfo()` (for fetchers started
173
- // from `Collection.fetchAttachment()`).
174
- //
175
- // In addition, we want to be able to intercept errors that occur after
176
- // this constructor has returned. For that, the whole creation of the
177
- // cancel token is wrapped in an inline async function that catches any
178
- // errors and then doesn't reject the cancel token promise, but the
179
- // `attachment` promise and through that the `AttachmentFetcher` itself.
180
- const weakThis = new WeakRef(this)
181
-
182
- // @ts-expect-error setting readonly property
183
- this.cancelTokenPromise = (async () => {
184
- try {
185
- return await mapFFIErrorsAsync(async () => FFI.dittoResolveAttachment(dittoHandle.deref(), token.idBytes, { onComplete, onProgress, onDelete }, onError), {
186
- 1: ['store/failed-to-fetch-attachment', 'Failed to fetch the attachment.'],
187
- 2: ['store/attachment-token-invalid', 'The attachment token was invalid.'],
188
- 3: ['store/attachment-not-found', 'The attachment was not found.'],
189
- })
190
- } catch (e) {
191
- let isDeleted = false
192
-
193
- // Legacy behavior: when the attachment is deleted before the fetch is
194
- // started, the fetcher is stopped and the promise is resolved to
195
- // `null`.
196
- if (e instanceof DittoError && e.code === 'store/attachment-not-found') {
197
- isDeleted = true
198
- eventHandlerOrNoOp({ type: 'Deleted' })
199
- }
200
-
201
- Logger.error(e.message)
202
-
203
- const strongThis = weakThis.deref()
204
- if (strongThis == null) {
205
- // The fetcher was already gc'd, so it's not possible to reject the
206
- // `attachment` promise anymore. We stop here as the error has been
207
- // logged.
208
- return null
209
- }
210
-
211
- // When this is called from legacy `Collection.fetchAttachment()`, we
212
- // convert the DittoError to a regular Error.
213
- if (strongThis.manager != null && e instanceof DittoError) {
214
- e = new Error(e.message)
215
- }
216
-
217
- strongThis.rejectPendingFetch = null
218
-
219
- // Reject the `attachment` promise to signal that the fetch has
220
- // failed, unless this is a legacy fetcher and the attachment was
221
- // deleted.
222
- if (strongThis.manager != null && isDeleted) {
223
- resolve(null)
224
- } else {
225
- reject(e)
226
- }
227
-
228
- // Set cancelTokenPromise to null to indicate that there is nothing to
229
- // cancel anymore.
230
- return null
231
- }
232
- })()
233
- })
234
-
235
- if (manager == null) {
236
- // Remove the attachment fetcher once it is done.
237
- this.attachment
238
- .then(() => {
239
- this.rejectPendingFetch = null
240
- this.ditto.store.removeAttachmentFetcher(this)
241
- })
242
- .catch(() => {
243
- this.rejectPendingFetch = null
244
- this.ditto.store.removeAttachmentFetcher(this)
245
- })
246
- }
247
- }
248
-
249
- /**
250
- * `true` if the fetcher has completed or was stopped.
251
- *
252
- * @internal
253
- */
254
- get isStopped(): boolean {
255
- return this.rejectPendingFetch == null
256
- }
257
-
258
- /**
259
- * This function is defined while a fetch is in progress and is used to reject
260
- * the promise `this.attachment` when the fetch is canceled.
261
- *
262
- * @internal
263
- */
264
- private rejectPendingFetch: (() => void) | null = null
265
- }
@@ -1,129 +0,0 @@
1
- //
2
- // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
- //
4
-
5
- import * as FFI from './ffi'
6
- import { mapFFIErrors } from './error'
7
-
8
- import type { AttachmentMetadata } from './attachment'
9
- import type { Store } from './store'
10
-
11
- /** @internal */
12
- export type UntypedAttachmentToken = { id: string; len: number | BigInt; metadata: AttachmentMetadata }
13
-
14
- /** @internal */
15
- export type TypedAttachmentToken = { [FFI.DittoCRDTTypeKey]?: FFI.DittoCRDTType.attachment; _id: Uint8Array; _len: number | BigInt; _meta: AttachmentMetadata }
16
-
17
- /**
18
- * Serves as a token for a specific attachment that you can pass to a call to
19
- * {@link Store.fetchAttachment | ditto.store.fetchAttachment()}.
20
- */
21
- export class AttachmentToken {
22
- /** The attachment's ID. */
23
- // This ID is a _non-padded_ base64-encoded version of `idBytes`.
24
- readonly id: string
25
-
26
- /** The attachment's size given as number of bytes. */
27
- readonly len: number | BigInt
28
-
29
- /** The attachment's metadata. */
30
- readonly metadata: AttachmentMetadata
31
-
32
- // -------------------------------------------------------------------------
33
-
34
- /** @internal */
35
- constructor(jsObj: UntypedAttachmentToken | TypedAttachmentToken) {
36
- // There are two representations of attachment tokens:
37
- // 1. The legacy typed representation is an internal format that is used by
38
- // the query builder API. It can be identified by the presence of the
39
- // [FFI.DittoCRDTTypeKey] field.
40
- // 2. The untyped representation is used in our public API and was first
41
- // introduced in the HTTP API. It is now used by the DQL API as well. It
42
- // uses a non-padded base64-encoded ID.
43
- let id: Uint8Array, len: number | BigInt, meta: AttachmentMetadata
44
- if (jsObj[FFI.DittoCRDTTypeKey] != null) {
45
- ;({ id, len, meta } = AttachmentToken.validateTypedInput(jsObj as TypedAttachmentToken))
46
- } else {
47
- ;({ id, len, meta } = AttachmentToken.validateUntypedInput(jsObj as UntypedAttachmentToken))
48
- }
49
-
50
- // base64-encode string and remove padding
51
- this.id = mapFFIErrors(() => FFI.base64encode(id, 'Unpadded'))
52
- this.idBytes = id
53
- this.len = len
54
- this.metadata = meta
55
- }
56
-
57
- /** @internal */
58
- readonly idBytes: Uint8Array
59
-
60
- /**
61
- * Validate an input value that has a field `[FFI.DittoCRDTTypeKey]` and
62
- * return its contents.
63
- *
64
- * @throws {Error} If the input is invalid.
65
- * @returns {object} binary id, len and metadata of the attachment token
66
- */
67
- private static validateTypedInput(jsObj: TypedAttachmentToken): { id: Uint8Array; len: number | BigInt; meta: AttachmentMetadata } {
68
- const type = jsObj[FFI.DittoCRDTTypeKey]
69
- if (type !== FFI.DittoCRDTType.attachment) {
70
- throw new Error('Invalid attachment token')
71
- }
72
-
73
- const id = jsObj['_id']
74
- if (!(id instanceof Uint8Array)) {
75
- throw new Error('Invalid attachment token id')
76
- }
77
-
78
- const len = jsObj['_len']
79
- if ((typeof len !== 'number' && typeof len !== 'bigint') || len < 0) {
80
- throw new Error('Invalid attachment token length, must be a non-negative number or bigint')
81
- }
82
-
83
- const meta = jsObj['_meta']
84
- if (typeof meta !== 'object') {
85
- throw new Error('Invalid attachment token meta')
86
- }
87
-
88
- return { id, len, meta }
89
- }
90
-
91
- /**
92
- * Validate an untyped input value and return its contents.
93
- *
94
- * Converts _unpadded_ base64-encoded ID in input to _padded_ base64-encoded
95
- * ID before returning it as `Uint8Array`.
96
- *
97
- * @throws {@link DittoError} `store/attachment-token-invalid` If the input id
98
- * is not a valid base64 string.
99
- * @returns {object} binary id, len and metadata of the attachment token
100
- */
101
- private static validateUntypedInput(jsObj: UntypedAttachmentToken): { id: Uint8Array; len: number | BigInt; meta: AttachmentMetadata } {
102
- const idBase64 = jsObj['id']
103
- if (typeof idBase64 !== 'string') {
104
- throw new Error('Invalid attachment token id')
105
- }
106
-
107
- const id = mapFFIErrors(
108
- () => FFI.tryBase64Decode(idBase64, 'Unpadded'),
109
- {
110
- Base64Invalid: ['store/attachment-token-invalid', 'Failed to decode attachment token id from base64 input'],
111
- },
112
- {
113
- attachmentTokenID: idBase64,
114
- },
115
- )
116
-
117
- const len = jsObj['len']
118
- if ((typeof len !== 'number' && typeof len !== 'bigint') || len < 0) {
119
- throw new Error('Invalid attachment token length, must be a non-negative number or bigint')
120
- }
121
-
122
- const meta = jsObj['metadata']
123
- if (typeof meta !== 'object') {
124
- throw new Error('Invalid attachment token meta')
125
- }
126
-
127
- return { id, len, meta }
128
- }
129
- }
@@ -1,121 +0,0 @@
1
- //
2
- // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
- //
4
-
5
- import * as FFI from './ffi'
6
- import * as Environment from './@environment'
7
- import { Bridge } from './bridge'
8
- import { DittoError } from './error'
9
-
10
- import type { Ditto } from './ditto'
11
- import type { AttachmentToken } from './attachment-token'
12
-
13
- /**
14
- * A key-value map of user-defined metadata for an attachment.
15
- */
16
- export type AttachmentMetadata = { [key: string]: string }
17
-
18
- /**
19
- * Represents an attachment and can be used to insert the associated attachment
20
- * into a document at a specific key-path. You can't instantiate an attachment
21
- * directly, please use the
22
- * {@link Store.newAttachment | ditto.store.newAttachment()} method instead.
23
- */
24
- export class Attachment {
25
- /** @internal */
26
- readonly ditto: Ditto
27
-
28
- /** @internal */
29
- readonly token: AttachmentToken
30
-
31
- /** The attachment's ID. */
32
- get id(): string {
33
- return this.token.id
34
- }
35
-
36
- /** The attachment's size given as number of bytes. */
37
- get len(): number | BigInt {
38
- return this.token.len
39
- }
40
-
41
- /** The attachment's metadata. */
42
- get metadata(): { [key: string]: string } {
43
- return this.token.metadata
44
- }
45
-
46
- /**
47
- * Returns the attachment's data.
48
- */
49
- data(): Promise<Uint8Array> {
50
- const ditto = this.ditto
51
- const dittoHandle = Bridge.ditto.handleFor(ditto)
52
- return this.ditto.deferCloseAsync(async () => {
53
-
54
-
55
- if (Environment.isReactNativeBuild) {
56
- const attachmentHandle = Bridge.attachment.handleFor(this)
57
- const attachmentPath = FFI.dittoGetCompleteAttachmentPath(dittoHandle.deref(), attachmentHandle.deref())
58
- return await FFI.readFile(attachmentPath)
59
- }
60
- })
61
- }
62
-
63
- /**
64
- * Returns the attachment's data.
65
- *
66
- * @deprecated Use `data()` instead.
67
- */
68
- getData(): Promise<Uint8Array> {
69
- return this.data()
70
- }
71
-
72
- /**
73
- * Copies the attachment to the specified file path. Node-only,
74
- * throws in the browser.
75
- *
76
- * @param path The path that the attachment should be copied to.
77
- */
78
- copyToPath(path: string): Promise<void> {
79
- const ditto = this.ditto
80
- const dittoHandle = Bridge.ditto.handleFor(ditto)
81
- return this.ditto.deferCloseAsync(async () => {
82
-
83
- if (Environment.isReactNativeBuild) {
84
- const attachmentHandle = Bridge.attachment.handleFor(this)
85
- const attachmentPath = FFI.dittoGetCompleteAttachmentPath(dittoHandle.deref(), attachmentHandle.deref())
86
- // If the file already exists, we fail. This is the same behavior as
87
- // for the Swift/ObjC SDK.
88
- return await FFI.copyFile(attachmentPath, path, ditto.persistenceDirectory)
89
- }
90
- })
91
- }
92
-
93
- /** @internal */
94
- constructor(ditto: Ditto, token: AttachmentToken) {
95
- this.ditto = ditto
96
- this.token = token
97
- }
98
- }
99
-
100
- /**
101
- * Validates the given attachment metadata. Metadata must be a flat object with
102
- * string values.
103
- *
104
- * This should really happen in core to make sure we use the same validation
105
- * logic across SDKs but we decided to postpone that for the next iteration on
106
- * attachments.
107
- *
108
- * @throws {@link DittoError} 'store/failed-to-create-attachment'
109
- * @internal
110
- */
111
- export function validateAttachmentMetadata(metadata: AttachmentMetadata): void {
112
- if (typeof metadata !== 'object') {
113
- throw new DittoError('store/failed-to-create-attachment', `Invalid attachment metadata: expected a value of type object but got ${typeof metadata}.`)
114
- }
115
-
116
- for (const key in metadata) {
117
- if (typeof metadata[key] !== 'string') {
118
- throw new DittoError('store/failed-to-create-attachment', `Invalid attachment metadata: metadata values must be strings but key '${key}' has a value of type ${typeof metadata[key]}.`)
119
- }
120
- }
121
- }
@@ -1,108 +0,0 @@
1
- //
2
- // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
- //
4
-
5
- // NOTE: proxy was originally written in pure JS rather than TypeScript. We'll
6
- // gradually port it to TypeScript and until done, we've renamed the pure JS
7
- // file to proxy.raw.js and introduced proxy.ts that'll contain all parts ported
8
- // to TypeScript or type declarations for the JS parts.
9
-
10
- // import * as proxyRaw from './proxy.raw'
11
-
12
- import * as FFI from './ffi'
13
- import { DocumentID } from './document-id'
14
- import { AttachmentToken } from './attachment-token'
15
- import { Attachment } from './attachment'
16
- import { Counter } from './counter'
17
- import { Register } from './register'
18
-
19
- // Takes an annotated JSON representation of a document (see CRDT's Document
20
- // class for more info about what an annotated representation is) and turns it
21
- // into a JavaScript-appropriate version. This means that counters get
22
- // represented by `Counter` objects and attachments get represented by
23
- // `Attachment` objects.
24
- export function augmentJSONValue(json, mutDoc, workingPath) {
25
- if (json && typeof json === 'object') {
26
- if (Array.isArray(json)) {
27
- return json.map((v, idx) => augmentJSONValue(v, mutDoc, `${workingPath}[${idx}]`))
28
- } else if (json[FFI.DittoCRDTTypeKey] === FFI.DittoCRDTType.counter) {
29
- return Counter['@ditto.create'](mutDoc, workingPath, json[FFI.DittoCRDTValueKey])
30
- } else if (json[FFI.DittoCRDTTypeKey] === FFI.DittoCRDTType.register) {
31
- return Register['@ditto.create'](mutDoc, workingPath, json[FFI.DittoCRDTValueKey])
32
- } else if (json[FFI.DittoCRDTTypeKey] === FFI.DittoCRDTType.attachment) {
33
- return new AttachmentToken(json)
34
- } else {
35
- for (const [key, value] of Object.entries(json)) {
36
- json[key] = augmentJSONValue(value, mutDoc, `${workingPath}['${key}']`)
37
- }
38
- return json
39
- }
40
- } else {
41
- return json
42
- }
43
- }
44
-
45
- /**
46
- * Converts objects that may contain instances of classes of this SDK, i.e.
47
- * `DocumentID`, `Counter`, `Register` and `Attachment`, into plain JS objects
48
- * that can be passed to the FFI layer.
49
- *
50
- * WARNING: For attachments in the input, the output can contain `BigInt`
51
- * values, which are not JSON-compatible.
52
- *
53
- * @throws {Error} If `jsObj` contains a non-finite float value.
54
- */
55
- export function desugarJSObject(jsObj: any): any {
56
- if (jsObj && typeof jsObj === 'object') {
57
- if (Array.isArray(jsObj)) {
58
- return jsObj.map((v, idx) => desugarJSObject(v))
59
- } else if (jsObj instanceof DocumentID) {
60
- return jsObj.value
61
- } else if (jsObj instanceof Counter) {
62
- const counterJSON = {}
63
- counterJSON[FFI.DittoCRDTTypeKey] = FFI.DittoCRDTType.counter
64
- counterJSON[FFI.DittoCRDTValueKey] = jsObj.value
65
- return counterJSON
66
- } else if (jsObj instanceof Register) {
67
- const registerJSON = {}
68
- registerJSON[FFI.DittoCRDTTypeKey] = FFI.DittoCRDTType.register
69
- registerJSON[FFI.DittoCRDTValueKey] = jsObj.value
70
- return registerJSON
71
- } else if (jsObj instanceof Attachment) {
72
- const attachmentJSON = {
73
- _id: jsObj.token.idBytes,
74
- _len: jsObj.token.len, // may be a BigInt
75
- _meta: jsObj.token.metadata,
76
- }
77
- attachmentJSON[FFI.DittoCRDTTypeKey] = FFI.DittoCRDTType.attachment
78
- return attachmentJSON
79
- } else {
80
- // Create a copy to not mutate the original object
81
- const jsObjJSON = {}
82
- for (const [key, value] of Object.entries(jsObj)) {
83
- jsObjJSON[key] = desugarJSObject(value)
84
- }
85
- return jsObjJSON
86
- }
87
- } else {
88
- checkForUnsupportedValues(jsObj)
89
- return jsObj
90
- }
91
- }
92
-
93
- /**
94
- * Throws an error if input is a non-finite float value.
95
- *
96
- * Workaround while we don't have a reliable way of receiving error messages
97
- * from `dittoCore.ditto_collection_insert_value()`.
98
- *
99
- * See https://github.com/getditto/ditto/issues/8657 for details.
100
- *
101
- * @param jsObj The object to check.
102
- * @throws {Error} If `jsObj` is a non-finite float value.
103
- */
104
- function checkForUnsupportedValues(jsObj: any): void {
105
- if (Number.isNaN(jsObj) || jsObj === Infinity || jsObj === -Infinity) {
106
- throw new Error('Non-finite float values are not supported')
107
- }
108
- }