@dittolive/ditto 4.7.4 → 4.7.5-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/README.md +2 -2
  2. package/node/ditto.cjs.js +1 -1
  3. package/node/ditto.darwin-arm64.node +0 -0
  4. package/node/ditto.darwin-x64.node +0 -0
  5. package/node/ditto.linux-arm.node +0 -0
  6. package/node/ditto.linux-arm64.node +0 -0
  7. package/node/ditto.linux-x64.node +0 -0
  8. package/node/ditto.win32-x64.node +0 -0
  9. package/node/transports.darwin-arm64.node +0 -0
  10. package/node/transports.darwin-x64.node +0 -0
  11. package/package.json +2 -5
  12. package/web/ditto.es6.js +1 -1
  13. package/web/ditto.umd.js +1 -1
  14. package/web/ditto.wasm +0 -0
  15. package/DittoReactNative.podspec +0 -27
  16. package/react-native/android/.gradle/8.9/checksums/checksums.lock +0 -0
  17. package/react-native/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  18. package/react-native/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  19. package/react-native/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  20. package/react-native/android/.gradle/8.9/gc.properties +0 -0
  21. package/react-native/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  22. package/react-native/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  23. package/react-native/android/.gradle/vcs-1/gc.properties +0 -0
  24. package/react-native/android/CMakeLists.txt +0 -36
  25. package/react-native/android/build.gradle +0 -190
  26. package/react-native/android/cpp-adapter.cpp +0 -259
  27. package/react-native/android/gradle.properties +0 -5
  28. package/react-native/android/src/main/AndroidManifest.xml +0 -4
  29. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +0 -120
  30. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKPackage.java +0 -28
  31. package/react-native/cpp/include/Arc.hpp +0 -159
  32. package/react-native/cpp/include/Attachment.h +0 -20
  33. package/react-native/cpp/include/Authentication.h +0 -23
  34. package/react-native/cpp/include/Collection.h +0 -13
  35. package/react-native/cpp/include/ConnectionRequest.h +0 -18
  36. package/react-native/cpp/include/DQL.h +0 -21
  37. package/react-native/cpp/include/Document.h +0 -17
  38. package/react-native/cpp/include/FFIUtils.h +0 -16
  39. package/react-native/cpp/include/IO.h +0 -13
  40. package/react-native/cpp/include/Identity.h +0 -17
  41. package/react-native/cpp/include/Lifecycle.h +0 -16
  42. package/react-native/cpp/include/LiveQuery.h +0 -17
  43. package/react-native/cpp/include/Logger.h +0 -22
  44. package/react-native/cpp/include/Misc.h +0 -30
  45. package/react-native/cpp/include/Presence.h +0 -18
  46. package/react-native/cpp/include/SmallPeerInfo.h +0 -19
  47. package/react-native/cpp/include/Transports.h +0 -25
  48. package/react-native/cpp/include/TypedArray.hpp +0 -167
  49. package/react-native/cpp/include/Utils.h +0 -70
  50. package/react-native/cpp/include/main.h +0 -10
  51. package/react-native/cpp/src/Attachment.cpp +0 -272
  52. package/react-native/cpp/src/Authentication.cpp +0 -227
  53. package/react-native/cpp/src/Collection.cpp +0 -56
  54. package/react-native/cpp/src/ConnectionRequest.cpp +0 -123
  55. package/react-native/cpp/src/DQL.cpp +0 -256
  56. package/react-native/cpp/src/Document.cpp +0 -146
  57. package/react-native/cpp/src/FFIUtils.cpp +0 -122
  58. package/react-native/cpp/src/IO.cpp +0 -35
  59. package/react-native/cpp/src/Identity.cpp +0 -122
  60. package/react-native/cpp/src/Lifecycle.cpp +0 -93
  61. package/react-native/cpp/src/LiveQuery.cpp +0 -63
  62. package/react-native/cpp/src/Logger.cpp +0 -199
  63. package/react-native/cpp/src/Misc.cpp +0 -322
  64. package/react-native/cpp/src/Presence.cpp +0 -166
  65. package/react-native/cpp/src/SmallPeerInfo.cpp +0 -142
  66. package/react-native/cpp/src/Transports.cpp +0 -275
  67. package/react-native/cpp/src/TypedArray.cpp +0 -303
  68. package/react-native/cpp/src/Utils.cpp +0 -139
  69. package/react-native/cpp/src/main.cpp +0 -178
  70. package/react-native/dittoffi/dittoffi.h +0 -4873
  71. package/react-native/dittoffi/ifaddrs.cpp +0 -385
  72. package/react-native/dittoffi/ifaddrs.h +0 -206
  73. package/react-native/ios/DittoRNSDK.h +0 -7
  74. package/react-native/ios/DittoRNSDK.mm +0 -159
  75. package/react-native/ios/YeetJSIUtils.h +0 -60
  76. package/react-native/ios/YeetJSIUtils.mm +0 -196
  77. package/react-native/lib/commonjs/ditto.rn.js +0 -93
  78. package/react-native/lib/commonjs/ditto.rn.js.map +0 -1
  79. package/react-native/lib/commonjs/index.js +0 -61
  80. package/react-native/lib/commonjs/index.js.map +0 -1
  81. package/react-native/lib/module/ditto.rn.js +0 -89
  82. package/react-native/lib/module/ditto.rn.js.map +0 -1
  83. package/react-native/lib/module/index.js +0 -27
  84. package/react-native/lib/module/index.js.map +0 -1
  85. package/react-native/lib/typescript/ditto.rn.d.ts +0 -15
  86. package/react-native/lib/typescript/ditto.rn.d.ts.map +0 -1
  87. package/react-native/lib/typescript/index.d.ts +0 -1
  88. package/react-native/lib/typescript/index.d.ts.map +0 -1
  89. package/react-native/src/ditto.rn.ts +0 -123
  90. package/react-native/src/environment/environment.fallback.ts +0 -4
  91. package/react-native/src/index.ts +0 -29
  92. package/react-native/src/sources/@cbor-redux.ts +0 -2
  93. package/react-native/src/sources/@ditto.core.ts +0 -1
  94. package/react-native/src/sources/@environment.ts +0 -1
  95. package/react-native/src/sources/attachment-fetch-event.ts +0 -54
  96. package/react-native/src/sources/attachment-fetcher-manager.ts +0 -145
  97. package/react-native/src/sources/attachment-fetcher.ts +0 -265
  98. package/react-native/src/sources/attachment-token.ts +0 -129
  99. package/react-native/src/sources/attachment.ts +0 -121
  100. package/react-native/src/sources/augment.ts +0 -108
  101. package/react-native/src/sources/authenticator.ts +0 -314
  102. package/react-native/src/sources/base-pending-cursor-operation.ts +0 -255
  103. package/react-native/src/sources/base-pending-id-specific-operation.ts +0 -112
  104. package/react-native/src/sources/bridge.ts +0 -557
  105. package/react-native/src/sources/build-time-constants.ts +0 -8
  106. package/react-native/src/sources/cbor.ts +0 -20
  107. package/react-native/src/sources/collection-interface.ts +0 -73
  108. package/react-native/src/sources/collection.ts +0 -219
  109. package/react-native/src/sources/collections-event.ts +0 -99
  110. package/react-native/src/sources/connection-request.ts +0 -142
  111. package/react-native/src/sources/counter.ts +0 -82
  112. package/react-native/src/sources/ditto.ts +0 -991
  113. package/react-native/src/sources/document-id.ts +0 -163
  114. package/react-native/src/sources/document-path.ts +0 -308
  115. package/react-native/src/sources/document.ts +0 -237
  116. package/react-native/src/sources/epilogue.ts +0 -32
  117. package/react-native/src/sources/error-codes.ts +0 -114
  118. package/react-native/src/sources/error.ts +0 -256
  119. package/react-native/src/sources/essentials.ts +0 -81
  120. package/react-native/src/sources/ffi-error.ts +0 -134
  121. package/react-native/src/sources/ffi.ts +0 -2190
  122. package/react-native/src/sources/identity.ts +0 -163
  123. package/react-native/src/sources/init.ts +0 -71
  124. package/react-native/src/sources/internal.ts +0 -143
  125. package/react-native/src/sources/keep-alive.ts +0 -73
  126. package/react-native/src/sources/key-path.ts +0 -198
  127. package/react-native/src/sources/live-query-event.ts +0 -208
  128. package/react-native/src/sources/live-query-manager.ts +0 -110
  129. package/react-native/src/sources/live-query.ts +0 -167
  130. package/react-native/src/sources/logger.ts +0 -196
  131. package/react-native/src/sources/main.ts +0 -61
  132. package/react-native/src/sources/observer-manager.ts +0 -185
  133. package/react-native/src/sources/observer.ts +0 -79
  134. package/react-native/src/sources/pending-collections-operation.ts +0 -241
  135. package/react-native/src/sources/pending-cursor-operation.ts +0 -218
  136. package/react-native/src/sources/pending-id-specific-operation.ts +0 -218
  137. package/react-native/src/sources/presence-manager.ts +0 -170
  138. package/react-native/src/sources/presence.ts +0 -427
  139. package/react-native/src/sources/query-result-item.ts +0 -131
  140. package/react-native/src/sources/query-result.ts +0 -55
  141. package/react-native/src/sources/register.ts +0 -95
  142. package/react-native/src/sources/small-peer-info.ts +0 -166
  143. package/react-native/src/sources/static-tcp-client.ts +0 -8
  144. package/react-native/src/sources/store-observer.ts +0 -170
  145. package/react-native/src/sources/store.ts +0 -630
  146. package/react-native/src/sources/subscription-manager.ts +0 -99
  147. package/react-native/src/sources/subscription.ts +0 -89
  148. package/react-native/src/sources/sync-subscription.ts +0 -90
  149. package/react-native/src/sources/sync.ts +0 -561
  150. package/react-native/src/sources/test-helpers.ts +0 -24
  151. package/react-native/src/sources/transport-conditions-manager.ts +0 -104
  152. package/react-native/src/sources/transport-config.ts +0 -430
  153. package/react-native/src/sources/update-result.ts +0 -66
  154. package/react-native/src/sources/update-results-map.ts +0 -65
  155. package/react-native/src/sources/websocket-client.ts +0 -7
  156. package/react-native/src/sources/write-transaction-collection.ts +0 -122
  157. package/react-native/src/sources/write-transaction-pending-cursor-operation.ts +0 -101
  158. package/react-native/src/sources/write-transaction-pending-id-specific-operation.ts +0 -74
  159. package/react-native/src/sources/write-transaction.ts +0 -121
  160. package/react-native.config.js +0 -9
@@ -1,2190 +0,0 @@
1
- //
2
- // Copyright © 2023 DittoLive Incorporated. All rights reserved.
3
- //
4
-
5
- // NOTE: This is a temporary *hand-written* shim file for glue code for the
6
- // Ditto native Node module. Mid to long term, we'll either move all of this
7
- // code to the native side or generate this file via a companion CLI tool or
8
- // something equivalent.
9
- //
10
- // IMPORTANT: please leave this file self-contained and do not import any
11
- // sources from the JS SDK.
12
-
13
- import * as dittoCore from './@ditto.core'
14
- import * as Environment from './@environment'
15
- import { DittoFFIError, throwOnErrorResult } from './ffi-error'
16
-
17
- // -------------------------------------------------------------- Prelude ------
18
-
19
- /** @internal */
20
- export type Pointer<Type> = { type: Type; addr: string }
21
-
22
- /** @internal */
23
- export var isTracingEnabled = false
24
-
25
- /** @internal */
26
- export const DittoCRDTTypeKey = '_ditto_internal_type_jkb12973t4b'
27
-
28
- /** @internal */
29
- export const DittoCRDTValueKey = '_value'
30
-
31
- // ---------------------------------------------------------------- Types ------
32
-
33
- /** @internal */
34
- export type FFIError = 'dittoffi_error_t'
35
-
36
- /** @internal */
37
- export type FFIWriteStrategy = 'merge' | 'insertIfAbsent' | 'insertDefaultIfAbsent' | 'updateDifferentValues'
38
-
39
- /** @internal */
40
- export type FFIDocument = 'CDocument_t'
41
-
42
- /** @internal */
43
- export type FFIQueryResultItem = 'dittoffi_query_result_item_t'
44
-
45
- /** @internal */
46
- export type FFIQueryResult = 'dittoffi_query_result_t'
47
-
48
- /** @internal */
49
- export type FFIReadTransaction = 'CReadTransaction_t'
50
-
51
- /** @internal */
52
- export type FFIWriteTransaction = 'CWriteTransaction_t'
53
-
54
- /** @internal */
55
- export type FFIUninitializedDitto = 'CUninitializedDitto_t'
56
-
57
- /** @internal */
58
- export type FFIDitto = 'CDitto_t'
59
-
60
- /** @internal */
61
- export type FFIIdentityConfig = 'CIdentityConfig_t'
62
-
63
- /** @internal */
64
- export type FFILoginProvider = 'CLoginProvider_t'
65
-
66
- /** @internal */
67
- export type FFIAuthServerAuthRequest = 'CAuthServerAuthRequest_t'
68
-
69
- /** @internal */
70
- export type FFIAuthServerRefreshRequest = 'CAuthServerRefreshRequest_t'
71
-
72
- /** @internal */
73
- export type FFIStaticTCPClient = 'TransportHandle_StaticTCPClientPlatformEvent_t'
74
-
75
- /** @internal */
76
- export type FFIWebsocketClient = 'TransportHandle_WebsocketClientPlatformEvent_t'
77
-
78
- /** @internal */
79
- export type FFISmallPeerInfoSyncScope = 'LocalPeerOnly' | 'BigPeerOnly'
80
-
81
- /** @internal */
82
- export type FFIConnectionType = 'dittoffi_connection_type_t'
83
-
84
- /** @internal */
85
- export type FFIConnectionRequest = 'dittoffi_connection_request_t'
86
-
87
- /** @internal */
88
- export type FFIConnectionRequestAuthorization = 'dittoffi_connection_request_authorization_t'
89
-
90
- /** @internal */
91
- export type LiveQueryAvailability = 'Always' | 'WhenSignalled'
92
-
93
- /** @internal */
94
- export type StringPrimitiveFormat = 'WithQuotes' | 'WithoutQuotes'
95
-
96
- /** @internal */
97
- export type LogLevel = 'Error' | 'Warning' | 'Info' | 'Debug' | 'Verbose'
98
-
99
- /** @internal */
100
- export type LicenseVerificationResult = 'LicenseOk' | 'VerificationFailed' | 'LicenseExpired' | 'UnsupportedFutureVersion'
101
-
102
- /** @internal */
103
- export type WebsocketMode = 'Enabled' | 'Disabled'
104
-
105
- /** @internal */
106
- export type HistoryTracking = 'Enabled' | 'Disabled'
107
-
108
- /** @internal */
109
- export type ConditionSource = 'Bluetooth' | 'Tcp' | 'Awdl' | 'Mdns'
110
-
111
- /** @internal */
112
- export type TransportCondition = 'Unknown' | 'Ok' | 'GenericFailure' | 'AppInBackground' | 'MdnsFailure' | 'TcpListenFailure' | 'NoBleCentralPermission' | 'NoBlePeripheralPermission' | 'CannotEstablishConnection' | 'BleDisabled' | 'NoBleHardware' | 'WifiDisabled' | 'TemporarilyUnavailable'
113
-
114
- /** @internal */
115
- export type TransportsError = 'None' | 'Generic' | 'Unavailable'
116
-
117
- /** @internal */
118
- export type TransportBluetooth = 'DittoTransportsBLE_t'
119
-
120
- /** @internal */
121
- export type TransportAWDL = 'DittoTransportsAWDL_t'
122
-
123
- /** @internal */
124
- export type TransportLAN = 'DittoTransportsLAN_t'
125
-
126
- /** @internal */
127
- export type TransportMdnsClient = 'DittoTransportsMdnsClient_t'
128
-
129
- /** @internal */
130
- export type TransportMdnsServer = 'DittoTransportsMdnsServer_t'
131
-
132
- /** @internal */
133
- export type Platform = 'Windows' | 'Mac' | 'Ios' | 'Android' | 'Linux' | 'Web' | 'Unknown'
134
-
135
- /** @internal */
136
- export type Language = 'Swift' | 'ObjectiveC' | 'CPlusPlus' | 'CSharp' | 'JavaScript' | 'Unknown' | 'Rust'
137
-
138
- /** @internal */
139
- export type OrderBy = { query: string; direction: 'Ascending' | 'Descending' }
140
-
141
- /** @internal */
142
- export type PathAccessorType = 'String' | 'Number' | 'Int' | 'UInt' | 'Float' | 'Double' | 'Bool' | 'Null' | 'Object' | 'Array' | 'Any' | 'Counter' | 'Register' | 'Attachment' | 'Rga' | 'RWMap'
143
-
144
- /** @internal */
145
- export enum DittoCRDTType {
146
- counter = 0,
147
- register = 1,
148
- attachment = 2,
149
- rga = 3,
150
- rwMap = 4,
151
- }
152
-
153
- /** @internal */
154
- export type Base64PaddingMode = 'Padded' | 'Unpadded'
155
-
156
- /** @internal */
157
- export type ConnectionRequestAuthorization = 'Allow' | 'Deny'
158
-
159
- /** @internal */
160
- export type Transport = 'P2PWiFi' | 'WebSocket' | 'AccessPoint' | 'Bluetooth'
161
-
162
- /** @internal */
163
- export type CBParamsDocs = {
164
- documents: Pointer<FFIDocument>[]
165
- is_initial: boolean
166
- old_documents: Pointer<FFIDocument>[]
167
- insertions: number[]
168
- deletions: number[]
169
- updates: number[]
170
- moves: [number, number][]
171
- }
172
-
173
- /** @internal */
174
- export type CBParamsQueryResult = {
175
- query_result: Pointer<FFIQueryResult>
176
- }
177
-
178
- /** @internal */
179
- export type CBORPathResult = {
180
- statusCode: number
181
- cbor: Uint8Array
182
- }
183
-
184
- /** Various options to pass the web assembly module to Ditto. */
185
- export type WebAssemblyModule = RequestInfo | URL | Response | BufferSource | WebAssembly.Module | string | null
186
-
187
- /** @internal */
188
- export type AttachmentFileOperation = 'Copy' | 'Move'
189
-
190
- /** @internal */
191
- // IDEA: rename to AttachmentHandleType for consistency.
192
- export type AttachmentHandle = 'AttachmentHandle_t'
193
-
194
- /** @internal */
195
- export type RawAttachment = {
196
- id: Uint8Array
197
- len: number | BigInt
198
- handle: Pointer<AttachmentHandle>
199
- }
200
-
201
- // -------------------------------------- Linux & Windows Transports Hack ------
202
-
203
- // HACK: quick and dirty, wrap the internal BLE functions which
204
- // are currently only used by the Node Linux & Windows build. See comment
205
- // in `sync.ts` -> `Ditto.applyPeerToPeerBluetoothLE()` for details.
206
-
207
- export function dittoAddInternalBLEClientTransport(ditto: Pointer<FFIDitto>): any {
208
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
209
- return dittoCore.ditto_add_internal_ble_client_transport(ditto)
210
- }
211
-
212
- if (Environment.isWebBuild) {
213
- throw new Error(`Internal inconsistency, can't add internal BLE client, only available for non-apple Ditto Node builds.`)
214
- }
215
- }
216
-
217
- export function dittoAddInternalBLEServerTransport(ditto: Pointer<FFIDitto>): any {
218
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
219
- return dittoCore.ditto_add_internal_ble_server_transport(ditto)
220
- }
221
-
222
- if (Environment.isWebBuild) {
223
- throw new Error(`Internal inconsistency, can't add internal BLE server, only available for non-apple Ditto Node builds.`)
224
- }
225
- }
226
-
227
- export function bleClientFreeHandle(handle: any) {
228
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
229
- return dittoCore.ble_client_free_handle(handle)
230
- }
231
-
232
- if (Environment.isWebBuild) {
233
- throw new Error(`Internal inconsistency, can't free BLE client handle, only available for non-apple Ditto Node builds.`)
234
- }
235
- }
236
-
237
- export function bleServerFreeHandle(handle: any) {
238
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
239
- return dittoCore.ble_server_free_handle(handle)
240
- }
241
-
242
- if (Environment.isWebBuild) {
243
- throw new Error(`Internal inconsistency, can't free BLE server handle, only available for non-apple Ditto Node builds.`)
244
- }
245
- }
246
-
247
- export function dittoAddInternalMdnsTransport(ditto: Pointer<FFIDitto>): any {
248
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
249
- return dittoCore.ditto_add_internal_mdns_client_transport(ditto)
250
- }
251
-
252
- if (Environment.isWebBuild) {
253
- throw new Error(`Internal inconsistency, can't add internal MDNS transport/client, only available for non-apple Ditto Node builds.`)
254
- }
255
- }
256
-
257
- export function mdnsClientFreeHandle(handle: any) {
258
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
259
- return dittoCore.mdns_client_free_handle(handle)
260
- }
261
-
262
- if (Environment.isWebBuild) {
263
- throw new Error(`Internal inconsistency, can't free MDNS transport/client handle, only available for non-apple Ditto Node builds.`)
264
- }
265
- }
266
-
267
- export function dittoAddInternalMdnsAdvertiser(ditto: Pointer<FFIDitto>): any {
268
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
269
- return dittoCore.ditto_add_internal_mdns_server_transport(ditto)
270
- }
271
-
272
- if (Environment.isWebBuild) {
273
- throw new Error(`Internal inconsistency, can't add internal MDNS advertiser/server, only available for non-apple Ditto Node builds.`)
274
- }
275
- }
276
-
277
- export function mdnsServerFreeHandle(handle: any) {
278
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
279
- return dittoCore.mdns_server_free_handle(handle)
280
- }
281
-
282
- if (Environment.isWebBuild) {
283
- throw new Error(`Internal inconsistency, can't free MDNS advertiser/server handle, only available for non-apple Ditto Node builds.`)
284
- }
285
- }
286
-
287
- // ------------------------------------------------------------- Document ------
288
-
289
- /** @internal */
290
- export function documentSetCBORWithTimestamp(document: Pointer<FFIDocument>, path: string, cbor: Uint8Array, timestamp: number) {
291
- trace()
292
- ensureInitialized()
293
-
294
- const pathX = bytesFromString(path)
295
- const errorCode = dittoCore.ditto_document_set_cbor_with_timestamp(document, pathX, cbor, timestamp)
296
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_document_set_cbor_with_timestamp() failed with error code: ${errorCode}`)
297
- }
298
-
299
- /** @internal */
300
- export function documentSetCBOR(document: Pointer<FFIDocument>, path: string, cbor: Uint8Array) {
301
- trace()
302
- ensureInitialized()
303
-
304
- // NOTE: not sure if this should be async or not.
305
- const pathX = bytesFromString(path)
306
- const errorCode = dittoCore.ditto_document_set_cbor(document, pathX, cbor)
307
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_document_set_cbor() failed with error code: ${errorCode}`)
308
- }
309
-
310
- /** @internal */
311
- export function documentID(self: Pointer<FFIDocument>): Uint8Array {
312
- trace()
313
- ensureInitialized()
314
-
315
- // REFACTOR: add proper error handling.
316
- const documentIDX = dittoCore.ditto_document_id(self)
317
- return dittoCore.boxCBytesIntoBuffer(documentIDX)
318
- }
319
-
320
- /** @internal */
321
- export function documentCBOR(self: Pointer<FFIDocument>): Uint8Array {
322
- trace()
323
- ensureInitialized()
324
-
325
- const cborBytes = dittoCore.ditto_document_cbor(self)
326
- return dittoCore.boxCBytesIntoBuffer(cborBytes)
327
- }
328
-
329
- /** @internal */
330
- export function documentGetCBORWithPathType(document: Pointer<FFIDocument>, path: string, pathType: PathAccessorType): CBORPathResult {
331
- trace()
332
- ensureInitialized()
333
-
334
- const pathBytes = bytesFromString(path)
335
- const cborPathResultRaw = dittoCore.ditto_document_get_cbor_with_path_type(document, pathBytes, pathType)
336
-
337
- const cborPathResult: CBORPathResult = {
338
- statusCode: cborPathResultRaw.status_code,
339
- cbor: dittoCore.boxCBytesIntoBuffer(cborPathResultRaw.cbor),
340
- }
341
-
342
- return cborPathResult
343
- }
344
-
345
- /** @internal */
346
- export function documentRemove(document: Pointer<FFIDocument>, path: string) {
347
- trace()
348
- ensureInitialized()
349
-
350
- const pathBytes = bytesFromString(path)
351
- const errorCode = dittoCore.ditto_document_remove(document, pathBytes)
352
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_document_remove() failed with error code: ${errorCode}`)
353
- }
354
-
355
- /** @internal */
356
- export function documentIncrementCounter(document: Pointer<FFIDocument>, path: string, amount: number) {
357
- trace()
358
- ensureInitialized()
359
-
360
- const pathBytes = bytesFromString(path)
361
- const errorCode = dittoCore.ditto_document_increment_counter(document, pathBytes, amount)
362
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_document_increment_counter() failed with error code: ${errorCode}`)
363
- }
364
-
365
- /** @internal */
366
- export function documentFree(self: Pointer<FFIDocument>) {
367
- trace()
368
- ensureInitialized()
369
-
370
- // REFACTOR: add proper error handling.
371
- dittoCore.ditto_document_free(self)
372
- }
373
-
374
- // ----------------------------------------------------------- DocumentID ------
375
-
376
- /** @internal */
377
- export function documentIDQueryCompatible(docID: Uint8Array, stringPrimitiveFormat: StringPrimitiveFormat): string {
378
- trace()
379
- ensureInitialized()
380
-
381
- const docIDString = dittoCore.ditto_document_id_query_compatible(docID, stringPrimitiveFormat)
382
- return dittoCore.boxCStringIntoString(docIDString)
383
- }
384
-
385
- /** @internal */
386
- export function validateDocumentID(docID: Uint8Array): Uint8Array {
387
- trace()
388
- ensureInitialized()
389
-
390
- const cborCBytes = dittoCore.withOutBoxCBytes((outCBOR) => {
391
- const errorCode = dittoCore.ditto_validate_document_id(docID, outCBOR)
392
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_validate_document_id() failed with error code: ${errorCode}`)
393
- return outCBOR
394
- })
395
-
396
- return dittoCore.boxCBytesIntoBuffer(cborCBytes)
397
- }
398
-
399
- // ----------------------------------------------------------- Collection ------
400
-
401
- /** @internal */
402
- export async function collectionGet(ditto: Pointer<FFIDitto>, collectionName: string, documentID: Uint8Array, readTransaction: Pointer<FFIReadTransaction>): Promise<Pointer<FFIDocument> | null> {
403
- trace()
404
- ensureInitialized()
405
-
406
- // REFACTOR: add proper error handling.
407
- const collectionNameX = bytesFromString(collectionName)
408
-
409
- const { status_code: errorCode, document } = await dittoCore.ditto_collection_get(ditto, collectionNameX, documentID, readTransaction)
410
- if (errorCode === NOT_FOUND_ERROR_CODE) return null
411
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_collection_get() failed with error code: ${errorCode}`)
412
- return document
413
- }
414
-
415
- /** @internal */
416
- export async function collectionInsertValue(ditto: Pointer<FFIDitto>, collectionName: string, doc_cbor: Uint8Array, writeStrategy: FFIWriteStrategy, writeTransaction?: Pointer<FFIWriteTransaction>): Promise<Uint8Array> {
417
- trace()
418
- ensureInitialized()
419
-
420
- // REFACTOR: add proper error handling.
421
- const collectionNameX = bytesFromString(collectionName)
422
-
423
- let strategy
424
- switch (writeStrategy) {
425
- case 'merge':
426
- strategy = 'Merge'
427
- break
428
- case 'insertIfAbsent':
429
- strategy = 'InsertIfAbsent'
430
- break
431
- case 'insertDefaultIfAbsent':
432
- strategy = 'InsertDefaultIfAbsent'
433
- break
434
- case 'updateDifferentValues':
435
- strategy = 'UpdateDifferentValues'
436
- break
437
- default:
438
- throw new Error(`Unsupported write strategy '${writeStrategy}' provided.`)
439
- }
440
-
441
- const { status_code: errorCode, id } = await dittoCore.ditto_collection_insert_value(ditto, collectionNameX, doc_cbor, strategy, null, writeTransaction ?? null)
442
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_collection_insert_value() failed with error code: ${errorCode}`)
443
- return dittoCore.boxCBytesIntoBuffer(id)
444
- }
445
-
446
- /** @internal */
447
- export async function collectionRemove(ditto: Pointer<FFIDitto>, collectionName: string, writeTransaction: Pointer<FFIWriteTransaction>, documentID: Uint8Array): Promise<boolean> {
448
- trace()
449
- ensureInitialized()
450
-
451
- // REFACTOR: add proper error handling.
452
- const collectionNameX = bytesFromString(collectionName)
453
-
454
- const { status_code: errorCode, bool_value: didRemove } = await dittoCore.ditto_collection_remove(ditto, collectionNameX, writeTransaction, documentID)
455
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_collection_remove() failed with error code: ${errorCode}`)
456
- return didRemove
457
- }
458
-
459
- /** @internal */
460
- export async function collectionEvict(ditto: Pointer<FFIDitto>, collectionName: string, writeTransaction: Pointer<FFIWriteTransaction>, documentID: Uint8Array): Promise<boolean> {
461
- trace()
462
- ensureInitialized()
463
-
464
- // REFACTOR: add proper error handling.
465
- const collectionNameX = bytesFromString(collectionName)
466
-
467
- const { status_code: errorCode, bool_value: didEvict } = await dittoCore.ditto_collection_evict(ditto, collectionNameX, writeTransaction, documentID)
468
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_collection_evict() failed with error code: ${errorCode}`)
469
- return didEvict
470
- }
471
-
472
- /** @internal */
473
- export async function collectionUpdate(ditto: Pointer<FFIDitto>, collectionName: string, writeTransaction: Pointer<FFIWriteTransaction>, document: Pointer<FFIDocument>): Promise<void> {
474
- trace()
475
- ensureInitialized()
476
-
477
- const collectionNameX = bytesFromString(collectionName)
478
- const errorCode = await dittoCore.ditto_collection_update(ditto, collectionNameX, writeTransaction, document)
479
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_collection_update() failed with error code: ${errorCode}`)
480
- }
481
-
482
- /** @internal */
483
- export async function collectionUpdateMultiple(ditto: Pointer<FFIDitto>, collectionName: string, writeTransaction: Pointer<FFIWriteTransaction>, documents: Pointer<FFIDocument>[]): Promise<void> {
484
- trace()
485
- ensureInitialized()
486
-
487
- const collectionNameX = bytesFromString(collectionName)
488
- const cDocuments = dittoCore.jsDocsToCDocs(documents)
489
- const errorCode = await dittoCore.ditto_collection_update_multiple(ditto, collectionNameX, writeTransaction, cDocuments)
490
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_collection_update_multiple() failed with error code: ${errorCode}`)
491
- }
492
-
493
- /** @internal */
494
- export async function collectionExecQueryStr(ditto: Pointer<FFIDitto>, collectionName: string, writeTransaction: Pointer<FFIWriteTransaction>, query: string, queryArgsCBOR: Uint8Array | null, orderBy: OrderBy[], limit: number, offset: number): Promise<Pointer<FFIDocument>[]> {
495
- trace()
496
- ensureInitialized()
497
-
498
- const collectionNameX = bytesFromString(collectionName)
499
- const queryX = bytesFromString(query)
500
- return await dittoCore.ditto_collection_exec_query_str(ditto, collectionNameX, writeTransaction, queryX, queryArgsCBOR, orderBy, limit, offset)
501
- }
502
-
503
- /** @internal */
504
- export async function collectionRemoveQueryStr(ditto: Pointer<FFIDitto>, collectionName: string, writeTransaction: Pointer<FFIWriteTransaction>, query: string, queryArgsCBOR: Uint8Array | null, orderBy: OrderBy[], limit: number, offset: number): Promise<Uint8Array[]> {
505
- trace()
506
- ensureInitialized()
507
-
508
- const collectionNameX = bytesFromString(collectionName)
509
- const queryX = bytesFromString(query)
510
- return await dittoCore.ditto_collection_remove_query_str(ditto, collectionNameX, writeTransaction, queryX, queryArgsCBOR, orderBy, limit, offset)
511
- }
512
-
513
- /** @internal */
514
- export async function collectionEvictQueryStr(ditto: Pointer<FFIDitto>, collectionName: string, writeTransaction: Pointer<FFIWriteTransaction>, query: string, queryArgsCBOR: Uint8Array | null, orderBy: OrderBy[], limit: number, offset: number): Promise<Uint8Array[]> {
515
- trace()
516
- ensureInitialized()
517
-
518
- const collectionNameX = bytesFromString(collectionName)
519
- const queryX = bytesFromString(query)
520
- return await dittoCore.ditto_collection_evict_query_str(ditto, collectionNameX, writeTransaction, queryX, queryArgsCBOR, orderBy, limit, offset)
521
- }
522
-
523
- /**
524
- * This FFI can error:
525
- * - DQL parser error
526
- * - Incorrect arguments to query parameters
527
- * - Collection is not found.
528
- *
529
- * @internal
530
- */
531
- export async function tryExecStatement(ditto: Pointer<FFIDitto>, writeTransaction: Pointer<FFIWriteTransaction> | null, query: string, queryArgsCBOR: Uint8Array | null): Promise<Pointer<FFIQueryResult>> {
532
- trace()
533
- ensureInitialized()
534
-
535
- const queryBytesPointer = bytesFromString(query)
536
- const result = await dittoCore.dittoffi_try_exec_statement(ditto, writeTransaction, queryBytesPointer, queryArgsCBOR)
537
- throwOnErrorResult(result.error, 'dittoffi_try_exec_statement')
538
- return result.success
539
- }
540
-
541
- /** @internal */
542
- export function addSubscription(ditto: Pointer<FFIDitto>, collectionName: string, query: string, queryArgsCBOR: Uint8Array | null, orderBy: OrderBy[], limit: number, offset: number): void {
543
- trace()
544
- ensureInitialized()
545
-
546
- const collectionNameX = bytesFromString(collectionName)
547
- const queryX = bytesFromString(query)
548
- const statusCode = dittoCore.ditto_add_subscription(ditto, collectionNameX, queryX, queryArgsCBOR, orderBy, limit, offset)
549
- if (statusCode !== 0) throw new Error(errorMessage() || `ditto_add_subscription() failed with error code: ${statusCode}`)
550
- }
551
-
552
- /** @internal */
553
- export function removeSubscription(ditto: Pointer<FFIDitto>, collectionName: string, query: string, queryArgsCBOR: Uint8Array | null, orderBy: OrderBy[], limit: number, offset: number): void {
554
- trace()
555
- ensureInitialized()
556
-
557
- const collectionNameX = bytesFromString(collectionName)
558
- const queryX = bytesFromString(query)
559
- const statusCode = dittoCore.ditto_remove_subscription(ditto, collectionNameX, queryX, queryArgsCBOR, orderBy, limit, offset)
560
- if (statusCode !== 0) throw new Error(errorMessage() || `ditto_remove_subscription() failed with error code: ${statusCode}`)
561
- }
562
-
563
- /** @internal */
564
- export function tryAddSyncSubscription(dittoPointer: Pointer<FFIDitto>, query: string, queryArgsCBOR: Uint8Array | null): void {
565
- trace()
566
- ensureInitialized()
567
-
568
- const queryBuffer = bytesFromString(query)
569
- const result = dittoCore.dittoffi_try_add_sync_subscription(dittoPointer, queryBuffer, queryArgsCBOR)
570
- throwOnErrorResult(result.error, 'dittoffi_try_add_sync_subscription')
571
- return
572
- }
573
-
574
- /** @internal */
575
- export function tryRemoveSyncSubscription(dittoPointer: Pointer<FFIDitto>, query: string, queryArgsCBOR: Uint8Array | null): void {
576
- trace()
577
- ensureInitialized()
578
-
579
- const queryBuffer = bytesFromString(query)
580
- const result = dittoCore.dittoffi_try_remove_sync_subscription(dittoPointer, queryBuffer, queryArgsCBOR)
581
- throwOnErrorResult(result.error, 'dittoffi_try_remove_sync_subscription')
582
- return
583
- }
584
-
585
- // ----------------------------------------------------------- QueryResult ------
586
-
587
- /**
588
- * Doesn't error
589
- *
590
- * @internal
591
- */
592
- export function queryResultFree(queryResultPointer: Pointer<FFIQueryResult>) {
593
- trace()
594
- ensureInitialized()
595
-
596
- dittoCore.dittoffi_query_result_free(queryResultPointer)
597
- }
598
-
599
- /**
600
- * Doesn't error
601
- *
602
- * @internal
603
- */
604
- export function queryResultItemFree(queryResultItemPointer: Pointer<FFIQueryResultItem>) {
605
- trace()
606
- ensureInitialized()
607
-
608
- dittoCore.dittoffi_query_result_item_free(queryResultItemPointer)
609
- }
610
-
611
- /**
612
- * Can error only on internal bug.
613
- *
614
- * @internal */
615
- export function queryResultItems(queryResultPointer: Pointer<FFIQueryResult>): Pointer<FFIQueryResultItem>[] {
616
- trace()
617
- ensureInitialized()
618
-
619
- const rv = []
620
- const resultCount = dittoCore.dittoffi_query_result_item_count(queryResultPointer)
621
- for (let i = 0; i < resultCount; i++) {
622
- rv.push(dittoCore.dittoffi_query_result_item_at(queryResultPointer, i))
623
- }
624
- return rv
625
- }
626
-
627
- /**
628
- * Doesn't error
629
- *
630
- * @internal
631
- */
632
- export function queryResultMutatedDocumentIDs(queryResultPointer: Pointer<FFIQueryResult>): Uint8Array[] {
633
- trace()
634
- ensureInitialized()
635
-
636
- const rv = []
637
- const resultCount = dittoCore.dittoffi_query_result_mutated_document_id_count(queryResultPointer)
638
- for (let i = 0; i < resultCount; i++) {
639
- const cborBytes = dittoCore.dittoffi_query_result_mutated_document_id_at(queryResultPointer, i)
640
- rv.push(dittoCore.boxCBytesIntoBuffer(cborBytes))
641
- }
642
- return rv
643
- }
644
-
645
- /**
646
- * The result CBOR contains a map/object with fields and values. No CRDTs are
647
- * present there as they are not needed. By default only values from registers
648
- * are returned and non-register fields are ignored.
649
- *
650
- * Doesn't error
651
- *
652
- * @internal
653
- */
654
- export function queryResultItemCBOR(queryResultItemPointer: Pointer<FFIQueryResultItem>): Uint8Array {
655
- trace()
656
- ensureInitialized()
657
-
658
- const cborBytes = dittoCore.dittoffi_query_result_item_cbor(queryResultItemPointer)
659
- return dittoCore.boxCBytesIntoBuffer(cborBytes)
660
- }
661
-
662
- /**
663
- * Returns JSON-encoded results given a DQL result item pointer.
664
- *
665
- * Compare for {@link queryResultItemCBOR} above.
666
- *
667
- * Doesn't error
668
- *
669
- * @internal
670
- */
671
- export function queryResultItemJSON(queryResultItemPointer: Pointer<FFIQueryResultItem>): string {
672
- trace()
673
- ensureInitialized()
674
-
675
- const jsonBytes = dittoCore.dittoffi_query_result_item_json(queryResultItemPointer)
676
- return dittoCore.boxCStringIntoString(jsonBytes)
677
- }
678
-
679
- // ------------------------------------------------------------ LiveQuery ------
680
-
681
- /** @internal */
682
- export function liveQueryRegister(
683
- ditto: Pointer<FFIDitto>,
684
- collectionName: string,
685
- query: string,
686
- queryArgsCBOR: Uint8Array | null,
687
- orderBy: OrderBy[],
688
- limit: number,
689
- offset: number,
690
- eventHandler: (cbParams: CBParamsDocs) => any,
691
- // Cb may be called in parallel at any point, so let's use
692
- // an optional error handler (which defaults to the ditto logger at 'Error' level).
693
- onError?: (error: any) => void,
694
- ): number {
695
- trace()
696
- ensureInitialized()
697
-
698
- const collectionNameBuffer = bytesFromString(collectionName)
699
- const queryBuffer = bytesFromString(query)
700
- // Note(Daniel): the callback is now registered to be called in a detached
701
- // manner: if the FFI / Rust does `cb()`, then when that call returns, the js
702
- // callback itself may not have completed. This is fine, since `signalNext()`
703
- // shall be the proper way to let the Rust core know the FFI call completed.
704
- const { status_code: errorCode, i64: id } = dittoCore.ditto_live_query_register_str_detached(ditto, collectionNameBuffer, queryBuffer, queryArgsCBOR, orderBy, limit, offset, wrapBackgroundCbForFFI(onError, eventHandler))
705
- if (errorCode !== 0) throw new Error(errorMessage() || `\`ditto_live_query_register_str()\` failed with error code: ${errorCode}`)
706
- return id
707
- }
708
-
709
- /** @internal */
710
- export function tryExperimentalRegisterChangeObserver(ditto: Pointer<FFIDitto>, query: string, queryArgsCBOR: Uint8Array | null, changeHandler: (cbParams: CBParamsQueryResult) => any): number {
711
- trace()
712
- ensureInitialized()
713
-
714
- const errorHandler = (err: any) => log('Error', `The registered store observer callback failed with ${err}`)
715
- const wrappedCallback = wrapBackgroundCbForFFI(errorHandler, changeHandler)
716
- const queryBuffer = bytesFromString(query)
717
- // Note(Daniel): the callback is registered to be called in a detached manner:
718
- // if the FFI / Rust does `cb()`, then when that call returns, the js callback
719
- // itself may not have completed. This is fine, since `signalNext()` shall be
720
- // the proper way to let the Rust core know the FFI call completed.
721
- const result = dittoCore.dittoffi_try_experimental_register_change_observer_str_detached(ditto, queryBuffer, queryArgsCBOR, wrappedCallback)
722
- throwOnErrorResult(result.error, 'dittoffi_try_experimental_register_change_observer_str_detached')
723
- return result.success
724
- }
725
-
726
- /** @internal */
727
- export async function liveQueryStart(ditto: Pointer<FFIDitto>, liveQueryID: number): Promise<void> {
728
- trace()
729
- ensureInitialized()
730
-
731
- const errorCode = await dittoCore.ditto_live_query_start(ditto, liveQueryID)
732
- if (errorCode !== 0) throw new Error(errorMessage() || `\`ditto_live_query_start()\` failed with error code: ${errorCode}`)
733
- }
734
-
735
- /** @internal */
736
- export function liveQueryStop(ditto: Pointer<FFIDitto>, liveQueryID: number) {
737
- trace()
738
- ensureInitialized()
739
-
740
- dittoCore.ditto_live_query_stop(ditto, liveQueryID)
741
- }
742
-
743
- /** @internal */
744
- export async function liveQuerySignalAvailableNext(ditto: Pointer<FFIDitto>, liveQueryID: number): Promise<void> {
745
- trace()
746
- ensureInitialized()
747
-
748
- await dittoCore.ditto_live_query_signal_available_next(ditto, liveQueryID)
749
- }
750
-
751
- // ------------------------------------------------------------ Webhook ------
752
-
753
- /** @internal */
754
- export async function liveQueryWebhookRegister(ditto: Pointer<FFIDitto>, collectionName: string, query: string, orderBy: OrderBy[], limit: number, offset: number, url: string): Promise<Uint8Array> {
755
- trace()
756
- ensureInitialized()
757
- const collectionNameBuffer = bytesFromString(collectionName)
758
- const queryBuffer = bytesFromString(query)
759
- const urlBuffer = bytesFromString(url)
760
-
761
- const { status_code: errorCode, id } = await dittoCore.ditto_live_query_webhook_register_str(ditto, collectionNameBuffer, queryBuffer, orderBy, limit, offset, urlBuffer)
762
- if (errorCode !== 0) throw new Error(errorMessage() || `\`ditto_live_query_webhook_register_str()\` failed with error code: ${errorCode}`)
763
-
764
- return dittoCore.boxCBytesIntoBuffer(id)
765
- }
766
-
767
- /** @internal */
768
- export async function tryRegisterStoreObserverWebhook(ditto: Pointer<FFIDitto>, query: string, queryArgsCBOR: Uint8Array | null, url: string): Promise<Uint8Array> {
769
- trace()
770
- ensureInitialized()
771
-
772
- const queryBuffer = bytesFromString(query)
773
- const urlBuffer = bytesFromString(url)
774
-
775
- const result = await dittoCore.dittoffi_try_register_store_observer_webhook(ditto, queryBuffer, queryArgsCBOR, urlBuffer)
776
- throwOnErrorResult(result.error, 'dittoffi_try_register_store_observer_webhook')
777
- const documentIdCBOR = result.success
778
-
779
- return dittoCore.boxCBytesIntoBuffer(documentIdCBOR)
780
- }
781
-
782
- // ------------------------------------------------------ ReadTransaction ------
783
-
784
- /** @internal */
785
- export async function readTransaction(ditto: Pointer<FFIDitto>): Promise<Pointer<FFIReadTransaction>> {
786
- trace()
787
- ensureInitialized()
788
-
789
- // REFACTOR: add proper error handling.
790
-
791
- const { status_code: errorCode, txn: readTransaction } = await dittoCore.ditto_read_transaction(ditto)
792
- if (errorCode !== 0) throw new Error(errorMessage() || `\`ditto_read_transaction()\` failed with error code: ${errorCode}`)
793
- return readTransaction
794
- }
795
-
796
- /** @internal */
797
- export function readTransactionFree(self: Pointer<FFIReadTransaction>) {
798
- trace()
799
- ensureInitialized()
800
-
801
- // REFACTOR: add proper error handling.
802
- return dittoCore.ditto_read_transaction_free(self)
803
- }
804
-
805
- // ----------------------------------------------------- WriteTransaction ------
806
-
807
- /** @internal */
808
- export async function writeTransaction(ditto: Pointer<FFIDitto>): Promise<Pointer<FFIWriteTransaction>> {
809
- trace()
810
- ensureInitialized()
811
-
812
- // REFACTOR: add proper error handling.
813
-
814
- const { status_code: errorCode, txn: writeTransaction } = await dittoCore.ditto_write_transaction(ditto, null)
815
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_write_transaction() failed with error code: ${errorCode}`)
816
- return writeTransaction
817
- }
818
-
819
- /** @internal */
820
- export async function writeTransactionCommit(ditto: Pointer<FFIDitto>, self: Pointer<FFIWriteTransaction>): Promise<void> {
821
- trace()
822
- ensureInitialized()
823
-
824
- const errorCode = await dittoCore.ditto_write_transaction_commit(ditto, self)
825
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_write_transaction_commit() failed with error code: ${errorCode}`)
826
- }
827
-
828
- /** @internal */
829
- export async function writeTransactionRollback(ditto: Pointer<FFIDitto>, transaction: Pointer<FFIWriteTransaction>): Promise<void> {
830
- trace()
831
- ensureInitialized()
832
-
833
- const errorCode = await dittoCore.ditto_write_transaction_rollback(ditto, transaction)
834
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_write_transaction_rollback() failed with error code: ${errorCode}`)
835
- }
836
-
837
- // ------------------------------------------------------ StaticTCPClient ------
838
-
839
- /** @internal */
840
- export function addStaticTCPClient(ditto: Pointer<FFIDitto>, address: string): Pointer<FFIStaticTCPClient> {
841
- trace()
842
- ensureInitialized()
843
-
844
- const addressBuffer = bytesFromString(address)
845
- return dittoCore.ditto_add_static_tcp_client(ditto, addressBuffer)
846
- }
847
-
848
- /** @internal */
849
- export function staticTCPClientFreeHandle(self: Pointer<FFIStaticTCPClient>) {
850
- trace()
851
- dittoCore.static_tcp_client_free_handle(self)
852
- }
853
-
854
- // ------------------------------------------------------ WebsocketClient ------
855
-
856
- /** @internal */
857
- export function addWebsocketClient(ditto: Pointer<FFIDitto>, address: string, routingHint: number): Pointer<FFIWebsocketClient> {
858
- trace()
859
- ensureInitialized()
860
-
861
- const addressBuffer = bytesFromString(address)
862
- return dittoCore.ditto_add_websocket_client(ditto, addressBuffer, routingHint)
863
- }
864
-
865
- /** @internal */
866
- export function websocketClientFreeHandle(self: Pointer<FFIWebsocketClient>) {
867
- trace()
868
- ensureInitialized()
869
- dittoCore.websocket_client_free_handle(self)
870
- }
871
-
872
- // --------------------------------------------------------------- Logger ------
873
-
874
- /** @internal */
875
- export function loggerInit() {
876
- trace()
877
- ensureInitialized()
878
- dittoCore.ditto_logger_init()
879
- }
880
-
881
- /** @internal */
882
- export async function loggerSetCustomLogCb(cb: null | ((lvl: LogLevel, msg: string) => void)): Promise<void> {
883
- trace()
884
- ensureInitialized()
885
-
886
- if (null === cb) {
887
- await dittoCore.ditto_logger_set_custom_log_cb(null)
888
- } else {
889
- // IDEA: pass custom error handler here instead of null?
890
- const wrappedCallback = wrapBackgroundCbForFFI(null, (loglevel: LogLevel, cMsg: Pointer<'char'>) => {
891
- try {
892
- const msg: string = dittoCore.boxCStringIntoString(cMsg)
893
- cb(loglevel, msg)
894
- } catch (e) {
895
- log('Error', `The registered cb in \`ditto_logger_set_custom_log_cb()\` failed with: ${e}`)
896
- }
897
- })
898
- await dittoCore.ditto_logger_set_custom_log_cb(wrappedCallback)
899
- }
900
- }
901
-
902
- /** @internal */
903
- export function loggerEnabled(enabled: boolean) {
904
- trace()
905
- ensureInitialized()
906
- dittoCore.ditto_logger_enabled(!!enabled)
907
- }
908
-
909
- /** @internal */
910
- export function loggerEnabledGet(): boolean {
911
- trace()
912
- ensureInitialized()
913
- return !!dittoCore.ditto_logger_enabled_get()
914
- }
915
-
916
- /** @internal */
917
- export function loggerEmojiHeadingsEnabled(loggerEmojiHeadingsEnabled: boolean) {
918
- trace()
919
- ensureInitialized()
920
- dittoCore.ditto_logger_emoji_headings_enabled(loggerEmojiHeadingsEnabled)
921
- }
922
-
923
- /** @internal */
924
- export function loggerEmojiHeadingsEnabledGet() {
925
- trace()
926
- ensureInitialized()
927
- return dittoCore.ditto_logger_emoji_headings_enabled_get()
928
- }
929
-
930
- /** @internal */
931
- export function loggerMinimumLogLevel(logLevel: LogLevel) {
932
- trace()
933
- ensureInitialized()
934
- dittoCore.ditto_logger_minimum_log_level(logLevel)
935
- }
936
-
937
- /** @internal */
938
- export function loggerMinimumLogLevelGet() {
939
- trace()
940
- ensureInitialized()
941
- return dittoCore.ditto_logger_minimum_log_level_get()
942
- }
943
-
944
- /** @internal */
945
- export function loggerSetLogFile(path?: string) {
946
- trace()
947
- ensureInitialized()
948
- const pathBytesOrNull = path ? bytesFromString(path) : null
949
- const errorCode = dittoCore.ditto_logger_set_log_file(pathBytesOrNull)
950
- if (errorCode !== 0) {
951
- const message = errorMessage()
952
- throw new Error(`Can't set log file, due to error: ${errorMessage}`)
953
- }
954
- }
955
-
956
- /** @internal */
957
- export function log(level: LogLevel, message: string) {
958
- trace()
959
- ensureInitialized()
960
- const messageBuffer = bytesFromString(message)
961
- dittoCore.ditto_log(level, messageBuffer)
962
- }
963
-
964
- // ----------------------------------------------------------- AuthClient ------
965
-
966
- /** @internal */
967
- export function dittoIdentityConfigMakeOnlinePlayground(appID: string, sharedToken: string, baseURL: string): Pointer<FFIIdentityConfig> {
968
- trace()
969
- ensureInitialized()
970
-
971
- const appIDX = bytesFromString(appID)
972
- const sharedTokenX = bytesFromString(sharedToken)
973
- const baseURLX = bytesFromString(baseURL)
974
-
975
- const { status_code: errorCode, identity_config: identityConfig } = dittoCore.ditto_identity_config_make_online_playground(appIDX, sharedTokenX, baseURLX)
976
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_identity_config_make_online_playground() failed with error code: ${errorCode}`)
977
- return identityConfig
978
- }
979
-
980
- /** @internal */
981
- export function dittoIdentityConfigMakeOnlineWithAuthentication(appID: string, baseURL: string): Pointer<FFIIdentityConfig> {
982
- trace()
983
- ensureInitialized()
984
-
985
- const appIDX = bytesFromString(appID)
986
- const baseURLX = bytesFromString(baseURL)
987
-
988
- const { status_code: errorCode, identity_config: identityConfig } = dittoCore.ditto_identity_config_make_online_with_authentication(appIDX, baseURLX)
989
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_identity_config_make_online_with_authentication() failed with error code: ${errorCode}`)
990
- return identityConfig
991
- }
992
-
993
- /** @internal */
994
- export function dittoIdentityConfigMakeOfflinePlayground(appId: string, siteID: number | BigInt): Pointer<FFIIdentityConfig> {
995
- trace()
996
- ensureInitialized()
997
-
998
- const appIdX = bytesFromString(appId)
999
- const siteIDX = Number(siteID)
1000
- const { status_code: errorCode, identity_config: identityConfig } = dittoCore.ditto_identity_config_make_offline_playground(appIdX, siteIDX)
1001
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_identity_config_make_offline_playground() failed with error code: ${errorCode}`)
1002
- return identityConfig
1003
- }
1004
-
1005
- /** @internal */
1006
- export function dittoIdentityConfigMakeSharedKey(appId: string, sharedKey: string, siteID: number | BigInt): Pointer<FFIIdentityConfig> {
1007
- trace()
1008
- ensureInitialized()
1009
-
1010
- const appIdX = bytesFromString(appId)
1011
- const sharedKeyX = bytesFromString(sharedKey)
1012
- const siteIDX = Number(siteID)
1013
- const { status_code: errorCode, identity_config: identityConfig } = dittoCore.ditto_identity_config_make_shared_key(appIdX, sharedKeyX, siteIDX)
1014
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_identity_config_make_shared_key() failed with error code: ${errorCode}`)
1015
- return identityConfig
1016
- }
1017
-
1018
- /** @internal */
1019
- export function dittoIdentityConfigMakeManual(configCBORBase64: string): Pointer<FFIIdentityConfig> {
1020
- trace()
1021
- ensureInitialized()
1022
-
1023
- const configCBORBase64X = bytesFromString(configCBORBase64)
1024
-
1025
- const { status_code: errorCode, identity_config: identityConfig } = dittoCore.ditto_identity_config_make_manual_v0(configCBORBase64X)
1026
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_identity_config_make_manual_v0() failed with error code: ${errorCode}`)
1027
- return identityConfig
1028
- }
1029
-
1030
- /** @internal */
1031
- export function dittoAuthClientGetSiteID(ditto: Pointer<FFIDitto>): number | BigInt {
1032
- trace()
1033
- ensureInitialized()
1034
- return dittoCore.ditto_auth_client_get_site_id(ditto)
1035
- }
1036
-
1037
- /** @internal */
1038
- export function dittoAuthClientGetAppID(ditto: Pointer<FFIDitto>): string {
1039
- trace()
1040
- ensureInitialized()
1041
- const cString = dittoCore.ditto_auth_client_get_app_id(ditto)
1042
- return dittoCore.boxCStringIntoString(cString)
1043
- }
1044
-
1045
- export function dittoAuthClientUserID(ditto: Pointer<FFIDitto>): string {
1046
- trace()
1047
- ensureInitialized()
1048
- const cStr = dittoCore.ditto_auth_client_user_id(ditto)
1049
- return dittoCore.boxCStringIntoString(cStr)
1050
- }
1051
-
1052
- /** @internal */
1053
- export function dittoAuthClientIsWebValid(ditto: Pointer<FFIDitto>): boolean {
1054
- trace()
1055
- ensureInitialized()
1056
- return dittoCore.ditto_auth_client_is_web_valid(ditto) !== 0
1057
- }
1058
-
1059
- export function dittoAuthClientIsX509Valid(ditto: Pointer<FFIDitto>): boolean {
1060
- trace()
1061
- ensureInitialized()
1062
- return dittoCore.ditto_auth_client_is_x509_valid(ditto) !== 0
1063
- }
1064
-
1065
- export async function dittoAuthClientLoginWithToken(ditto: Pointer<FFIDitto>, token: string, provider: string) {
1066
- trace()
1067
- ensureInitialized()
1068
-
1069
- const tokenBytes = bytesFromString(token)
1070
- const providerBytes = bytesFromString(provider)
1071
-
1072
- const errorCode = await dittoCore.ditto_auth_client_login_with_token(ditto, tokenBytes, providerBytes)
1073
- if (errorCode !== 0) throw new Error(errorMessage() || `Ditto failed to authenticate (error code: ${errorCode}).`)
1074
- }
1075
-
1076
- export async function dittoAuthClientLoginWithUsernameAndPassword(ditto: Pointer<FFIDitto>, username: string, password: string, provider: string) {
1077
- trace()
1078
- ensureInitialized()
1079
-
1080
- const usernameBytes = bytesFromString(username)
1081
- const passwordBytes = bytesFromString(password)
1082
- const providerBytes = bytesFromString(provider)
1083
-
1084
- const errorCode = await dittoCore.ditto_auth_client_login_with_credentials(ditto, usernameBytes, passwordBytes, providerBytes)
1085
- if (errorCode !== 0) throw new Error(errorMessage() || `Ditto failed to authenticate (error code: ${errorCode}).`)
1086
- }
1087
-
1088
- export async function dittoAuthClientLogout(ditto: Pointer<FFIDitto>) {
1089
- trace()
1090
- ensureInitialized()
1091
-
1092
- const errorCode = await dittoCore.ditto_auth_client_logout(ditto)
1093
- if (errorCode !== 0) throw new Error(errorMessage() || `Ditto failed to logout (error code: ${errorCode}).`)
1094
- }
1095
-
1096
- // ---------------------------------------------------------------- Ditto ------
1097
-
1098
- /** @internal */
1099
- export function dittoMake(path: string, identityConfig: Pointer<FFIIdentityConfig>, historyTracking: string): Pointer<FFIDitto> {
1100
- trace()
1101
- ensureInitialized()
1102
-
1103
- const pathPointer = bytesFromString(path)
1104
- return dittoCore.ditto_make(pathPointer, identityConfig, historyTracking)
1105
- }
1106
-
1107
- /** @internal */
1108
- export async function dittoGetCollectionNames(self: Pointer<FFIDitto>): Promise<string[]> {
1109
- trace()
1110
- ensureInitialized()
1111
-
1112
- const result = await dittoCore.ditto_get_collection_names(self)
1113
- const errorCode = result.status_code
1114
- const cStringVec: { ptr: Pointer<'char *'>; len: number; cap: number } = result.names
1115
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_get_collection_names() failed with error code: ${errorCode}`)
1116
-
1117
- const strings: string[] = dittoCore.cStringVecToStringArray(cStringVec) as string[]
1118
- return strings
1119
- }
1120
-
1121
- /** @internal */
1122
- export function dittoFree(self: Pointer<FFIDitto>) {
1123
- trace()
1124
- ensureInitialized()
1125
-
1126
- // REFACTOR: add proper error handling.
1127
- return dittoCore.ditto_free(self)
1128
- }
1129
-
1130
- /** @internal */
1131
- export function getDeadlockTimeout(): number {
1132
- trace()
1133
- ensureInitialized()
1134
-
1135
- return dittoCore.getDeadlockTimeout()
1136
- }
1137
-
1138
- /** @internal */
1139
- export function setDeadlockTimeout(duration: number): void {
1140
- trace()
1141
- ensureInitialized()
1142
-
1143
- dittoCore.setDeadlockTimeout(duration)
1144
- }
1145
-
1146
- /** @internal */
1147
- export function dittoRegisterPresenceV1Callback(self: Pointer<FFIDitto>, cb: (json: string) => void): void {
1148
- trace()
1149
- ensureInitialized()
1150
-
1151
- dittoCore.ditto_register_presence_v1_callback(
1152
- self,
1153
- wrapBackgroundCbForFFI(
1154
- (err) => log('Error', `The registered presence callback v1 errored with ${err}`),
1155
- (cJsonStr: Pointer<'char'>) => {
1156
- const jsonStr: string = dittoCore.refCStringToString(cJsonStr)
1157
- cb(jsonStr)
1158
- },
1159
- ),
1160
- )
1161
- }
1162
-
1163
- /** @internal */
1164
- export async function dittoClearPresenceCallback(self: Pointer<FFIDitto>): Promise<void> {
1165
- trace()
1166
- ensureInitialized()
1167
-
1168
- return dittoCore.ditto_clear_presence_callback(self)
1169
- }
1170
-
1171
- /** @internal */
1172
- export function dittoRegisterPresenceV3Callback(self: Pointer<FFIDitto>, cb: (json: string) => void): void {
1173
- trace()
1174
- ensureInitialized()
1175
-
1176
- dittoCore.ditto_register_presence_v3_callback(
1177
- self,
1178
- wrapBackgroundCbForFFI(
1179
- (err) => log('Error', `The registered presence callback v3 errored with ${err}`),
1180
- (cJsonStr: Pointer<'char'>) => {
1181
- const jsonStr: string = dittoCore.refCStringToString(cJsonStr)
1182
- cb(jsonStr)
1183
- },
1184
- ),
1185
- )
1186
- }
1187
-
1188
- /** @internal */
1189
- export async function dittoClearPresenceV3Callback(self: Pointer<FFIDitto>): Promise<void> {
1190
- trace()
1191
- ensureInitialized()
1192
-
1193
- return dittoCore.ditto_clear_presence_v3_callback(self)
1194
- }
1195
-
1196
- /** @internal */
1197
- export function presencePeerMetadataJSON(self: Pointer<FFIDitto>): string {
1198
- trace()
1199
- ensureInitialized()
1200
-
1201
- const result = dittoCore.dittoffi_presence_peer_metadata_json(self)
1202
- const typedArray = dittoCore.boxCBytesIntoBuffer(result)
1203
- const textDecoder = new TextDecoder()
1204
- return textDecoder.decode(typedArray)
1205
- }
1206
-
1207
- /** @internal */
1208
- export async function presenceTrySetPeerMetadataJSON(self: Pointer<FFIDitto>, jsonString: string) {
1209
- trace()
1210
- ensureInitialized()
1211
-
1212
- const jsonDataCString = bytesFromString(jsonString)
1213
- const result = await dittoCore.dittoffi_presence_try_set_peer_metadata_json(self, jsonDataCString)
1214
- throwOnErrorResult(result.error, 'dittoffi_presence_try_set_peer_metadata_json')
1215
- }
1216
-
1217
- /** @internal */
1218
- export function connectionRequestPeerKeyString(connectionRequest: Pointer<FFIConnectionRequest>): string {
1219
- trace()
1220
- ensureInitialized()
1221
-
1222
- const cString = dittoCore.dittoffi_connection_request_peer_key_string(connectionRequest)
1223
- return dittoCore.boxCStringIntoString(cString)
1224
- }
1225
-
1226
- /** @internal */
1227
- export function connectionRequestPeerMetadataJSON(connectionRequest: Pointer<FFIConnectionRequest>): string {
1228
- trace()
1229
- ensureInitialized()
1230
-
1231
- const jsonByteRef = dittoCore.dittoffi_connection_request_peer_metadata_json(connectionRequest)
1232
- const jsonBuffer = dittoCore.refCBytesIntoBuffer(jsonByteRef)
1233
- const textDecoder = new TextDecoder()
1234
- return textDecoder.decode(jsonBuffer)
1235
- }
1236
-
1237
- /** @internal */
1238
- export function connectionRequestIdentityServiceMetadataJSON(connectionRequest: Pointer<FFIConnectionRequest>): string {
1239
- trace()
1240
- ensureInitialized()
1241
-
1242
- const jsonBytesRef = dittoCore.dittoffi_connection_request_identity_service_metadata_json(connectionRequest)
1243
- const jsonBuffer = dittoCore.refCBytesIntoBuffer(jsonBytesRef)
1244
- const textDecoder = new TextDecoder()
1245
- return textDecoder.decode(jsonBuffer)
1246
- }
1247
-
1248
- /** @internal */
1249
- export function connectionRequestConnectionType(connectionRequest: Pointer<FFIConnectionRequest>): Transport {
1250
- trace()
1251
- ensureInitialized()
1252
-
1253
- return dittoCore.dittoffi_connection_request_connection_type(connectionRequest)
1254
- }
1255
-
1256
- /** @internal */
1257
- export function connectionRequestAuthorize(connectionRequest: Pointer<FFIConnectionRequest>, authorization: ConnectionRequestAuthorization) {
1258
- trace()
1259
- ensureInitialized()
1260
-
1261
- dittoCore.dittoffi_connection_request_authorize(connectionRequest, authorization)
1262
- }
1263
-
1264
- /** @internal */
1265
- export function connectionRequestFree(connectionRequest: Pointer<FFIConnectionRequest>) {
1266
- trace()
1267
- ensureInitialized()
1268
-
1269
- dittoCore.dittoffi_connection_request_free(connectionRequest)
1270
- }
1271
-
1272
- /** @internal */
1273
- export function presenceSetConnectionRequestHandler(ditto: Pointer<FFIDitto>, connectionRequestHandler?: (connectionRequest: Pointer<FFIConnectionRequest>) => void, onError?: (err: any) => void) {
1274
- trace()
1275
- ensureInitialized()
1276
-
1277
- if (connectionRequestHandler == null) {
1278
- dittoCore.dittoffi_presence_set_connection_request_handler(ditto, null)
1279
- } else {
1280
- const wrappedCallback = wrapAsyncBackgroundCbForFFI(onError, connectionRequestHandler)
1281
- dittoCore.dittoffi_presence_set_connection_request_handler(ditto, wrappedCallback)
1282
- }
1283
- }
1284
-
1285
- /** @internal */
1286
- export function dittoSmallPeerInfoGetIsEnabled(dittoPointer: Pointer<FFIDitto>): boolean {
1287
- trace()
1288
- ensureInitialized()
1289
-
1290
- return dittoCore.ditto_small_peer_info_get_is_enabled(dittoPointer)
1291
- }
1292
-
1293
- /** @internal */
1294
- export async function dittoSmallPeerInfoSetEnabled(dittoPointer: Pointer<FFIDitto>, isEnabled: boolean): Promise<void> {
1295
- trace()
1296
- ensureInitialized()
1297
-
1298
- dittoCore.ditto_small_peer_info_set_enabled(dittoPointer, isEnabled)
1299
- }
1300
-
1301
- /** @internal */
1302
- export async function dittoSmallPeerInfoGetSyncScope(dittoPointer: Pointer<FFIDitto>): Promise<FFISmallPeerInfoSyncScope> {
1303
- trace()
1304
- ensureInitialized()
1305
-
1306
- return dittoCore.ditto_small_peer_info_get_sync_scope(dittoPointer)
1307
- }
1308
-
1309
- /** @internal */
1310
- export async function dittoSmallPeerInfoSetSyncScope(dittoPointer: Pointer<FFIDitto>, syncScope: FFISmallPeerInfoSyncScope): Promise<void> {
1311
- trace()
1312
- ensureInitialized()
1313
-
1314
- return dittoCore.ditto_small_peer_info_set_sync_scope(dittoPointer, syncScope)
1315
- }
1316
-
1317
- /** @internal */
1318
- export function dittoSmallPeerInfoGetMetadata(dittoPointer: Pointer<FFIDitto>): string {
1319
- trace()
1320
- ensureInitialized()
1321
-
1322
- const cString = dittoCore.ditto_small_peer_info_get_metadata(dittoPointer)
1323
- return dittoCore.boxCStringIntoString(cString)
1324
- }
1325
-
1326
- /** @internal */
1327
- export function dittoSmallPeerInfoSetMetadata(dittoPointer: Pointer<FFIDitto>, metadata: string): void {
1328
- trace()
1329
- ensureInitialized()
1330
-
1331
- const metadataCString = bytesFromString(metadata)
1332
- const statusCode = dittoCore.ditto_small_peer_info_set_metadata(dittoPointer, metadataCString)
1333
- switch (statusCode) {
1334
- case 0:
1335
- return
1336
- case -1:
1337
- throw new Error('Internal inconsistency, the observability subsystem is unavailable.')
1338
- case 1:
1339
- throw new Error(`Validation error, size limit exceeded: ${errorMessage() || 'metadata is too big'}`)
1340
- case 2:
1341
- throw new Error(`Validation error, ${errorMessage() || 'depth limit for metadata object exceeded'}`)
1342
- case 3:
1343
- throw new Error(`Validation error, ${errorMessage() || `'${metadata}' is not a valid JSON object`}`)
1344
- default:
1345
- throw new Error(errorMessage() || `Internal inconsistency, ditto_small_peer_info_set_metadata() returned an unknown error code: ${statusCode}`)
1346
- }
1347
- }
1348
-
1349
- /** @internal */
1350
- export function dittoSmallPeerInfoCollectionSetTransportConfigData(self: Pointer<FFIDitto>, transportConfigData: Uint8Array): void {
1351
- trace()
1352
- ensureInitialized()
1353
-
1354
- dittoCore.ditto_small_peer_info_set_transport_config_data(self, transportConfigData)
1355
- }
1356
-
1357
- /** @internal */
1358
- export function dittoRegisterTransportConditionChangedCallback(self: Pointer<FFIDitto>, cb: null | ((ConditionSource, TransportCondition) => void)) {
1359
- trace()
1360
- ensureInitialized()
1361
-
1362
- if (!cb) {
1363
- dittoCore.ditto_register_transport_condition_changed_callback(self, null)
1364
- } else {
1365
- dittoCore.ditto_register_transport_condition_changed_callback(
1366
- self,
1367
- wrapBackgroundCbForFFI((err) => log('Error', `The registered "transport condition changed" callback errored with ${err}`), cb),
1368
- )
1369
- }
1370
- }
1371
-
1372
- /** @internal */
1373
- export function dittoSetDeviceName(dittoPointer: Pointer<FFIDitto>, deviceName: string): string {
1374
- trace()
1375
- ensureInitialized()
1376
-
1377
- const deviceNameCString = bytesFromString(deviceName)
1378
- const truncatedDeviceNameCString = dittoCore.ditto_set_device_name(dittoPointer, deviceNameCString)
1379
- return dittoCore.boxCStringIntoString(truncatedDeviceNameCString)
1380
- }
1381
-
1382
- /** @internal */
1383
- export function dittoSetConnectRetryInterval(dittoPointer: Pointer<FFIDitto>, retryInterval: number) {
1384
- trace()
1385
- ensureInitialized()
1386
-
1387
- // Unfortunately JS doesn't have a u32::MAX const...
1388
- const UINT32_MAX = 4_294_967_295
1389
- // Clamp the provided interval to u32 range (0 .. 2^32-1).
1390
- const clampedInterval = Math.min(Math.max(0, retryInterval), UINT32_MAX)
1391
-
1392
- return dittoCore.ditto_set_connect_retry_interval(dittoPointer, clampedInterval)
1393
- }
1394
-
1395
- /** @internal */
1396
- export function dittoSetSyncGroup(dittoPointer: Pointer<FFIDitto>, syncGroup: number) {
1397
- trace()
1398
- ensureInitialized()
1399
-
1400
- return dittoCore.ditto_set_sync_group(dittoPointer, syncGroup)
1401
- }
1402
-
1403
- // Not supported on Wasm.
1404
- /** @internal */
1405
- export function dittoNewAttachmentFromFile(ditto: Pointer<FFIDitto>, sourcePath: string, fileOperation: AttachmentFileOperation): RawAttachment {
1406
- trace()
1407
- ensureInitialized()
1408
-
1409
- const sourcePathCString = bytesFromString(sourcePath)
1410
- const outAttachment: any = {}
1411
- const errorCode = dittoCore.ditto_new_attachment_from_file(ditto, sourcePathCString, fileOperation, outAttachment)
1412
- if (errorCode !== 0) {
1413
- throw new DittoFFIError(errorCode, null, `ditto_new_attachment_from_file() failed with error code: ${errorCode}`)
1414
- }
1415
- return outAttachment
1416
- }
1417
-
1418
- /** @internal */
1419
- export async function dittoNewAttachmentFromBytes(ditto: Pointer<FFIDitto>, bytes: Uint8Array): Promise<RawAttachment> {
1420
- trace()
1421
- ensureInitialized()
1422
-
1423
- const outAttachment: any = {}
1424
- const errorCode = await dittoCore.ditto_new_attachment_from_bytes(ditto, bytes, outAttachment)
1425
- if (errorCode !== 0) {
1426
- throw new DittoFFIError(errorCode, null, `ditto_new_attachment_from_bytes() failed with error code: ${errorCode}`)
1427
- }
1428
- return outAttachment
1429
- }
1430
-
1431
- /**
1432
- * @throws {@link DittoFFIError}
1433
- * @internal
1434
- */
1435
- export async function dittoResolveAttachment(
1436
- ditto: Pointer<FFIDitto>,
1437
- id: Uint8Array,
1438
- namedCallbacks: {
1439
- onComplete: (attachmentHandlePointer: Pointer<AttachmentHandle>) => void
1440
- onProgress: (downloaded: number | BigInt, toDownload: number | BigInt) => void
1441
- onDelete: () => void
1442
- },
1443
- // Cb may be called in parallel at any point, so let's use
1444
- // an optional error handler (which defaults to the ditto logger at 'Error' level).
1445
- onError?: (error: any) => void,
1446
- ): Promise<number | BigInt> {
1447
- trace()
1448
- ensureInitialized()
1449
-
1450
- const { onComplete, onProgress, onDelete } = namedCallbacks
1451
-
1452
- const wrappedOnComplete = wrapBackgroundCbForFFI(onError, onComplete)
1453
- const wrappedOnProgress = wrapBackgroundCbForFFI(onError, onProgress)
1454
- const wrappedOnDelete = wrapBackgroundCbForFFI(onError, onDelete)
1455
-
1456
- const { status_code: errorCode, cancel_token: cancelToken } = await dittoCore.ditto_resolve_attachment(ditto, id, wrappedOnComplete, wrappedOnProgress, wrappedOnDelete)
1457
- if (errorCode !== 0) {
1458
- throw new DittoFFIError(errorCode, null, `ditto_resolve_attachment() failed with error code: ${errorCode}`)
1459
- }
1460
-
1461
- return cancelToken
1462
- }
1463
-
1464
- /** @internal */
1465
- export function dittoCancelResolveAttachment(dittoPointer: Pointer<FFIDitto>, id: Uint8Array, cancelToken: number | BigInt) {
1466
- trace()
1467
- ensureInitialized()
1468
-
1469
- const errorCode = dittoCore.ditto_cancel_resolve_attachment(dittoPointer, id, cancelToken)
1470
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_cancel_resolve_attachment() failed with error code: ${errorCode}`)
1471
- }
1472
-
1473
- /** @internal */
1474
- export function freeAttachmentHandle(attachmentHandlePointer: Pointer<AttachmentHandle>) {
1475
- trace()
1476
- ensureInitialized()
1477
- dittoCore.ditto_free_attachment_handle(attachmentHandlePointer)
1478
- }
1479
-
1480
- /** @internal */
1481
- export async function dittoGetAttachmentStatus(dittoPointer: Pointer<FFIDitto>, id: Uint8Array): Promise<Pointer<AttachmentHandle>> {
1482
- trace()
1483
- ensureInitialized()
1484
-
1485
- const { status_code: errorCode, handle: attachmentHandle } = await dittoCore.ditto_get_attachment_status(dittoPointer, id)
1486
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_get_attachment_status() failed with error code: ${errorCode}`)
1487
- return attachmentHandle
1488
- }
1489
-
1490
- /** @internal */
1491
- export async function dittoGetCompleteAttachmentData(dittoPointer: Pointer<FFIDitto>, attachmentHandlePointer: Pointer<AttachmentHandle>): Promise<Uint8Array> {
1492
- trace()
1493
- ensureInitialized()
1494
-
1495
- const { status: errorCode, data } = await dittoCore.ditto_get_complete_attachment_data(dittoPointer, attachmentHandlePointer)
1496
- if (errorCode !== 0) throw new Error(errorMessage() || `\`ditto_get_complete_attachment_data()\` failed with error code: ${errorCode}`)
1497
- return dittoCore.boxCBytesIntoBuffer(data)
1498
- }
1499
-
1500
- /** @internal */
1501
- export function dittoGetCompleteAttachmentPath(dittoPointer: Pointer<FFIDitto>, attachmentHandlePointer: Pointer<AttachmentHandle>): string {
1502
- trace()
1503
- ensureInitialized()
1504
-
1505
- const pathCString = dittoCore.ditto_get_complete_attachment_path(dittoPointer, attachmentHandlePointer)
1506
- return dittoCore.refCStringToString(pathCString)
1507
- }
1508
-
1509
- /** @internal */
1510
- export function dittoGetSDKVersion(ditto: Pointer<FFIDitto>): string {
1511
- trace()
1512
- ensureInitialized()
1513
-
1514
- const cString = dittoCore.ditto_get_sdk_version(ditto)
1515
- return dittoCore.boxCStringIntoString(cString)
1516
- }
1517
-
1518
- /** @internal */
1519
- export function dittoGetSDKSemver(): string {
1520
- trace()
1521
- ensureInitialized()
1522
-
1523
- const cString = dittoCore.dittoffi_get_sdk_semver()
1524
- return dittoCore.boxCStringIntoString(cString)
1525
- }
1526
-
1527
- /** @internal */
1528
- export function dittoPresenceV1(self: Pointer<FFIDitto>): string {
1529
- trace()
1530
- ensureInitialized()
1531
-
1532
- const cString = dittoCore.ditto_presence_v1(self)
1533
- return dittoCore.boxCStringIntoString(cString)
1534
- }
1535
-
1536
- /** @internal */
1537
- export function dittoPresenceV2(self: Pointer<FFIDitto>): string {
1538
- trace()
1539
- ensureInitialized()
1540
-
1541
- const cString = dittoCore.ditto_presence_v2(self)
1542
- return dittoCore.boxCStringIntoString(cString)
1543
- }
1544
-
1545
- /** @internal */
1546
- export function dittoPresenceV3(self: Pointer<FFIDitto>): string {
1547
- trace()
1548
- ensureInitialized()
1549
-
1550
- const cString = dittoCore.ditto_presence_v3(self)
1551
- return dittoCore.boxCStringIntoString(cString)
1552
- }
1553
-
1554
- /** @internal */
1555
- export function dittoStartTCPServer(dittoPointer: Pointer<FFIDitto>, bind: string) {
1556
- trace()
1557
- ensureInitialized()
1558
-
1559
- const bindBuffer = bytesFromString(bind)
1560
- return dittoCore.ditto_start_tcp_server(dittoPointer, bindBuffer)
1561
- }
1562
-
1563
- /** @internal */
1564
- export function dittoStopTCPServer(dittoPointer: Pointer<FFIDitto>) {
1565
- trace()
1566
- ensureInitialized()
1567
-
1568
- return dittoCore.ditto_stop_tcp_server(dittoPointer)
1569
- }
1570
-
1571
- /** @internal */
1572
- export async function dittoShutdown(dittoPointer: Pointer<FFIDitto>): Promise<void> {
1573
- trace()
1574
- ensureInitialized()
1575
-
1576
- return await dittoCore.ditto_shutdown(dittoPointer)
1577
- }
1578
-
1579
- /** @internal */
1580
- export function dittoAddMulticastTransport(dittoPointer: Pointer<FFIDitto>) {
1581
- trace()
1582
- ensureInitialized()
1583
-
1584
- return dittoCore.ditto_add_multicast_transport(dittoPointer)
1585
- }
1586
-
1587
- /** @internal */
1588
- export function dittoRemoveMulticastTransport(dittoPointer: Pointer<FFIDitto>) {
1589
- trace()
1590
- ensureInitialized()
1591
-
1592
- return dittoCore.ditto_remove_multicast_transport(dittoPointer)
1593
- }
1594
-
1595
- /** @internal */
1596
- export function dittoStartHTTPServer(dittoPointer: Pointer<FFIDitto>, bind: string, staticPath: string | null, websocketMode: WebsocketMode, tlsCertPath: string | null, tlsKeyPath: string | null) {
1597
- trace()
1598
- ensureInitialized()
1599
-
1600
- const bindBuffer = bytesFromString(bind)
1601
- const staticPathBuffer = bytesFromString(staticPath)
1602
- const tlsCertPathBuffer = bytesFromString(tlsCertPath)
1603
- const tlsKeyPathBuffer = bytesFromString(tlsKeyPath)
1604
- return dittoCore.ditto_start_http_server(dittoPointer, bindBuffer, staticPathBuffer, websocketMode, tlsCertPathBuffer, tlsKeyPathBuffer)
1605
- }
1606
-
1607
- /** @internal */
1608
- export function dittoStopHTTPServer(dittoPointer: Pointer<FFIDitto>) {
1609
- trace()
1610
- ensureInitialized()
1611
- return dittoCore.ditto_stop_http_server(dittoPointer)
1612
- }
1613
-
1614
- /** @internal */
1615
- export function dittoRunGarbageCollection(dittoPointer: Pointer<FFIDitto>) {
1616
- trace()
1617
- ensureInitialized()
1618
- return dittoCore.ditto_run_garbage_collection(dittoPointer)
1619
- }
1620
-
1621
- /** @internal */
1622
- export async function dittoDisableSyncWithV3(dittoPointer: Pointer<FFIDitto>): Promise<void> {
1623
- trace()
1624
- ensureInitialized()
1625
- const errorCode = await dittoCore.ditto_disable_sync_with_v3(dittoPointer)
1626
- if (errorCode !== 0) throw new Error(errorMessage() || `ditto_disable_sync_with_v3() failed with error code: ${errorCode}`)
1627
- }
1628
-
1629
- export function dittoSetStaticTCPClients(ditto: Pointer<FFIDitto>, listOfServers: string[]) {
1630
- trace()
1631
- ensureInitialized()
1632
-
1633
- if (Environment.isNodeBuild) {
1634
- const listOfServersBytes = listOfServers.map((server) => bytesFromString(server))
1635
- dittoCore.ditto_set_static_tcp_clients(ditto, listOfServersBytes)
1636
- }
1637
-
1638
- if (Environment.isWebBuild) {
1639
- if (listOfServers.length > 0) {
1640
- throw new Error(`Web variant of Ditto does not support connecting to TCP servers: ${listOfServers.join(', ')}`)
1641
- }
1642
- }
1643
- }
1644
-
1645
- export function dittoSetStaticWebsocketClients(ditto: Pointer<FFIDitto>, listOfServers: string[], routingHint: number) {
1646
- trace()
1647
- ensureInitialized()
1648
- const listOfServersBytes = listOfServers.map((server) => bytesFromString(server))
1649
- dittoCore.ditto_set_static_websocket_clients(ditto, listOfServersBytes, routingHint)
1650
- }
1651
-
1652
- // ------------------------------------------------------ Hash & Mnemonic ------
1653
-
1654
- /** @internal */
1655
- export function documentsHash(documents: Pointer<FFIDocument>[]): BigInt {
1656
- trace()
1657
- ensureInitialized()
1658
- const { status_code: errorCode, u64: hash } = dittoCore.ditto_documents_hash(documents)
1659
- if (errorCode !== 0) throw new Error(errorMessage() || `\`ditto_documents_hash()\` failed with error code: ${errorCode}`)
1660
- // `hash` is of type `number | BigInt`, let's unify it to `BigInt` to keep it simple.
1661
- return BigInt(hash)
1662
- }
1663
-
1664
- /** @internal */
1665
- export function documentsHashMnemonic(documents: Pointer<FFIDocument>[]): string {
1666
- trace()
1667
- ensureInitialized()
1668
- const { status_code: errorCode, c_string } = dittoCore.ditto_documents_hash_mnemonic(documents)
1669
- if (errorCode !== 0) throw new Error(errorMessage() || `\`ditto_documents_hash_mnemonic()\` failed with error code: ${errorCode}`)
1670
- return dittoCore.boxCStringIntoString(c_string)
1671
- }
1672
-
1673
- // ------------------------------------------------------------- base64 --------
1674
-
1675
- /** @internal */
1676
- export function base64encode(bytes: Uint8Array, paddingMode: Base64PaddingMode): string {
1677
- const base64CString = dittoCore.dittoffi_base64_encode(bytes, paddingMode)
1678
- return dittoCore.boxCStringIntoString(base64CString)
1679
- }
1680
-
1681
- /**
1682
- * @throws {@link DittoFFIError} if the base64 string is invalid
1683
- * @internal
1684
- */
1685
- export function tryBase64Decode(base64: string, paddingMode?: Base64PaddingMode): Uint8Array {
1686
- const base64BytesPointer = bytesFromString(base64)
1687
- const result = dittoCore.dittoffi_try_base64_decode(base64BytesPointer, paddingMode || null)
1688
- throwOnErrorResult(result.error, 'dittoffi_try_base64_decode')
1689
- return dittoCore.boxCBytesIntoBuffer(result.success)
1690
- }
1691
-
1692
- // ------------------------------------------------------------- Auth ----------
1693
-
1694
- /** @internal */
1695
- export function authServerAuthSubmitWithSuccess(req: Pointer<FFIAuthServerAuthRequest>, successCbor: Uint8Array): void {
1696
- trace()
1697
- ensureInitialized()
1698
- return dittoCore.auth_server_auth_submit_with_success(req, successCbor)
1699
- }
1700
-
1701
- /** @internal */
1702
- export function authServerAuthSubmitWithError(req: Pointer<FFIAuthServerAuthRequest>, errorCode: number): void {
1703
- trace()
1704
- ensureInitialized()
1705
- return dittoCore.auth_server_auth_submit_with_error(req, errorCode)
1706
- }
1707
-
1708
- /** @internal */
1709
- export function authServerRefreshSubmitWithSuccess(req: Pointer<FFIAuthServerRefreshRequest>, successCbor: Uint8Array): void {
1710
- trace()
1711
- ensureInitialized()
1712
- return dittoCore.auth_server_refresh_submit_with_success(req, successCbor)
1713
- }
1714
-
1715
- /** @internal */
1716
- export function authServerRefreshSubmitWithError(req: Pointer<FFIAuthServerRefreshRequest>, errorCode: number): void {
1717
- trace()
1718
- ensureInitialized()
1719
- return dittoCore.auth_server_refresh_submit_with_error(req, errorCode)
1720
- }
1721
-
1722
- /** @internal */
1723
- export function dittoUnregisterLocalAuthServer(ditto: Pointer<FFIDitto>): void {
1724
- trace()
1725
- ensureInitialized()
1726
- return dittoCore.ditto_unregister_local_auth_server(ditto)
1727
- }
1728
-
1729
- /** @internal */
1730
- export function dittoRegisterLocalAuthServer(namedArgs: {
1731
- ditto: Pointer<FFIDitto>
1732
- signingKeyPem: string
1733
- verifyingKeysPem: string[]
1734
- caKeyPem?: string
1735
- authCb: (authRequest: Pointer<FFIAuthServerAuthRequest>, cbor: Uint8Array) => void
1736
- refreshCb: (authRequest: Pointer<FFIAuthServerRefreshRequest>, cbor: Uint8Array) => void
1737
- // Cb may be called in parallel at any point, so let's use
1738
- // an optional error handler
1739
- onError?: (error: any) => void
1740
- }): void {
1741
- const { ditto, signingKeyPem, verifyingKeysPem, caKeyPem, authCb, refreshCb, onError } = namedArgs
1742
- trace()
1743
- ensureInitialized()
1744
-
1745
- const signingKeyPemFfi = bytesFromString(signingKeyPem)
1746
- const verifyingKeysPemFfi = verifyingKeysPem.map(bytesFromString)
1747
- const caKeyPemFfi = typeof caKeyPem !== 'undefined' ? bytesFromString(caKeyPem) : null
1748
- const authCbFfi = wrapBackgroundCbForFFI(onError, authCb)
1749
- const refreshCbFfi = wrapBackgroundCbForFFI(onError, refreshCb)
1750
- return dittoCore.ditto_register_local_auth_server(ditto, signingKeyPemFfi, verifyingKeysPemFfi, caKeyPemFfi, authCbFfi, refreshCbFfi)
1751
- }
1752
-
1753
- /** @internal */
1754
- export async function dittoAuthSetLoginProvider(ditto: Pointer<FFIDitto>, loginProvider: Pointer<FFILoginProvider>): Promise<void> {
1755
- trace()
1756
- ensureInitialized()
1757
-
1758
- return await dittoCore.ditto_auth_set_login_provider(ditto, loginProvider)
1759
- }
1760
-
1761
- /** @internal */
1762
- export function dittoAuthClientMakeLoginProvider(
1763
- expiringCb: (secs_until_expiry: number) => void,
1764
- // Cb may be called in parallel at any point, so let's use an optional error handler
1765
- onError?: (error: any) => void,
1766
- ): Pointer<FFILoginProvider> {
1767
- trace()
1768
- ensureInitialized()
1769
-
1770
- return dittoCore.ditto_auth_client_make_login_provider(wrapBackgroundCbForFFI(onError, expiringCb))
1771
- }
1772
-
1773
- /** @internal */
1774
- export function dittoAuthClientSetValidityListener(
1775
- ditto: Pointer<FFIDitto>,
1776
- validityUpdateCb: (isWebValid: boolean, isX509Valid: boolean) => void,
1777
- // Cb may be called in parallel at any point, so let's use an optional error handler
1778
- onError?: (error: any) => void,
1779
- ): void {
1780
- trace()
1781
- ensureInitialized()
1782
-
1783
- const validityUpdateRawCb = wrapBackgroundCbForFFI(onError, function (isWebValidInt: number, isX509ValidInt: number) {
1784
- return validityUpdateCb(isWebValidInt === 1, isX509ValidInt === 1)
1785
- })
1786
-
1787
- return dittoCore.ditto_auth_client_set_validity_listener(ditto, validityUpdateRawCb)
1788
- }
1789
-
1790
- // ----------------------------------------------------------- Transports ------
1791
-
1792
- /**
1793
- * We currently don't initialize transports through this function but rather in
1794
- * the NAPI module registration in `transports.c` due to an issue with importing
1795
- * the functions required by this function.
1796
- * See https://github.com/getditto/ditto/issues/10723
1797
- *
1798
- * @internal
1799
- */
1800
- export function transportsInit(): void {
1801
- trace()
1802
- ensureInitialized()
1803
-
1804
- // The symbols called below are not exported in the Wasm build.
1805
- if (Environment.isWebBuild) return
1806
-
1807
- const { output: wasInitialized, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_init)
1808
- if (wasInitialized === false) {
1809
- throw new Error(`Failed to initialize transports (${errorType} error)`)
1810
- }
1811
- }
1812
-
1813
- /** @internal */
1814
- export function transportsBLEIsAvailable(ditto: Pointer<FFIDitto>): boolean {
1815
- trace()
1816
- ensureInitialized()
1817
-
1818
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
1819
- return dittoCore.ditto_sdk_transports_ble_is_available(ditto)
1820
- }
1821
- return false
1822
- }
1823
-
1824
- /** @internal */
1825
- export function transportsBLECreate(ditto: Pointer<FFIDitto>): Pointer<TransportBluetooth> | null | void {
1826
- trace()
1827
- ensureInitialized()
1828
-
1829
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
1830
- const { output: blePointer, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_ble_create, ditto)
1831
-
1832
- if (blePointer != null) {
1833
- log('Info', `Bluetooth transport created.`)
1834
- } else {
1835
- log('Error', `Can't create bluetooth transport (${errorType} error).`)
1836
- }
1837
-
1838
- return blePointer
1839
- }
1840
- }
1841
-
1842
- /** @internal */
1843
- export function transportsBLEDestroy(ble: Pointer<TransportBluetooth>): boolean | void {
1844
- trace()
1845
- ensureInitialized()
1846
-
1847
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
1848
- const { output: wasDestroyed, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_ble_destroy, ble)
1849
-
1850
- if (wasDestroyed === true) {
1851
- log('Info', 'Bluetooth transport disabled.')
1852
- } else {
1853
- log('Error', `Bluetooth transport could not be disabled (${errorType} error).`)
1854
- }
1855
- return wasDestroyed
1856
- }
1857
- }
1858
-
1859
- /** @internal */
1860
- export function transportsLANIsAvailable(ditto: Pointer<FFIDitto>): boolean {
1861
- trace()
1862
- ensureInitialized()
1863
-
1864
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
1865
- return dittoCore.ditto_sdk_transports_lan_is_available(ditto)
1866
- }
1867
- return false
1868
- }
1869
-
1870
- /** @internal */
1871
- export function transportsLANCreate(ditto: Pointer<FFIDitto>): Pointer<TransportLAN> | void {
1872
- trace()
1873
- ensureInitialized()
1874
-
1875
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
1876
- const { output: lanPointer, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_lan_create, ditto)
1877
-
1878
- if (lanPointer != null) {
1879
- log('Info', `LAN transport created.`)
1880
- } else {
1881
- log('Error', `Can't create LAN transport (${errorType} error).`)
1882
- }
1883
-
1884
- return lanPointer
1885
- }
1886
- }
1887
-
1888
- /** @internal */
1889
- export function transportsLANDestroy(lan: Pointer<TransportLAN>): boolean | void {
1890
- trace()
1891
- ensureInitialized()
1892
-
1893
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
1894
- const { output: wasDestroyed, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_lan_destroy, lan)
1895
-
1896
- if (wasDestroyed === true) {
1897
- log('Info', 'LAN transport disabled.')
1898
- } else {
1899
- log('Error', `LAN transport could not be disabled (${errorType} error).`)
1900
- }
1901
- return wasDestroyed
1902
- }
1903
- }
1904
-
1905
- /** @internal */
1906
- export function transportsAWDLIsAvailable(ditto: Pointer<FFIDitto>): boolean {
1907
- trace()
1908
- ensureInitialized()
1909
-
1910
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
1911
- return dittoCore.ditto_sdk_transports_awdl_is_available(ditto)
1912
- }
1913
- return false
1914
- }
1915
-
1916
- /** @internal */
1917
- export function transportsAWDLCreate(ditto: Pointer<FFIDitto>): Pointer<TransportAWDL> | null | void {
1918
- trace()
1919
- ensureInitialized()
1920
-
1921
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
1922
- const { output: awdlPointer, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_awdl_create, ditto)
1923
-
1924
- if (awdlPointer != null) {
1925
- log('Info', `AWDL transport created.`)
1926
- } else {
1927
- log('Error', `Can't create AWDL transport (${errorType} error).`)
1928
- }
1929
-
1930
- return awdlPointer
1931
- }
1932
- }
1933
-
1934
- /** @internal */
1935
- export function transportsAWDLDestroy(awdl: Pointer<TransportAWDL>): boolean | void {
1936
- trace()
1937
- ensureInitialized()
1938
-
1939
- if (Environment.isNodeBuild || Environment.isReactNativeBuild) {
1940
- const { output: wasDestroyed, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_awdl_destroy, awdl)
1941
-
1942
- if (wasDestroyed === true) {
1943
- log('Info', 'AWDL transport disabled.')
1944
- } else {
1945
- log('Error', `AWDL transport could not be disabled (${errorType} error).`)
1946
- }
1947
- return wasDestroyed
1948
- }
1949
- }
1950
-
1951
- /**
1952
- * Helper type that extracts all but the last parameter from a function type.
1953
- *
1954
- * NOTE: will accept any parameters for functions that don't have typed parameters.
1955
- */
1956
- // prettier-ignore
1957
- type ParametersExceptLast<F extends (...args: any[]) => any> = Parameters<F> extends [...infer U, any]
1958
- ? U
1959
- : any // FIXME: this should really be `never` but we don't have proper types for the FFI functions yet.
1960
-
1961
- /**
1962
- * Calls the given FFI function with the passed in arguments and a newly
1963
- * allocated `transportsErrorPointer` as the last argument, then returns its
1964
- * result.
1965
- *
1966
- * The given function MUST take a `transportsErrorPointer` as its last argument.
1967
- *
1968
- * @param ffiFunction The FFI function to wrap.
1969
- * @param args The arguments to pass to the FFI function, excluding the
1970
- * `transportsErrorPointer`.
1971
- * @returns An object with two properties: `output` and `errorType`. `output` is
1972
- * the return value of the FFI function, and `errorType` is the value of the
1973
- * `transportsErrorPointer` after the FFI function has been called.
1974
- */
1975
- function withTransportsError<T extends (...args: any[]) => any>(ffiFunction: T, ...args: ParametersExceptLast<T>): { output: ReturnType<T>; errorType: TransportsError } {
1976
- const transportsErrorPointer = dittoCore.ditto_sdk_transports_error_new()
1977
- const output = ffiFunction(...args, transportsErrorPointer)
1978
- const errorType: TransportsError = dittoCore.ditto_sdk_transports_error_value(transportsErrorPointer)
1979
- dittoCore.ditto_sdk_transports_error_free(transportsErrorPointer)
1980
- return { output, errorType }
1981
- }
1982
-
1983
- // ---------------------------------------------------------------- Other ------
1984
-
1985
- /** @internal */
1986
- let isInitialized = false
1987
-
1988
- if (Environment.isNodeBuild) {
1989
- isInitialized = true
1990
- }
1991
-
1992
- if (Environment.isReactNativeBuild) {
1993
- isInitialized = true
1994
- }
1995
-
1996
- /** @internal */
1997
- export async function init(webAssemblyModule?: WebAssemblyModule): Promise<void> {
1998
- if (Environment.isWebBuild) {
1999
- if (webAssemblyModule) {
2000
- await dittoCore.init(webAssemblyModule as any)
2001
- } else {
2002
- await dittoCore.init()
2003
- }
2004
-
2005
- isInitialized = true
2006
- }
2007
- }
2008
-
2009
- /** @internal */
2010
- export function initSDKVersion(platform: Platform, language: Language, semVer: string) {
2011
- trace()
2012
- ensureInitialized()
2013
-
2014
- const platformCString = bytesFromString(platform)
2015
- const languageCString = bytesFromString(language)
2016
- const semVerCString = bytesFromString(semVer)
2017
-
2018
- const errorCode = dittoCore.ditto_init_sdk_version(platform, language, semVerCString)
2019
- if (typeof errorCode !== 'undefined' && errorCode !== 0) throw new Error(errorMessage() || `ditto_init_sdk_version() failed with error code: ${errorCode}`)
2020
- }
2021
-
2022
- /** @internal */
2023
- export function tryVerifyLicense(license: string) {
2024
- trace()
2025
- ensureInitialized()
2026
-
2027
- const licenseBuffer = bytesFromString(license)
2028
- const result = dittoCore.dittoffi_try_verify_license(licenseBuffer)
2029
- throwOnErrorResult(result.error, 'dittoffi_try_verify_license')
2030
- }
2031
-
2032
- // ---------------------------------------------------- React Native only ------
2033
-
2034
- /** @internal */
2035
- export function defaultDeviceName(): string | void {
2036
- if (Environment.isReactNativeBuild) {
2037
- // @ts-expect-error Throws method not-found on non-RN envs.
2038
- return dittoCore.defaultDeviceName()
2039
- }
2040
- }
2041
-
2042
- /** @internal */
2043
- export function getRandomValues<T extends ArrayBufferView>(array: T): T | void {
2044
- if (Environment.isReactNativeBuild) {
2045
- // @ts-expect-error Throws method not-found on non-RN envs.
2046
- return dittoCore.getRandomValues(array)
2047
- }
2048
- }
2049
-
2050
- /** @internal */
2051
- export function createDirectory(path: string): string | void {
2052
- if (Environment.isReactNativeBuild) {
2053
- // @ts-expect-error Throws method not-found on non-RN envs.
2054
- return dittoCore.createDirectory(path)
2055
- }
2056
- }
2057
-
2058
- /** @internal */
2059
- export function readFile(path: string): string {
2060
- if (Environment.isReactNativeBuild) {
2061
- // @ts-expect-error Throws method not-found on non-RN envs.
2062
- return dittoCore.readFile(path)
2063
- }
2064
- }
2065
-
2066
- /** @internal */
2067
- export function copyFile(source: string, destination: string, dittoPath: string): string {
2068
- if (Environment.isReactNativeBuild) {
2069
- // @ts-expect-error Throws method not-found on non-RN envs.
2070
- return dittoCore.copyFile(source, destination, dittoPath)
2071
- }
2072
- }
2073
-
2074
- // -------------------------------------------------------------- Private ------
2075
-
2076
- /** @internal */
2077
- const NOT_FOUND_ERROR_CODE = -30798
2078
-
2079
- /** @internal */
2080
- // prettier-ignore
2081
- function wrapBackgroundCbForFFI<
2082
- F extends (...args: any[]) => any,
2083
- E extends (err: any) => void | null
2084
- >(onError: E, cb: F): (
2085
- ret_sender: (result: ReturnType<F>) => any, ...args: Parameters<F>
2086
- ) => any {
2087
- // There's no need to wrap callbacks through JSI while they are not returning
2088
- // anything.
2089
- if (Environment.isReactNativeBuild) {
2090
- return cb
2091
- }
2092
-
2093
- const errorHandler = onError ?? ((err: any) => log('Error', `The registered callback failed with ${err}`))
2094
-
2095
- return (ret_sender: (result: ReturnType<F>) => any, ...args: Parameters<F>) => {
2096
- let ret: ReturnType<F>
2097
- try {
2098
- ret = cb(...args)
2099
- } catch (err) {
2100
- try {
2101
- errorHandler(err)
2102
- } catch (nested_error) {
2103
- log('Error', `Internal error: \`onError()\` handler oughtn't throw, but it did throw ${nested_error}`)
2104
- }
2105
- }
2106
- return ret_sender(ret)
2107
- }
2108
- }
2109
-
2110
- /** @internal */
2111
- // prettier-ignore
2112
- function wrapAsyncBackgroundCbForFFI<
2113
- F extends (...args: any[]) => (Promise<any> | any),
2114
- E extends (err: any) => void | null
2115
- >(onError: E, cb: F): (
2116
- ret_sender: (result: ReturnType<F>) => unknown, ...args: Parameters<F>
2117
- ) => Promise<unknown> {
2118
- // There's no need to wrap callbacks through JSI while they are not returning
2119
- // anything.
2120
- if (Environment.isReactNativeBuild) {
2121
- return cb
2122
- }
2123
-
2124
- const errorHandler = onError ?? ((err: any) => log('Error', `The registered callback failed with ${err}`))
2125
-
2126
- return async (ret_sender: (result: ReturnType<F>) => any, ...args: Parameters<F>) => {
2127
- let ret: ReturnType<F>
2128
- try {
2129
- ret = await cb(...args)
2130
- } catch (err) {
2131
- try {
2132
- errorHandler(err)
2133
- } catch (nested_error) {
2134
- log('Error', `Internal error: \`onError()\` handler oughtn't throw, but it did throw ${nested_error}`)
2135
- }
2136
- }
2137
- return ret_sender(ret)
2138
- }
2139
- }
2140
-
2141
- /** @internal */
2142
- function bytesFromString(jsString: string | null | undefined): Uint8Array | null | undefined {
2143
- if (typeof jsString === 'undefined') return undefined
2144
- if (jsString === null) return null
2145
- if (typeof jsString !== 'string') throw new Error(`Can't convert string to Uint8Array, not a string: ${jsString}`)
2146
- const textEncoder = new TextEncoder()
2147
- return textEncoder.encode(`${jsString}\0`)
2148
- }
2149
-
2150
- /**
2151
- * This is the legacy error-message retrieving function, using thread-local
2152
- * storage.
2153
- *
2154
- * @internal
2155
- */
2156
- function errorMessage(): string {
2157
- trace()
2158
- ensureInitialized()
2159
-
2160
- // eslint-disable-next-line
2161
- const errorMessageCString = dittoCore.ditto_error_message()
2162
- return dittoCore.boxCStringIntoString(errorMessageCString)
2163
- }
2164
-
2165
- /** @internal */
2166
- function trace() {
2167
- if (isTracingEnabled) {
2168
- // Copied and adapted from a Stack Overflow comment:
2169
- // https://stackoverflow.com/a/38435618
2170
- const error = new Error()
2171
- const stack = error.stack
2172
- let caller = '<unknown>'
2173
- try {
2174
- caller = stack.split('\n')[2].trim().split(/\s+/)[1].replace('Module.', '')
2175
- } catch (error) {
2176
- // Nothing to do, caller remains unknown.
2177
- }
2178
-
2179
- // We use use `console.log()` instead of `log()` here to avoid infinite recursion.
2180
- // eslint-disable-next-line no-console
2181
- console.log(`💗 [TRACE] ${caller}()`)
2182
- }
2183
- }
2184
-
2185
- /** @internal */
2186
- function ensureInitialized() {
2187
- if (!isInitialized) {
2188
- throw new Error('Ditto needs to be initialized before using any of its API, please make sure to call `await init()` first.')
2189
- }
2190
- }