@dittolive/ditto 4.6.0 → 4.7.0-rc.3

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 (69) hide show
  1. package/README.md +2 -2
  2. package/node/ditto.cjs.js +479 -128
  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 +1 -1
  12. package/react-native/android/.project +34 -0
  13. package/react-native/android/bin/.project +34 -0
  14. package/react-native/android/bin/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.class +0 -0
  15. package/react-native/android/bin/src/main/java/com/dittolive/rnsdk/DittoRNSDKPackage.class +0 -0
  16. package/react-native/android/build/intermediates/cxx/abi_configuration_4i3a4k2a.json +14 -0
  17. package/react-native/android/build/intermediates/cxx/abi_configuration_4i3a4k2a.log +1 -0
  18. package/react-native/android/build/intermediates/cxx/abi_configuration_4i3a4k2a_key.json +23 -0
  19. package/react-native/android/build/intermediates/cxx/create_cxx_tasks_371_timing.txt +5 -0
  20. package/react-native/android/build/intermediates/cxx/ndk_locator_record_4q2c3f1f.json +11 -0
  21. package/react-native/android/build/intermediates/cxx/ndk_locator_record_4q2c3f1f.log +72 -0
  22. package/react-native/android/build/intermediates/cxx/ndk_locator_record_4q2c3f1f_key.json +10 -0
  23. package/react-native/android/build.gradle +1 -1
  24. package/react-native/android/cpp-adapter.cpp +39 -43
  25. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +1 -1
  26. package/react-native/cpp/include/Arc.hpp +18 -0
  27. package/react-native/cpp/include/ConnectionRequest.h +18 -0
  28. package/react-native/cpp/include/FFIUtils.h +2 -0
  29. package/react-native/cpp/include/Misc.h +1 -1
  30. package/react-native/cpp/include/Presence.h +4 -0
  31. package/react-native/cpp/include/Utils.h +14 -3
  32. package/react-native/cpp/src/Attachment.cpp +5 -6
  33. package/react-native/cpp/src/Authentication.cpp +1 -1
  34. package/react-native/cpp/src/Collection.cpp +2 -0
  35. package/react-native/cpp/src/ConnectionRequest.cpp +123 -0
  36. package/react-native/cpp/src/DQL.cpp +1 -1
  37. package/react-native/cpp/src/FFIUtils.cpp +58 -0
  38. package/react-native/cpp/src/Identity.cpp +2 -3
  39. package/react-native/cpp/src/LiveQuery.cpp +3 -3
  40. package/react-native/cpp/src/Misc.cpp +14 -23
  41. package/react-native/cpp/src/Presence.cpp +87 -0
  42. package/react-native/cpp/src/Utils.cpp +104 -99
  43. package/react-native/cpp/src/main.cpp +15 -2
  44. package/react-native/dittoffi/dittoffi.h +375 -252
  45. package/react-native/ios/DittoRNSDK.mm +3 -3
  46. package/react-native/src/ditto.rn.ts +12 -4
  47. package/react-native/src/index.ts +2 -2
  48. package/react-native/src/sources/bridge.ts +6 -2
  49. package/react-native/src/sources/connection-request.ts +139 -0
  50. package/react-native/src/sources/ditto.ts +31 -28
  51. package/react-native/src/sources/epilogue.ts +4 -2
  52. package/react-native/src/sources/error-codes.ts +37 -3
  53. package/react-native/src/sources/error.ts +30 -1
  54. package/react-native/src/sources/essentials.ts +6 -0
  55. package/react-native/src/sources/ffi-error.ts +20 -9
  56. package/react-native/src/sources/ffi.ts +206 -111
  57. package/react-native/src/sources/main.ts +1 -0
  58. package/react-native/src/sources/pending-collections-operation.ts +1 -1
  59. package/react-native/src/sources/presence.ts +189 -0
  60. package/react-native/src/sources/query-result-item.ts +4 -4
  61. package/react-native/src/sources/query-result.ts +6 -6
  62. package/react-native/src/sources/small-peer-info.ts +1 -12
  63. package/react-native/src/sources/store-observer.ts +6 -15
  64. package/react-native/src/sources/store.ts +5 -13
  65. package/react-native/src/sources/sync.ts +2 -3
  66. package/types/ditto.d.ts +265 -28
  67. package/web/ditto.es6.js +1 -1
  68. package/web/ditto.umd.js +1 -1
  69. package/web/ditto.wasm +0 -0
package/node/ditto.cjs.js CHANGED
@@ -407,15 +407,23 @@ function ditto_start_tcp_server(...args) { return ditto.ditto_start_tcp_server(.
407
407
  function ditto_stop_http_server(...args) { return ditto.ditto_stop_http_server(...args) }
408
408
  function ditto_stop_tcp_server(...args) { return ditto.ditto_stop_tcp_server(...args) }
409
409
  function ditto_validate_document_id(...args) { return ditto.ditto_validate_document_id(...args) }
410
- function ditto_verify_license(...args) { return ditto.ditto_verify_license(...args) }
411
410
  function ditto_write_transaction(...args) { return ditto.ditto_write_transaction(...args) }
412
411
  function ditto_write_transaction_commit(...args) { return ditto.ditto_write_transaction_commit(...args) }
413
412
  function ditto_write_transaction_rollback(...args) { return ditto.ditto_write_transaction_rollback(...args) }
414
413
  function dittoffi_base64_encode(...args) { return ditto.dittoffi_base64_encode(...args) }
414
+ function dittoffi_connection_request_authorize(...args) { return ditto.dittoffi_connection_request_authorize(...args) }
415
+ function dittoffi_connection_request_connection_type(...args) { return ditto.dittoffi_connection_request_connection_type(...args) }
416
+ function dittoffi_connection_request_free(...args) { return ditto.dittoffi_connection_request_free(...args) }
417
+ function dittoffi_connection_request_identity_service_metadata_json(...args) { return ditto.dittoffi_connection_request_identity_service_metadata_json(...args) }
418
+ function dittoffi_connection_request_peer_key_string(...args) { return ditto.dittoffi_connection_request_peer_key_string(...args) }
419
+ function dittoffi_connection_request_peer_metadata_json(...args) { return ditto.dittoffi_connection_request_peer_metadata_json(...args) }
415
420
  function dittoffi_error_code(...args) { return ditto.dittoffi_error_code(...args) }
416
421
  function dittoffi_error_description(...args) { return ditto.dittoffi_error_description(...args) }
417
422
  function dittoffi_error_free(...args) { return ditto.dittoffi_error_free(...args) }
418
423
  function dittoffi_get_sdk_semver(...args) { return ditto.dittoffi_get_sdk_semver(...args) }
424
+ function dittoffi_presence_peer_metadata_json(...args) { return ditto.dittoffi_presence_peer_metadata_json(...args) }
425
+ function dittoffi_presence_set_connection_request_handler(...args) { return ditto.dittoffi_presence_set_connection_request_handler(...args) }
426
+ function dittoffi_presence_try_set_peer_metadata_json(...args) { return ditto.dittoffi_presence_try_set_peer_metadata_json(...args) }
419
427
  function dittoffi_query_result_free(...args) { return ditto.dittoffi_query_result_free(...args) }
420
428
  function dittoffi_query_result_item_at(...args) { return ditto.dittoffi_query_result_item_at(...args) }
421
429
  function dittoffi_query_result_item_cbor(...args) { return ditto.dittoffi_query_result_item_cbor(...args) }
@@ -430,16 +438,17 @@ function dittoffi_try_exec_statement(...args) { return ditto.dittoffi_try_exec_s
430
438
  function dittoffi_try_experimental_register_change_observer_str_detached(...args) { return ditto.dittoffi_try_experimental_register_change_observer_str_detached(...args) }
431
439
  function dittoffi_try_register_store_observer_webhook(...args) { return ditto.dittoffi_try_register_store_observer_webhook(...args) }
432
440
  function dittoffi_try_remove_sync_subscription(...args) { return ditto.dittoffi_try_remove_sync_subscription(...args) }
441
+ function dittoffi_try_verify_license(...args) { return ditto.dittoffi_try_verify_license(...args) }
433
442
  function getDeadlockTimeout$1(...args) { return ditto.getDeadlockTimeout(...args) }
434
443
  function jsDocsToCDocs(...args) { return ditto.jsDocsToCDocs(...args) }
435
444
  function mdns_client_free_handle(...args) { return ditto.mdns_client_free_handle(...args) }
436
445
  function mdns_server_free_handle(...args) { return ditto.mdns_server_free_handle(...args) }
446
+ function refCBytesIntoBuffer(...args) { return ditto.refCBytesIntoBuffer(...args) }
437
447
  function refCStringToString(...args) { return ditto.refCStringToString(...args) }
438
448
  function setDeadlockTimeout$1(...args) { return ditto.setDeadlockTimeout(...args) }
439
449
  function static_tcp_client_free_handle(...args) { return ditto.static_tcp_client_free_handle(...args) }
440
450
  function websocket_client_free_handle(...args) { return ditto.websocket_client_free_handle(...args) }
441
451
  function withOutBoxCBytes(...args) { return ditto.withOutBoxCBytes(...args) }
442
- function withOutPtr$1(...args) { return ditto.withOutPtr(...args) }
443
452
 
444
453
  const isWebBuild = false;
445
454
 
@@ -704,8 +713,11 @@ async function collectionInsertValue(ditto, collectionName, doc_cbor, writeStrat
704
713
  case 'insertDefaultIfAbsent':
705
714
  strategy = 'InsertDefaultIfAbsent';
706
715
  break;
716
+ case 'updateDifferentValues':
717
+ strategy = 'UpdateDifferentValues';
718
+ break;
707
719
  default:
708
- throw new Error('Invalid write strategy provided');
720
+ throw new Error(`Unsupported write strategy '${writeStrategy}' provided.`);
709
721
  }
710
722
  const { status_code: errorCode, id } = await ditto_collection_insert_value(ditto, collectionNameX, doc_cbor, strategy, null, writeTransaction !== null && writeTransaction !== void 0 ? writeTransaction : null);
711
723
  if (errorCode !== 0)
@@ -778,7 +790,7 @@ async function collectionEvictQueryStr(ditto, collectionName, writeTransaction,
778
790
  *
779
791
  * @internal
780
792
  */
781
- async function tryExperimentalExecQueryStr(ditto, writeTransaction, query, queryArgsCBOR) {
793
+ async function tryExecStatement(ditto, writeTransaction, query, queryArgsCBOR) {
782
794
  ensureInitialized();
783
795
  const queryBytesPointer = bytesFromString(query);
784
796
  const result = await dittoffi_try_exec_statement(ditto, writeTransaction, queryBytesPointer, queryArgsCBOR);
@@ -800,7 +812,7 @@ function removeSubscription(ditto, collectionName, query, queryArgsCBOR, orderBy
800
812
  return ditto_remove_subscription(ditto, collectionNameX, queryX, queryArgsCBOR, orderBy, limit, offset);
801
813
  }
802
814
  /** @internal */
803
- function tryExperimentalAddDQLSubscription(dittoPointer, query, queryArgsCBOR) {
815
+ function tryAddSyncSubscription(dittoPointer, query, queryArgsCBOR) {
804
816
  ensureInitialized();
805
817
  const queryBuffer = bytesFromString(query);
806
818
  const result = dittoffi_try_add_sync_subscription(dittoPointer, queryBuffer, queryArgsCBOR);
@@ -808,42 +820,42 @@ function tryExperimentalAddDQLSubscription(dittoPointer, query, queryArgsCBOR) {
808
820
  return;
809
821
  }
810
822
  /** @internal */
811
- function tryExperimentalRemoveDQLSubscription(dittoPointer, query, queryArgsCBOR) {
823
+ function tryRemoveSyncSubscription(dittoPointer, query, queryArgsCBOR) {
812
824
  ensureInitialized();
813
825
  const queryBuffer = bytesFromString(query);
814
826
  const result = dittoffi_try_remove_sync_subscription(dittoPointer, queryBuffer, queryArgsCBOR);
815
827
  throwOnErrorResult(result.error, 'dittoffi_try_remove_sync_subscription');
816
828
  return;
817
829
  }
818
- // ----------------------------------------------------------- DqlResponse ------
830
+ // ----------------------------------------------------------- QueryResult ------
819
831
  /**
820
832
  * Doesn't error
821
833
  *
822
834
  * @internal
823
835
  */
824
- function dqlResponseFree(responsePointer) {
836
+ function queryResultFree(queryResultPointer) {
825
837
  ensureInitialized();
826
- dittoffi_query_result_free(responsePointer);
838
+ dittoffi_query_result_free(queryResultPointer);
827
839
  }
828
840
  /**
829
841
  * Doesn't error
830
842
  *
831
843
  * @internal
832
844
  */
833
- function dqlResultFree(resultPointer) {
845
+ function queryResultItemFree(queryResultItemPointer) {
834
846
  ensureInitialized();
835
- dittoffi_query_result_item_free(resultPointer);
847
+ dittoffi_query_result_item_free(queryResultItemPointer);
836
848
  }
837
849
  /**
838
850
  * Can error only on internal bug.
839
851
  *
840
852
  * @internal */
841
- function dqlResponseResults(responsePointer) {
853
+ function queryResultItems(queryResultPointer) {
842
854
  ensureInitialized();
843
855
  const rv = [];
844
- const resultCount = dittoffi_query_result_item_count(responsePointer);
856
+ const resultCount = dittoffi_query_result_item_count(queryResultPointer);
845
857
  for (let i = 0; i < resultCount; i++) {
846
- rv.push(dittoffi_query_result_item_at(responsePointer, i));
858
+ rv.push(dittoffi_query_result_item_at(queryResultPointer, i));
847
859
  }
848
860
  return rv;
849
861
  }
@@ -852,44 +864,42 @@ function dqlResponseResults(responsePointer) {
852
864
  *
853
865
  * @internal
854
866
  */
855
- function dqlMutatedDocumentIDs(responsePointer) {
867
+ function queryResultMutatedDocumentIDs(queryResultPointer) {
856
868
  ensureInitialized();
857
869
  const rv = [];
858
- const resultCount = dittoffi_query_result_mutated_document_id_count(responsePointer);
870
+ const resultCount = dittoffi_query_result_mutated_document_id_count(queryResultPointer);
859
871
  for (let i = 0; i < resultCount; i++) {
860
- const cborBytes = dittoffi_query_result_mutated_document_id_at(responsePointer, i);
872
+ const cborBytes = dittoffi_query_result_mutated_document_id_at(queryResultPointer, i);
861
873
  rv.push(boxCBytesIntoBuffer(cborBytes));
862
874
  }
863
875
  return rv;
864
876
  }
865
877
  /**
866
- * The result CBOR contains a map/object with fields and values.
867
- * No CRDTs are present there as they are not needed. Currently
868
- * only values from registers are returned and non-register fields are
869
- * ignored. Reading values from other CRDTs will be supported with
870
- * definition support.
878
+ * The result CBOR contains a map/object with fields and values. No CRDTs are
879
+ * present there as they are not needed. By default only values from registers
880
+ * are returned and non-register fields are ignored.
871
881
  *
872
882
  * Doesn't error
873
883
  *
874
884
  * @internal
875
885
  */
876
- function dqlResultCBOR(resultPointer) {
886
+ function queryResultItemCBOR(queryResultItemPointer) {
877
887
  ensureInitialized();
878
- const cborBytes = dittoffi_query_result_item_cbor(resultPointer);
888
+ const cborBytes = dittoffi_query_result_item_cbor(queryResultItemPointer);
879
889
  return boxCBytesIntoBuffer(cborBytes);
880
890
  }
881
891
  /**
882
- * Returns JSON-encoded results given a DQL result pointer.
892
+ * Returns JSON-encoded results given a DQL result item pointer.
883
893
  *
884
- * Compare for {@link dqlResultCBOR} above.
894
+ * Compare for {@link queryResultItemCBOR} above.
885
895
  *
886
896
  * Doesn't error
887
897
  *
888
898
  * @internal
889
899
  */
890
- function dqlResultJSON(resultPointer) {
900
+ function queryResultItemJSON(queryResultItemPointer) {
891
901
  ensureInitialized();
892
- const jsonBytes = dittoffi_query_result_item_json(resultPointer);
902
+ const jsonBytes = dittoffi_query_result_item_json(queryResultItemPointer);
893
903
  return boxCStringIntoString(jsonBytes);
894
904
  }
895
905
  // ------------------------------------------------------------ LiveQuery ------
@@ -954,7 +964,7 @@ async function liveQueryWebhookRegister(ditto, collectionName, query, orderBy, l
954
964
  return boxCBytesIntoBuffer(id);
955
965
  }
956
966
  /** @internal */
957
- async function tryExperimentalWebhookRegisterDqlLiveQuery(ditto, query, queryArgsCBOR, url) {
967
+ async function tryRegisterStoreObserverWebhook(ditto, query, queryArgsCBOR, url) {
958
968
  ensureInitialized();
959
969
  const queryBuffer = bytesFromString(query);
960
970
  const urlBuffer = bytesFromString(url);
@@ -1248,6 +1258,69 @@ async function dittoClearPresenceV3Callback(self) {
1248
1258
  ditto_clear_presence_v3_callback(self);
1249
1259
  }
1250
1260
  /** @internal */
1261
+ function presencePeerMetadataJSON(self) {
1262
+ ensureInitialized();
1263
+ const result = dittoffi_presence_peer_metadata_json(self);
1264
+ const typedArray = boxCBytesIntoBuffer(result);
1265
+ const textDecoder = new TextDecoder();
1266
+ return textDecoder.decode(typedArray);
1267
+ }
1268
+ /** @internal */
1269
+ async function presenceTrySetPeerMetadataJSON(self, jsonString) {
1270
+ ensureInitialized();
1271
+ const jsonDataCString = bytesFromString(jsonString);
1272
+ const result = await dittoffi_presence_try_set_peer_metadata_json(self, jsonDataCString);
1273
+ throwOnErrorResult(result.error, 'dittoffi_presence_try_set_peer_metadata_json');
1274
+ }
1275
+ /** @internal */
1276
+ function connectionRequestPeerKeyString(connectionRequest) {
1277
+ ensureInitialized();
1278
+ const cString = dittoffi_connection_request_peer_key_string(connectionRequest);
1279
+ return boxCStringIntoString(cString);
1280
+ }
1281
+ /** @internal */
1282
+ function connectionRequestPeerMetadataJSON(connectionRequest) {
1283
+ ensureInitialized();
1284
+ const jsonByteRef = dittoffi_connection_request_peer_metadata_json(connectionRequest);
1285
+ const jsonBuffer = refCBytesIntoBuffer(jsonByteRef);
1286
+ const textDecoder = new TextDecoder();
1287
+ return textDecoder.decode(jsonBuffer);
1288
+ }
1289
+ /** @internal */
1290
+ function connectionRequestIdentityServiceMetadataJSON(connectionRequest) {
1291
+ ensureInitialized();
1292
+ const jsonBytesRef = dittoffi_connection_request_identity_service_metadata_json(connectionRequest);
1293
+ const jsonBuffer = refCBytesIntoBuffer(jsonBytesRef);
1294
+ const textDecoder = new TextDecoder();
1295
+ return textDecoder.decode(jsonBuffer);
1296
+ }
1297
+ /** @internal */
1298
+ function connectionRequestConnectionType(connectionRequest) {
1299
+ ensureInitialized();
1300
+ return dittoffi_connection_request_connection_type(connectionRequest);
1301
+ }
1302
+ /** @internal */
1303
+ function connectionRequestAuthorize(connectionRequest, authorization) {
1304
+ ensureInitialized();
1305
+ dittoffi_connection_request_authorize(connectionRequest, authorization);
1306
+ }
1307
+ /** @internal */
1308
+ function connectionRequestFree(connectionRequest) {
1309
+ ensureInitialized();
1310
+ dittoffi_connection_request_free(connectionRequest);
1311
+ }
1312
+ /** @internal */
1313
+ function presenceSetConnectionRequestHandler(ditto, connectionRequestHandler, onError) {
1314
+ ensureInitialized();
1315
+ if (connectionRequestHandler == null) {
1316
+ dittoffi_presence_set_connection_request_handler(ditto, null);
1317
+ }
1318
+ else {
1319
+ const wrappedCallback = wrapAsyncBackgroundCbForFFI(onError, connectionRequestHandler);
1320
+ dittoffi_presence_set_connection_request_handler(ditto, wrappedCallback);
1321
+ }
1322
+ }
1323
+ /** @internal */
1251
1324
  function dittoSmallPeerInfoGetIsEnabled(dittoPointer) {
1252
1325
  ensureInitialized();
1253
1326
  return ditto_small_peer_info_get_is_enabled(dittoPointer);
@@ -1312,8 +1385,9 @@ function dittoRegisterTransportConditionChangedCallback(self, cb) {
1312
1385
  /** @internal */
1313
1386
  function dittoSetDeviceName(dittoPointer, deviceName) {
1314
1387
  ensureInitialized();
1315
- let deviceNameCString = bytesFromString(deviceName);
1316
- return ditto_set_device_name(dittoPointer, deviceNameCString);
1388
+ const deviceNameCString = bytesFromString(deviceName);
1389
+ const truncatedDeviceNameCString = ditto_set_device_name(dittoPointer, deviceNameCString);
1390
+ return boxCStringIntoString(truncatedDeviceNameCString);
1317
1391
  }
1318
1392
  /** @internal */
1319
1393
  function dittoSetConnectRetryInterval(dittoPointer, retryInterval) {
@@ -1361,7 +1435,10 @@ async function dittoResolveAttachment(ditto, id, namedCallbacks,
1361
1435
  onError) {
1362
1436
  ensureInitialized();
1363
1437
  const { onComplete, onProgress, onDelete } = namedCallbacks;
1364
- const { status_code: errorCode, cancel_token: cancelToken } = await ditto_resolve_attachment(ditto, id, wrapBackgroundCbForFFI(onError, onComplete), wrapBackgroundCbForFFI(onError, onProgress), wrapBackgroundCbForFFI(onError, onDelete));
1438
+ const wrappedOnComplete = wrapBackgroundCbForFFI(onError, onComplete);
1439
+ const wrappedOnProgress = wrapBackgroundCbForFFI(onError, onProgress);
1440
+ const wrappedOnDelete = wrapBackgroundCbForFFI(onError, onDelete);
1441
+ const { status_code: errorCode, cancel_token: cancelToken } = await ditto_resolve_attachment(ditto, id, wrappedOnComplete, wrappedOnProgress, wrappedOnDelete);
1365
1442
  if (errorCode !== 0) {
1366
1443
  throw new DittoFFIError(errorCode, null, `ditto_resolve_attachment() failed with error code: ${errorCode}`);
1367
1444
  }
@@ -1676,11 +1753,8 @@ function withTransportsError(ffiFunction, ...args) {
1676
1753
  // ---------------------------------------------------------------- Other ------
1677
1754
  /** @internal */
1678
1755
  let isInitialized = false;
1679
- /** @internal */
1680
- let withOutPtr;
1681
1756
  {
1682
1757
  isInitialized = true;
1683
- withOutPtr = wrapFFIOutFunction(withOutPtr$1);
1684
1758
  }
1685
1759
  /** @internal */
1686
1760
  function initSDKVersion(platform, language, semVer) {
@@ -1693,16 +1767,11 @@ function initSDKVersion(platform, language, semVer) {
1693
1767
  throw new Error(errorMessage() || `ditto_init_sdk_version() failed with error code: ${errorCode}`);
1694
1768
  }
1695
1769
  /** @internal */
1696
- function verifyLicense(license) {
1770
+ function tryVerifyLicense(license) {
1697
1771
  ensureInitialized();
1698
1772
  const licenseBuffer = bytesFromString(license);
1699
- let result;
1700
- const errorMessageCString = withOutPtr('char *', (outErrorMessage) => {
1701
- result = ditto_verify_license(licenseBuffer, outErrorMessage);
1702
- return outErrorMessage;
1703
- });
1704
- const errorMessage = boxCStringIntoString(errorMessageCString);
1705
- return { result, errorMessage };
1773
+ const result = dittoffi_try_verify_license(licenseBuffer);
1774
+ throwOnErrorResult(result.error, 'dittoffi_try_verify_license');
1706
1775
  }
1707
1776
  // -------------------------------------------------------------- Private ------
1708
1777
  // HACK: this is a left-over error code still in use which will be removed
@@ -1712,11 +1781,9 @@ function verifyLicense(license) {
1712
1781
  /** @internal */
1713
1782
  const NOT_FOUND_ERROR_CODE = -30798;
1714
1783
  /** @internal */
1784
+ // prettier-ignore
1715
1785
  function wrapBackgroundCbForFFI(onError, cb) {
1716
- // Basic fallback based off: https://stackoverflow.com/a/3390635
1717
- if (onError === undefined) {
1718
- onError = (err) => log('Error', `The registered callback failed with ${err}`);
1719
- }
1786
+ const errorHandler = onError !== null && onError !== void 0 ? onError : ((err) => log('Error', `The registered callback failed with ${err}`));
1720
1787
  return (ret_sender, ...args) => {
1721
1788
  let ret;
1722
1789
  try {
@@ -1724,7 +1791,7 @@ function wrapBackgroundCbForFFI(onError, cb) {
1724
1791
  }
1725
1792
  catch (err) {
1726
1793
  try {
1727
- onError(err);
1794
+ errorHandler(err);
1728
1795
  }
1729
1796
  catch (nested_error) {
1730
1797
  log('Error', `Internal error: \`onError()\` handler oughtn't throw, but it did throw ${nested_error}`);
@@ -1734,26 +1801,23 @@ function wrapBackgroundCbForFFI(onError, cb) {
1734
1801
  };
1735
1802
  }
1736
1803
  /** @internal */
1737
- function wrapFFIOutFunction(ffiOutFunction) {
1738
- return function (...args) {
1739
- let occurredError = undefined;
1740
- let callbackResult = undefined;
1741
- let isCallbackResultOutParameter = false;
1742
- const callback = args[args.length - 1];
1743
- const previous_args = args.splice(0, args.length - 1);
1744
- const dittoCoreResult = ffiOutFunction(...previous_args, (outParameter) => {
1804
+ // prettier-ignore
1805
+ function wrapAsyncBackgroundCbForFFI(onError, cb) {
1806
+ const errorHandler = onError !== null && onError !== void 0 ? onError : ((err) => log('Error', `The registered callback failed with ${err}`));
1807
+ return async (ret_sender, ...args) => {
1808
+ let ret;
1809
+ try {
1810
+ ret = await cb(...args);
1811
+ }
1812
+ catch (err) {
1745
1813
  try {
1746
- callbackResult = callback(outParameter);
1747
- isCallbackResultOutParameter = callbackResult === outParameter;
1814
+ errorHandler(err);
1748
1815
  }
1749
- catch (error) {
1750
- occurredError = error;
1816
+ catch (nested_error) {
1817
+ log('Error', `Internal error: \`onError()\` handler oughtn't throw, but it did throw ${nested_error}`);
1751
1818
  }
1752
- });
1753
- if (occurredError) {
1754
- throw occurredError;
1755
1819
  }
1756
- return isCallbackResultOutParameter ? dittoCoreResult : callbackResult;
1820
+ return ret_sender(ret);
1757
1821
  };
1758
1822
  }
1759
1823
  /** @internal */
@@ -1801,9 +1865,9 @@ function ensureInitialized() {
1801
1865
  */
1802
1866
  const ERROR_CODES = {
1803
1867
  /** Internal error for unexpected system states */
1804
- internal: 'An unexpected internal error occured. Please get in touch with Ditto customer service to report this incident.',
1805
- /** Internal error with an unknown error cause **/
1806
- 'internal/unknown-error': 'An unexpected internal error occured. Please get in touch with Ditto customer service to report this incident.',
1868
+ internal: 'An unexpected internal error occurred. Please get in touch with Ditto customer service to report this incident.',
1869
+ /** Internal error with an unknown error cause */
1870
+ 'internal/unknown-error': 'An unexpected internal error occurred. Please get in touch with Ditto customer service to report this incident.',
1807
1871
  //
1808
1872
  // Errors originating in the SDK
1809
1873
  //
@@ -1843,6 +1907,29 @@ const ERROR_CODES = {
1843
1907
  'store/failed-to-create-attachment': 'The attachment could not be created.',
1844
1908
  /** An unclassified error while fetching an attachment. */
1845
1909
  'store/failed-to-fetch-attachment': 'The attachment could not be fetched.',
1910
+ //
1911
+ // Activation errors
1912
+ //
1913
+ /** An error representing an invalid license token. */
1914
+ 'activation/license-token-verification-failed': 'Please provide a valid license token.',
1915
+ /** An error representing an expired license token. */
1916
+ 'activation/license-token-expired': 'The license token expired. Please renew it.',
1917
+ /** An error representing a token is in an unsupported future format. */
1918
+ 'activation/license-token-unsupported-future-version': 'The provided license token is in an unsupported future format.',
1919
+ /** The operation failed because it requires an activated Ditto instance. */
1920
+ 'activation/not-activated': 'The operation failed because the Ditto instance has not yet been activated.',
1921
+ /** A validation error where the maximum depth limit was exceeded. */
1922
+ 'validation/depth-limit-exceeded': 'The maximum depth limit has been exceeded.',
1923
+ /** A validation error where the value is not valid CBOR. */
1924
+ 'validation/invalid-cbor': 'The value provided is not valid CBOR.',
1925
+ /** A validation error where the value is not valid JSON. */
1926
+ 'validation/invalid-json': 'The value provided is not valid JSON.',
1927
+ /** A validation error where a value is required to be a JavaScript object */
1928
+ 'validation/not-an-object': 'The value provided is not of type object.',
1929
+ /** The value provided can not be serialized as JSON. */
1930
+ 'validation/not-json-compatible': 'Value is not serializable as JSON.',
1931
+ /** A validation error where a size limit was exceeded. */
1932
+ 'validation/size-limit-exceeded': 'The size limit has been exceeded.',
1846
1933
  };
1847
1934
 
1848
1935
  //
@@ -1850,6 +1937,13 @@ const ERROR_CODES = {
1850
1937
  //
1851
1938
  /** @see {@link FFIErrorMapping} */
1852
1939
  const DEFAULT_STATUS_CODE_MAPPING = {
1940
+ //
1941
+ // Activation errors
1942
+ //
1943
+ ActivationLicenseTokenExpired: ['activation/license-token-expired'],
1944
+ ActivationLicenseTokenInvalid: ['activation/license-token-verification-failed'],
1945
+ ActivationLicenseUnsupportedFutureVersion: ['activation/license-token-unsupported-future-version'],
1946
+ ActivationNotActivated: ['activation/not-activated'],
1853
1947
  //
1854
1948
  // SDK-specific errors
1855
1949
  //
@@ -1874,6 +1968,11 @@ const DEFAULT_STATUS_CODE_MAPPING = {
1874
1968
  // This gets mapped to `internal` by default but depending on the context,
1875
1969
  // it should be mapped to a more specific error code.
1876
1970
  Base64Invalid: ['internal', 'Invalid base64 encoding.'],
1971
+ ValidationDepthLimitExceeded: ['validation/depth-limit-exceeded'],
1972
+ ValidationInvalidCbor: ['validation/invalid-cbor'],
1973
+ ValidationInvalidJson: ['validation/invalid-json'],
1974
+ ValidationNotAMap: ['validation/not-an-object'],
1975
+ ValidationSizeLimitExceeded: ['validation/size-limit-exceeded'],
1877
1976
  default: ['internal/unknown-error'],
1878
1977
  };
1879
1978
  /**
@@ -1883,6 +1982,22 @@ const DEFAULT_STATUS_CODE_MAPPING = {
1883
1982
  *
1884
1983
  * Please reference {@link ERROR_CODES} for a comprehensive list of
1885
1984
  * possible error codes in this SDK version.
1985
+ *
1986
+ * @example
1987
+ * Handling a specific error code:
1988
+ * ```typescript
1989
+ * import { Attachment, DittoError } from '@dittolive/ditto'
1990
+ *
1991
+ * let attachment: Attachment
1992
+ * try {
1993
+ * attachment = await ditto.store.newAttachment(filePath)
1994
+ * } catch (error) {
1995
+ * if (error instanceof DittoError && error.code === 'store/attachment-file-not-found') {
1996
+ * // Handle a non-existing file
1997
+ * }
1998
+ * throw error // Rethrow any other error
1999
+ * }
2000
+ * ```
1886
2001
  */
1887
2002
  class DittoError extends Error {
1888
2003
  // --------------------------------------- Internal ------------------------
@@ -1897,7 +2012,7 @@ class DittoError extends Error {
1897
2012
  if (ERROR_CODES[code] == null) {
1898
2013
  throw new DittoError('internal', `Invalid error code: ${code}`);
1899
2014
  }
1900
- super(`<${code}> ${message || ERROR_CODES[code]}`);
2015
+ super(message || ERROR_CODES[code]);
1901
2016
  /**
1902
2017
  * Use the error code to identify a specific error programatically.
1903
2018
  *
@@ -2103,7 +2218,7 @@ class AttachmentToken {
2103
2218
 
2104
2219
  // NOTE: this is patched up with the actual build version by Jake task
2105
2220
  // build:package and has to be a valid semantic version as defined here: https://semver.org.
2106
- const fullBuildVersionString = '4.6.0';
2221
+ const fullBuildVersionString = '4.7.0-rc.3';
2107
2222
 
2108
2223
  //
2109
2224
  // Copyright © 2021 DittoLive Incorporated. All rights reserved.
@@ -3884,13 +3999,15 @@ Bridge.all = [];
3884
3999
  /** @internal */
3885
4000
  Bridge.attachment = new _a(freeAttachmentHandle);
3886
4001
  /** @internal */
4002
+ Bridge.connectionRequest = new _a(connectionRequestFree);
4003
+ /** @internal */
3887
4004
  Bridge.document = new _a(documentFree);
3888
4005
  /** @internal */
3889
4006
  Bridge.mutableDocument = new _a(documentFree);
3890
4007
  /** @internal */
3891
- Bridge.dqlResponse = new _a(dqlResponseFree);
4008
+ Bridge.queryResult = new _a(queryResultFree);
3892
4009
  /** @internal */
3893
- Bridge.dqlResult = new _a(dqlResultFree);
4010
+ Bridge.queryResultItem = new _a(queryResultItemFree);
3894
4011
  /** @internal */
3895
4012
  Bridge.staticTCPClient = new _a(staticTCPClientFreeHandle);
3896
4013
  /** @internal */
@@ -5143,6 +5260,106 @@ class BasePendingIDSpecificOperation {
5143
5260
  }
5144
5261
  }
5145
5262
 
5263
+ //
5264
+ // Copyright © 2024 DittoLive Incorporated. All rights reserved.
5265
+ //
5266
+ /**
5267
+ * Contains information about a remote peer that has requested a connection.
5268
+ *
5269
+ * Connection requests and their authorization are scoped to a specific Ditto
5270
+ * peer and connection type.
5271
+ */
5272
+ class ConnectionRequest {
5273
+ /**
5274
+ * The unique peer key of the remote peer.
5275
+ *
5276
+ * @see field `peerKeyString` on {@link Peer} for more information on peer
5277
+ * keys.
5278
+ */
5279
+ get peerKeyString() {
5280
+ return connectionRequestPeerKeyString(this.deref());
5281
+ }
5282
+ /**
5283
+ * Metadata associated with the remote peer.
5284
+ *
5285
+ * This is an empty object if the remote peer has not set any metadata.
5286
+ *
5287
+ * Set peer metadata for the local peer using {@link Presence.peerMetadata}
5288
+ * or {@link Presence.peerMetadataJSONString}.
5289
+ *
5290
+ * This is a convenience property that wraps
5291
+ * {@link peerMetadataJSONString | `peerMetadataJSONString()`}.
5292
+ */
5293
+ get peerMetadata() {
5294
+ return JSON.parse(this.peerMetadataJSONString);
5295
+ }
5296
+ /**
5297
+ * JSON-encoded metadata associated with the remote peer.
5298
+ *
5299
+ * This is a JSON string representing an empty dictionary if the remote peer
5300
+ * has not set any metadata.
5301
+ *
5302
+ * Set peer metadata for the local peer using {@link Presence.peerMetadata} or
5303
+ * {@link Presence.peerMetadataJSONString}.
5304
+ *
5305
+ * Uses UTF-8 encoding.
5306
+ */
5307
+ get peerMetadataJSONString() {
5308
+ return connectionRequestPeerMetadataJSON(this.deref());
5309
+ }
5310
+ /**
5311
+ * Metadata for the remote peer that is provided by the identity service.
5312
+ *
5313
+ * Use an authentication webhook to set this value. See Ditto's online
5314
+ * documentation for more information on how to configure an authentication
5315
+ * webhook.
5316
+ *
5317
+ * Convenience property that wraps {@link identityServiceMetadataJSONString}.
5318
+ */
5319
+ get identityServiceMetadata() {
5320
+ return JSON.parse(this.identityServiceMetadataJSONString);
5321
+ }
5322
+ /**
5323
+ * JSON-encoded metadata for the remote peer that is provided by the
5324
+ * identity service.
5325
+ *
5326
+ * Use an authentication webhook to set this value. See Ditto's online
5327
+ * documentation for more information on how to configure an authentication
5328
+ * webhook.
5329
+ *
5330
+ * Uses UTF-8 encoding.
5331
+ */
5332
+ get identityServiceMetadataJSONString() {
5333
+ return connectionRequestIdentityServiceMetadataJSON(this.deref());
5334
+ }
5335
+ /**
5336
+ * The network transport of this connection request.
5337
+ *
5338
+ * Expect to receive separate connection requests for each network
5339
+ * transport that connects the local and remote peer.
5340
+ */
5341
+ get connectionType() {
5342
+ return connectionRequestConnectionType(this.deref());
5343
+ }
5344
+ /** @internal */
5345
+ toString() {
5346
+ return `ConnectionRequest(${this.peerKeyString} via ${this.connectionType})`;
5347
+ }
5348
+ /**
5349
+ * Defines a custom inspect function for Node.js that will be used when the
5350
+ * object is inspected with console.log() or util.inspect().
5351
+ *
5352
+ * @internal
5353
+ */
5354
+ [Symbol.for('nodejs.util.inspect.custom')](_depth, _inspectOptions, inspect) {
5355
+ return this.toString();
5356
+ }
5357
+ // --------------------------------------------------------------------------
5358
+ deref() {
5359
+ return Bridge.connectionRequest.handleFor(this).deref();
5360
+ }
5361
+ }
5362
+
5146
5363
  //
5147
5364
  // Copyright © 2021 DittoLive Incorporated. All rights reserved.
5148
5365
  //
@@ -6776,18 +6993,18 @@ class QueryResult {
6776
6993
  * @returns an array of document IDs
6777
6994
  */
6778
6995
  mutatedDocumentIDs() {
6779
- const responseHandle = Bridge.dqlResponse.handleFor(this);
6780
- const affectedCBORIDs = dqlMutatedDocumentIDs(responseHandle.deref());
6996
+ const queryResultHandle = Bridge.queryResult.handleFor(this);
6997
+ const affectedCBORIDs = queryResultMutatedDocumentIDs(queryResultHandle.deref());
6781
6998
  return affectedCBORIDs.map((id) => new DocumentID(id, true));
6782
6999
  }
6783
7000
  // ----------------------------------------------------- Internal ------------
6784
7001
  /** @internal */
6785
- constructor(responsePointer) {
6786
- if (responsePointer == null) {
7002
+ constructor(queryResultPointer) {
7003
+ if (queryResultPointer == null) {
6787
7004
  throw new Error('Internal inconsistency, failed to initialize query result without a response pointer');
6788
7005
  }
6789
- const results = dqlResponseResults(responsePointer);
6790
- this.items = results.map((r) => Bridge.dqlResult.bridge(r));
7006
+ const resultItems = queryResultItems(queryResultPointer);
7007
+ this.items = resultItems.map((r) => Bridge.queryResultItem.bridge(r));
6791
7008
  }
6792
7009
  }
6793
7010
 
@@ -6857,19 +7074,15 @@ class StoreObserver {
6857
7074
  Logger.debug(`Ignoring change event received by store observer ${storeObserverID} after it was cancelled`);
6858
7075
  return;
6859
7076
  }
6860
- const response = Bridge.dqlResponse.bridge(cCBParams.query_result, () => new QueryResult(cCBParams.query_result));
7077
+ const result = Bridge.queryResult.bridge(cCBParams.query_result, () => new QueryResult(cCBParams.query_result));
6861
7078
  Logger.debug(`Invoking user event handler with new event for store observer ${storeObserverID}`);
6862
- observationHandler(response, () => {
7079
+ observationHandler(result, () => {
6863
7080
  strongThis.signalNext();
6864
7081
  });
6865
7082
  }
6866
- const errorContext = {
6867
- query,
6868
- queryArguments,
6869
- };
6870
7083
  mapFFIErrors(() => {
6871
7084
  storeObserverID = tryExperimentalRegisterChangeObserver(dittoHandle.deref(), query, queryArgumentsCBOR, wrappedObservationHandler);
6872
- }, undefined, errorContext);
7085
+ });
6873
7086
  });
6874
7087
  if (storeObserverID == null) {
6875
7088
  throw new DittoError('internal', 'Internal inconsistency, store observer ID is undefined after registering');
@@ -7594,10 +7807,9 @@ class Store {
7594
7807
  throw new DittoError('query/arguments-invalid', `Unable to encode query arguments: ${error.message}`);
7595
7808
  }
7596
7809
  }
7597
- const errorContext = { query, queryArguments };
7598
7810
  // prettier-ignore
7599
- const responsePointer = await mapFFIErrorsAsync(async () => await performAsyncToWorkaroundNonAsyncFFIAPI(() => tryExperimentalExecQueryStr(dittoHandle.deref(), writeTransaction, query, queryArgumentsCBOR)), undefined, errorContext);
7600
- return Bridge.dqlResponse.bridge(responsePointer, () => new QueryResult(responsePointer));
7811
+ const queryResultPointer = await mapFFIErrorsAsync(async () => await performAsyncToWorkaroundNonAsyncFFIAPI(() => tryExecStatement(dittoHandle.deref(), writeTransaction, query, queryArgumentsCBOR)));
7812
+ return Bridge.queryResult.bridge(queryResultPointer, () => new QueryResult(queryResultPointer));
7601
7813
  });
7602
7814
  }
7603
7815
  /**
@@ -7845,11 +8057,10 @@ class Store {
7845
8057
  throw new DittoError('query/arguments-invalid', `Invalid query arguments: ${error.message}`);
7846
8058
  }
7847
8059
  }
7848
- const errorContext = { query, queryArguments };
7849
8060
  const dittoHandle = Bridge.ditto.handleFor(this.ditto);
7850
8061
  // prettier-ignore
7851
8062
  return this.ditto.deferCloseAsync(async () => {
7852
- const webhookIDCBOR = await mapFFIErrorsAsync(async () => await tryExperimentalWebhookRegisterDqlLiveQuery(dittoHandle.deref(), query, queryArgumentsCBOR, url), undefined, errorContext);
8063
+ const webhookIDCBOR = await mapFFIErrorsAsync(async () => await tryRegisterStoreObserverWebhook(dittoHandle.deref(), query, queryArgumentsCBOR, url));
7853
8064
  return new DocumentID(webhookIDCBOR, true);
7854
8065
  });
7855
8066
  }
@@ -7970,6 +8181,61 @@ function addressToString(address) {
7970
8181
  * instance via its `presence` property.
7971
8182
  */
7972
8183
  class Presence {
8184
+ /**
8185
+ * Set this handler to control which peers in a Ditto mesh can connect to the
8186
+ * current peer.
8187
+ *
8188
+ * Each peer in a Ditto mesh will attempt to connect to other peers that it
8189
+ * can reach. By default, the mesh will try and establish connections that
8190
+ * optimize for the best overall connectivity between peers. However, you can
8191
+ * set this handler to assert some control over which peers you connect to.
8192
+ *
8193
+ * If set, this handler is called for every incoming connection request from a
8194
+ * remote peer and is passed the other peer's `peerKey`, `peerMetadata`, and
8195
+ * `identityServiceMetadata`. The handler can then accept or reject the
8196
+ * request by returning an according {@link ConnectionRequestAuthorization}
8197
+ * value. When the connection request is rejected, the remote peer may retry
8198
+ * the connection request after a short delay.
8199
+ *
8200
+ * Connection request handlers must reliably respond to requests within a
8201
+ * short time. If a handler takes too long to respond or throws an exception,
8202
+ * the connection request will be denied. The response timeout is currently 10
8203
+ * seconds but may be subject to change in future releases.
8204
+ *
8205
+ * @see {@link peerMetadata | peerMetadata()}
8206
+ */
8207
+ get connectionRequestHandler() {
8208
+ return this._connectionRequestHandler;
8209
+ }
8210
+ /**
8211
+ * @throws TypeError: if the given handler is not a function.
8212
+ */
8213
+ set connectionRequestHandler(handler) {
8214
+ let wrappedHandler = null;
8215
+ if (handler != null) {
8216
+ if (typeof handler !== 'function') {
8217
+ throw new TypeError(`Expected parameter 'handler' to be a function but got ${typeof handler} instead`);
8218
+ }
8219
+ wrappedHandler = async (connectionRequest) => {
8220
+ const request = Bridge.connectionRequest.bridge(connectionRequest);
8221
+ // Any errors will be caught by ffi.ts and passed to `handleError` below
8222
+ const authorization = await handler(request);
8223
+ if (authorization !== 'allow' && authorization !== 'deny') {
8224
+ Logger.error(`The connection request handler must return "allow" or "deny" but returned "${authorization}" instead. The connection request will be denied.`);
8225
+ return 'Deny';
8226
+ }
8227
+ connectionRequestAuthorize(connectionRequest, authorization === 'allow' ? 'Allow' : 'Deny');
8228
+ };
8229
+ }
8230
+ this._connectionRequestHandler = handler;
8231
+ const handleError = (error) => {
8232
+ Logger.error(`The connection request handler threw an error while handling a connection request, the connection request will be denied. ${error}`);
8233
+ };
8234
+ const dittoHandle = Bridge.ditto.handleFor(this.ditto);
8235
+ this.ditto.deferClose(() => {
8236
+ presenceSetConnectionRequestHandler(dittoHandle.deref(), wrappedHandler, handleError);
8237
+ });
8238
+ }
7973
8239
  /**
7974
8240
  * Returns the current presence graph capturing all known peers and
7975
8241
  * connections between them.
@@ -7982,6 +8248,87 @@ class Presence {
7982
8248
  return JSON.parse(graphJSONString);
7983
8249
  });
7984
8250
  }
8251
+ /**
8252
+ * Metadata associated with the current peer. Other peers in the same mesh can
8253
+ * access this user-provided object of metadata via the presence {@link graph}
8254
+ * and when evaluating connection requests using
8255
+ * {@link connectionRequestHandler | connectionRequestHandler()}.
8256
+ *
8257
+ * Uses UTF-8 encoding.
8258
+ *
8259
+ * @see {@link peerMetadata | peerMetadata()} for a convenience property that
8260
+ * provides access to parsed metadata.
8261
+ */
8262
+ get peerMetadataJSONString() {
8263
+ const dittoHandle = Bridge.ditto.handleFor(this.ditto);
8264
+ return this.ditto.deferClose(() => {
8265
+ return mapFFIErrors(() => {
8266
+ return presencePeerMetadataJSON(dittoHandle.deref());
8267
+ });
8268
+ });
8269
+ }
8270
+ /**
8271
+ * Set arbitrary metadata to be associated with the current peer.
8272
+ *
8273
+ * The metadata must not exceed 4 KB in size when JSON-encoded.
8274
+ *
8275
+ * @param {string} jsonString: JSON-encoded metadata.
8276
+ *
8277
+ * @throws {@link DittoError} `validation/invalid-json`: if `jsonString` does
8278
+ * not contain valid JSON.
8279
+ *
8280
+ * @throws {@link DittoError} `validation/not-an-object`: if `jsonString` does
8281
+ * not contain an object.
8282
+ *
8283
+ * @throws {@link DittoError} `validation/size-limit-exceeded`: if the size
8284
+ * limit for `jsonString` has been exceeded.
8285
+ *
8286
+ * @see {@link peerMetadataJSONString | peerMetadataJSONString()} for details
8287
+ * on usage of metadata.
8288
+ */
8289
+ async setPeerMetadataJSONString(jsonString) {
8290
+ const dittoHandle = Bridge.ditto.handleFor(this.ditto);
8291
+ await this.ditto.deferClose(() => {
8292
+ return mapFFIErrorsAsync(async () => {
8293
+ await presenceTrySetPeerMetadataJSON(dittoHandle.deref(), jsonString);
8294
+ });
8295
+ });
8296
+ }
8297
+ /**
8298
+ * This is a convenience property that wraps
8299
+ * {@link peerMetadataJSONString | peerMetadataJSONString()}.
8300
+ *
8301
+ * @see {@link peerMetadataJSONString | peerMetadataJSONString()} for details.
8302
+ */
8303
+ get peerMetadata() {
8304
+ return JSON.parse(this.peerMetadataJSONString);
8305
+ }
8306
+ /**
8307
+ * This is a convenience method that wraps
8308
+ * {@link setPeerMetadataJSONString | setPeerMetadataJSONString()}.
8309
+ *
8310
+ * @throws {@link DittoError} `validation/not-an-object`: if `peerMetadata` is
8311
+ * not an object.
8312
+ *
8313
+ * @throws {@link DittoError} `validation/not-json-compatible`: if
8314
+ * `peerMetadata` is not JSON serializable.
8315
+ *
8316
+ * @throws {@link DittoError} `validation/size-limit-exceeded`: if the size
8317
+ * limit for `peerMetadata` has been exceeded.
8318
+ *
8319
+ * @see {@link setPeerMetadataJSONString | setPeerMetadataJSONString()} for
8320
+ * details.
8321
+ */
8322
+ async setPeerMetadata(peerMetadata) {
8323
+ let jsonString;
8324
+ try {
8325
+ jsonString = JSON.stringify(peerMetadata);
8326
+ }
8327
+ catch (error) {
8328
+ throw new DittoError('validation/not-json-compatible', `Failed encoding peer metadata to JSON. ${error}`);
8329
+ }
8330
+ await this.setPeerMetadataJSONString(jsonString);
8331
+ }
7985
8332
  /**
7986
8333
  * Request information about Ditto peers in range of this device.
7987
8334
  *
@@ -8001,8 +8348,10 @@ class Presence {
8001
8348
  didChangeHandler(this.graph);
8002
8349
  return observer;
8003
8350
  }
8351
+ // -----------------------------------------------------------------------------
8004
8352
  /** @internal */
8005
8353
  constructor(ditto) {
8354
+ this._connectionRequestHandler = null;
8006
8355
  this.ditto = ditto;
8007
8356
  this.observerManager = new ObserverManager('PresenceObservation', {
8008
8357
  keepAlive: ditto.keepAlive,
@@ -8440,10 +8789,9 @@ class Sync {
8440
8789
  throw new DittoError('query/arguments-invalid', `Unable to encode query arguments: ${error.message}`);
8441
8790
  }
8442
8791
  }
8443
- const errorContext = { query, queryArguments };
8444
8792
  const dittoHandle = Bridge.ditto.handleFor(this.ditto);
8445
8793
  this.ditto.deferClose(() => {
8446
- mapFFIErrors(() => tryExperimentalAddDQLSubscription(dittoHandle.deref(), query, queryArgumentsCBOR), undefined, errorContext);
8794
+ mapFFIErrors(() => tryAddSyncSubscription(dittoHandle.deref(), query, queryArgumentsCBOR));
8447
8795
  });
8448
8796
  const subscription = new SyncSubscription(this.ditto, query, queryArguments || null, queryArgumentsCBOR);
8449
8797
  // @ts-expect-error modifying readonly property
@@ -8513,7 +8861,7 @@ class Sync {
8513
8861
  const dittoHandle = Bridge.ditto.handleFor(this.ditto);
8514
8862
  this.ditto.deferClose(() => {
8515
8863
  // prettier-ignore
8516
- mapFFIErrors(() => tryExperimentalRemoveDQLSubscription(dittoHandle.deref(), syncSubscription.queryString, syncSubscription.queryArgumentsCBOR));
8864
+ mapFFIErrors(() => tryRemoveSyncSubscription(dittoHandle.deref(), syncSubscription.queryString, syncSubscription.queryArgumentsCBOR));
8517
8865
  });
8518
8866
  return true;
8519
8867
  }
@@ -9086,7 +9434,7 @@ class SmallPeerInfo {
9086
9434
  *
9087
9435
  * - Must be a JSON object (not an array, string, number, etc.)
9088
9436
  * - The size when encoded as JSON must be less than 128 KB
9089
- * - May only be nested up to 2 levels deep
9437
+ * - May only be nested up to 64 levels deep
9090
9438
  *
9091
9439
  * @example <caption>Valid metadata</caption>
9092
9440
  * ditto.smallPeerInfo.metadata = {
@@ -9096,17 +9444,6 @@ class SmallPeerInfo {
9096
9444
  * }
9097
9445
  * }
9098
9446
  *
9099
- * @example <caption>Invalid metadata</caption>
9100
- * // This is invalid and results in an error.
9101
- * ditto.smallPeerInfo.metadata = {
9102
- * "foo": "bar",
9103
- * "nested": {
9104
- * "illegal": {
9105
- * "inner": "value"
9106
- * }
9107
- * }
9108
- * }
9109
- *
9110
9447
  * @throws when set to a value that violates any of the constraints listed
9111
9448
  * above.
9112
9449
  */
@@ -9191,6 +9528,27 @@ class Ditto {
9191
9528
  // Requires having called FFI.initSDKVersion() first.
9192
9529
  return dittoGetSDKSemver();
9193
9530
  }
9531
+ /**
9532
+ * Configure a custom identifier for this peer.
9533
+ *
9534
+ * When using {@link Presence.observe | presence.observe()}, each remote peer
9535
+ * is represented by a short UTF-8 "device name". By default this will be a
9536
+ * truncated version of the device's hostname.
9537
+ *
9538
+ * Changes to this property after {@link startSync | startSync()} was called
9539
+ * will only take effect after the next restart of sync. The value does not
9540
+ * need to be unique among peers. Device names longer than 24 bytes will be
9541
+ * truncated once {@link startSync | startSync()} is called.
9542
+ */
9543
+ get deviceName() {
9544
+ return this._deviceName;
9545
+ }
9546
+ set deviceName(value) {
9547
+ if (this.isSyncActive) {
9548
+ Logger.warning('Changes to the device name take effect when sync is restarted.');
9549
+ }
9550
+ this._deviceName = value;
9551
+ }
9194
9552
  /** Returns a string identifying the version of the Ditto SDK. */
9195
9553
  get sdkVersion() {
9196
9554
  const dittoHandle = Bridge.ditto.handleFor(this);
@@ -9274,7 +9632,7 @@ class Ditto {
9274
9632
  // Check if device name stays the same on sdk and core levels (#10729).
9275
9633
  {
9276
9634
  const os = require('os');
9277
- this.deviceName = os.hostname();
9635
+ this._deviceName = os.hostname();
9278
9636
  }
9279
9637
  this.keepAlive = new KeepAlive();
9280
9638
  // WORKAROUND: the login provider triggers the registered callback right
@@ -9538,24 +9896,15 @@ class Ditto {
9538
9896
  *
9539
9897
  * @param licenseToken the license token to activate the `Ditto` instance
9540
9898
  * with. You can find yours on the [Ditto portal](https://portal.ditto.live).
9541
- *
9542
- * @throws {Error} if called in a React Native environment.
9543
9899
  */
9544
9900
  setOfflineOnlyLicenseToken(licenseToken) {
9545
- {
9546
- if (IdentityTypesRequiringOfflineLicenseToken.includes(this.identity.type)) {
9547
- const { result, errorMessage } = verifyLicense(licenseToken);
9548
- if (result !== 'LicenseOk') {
9549
- this._isActivated = false;
9550
- throw new Error(errorMessage);
9551
- }
9552
- else {
9553
- this._isActivated = true;
9554
- }
9555
- }
9556
- else {
9557
- throw new Error('Offline license tokens should only be used for manual, sharedKey or offlinePlayground identities');
9558
- }
9901
+ if (IdentityTypesRequiringOfflineLicenseToken.includes(this.identity.type)) {
9902
+ this._isActivated = false;
9903
+ mapFFIErrors(() => tryVerifyLicense(licenseToken));
9904
+ this._isActivated = true;
9905
+ }
9906
+ else {
9907
+ Logger.error(`The identity type '${this.identity.type}' does not require an offline license token.`);
9559
9908
  }
9560
9909
  }
9561
9910
  /**
@@ -9862,7 +10211,7 @@ class Ditto {
9862
10211
  const isX509Valid = this.isX509Valid;
9863
10212
  const identity = this.identity;
9864
10213
  const transportConfig = this.transportConfig;
9865
- dittoSetDeviceName(dittoHandle.deref(), this.deviceName);
10214
+ this._deviceName = dittoSetDeviceName(dittoHandle.deref(), this.deviceName);
9866
10215
  this.sync.update({ identity, transportConfig, isWebValid, isX509Valid, isSyncActive: !!flag, ditto: this });
9867
10216
  });
9868
10217
  }
@@ -10056,8 +10405,8 @@ class QueryResultItem {
10056
10405
  * method once and keep it for as long as needed.
10057
10406
  */
10058
10407
  cborData() {
10059
- const resultHandle = Bridge.dqlResult.handleFor(this);
10060
- return dqlResultCBOR(resultHandle.deref());
10408
+ const resultItemHandle = Bridge.queryResultItem.handleFor(this);
10409
+ return queryResultItemCBOR(resultItemHandle.deref());
10061
10410
  }
10062
10411
  /**
10063
10412
  * Returns the content of the item as a JSON string.
@@ -10066,8 +10415,8 @@ class QueryResultItem {
10066
10415
  * method once and keep it for as long as needed.
10067
10416
  */
10068
10417
  jsonString() {
10069
- const resultHandle = Bridge.dqlResult.handleFor(this);
10070
- return dqlResultJSON(resultHandle.deref());
10418
+ const resultItemHandle = Bridge.queryResultItem.handleFor(this);
10419
+ return queryResultItemJSON(resultItemHandle.deref());
10071
10420
  }
10072
10421
  // ----------------------------------------------------------- Internal ------
10073
10422
  /**
@@ -10132,9 +10481,10 @@ class WebsocketClient {
10132
10481
  // bridges, because anything that would require a certain bridge would
10133
10482
  // immediately require the bridged type, oftentimes leading to an import cycle.
10134
10483
  Bridge.attachment.registerType(Attachment);
10484
+ Bridge.connectionRequest.registerType(ConnectionRequest);
10135
10485
  Bridge.document.registerType(Document);
10136
- Bridge.dqlResult.registerType(QueryResultItem);
10137
- Bridge.dqlResponse.registerType(QueryResult);
10486
+ Bridge.queryResultItem.registerType(QueryResultItem);
10487
+ Bridge.queryResult.registerType(QueryResult);
10138
10488
  Bridge.mutableDocument.registerType(MutableDocument);
10139
10489
  Bridge.staticTCPClient.registerType(StaticTCPClient);
10140
10490
  Bridge.websocketClient.registerType(WebsocketClient);
@@ -10149,6 +10499,7 @@ exports.BasePendingIDSpecificOperation = BasePendingIDSpecificOperation;
10149
10499
  exports.CBOR = CBOR;
10150
10500
  exports.Collection = Collection;
10151
10501
  exports.CollectionsEvent = CollectionsEvent;
10502
+ exports.ConnectionRequest = ConnectionRequest;
10152
10503
  exports.Counter = Counter;
10153
10504
  exports.Ditto = Ditto;
10154
10505
  exports.DittoError = DittoError;