@dittolive/ditto 4.5.4-alpha.1 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DittoReactNative.podspec +5 -3
- package/README.md +2 -2
- package/node/ditto.cjs.js +1111 -563
- package/node/ditto.darwin-arm64.node +0 -0
- package/node/ditto.darwin-x64.node +0 -0
- package/node/ditto.linux-arm.node +0 -0
- package/node/ditto.linux-arm64.node +0 -0
- package/node/ditto.linux-x64.node +0 -0
- package/node/ditto.win32-x64.node +0 -0
- package/node/transports.darwin-arm64.node +0 -0
- package/node/transports.darwin-x64.node +0 -0
- package/package.json +3 -11
- package/react-native/android/CMakeLists.txt +0 -1
- package/react-native/android/build.gradle +7 -3
- package/react-native/android/cpp-adapter.cpp +68 -59
- package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +35 -0
- package/react-native/cpp/include/Arc.hpp +1 -1
- package/react-native/cpp/include/Attachment.h +5 -1
- package/react-native/cpp/include/DQL.h +9 -9
- package/react-native/cpp/include/FFIUtils.h +14 -0
- package/react-native/cpp/include/IO.h +13 -0
- package/react-native/cpp/include/Lifecycle.h +0 -1
- package/react-native/cpp/include/Misc.h +3 -0
- package/react-native/cpp/include/Utils.h +0 -2
- package/react-native/cpp/src/Attachment.cpp +200 -13
- package/react-native/cpp/src/Authentication.cpp +3 -3
- package/react-native/cpp/src/DQL.cpp +23 -23
- package/react-native/cpp/src/Document.cpp +10 -10
- package/react-native/cpp/src/FFIUtils.cpp +64 -0
- package/react-native/cpp/src/IO.cpp +35 -0
- package/react-native/cpp/src/Identity.cpp +3 -3
- package/react-native/cpp/src/Lifecycle.cpp +2 -19
- package/react-native/cpp/src/LiveQuery.cpp +3 -3
- package/react-native/cpp/src/Logger.cpp +171 -172
- package/react-native/cpp/src/Misc.cpp +52 -4
- package/react-native/cpp/src/Presence.cpp +1 -1
- package/react-native/cpp/src/SmallPeerInfo.cpp +1 -1
- package/react-native/cpp/src/Transports.cpp +10 -5
- package/react-native/cpp/src/Utils.cpp +110 -114
- package/react-native/cpp/src/main.cpp +28 -15
- package/react-native/dittoffi/dittoffi.h +328 -280
- package/react-native/ios/DittoRNSDK.mm +123 -71
- package/react-native/src/ditto.rn.ts +30 -6
- package/react-native/src/index.ts +7 -4
- package/react-native/src/sources/@cbor-redux.ts +1 -1
- package/react-native/src/sources/attachment-fetch-event.ts +2 -2
- package/react-native/src/sources/attachment-fetcher-manager.ts +5 -4
- package/react-native/src/sources/attachment-fetcher.ts +152 -21
- package/react-native/src/sources/attachment-token.ts +94 -13
- package/react-native/src/sources/attachment.ts +66 -19
- package/react-native/src/sources/augment.ts +13 -6
- package/react-native/src/sources/base-pending-cursor-operation.ts +22 -6
- package/react-native/src/sources/base-pending-id-specific-operation.ts +3 -0
- package/react-native/src/sources/bridge.ts +2 -2
- package/react-native/src/sources/cbor.ts +0 -15
- package/react-native/src/sources/collection-interface.ts +12 -6
- package/react-native/src/sources/collection.ts +9 -2
- package/react-native/src/sources/ditto.ts +26 -18
- package/react-native/src/sources/document-id.ts +11 -7
- package/react-native/src/sources/document-path.ts +4 -2
- package/react-native/src/sources/document.ts +49 -5
- package/react-native/src/sources/error-codes.ts +28 -0
- package/react-native/src/sources/error.ts +20 -1
- package/react-native/src/sources/essentials.ts +25 -3
- package/react-native/src/sources/ffi-error.ts +2 -1
- package/react-native/src/sources/ffi.ts +180 -102
- package/react-native/src/sources/internal.ts +37 -3
- package/react-native/src/sources/live-query-manager.ts +10 -1
- package/react-native/src/sources/live-query.ts +1 -1
- package/react-native/src/sources/observer-manager.ts +7 -0
- package/react-native/src/sources/pending-id-specific-operation.ts +2 -2
- package/react-native/src/sources/presence-manager.ts +12 -2
- package/react-native/src/sources/presence.ts +5 -0
- package/react-native/src/sources/query-result-item.ts +15 -0
- package/react-native/src/sources/small-peer-info.ts +2 -2
- package/react-native/src/sources/static-tcp-client.ts +2 -0
- package/react-native/src/sources/store-observer.ts +4 -2
- package/react-native/src/sources/store.ts +253 -3
- package/react-native/src/sources/sync.ts +6 -3
- package/react-native/src/sources/transport-config.ts +2 -2
- package/react-native/src/sources/update-results-map.ts +8 -0
- package/react-native/src/sources/write-transaction-collection.ts +1 -1
- package/react-native/src/sources/write-transaction.ts +1 -1
- package/types/ditto.d.ts +2866 -2568
- package/web/ditto.es6.js +1 -1
- package/web/ditto.umd.js +1 -1
- package/web/ditto.wasm +0 -0
- package/react-native/android/.project +0 -34
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import * as dittoCore from './@ditto.core'
|
|
14
14
|
import * as Environment from './@environment'
|
|
15
|
-
import { throwOnErrorResult } from './ffi-error'
|
|
15
|
+
import { DittoFFIError, throwOnErrorResult } from './ffi-error'
|
|
16
16
|
|
|
17
17
|
// -------------------------------------------------------------- Prelude ------
|
|
18
18
|
|
|
@@ -40,10 +40,10 @@ export type FFIWriteStrategy = 'merge' | 'insertIfAbsent' | 'insertDefaultIfAbse
|
|
|
40
40
|
export type FFIDocument = 'CDocument_t'
|
|
41
41
|
|
|
42
42
|
/** @internal */
|
|
43
|
-
export type FFIDqlResult = '
|
|
43
|
+
export type FFIDqlResult = 'dittoffi_query_result_item_t'
|
|
44
44
|
|
|
45
45
|
/** @internal */
|
|
46
|
-
export type FFIDqlResponse = '
|
|
46
|
+
export type FFIDqlResponse = 'dittoffi_query_result_t'
|
|
47
47
|
|
|
48
48
|
/** @internal */
|
|
49
49
|
export type FFIReadTransaction = 'CReadTransaction_t'
|
|
@@ -141,6 +141,9 @@ export enum DittoCRDTType {
|
|
|
141
141
|
rwMap = 4,
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
/** @internal */
|
|
145
|
+
export type Base64PaddingMode = 'Padded' | 'Unpadded'
|
|
146
|
+
|
|
144
147
|
/** @internal */
|
|
145
148
|
export type CBParamsDocs = {
|
|
146
149
|
documents: Pointer<FFIDocument>[]
|
|
@@ -180,7 +183,7 @@ export type RawAttachment = {
|
|
|
180
183
|
handle: Pointer<AttachmentHandle>
|
|
181
184
|
}
|
|
182
185
|
|
|
183
|
-
// -------------------------------------- Linux & Windows Transports ------
|
|
186
|
+
// -------------------------------------- Linux & Windows Transports Hack ------
|
|
184
187
|
|
|
185
188
|
export function dittoAddInternalBLEClientTransport(ditto: Pointer<FFIDitto>): any {
|
|
186
189
|
if (Environment.isNodeBuild) {
|
|
@@ -290,6 +293,7 @@ export function documentID(self: Pointer<FFIDocument>): Uint8Array {
|
|
|
290
293
|
trace()
|
|
291
294
|
ensureInitialized()
|
|
292
295
|
|
|
296
|
+
// REFACTOR: add proper error handling.
|
|
293
297
|
const documentIDX = dittoCore.ditto_document_id(self)
|
|
294
298
|
return dittoCore.boxCBytesIntoBuffer(documentIDX)
|
|
295
299
|
}
|
|
@@ -344,6 +348,7 @@ export function documentFree(self: Pointer<FFIDocument>) {
|
|
|
344
348
|
trace()
|
|
345
349
|
ensureInitialized()
|
|
346
350
|
|
|
351
|
+
// REFACTOR: add proper error handling.
|
|
347
352
|
dittoCore.ditto_document_free(self)
|
|
348
353
|
}
|
|
349
354
|
|
|
@@ -379,6 +384,7 @@ export async function collectionGet(ditto: Pointer<FFIDitto>, collectionName: st
|
|
|
379
384
|
trace()
|
|
380
385
|
ensureInitialized()
|
|
381
386
|
|
|
387
|
+
// REFACTOR: add proper error handling.
|
|
382
388
|
const collectionNameX = bytesFromString(collectionName)
|
|
383
389
|
|
|
384
390
|
const { status_code: errorCode, document } = await dittoCore.ditto_collection_get(ditto, collectionNameX, documentID, readTransaction)
|
|
@@ -392,6 +398,7 @@ export async function collectionInsertValue(ditto: Pointer<FFIDitto>, collection
|
|
|
392
398
|
trace()
|
|
393
399
|
ensureInitialized()
|
|
394
400
|
|
|
401
|
+
// REFACTOR: add proper error handling.
|
|
395
402
|
const collectionNameX = bytesFromString(collectionName)
|
|
396
403
|
|
|
397
404
|
let strategy
|
|
@@ -419,6 +426,7 @@ export async function collectionRemove(ditto: Pointer<FFIDitto>, collectionName:
|
|
|
419
426
|
trace()
|
|
420
427
|
ensureInitialized()
|
|
421
428
|
|
|
429
|
+
// REFACTOR: add proper error handling.
|
|
422
430
|
const collectionNameX = bytesFromString(collectionName)
|
|
423
431
|
|
|
424
432
|
const { status_code: errorCode, bool_value: didRemove } = await dittoCore.ditto_collection_remove(ditto, collectionNameX, writeTransaction, documentID)
|
|
@@ -431,6 +439,7 @@ export async function collectionEvict(ditto: Pointer<FFIDitto>, collectionName:
|
|
|
431
439
|
trace()
|
|
432
440
|
ensureInitialized()
|
|
433
441
|
|
|
442
|
+
// REFACTOR: add proper error handling.
|
|
434
443
|
const collectionNameX = bytesFromString(collectionName)
|
|
435
444
|
|
|
436
445
|
const { status_code: errorCode, bool_value: didEvict } = await dittoCore.ditto_collection_evict(ditto, collectionNameX, writeTransaction, documentID)
|
|
@@ -502,8 +511,8 @@ export async function tryExperimentalExecQueryStr(ditto: Pointer<FFIDitto>, writ
|
|
|
502
511
|
ensureInitialized()
|
|
503
512
|
|
|
504
513
|
const queryBytesPointer = bytesFromString(query)
|
|
505
|
-
const result = await dittoCore.
|
|
506
|
-
throwOnErrorResult(result.error, '
|
|
514
|
+
const result = await dittoCore.dittoffi_try_exec_statement(ditto, writeTransaction, queryBytesPointer, queryArgsCBOR)
|
|
515
|
+
throwOnErrorResult(result.error, 'dittoffi_try_exec_statement')
|
|
507
516
|
return result.success
|
|
508
517
|
}
|
|
509
518
|
|
|
@@ -533,8 +542,8 @@ export function tryExperimentalAddDQLSubscription(dittoPointer: Pointer<FFIDitto
|
|
|
533
542
|
ensureInitialized()
|
|
534
543
|
|
|
535
544
|
const queryBuffer = bytesFromString(query)
|
|
536
|
-
const result = dittoCore.
|
|
537
|
-
throwOnErrorResult(result.error, '
|
|
545
|
+
const result = dittoCore.dittoffi_try_add_sync_subscription(dittoPointer, queryBuffer, queryArgsCBOR)
|
|
546
|
+
throwOnErrorResult(result.error, 'dittoffi_try_add_sync_subscription')
|
|
538
547
|
return
|
|
539
548
|
}
|
|
540
549
|
|
|
@@ -544,8 +553,8 @@ export function tryExperimentalRemoveDQLSubscription(dittoPointer: Pointer<FFIDi
|
|
|
544
553
|
ensureInitialized()
|
|
545
554
|
|
|
546
555
|
const queryBuffer = bytesFromString(query)
|
|
547
|
-
const result = dittoCore.
|
|
548
|
-
throwOnErrorResult(result.error, '
|
|
556
|
+
const result = dittoCore.dittoffi_try_remove_sync_subscription(dittoPointer, queryBuffer, queryArgsCBOR)
|
|
557
|
+
throwOnErrorResult(result.error, 'dittoffi_try_remove_sync_subscription')
|
|
549
558
|
return
|
|
550
559
|
}
|
|
551
560
|
|
|
@@ -560,7 +569,7 @@ export function dqlResponseFree(responsePointer: Pointer<FFIDqlResponse>) {
|
|
|
560
569
|
trace()
|
|
561
570
|
ensureInitialized()
|
|
562
571
|
|
|
563
|
-
dittoCore.
|
|
572
|
+
dittoCore.dittoffi_query_result_free(responsePointer)
|
|
564
573
|
}
|
|
565
574
|
|
|
566
575
|
/**
|
|
@@ -572,7 +581,7 @@ export function dqlResultFree(resultPointer: Pointer<FFIDqlResult>) {
|
|
|
572
581
|
trace()
|
|
573
582
|
ensureInitialized()
|
|
574
583
|
|
|
575
|
-
dittoCore.
|
|
584
|
+
dittoCore.dittoffi_query_result_item_free(resultPointer)
|
|
576
585
|
}
|
|
577
586
|
|
|
578
587
|
/**
|
|
@@ -584,9 +593,9 @@ export function dqlResponseResults(responsePointer: Pointer<FFIDqlResponse>): Po
|
|
|
584
593
|
ensureInitialized()
|
|
585
594
|
|
|
586
595
|
const rv = []
|
|
587
|
-
const resultCount = dittoCore.
|
|
596
|
+
const resultCount = dittoCore.dittoffi_query_result_item_count(responsePointer)
|
|
588
597
|
for (let i = 0; i < resultCount; i++) {
|
|
589
|
-
rv.push(dittoCore.
|
|
598
|
+
rv.push(dittoCore.dittoffi_query_result_item_at(responsePointer, i))
|
|
590
599
|
}
|
|
591
600
|
return rv
|
|
592
601
|
}
|
|
@@ -601,9 +610,9 @@ export function dqlMutatedDocumentIDs(responsePointer: Pointer<FFIDqlResponse>):
|
|
|
601
610
|
ensureInitialized()
|
|
602
611
|
|
|
603
612
|
const rv = []
|
|
604
|
-
const resultCount = dittoCore.
|
|
613
|
+
const resultCount = dittoCore.dittoffi_query_result_mutated_document_id_count(responsePointer)
|
|
605
614
|
for (let i = 0; i < resultCount; i++) {
|
|
606
|
-
const cborBytes = dittoCore.
|
|
615
|
+
const cborBytes = dittoCore.dittoffi_query_result_mutated_document_id_at(responsePointer, i)
|
|
607
616
|
rv.push(dittoCore.boxCBytesIntoBuffer(cborBytes))
|
|
608
617
|
}
|
|
609
618
|
return rv
|
|
@@ -624,7 +633,7 @@ export function dqlResultCBOR(resultPointer: Pointer<FFIDqlResult>): Uint8Array
|
|
|
624
633
|
trace()
|
|
625
634
|
ensureInitialized()
|
|
626
635
|
|
|
627
|
-
const cborBytes = dittoCore.
|
|
636
|
+
const cborBytes = dittoCore.dittoffi_query_result_item_cbor(resultPointer)
|
|
628
637
|
return dittoCore.boxCBytesIntoBuffer(cborBytes)
|
|
629
638
|
}
|
|
630
639
|
|
|
@@ -641,7 +650,7 @@ export function dqlResultJSON(resultPointer: Pointer<FFIDqlResult>): string {
|
|
|
641
650
|
trace()
|
|
642
651
|
ensureInitialized()
|
|
643
652
|
|
|
644
|
-
const jsonBytes = dittoCore.
|
|
653
|
+
const jsonBytes = dittoCore.dittoffi_query_result_item_json(resultPointer)
|
|
645
654
|
return dittoCore.boxCStringIntoString(jsonBytes)
|
|
646
655
|
}
|
|
647
656
|
|
|
@@ -741,8 +750,8 @@ export async function tryExperimentalWebhookRegisterDqlLiveQuery(ditto: Pointer<
|
|
|
741
750
|
const queryBuffer = bytesFromString(query)
|
|
742
751
|
const urlBuffer = bytesFromString(url)
|
|
743
752
|
|
|
744
|
-
const result = await dittoCore.
|
|
745
|
-
throwOnErrorResult(result.error, '
|
|
753
|
+
const result = await dittoCore.dittoffi_try_register_store_observer_webhook(ditto, queryBuffer, queryArgsCBOR, urlBuffer)
|
|
754
|
+
throwOnErrorResult(result.error, 'dittoffi_try_register_store_observer_webhook')
|
|
746
755
|
const documentIdCBOR = result.success
|
|
747
756
|
|
|
748
757
|
return dittoCore.boxCBytesIntoBuffer(documentIdCBOR)
|
|
@@ -755,6 +764,8 @@ export async function readTransaction(ditto: Pointer<FFIDitto>): Promise<Pointer
|
|
|
755
764
|
trace()
|
|
756
765
|
ensureInitialized()
|
|
757
766
|
|
|
767
|
+
// REFACTOR: add proper error handling.
|
|
768
|
+
|
|
758
769
|
const { status_code: errorCode, txn: readTransaction } = await dittoCore.ditto_read_transaction(ditto)
|
|
759
770
|
if (errorCode !== 0) throw new Error(errorMessage() || `\`ditto_read_transaction()\` failed with error code: ${errorCode}`)
|
|
760
771
|
return readTransaction
|
|
@@ -765,6 +776,7 @@ export function readTransactionFree(self: Pointer<FFIReadTransaction>) {
|
|
|
765
776
|
trace()
|
|
766
777
|
ensureInitialized()
|
|
767
778
|
|
|
779
|
+
// REFACTOR: add proper error handling.
|
|
768
780
|
return dittoCore.ditto_read_transaction_free(self)
|
|
769
781
|
}
|
|
770
782
|
|
|
@@ -775,6 +787,8 @@ export async function writeTransaction(ditto: Pointer<FFIDitto>): Promise<Pointe
|
|
|
775
787
|
trace()
|
|
776
788
|
ensureInitialized()
|
|
777
789
|
|
|
790
|
+
// REFACTOR: add proper error handling.
|
|
791
|
+
|
|
778
792
|
const { status_code: errorCode, txn: writeTransaction } = await dittoCore.ditto_write_transaction(ditto, null)
|
|
779
793
|
if (errorCode !== 0) throw new Error(errorMessage() || `ditto_write_transaction() failed with error code: ${errorCode}`)
|
|
780
794
|
return writeTransaction
|
|
@@ -1060,18 +1074,12 @@ export async function dittoAuthClientLogout(ditto: Pointer<FFIDitto>) {
|
|
|
1060
1074
|
// ---------------------------------------------------------------- Ditto ------
|
|
1061
1075
|
|
|
1062
1076
|
/** @internal */
|
|
1063
|
-
export function
|
|
1077
|
+
export function dittoMake(path: string, identityConfig: Pointer<FFIIdentityConfig>, historyTracking: string): Pointer<FFIDitto> {
|
|
1064
1078
|
trace()
|
|
1065
1079
|
ensureInitialized()
|
|
1066
|
-
const pathX = bytesFromString(path)
|
|
1067
|
-
return dittoCore.ditto_uninitialized_ditto_make(pathX)
|
|
1068
|
-
}
|
|
1069
1080
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
trace()
|
|
1073
|
-
ensureInitialized()
|
|
1074
|
-
return dittoCore.ditto_make(uninitializedDitto, identityConfig, 'Disabled')
|
|
1081
|
+
const pathPointer = bytesFromString(path)
|
|
1082
|
+
return dittoCore.ditto_make(pathPointer, identityConfig, historyTracking)
|
|
1075
1083
|
}
|
|
1076
1084
|
|
|
1077
1085
|
/** @internal */
|
|
@@ -1093,6 +1101,7 @@ export function dittoFree(self: Pointer<FFIDitto>) {
|
|
|
1093
1101
|
trace()
|
|
1094
1102
|
ensureInitialized()
|
|
1095
1103
|
|
|
1104
|
+
// REFACTOR: add proper error handling.
|
|
1096
1105
|
return dittoCore.ditto_free(self)
|
|
1097
1106
|
}
|
|
1098
1107
|
|
|
@@ -1255,6 +1264,7 @@ export function dittoSetDeviceName(dittoPointer: Pointer<FFIDitto>, deviceName:
|
|
|
1255
1264
|
|
|
1256
1265
|
if (Environment.isWebBuild) {
|
|
1257
1266
|
if (deviceNameCString.length > 64) {
|
|
1267
|
+
|
|
1258
1268
|
const sanitizedDeviceName = deviceName.replace(/[^ -~]+/g, '')
|
|
1259
1269
|
deviceNameCString = bytesFromString(sanitizedDeviceName.substr(0, 63))
|
|
1260
1270
|
|
|
@@ -1301,7 +1311,7 @@ export function dittoNewAttachmentFromFile(ditto: Pointer<FFIDitto>, sourcePath:
|
|
|
1301
1311
|
const outAttachment: any = {}
|
|
1302
1312
|
const errorCode = dittoCore.ditto_new_attachment_from_file(ditto, sourcePathCString, fileOperation, outAttachment)
|
|
1303
1313
|
if (errorCode !== 0) {
|
|
1304
|
-
throw new
|
|
1314
|
+
throw new DittoFFIError(errorCode, null, `ditto_new_attachment_from_file() failed with error code: ${errorCode}`)
|
|
1305
1315
|
}
|
|
1306
1316
|
return outAttachment
|
|
1307
1317
|
}
|
|
@@ -1314,12 +1324,15 @@ export async function dittoNewAttachmentFromBytes(ditto: Pointer<FFIDitto>, byte
|
|
|
1314
1324
|
const outAttachment: any = {}
|
|
1315
1325
|
const errorCode = await dittoCore.ditto_new_attachment_from_bytes(ditto, bytes, outAttachment)
|
|
1316
1326
|
if (errorCode !== 0) {
|
|
1317
|
-
throw new
|
|
1327
|
+
throw new DittoFFIError(errorCode, null, `ditto_new_attachment_from_bytes() failed with error code: ${errorCode}`)
|
|
1318
1328
|
}
|
|
1319
1329
|
return outAttachment
|
|
1320
1330
|
}
|
|
1321
1331
|
|
|
1322
|
-
/**
|
|
1332
|
+
/**
|
|
1333
|
+
* @throws {@link DittoFFIError}
|
|
1334
|
+
* @internal
|
|
1335
|
+
*/
|
|
1323
1336
|
export async function dittoResolveAttachment(
|
|
1324
1337
|
ditto: Pointer<FFIDitto>,
|
|
1325
1338
|
id: Uint8Array,
|
|
@@ -1337,14 +1350,16 @@ export async function dittoResolveAttachment(
|
|
|
1337
1350
|
|
|
1338
1351
|
const { onComplete, onProgress, onDelete } = namedCallbacks
|
|
1339
1352
|
const { status_code: errorCode, cancel_token: cancelToken } = await dittoCore.ditto_resolve_attachment(ditto, id, wrapBackgroundCbForFFI(onError, onComplete), wrapBackgroundCbForFFI(onError, onProgress), wrapBackgroundCbForFFI(onError, onDelete))
|
|
1353
|
+
|
|
1340
1354
|
if (errorCode !== 0) {
|
|
1341
|
-
throw new
|
|
1355
|
+
throw new DittoFFIError(errorCode, null, `ditto_resolve_attachment() failed with error code: ${errorCode}`)
|
|
1342
1356
|
}
|
|
1357
|
+
|
|
1343
1358
|
return cancelToken
|
|
1344
1359
|
}
|
|
1345
1360
|
|
|
1346
1361
|
/** @internal */
|
|
1347
|
-
export function dittoCancelResolveAttachment(dittoPointer: Pointer<FFIDitto>, id: Uint8Array, cancelToken:
|
|
1362
|
+
export function dittoCancelResolveAttachment(dittoPointer: Pointer<FFIDitto>, id: Uint8Array, cancelToken: number | BigInt) {
|
|
1348
1363
|
trace()
|
|
1349
1364
|
ensureInitialized()
|
|
1350
1365
|
|
|
@@ -1552,6 +1567,25 @@ export function documentsHashMnemonic(documents: Pointer<FFIDocument>[]): string
|
|
|
1552
1567
|
return dittoCore.boxCStringIntoString(c_string)
|
|
1553
1568
|
}
|
|
1554
1569
|
|
|
1570
|
+
// ------------------------------------------------------------- base64 --------
|
|
1571
|
+
|
|
1572
|
+
/** @internal */
|
|
1573
|
+
export function base64encode(bytes: Uint8Array, paddingMode: Base64PaddingMode): string {
|
|
1574
|
+
const base64CString = dittoCore.dittoffi_base64_encode(bytes, paddingMode)
|
|
1575
|
+
return dittoCore.boxCStringIntoString(base64CString)
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
/**
|
|
1579
|
+
* @throws {@link DittoFFIError} if the base64 string is invalid
|
|
1580
|
+
* @internal
|
|
1581
|
+
*/
|
|
1582
|
+
export function tryBase64Decode(base64: string, paddingMode?: Base64PaddingMode): Uint8Array {
|
|
1583
|
+
const base64BytesPointer = bytesFromString(base64)
|
|
1584
|
+
const result = dittoCore.dittoffi_try_base64_decode(base64BytesPointer, paddingMode || null)
|
|
1585
|
+
throwOnErrorResult(result.error, 'dittoffi_try_base64_decode')
|
|
1586
|
+
return dittoCore.boxCBytesIntoBuffer(result.success)
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1555
1589
|
// ------------------------------------------------------------- Auth ----------
|
|
1556
1590
|
|
|
1557
1591
|
/** @internal */
|
|
@@ -1664,12 +1698,10 @@ export function transportsInit(): void {
|
|
|
1664
1698
|
trace()
|
|
1665
1699
|
ensureInitialized()
|
|
1666
1700
|
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
const errorType: TransportsError = dittoCore.ditto_sdk_transports_error_value(transportsErrorPointer)
|
|
1671
|
-
dittoCore.ditto_sdk_transports_error_free(transportsErrorPointer)
|
|
1701
|
+
// The symbols called below are not exported in the Wasm build.
|
|
1702
|
+
if (Environment.isWebBuild) return
|
|
1672
1703
|
|
|
1704
|
+
const { output: wasInitialized, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_init)
|
|
1673
1705
|
if (wasInitialized === false) {
|
|
1674
1706
|
throw new Error(`Failed to initialize transports (${errorType} error)`)
|
|
1675
1707
|
}
|
|
@@ -1680,7 +1712,10 @@ export function transportsBLEIsAvailable(ditto: Pointer<FFIDitto>): boolean {
|
|
|
1680
1712
|
trace()
|
|
1681
1713
|
ensureInitialized()
|
|
1682
1714
|
|
|
1683
|
-
|
|
1715
|
+
if (Environment.isNodeBuild) {
|
|
1716
|
+
return dittoCore.ditto_sdk_transports_ble_is_available(ditto)
|
|
1717
|
+
}
|
|
1718
|
+
return false
|
|
1684
1719
|
}
|
|
1685
1720
|
|
|
1686
1721
|
/** @internal */
|
|
@@ -1688,19 +1723,17 @@ export function transportsBLECreate(ditto: Pointer<FFIDitto>): Pointer<Transport
|
|
|
1688
1723
|
trace()
|
|
1689
1724
|
ensureInitialized()
|
|
1690
1725
|
|
|
1691
|
-
|
|
1692
|
-
|
|
1726
|
+
if (Environment.isNodeBuild) {
|
|
1727
|
+
const { output: blePointer, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_ble_create, ditto)
|
|
1693
1728
|
|
|
1694
|
-
|
|
1695
|
-
|
|
1729
|
+
if (blePointer != null) {
|
|
1730
|
+
log('Info', `Bluetooth transport created.`)
|
|
1731
|
+
} else {
|
|
1732
|
+
log('Error', `Can't create bluetooth transport (${errorType} error).`)
|
|
1733
|
+
}
|
|
1696
1734
|
|
|
1697
|
-
|
|
1698
|
-
log('Info', `Bluetooth transport created.`)
|
|
1699
|
-
} else {
|
|
1700
|
-
log('Error', `Can't create bluetooth transport (${errorType} error).`)
|
|
1735
|
+
return blePointer
|
|
1701
1736
|
}
|
|
1702
|
-
|
|
1703
|
-
return blePointer
|
|
1704
1737
|
}
|
|
1705
1738
|
|
|
1706
1739
|
/** @internal */
|
|
@@ -1708,18 +1741,16 @@ export function transportsBLEDestroy(ble: Pointer<TransportBluetooth>): boolean
|
|
|
1708
1741
|
trace()
|
|
1709
1742
|
ensureInitialized()
|
|
1710
1743
|
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
const errorType: TransportsError = dittoCore.ditto_sdk_transports_error_value(ffiError)
|
|
1715
|
-
dittoCore.ditto_sdk_transports_error_free(ffiError)
|
|
1744
|
+
if (Environment.isNodeBuild) {
|
|
1745
|
+
const { output: wasDestroyed, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_ble_destroy, ble)
|
|
1716
1746
|
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1747
|
+
if (wasDestroyed === true) {
|
|
1748
|
+
log('Info', 'Bluetooth transport disabled.')
|
|
1749
|
+
} else {
|
|
1750
|
+
log('Error', `Bluetooth transport could not be disabled (${errorType} error).`)
|
|
1751
|
+
}
|
|
1752
|
+
return wasDestroyed
|
|
1721
1753
|
}
|
|
1722
|
-
return wasDestroyed
|
|
1723
1754
|
}
|
|
1724
1755
|
|
|
1725
1756
|
/** @internal */
|
|
@@ -1727,7 +1758,10 @@ export function transportsLANIsAvailable(ditto: Pointer<FFIDitto>): boolean {
|
|
|
1727
1758
|
trace()
|
|
1728
1759
|
ensureInitialized()
|
|
1729
1760
|
|
|
1730
|
-
|
|
1761
|
+
if (Environment.isNodeBuild) {
|
|
1762
|
+
return dittoCore.ditto_sdk_transports_lan_is_available(ditto)
|
|
1763
|
+
}
|
|
1764
|
+
return false
|
|
1731
1765
|
}
|
|
1732
1766
|
|
|
1733
1767
|
/** @internal */
|
|
@@ -1735,19 +1769,17 @@ export function transportsLANCreate(ditto: Pointer<FFIDitto>): Pointer<Transport
|
|
|
1735
1769
|
trace()
|
|
1736
1770
|
ensureInitialized()
|
|
1737
1771
|
|
|
1738
|
-
|
|
1739
|
-
|
|
1772
|
+
if (Environment.isNodeBuild) {
|
|
1773
|
+
const { output: lanPointer, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_lan_create, ditto)
|
|
1740
1774
|
|
|
1741
|
-
|
|
1742
|
-
|
|
1775
|
+
if (lanPointer != null) {
|
|
1776
|
+
log('Info', `LAN transport created.`)
|
|
1777
|
+
} else {
|
|
1778
|
+
log('Error', `Can't create LAN transport (${errorType} error).`)
|
|
1779
|
+
}
|
|
1743
1780
|
|
|
1744
|
-
|
|
1745
|
-
log('Info', `LAN transport created.`)
|
|
1746
|
-
} else {
|
|
1747
|
-
log('Error', `Can't create LAN transport (${errorType} error).`)
|
|
1781
|
+
return lanPointer
|
|
1748
1782
|
}
|
|
1749
|
-
|
|
1750
|
-
return lanPointer
|
|
1751
1783
|
}
|
|
1752
1784
|
|
|
1753
1785
|
/** @internal */
|
|
@@ -1755,18 +1787,16 @@ export function transportsLANDestroy(lan: Pointer<TransportLAN>): boolean | void
|
|
|
1755
1787
|
trace()
|
|
1756
1788
|
ensureInitialized()
|
|
1757
1789
|
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
const error: TransportsError = dittoCore.ditto_sdk_transports_error_value(ffiError)
|
|
1762
|
-
dittoCore.ditto_sdk_transports_error_free(ffiError)
|
|
1790
|
+
if (Environment.isNodeBuild) {
|
|
1791
|
+
const { output: wasDestroyed, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_lan_destroy, lan)
|
|
1763
1792
|
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1793
|
+
if (wasDestroyed === true) {
|
|
1794
|
+
log('Info', 'LAN transport disabled.')
|
|
1795
|
+
} else {
|
|
1796
|
+
log('Error', `LAN transport could not be disabled (${errorType} error).`)
|
|
1797
|
+
}
|
|
1798
|
+
return wasDestroyed
|
|
1768
1799
|
}
|
|
1769
|
-
return wasDestroyed
|
|
1770
1800
|
}
|
|
1771
1801
|
|
|
1772
1802
|
/** @internal */
|
|
@@ -1774,7 +1804,10 @@ export function transportsAWDLIsAvailable(ditto: Pointer<FFIDitto>): boolean {
|
|
|
1774
1804
|
trace()
|
|
1775
1805
|
ensureInitialized()
|
|
1776
1806
|
|
|
1777
|
-
|
|
1807
|
+
if (Environment.isNodeBuild) {
|
|
1808
|
+
return dittoCore.ditto_sdk_transports_awdl_is_available(ditto)
|
|
1809
|
+
}
|
|
1810
|
+
return false
|
|
1778
1811
|
}
|
|
1779
1812
|
|
|
1780
1813
|
/** @internal */
|
|
@@ -1782,19 +1815,17 @@ export function transportsAWDLCreate(ditto: Pointer<FFIDitto>): Pointer<Transpor
|
|
|
1782
1815
|
trace()
|
|
1783
1816
|
ensureInitialized()
|
|
1784
1817
|
|
|
1785
|
-
|
|
1786
|
-
|
|
1818
|
+
if (Environment.isNodeBuild) {
|
|
1819
|
+
const { output: awdlPointer, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_awdl_create, ditto)
|
|
1787
1820
|
|
|
1788
|
-
|
|
1789
|
-
|
|
1821
|
+
if (awdlPointer != null) {
|
|
1822
|
+
log('Info', `AWDL transport created.`)
|
|
1823
|
+
} else {
|
|
1824
|
+
log('Error', `Can't create AWDL transport (${errorType} error).`)
|
|
1825
|
+
}
|
|
1790
1826
|
|
|
1791
|
-
|
|
1792
|
-
log('Info', `AWDL transport created.`)
|
|
1793
|
-
} else {
|
|
1794
|
-
log('Error', `Can't create AWDL transport (${errorType} error).`)
|
|
1827
|
+
return awdlPointer
|
|
1795
1828
|
}
|
|
1796
|
-
|
|
1797
|
-
return awdlPointer
|
|
1798
1829
|
}
|
|
1799
1830
|
|
|
1800
1831
|
/** @internal */
|
|
@@ -1802,18 +1833,48 @@ export function transportsAWDLDestroy(awdl: Pointer<TransportAWDL>): boolean | v
|
|
|
1802
1833
|
trace()
|
|
1803
1834
|
ensureInitialized()
|
|
1804
1835
|
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
const errorType: TransportsError = dittoCore.ditto_sdk_transports_error_value(ffiError)
|
|
1809
|
-
dittoCore.ditto_sdk_transports_error_free(ffiError)
|
|
1836
|
+
if (Environment.isNodeBuild) {
|
|
1837
|
+
const { output: wasDestroyed, errorType } = withTransportsError(dittoCore.ditto_sdk_transports_awdl_destroy, awdl)
|
|
1810
1838
|
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1839
|
+
if (wasDestroyed === true) {
|
|
1840
|
+
log('Info', 'AWDL transport disabled.')
|
|
1841
|
+
} else {
|
|
1842
|
+
log('Error', `AWDL transport could not be disabled (${errorType} error).`)
|
|
1843
|
+
}
|
|
1844
|
+
return wasDestroyed
|
|
1815
1845
|
}
|
|
1816
|
-
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
/**
|
|
1849
|
+
* Helper type that extracts all but the last parameter from a function type.
|
|
1850
|
+
*
|
|
1851
|
+
* NOTE: will accept any parameters for functions that don't have typed parameters.
|
|
1852
|
+
*/
|
|
1853
|
+
// prettier-ignore
|
|
1854
|
+
type ParametersExceptLast<F extends (...args: any[]) => any> = Parameters<F> extends [...infer U, any]
|
|
1855
|
+
? U
|
|
1856
|
+
: any // FIXME: this should really be `never` but we don't have proper types for the FFI functions yet.
|
|
1857
|
+
|
|
1858
|
+
/**
|
|
1859
|
+
* Calls the given FFI function with the passed in arguments and a newly
|
|
1860
|
+
* allocated `transportsErrorPointer` as the last argument, then returns its
|
|
1861
|
+
* result.
|
|
1862
|
+
*
|
|
1863
|
+
* The given function MUST take a `transportsErrorPointer` as its last argument.
|
|
1864
|
+
*
|
|
1865
|
+
* @param ffiFunction The FFI function to wrap.
|
|
1866
|
+
* @param args The arguments to pass to the FFI function, excluding the
|
|
1867
|
+
* `transportsErrorPointer`.
|
|
1868
|
+
* @returns An object with two properties: `output` and `errorType`. `output` is
|
|
1869
|
+
* the return value of the FFI function, and `errorType` is the value of the
|
|
1870
|
+
* `transportsErrorPointer` after the FFI function has been called.
|
|
1871
|
+
*/
|
|
1872
|
+
function withTransportsError<T extends (...args: any[]) => any>(ffiFunction: T, ...args: ParametersExceptLast<T>): { output: ReturnType<T>; errorType: TransportsError } {
|
|
1873
|
+
const transportsErrorPointer = dittoCore.ditto_sdk_transports_error_new()
|
|
1874
|
+
const output = ffiFunction(...args, transportsErrorPointer)
|
|
1875
|
+
const errorType: TransportsError = dittoCore.ditto_sdk_transports_error_value(transportsErrorPointer)
|
|
1876
|
+
dittoCore.ditto_sdk_transports_error_free(transportsErrorPointer)
|
|
1877
|
+
return { output, errorType }
|
|
1817
1878
|
}
|
|
1818
1879
|
|
|
1819
1880
|
// ---------------------------------------------------------------- Other ------
|
|
@@ -1902,8 +1963,25 @@ export function createDirectory(path: string): string | void {
|
|
|
1902
1963
|
}
|
|
1903
1964
|
}
|
|
1904
1965
|
|
|
1966
|
+
/** @internal */
|
|
1967
|
+
export function readFile(path: string): string {
|
|
1968
|
+
if (Environment.isReactNativeBuild) {
|
|
1969
|
+
// @ts-expect-error Throws method not-found on non-RN envs.
|
|
1970
|
+
return dittoCore.readFile(path)
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
/** @internal */
|
|
1975
|
+
export function copyFile(source: string, destination: string, dittoPath: string): string {
|
|
1976
|
+
if (Environment.isReactNativeBuild) {
|
|
1977
|
+
// @ts-expect-error Throws method not-found on non-RN envs.
|
|
1978
|
+
return dittoCore.copyFile(source, destination, dittoPath)
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1905
1982
|
// -------------------------------------------------------------- Private ------
|
|
1906
1983
|
|
|
1984
|
+
|
|
1907
1985
|
/** @internal */
|
|
1908
1986
|
const NOT_FOUND_ERROR_CODE = -30798
|
|
1909
1987
|
|
|
@@ -82,14 +82,32 @@ export function validateQuery(query, options = {}): string {
|
|
|
82
82
|
export function generateEphemeralToken(): string {
|
|
83
83
|
|
|
84
84
|
let data = new Uint16Array(16)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
if (Environment.isReactNativeBuild) {
|
|
86
|
+
data = FFI.getRandomValues(data) as Uint16Array
|
|
87
|
+
} else {
|
|
88
|
+
throw new Error('Internal inconsistency, incorrect environment to run getRandomValues()')
|
|
89
|
+
}
|
|
88
90
|
|
|
89
91
|
const doublets = Array.from(data)
|
|
90
92
|
return doublets.map((doublet) => doublet.toString(16)).join('')
|
|
91
93
|
}
|
|
92
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Can be used to implement a custom Node.js `inspect` representation for
|
|
97
|
+
* objects that have a `value` property.
|
|
98
|
+
*
|
|
99
|
+
* Node.js < 16.14.0 and Electron < 19.0.0 do not provide the `inspect`
|
|
100
|
+
* parameter used below, which is when we fall back to `JSON.stringify`.
|
|
101
|
+
*
|
|
102
|
+
* See https://nodejs.org/api/util.html#custom-inspection-functions-on-objects
|
|
103
|
+
*/
|
|
104
|
+
export function customInspectRepresentation(documentLike: { value: any }, inspect?: any): string {
|
|
105
|
+
if (inspect === undefined) {
|
|
106
|
+
return `${documentLike.constructor.name} ${JSON.stringify({ value: documentLike.value }, null, 2)}`
|
|
107
|
+
}
|
|
108
|
+
return `${documentLike.constructor.name} ${inspect({ value: documentLike.value })}`
|
|
109
|
+
}
|
|
110
|
+
|
|
93
111
|
// --------------------------------------------------------------- System ------
|
|
94
112
|
|
|
95
113
|
/** @internal */
|
|
@@ -106,4 +124,20 @@ export async function step<T>(closure: () => T): Promise<T> {
|
|
|
106
124
|
}
|
|
107
125
|
|
|
108
126
|
/** @internal */
|
|
127
|
+
// WORKAROUND: the corresponding FFI function(s) is not async at the
|
|
128
|
+
// moment, we therefore artificially make it async via step() until an
|
|
129
|
+
// async variant becomes available.
|
|
130
|
+
//
|
|
131
|
+
// Why? Any function marked as async that isn't under the hood appears to be
|
|
132
|
+
// yield-ing on the use site but isn't. This may lead to blocking the
|
|
133
|
+
// event loop for a long time, which in turn can lead to excessive memory
|
|
134
|
+
// consumption and other side-effects. Plus, WebAssembly limitations may
|
|
135
|
+
// lead to deadlocks and other crashes.
|
|
136
|
+
//
|
|
137
|
+
// The function alias here is to be able to easily see that its use is
|
|
138
|
+
// a workaround, plus easily finding all of those workarounds to fix
|
|
139
|
+
// them all once the FFI API is properly asyncified.
|
|
140
|
+
//
|
|
141
|
+
// See PR #4833 for details:
|
|
142
|
+
// https://github.com/getditto/ditto/pull/4833
|
|
109
143
|
export const performAsyncToWorkaroundNonAsyncFFIAPI = step
|
|
@@ -26,7 +26,16 @@ export class LiveQueryManager {
|
|
|
26
26
|
startLiveQuery(liveQuery: LiveQuery) {
|
|
27
27
|
const ditto = this.ditto
|
|
28
28
|
const dittoHandle = Bridge.ditto.handleFor(ditto)
|
|
29
|
-
|
|
29
|
+
|
|
30
|
+
// REFACTOR: the starting closure runs detached from here which is a smell.
|
|
31
|
+
// Can we make this whole starting mechanism non-async? The culprit is
|
|
32
|
+
// the workaround for a zalgo with `ditto_live_query_start()` FFI function:
|
|
33
|
+
// It immediately triggers the live query handler making it run "in-line"
|
|
34
|
+
// when creating a live query, while subsequent invocations are async
|
|
35
|
+
// (by definition). This is a classic zalgo case. Fix by making
|
|
36
|
+
// `ditto_live_query_start()` trigger the first live query callback `async`,
|
|
37
|
+
// just like the subsequent ones.
|
|
38
|
+
|
|
30
39
|
ditto.deferCloseAsync(async () => {
|
|
31
40
|
const liveQueryID = liveQuery.liveQueryID
|
|
32
41
|
if (!liveQueryID) {
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
import * as FFI from './ffi'
|
|
6
6
|
|
|
7
7
|
import { Bridge } from './bridge'
|
|
8
|
-
import { Collection } from './collection'
|
|
9
8
|
|
|
10
9
|
import { LiveQueryEventInitial } from './live-query-event'
|
|
11
10
|
import { LiveQueryEventUpdate } from './live-query-event'
|
|
12
11
|
|
|
12
|
+
import type { Collection } from './collection'
|
|
13
13
|
import type { QueryArguments } from './essentials'
|
|
14
14
|
import type { LiveQueryEvent } from './live-query-event'
|
|
15
15
|
import type { LiveQueryManager } from './live-query-manager'
|