@dittolive/ditto 4.10.2 → 4.11.0-preview.1
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 +1 -17
- package/README.md +4 -80
- package/node/ditto.cjs.js +444 -81
- package/node/ditto.darwin-arm64.node +0 -0
- package/node/ditto.darwin-x64.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/package.json +1 -1
- package/react-native/android/build.gradle +29 -34
- package/react-native/android/cpp-adapter.cpp +10 -11
- package/react-native/android/dittoffi/src/ditto_transaction.cpp +1 -0
- package/react-native/android/dittoffi/src/ditto_transaction.h +91 -0
- package/react-native/android/dittoffi/src/dittoffi.h +587 -390
- package/react-native/android/dittoffi/src/dittoffi_java.cpp +3360 -1358
- package/react-native/android/dittoffi/src/dittoffi_java.h +59 -10
- package/react-native/android/dittoffi/src/dittoffi_java.i +2 -0
- package/react-native/android/dittoffi/src/dittostore_java.i +48 -0
- package/react-native/android/dittoffi/src/mesh_java_interfaces.h +81 -109
- package/react-native/android/gradle.properties +6 -5
- package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.kt +23 -15
- package/react-native/cpp/include/DQL.h +1 -0
- package/react-native/cpp/include/Differ.h +14 -0
- package/react-native/cpp/include/Lifecycle.h +1 -1
- package/react-native/cpp/include/Transaction.h +18 -0
- package/react-native/cpp/include/Transports.h +1 -0
- package/react-native/cpp/include/Utils.h +27 -3
- package/react-native/cpp/include/main.h +2 -0
- package/react-native/cpp/src/DQL.cpp +21 -0
- package/react-native/cpp/src/Differ.cpp +57 -0
- package/react-native/cpp/src/Lifecycle.cpp +17 -7
- package/react-native/cpp/src/Misc.cpp +50 -32
- package/react-native/cpp/src/Transaction.cpp +195 -0
- package/react-native/cpp/src/Transports.cpp +77 -1
- package/react-native/cpp/src/Utils.cpp +11 -0
- package/react-native/cpp/src/main.cpp +18 -1
- package/react-native/ditto.es6.js +1 -1
- package/react-native/ios/DittoRNSDK.mm +2 -4
- package/types/ditto.d.ts +271 -33
- package/web/ditto.es6.js +1 -1
- package/web/ditto.umd.js +1 -1
- package/web/ditto.wasm +0 -0
- package/react-native/ios/YeetJSIUtils.h +0 -60
- package/react-native/ios/YeetJSIUtils.mm +0 -196
package/node/ditto.cjs.js
CHANGED
|
@@ -344,7 +344,6 @@ function ditto_live_query_register_str_detached(...args) { return ditto.ditto_li
|
|
|
344
344
|
function ditto_live_query_signal_available_next(...args) { return ditto.ditto_live_query_signal_available_next(...args) }
|
|
345
345
|
function ditto_live_query_start(...args) { return ditto.ditto_live_query_start(...args) }
|
|
346
346
|
function ditto_live_query_stop(...args) { return ditto.ditto_live_query_stop(...args) }
|
|
347
|
-
function ditto_live_query_webhook_register_str(...args) { return ditto.ditto_live_query_webhook_register_str(...args) }
|
|
348
347
|
function ditto_log(...args) { return ditto.ditto_log(...args) }
|
|
349
348
|
function ditto_logger_emoji_headings_enabled(...args) { return ditto.ditto_logger_emoji_headings_enabled(...args) }
|
|
350
349
|
function ditto_logger_emoji_headings_enabled_get(...args) { return ditto.ditto_logger_emoji_headings_enabled_get(...args) }
|
|
@@ -394,12 +393,16 @@ function dittoffi_connection_request_identity_service_metadata_json(...args) { r
|
|
|
394
393
|
function dittoffi_connection_request_peer_key_string(...args) { return ditto.dittoffi_connection_request_peer_key_string(...args) }
|
|
395
394
|
function dittoffi_connection_request_peer_metadata_json(...args) { return ditto.dittoffi_connection_request_peer_metadata_json(...args) }
|
|
396
395
|
function dittoffi_crypto_generate_secure_random_token(...args) { return ditto.dittoffi_crypto_generate_secure_random_token(...args) }
|
|
396
|
+
function dittoffi_differ_diff(...args) { return ditto.dittoffi_differ_diff(...args) }
|
|
397
|
+
function dittoffi_differ_free(...args) { return ditto.dittoffi_differ_free(...args) }
|
|
398
|
+
function dittoffi_differ_new(...args) { return ditto.dittoffi_differ_new(...args) }
|
|
397
399
|
function dittoffi_ditto_is_activated(...args) { return ditto.dittoffi_ditto_is_activated(...args) }
|
|
398
400
|
function dittoffi_ditto_is_sync_active(...args) { return ditto.dittoffi_ditto_is_sync_active(...args) }
|
|
399
401
|
function dittoffi_ditto_set_authentication_status_handler(...args) { return ditto.dittoffi_ditto_set_authentication_status_handler(...args) }
|
|
400
402
|
function dittoffi_ditto_set_cloud_sync_enabled(...args) { return ditto.dittoffi_ditto_set_cloud_sync_enabled(...args) }
|
|
401
403
|
function dittoffi_ditto_stop_sync(...args) { return ditto.dittoffi_ditto_stop_sync(...args) }
|
|
402
404
|
function dittoffi_ditto_transport_config(...args) { return ditto.dittoffi_ditto_transport_config(...args) }
|
|
405
|
+
function dittoffi_ditto_try_new_blocking(...args) { return ditto.dittoffi_ditto_try_new_blocking(...args) }
|
|
403
406
|
function dittoffi_ditto_try_set_transport_config(...args) { return ditto.dittoffi_ditto_try_set_transport_config(...args) }
|
|
404
407
|
function dittoffi_ditto_try_start_sync(...args) { return ditto.dittoffi_ditto_try_start_sync(...args) }
|
|
405
408
|
function dittoffi_error_code(...args) { return ditto.dittoffi_error_code(...args) }
|
|
@@ -407,7 +410,6 @@ function dittoffi_error_description(...args) { return ditto.dittoffi_error_descr
|
|
|
407
410
|
function dittoffi_error_free(...args) { return ditto.dittoffi_error_free(...args) }
|
|
408
411
|
function dittoffi_get_sdk_semver(...args) { return ditto.dittoffi_get_sdk_semver(...args) }
|
|
409
412
|
function dittoffi_logger_try_export_to_file_async(...args) { return ditto.dittoffi_logger_try_export_to_file_async(...args) }
|
|
410
|
-
function dittoffi_make_with_transport_config_mode(...args) { return ditto.dittoffi_make_with_transport_config_mode(...args) }
|
|
411
413
|
function dittoffi_presence_peer_metadata_json(...args) { return ditto.dittoffi_presence_peer_metadata_json(...args) }
|
|
412
414
|
function dittoffi_presence_set_connection_request_handler(...args) { return ditto.dittoffi_presence_set_connection_request_handler(...args) }
|
|
413
415
|
function dittoffi_presence_try_set_peer_metadata_json(...args) { return ditto.dittoffi_presence_try_set_peer_metadata_json(...args) }
|
|
@@ -417,8 +419,15 @@ function dittoffi_query_result_item_cbor(...args) { return ditto.dittoffi_query_
|
|
|
417
419
|
function dittoffi_query_result_item_count(...args) { return ditto.dittoffi_query_result_item_count(...args) }
|
|
418
420
|
function dittoffi_query_result_item_free(...args) { return ditto.dittoffi_query_result_item_free(...args) }
|
|
419
421
|
function dittoffi_query_result_item_json(...args) { return ditto.dittoffi_query_result_item_json(...args) }
|
|
422
|
+
function dittoffi_query_result_item_new(...args) { return ditto.dittoffi_query_result_item_new(...args) }
|
|
420
423
|
function dittoffi_query_result_mutated_document_id_at(...args) { return ditto.dittoffi_query_result_mutated_document_id_at(...args) }
|
|
421
424
|
function dittoffi_query_result_mutated_document_id_count(...args) { return ditto.dittoffi_query_result_mutated_document_id_count(...args) }
|
|
425
|
+
function dittoffi_store_begin_transaction_async_throws(...args) { return ditto.dittoffi_store_begin_transaction_async_throws(...args) }
|
|
426
|
+
function dittoffi_store_transactions(...args) { return ditto.dittoffi_store_transactions(...args) }
|
|
427
|
+
function dittoffi_transaction_complete_async_throws(...args) { return ditto.dittoffi_transaction_complete_async_throws(...args) }
|
|
428
|
+
function dittoffi_transaction_execute_async_throws(...args) { return ditto.dittoffi_transaction_execute_async_throws(...args) }
|
|
429
|
+
function dittoffi_transaction_free(...args) { return ditto.dittoffi_transaction_free(...args) }
|
|
430
|
+
function dittoffi_transaction_info(...args) { return ditto.dittoffi_transaction_info(...args) }
|
|
422
431
|
function dittoffi_try_add_sync_subscription(...args) { return ditto.dittoffi_try_add_sync_subscription(...args) }
|
|
423
432
|
function dittoffi_try_base64_decode(...args) { return ditto.dittoffi_try_base64_decode(...args) }
|
|
424
433
|
function dittoffi_try_exec_statement(...args) { return ditto.dittoffi_try_exec_statement(...args) }
|
|
@@ -544,6 +553,28 @@ var DittoCRDTType;
|
|
|
544
553
|
DittoCRDTType[DittoCRDTType["rga"] = 3] = "rga";
|
|
545
554
|
DittoCRDTType[DittoCRDTType["rwMap"] = 4] = "rwMap";
|
|
546
555
|
})(DittoCRDTType || (DittoCRDTType = {}));
|
|
556
|
+
// ------------------------------------------------------------- Differ --------
|
|
557
|
+
function differNew() {
|
|
558
|
+
ensureInitialized();
|
|
559
|
+
return dittoffi_differ_new();
|
|
560
|
+
}
|
|
561
|
+
function differDiff(differ, items) {
|
|
562
|
+
ensureInitialized();
|
|
563
|
+
return dittoffi_differ_diff(differ, items);
|
|
564
|
+
}
|
|
565
|
+
function differFree(differ) {
|
|
566
|
+
ensureInitialized();
|
|
567
|
+
dittoffi_differ_free(differ);
|
|
568
|
+
}
|
|
569
|
+
// HACK: underlying safer-ffi doesn't equivalent a CDitto with dittoffi_store_t
|
|
570
|
+
// although they are C aliases so we need to force it's type.
|
|
571
|
+
/** @internal */
|
|
572
|
+
function dittoPointerToStorePointer(dittoHandle) {
|
|
573
|
+
return {
|
|
574
|
+
addr: dittoHandle.addr,
|
|
575
|
+
type: 'dittoffi_store_t const *',
|
|
576
|
+
};
|
|
577
|
+
}
|
|
547
578
|
// ------------------------------------------------------------- Document ------
|
|
548
579
|
/** @internal */
|
|
549
580
|
function documentSetCBORWithTimestamp(document, path, cbor, timestamp) {
|
|
@@ -878,6 +909,12 @@ function queryResultItemJSON(queryResultItemPointer) {
|
|
|
878
909
|
const jsonBytes = dittoffi_query_result_item_json(queryResultItemPointer);
|
|
879
910
|
return boxCStringIntoString(jsonBytes);
|
|
880
911
|
}
|
|
912
|
+
function queryResultItemNew(jsonData) {
|
|
913
|
+
ensureInitialized();
|
|
914
|
+
const result = dittoffi_query_result_item_new(jsonData);
|
|
915
|
+
throwOnErrorResult(result.error, 'dittoffi_query_result_item_new');
|
|
916
|
+
return result.success;
|
|
917
|
+
}
|
|
881
918
|
// ------------------------------------------------------------ LiveQuery ------
|
|
882
919
|
/** @internal */
|
|
883
920
|
function liveQueryRegister(ditto, collectionName, query, queryArgsCBOR, orderBy, limit, offset, eventHandler,
|
|
@@ -931,20 +968,6 @@ async function liveQuerySignalAvailableNext(ditto, liveQueryID) {
|
|
|
931
968
|
ensureInitialized();
|
|
932
969
|
await ditto_live_query_signal_available_next(ditto, liveQueryID);
|
|
933
970
|
}
|
|
934
|
-
// ------------------------------------------------------------ Webhook ------
|
|
935
|
-
/** @internal */
|
|
936
|
-
async function liveQueryWebhookRegister(ditto, collectionName, query, orderBy, limit, offset, url) {
|
|
937
|
-
ensureInitialized();
|
|
938
|
-
const collectionNameBuffer = bytesFromString(collectionName);
|
|
939
|
-
const queryBuffer = bytesFromString(query);
|
|
940
|
-
const urlBuffer = bytesFromString(url);
|
|
941
|
-
const { status_code: errorCode, id } = await ditto_live_query_webhook_register_str(ditto, collectionNameBuffer, queryBuffer, orderBy, limit, offset, urlBuffer);
|
|
942
|
-
if (errorCode !== 0) {
|
|
943
|
-
throw new Error(errorMessage() ||
|
|
944
|
-
`\`ditto_live_query_webhook_register_str()\` failed with error code: ${errorCode}`);
|
|
945
|
-
}
|
|
946
|
-
return boxCBytesIntoBuffer(id);
|
|
947
|
-
}
|
|
948
971
|
// ------------------------------------------------------ ReadTransaction ------
|
|
949
972
|
/** @internal */
|
|
950
973
|
async function readTransaction(ditto) {
|
|
@@ -1225,12 +1248,68 @@ function authenticationStatusFree(ffiAuthenticationStatus) {
|
|
|
1225
1248
|
ensureInitialized();
|
|
1226
1249
|
dittoffi_authentication_status_free(ffiAuthenticationStatus);
|
|
1227
1250
|
}
|
|
1251
|
+
// --------------------------------------------------------- Transactions ------
|
|
1252
|
+
function storeTransactions(store) {
|
|
1253
|
+
ensureInitialized();
|
|
1254
|
+
const cborBytes = dittoffi_store_transactions(store);
|
|
1255
|
+
return boxCBytesIntoBuffer(cborBytes);
|
|
1256
|
+
}
|
|
1257
|
+
async function storeBeginTransaction(store, options) {
|
|
1258
|
+
ensureInitialized();
|
|
1259
|
+
const ffiOptions = {
|
|
1260
|
+
is_read_only: options.isReadOnly,
|
|
1261
|
+
hint: bytesFromString(options.hint),
|
|
1262
|
+
};
|
|
1263
|
+
return new Promise((resolve, reject) => {
|
|
1264
|
+
const callback = wrapBackgroundCbForFFI(reject, (resultObj) => {
|
|
1265
|
+
throwOnErrorResult(resultObj.error, 'dittoffi_store_begin_transaction_async_throws');
|
|
1266
|
+
resolve(resultObj.success);
|
|
1267
|
+
});
|
|
1268
|
+
dittoffi_store_begin_transaction_async_throws(store, ffiOptions, callback);
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
async function transactionCompleteAsync(transaction, action) {
|
|
1272
|
+
ensureInitialized();
|
|
1273
|
+
return new Promise((resolve, reject) => {
|
|
1274
|
+
const callback = wrapBackgroundCbForFFI(reject, (resultObj) => {
|
|
1275
|
+
throwOnErrorResult(resultObj.error, 'dittoffi_transaction_complete_async_throws');
|
|
1276
|
+
const action = resultObj.success;
|
|
1277
|
+
resolve(action);
|
|
1278
|
+
});
|
|
1279
|
+
dittoffi_transaction_complete_async_throws(transaction, action, callback);
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
async function transactionExecuteAsync(transaction, query, queryArgsCbor) {
|
|
1283
|
+
ensureInitialized();
|
|
1284
|
+
return new Promise((resolve, reject) => {
|
|
1285
|
+
const callback = wrapBackgroundCbForFFI(reject, (resultObj) => {
|
|
1286
|
+
throwOnErrorResult(resultObj.error, 'dittoffi_transaction_execute_async_throws');
|
|
1287
|
+
resolve(resultObj.success);
|
|
1288
|
+
});
|
|
1289
|
+
const queryBytes = bytesFromString(query);
|
|
1290
|
+
dittoffi_transaction_execute_async_throws(transaction, queryBytes, queryArgsCbor, callback);
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
function transactionInfo(transaction) {
|
|
1294
|
+
ensureInitialized();
|
|
1295
|
+
const cborBytes = dittoffi_transaction_info(transaction);
|
|
1296
|
+
return boxCBytesIntoBuffer(cborBytes);
|
|
1297
|
+
}
|
|
1298
|
+
function transactionFree(transaction) {
|
|
1299
|
+
ensureInitialized();
|
|
1300
|
+
dittoffi_transaction_free(transaction);
|
|
1301
|
+
}
|
|
1228
1302
|
// ---------------------------------------------------------------- Ditto ------
|
|
1229
1303
|
/** @internal */
|
|
1230
|
-
function
|
|
1304
|
+
function dittoTryNewBlocking(path, identityConfig, historyTracking, transportConfigMode) {
|
|
1231
1305
|
ensureInitialized();
|
|
1306
|
+
// Encryption is not supported by the JS SDK.
|
|
1307
|
+
const experimentalPassphrase = null;
|
|
1232
1308
|
const pathPointer = bytesFromString(path);
|
|
1233
|
-
|
|
1309
|
+
const experimentalPassphrasePointer = bytesFromString(experimentalPassphrase);
|
|
1310
|
+
const result = dittoffi_ditto_try_new_blocking(pathPointer, identityConfig, historyTracking, experimentalPassphrasePointer, transportConfigMode);
|
|
1311
|
+
throwOnErrorResult(result.error, 'dittoffi_ditto_try_new_blocking');
|
|
1312
|
+
return result.success;
|
|
1234
1313
|
}
|
|
1235
1314
|
/** @internal */
|
|
1236
1315
|
async function dittoGetCollectionNames(self) {
|
|
@@ -1403,17 +1482,17 @@ function dittoSmallPeerInfoGetIsEnabled(dittoPointer) {
|
|
|
1403
1482
|
return ditto_small_peer_info_get_is_enabled(dittoPointer);
|
|
1404
1483
|
}
|
|
1405
1484
|
/** @internal */
|
|
1406
|
-
|
|
1485
|
+
function dittoSmallPeerInfoSetEnabled(dittoPointer, isEnabled) {
|
|
1407
1486
|
ensureInitialized();
|
|
1408
|
-
ditto_small_peer_info_set_enabled(dittoPointer, isEnabled);
|
|
1487
|
+
return ditto_small_peer_info_set_enabled(dittoPointer, isEnabled);
|
|
1409
1488
|
}
|
|
1410
1489
|
/** @internal */
|
|
1411
|
-
|
|
1490
|
+
function dittoSmallPeerInfoGetSyncScope(dittoPointer) {
|
|
1412
1491
|
ensureInitialized();
|
|
1413
1492
|
return ditto_small_peer_info_get_sync_scope(dittoPointer);
|
|
1414
1493
|
}
|
|
1415
1494
|
/** @internal */
|
|
1416
|
-
|
|
1495
|
+
function dittoSmallPeerInfoSetSyncScope(dittoPointer, syncScope) {
|
|
1417
1496
|
ensureInitialized();
|
|
1418
1497
|
return ditto_small_peer_info_set_sync_scope(dittoPointer, syncScope);
|
|
1419
1498
|
}
|
|
@@ -1448,7 +1527,6 @@ function dittoSmallPeerInfoSetMetadata(dittoPointer, metadata) {
|
|
|
1448
1527
|
function dittoRegisterTransportConditionChangedCallback(self, cb) {
|
|
1449
1528
|
ensureInitialized();
|
|
1450
1529
|
if (!cb) {
|
|
1451
|
-
// @Konstantin: do we do this?
|
|
1452
1530
|
ditto_register_transport_condition_changed_callback(self, null);
|
|
1453
1531
|
}
|
|
1454
1532
|
else {
|
|
@@ -1813,8 +1891,12 @@ const ERROR_CODES = {
|
|
|
1813
1891
|
'store/crdt': 'An error occurred processing a CRDT.',
|
|
1814
1892
|
/** Error for a document not found. */
|
|
1815
1893
|
'store/document-not-found': 'The document with the provided ID could not be found.',
|
|
1894
|
+
/** Error for writing to a read-only transaction. */
|
|
1895
|
+
'store/transaction-read-only': 'A mutating DQL query was attempted using a read-only transaction.',
|
|
1816
1896
|
/** Error for an invalid document ID. */
|
|
1817
1897
|
'store/document-id': 'The document ID is invalid.',
|
|
1898
|
+
/** Error when the chosen persistence directory is already in use by another Ditto instance. */
|
|
1899
|
+
'store/persistence-directory-locked': 'The chosen persistence directory is already in use by another Ditto instance.',
|
|
1818
1900
|
/** Permission has been denied for a file operation when working with attachments. */
|
|
1819
1901
|
'store/attachment-file-permission-denied': 'Permission has been denied for a file operation when working with attachments.',
|
|
1820
1902
|
/** The source file for an attachment does not exist. */
|
|
@@ -1854,6 +1936,21 @@ const ERROR_CODES = {
|
|
|
1854
1936
|
'validation/not-json-compatible': 'Value is not serializable as JSON.',
|
|
1855
1937
|
/** A validation error where a size limit was exceeded. */
|
|
1856
1938
|
'validation/size-limit-exceeded': 'The size limit has been exceeded.',
|
|
1939
|
+
//
|
|
1940
|
+
// Encryption errors
|
|
1941
|
+
//
|
|
1942
|
+
/**
|
|
1943
|
+
* Error when a passphrase was provided but the store is not encrypted.
|
|
1944
|
+
*
|
|
1945
|
+
* This error is not in use for the JavaScript SDK, which currently does not
|
|
1946
|
+
* support encrypted stores.
|
|
1947
|
+
*/
|
|
1948
|
+
'encryption/extraneous-passphrase-given': 'Unexpected passphrase provided for the currently unencrypted store.',
|
|
1949
|
+
//
|
|
1950
|
+
// Differ errors
|
|
1951
|
+
//
|
|
1952
|
+
/** */
|
|
1953
|
+
'differ/identity-key-path-invalid': 'A provided identity key path is invalid.',
|
|
1857
1954
|
};
|
|
1858
1955
|
|
|
1859
1956
|
//
|
|
@@ -1897,12 +1994,20 @@ const DEFAULT_STATUS_CODE_MAPPING = {
|
|
|
1897
1994
|
StoreQuery: ['query/execution'],
|
|
1898
1995
|
ParameterQuery: ['query/parameter'],
|
|
1899
1996
|
//
|
|
1997
|
+
// Encryption errors
|
|
1998
|
+
//
|
|
1999
|
+
EncryptionExtraneousPassphraseGiven: [
|
|
2000
|
+
'encryption/extraneous-passphrase-given',
|
|
2001
|
+
],
|
|
2002
|
+
//
|
|
1900
2003
|
// Store errors
|
|
1901
2004
|
//
|
|
1902
2005
|
StoreDatabase: ['store/backend'],
|
|
1903
2006
|
StoreDocumentId: ['store/document-id'],
|
|
1904
2007
|
StoreDocumentNotFound: ['store/document-not-found'],
|
|
2008
|
+
StoreTransactionReadOnly: ['store/transaction-read-only'],
|
|
1905
2009
|
Crdt: ['store/crdt'],
|
|
2010
|
+
LockedDittoWorkingDirectory: ['store/persistence-directory-locked'],
|
|
1906
2011
|
//
|
|
1907
2012
|
// Validation errors
|
|
1908
2013
|
//
|
|
@@ -1918,17 +2023,12 @@ const DEFAULT_STATUS_CODE_MAPPING = {
|
|
|
1918
2023
|
ValidationNotAMap: ['validation/not-an-object'],
|
|
1919
2024
|
ValidationSizeLimitExceeded: ['validation/size-limit-exceeded'],
|
|
1920
2025
|
//
|
|
2026
|
+
// Differ errors
|
|
2027
|
+
//
|
|
2028
|
+
DifferIdentityKeyPathInvalid: ['differ/identity-key-path-invalid'],
|
|
2029
|
+
//
|
|
1921
2030
|
// Lifecycle errors
|
|
1922
2031
|
//
|
|
1923
|
-
// FIXME: A locked Ditto working directory should eventually not result in an
|
|
1924
|
-
// `internal` error. Here it is mapped to that until
|
|
1925
|
-
// https://github.com/getditto/ditto/issues/12096 is fixed, and this kind of
|
|
1926
|
-
// error is actually thrown instead of the SDK panicking when the persistence
|
|
1927
|
-
// directory is locked.
|
|
1928
|
-
LockedDittoWorkingDirectory: [
|
|
1929
|
-
'internal',
|
|
1930
|
-
'Ditto working directory is locked.',
|
|
1931
|
-
],
|
|
1932
2032
|
Transport: ['internal', 'Transport error.'],
|
|
1933
2033
|
Unsupported: ['sdk/unsupported'],
|
|
1934
2034
|
Unknown: ['internal/unknown-error'], // May be updated in v5, c.f. #12755
|
|
@@ -2174,7 +2274,7 @@ class AttachmentToken {
|
|
|
2174
2274
|
|
|
2175
2275
|
// NOTE: this is patched up with the actual build version by Jake task
|
|
2176
2276
|
// build:package and has to be a valid semantic version as defined here: https://semver.org.
|
|
2177
|
-
const fullBuildVersionString = '4.
|
|
2277
|
+
const fullBuildVersionString = '4.11.0-preview.1';
|
|
2178
2278
|
|
|
2179
2279
|
//
|
|
2180
2280
|
// Copyright © 2021 DittoLive Incorporated. All rights reserved.
|
|
@@ -4057,6 +4157,10 @@ Bridge.queryResult = new _a(queryResultFree);
|
|
|
4057
4157
|
/** @internal */
|
|
4058
4158
|
Bridge.queryResultItem = new _a(queryResultItemFree);
|
|
4059
4159
|
/** @internal */
|
|
4160
|
+
Bridge.transaction = new _a(transactionFree);
|
|
4161
|
+
/** @internal */
|
|
4162
|
+
Bridge.differ = new _a(differFree);
|
|
4163
|
+
/** @internal */
|
|
4060
4164
|
Bridge.ditto = new _a(async (dittoPointer) => {
|
|
4061
4165
|
// HACK: quick and dirty, clear all presence callbacks. This covers presence
|
|
4062
4166
|
// v1 and v2 callbacks. v3 should be cleared properly by the `Presence`
|
|
@@ -4407,6 +4511,9 @@ async function step(closure) {
|
|
|
4407
4511
|
// See PR #4833 for details:
|
|
4408
4512
|
// https://github.com/getditto/ditto/pull/4833
|
|
4409
4513
|
const performAsyncToWorkaroundNonAsyncFFIAPI = step;
|
|
4514
|
+
function capitalize(str) {
|
|
4515
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
4516
|
+
}
|
|
4410
4517
|
|
|
4411
4518
|
//
|
|
4412
4519
|
// Copyright © 2021 DittoLive Incorporated. All rights reserved.
|
|
@@ -7914,6 +8021,69 @@ class WriteTransaction {
|
|
|
7914
8021
|
}
|
|
7915
8022
|
}
|
|
7916
8023
|
|
|
8024
|
+
/** Encapsulates information about a transaction.
|
|
8025
|
+
*
|
|
8026
|
+
* @see {@link Store.transaction | ditto.store.transaction()}
|
|
8027
|
+
*/
|
|
8028
|
+
class TransactionInfo {
|
|
8029
|
+
constructor(id, isReadOnly, hint) {
|
|
8030
|
+
this.id = id;
|
|
8031
|
+
this.hint = hint;
|
|
8032
|
+
this.isReadOnly = isReadOnly;
|
|
8033
|
+
}
|
|
8034
|
+
}
|
|
8035
|
+
/**
|
|
8036
|
+
* Represents a transaction in the Ditto store.
|
|
8037
|
+
*
|
|
8038
|
+
* A `Transaction` groups multiple operations into a single atomic unit,
|
|
8039
|
+
* ensuring that all operations within the transaction are either fully applied
|
|
8040
|
+
* or not applied at all, thereby maintaining data integrity.
|
|
8041
|
+
*
|
|
8042
|
+
* For more information on creating and using transactions, refer to the
|
|
8043
|
+
* {@link Store.transaction | ditto.store.transaction()} method. For a comprehensive guide on
|
|
8044
|
+
* transactions, please visit the
|
|
8045
|
+
* [Ditto documentation](https://docs.ditto.live/sdk/latest/crud/transactions).
|
|
8046
|
+
*/
|
|
8047
|
+
class Transaction {
|
|
8048
|
+
constructor(store) {
|
|
8049
|
+
this.store = store;
|
|
8050
|
+
}
|
|
8051
|
+
/** Provides information about the current transaction. */
|
|
8052
|
+
get info() {
|
|
8053
|
+
const transactionHandle = Bridge.transaction.handleFor(this);
|
|
8054
|
+
const cborData = transactionInfo(transactionHandle.deref());
|
|
8055
|
+
const options = CBOR.decode(cborData);
|
|
8056
|
+
return new TransactionInfo(options.id, options.is_read_only, options.hint);
|
|
8057
|
+
}
|
|
8058
|
+
async execute(query, queryArguments) {
|
|
8059
|
+
if (typeof query !== 'string') {
|
|
8060
|
+
throw new DittoError('query/invalid', `Expected parameter 'query' to be of type 'string', found: ${typeof query}`);
|
|
8061
|
+
}
|
|
8062
|
+
return this.store.ditto.deferCloseAsync(async () => {
|
|
8063
|
+
let queryArgumentsCBOR = null;
|
|
8064
|
+
if (queryArguments) {
|
|
8065
|
+
try {
|
|
8066
|
+
const queryArgumentsJSON = desugarJSObject(queryArguments);
|
|
8067
|
+
queryArgumentsCBOR = CBOR.encode(queryArgumentsJSON);
|
|
8068
|
+
}
|
|
8069
|
+
catch (error) {
|
|
8070
|
+
throw new DittoError('query/arguments-invalid', `Unable to encode query arguments: ${error.message}`);
|
|
8071
|
+
}
|
|
8072
|
+
}
|
|
8073
|
+
const transactionHandle = Bridge.transaction.handleFor(this);
|
|
8074
|
+
const queryResultPointer = await mapFFIErrorsAsync(async () => transactionExecuteAsync(transactionHandle.deref(), query, queryArgumentsCBOR));
|
|
8075
|
+
return Bridge.queryResult.bridge(queryResultPointer, () => new QueryResult(queryResultPointer));
|
|
8076
|
+
});
|
|
8077
|
+
}
|
|
8078
|
+
// ----------------------------------------------------------- Internal ------
|
|
8079
|
+
/** @internal */
|
|
8080
|
+
async complete(action) {
|
|
8081
|
+
const transactionHandle = Bridge.transaction.handleFor(this);
|
|
8082
|
+
const result = await mapFFIErrorsAsync(async () => await transactionCompleteAsync(transactionHandle.deref(), capitalize(action)));
|
|
8083
|
+
return result.toLowerCase();
|
|
8084
|
+
}
|
|
8085
|
+
}
|
|
8086
|
+
|
|
7917
8087
|
//
|
|
7918
8088
|
// Copyright © 2021 DittoLive Incorporated. All rights reserved.
|
|
7919
8089
|
//
|
|
@@ -7925,6 +8095,22 @@ class WriteTransaction {
|
|
|
7925
8095
|
* {@link Ditto} instance via its {@link Ditto.store | store} property.
|
|
7926
8096
|
*/
|
|
7927
8097
|
class Store {
|
|
8098
|
+
/** @internal */
|
|
8099
|
+
// NOTE: currently, this property will only return the currently _running_
|
|
8100
|
+
// transactions rather than all pending. This means it's at most a single
|
|
8101
|
+
// read-write transaction, and potentially multiple read-only transactions.
|
|
8102
|
+
// Ideally, we'd want to have all _enqueued_ transactions appear here but
|
|
8103
|
+
// we don't have the infrastructure in the Rust Core for this yet.
|
|
8104
|
+
// Therefore, we'll keep this property internal for the time being,
|
|
8105
|
+
// which is still useful for some tests.
|
|
8106
|
+
get transactions() {
|
|
8107
|
+
return this.ditto.deferClose((dittoHandle) => {
|
|
8108
|
+
const storePointer = dittoPointerToStorePointer(dittoHandle.deref());
|
|
8109
|
+
const cborData = storeTransactions(storePointer);
|
|
8110
|
+
const data = CBOR.decode(cborData);
|
|
8111
|
+
return data.map((t) => new TransactionInfo(t.id, t.is_read_only, t.hint));
|
|
8112
|
+
});
|
|
8113
|
+
}
|
|
7928
8114
|
/**
|
|
7929
8115
|
* Register a handler to be called whenever a query's results change in the
|
|
7930
8116
|
* local store.
|
|
@@ -8072,31 +8258,6 @@ class Store {
|
|
|
8072
8258
|
return mapFFIErrors(() => dittoGetCollectionNames(dittoHandle.deref()));
|
|
8073
8259
|
});
|
|
8074
8260
|
}
|
|
8075
|
-
/**
|
|
8076
|
-
* Executes a DQL query and returns matching items as a query result.
|
|
8077
|
-
*
|
|
8078
|
-
* **Note:** only returns results from the local store without waiting for any
|
|
8079
|
-
* {@link SyncSubscription | sync subscriptions} to have caught up with the
|
|
8080
|
-
* latest changes. Only use this method if your program must proceed with
|
|
8081
|
-
* immediate results. Use a {@link StoreObserver | store observer} to receive
|
|
8082
|
-
* updates to query results as soon as they have been synced to this peer.
|
|
8083
|
-
*
|
|
8084
|
-
* @param query A string containing a valid query expressed in DQL.
|
|
8085
|
-
* @param queryArguments An object of values keyed by the placeholder name
|
|
8086
|
-
* without the leading `:`. Example: `{ "name": "John" }` for a query like
|
|
8087
|
-
* `SELECT * FROM people WHERE name = :name`.
|
|
8088
|
-
* @template T The type of items returned by the query. This is a convenience
|
|
8089
|
-
* type that is neither inferred from the `query` parameter nor validated
|
|
8090
|
-
* against it.
|
|
8091
|
-
* @template U The type of the query arguments
|
|
8092
|
-
* @returns A promise for a {@link QueryResult} containing a
|
|
8093
|
-
* {@link QueryResultItem} for each match.
|
|
8094
|
-
* @throws {@link DittoError} `query/invalid`: if `query` argument is not a
|
|
8095
|
-
* string or not valid DQL.
|
|
8096
|
-
* @throws {@link DittoError} `query/arguments-invalid`: if `queryArguments`
|
|
8097
|
-
* argument is invalid (e.g. contains unsupported types).
|
|
8098
|
-
* @throws {@link DittoError} may throw other errors.
|
|
8099
|
-
*/
|
|
8100
8261
|
async execute(query, queryArguments) {
|
|
8101
8262
|
if (typeof query !== 'string') {
|
|
8102
8263
|
throw new DittoError('query/invalid', `Expected parameter 'query' to be of type 'string', found: ${typeof query}`);
|
|
@@ -8408,6 +8569,131 @@ class Store {
|
|
|
8408
8569
|
this.attachmentFetchers = Object.freeze(newAttachmentFetchers);
|
|
8409
8570
|
return true;
|
|
8410
8571
|
}
|
|
8572
|
+
// ------------------------------------------ Working with Transactions ------
|
|
8573
|
+
/**
|
|
8574
|
+
* Executes multiple DQL queries within a single atomic transaction.
|
|
8575
|
+
*
|
|
8576
|
+
* This ensures that either all statements are executed successfully, or none
|
|
8577
|
+
* are executed at all, providing strong consistency guarantees. Certain mesh
|
|
8578
|
+
* configurations may impose limitations on these guarantees. For more
|
|
8579
|
+
* details, refer to the [Ditto
|
|
8580
|
+
* documentation](https://docs.ditto.live/sdk/latest/crud/transactions).
|
|
8581
|
+
*
|
|
8582
|
+
* Transactions are initiated as read-write by default, and only one
|
|
8583
|
+
* read-write transaction can be executed at any given time. Any other
|
|
8584
|
+
* read-write transaction started concurrently will wait until the current
|
|
8585
|
+
* transaction has been committed or rolled back. Therefore, it is crucial to
|
|
8586
|
+
* ensure a transaction finishes as early as possible to prevent blocking
|
|
8587
|
+
* other read-write transactions.
|
|
8588
|
+
*
|
|
8589
|
+
* A transaction can also be configured to be read-only using the `isReadOnly`
|
|
8590
|
+
* parameter. Multiple read-only transactions can be executed concurrently.
|
|
8591
|
+
* However, executing a mutating DQL statement in a read-only transaction will
|
|
8592
|
+
* throw an error.
|
|
8593
|
+
*
|
|
8594
|
+
* If errors occur in an `execute()` call within a transaction block and the
|
|
8595
|
+
* error is caught and handled within the block, the transaction will continue
|
|
8596
|
+
* to run and not be rolled back. When an error is thrown at any point inside
|
|
8597
|
+
* the transaction block or while committing the transaction, the transaction
|
|
8598
|
+
* is implicitly rolled back, and the error is propagated to the caller.
|
|
8599
|
+
*
|
|
8600
|
+
* When a Ditto instance goes out of scope, it will drive all pending
|
|
8601
|
+
* transactions to completion before being shut down.
|
|
8602
|
+
*
|
|
8603
|
+
* **Warning:** Calling `ditto.store.execute()` or creating a nested
|
|
8604
|
+
* transaction within a transaction may lead to a deadlock.
|
|
8605
|
+
*
|
|
8606
|
+
* The transaction closure provided here can either return a
|
|
8607
|
+
* {@link TransactionCompletionAction} or an arbitrary value, either of which
|
|
8608
|
+
* will then also be returned by the call to this method itself. If one of the
|
|
8609
|
+
* {@link TransactionCompletionAction} values `'commit'` or `'rollback'` is
|
|
8610
|
+
* returned from the closure, that action is applied. If any other value,
|
|
8611
|
+
* including `null`, is returned, the transaction is committed unless an error
|
|
8612
|
+
* is thrown from the closure.
|
|
8613
|
+
*
|
|
8614
|
+
* Example usage (explicit completion):
|
|
8615
|
+
*
|
|
8616
|
+
* ```ts
|
|
8617
|
+
* await store.transaction(async (transaction) => {
|
|
8618
|
+
* // ...
|
|
8619
|
+
* return 'commit'
|
|
8620
|
+
* })
|
|
8621
|
+
* ```
|
|
8622
|
+
*
|
|
8623
|
+
* Example usage (returning a custom type):
|
|
8624
|
+
*
|
|
8625
|
+
* ```ts
|
|
8626
|
+
* interface UserData {
|
|
8627
|
+
* id: string
|
|
8628
|
+
* name: string
|
|
8629
|
+
* }
|
|
8630
|
+
*
|
|
8631
|
+
* const user: UserData = await store.transaction<UserData>(async (transaction) => {
|
|
8632
|
+
* // ...
|
|
8633
|
+
* return { id: 'u1', name: 'Alice' }
|
|
8634
|
+
* })
|
|
8635
|
+
* ```
|
|
8636
|
+
*
|
|
8637
|
+
* @template T The type of the value returned from the `scope` function.
|
|
8638
|
+
* Defaults to `TransactionCompletionAction`.
|
|
8639
|
+
* @param {Function} scope A function that provides access to a transaction
|
|
8640
|
+
* object to execute DQL queries.
|
|
8641
|
+
* @param {TransactionOptions} [options] Optional settings for the
|
|
8642
|
+
* transaction.
|
|
8643
|
+
* @returns {Promise<T>} A promise that resolves to the value returned by the
|
|
8644
|
+
* scope function. If that value is a {@link TransactionCompletionAction}, the
|
|
8645
|
+
* transaction is completed with the same action.
|
|
8646
|
+
* @throws {DittoError} Throws `DittoError` of `store/transaction-read-only`
|
|
8647
|
+
* if a mutating query is executed in a read-only transaction.
|
|
8648
|
+
* @throws {DittoError} May throw other `DittoError`s.
|
|
8649
|
+
* @throws Will rethrow any error thrown within the `scope` function.
|
|
8650
|
+
* @see {@link Transaction}
|
|
8651
|
+
* @see {@link TransactionOptions}
|
|
8652
|
+
*/
|
|
8653
|
+
async transaction(scope, options = {}) {
|
|
8654
|
+
return this.ditto.deferCloseAsync(async () => {
|
|
8655
|
+
if ((options === null || options === void 0 ? void 0 : options.isReadOnly) && typeof options.isReadOnly !== 'boolean')
|
|
8656
|
+
throw new TypeError("Expected 'options.isReadOnly' to be a boolean");
|
|
8657
|
+
if ((options === null || options === void 0 ? void 0 : options.hint) && typeof options.hint !== 'string')
|
|
8658
|
+
throw new TypeError("Expected 'options.hint' to be a string");
|
|
8659
|
+
const transaction = await this.beginTransaction(options);
|
|
8660
|
+
// REFACTOR: completing with action `rollback` should never fail even
|
|
8661
|
+
// though the API is fallible (because `commit` _can_ fail). The Rust Core
|
|
8662
|
+
// will log an error if anything goes wrong here, so we simply ignore any
|
|
8663
|
+
// `transaction.complete()` errors.
|
|
8664
|
+
let result;
|
|
8665
|
+
try {
|
|
8666
|
+
result = await scope(transaction);
|
|
8667
|
+
}
|
|
8668
|
+
catch (error) {
|
|
8669
|
+
await transaction.complete('rollback');
|
|
8670
|
+
throw error;
|
|
8671
|
+
}
|
|
8672
|
+
if (result === 'rollback' || result === 'commit') {
|
|
8673
|
+
return (await transaction.complete(result));
|
|
8674
|
+
}
|
|
8675
|
+
await transaction.complete('commit');
|
|
8676
|
+
return result;
|
|
8677
|
+
});
|
|
8678
|
+
}
|
|
8679
|
+
// ----------------------------------------------------------- Internal ------
|
|
8680
|
+
/** @internal */
|
|
8681
|
+
async beginTransaction(options = {}) {
|
|
8682
|
+
return this.ditto.deferCloseAsync(async (dittoHandle) => {
|
|
8683
|
+
var _a, _b;
|
|
8684
|
+
// We explicitely set the default value here to maintain consistency with
|
|
8685
|
+
// other API that we already have, while acknowledging that default values
|
|
8686
|
+
// are generally better to be dictated from Core (via a factory method).
|
|
8687
|
+
const isReadOnly = (_a = options.isReadOnly) !== null && _a !== void 0 ? _a : false;
|
|
8688
|
+
const hint = (_b = options.hint) !== null && _b !== void 0 ? _b : null;
|
|
8689
|
+
const storePointer = dittoPointerToStorePointer(dittoHandle.deref());
|
|
8690
|
+
const transactionPointer = await storeBeginTransaction(storePointer, {
|
|
8691
|
+
isReadOnly,
|
|
8692
|
+
hint,
|
|
8693
|
+
});
|
|
8694
|
+
return Bridge.transaction.bridge(transactionPointer, () => new Transaction(this));
|
|
8695
|
+
});
|
|
8696
|
+
}
|
|
8411
8697
|
/** @internal */
|
|
8412
8698
|
close() {
|
|
8413
8699
|
for (const observer of this.observers)
|
|
@@ -8417,17 +8703,6 @@ class Store {
|
|
|
8417
8703
|
// NOTE: live query webhook is taken care of by the FFI's
|
|
8418
8704
|
// `ditto_shutdown()`, no need to unregister it here.
|
|
8419
8705
|
}
|
|
8420
|
-
/**
|
|
8421
|
-
* Private method, used only by the Portal https://github.com/getditto/ditto/pull/3652
|
|
8422
|
-
* @internal
|
|
8423
|
-
*/
|
|
8424
|
-
async registerLiveQueryWebhook(collectionName, query, url) {
|
|
8425
|
-
return this.ditto.deferCloseAsync(async (dittoHandle) => {
|
|
8426
|
-
const validatedQuery = validateQuery(query);
|
|
8427
|
-
const idCBOR = await liveQueryWebhookRegister(dittoHandle.deref(), collectionName, validatedQuery, [], 0, 0, url);
|
|
8428
|
-
return new DocumentID(idCBOR, true);
|
|
8429
|
-
});
|
|
8430
|
-
}
|
|
8431
8706
|
}
|
|
8432
8707
|
|
|
8433
8708
|
//
|
|
@@ -9323,8 +9598,8 @@ class SmallPeerInfo {
|
|
|
9323
9598
|
set isEnabled(newValue) {
|
|
9324
9599
|
if (typeof newValue !== 'boolean')
|
|
9325
9600
|
throw new TypeError(`Expected boolean, got ${typeof newValue}`);
|
|
9326
|
-
|
|
9327
|
-
|
|
9601
|
+
this.ditto.deferClose((dittoHandle) => {
|
|
9602
|
+
dittoSmallPeerInfoSetEnabled(dittoHandle.deref(), newValue);
|
|
9328
9603
|
});
|
|
9329
9604
|
}
|
|
9330
9605
|
/**
|
|
@@ -9385,15 +9660,35 @@ class SmallPeerInfo {
|
|
|
9385
9660
|
dittoSmallPeerInfoSetMetadata(dittoHandle.deref(), metadata);
|
|
9386
9661
|
});
|
|
9387
9662
|
}
|
|
9663
|
+
/**
|
|
9664
|
+
* Determines which "kind" of peers the small peer info will be replicated to.
|
|
9665
|
+
*
|
|
9666
|
+
* Defaults to `LocalPeerOnly`, which means no replication. Set this to
|
|
9667
|
+
* `BigPeerOnly` to replicate collected info to the Big Peer.
|
|
9668
|
+
*
|
|
9669
|
+
* @throws when set to a value other than `BigPeerOnly` or `LocalPeerOnly`.
|
|
9670
|
+
*/
|
|
9671
|
+
get syncScope() {
|
|
9672
|
+
return this.ditto.deferClose((dittoHandle) => {
|
|
9673
|
+
return dittoSmallPeerInfoGetSyncScope(dittoHandle.deref());
|
|
9674
|
+
});
|
|
9675
|
+
}
|
|
9676
|
+
set syncScope(syncScope) {
|
|
9677
|
+
this.ditto.deferClose((dittoHandle) => {
|
|
9678
|
+
return dittoSmallPeerInfoSetSyncScope(dittoHandle.deref(), syncScope);
|
|
9679
|
+
});
|
|
9680
|
+
}
|
|
9388
9681
|
/**
|
|
9389
9682
|
* Determines which "kind" of peers the small peer info will be
|
|
9390
9683
|
* replicated to.
|
|
9391
9684
|
*
|
|
9392
9685
|
* Defaults to `LocalPeerOnly`, which means no replication. Set this to
|
|
9393
9686
|
* `BigPeerOnly` to replicate collected info to the Big Peer.
|
|
9687
|
+
*
|
|
9688
|
+
* @deprecated use {@link SmallPeerInfo.syncScope} instead.
|
|
9394
9689
|
*/
|
|
9395
9690
|
async getSyncScope() {
|
|
9396
|
-
return this.ditto.
|
|
9691
|
+
return this.ditto.deferClose((dittoHandle) => {
|
|
9397
9692
|
return dittoSmallPeerInfoGetSyncScope(dittoHandle.deref());
|
|
9398
9693
|
});
|
|
9399
9694
|
}
|
|
@@ -9404,9 +9699,10 @@ class SmallPeerInfo {
|
|
|
9404
9699
|
*
|
|
9405
9700
|
* @param syncScope the new sync scope.
|
|
9406
9701
|
* @throws when set to a value other than `BigPeerOnly` or `LocalPeerOnly`.
|
|
9702
|
+
* @deprecated use {@link SmallPeerInfo.syncScope} instead.
|
|
9407
9703
|
*/
|
|
9408
9704
|
async setSyncScope(syncScope) {
|
|
9409
|
-
return this.ditto.
|
|
9705
|
+
return this.ditto.deferClose((dittoHandle) => {
|
|
9410
9706
|
return dittoSmallPeerInfoSetSyncScope(dittoHandle.deref(), syncScope);
|
|
9411
9707
|
});
|
|
9412
9708
|
}
|
|
@@ -9581,7 +9877,7 @@ class Ditto {
|
|
|
9581
9877
|
// determined for P2P transports based on the environment. We specify this here by setting
|
|
9582
9878
|
// `transportConfigMode` to 'PlatformDependent'.
|
|
9583
9879
|
const transportConfigMode = 'PlatformDependent';
|
|
9584
|
-
const dittoPointer =
|
|
9880
|
+
const dittoPointer = mapFFIErrors(() => dittoTryNewBlocking(this.persistenceDirectory, identityConfig, historyTracking, transportConfigMode));
|
|
9585
9881
|
const appID = dittoAuthClientGetAppID(dittoPointer);
|
|
9586
9882
|
const siteID = dittoAuthClientGetSiteID(dittoPointer);
|
|
9587
9883
|
Bridge.ditto.bridge(dittoPointer, this);
|
|
@@ -9753,11 +10049,13 @@ class Ditto {
|
|
|
9753
10049
|
const path = require('path');
|
|
9754
10050
|
if (process.platform === 'win32') {
|
|
9755
10051
|
// Normalize the path on Windows to prevent issues with its max path
|
|
9756
|
-
// length. Windows has a hard limit at 260 characters
|
|
9757
|
-
// [1]. When this limit is exceeded reads and writes
|
|
10052
|
+
// length (if needed). Windows has a hard limit at 260 characters
|
|
10053
|
+
// for file paths [1]. When this limit is exceeded reads and writes
|
|
10054
|
+
// may fail.
|
|
9758
10055
|
//
|
|
9759
10056
|
// [1]: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation
|
|
9760
|
-
validatedPath
|
|
10057
|
+
if (!validatedPath.startsWith('\\\\?\\'))
|
|
10058
|
+
validatedPath = `\\\\?\\${path.resolve(validatedPath)}`;
|
|
9761
10059
|
}
|
|
9762
10060
|
const absolutePath = path.resolve(validatedPath);
|
|
9763
10061
|
// We check if the directory exists before creating it to be able to
|
|
@@ -10227,6 +10525,58 @@ const isDirectoryWritable = (directoryPath) => {
|
|
|
10227
10525
|
return true;
|
|
10228
10526
|
};
|
|
10229
10527
|
|
|
10528
|
+
//
|
|
10529
|
+
// Copyright © 2025 DittoLive Incorporated. All rights reserved.
|
|
10530
|
+
//
|
|
10531
|
+
/**
|
|
10532
|
+
* Represents a diff between two arrays.
|
|
10533
|
+
*
|
|
10534
|
+
* Create a diff between arrays of {@link QueryResultItem} using a {@link Differ}.
|
|
10535
|
+
*/
|
|
10536
|
+
class Diff {
|
|
10537
|
+
constructor(cborData) {
|
|
10538
|
+
const object = CBOR.decode(cborData);
|
|
10539
|
+
this.insertions = object.insertions;
|
|
10540
|
+
this.deletions = object.deletions;
|
|
10541
|
+
this.updates = object.updates;
|
|
10542
|
+
this.moves = object.moves.map(([from, to]) => ({ from, to }));
|
|
10543
|
+
}
|
|
10544
|
+
}
|
|
10545
|
+
/**
|
|
10546
|
+
* Calculates diffs between arrays of {@link QueryResultItem}.
|
|
10547
|
+
*
|
|
10548
|
+
* Use a {@link Differ} with a {@link StoreObserver} to get the diff between
|
|
10549
|
+
* subsequent query results delivered by the store observer.
|
|
10550
|
+
*/
|
|
10551
|
+
class Differ {
|
|
10552
|
+
/** Create a new differ. */
|
|
10553
|
+
constructor() {
|
|
10554
|
+
const ffiDiffer = differNew();
|
|
10555
|
+
return Bridge.differ.bridge(ffiDiffer, this);
|
|
10556
|
+
}
|
|
10557
|
+
/**
|
|
10558
|
+
* Calculate the diff of the provided items against the last set of items that
|
|
10559
|
+
* were passed to this differ.
|
|
10560
|
+
*
|
|
10561
|
+
* The returned {@link Diff} identifies changes from the old array of items
|
|
10562
|
+
* to the new array of items using indices into both arrays.
|
|
10563
|
+
*
|
|
10564
|
+
* Initially, the differ has no items, so the first call to this method will
|
|
10565
|
+
* always return a diff showing all items as insertions.
|
|
10566
|
+
*
|
|
10567
|
+
* The identity of items is determined by their `_id` field.
|
|
10568
|
+
*/
|
|
10569
|
+
diff(items) {
|
|
10570
|
+
const pointers = items.map((item) => item.deref());
|
|
10571
|
+
const cborData = differDiff(this.deref(), pointers);
|
|
10572
|
+
return new Diff(cborData);
|
|
10573
|
+
}
|
|
10574
|
+
/** @internal */
|
|
10575
|
+
deref() {
|
|
10576
|
+
return Bridge.differ.handleFor(this).deref();
|
|
10577
|
+
}
|
|
10578
|
+
}
|
|
10579
|
+
|
|
10230
10580
|
//
|
|
10231
10581
|
// Copyright © 2023 DittoLive Incorporated. All rights reserved.
|
|
10232
10582
|
//
|
|
@@ -10314,8 +10664,7 @@ class QueryResultItem {
|
|
|
10314
10664
|
* method once and keep it for as long as needed.
|
|
10315
10665
|
*/
|
|
10316
10666
|
cborData() {
|
|
10317
|
-
|
|
10318
|
-
return queryResultItemCBOR(resultItemHandle.deref());
|
|
10667
|
+
return queryResultItemCBOR(this.deref());
|
|
10319
10668
|
}
|
|
10320
10669
|
/**
|
|
10321
10670
|
* Returns the content of the item as a JSON string.
|
|
@@ -10324,8 +10673,7 @@ class QueryResultItem {
|
|
|
10324
10673
|
* method once and keep it for as long as needed.
|
|
10325
10674
|
*/
|
|
10326
10675
|
jsonString() {
|
|
10327
|
-
|
|
10328
|
-
return queryResultItemJSON(resultItemHandle.deref());
|
|
10676
|
+
return queryResultItemJSON(this.deref());
|
|
10329
10677
|
}
|
|
10330
10678
|
// ----------------------------------------------------------- Internal ------
|
|
10331
10679
|
/**
|
|
@@ -10339,6 +10687,15 @@ class QueryResultItem {
|
|
|
10339
10687
|
}
|
|
10340
10688
|
/** @internal */
|
|
10341
10689
|
constructor() { }
|
|
10690
|
+
/** @internal */
|
|
10691
|
+
static fromJSON(jsonData) {
|
|
10692
|
+
const encodedData = new TextEncoder().encode(jsonData);
|
|
10693
|
+
return Bridge.queryResultItem.bridge(queryResultItemNew(encodedData));
|
|
10694
|
+
}
|
|
10695
|
+
/** @internal */
|
|
10696
|
+
deref() {
|
|
10697
|
+
return Bridge.queryResultItem.handleFor(this).deref();
|
|
10698
|
+
}
|
|
10342
10699
|
}
|
|
10343
10700
|
|
|
10344
10701
|
/**
|
|
@@ -10375,6 +10732,8 @@ Bridge.attachment.registerType(Attachment);
|
|
|
10375
10732
|
Bridge.connectionRequest.registerType(ConnectionRequest);
|
|
10376
10733
|
Bridge.document.registerType(Document);
|
|
10377
10734
|
Bridge.queryResultItem.registerType(QueryResultItem);
|
|
10735
|
+
Bridge.differ.registerType(Differ);
|
|
10736
|
+
Bridge.transaction.registerType(Transaction);
|
|
10378
10737
|
Bridge.queryResult.registerType(QueryResult);
|
|
10379
10738
|
Bridge.mutableDocument.registerType(MutableDocument);
|
|
10380
10739
|
Bridge.ditto.registerType(Ditto);
|
|
@@ -10391,6 +10750,8 @@ exports.Collection = Collection;
|
|
|
10391
10750
|
exports.CollectionsEvent = CollectionsEvent;
|
|
10392
10751
|
exports.ConnectionRequest = ConnectionRequest;
|
|
10393
10752
|
exports.Counter = Counter;
|
|
10753
|
+
exports.Diff = Diff;
|
|
10754
|
+
exports.Differ = Differ;
|
|
10394
10755
|
exports.Ditto = Ditto;
|
|
10395
10756
|
exports.DittoError = DittoError;
|
|
10396
10757
|
exports.Document = Document;
|
|
@@ -10424,6 +10785,8 @@ exports.StoreObserver = StoreObserver;
|
|
|
10424
10785
|
exports.Subscription = Subscription;
|
|
10425
10786
|
exports.Sync = Sync;
|
|
10426
10787
|
exports.SyncSubscription = SyncSubscription;
|
|
10788
|
+
exports.Transaction = Transaction;
|
|
10789
|
+
exports.TransactionInfo = TransactionInfo;
|
|
10427
10790
|
exports.TransportConfig = TransportConfig;
|
|
10428
10791
|
exports.UpdateResult = UpdateResult;
|
|
10429
10792
|
exports.UpdateResultsMap = UpdateResultsMap;
|