@dittolive/ditto 4.7.4 → 4.8.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/DittoReactNative.podspec +33 -2
  2. package/README.md +2 -2
  3. package/node/ditto.cjs.js +341 -376
  4. package/node/ditto.darwin-arm64.node +0 -0
  5. package/node/ditto.darwin-x64.node +0 -0
  6. package/node/ditto.linux-arm.node +0 -0
  7. package/node/ditto.linux-arm64.node +0 -0
  8. package/node/ditto.linux-x64.node +0 -0
  9. package/node/ditto.win32-x64.node +0 -0
  10. package/package.json +2 -2
  11. package/react-native/android/build.gradle +24 -64
  12. package/react-native/android/cpp-adapter.cpp +37 -104
  13. package/react-native/android/src/main/AndroidManifestNew.xml +2 -0
  14. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +5 -70
  15. package/react-native/cpp/include/ConnectionRequest.h +1 -1
  16. package/react-native/cpp/include/IO.h +2 -0
  17. package/react-native/cpp/include/Logger.h +2 -1
  18. package/react-native/cpp/include/Misc.h +1 -0
  19. package/react-native/cpp/include/main.h +4 -2
  20. package/react-native/cpp/src/Attachment.cpp +1 -3
  21. package/react-native/cpp/src/ConnectionRequest.cpp +1 -1
  22. package/react-native/cpp/src/IO.cpp +79 -0
  23. package/react-native/cpp/src/Logger.cpp +63 -0
  24. package/react-native/cpp/src/Misc.cpp +21 -0
  25. package/react-native/cpp/src/main.cpp +10 -4
  26. package/react-native/ditto.es6.js +2 -0
  27. package/react-native/dittoffi/dittoffi.h +137 -40
  28. package/react-native/ios/DittoRNSDK.mm +19 -124
  29. package/react-native.config.js +2 -1
  30. package/types/ditto.d.ts +2412 -2032
  31. package/web/ditto.es6.js +1 -1
  32. package/web/ditto.umd.js +1 -1
  33. package/web/ditto.wasm +0 -0
  34. package/node/transports.darwin-arm64.node +0 -0
  35. package/node/transports.darwin-x64.node +0 -0
  36. package/react-native/android/.gradle/8.9/checksums/checksums.lock +0 -0
  37. package/react-native/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  38. package/react-native/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  39. package/react-native/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  40. package/react-native/android/.gradle/8.9/gc.properties +0 -0
  41. package/react-native/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  42. package/react-native/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  43. package/react-native/android/.gradle/vcs-1/gc.properties +0 -0
  44. package/react-native/lib/commonjs/ditto.rn.js +0 -93
  45. package/react-native/lib/commonjs/ditto.rn.js.map +0 -1
  46. package/react-native/lib/commonjs/index.js +0 -61
  47. package/react-native/lib/commonjs/index.js.map +0 -1
  48. package/react-native/lib/module/ditto.rn.js +0 -89
  49. package/react-native/lib/module/ditto.rn.js.map +0 -1
  50. package/react-native/lib/module/index.js +0 -27
  51. package/react-native/lib/module/index.js.map +0 -1
  52. package/react-native/lib/typescript/ditto.rn.d.ts +0 -15
  53. package/react-native/lib/typescript/ditto.rn.d.ts.map +0 -1
  54. package/react-native/lib/typescript/index.d.ts +0 -1
  55. package/react-native/lib/typescript/index.d.ts.map +0 -1
  56. package/react-native/src/ditto.rn.ts +0 -123
  57. package/react-native/src/environment/environment.fallback.ts +0 -4
  58. package/react-native/src/index.ts +0 -29
  59. package/react-native/src/sources/@cbor-redux.ts +0 -2
  60. package/react-native/src/sources/@ditto.core.ts +0 -1
  61. package/react-native/src/sources/@environment.ts +0 -1
  62. package/react-native/src/sources/attachment-fetch-event.ts +0 -54
  63. package/react-native/src/sources/attachment-fetcher-manager.ts +0 -145
  64. package/react-native/src/sources/attachment-fetcher.ts +0 -265
  65. package/react-native/src/sources/attachment-token.ts +0 -129
  66. package/react-native/src/sources/attachment.ts +0 -121
  67. package/react-native/src/sources/augment.ts +0 -108
  68. package/react-native/src/sources/authenticator.ts +0 -314
  69. package/react-native/src/sources/base-pending-cursor-operation.ts +0 -255
  70. package/react-native/src/sources/base-pending-id-specific-operation.ts +0 -112
  71. package/react-native/src/sources/bridge.ts +0 -557
  72. package/react-native/src/sources/build-time-constants.ts +0 -8
  73. package/react-native/src/sources/cbor.ts +0 -20
  74. package/react-native/src/sources/collection-interface.ts +0 -73
  75. package/react-native/src/sources/collection.ts +0 -219
  76. package/react-native/src/sources/collections-event.ts +0 -99
  77. package/react-native/src/sources/connection-request.ts +0 -142
  78. package/react-native/src/sources/counter.ts +0 -82
  79. package/react-native/src/sources/ditto.ts +0 -991
  80. package/react-native/src/sources/document-id.ts +0 -163
  81. package/react-native/src/sources/document-path.ts +0 -308
  82. package/react-native/src/sources/document.ts +0 -237
  83. package/react-native/src/sources/epilogue.ts +0 -32
  84. package/react-native/src/sources/error-codes.ts +0 -114
  85. package/react-native/src/sources/error.ts +0 -256
  86. package/react-native/src/sources/essentials.ts +0 -81
  87. package/react-native/src/sources/ffi-error.ts +0 -134
  88. package/react-native/src/sources/ffi.ts +0 -2190
  89. package/react-native/src/sources/identity.ts +0 -163
  90. package/react-native/src/sources/init.ts +0 -71
  91. package/react-native/src/sources/internal.ts +0 -143
  92. package/react-native/src/sources/keep-alive.ts +0 -73
  93. package/react-native/src/sources/key-path.ts +0 -198
  94. package/react-native/src/sources/live-query-event.ts +0 -208
  95. package/react-native/src/sources/live-query-manager.ts +0 -110
  96. package/react-native/src/sources/live-query.ts +0 -167
  97. package/react-native/src/sources/logger.ts +0 -196
  98. package/react-native/src/sources/main.ts +0 -61
  99. package/react-native/src/sources/observer-manager.ts +0 -185
  100. package/react-native/src/sources/observer.ts +0 -79
  101. package/react-native/src/sources/pending-collections-operation.ts +0 -241
  102. package/react-native/src/sources/pending-cursor-operation.ts +0 -218
  103. package/react-native/src/sources/pending-id-specific-operation.ts +0 -218
  104. package/react-native/src/sources/presence-manager.ts +0 -170
  105. package/react-native/src/sources/presence.ts +0 -427
  106. package/react-native/src/sources/query-result-item.ts +0 -131
  107. package/react-native/src/sources/query-result.ts +0 -55
  108. package/react-native/src/sources/register.ts +0 -95
  109. package/react-native/src/sources/small-peer-info.ts +0 -166
  110. package/react-native/src/sources/static-tcp-client.ts +0 -8
  111. package/react-native/src/sources/store-observer.ts +0 -170
  112. package/react-native/src/sources/store.ts +0 -630
  113. package/react-native/src/sources/subscription-manager.ts +0 -99
  114. package/react-native/src/sources/subscription.ts +0 -89
  115. package/react-native/src/sources/sync-subscription.ts +0 -90
  116. package/react-native/src/sources/sync.ts +0 -561
  117. package/react-native/src/sources/test-helpers.ts +0 -24
  118. package/react-native/src/sources/transport-conditions-manager.ts +0 -104
  119. package/react-native/src/sources/transport-config.ts +0 -430
  120. package/react-native/src/sources/update-result.ts +0 -66
  121. package/react-native/src/sources/update-results-map.ts +0 -65
  122. package/react-native/src/sources/websocket-client.ts +0 -7
  123. package/react-native/src/sources/write-transaction-collection.ts +0 -122
  124. package/react-native/src/sources/write-transaction-pending-cursor-operation.ts +0 -101
  125. package/react-native/src/sources/write-transaction-pending-id-specific-operation.ts +0 -74
  126. package/react-native/src/sources/write-transaction.ts +0 -121
package/node/ditto.cjs.js CHANGED
@@ -278,18 +278,6 @@ const ditto = (function () {
278
278
 
279
279
  throw new Error("No native module 'ditto." + target + ".node' found. Please check the Ditto documentation for supported platforms.")
280
280
  })();
281
-
282
- // Kept in a block scope to avoid leaking the target variable. The native
283
- // module registers its functions in global scope.
284
- {
285
- const target = process.platform + '-' + process.arch;
286
- try {
287
- if (target === 'darwin-x64') require('./transports.darwin-x64.node');
288
- if (target === 'darwin-arm64') require('./transports.darwin-arm64.node');
289
- } catch (error) {
290
- console.warn("Couldn't load native module 'transports." + target + ".node' due to error:" + error.toString());
291
- }
292
- }
293
281
  function ble_client_free_handle(...args) { return ditto.ble_client_free_handle(...args) }
294
282
  function ble_server_free_handle(...args) { return ditto.ble_server_free_handle(...args) }
295
283
  function boxCBytesIntoBuffer(...args) { return ditto.boxCBytesIntoBuffer(...args) }
@@ -417,10 +405,12 @@ function dittoffi_connection_request_free(...args) { return ditto.dittoffi_conne
417
405
  function dittoffi_connection_request_identity_service_metadata_json(...args) { return ditto.dittoffi_connection_request_identity_service_metadata_json(...args) }
418
406
  function dittoffi_connection_request_peer_key_string(...args) { return ditto.dittoffi_connection_request_peer_key_string(...args) }
419
407
  function dittoffi_connection_request_peer_metadata_json(...args) { return ditto.dittoffi_connection_request_peer_metadata_json(...args) }
408
+ function dittoffi_crypto_generate_secure_random_token(...args) { return ditto.dittoffi_crypto_generate_secure_random_token(...args) }
420
409
  function dittoffi_error_code(...args) { return ditto.dittoffi_error_code(...args) }
421
410
  function dittoffi_error_description(...args) { return ditto.dittoffi_error_description(...args) }
422
411
  function dittoffi_error_free(...args) { return ditto.dittoffi_error_free(...args) }
423
412
  function dittoffi_get_sdk_semver(...args) { return ditto.dittoffi_get_sdk_semver(...args) }
413
+ function dittoffi_logger_try_export_to_file_async(...args) { return ditto.dittoffi_logger_try_export_to_file_async(...args) }
424
414
  function dittoffi_presence_peer_metadata_json(...args) { return ditto.dittoffi_presence_peer_metadata_json(...args) }
425
415
  function dittoffi_presence_set_connection_request_handler(...args) { return ditto.dittoffi_presence_set_connection_request_handler(...args) }
426
416
  function dittoffi_presence_try_set_peer_metadata_json(...args) { return ditto.dittoffi_presence_try_set_peer_metadata_json(...args) }
@@ -446,8 +436,6 @@ function mdns_server_free_handle(...args) { return ditto.mdns_server_free_handle
446
436
  function refCBytesIntoBuffer(...args) { return ditto.refCBytesIntoBuffer(...args) }
447
437
  function refCStringToString(...args) { return ditto.refCStringToString(...args) }
448
438
  function setDeadlockTimeout$1(...args) { return ditto.setDeadlockTimeout(...args) }
449
- function static_tcp_client_free_handle(...args) { return ditto.static_tcp_client_free_handle(...args) }
450
- function websocket_client_free_handle(...args) { return ditto.websocket_client_free_handle(...args) }
451
439
  function withOutBoxCBytes(...args) { return ditto.withOutBoxCBytes(...args) }
452
440
 
453
441
  const isWebBuild = false;
@@ -821,7 +809,6 @@ function tryAddSyncSubscription(dittoPointer, query, queryArgsCBOR) {
821
809
  const queryBuffer = bytesFromString(query);
822
810
  const result = dittoffi_try_add_sync_subscription(dittoPointer, queryBuffer, queryArgsCBOR);
823
811
  throwOnErrorResult(result.error, 'dittoffi_try_add_sync_subscription');
824
- return;
825
812
  }
826
813
  /** @internal */
827
814
  function tryRemoveSyncSubscription(dittoPointer, query, queryArgsCBOR) {
@@ -829,7 +816,6 @@ function tryRemoveSyncSubscription(dittoPointer, query, queryArgsCBOR) {
829
816
  const queryBuffer = bytesFromString(query);
830
817
  const result = dittoffi_try_remove_sync_subscription(dittoPointer, queryBuffer, queryArgsCBOR);
831
818
  throwOnErrorResult(result.error, 'dittoffi_try_remove_sync_subscription');
832
- return;
833
819
  }
834
820
  // ----------------------------------------------------------- QueryResult ------
835
821
  /**
@@ -1017,15 +1003,6 @@ async function writeTransactionRollback(ditto, transaction) {
1017
1003
  if (errorCode !== 0)
1018
1004
  throw new Error(errorMessage() || `ditto_write_transaction_rollback() failed with error code: ${errorCode}`);
1019
1005
  }
1020
- /** @internal */
1021
- function staticTCPClientFreeHandle(self) {
1022
- static_tcp_client_free_handle(self);
1023
- }
1024
- /** @internal */
1025
- function websocketClientFreeHandle(self) {
1026
- ensureInitialized();
1027
- websocket_client_free_handle(self);
1028
- }
1029
1006
  // --------------------------------------------------------------- Logger ------
1030
1007
  /** @internal */
1031
1008
  function loggerInit() {
@@ -1088,11 +1065,22 @@ function loggerSetLogFile(path) {
1088
1065
  const pathBytesOrNull = path ? bytesFromString(path) : null;
1089
1066
  const errorCode = ditto_logger_set_log_file(pathBytesOrNull);
1090
1067
  if (errorCode !== 0) {
1091
- errorMessage();
1092
- throw new Error(`Can't set log file, due to error: ${errorMessage}`);
1068
+ const message = errorMessage();
1069
+ throw new Error(`Can't set log file, due to error: ${message}`);
1093
1070
  }
1094
1071
  }
1095
1072
  /** @internal */
1073
+ async function loggerTryExportToFileAsync(path) {
1074
+ ensureInitialized();
1075
+ const pathBytes = bytesFromString(path);
1076
+ const result = await new Promise((resolve, reject) => {
1077
+ const wrappedCallback = wrapBackgroundCbForFFI(reject, resolve);
1078
+ dittoffi_logger_try_export_to_file_async(pathBytes, wrappedCallback);
1079
+ });
1080
+ throwOnErrorResult(result.error, 'dittoffi_logger_try_export_to_file_async');
1081
+ return result.success;
1082
+ }
1083
+ /** @internal */
1096
1084
  function log(level, message) {
1097
1085
  ensureInitialized();
1098
1086
  const messageBuffer = bytesFromString(message);
@@ -1236,6 +1224,12 @@ function setDeadlockTimeout(duration) {
1236
1224
  setDeadlockTimeout$1(duration);
1237
1225
  }
1238
1226
  /** @internal */
1227
+ function cryptoGenerateSecureRandomToken() {
1228
+ ensureInitialized();
1229
+ const docIDString = dittoffi_crypto_generate_secure_random_token();
1230
+ return boxCStringIntoString(docIDString);
1231
+ }
1232
+ /** @internal */
1239
1233
  function dittoRegisterPresenceV1Callback(self, cb) {
1240
1234
  ensureInitialized();
1241
1235
  ditto_register_presence_v1_callback(self, wrapBackgroundCbForFFI((err) => log('Error', `The registered presence callback v1 errored with ${err}`), (cJsonStr) => {
@@ -1531,9 +1525,11 @@ function dittoStopHTTPServer(dittoPointer) {
1531
1525
  return ditto_stop_http_server(dittoPointer);
1532
1526
  }
1533
1527
  /** @internal */
1534
- function dittoRunGarbageCollection(dittoPointer) {
1528
+ async function dittoRunGarbageCollection(dittoPointer) {
1535
1529
  ensureInitialized();
1536
- return ditto_run_garbage_collection(dittoPointer);
1530
+ const statusCode = await ditto_run_garbage_collection(dittoPointer);
1531
+ if (statusCode !== 0)
1532
+ throw new Error(errorMessage() || `ditto_run_garbage_collection() failed with error code: ${statusCode}`);
1537
1533
  }
1538
1534
  /** @internal */
1539
1535
  async function dittoDisableSyncWithV3(dittoPointer) {
@@ -1613,14 +1609,7 @@ onError) {
1613
1609
  return ditto_auth_client_set_validity_listener(ditto, validityUpdateRawCb);
1614
1610
  }
1615
1611
  // ----------------------------------------------------------- Transports ------
1616
- /**
1617
- * We currently don't initialize transports through this function but rather in
1618
- * the NAPI module registration in `transports.c` due to an issue with importing
1619
- * the functions required by this function.
1620
- * See https://github.com/getditto/ditto/issues/10723
1621
- *
1622
- * @internal
1623
- */
1612
+ /** @internal */
1624
1613
  function transportsInit() {
1625
1614
  ensureInitialized();
1626
1615
  const { output: wasInitialized, errorType } = withTransportsError(ditto_sdk_transports_init);
@@ -1871,13 +1860,26 @@ const ERROR_CODES = {
1871
1860
  /** Internal error for unexpected system states */
1872
1861
  internal: 'An unexpected internal error occurred. Please get in touch with Ditto customer service to report this incident.',
1873
1862
  /** Internal error with an unknown error cause */
1863
+ // REFACTOR: May be replaced by `unknown` in v5. Tracked in #12755.
1874
1864
  'internal/unknown-error': 'An unexpected internal error occurred. Please get in touch with Ditto customer service to report this incident.',
1875
1865
  //
1876
1866
  // Errors originating in the SDK
1877
1867
  //
1878
1868
  /** Error when using a feature not supported by the current environment */
1869
+ // REFACTOR: May be replaced by `unsupported` in v5. Tracked in #12755.
1879
1870
  'sdk/unsupported': 'The feature is not supported by the current environment.',
1880
1871
  //
1872
+ // IO errors
1873
+ //
1874
+ /** Error when a file or directory already exists */
1875
+ 'io/already-exists': 'A file or directory already exists.',
1876
+ /** Error when a file or directory could not be found */
1877
+ 'io/not-found': 'A file or directory could not be found.',
1878
+ /** Error when permission is denied for a file operation */
1879
+ 'io/permission-denied': 'The operation failed due to insufficient permissions.',
1880
+ /** Error when an IO operation failed for an unspecified reason. See error message for details. */
1881
+ 'io/operation-failed': 'The operation failed.',
1882
+ //
1881
1883
  // Query errors
1882
1884
  //
1883
1885
  /** Error for invalid DQL query arguments. */
@@ -1949,6 +1951,13 @@ const DEFAULT_STATUS_CODE_MAPPING = {
1949
1951
  ActivationLicenseUnsupportedFutureVersion: ['activation/license-token-unsupported-future-version'],
1950
1952
  ActivationNotActivated: ['activation/not-activated'],
1951
1953
  //
1954
+ // Input/output errors
1955
+ //
1956
+ IoAlreadyExists: ['io/already-exists'],
1957
+ IoNotFound: ['io/not-found'],
1958
+ IoPermissionDenied: ['io/permission-denied'],
1959
+ IoOperationFailed: ['io/operation-failed'],
1960
+ //
1952
1961
  // SDK-specific errors
1953
1962
  //
1954
1963
  JsFloatingStoreOperation: ['internal', 'Internal inconsistency, an outstanding store operation was not awaited.'],
@@ -1977,6 +1986,8 @@ const DEFAULT_STATUS_CODE_MAPPING = {
1977
1986
  ValidationInvalidJson: ['validation/invalid-json'],
1978
1987
  ValidationNotAMap: ['validation/not-an-object'],
1979
1988
  ValidationSizeLimitExceeded: ['validation/size-limit-exceeded'],
1989
+ Unsupported: ['sdk/unsupported'],
1990
+ Unknown: ['internal/unknown-error'], // May be updated in v5, c.f. #12755
1980
1991
  default: ['internal/unknown-error'],
1981
1992
  };
1982
1993
  /**
@@ -2222,7 +2233,7 @@ class AttachmentToken {
2222
2233
 
2223
2234
  // NOTE: this is patched up with the actual build version by Jake task
2224
2235
  // build:package and has to be a valid semantic version as defined here: https://semver.org.
2225
- const fullBuildVersionString = '4.7.4';
2236
+ const fullBuildVersionString = '4.8.0-rc.2';
2226
2237
 
2227
2238
  //
2228
2239
  // Copyright © 2021 DittoLive Incorporated. All rights reserved.
@@ -2253,7 +2264,6 @@ async function init(options = {}) {
2253
2264
  initSDKVersion('Unknown', 'JavaScript', fullBuildVersionString);
2254
2265
  break;
2255
2266
  }
2256
- loggerInit();
2257
2267
  }
2258
2268
 
2259
2269
  //
@@ -2262,6 +2272,16 @@ async function init(options = {}) {
2262
2272
  /**
2263
2273
  * Class with static methods to customize the logging behavior from Ditto and
2264
2274
  * log messages with the Ditto logging infrastructure.
2275
+ *
2276
+ * Currently, Ditto uses the persistence directory of the Ditto instance that
2277
+ * was most recently created to store a limited amount of logs. Ditto may
2278
+ * continue writing logs to a persistence directory even after the associated
2279
+ * Ditto instance is {@link Ditto.close | closed}. If this is a concern,
2280
+ * consider either disabling logging by setting {@link Logger.enabled} to
2281
+ * `false`, or instantiating a new Ditto instance. After either of these
2282
+ * actions, it is safe to remove the persistence directory. Please refer to
2283
+ * {@link Logger.exportToFile | `exportToFile()`} for further details on locally
2284
+ * collected logs.
2265
2285
  */
2266
2286
  class Logger {
2267
2287
  /**
@@ -2298,7 +2318,13 @@ class Logger {
2298
2318
  var _a;
2299
2319
  this.setLogFile((_a = url === null || url === void 0 ? void 0 : url.pathname) !== null && _a !== void 0 ? _a : null);
2300
2320
  }
2301
- /** Whether the logger is currently enabled. */
2321
+ /**
2322
+ * Whether the logger is currently enabled.
2323
+ *
2324
+ * Logs exported through {@link exportToFile | exportToFile()} are not
2325
+ * affected by this setting and will also include logs emitted while
2326
+ * {@link enabled} is `false`.
2327
+ */
2302
2328
  static get enabled() {
2303
2329
  return loggerEnabledGet();
2304
2330
  }
@@ -2325,6 +2351,9 @@ class Logger {
2325
2351
  *
2326
2352
  * For example if this is set to `Warning`, then only logs that are logged
2327
2353
  * with the `Warning` or `Error` log levels will be shown.
2354
+ *
2355
+ * Logs exported through {@link exportToFile | exportToFile()} are not
2356
+ * affected by this setting and include all logs at `Debug` level and above.
2328
2357
  */
2329
2358
  static get minimumLogLevel() {
2330
2359
  return loggerMinimumLogLevelGet();
@@ -2353,10 +2382,14 @@ class Logger {
2353
2382
  * unregister any previous callback and stop reporting log entries through
2354
2383
  * callbacks.
2355
2384
  *
2385
+ * @throws {TypeError} if `callback` is not a function or `undefined`.
2356
2386
  * @throws {Error} if called in a React Native environment.
2357
2387
  */
2358
2388
  static async setCustomLogCallback(callback) {
2359
- if (callback) {
2389
+ if (callback != null && typeof callback !== 'function') {
2390
+ throw new TypeError(`Expected parameter 'callback' to be a function or undefined, but got ${typeof callback}.`);
2391
+ }
2392
+ if (callback != null) {
2360
2393
  await loggerSetCustomLogCb(callback);
2361
2394
  this._customLogCallback = callback;
2362
2395
  }
@@ -2365,6 +2398,65 @@ class Logger {
2365
2398
  delete this._customLogCallback;
2366
2399
  }
2367
2400
  }
2401
+ /**
2402
+ * Exports collected logs to a compressed and JSON-encoded file on the local
2403
+ * file system.
2404
+ *
2405
+ * Ditto's logger locally collects a limited amount of logs at `Debug` level
2406
+ * and above, periodically discarding older logs. This internal logger is
2407
+ * always enabled and works independently of the {@link Logger.enabled}
2408
+ * setting and the configured {@link Logger.minimumLogLevel}. Its logs can be
2409
+ * requested and downloaded from any peer that is active in a Ditto app using
2410
+ * the portal's device dashboard. This method provides an alternative way of
2411
+ * accessing those logs by exporting them to the local file system.
2412
+ *
2413
+ * The logs will be written as a gzip compressed file at the path specified by
2414
+ * the `path` parameter. When uncompressed, the file contains one JSON value
2415
+ * per line with the oldest entry on the first line (JSON lines format).
2416
+ *
2417
+ * Ditto limits the amount of logs it retains on disk to 15 MB and a maximum
2418
+ * age of three days. Older logs are periodically discarded once one of these
2419
+ * limits is reached.
2420
+ *
2421
+ * This method currently only exports logs from the most recently created
2422
+ * Ditto instance, even when multiple instances are running in the same
2423
+ * process.
2424
+ *
2425
+ * Not supported in browser environments.
2426
+ *
2427
+ * @param path The path of the file to write the logs to. The file must not
2428
+ * already exist, and the containing directory must exist. It is recommended
2429
+ * for the `path` to have the `.jsonl.gz` file extension but Ditto won't
2430
+ * enforce it, nor correct it.
2431
+ *
2432
+ * @returns The number of bytes written to the file.
2433
+ *
2434
+ * @throws `TypeError` if `path` is not a string.
2435
+ *
2436
+ * @throws {@link DittoError} `io/*` when the file cannot be written to disk.
2437
+ * Prevent this by ensuring that no file exists at the provided `path`, all
2438
+ * parent directories exists, sufficient permissions are granted, and that the
2439
+ * disk is not full.
2440
+ *
2441
+ * @throws {@link DittoError} `sdk/unsupported` when called in a browser
2442
+ * environment.
2443
+ */
2444
+ static async exportToFile(path) {
2445
+ if (typeof path !== 'string') {
2446
+ throw new TypeError(`Expected parameter 'path' to be a string, but got ${typeof path}.`);
2447
+ }
2448
+ let normalizedPath = path;
2449
+ if (process.platform === 'win32' && !path.startsWith('\\\\?\\')) {
2450
+ if (path.length === 0) {
2451
+ throw new DittoError('io/not-found', 'The path must not be empty.');
2452
+ }
2453
+ // Normalize the path on Windows to prevent issues with long paths.
2454
+ // Windows has a hard limit of 260 characters for paths.
2455
+ // c.f. httpes://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation
2456
+ normalizedPath = `\\\\?\\${path}`;
2457
+ }
2458
+ return mapFFIErrorsAsync(() => loggerTryExportToFileAsync(normalizedPath));
2459
+ }
2368
2460
  /**
2369
2461
  * Logs the message for the given `level`.
2370
2462
  *
@@ -3416,8 +3508,8 @@ const CBOR$1 = {
3416
3508
  /** @internal */
3417
3509
  class CBOR {
3418
3510
  /** @internal */
3419
- static encode(data, replacer) {
3420
- const arrayBuffer = CBOR$1.encode(data, replacer);
3511
+ static encode(data) {
3512
+ const arrayBuffer = CBOR$1.encode(data);
3421
3513
  return new Uint8Array(arrayBuffer);
3422
3514
  }
3423
3515
  /** @internal */
@@ -3727,8 +3819,6 @@ class Handles {
3727
3819
  * - {@link Ditto}: `Bridge.ditto`
3728
3820
  * - {@link Document}: `Bridge.document`
3729
3821
  * - {@link MutableDocument}: `Bridge.mutableDocument`
3730
- * - {@link StaticTCPClient}: `Bridge.staticTCPClient`
3731
- * - {@link WebsocketClient}: `Bridge.websocketClient`
3732
3822
  *
3733
3823
  * Use `Bridge.<type>.handleFor()` to obtain a handle, which is a wrapper around
3734
3824
  * the raw pointer, and `Bridge.<type>.bridge()` to get or create the matching
@@ -4013,10 +4103,6 @@ Bridge.queryResult = new _a(queryResultFree);
4013
4103
  /** @internal */
4014
4104
  Bridge.queryResultItem = new _a(queryResultItemFree);
4015
4105
  /** @internal */
4016
- Bridge.staticTCPClient = new _a(staticTCPClientFreeHandle);
4017
- /** @internal */
4018
- Bridge.websocketClient = new _a(websocketClientFreeHandle);
4019
- /** @internal */
4020
4106
  Bridge.ditto = new _a(async (dittoPointer) => {
4021
4107
  // HACK: quick and dirty, clear all presence callbacks. This covers presence
4022
4108
  // v1 and v2 callbacks. v3 should be cleared properly by the `Presence`
@@ -4052,9 +4138,7 @@ class Attachment {
4052
4138
  * Returns the attachment's data.
4053
4139
  */
4054
4140
  data() {
4055
- const ditto = this.ditto;
4056
- const dittoHandle = Bridge.ditto.handleFor(ditto);
4057
- return this.ditto.deferCloseAsync(async () => {
4141
+ return this.ditto.deferCloseAsync(async (dittoHandle) => {
4058
4142
  {
4059
4143
  const attachmentHandle = Bridge.attachment.handleFor(this);
4060
4144
  const attachmentPath = dittoGetCompleteAttachmentPath(dittoHandle.deref(), attachmentHandle.deref());
@@ -4078,16 +4162,14 @@ class Attachment {
4078
4162
  * @param path The path that the attachment should be copied to.
4079
4163
  */
4080
4164
  copyToPath(path) {
4081
- const ditto = this.ditto;
4082
- const dittoHandle = Bridge.ditto.handleFor(ditto);
4083
- return this.ditto.deferCloseAsync(async () => {
4165
+ return this.ditto.deferCloseAsync(async (dittoHandle) => {
4084
4166
  {
4085
4167
  const attachmentHandle = Bridge.attachment.handleFor(this);
4086
4168
  const attachmentPath = dittoGetCompleteAttachmentPath(dittoHandle.deref(), attachmentHandle.deref());
4087
4169
  const fs = require('fs').promises;
4088
4170
  // If the file already exists, we fail. This is the same behavior as
4089
4171
  // for the Swift/ObjC SDK.
4090
- return await fs.copyFile(attachmentPath, path, fs.COPYFILE_EXCL);
4172
+ await fs.copyFile(attachmentPath, path, fs.COPYFILE_EXCL);
4091
4173
  }
4092
4174
  });
4093
4175
  }
@@ -4331,21 +4413,6 @@ function validateQuery(query, options = {}) {
4331
4413
  return validatedQuery;
4332
4414
  }
4333
4415
  // -------------------------------------------------------------- Helpers ------
4334
- /**
4335
- * Generate a random hex-encoded token using the WebCrypto API.
4336
- *
4337
- * @internal */
4338
- function generateEphemeralToken() {
4339
- let webcrypto = undefined;
4340
- let data = new Uint16Array(16);
4341
- // Note: Replacing conditional with polymorphism. (#10731)
4342
- {
4343
- webcrypto = require('crypto').webcrypto;
4344
- webcrypto.getRandomValues(data);
4345
- }
4346
- const doublets = Array.from(data);
4347
- return doublets.map((doublet) => doublet.toString(16)).join('');
4348
- }
4349
4416
  /**
4350
4417
  * Can be used to implement a custom Node.js `inspect` representation for
4351
4418
  * objects that have a `value` property.
@@ -5123,8 +5190,7 @@ class BasePendingCursorOperation {
5123
5190
  */
5124
5191
  async exec() {
5125
5192
  const ditto = this.collection.store.ditto;
5126
- const dittoHandle = Bridge.ditto.handleFor(ditto);
5127
- return ditto.deferCloseAsync(async () => {
5193
+ return ditto.deferCloseAsync(async (dittoHandle) => {
5128
5194
  const query = this.query;
5129
5195
  const documentPointers = await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
5130
5196
  return await collectionExecQueryStr(dittoHandle.deref(), this.collection.name, null, query, this.queryArgsCBOR, this.orderBys, this.currentLimit, this.currentOffset);
@@ -5151,8 +5217,7 @@ class BasePendingCursorOperation {
5151
5217
  */
5152
5218
  async updateWithTransaction(closure, writeTransactionX) {
5153
5219
  const ditto = this.collection.store.ditto;
5154
- const dittoHandle = Bridge.ditto.handleFor(ditto);
5155
- return ditto.deferCloseAsync(async () => {
5220
+ return ditto.deferCloseAsync(async (dittoHandle) => {
5156
5221
  return await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
5157
5222
  const query = this.query;
5158
5223
  const documentsX = await collectionExecQueryStr(dittoHandle.deref(), this.collection.name, writeTransactionX, query, this.queryArgsCBOR, this.orderBys, this.currentLimit, this.currentOffset);
@@ -5234,8 +5299,7 @@ class BasePendingIDSpecificOperation {
5234
5299
  */
5235
5300
  async exec() {
5236
5301
  const ditto = this.collection.store.ditto;
5237
- const dittoHandle = Bridge.ditto.handleFor(ditto);
5238
- return ditto.deferCloseAsync(async () => {
5302
+ return ditto.deferCloseAsync(async (dittoHandle) => {
5239
5303
  return await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
5240
5304
  const readTransactionX = await readTransaction(dittoHandle.deref());
5241
5305
  const documentX = await collectionGet(dittoHandle.deref(), this.collection.name, this.documentIDCBOR, readTransactionX);
@@ -5286,9 +5350,7 @@ class ConnectionRequest {
5286
5350
  /**
5287
5351
  * Metadata associated with the remote peer.
5288
5352
  *
5289
- * This is an empty object if the remote peer has not set any metadata, or
5290
- * when this request is for a WebSocket connection (which does not currently
5291
- * support peer metadata).
5353
+ * This is an empty object if the remote peer has not set any metadata.
5292
5354
  *
5293
5355
  * Set peer metadata for the local peer using {@link Presence.peerMetadata} or
5294
5356
  * {@link Presence.peerMetadataJSONString}.
@@ -5303,8 +5365,7 @@ class ConnectionRequest {
5303
5365
  * JSON-encoded metadata associated with the remote peer.
5304
5366
  *
5305
5367
  * This is a JSON string representing an empty dictionary if the remote peer
5306
- * has not set any metadata or when this request is for a WebSocket
5307
- * connection.
5368
+ * has not set any metadata.
5308
5369
  *
5309
5370
  * Set peer metadata for the local peer using {@link Presence.peerMetadata} or
5310
5371
  * {@link Presence.peerMetadataJSONString}.
@@ -5403,7 +5464,7 @@ class ObserverManager {
5403
5464
  throw new Error(`Internal inconsistency, can't add '${this.id}' observer, observer mananger close()-ed.`);
5404
5465
  }
5405
5466
  this.registerIfNeeded();
5406
- const token = generateEphemeralToken();
5467
+ const token = cryptoGenerateSecureRandomToken();
5407
5468
  this.callbacksByToken[token] = callback;
5408
5469
  (_a = this.keepAlive) === null || _a === void 0 ? void 0 : _a.retain(`${this.id}.${token}`);
5409
5470
  return token;
@@ -5590,44 +5651,26 @@ class Authenticator {
5590
5651
  class OnlineAuthenticator extends Authenticator {
5591
5652
  async loginWithToken(token, provider) {
5592
5653
  const ditto = this.ditto.deref();
5593
- if (!ditto) {
5594
- return;
5595
- }
5596
- const dittoHandle = Bridge.ditto.handleFor(ditto);
5597
- const dittoPointer = dittoHandle.derefOrNull();
5598
- if (!dittoPointer) {
5654
+ if (!ditto || ditto.isClosed)
5599
5655
  return;
5600
- }
5601
- return ditto.deferCloseAsync(async () => {
5602
- await dittoAuthClientLoginWithToken(dittoPointer, token, provider);
5656
+ return ditto.deferCloseAsync(async (dittoHandle) => {
5657
+ await dittoAuthClientLoginWithToken(dittoHandle.deref(), token, provider);
5603
5658
  });
5604
5659
  }
5605
5660
  async loginWithUsernameAndPassword(username, password, provider) {
5606
5661
  const ditto = this.ditto.deref();
5607
- if (!ditto) {
5608
- return;
5609
- }
5610
- const dittoHandle = Bridge.ditto.handleFor(ditto);
5611
- const dittoPointer = dittoHandle.derefOrNull();
5612
- if (!dittoPointer) {
5662
+ if (!ditto || ditto.isClosed)
5613
5663
  return;
5614
- }
5615
- return ditto.deferCloseAsync(async () => {
5616
- await dittoAuthClientLoginWithUsernameAndPassword(dittoPointer, username, password, provider);
5664
+ return ditto.deferCloseAsync(async (dittoHandle) => {
5665
+ await dittoAuthClientLoginWithUsernameAndPassword(dittoHandle.deref(), username, password, provider);
5617
5666
  });
5618
5667
  }
5619
5668
  async logout(cleanupFn) {
5620
5669
  const ditto = this.ditto.deref();
5621
- if (!ditto) {
5622
- return;
5623
- }
5624
- const dittoHandle = Bridge.ditto.handleFor(ditto);
5625
- const dittoPointer = dittoHandle.derefOrNull();
5626
- if (!dittoPointer) {
5670
+ if (!ditto || ditto.isClosed)
5627
5671
  return;
5628
- }
5629
- return ditto.deferCloseAsync(async () => {
5630
- await dittoAuthClientLogout(dittoPointer);
5672
+ return ditto.deferCloseAsync(async (dittoHandle) => {
5673
+ await dittoAuthClientLogout(dittoHandle.deref());
5631
5674
  ditto.stopSync();
5632
5675
  cleanupFn === null || cleanupFn === void 0 ? void 0 : cleanupFn(ditto);
5633
5676
  });
@@ -6044,7 +6087,7 @@ class AttachmentFetcher {
6044
6087
  this.ditto = ditto;
6045
6088
  this.token = token;
6046
6089
  this.manager = manager;
6047
- this.id = generateEphemeralToken();
6090
+ this.id = cryptoGenerateSecureRandomToken();
6048
6091
  const eventHandlerOrNoOp = eventHandler || function () { };
6049
6092
  const dittoHandle = Bridge.ditto.handleFor(ditto);
6050
6093
  this.attachment = new Promise((resolve, reject) => {
@@ -6210,7 +6253,7 @@ class Subscription {
6210
6253
  this.queryArgsCBOR = queryArgsCBOR;
6211
6254
  this.collection = collection;
6212
6255
  this.contextInfo = {
6213
- id: generateEphemeralToken(),
6256
+ id: cryptoGenerateSecureRandomToken(),
6214
6257
  collectionName: collection.name,
6215
6258
  query,
6216
6259
  queryArgsCBOR,
@@ -6390,19 +6433,14 @@ class LiveQuery {
6390
6433
  let liveQueryID = undefined;
6391
6434
  const signalNext = async () => {
6392
6435
  const ditto = weakDitto.deref();
6393
- if (!ditto)
6394
- return;
6395
- const dittoHandle = Bridge.ditto.handleFor(ditto);
6396
- const dittoPointer = dittoHandle.derefOrNull();
6397
- if (!dittoPointer)
6436
+ if (!ditto || ditto.isClosed)
6398
6437
  return;
6399
- return ditto.deferCloseAsync(async () => {
6400
- await liveQuerySignalAvailableNext(dittoPointer, liveQueryID);
6438
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6439
+ await liveQuerySignalAvailableNext(dittoHandle.deref(), liveQueryID);
6401
6440
  });
6402
6441
  };
6403
6442
  const ditto = collection.store.ditto;
6404
- const dittoHandle = Bridge.ditto.handleFor(ditto);
6405
- ditto.deferClose(() => {
6443
+ ditto.deferClose((dittoHandle) => {
6406
6444
  liveQueryID = liveQueryRegister(dittoHandle.deref(), collectionName, query, queryArgsCBOR, this.orderBys, limit, offset, (cCBParams) => {
6407
6445
  const documents = cCBParams.documents.map((ptr) => Bridge.document.bridge(ptr));
6408
6446
  let event;
@@ -6427,18 +6465,6 @@ class LiveQuery {
6427
6465
  }
6428
6466
  this._liveQueryID = liveQueryID;
6429
6467
  }
6430
- /** @internal */
6431
- async signalNext() {
6432
- // IDEA: make this public?
6433
- const ditto = this.collection.store.ditto;
6434
- const dittoHandle = Bridge.ditto.handleFor(ditto);
6435
- const dittoPointer = dittoHandle.derefOrNull();
6436
- if (!dittoPointer)
6437
- return;
6438
- return ditto.deferCloseAsync(async () => {
6439
- await liveQuerySignalAvailableNext(dittoHandle.deref(), this.liveQueryID);
6440
- });
6441
- }
6442
6468
  }
6443
6469
 
6444
6470
  //
@@ -6482,8 +6508,7 @@ class PendingCursorOperation extends BasePendingCursorOperation {
6482
6508
  }
6483
6509
  async remove() {
6484
6510
  const ditto = this.collection.store.ditto;
6485
- const dittoHandle = Bridge.ditto.handleFor(ditto);
6486
- return ditto.deferCloseAsync(async () => {
6511
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6487
6512
  const query = this.query;
6488
6513
  const documentsX = await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
6489
6514
  const writeTransactionX = await writeTransaction(dittoHandle.deref());
@@ -6498,8 +6523,7 @@ class PendingCursorOperation extends BasePendingCursorOperation {
6498
6523
  }
6499
6524
  async evict() {
6500
6525
  const ditto = this.collection.store.ditto;
6501
- const dittoHandle = Bridge.ditto.handleFor(ditto);
6502
- return ditto.deferCloseAsync(async () => {
6526
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6503
6527
  const query = this.query;
6504
6528
  const documentsX = await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
6505
6529
  const writeTransactionX = await writeTransaction(dittoHandle.deref());
@@ -6514,8 +6538,7 @@ class PendingCursorOperation extends BasePendingCursorOperation {
6514
6538
  }
6515
6539
  async update(closure) {
6516
6540
  const ditto = this.collection.store.ditto;
6517
- const dittoHandle = Bridge.ditto.handleFor(ditto);
6518
- return ditto.deferCloseAsync(async () => {
6541
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6519
6542
  return await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
6520
6543
  const writeTransactionX = await writeTransaction(dittoHandle.deref());
6521
6544
  const results = await super.updateWithTransaction(closure, writeTransactionX);
@@ -6649,8 +6672,7 @@ class PendingCursorOperation extends BasePendingCursorOperation {
6649
6672
  class PendingIDSpecificOperation extends BasePendingIDSpecificOperation {
6650
6673
  async remove() {
6651
6674
  const ditto = this.collection.store.ditto;
6652
- const dittoHandle = Bridge.ditto.handleFor(ditto);
6653
- return ditto.deferCloseAsync(async () => {
6675
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6654
6676
  return await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
6655
6677
  const writeTransactionX = await writeTransaction(dittoHandle.deref());
6656
6678
  const didRemove = await collectionRemove(dittoHandle.deref(), this.collection.name, writeTransactionX, this.documentIDCBOR);
@@ -6661,8 +6683,7 @@ class PendingIDSpecificOperation extends BasePendingIDSpecificOperation {
6661
6683
  }
6662
6684
  async evict() {
6663
6685
  const ditto = this.collection.store.ditto;
6664
- const dittoHandle = Bridge.ditto.handleFor(ditto);
6665
- return ditto.deferCloseAsync(async () => {
6686
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6666
6687
  return await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
6667
6688
  const writeTransactionX = await writeTransaction(dittoHandle.deref());
6668
6689
  const didEvict = await collectionEvict(dittoHandle.deref(), this.collection.name, writeTransactionX, this.documentIDCBOR);
@@ -6673,8 +6694,7 @@ class PendingIDSpecificOperation extends BasePendingIDSpecificOperation {
6673
6694
  }
6674
6695
  async update(closure) {
6675
6696
  const ditto = this.collection.store.ditto;
6676
- const dittoHandle = Bridge.ditto.handleFor(ditto);
6677
- return ditto.deferCloseAsync(async () => {
6697
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6678
6698
  const readTransactionX = await readTransaction(dittoHandle.deref());
6679
6699
  const documentX = await collectionGet(dittoHandle.deref(), this.collection.name, this.documentIDCBOR, readTransactionX);
6680
6700
  readTransactionFree(readTransactionX);
@@ -6864,9 +6884,7 @@ class Collection {
6864
6884
  return new PendingIDSpecificOperation(documentID, this);
6865
6885
  }
6866
6886
  async upsert(value, options = {}) {
6867
- const ditto = this.store.ditto;
6868
- const dittoHandle = Bridge.ditto.handleFor(ditto);
6869
- return ditto.deferCloseAsync(async () => {
6887
+ return this.store.ditto.deferCloseAsync(async (dittoHandle) => {
6870
6888
  var _a;
6871
6889
  const writeStrategy = (_a = options.writeStrategy) !== null && _a !== void 0 ? _a : 'merge';
6872
6890
  const documentValueJSON = desugarJSObject(value);
@@ -6908,8 +6926,7 @@ class Collection {
6908
6926
  */
6909
6927
  async newAttachment(pathOrData, metadata = {}) {
6910
6928
  const ditto = this.store.ditto;
6911
- const dittoHandle = Bridge.ditto.handleFor(ditto);
6912
- return ditto.deferCloseAsync(async () => {
6929
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6913
6930
  const { id, len, handle } = await (async () => {
6914
6931
  if (typeof pathOrData === 'string') {
6915
6932
  {
@@ -6984,6 +7001,8 @@ class Collection {
6984
7001
  * {@link QueryResultItem} for each match.
6985
7002
  *
6986
7003
  * More info, such as metrics, will be provided in the near future.
7004
+ *
7005
+ * @template T The type of items in the query result.
6987
7006
  */
6988
7007
  class QueryResult {
6989
7008
  /**
@@ -7029,6 +7048,11 @@ class QueryResult {
7029
7048
  *
7030
7049
  * Create a store observer by calling
7031
7050
  * {@link Store.registerObserver | `ditto.store.registerObserver()`}.
7051
+ *
7052
+ * @template T The type of items in query results. This is a convenience type
7053
+ * that is neither inferred from the store observer's
7054
+ * {@link StoreObserver.queryString | query} nor validated against it.
7055
+ * @template S The type of query arguments.
7032
7056
  */
7033
7057
  class StoreObserver {
7034
7058
  /**
@@ -7073,8 +7097,7 @@ class StoreObserver {
7073
7097
  }
7074
7098
  }
7075
7099
  let storeObserverID;
7076
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7077
- this.ditto.deferClose(() => {
7100
+ this.ditto.deferClose((dittoHandle) => {
7078
7101
  const weakThis = new WeakRef(this);
7079
7102
  function wrappedObservationHandler(cCBParams) {
7080
7103
  const strongThis = weakThis.deref();
@@ -7100,20 +7123,16 @@ class StoreObserver {
7100
7123
  /**
7101
7124
  * Signals to Ditto Core that the observer is ready for the next event.
7102
7125
  */
7103
- signalNext() {
7126
+ async signalNext() {
7104
7127
  const ditto = this.ditto;
7105
7128
  if (!ditto || ditto.isClosed)
7106
7129
  return;
7107
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7108
- const dittoPointer = dittoHandle.derefOrNull();
7109
- if (!dittoPointer)
7110
- return;
7111
7130
  if (this.liveQueryID == null) {
7112
7131
  throw new Error('live query ID is null while signaling ready for next event');
7113
7132
  }
7114
- return ditto.deferCloseAsync(async () => {
7133
+ return ditto.deferCloseAsync(async (dittoHandle) => {
7115
7134
  Logger.debug(`Signaling availability for live query ${this.liveQueryID}`);
7116
- await liveQuerySignalAvailableNext(dittoPointer, this.liveQueryID);
7135
+ await liveQuerySignalAvailableNext(dittoHandle.deref(), this.liveQueryID);
7117
7136
  });
7118
7137
  }
7119
7138
  }
@@ -7386,8 +7405,7 @@ class WriteTransactionPendingCursorOperation extends BasePendingCursorOperation
7386
7405
  }
7387
7406
  async remove() {
7388
7407
  const ditto = this.collection.store.ditto;
7389
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7390
- return ditto.deferCloseAsync(async () => {
7408
+ return ditto.deferCloseAsync(async (dittoHandle) => {
7391
7409
  const query = this.query;
7392
7410
  const transaction = this.collection.writeTransaction;
7393
7411
  const documentsX = await performAsyncToWorkaroundNonAsyncFFIAPI(async () => collectionRemoveQueryStr(dittoHandle.deref(), this.collection.name, transaction.writeTransactionPointer, query, this.queryArgsCBOR, this.orderBys, this.currentLimit, this.currentOffset));
@@ -7402,8 +7420,7 @@ class WriteTransactionPendingCursorOperation extends BasePendingCursorOperation
7402
7420
  }
7403
7421
  async evict() {
7404
7422
  const ditto = this.collection.store.ditto;
7405
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7406
- return ditto.deferCloseAsync(async () => {
7423
+ return ditto.deferCloseAsync(async (dittoHandle) => {
7407
7424
  const query = this.query;
7408
7425
  const transaction = this.collection.writeTransaction;
7409
7426
  const documentsX = await performAsyncToWorkaroundNonAsyncFFIAPI(async () => collectionEvictQueryStr(dittoHandle.deref(), this.collection.name, transaction.writeTransactionPointer, query, this.queryArgsCBOR, this.orderBys, this.currentLimit, this.currentOffset));
@@ -7437,8 +7454,7 @@ class WriteTransactionPendingCursorOperation extends BasePendingCursorOperation
7437
7454
  class WriteTransactionPendingIDSpecificOperation extends BasePendingIDSpecificOperation {
7438
7455
  async remove() {
7439
7456
  const ditto = this.collection.store.ditto;
7440
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7441
- return ditto.deferCloseAsync(async () => {
7457
+ return ditto.deferCloseAsync(async (dittoHandle) => {
7442
7458
  const transaction = this.collection.writeTransaction;
7443
7459
  const result = await performAsyncToWorkaroundNonAsyncFFIAPI(async () => collectionRemove(dittoHandle.deref(), this.collection.name, transaction.writeTransactionPointer, this.documentIDCBOR));
7444
7460
  transaction.addResult('removed', this.documentID, this.collection.name);
@@ -7447,8 +7463,7 @@ class WriteTransactionPendingIDSpecificOperation extends BasePendingIDSpecificOp
7447
7463
  }
7448
7464
  async evict() {
7449
7465
  const ditto = this.collection.store.ditto;
7450
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7451
- return ditto.deferCloseAsync(async () => {
7466
+ return ditto.deferCloseAsync(async (dittoHandle) => {
7452
7467
  const transaction = this.collection.writeTransaction;
7453
7468
  const result = await performAsyncToWorkaroundNonAsyncFFIAPI(async () => await collectionEvict(dittoHandle.deref(), this.collection.name, transaction.writeTransactionPointer, this.documentIDCBOR));
7454
7469
  transaction.addResult('evicted', this.documentID, this.collection.name);
@@ -7457,8 +7472,7 @@ class WriteTransactionPendingIDSpecificOperation extends BasePendingIDSpecificOp
7457
7472
  }
7458
7473
  async update(closure) {
7459
7474
  const ditto = this.collection.store.ditto;
7460
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7461
- return ditto.deferCloseAsync(async () => {
7475
+ return ditto.deferCloseAsync(async (dittoHandle) => {
7462
7476
  const transaction = this.collection.writeTransaction;
7463
7477
  const readTransactionX = await readTransaction(dittoHandle.deref());
7464
7478
  const documentX = await collectionGet(dittoHandle.deref(), this.collection.name, this.documentIDCBOR, readTransactionX);
@@ -7531,8 +7545,7 @@ class WriteTransactionCollection {
7531
7545
  }
7532
7546
  async upsert(value, options = {}) {
7533
7547
  const ditto = this.store.ditto;
7534
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7535
- return ditto.deferCloseAsync(async () => {
7548
+ return ditto.deferCloseAsync(async (dittoHandle) => {
7536
7549
  var _a;
7537
7550
  const writeStrategy = (_a = options.writeStrategy) !== null && _a !== void 0 ? _a : 'merge';
7538
7551
  const documentValueJSON = desugarJSObject(value);
@@ -7574,22 +7587,6 @@ class WriteTransactionCollection {
7574
7587
  * Create a write transaction using {@link Store.write | ditto.store.write}.
7575
7588
  */
7576
7589
  class WriteTransaction {
7577
- /**
7578
- * Initialise a write transaction given a Ditto instance.
7579
- *
7580
- * This is not implemented as a constructor in order to be able to use FFI
7581
- * async functions. Users start transactions through {@link Store.write}.
7582
- *
7583
- * @param ditto an instance of Ditto
7584
- * @internal
7585
- */
7586
- static async init(ditto) {
7587
- return ditto.deferCloseAsync(async () => {
7588
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7589
- const writeTransactionPointer = await writeTransaction(dittoHandle.deref());
7590
- return new WriteTransaction(ditto, writeTransactionPointer);
7591
- });
7592
- }
7593
7590
  /**
7594
7591
  * Creates a transaction-specific
7595
7592
  * {@link WriteTransactionCollection | collection} object that will ensure
@@ -7604,20 +7601,36 @@ class WriteTransaction {
7604
7601
  }
7605
7602
  return new WriteTransactionCollection(toCollectionNamed, this.ditto.store, this);
7606
7603
  }
7607
- // ----------------------------------------------------------- Internal ------
7604
+ /** @internal */
7605
+ constructor(ditto, cTransaction) {
7606
+ this.writeTransactionPointer = cTransaction;
7607
+ this.ditto = ditto;
7608
+ this.results = [];
7609
+ }
7610
+ /**
7611
+ * Initialise a write transaction given a Ditto instance.
7612
+ *
7613
+ * This is not implemented as a constructor in order to be able to use FFI
7614
+ * async functions. Users start transactions through {@link Store.write}.
7615
+ *
7616
+ * @param ditto an instance of Ditto
7617
+ * @internal
7618
+ */
7619
+ static async init(ditto) {
7620
+ return ditto.deferCloseAsync(async (dittoHandle) => {
7621
+ const writeTransactionPointer = await writeTransaction(dittoHandle.deref());
7622
+ return new WriteTransaction(ditto, writeTransactionPointer);
7623
+ });
7624
+ }
7608
7625
  /** @internal */
7609
7626
  async commit() {
7610
- const ditto = this.ditto;
7611
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7612
- return ditto.deferCloseAsync(async () => {
7627
+ return this.ditto.deferCloseAsync(async (dittoHandle) => {
7613
7628
  return writeTransactionCommit(dittoHandle.deref(), this.writeTransactionPointer);
7614
7629
  });
7615
7630
  }
7616
7631
  /** @internal */
7617
7632
  async rollback() {
7618
- const ditto = this.ditto;
7619
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7620
- return ditto.deferCloseAsync(async () => {
7633
+ return this.ditto.deferCloseAsync(async (dittoHandle) => {
7621
7634
  return writeTransactionRollback(dittoHandle.deref(), this.writeTransactionPointer);
7622
7635
  });
7623
7636
  }
@@ -7625,7 +7638,8 @@ class WriteTransaction {
7625
7638
  * Adds an entry to the list of results that is returned at the end of a
7626
7639
  * transaction.
7627
7640
  *
7628
- * @internal */
7641
+ * @internal
7642
+ */
7629
7643
  addResult(type, docID, collectionName) {
7630
7644
  this.results.push({
7631
7645
  type,
@@ -7633,12 +7647,6 @@ class WriteTransaction {
7633
7647
  collectionName,
7634
7648
  });
7635
7649
  }
7636
- /** @internal */
7637
- constructor(ditto, cTransaction) {
7638
- this.writeTransactionPointer = cTransaction;
7639
- this.ditto = ditto;
7640
- this.results = [];
7641
- }
7642
7650
  }
7643
7651
 
7644
7652
  //
@@ -7662,14 +7670,18 @@ class Store {
7662
7670
  * triggered automatically instead of having to call the passed in
7663
7671
  * `signalNext` function.
7664
7672
  *
7665
- * @param query a string containing a valid query expressed in DQL.
7666
- * @param observationHandler a function that is called whenever the query's results
7667
- * change. The function is passed a {@link QueryResult} containing a
7673
+ * @param query A string containing a valid query expressed in DQL.
7674
+ * @param observationHandler A function that is called whenever the query's
7675
+ * results change. The function is passed a {@link QueryResult} containing a
7668
7676
  * {@link QueryResultItem} for each match.
7669
- * @param queryArguments an object of values keyed by the placeholder name
7677
+ * @param queryArguments An object of values keyed by the placeholder name
7670
7678
  * without the leading `:`. Example: `{ "name": "Joanna" }` for a query like
7671
7679
  * `SELECT * FROM people WHERE name = :name`.
7672
- * @returns a {@link StoreObserver} that can be used to cancel the
7680
+ * @template T The type of items returned by the query. This is a convenience
7681
+ * type that is neither inferred from the `query` parameter nor validated
7682
+ * against it.
7683
+ * @template U The type of the query arguments.
7684
+ * @returns A {@link StoreObserver} that can be used to cancel the
7673
7685
  * observation.
7674
7686
  * @throws {@link DittoError} `query/invalid`: if `query` argument is not a
7675
7687
  * string or not valid DQL.
@@ -7706,14 +7718,18 @@ class Store {
7706
7718
  * The first invocation of `observationHandler` will always happen after this
7707
7719
  * method has returned.
7708
7720
  *
7709
- * @param query a string containing a valid query expressed in DQL.
7710
- * @param observationHandler an observation handler function that is called
7721
+ * @param query A string containing a valid query expressed in DQL.
7722
+ * @param observationHandler An observation handler function that is called
7711
7723
  * whenever the query's results change. The function is passed a
7712
7724
  * {@link QueryResult} containing a {@link QueryResultItem} for each match.
7713
- * @param queryArguments an object of values keyed by the placeholder name
7725
+ * @param queryArguments An object of values keyed by the placeholder name
7714
7726
  * without the leading `:`. Example: `{ "name": "Joanna" }` for a query like
7715
7727
  * `SELECT * FROM people WHERE name = :name`.
7716
- * @returns a {@link StoreObserver} that can be used to cancel the
7728
+ * @template T The type of items returned by the query. This is a convenience
7729
+ * type that is neither inferred from the `query` parameter nor validated
7730
+ * against it.
7731
+ * @template U The type of the query arguments
7732
+ * @returns A {@link StoreObserver} that can be used to cancel the
7717
7733
  * observation.
7718
7734
  * @throws {@link DittoError} `query/invalid`: if `query` argument is not a
7719
7735
  * string or not valid DQL.
@@ -7736,8 +7752,7 @@ class Store {
7736
7752
  // If we would await the call here, we could end up in a situation where
7737
7753
  // the first callback to the event handler is emitted before we return from
7738
7754
  // the method call that started the observer.
7739
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
7740
- void this.ditto.deferCloseAsync(async () => {
7755
+ void this.ditto.deferCloseAsync(async (dittoHandle) => {
7741
7756
  return new Promise((resolve) => {
7742
7757
  void step(async () => {
7743
7758
  try {
@@ -7783,20 +7798,28 @@ class Store {
7783
7798
  * related {@link Ditto} instance.
7784
7799
  */
7785
7800
  collectionNames() {
7786
- const ditto = this.ditto;
7787
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7788
- return ditto.deferClose(() => {
7801
+ return this.ditto.deferClose((dittoHandle) => {
7789
7802
  return mapFFIErrors(() => dittoGetCollectionNames(dittoHandle.deref()));
7790
7803
  });
7791
7804
  }
7792
7805
  /**
7793
7806
  * Executes a DQL query and returns matching items as a query result.
7794
7807
  *
7795
- * @param query a string containing a valid query expressed in DQL.
7796
- * @param queryArguments an object of values keyed by the placeholder name
7808
+ * **Note:** only returns results from the local store without waiting for any
7809
+ * {@link SyncSubscription | sync subscriptions} to have caught up with the
7810
+ * latest changes. Only use this method if your program must proceed with
7811
+ * immediate results. Use a {@link StoreObserver | store observer} to receive
7812
+ * updates to query results as soon as they have been synced to this peer.
7813
+ *
7814
+ * @param query A string containing a valid query expressed in DQL.
7815
+ * @param queryArguments An object of values keyed by the placeholder name
7797
7816
  * without the leading `:`. Example: `{ "name": "John" }` for a query like
7798
7817
  * `SELECT * FROM people WHERE name = :name`.
7799
- * @returns a promise for a {@link QueryResult} containing a
7818
+ * @template T The type of items returned by the query. This is a convenience
7819
+ * type that is neither inferred from the `query` parameter nor validated
7820
+ * against it.
7821
+ * @template U The type of the query arguments
7822
+ * @returns A promise for a {@link QueryResult} containing a
7800
7823
  * {@link QueryResultItem} for each match.
7801
7824
  * @throws {@link DittoError} `query/invalid`: if `query` argument is not a
7802
7825
  * string or not valid DQL.
@@ -7808,8 +7831,7 @@ class Store {
7808
7831
  if (typeof query !== 'string') {
7809
7832
  throw new DittoError('query/invalid', `Expected parameter 'query' to be of type 'string', found: ${typeof query}`);
7810
7833
  }
7811
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
7812
- return this.ditto.deferCloseAsync(async () => {
7834
+ return this.ditto.deferCloseAsync(async (dittoHandle) => {
7813
7835
  // A one-off query execution uses a transaction internally but a
7814
7836
  // transaction API is not implemented yet.
7815
7837
  const writeTransaction = null;
@@ -7914,12 +7936,10 @@ class Store {
7914
7936
  * attachment from a file path in a web browser.
7915
7937
  */
7916
7938
  async newAttachment(pathOrData, metadata) {
7917
- const ditto = this.ditto;
7918
- const dittoHandle = Bridge.ditto.handleFor(ditto);
7919
7939
  if (metadata != null) {
7920
7940
  validateAttachmentMetadata(metadata);
7921
7941
  }
7922
- return ditto.deferCloseAsync(async () => {
7942
+ return this.ditto.deferCloseAsync(async (dittoHandle) => {
7923
7943
  //
7924
7944
  // Create inputs for the attachment token from either a file path or raw data.
7925
7945
  //
@@ -7942,7 +7962,8 @@ class Store {
7942
7962
  })();
7943
7963
  const attachmentTokenJSON = { _id: id, _len: len, _meta: { ...metadata }, [DittoCRDTTypeKey]: DittoCRDTType.attachment };
7944
7964
  const attachmentToken = new AttachmentToken(attachmentTokenJSON);
7945
- const attachment = new Attachment(ditto, attachmentToken);
7965
+ // this.ditto is safe to use because we are inside a deferCloseAsync block
7966
+ const attachment = new Attachment(this.ditto, attachmentToken);
7946
7967
  return Bridge.attachment.bridge(handle, () => attachment);
7947
7968
  });
7948
7969
  }
@@ -8015,9 +8036,8 @@ class Store {
8015
8036
  else {
8016
8037
  attachmentToken = new AttachmentToken(token);
8017
8038
  }
8018
- const ditto = this.ditto;
8019
- return ditto.deferClose(() => {
8020
- const attachmentFetcher = new AttachmentFetcher(ditto, attachmentToken, null, eventHandler);
8039
+ return this.ditto.deferClose(() => {
8040
+ const attachmentFetcher = new AttachmentFetcher(this.ditto, attachmentToken, null, eventHandler);
8021
8041
  // @ts-expect-error modifying readonly property
8022
8042
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
8023
8043
  this.attachmentFetchers = Object.freeze([...this.attachmentFetchers, attachmentFetcher]);
@@ -8035,6 +8055,7 @@ class Store {
8035
8055
  * observer and {@link StoreObserver.cancel | StoreObserver.cancel()} to
8036
8056
  * remove an existing store observer.
8037
8057
  */
8058
+ // The type parameters are defined as `any` to avoid recursive type inference.
8038
8059
  this.observers = Object.freeze([]);
8039
8060
  /**
8040
8061
  * All currently active attachment fetchers.
@@ -8074,9 +8095,8 @@ class Store {
8074
8095
  throw new DittoError('query/arguments-invalid', `Invalid query arguments: ${error.message}`);
8075
8096
  }
8076
8097
  }
8077
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
8078
8098
  // prettier-ignore
8079
- return this.ditto.deferCloseAsync(async () => {
8099
+ return this.ditto.deferCloseAsync(async (dittoHandle) => {
8080
8100
  const webhookIDCBOR = await mapFFIErrorsAsync(async () => await tryRegisterStoreObserverWebhook(dittoHandle.deref(), query, queryArgumentsCBOR, url));
8081
8101
  return new DocumentID(webhookIDCBOR, true);
8082
8102
  });
@@ -8169,9 +8189,7 @@ class Store {
8169
8189
  * @internal
8170
8190
  */
8171
8191
  async registerLiveQueryWebhook(collectionName, query, url) {
8172
- const ditto = this.ditto;
8173
- const dittoHandle = Bridge.ditto.handleFor(ditto);
8174
- return ditto.deferCloseAsync(async () => {
8192
+ return this.ditto.deferCloseAsync(async (dittoHandle) => {
8175
8193
  const validatedQuery = validateQuery(query);
8176
8194
  const idCBOR = await liveQueryWebhookRegister(dittoHandle.deref(), collectionName, validatedQuery, [], 0, 0, url);
8177
8195
  return new DocumentID(idCBOR, true);
@@ -8260,9 +8278,7 @@ class Presence {
8260
8278
  * connections between them.
8261
8279
  */
8262
8280
  get graph() {
8263
- const ditto = this.ditto;
8264
- const dittoHandle = Bridge.ditto.handleFor(ditto);
8265
- return ditto.deferClose(() => {
8281
+ return this.ditto.deferClose((dittoHandle) => {
8266
8282
  const graphJSONString = dittoPresenceV3(dittoHandle.deref());
8267
8283
  return JSON.parse(graphJSONString);
8268
8284
  });
@@ -8273,16 +8289,13 @@ class Presence {
8273
8289
  * and when evaluating connection requests using
8274
8290
  * {@link connectionRequestHandler | connectionRequestHandler()}.
8275
8291
  *
8276
- * This is not made available to peers only connected via WebSocket.
8277
- *
8278
8292
  * Uses UTF-8 encoding.
8279
8293
  *
8280
8294
  * @see {@link peerMetadata | peerMetadata()} for a convenience property that
8281
8295
  * provides access to parsed metadata.
8282
8296
  */
8283
8297
  get peerMetadataJSONString() {
8284
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
8285
- return this.ditto.deferClose(() => {
8298
+ return this.ditto.deferClose((dittoHandle) => {
8286
8299
  return mapFFIErrors(() => {
8287
8300
  return presencePeerMetadataJSON(dittoHandle.deref());
8288
8301
  });
@@ -8293,7 +8306,7 @@ class Presence {
8293
8306
  *
8294
8307
  * The metadata must not exceed 4 KB in size when JSON-encoded.
8295
8308
  *
8296
- * @param {string} jsonString: JSON-encoded metadata.
8309
+ * @param {string} jsonString JSON-encoded metadata.
8297
8310
  *
8298
8311
  * @throws {@link DittoError} `validation/invalid-json`: if `jsonString` does
8299
8312
  * not contain valid JSON.
@@ -8308,8 +8321,7 @@ class Presence {
8308
8321
  * on usage of metadata.
8309
8322
  */
8310
8323
  async setPeerMetadataJSONString(jsonString) {
8311
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
8312
- await this.ditto.deferCloseAsync(async () => {
8324
+ await this.ditto.deferCloseAsync(async (dittoHandle) => {
8313
8325
  return mapFFIErrorsAsync(async () => {
8314
8326
  return presenceTrySetPeerMetadataJSON(dittoHandle.deref(), jsonString);
8315
8327
  });
@@ -8377,16 +8389,12 @@ class Presence {
8377
8389
  this.observerManager = new ObserverManager('PresenceObservation', {
8378
8390
  keepAlive: ditto.keepAlive,
8379
8391
  register: (callback) => {
8380
- const ditto = this.ditto;
8381
- const dittoHandle = Bridge.ditto.handleFor(ditto);
8382
- ditto.deferClose(() => {
8392
+ this.ditto.deferClose((dittoHandle) => {
8383
8393
  dittoRegisterPresenceV3Callback(dittoHandle.deref(), callback);
8384
8394
  });
8385
8395
  },
8386
8396
  unregister: () => {
8387
- const ditto = this.ditto;
8388
- const dittoHandle = Bridge.ditto.handleFor(ditto);
8389
- void ditto.deferCloseAsync(async () => {
8397
+ void ditto.deferCloseAsync(async (dittoHandle) => {
8390
8398
  return dittoClearPresenceV3Callback(dittoHandle.deref());
8391
8399
  });
8392
8400
  },
@@ -8416,8 +8424,6 @@ class LiveQueryManager {
8416
8424
  }
8417
8425
  /** @internal */
8418
8426
  startLiveQuery(liveQuery) {
8419
- const ditto = this.ditto;
8420
- const dittoHandle = Bridge.ditto.handleFor(ditto);
8421
8427
  // REFACTOR: the starting closure runs detached from here which is a smell.
8422
8428
  // Can we make this whole starting mechanism non-async? The culprit is
8423
8429
  // the workaround for a zalgo with `ditto_live_query_start()` FFI function:
@@ -8426,7 +8432,7 @@ class LiveQueryManager {
8426
8432
  // (by definition). This is a classic zalgo case. Fix by making
8427
8433
  // `ditto_live_query_start()` trigger the first live query callback `async`,
8428
8434
  // just like the subsequent ones.
8429
- void this.ditto.deferCloseAsync(async () => {
8435
+ void this.ditto.deferCloseAsync(async (dittoHandle) => {
8430
8436
  const liveQueryID = liveQuery.liveQueryID;
8431
8437
  if (!liveQueryID) {
8432
8438
  throw new Error("Internal inconsistency, tried to add a live query that doesn't have a live query ID (probably stopped).");
@@ -8439,7 +8445,7 @@ class LiveQueryManager {
8439
8445
  this.liveQueriesByID[liveQueryID] = weakLiveQuery;
8440
8446
  this.finalizationRegistry.register(liveQuery, liveQueryID, this.finalize);
8441
8447
  liveQuery.liveQueryManager = this;
8442
- ditto.keepAlive.retain(`LiveQuery.${liveQueryID}`);
8448
+ this.ditto.keepAlive.retain(`LiveQuery.${liveQueryID}`);
8443
8449
  return new Promise((resolve, reject) => {
8444
8450
  // not awaited on purpose; let the invocation of the initial observation
8445
8451
  // happen in a "fire-and-forget" / detached / escaping fashion, to be
@@ -8472,9 +8478,7 @@ class LiveQueryManager {
8472
8478
  }
8473
8479
  }
8474
8480
  stopLiveQueryWithID(liveQueryID) {
8475
- const ditto = this.ditto;
8476
- const dittoHandle = Bridge.ditto.handleFor(ditto);
8477
- ditto.deferClose(() => {
8481
+ this.ditto.deferClose((dittoHandle) => {
8478
8482
  liveQueryStop(dittoHandle.deref(), liveQueryID);
8479
8483
  this.keepAlive.release(`LiveQuery.${liveQueryID}`);
8480
8484
  delete this.liveQueriesByID[liveQueryID];
@@ -8508,7 +8512,7 @@ class PresenceManager {
8508
8512
  throw new Error(`Internal inconsistency, can't add presence observer, observer mananger close()-ed.`);
8509
8513
  }
8510
8514
  this.registerIfNeeded();
8511
- const token = generateEphemeralToken();
8515
+ const token = cryptoGenerateSecureRandomToken();
8512
8516
  this.callbacksByPresenceToken[token] = callback;
8513
8517
  this.ditto.keepAlive.retain(`PresenceObservation.${token}`);
8514
8518
  // REFACTOR: make the initial callback call async, too (othewise we'd be
@@ -8553,9 +8557,7 @@ class PresenceManager {
8553
8557
  return Object.keys(this.callbacksByPresenceToken).length > 0;
8554
8558
  }
8555
8559
  registerIfNeeded() {
8556
- const ditto = this.ditto;
8557
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
8558
- ditto.deferClose(() => {
8560
+ this.ditto.deferClose((dittoHandle) => {
8559
8561
  const needsToRegister = !this.isRegistered;
8560
8562
  if (needsToRegister) {
8561
8563
  this.isRegistered = true;
@@ -8566,9 +8568,7 @@ class PresenceManager {
8566
8568
  });
8567
8569
  }
8568
8570
  unregisterIfNeeded() {
8569
- const ditto = this.ditto;
8570
- const dittoHandle = Bridge.ditto.handleFor(ditto);
8571
- return this.ditto.deferCloseAsync(async () => {
8571
+ return this.ditto.deferCloseAsync(async (dittoHandle) => {
8572
8572
  const needsToUnregister = !this.hasObservers() && this.isRegistered;
8573
8573
  if (needsToUnregister) {
8574
8574
  this.isRegistered = false;
@@ -8631,16 +8631,12 @@ class TransportConditionsManager extends ObserverManager {
8631
8631
  this.ditto = ditto;
8632
8632
  }
8633
8633
  register(callback) {
8634
- const ditto = this.ditto;
8635
- const dittoHandle = Bridge.ditto.handleFor(ditto);
8636
- return ditto.deferClose(() => {
8634
+ return this.ditto.deferClose((dittoHandle) => {
8637
8635
  return dittoRegisterTransportConditionChangedCallback(dittoHandle.deref(), callback);
8638
8636
  });
8639
8637
  }
8640
8638
  unregister() {
8641
- const ditto = this.ditto;
8642
- const dittoHandle = Bridge.ditto.handleFor(ditto);
8643
- return ditto.deferClose(() => {
8639
+ return this.ditto.deferClose((dittoHandle) => {
8644
8640
  return dittoRegisterTransportConditionChangedCallback(dittoHandle.deref(), null);
8645
8641
  });
8646
8642
  }
@@ -8723,6 +8719,8 @@ class TransportConditionsManager extends ObserverManager {
8723
8719
  *
8724
8720
  * Create a sync subscription by calling
8725
8721
  * {@link Sync.registerSubscription | `ditto.sync.registerSubscription()`}.
8722
+ *
8723
+ * @template T The type of query arguments passed to the sync subscription.
8726
8724
  */
8727
8725
  class SyncSubscription {
8728
8726
  /**
@@ -8782,6 +8780,7 @@ class Sync {
8782
8780
  * @param query a string containing a valid query expressed in DQL.
8783
8781
  * @param queryArguments an object containing the arguments for the query.
8784
8782
  * Example: `{mileage: 123}` for a query with `:mileage` placeholder.
8783
+ * @template T The type of the query arguments.
8785
8784
  * @returns An active `SyncSubscription` for the passed in query and
8786
8785
  * arguments. It will remain active until it is
8787
8786
  * {@link SyncSubscription.cancel | cancelled} or the {@link Ditto} instance
@@ -8808,8 +8807,7 @@ class Sync {
8808
8807
  throw new DittoError('query/arguments-invalid', `Unable to encode query arguments: ${error.message}`);
8809
8808
  }
8810
8809
  }
8811
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
8812
- this.ditto.deferClose(() => {
8810
+ this.ditto.deferClose((dittoHandle) => {
8813
8811
  mapFFIErrors(() => tryAddSyncSubscription(dittoHandle.deref(), query, queryArgumentsCBOR));
8814
8812
  });
8815
8813
  const subscription = new SyncSubscription(this.ditto, query, queryArguments || null, queryArgumentsCBOR);
@@ -8877,8 +8875,7 @@ class Sync {
8877
8875
  newSyncSubscriptions.splice(indexToDelete, 1);
8878
8876
  // @ts-expect-error modifying readonly property
8879
8877
  this.subscriptions = Object.freeze(newSyncSubscriptions);
8880
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
8881
- this.ditto.deferClose(() => {
8878
+ this.ditto.deferClose((dittoHandle) => {
8882
8879
  // prettier-ignore
8883
8880
  mapFFIErrors(() => tryRemoveSyncSubscription(dittoHandle.deref(), syncSubscription.queryString, syncSubscription.queryArgumentsCBOR));
8884
8881
  });
@@ -8917,9 +8914,7 @@ class Sync {
8917
8914
  // already be cleaned up properly.
8918
8915
  }
8919
8916
  updatePeerToPeerBluetoothLE(stateOld, stateNew) {
8920
- const ditto = this.ditto;
8921
- const dittoHandle = Bridge.ditto.handleFor(ditto);
8922
- ditto.deferClose(() => {
8917
+ this.ditto.deferClose((dittoHandle) => {
8923
8918
  const bluetoothLEOld = stateOld.effectiveTransportConfig.peerToPeer.bluetoothLE;
8924
8919
  const bluetoothLENew = stateNew.effectiveTransportConfig.peerToPeer.bluetoothLE;
8925
8920
  const shouldStart = !bluetoothLEOld.isEnabled && bluetoothLENew.isEnabled;
@@ -8958,9 +8953,7 @@ class Sync {
8958
8953
  });
8959
8954
  }
8960
8955
  updatePeerToPeerAWDL(stateOld, stateNew) {
8961
- const ditto = this.ditto;
8962
- const dittoHandle = Bridge.ditto.handleFor(ditto);
8963
- ditto.deferClose(() => {
8956
+ this.ditto.deferClose((dittoHandle) => {
8964
8957
  const awdlOld = stateOld.effectiveTransportConfig.peerToPeer.awdl;
8965
8958
  const awdlNew = stateNew.effectiveTransportConfig.peerToPeer.awdl;
8966
8959
  const shouldStart = !awdlOld.isEnabled && awdlNew.isEnabled;
@@ -8980,9 +8973,7 @@ class Sync {
8980
8973
  });
8981
8974
  }
8982
8975
  updatePeerToPeerLAN(stateOld, stateNew) {
8983
- const ditto = this.ditto;
8984
- const dittoHandle = Bridge.ditto.handleFor(ditto);
8985
- ditto.deferClose(() => {
8976
+ this.ditto.deferClose((dittoHandle) => {
8986
8977
  const lanOld = stateOld.effectiveTransportConfig.peerToPeer.lan;
8987
8978
  const lanNew = stateNew.effectiveTransportConfig.peerToPeer.lan;
8988
8979
  // HACK: quick & dirty Linux & Windows hack. A proper implementation
@@ -9041,9 +9032,7 @@ class Sync {
9041
9032
  });
9042
9033
  }
9043
9034
  updateListenTCP(stateOld, stateNew) {
9044
- const ditto = this.ditto;
9045
- const dittoHandle = Bridge.ditto.handleFor(ditto);
9046
- ditto.deferClose(() => {
9035
+ this.ditto.deferClose((dittoHandle) => {
9047
9036
  const tcpOld = stateOld.effectiveTransportConfig.listen.tcp;
9048
9037
  const tcpNew = stateNew.effectiveTransportConfig.listen.tcp;
9049
9038
  if (TransportConfig.areListenTCPsEqual(tcpNew, tcpOld))
@@ -9055,9 +9044,7 @@ class Sync {
9055
9044
  });
9056
9045
  }
9057
9046
  updateListenHTTP(stateOld, stateNew) {
9058
- const ditto = this.ditto;
9059
- const dittoHandle = Bridge.ditto.handleFor(ditto);
9060
- ditto.deferClose(() => {
9047
+ this.ditto.deferClose((dittoHandle) => {
9061
9048
  const httpOld = stateOld.effectiveTransportConfig.listen.http;
9062
9049
  const httpNew = stateNew.effectiveTransportConfig.listen.http;
9063
9050
  if (TransportConfig.areListenHTTPsEqual(httpOld, httpNew))
@@ -9072,35 +9059,27 @@ class Sync {
9072
9059
  });
9073
9060
  }
9074
9061
  updateConnectTCPServers(stateOld, stateNew) {
9075
- const ditto = this.ditto;
9076
- const dittoHandle = Bridge.ditto.handleFor(ditto);
9077
- ditto.deferClose(() => {
9062
+ this.ditto.deferClose((dittoHandle) => {
9078
9063
  const tcpServers = stateNew.effectiveTransportConfig.connect.tcpServers;
9079
9064
  dittoSetStaticTCPClients(dittoHandle.deref(), tcpServers);
9080
9065
  });
9081
9066
  }
9082
9067
  updateConnectWebsocketURLs(stateOld, stateNew) {
9083
- const ditto = this.ditto;
9084
- const dittoHandle = Bridge.ditto.handleFor(ditto);
9085
- ditto.deferClose(() => {
9068
+ this.ditto.deferClose((dittoHandle) => {
9086
9069
  const websocketURLs = stateNew.effectiveTransportConfig.connect.websocketURLs;
9087
9070
  const routingHint = stateNew.effectiveTransportConfig.global.routingHint;
9088
9071
  dittoSetStaticWebsocketClients(dittoHandle.deref(), websocketURLs, routingHint);
9089
9072
  });
9090
9073
  }
9091
9074
  updateGlobal(stateOld, stateNew) {
9092
- const ditto = this.ditto;
9093
- const dittoHandle = Bridge.ditto.handleFor(ditto);
9094
- ditto.deferClose(() => {
9075
+ this.ditto.deferClose((dittoHandle) => {
9095
9076
  if (stateOld.effectiveTransportConfig.global.syncGroup !== stateNew.effectiveTransportConfig.global.syncGroup) {
9096
9077
  dittoSetSyncGroup(dittoHandle.deref(), stateNew.effectiveTransportConfig.global.syncGroup);
9097
9078
  }
9098
9079
  });
9099
9080
  }
9100
9081
  updateConnectRetryInterval(stateOld, stateNew) {
9101
- const ditto = this.ditto;
9102
- const dittoHandle = Bridge.ditto.handleFor(ditto);
9103
- ditto.deferClose(() => {
9082
+ this.ditto.deferClose((dittoHandle) => {
9104
9083
  dittoSetConnectRetryInterval(dittoHandle.deref(), stateNew.effectiveTransportConfig.connect.retryInterval);
9105
9084
  });
9106
9085
  }
@@ -9173,8 +9152,7 @@ function stateFrom(parameters) {
9173
9152
  * @private
9174
9153
  */
9175
9154
  function validateEnabledTransportsAvailable(ditto, transportConfig) {
9176
- const dittoHandle = Bridge.ditto.handleFor(ditto);
9177
- return ditto.deferClose(() => {
9155
+ return ditto.deferClose((dittoHandle) => {
9178
9156
  // - BLE
9179
9157
  // - AWDL
9180
9158
  // - LAN / mDNS
@@ -9230,10 +9208,8 @@ class SubscriptionManager {
9230
9208
  * @internal
9231
9209
  */
9232
9210
  add(subscription) {
9233
- const ditto = this.ditto;
9234
- const dittoHandle = Bridge.ditto.handleFor(ditto);
9235
9211
  const contextInfo = subscription.contextInfo;
9236
- ditto.deferClose(() => {
9212
+ this.ditto.deferClose((dittoHandle) => {
9237
9213
  this.subscriptions[contextInfo.id] = new WeakRef(subscription);
9238
9214
  this.finalizationRegistry.register(subscription, subscription.contextInfo, subscription);
9239
9215
  addSubscription(dittoHandle.deref(), contextInfo.collectionName, contextInfo.query, contextInfo.queryArgsCBOR, contextInfo.orderBys, contextInfo.limit, contextInfo.offset);
@@ -9271,9 +9247,7 @@ class SubscriptionManager {
9271
9247
  * @internal
9272
9248
  */
9273
9249
  removeWithContextInfo(contextInfo) {
9274
- const ditto = this.ditto;
9275
- const dittoHandle = Bridge.ditto.handleFor(ditto);
9276
- ditto.deferClose(() => {
9250
+ this.ditto.deferClose((dittoHandle) => {
9277
9251
  delete this.subscriptions[contextInfo.id];
9278
9252
  removeSubscription(dittoHandle.deref(), contextInfo.collectionName, contextInfo.query, contextInfo.queryArgsCBOR, contextInfo.orderBys, contextInfo.limit, contextInfo.offset);
9279
9253
  });
@@ -9373,8 +9347,7 @@ class AttachmentFetcherManager {
9373
9347
  * registry.
9374
9348
  */
9375
9349
  stopWithContextInfo(contextInfo) {
9376
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
9377
- return this.ditto.deferCloseAsync(async () => {
9350
+ return this.ditto.deferCloseAsync(async (dittoHandle) => {
9378
9351
  // Remove the manager's own record of the context info.
9379
9352
  if (this.contextInfoByID[contextInfo.id] == null) {
9380
9353
  throw new Error(`Internal inconsistency: attachment fetcher ${contextInfo.id} not found in active attachment fetchers.`);
@@ -9407,7 +9380,7 @@ class AttachmentFetcherManager {
9407
9380
  class SmallPeerInfo {
9408
9381
  /**
9409
9382
  * Indicates whether small peer info collection is currently enabled, defaults
9410
- * to `false`.
9383
+ * to `true`.
9411
9384
  *
9412
9385
  * **Note**: whether the background ingestion process is enabled or not is a
9413
9386
  * separate decision to whether this information is allowed to sync to other
@@ -9416,8 +9389,7 @@ class SmallPeerInfo {
9416
9389
  * {@link setSyncScope | setSyncScope()}.
9417
9390
  */
9418
9391
  get isEnabled() {
9419
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
9420
- return this.ditto.deferClose(() => {
9392
+ return this.ditto.deferClose((dittoHandle) => {
9421
9393
  return dittoSmallPeerInfoGetIsEnabled(dittoHandle.deref());
9422
9394
  });
9423
9395
  }
@@ -9430,8 +9402,7 @@ class SmallPeerInfo {
9430
9402
  if (typeof newValue !== 'boolean') {
9431
9403
  throw new TypeError(`Expected boolean, got ${typeof newValue}`);
9432
9404
  }
9433
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
9434
- void this.ditto.deferCloseAsync(async () => {
9405
+ void this.ditto.deferCloseAsync(async (dittoHandle) => {
9435
9406
  return dittoSmallPeerInfoSetEnabled(dittoHandle.deref(), newValue);
9436
9407
  });
9437
9408
  }
@@ -9473,8 +9444,7 @@ class SmallPeerInfo {
9473
9444
  * The metadata associated with the small peer info, as a JSON string.
9474
9445
  */
9475
9446
  get metadataJSONString() {
9476
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
9477
- return this.ditto.deferClose(() => {
9447
+ return this.ditto.deferClose((dittoHandle) => {
9478
9448
  return dittoSmallPeerInfoGetMetadata(dittoHandle.deref());
9479
9449
  });
9480
9450
  }
@@ -9490,8 +9460,7 @@ class SmallPeerInfo {
9490
9460
  if (typeof metadata !== 'string') {
9491
9461
  throw new TypeError(`Expected string, got ${typeof metadata}`);
9492
9462
  }
9493
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
9494
- this.ditto.deferClose(() => {
9463
+ this.ditto.deferClose((dittoHandle) => {
9495
9464
  // throws if any validation errors occur
9496
9465
  dittoSmallPeerInfoSetMetadata(dittoHandle.deref(), metadata);
9497
9466
  });
@@ -9504,8 +9473,7 @@ class SmallPeerInfo {
9504
9473
  * `BigPeerOnly` to replicate collected info to the Big Peer.
9505
9474
  */
9506
9475
  async getSyncScope() {
9507
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
9508
- return this.ditto.deferCloseAsync(async () => {
9476
+ return this.ditto.deferCloseAsync(async (dittoHandle) => {
9509
9477
  return dittoSmallPeerInfoGetSyncScope(dittoHandle.deref());
9510
9478
  });
9511
9479
  }
@@ -9518,8 +9486,7 @@ class SmallPeerInfo {
9518
9486
  * @throws when set to a value other than `BigPeerOnly` or `LocalPeerOnly`.
9519
9487
  */
9520
9488
  async setSyncScope(syncScope) {
9521
- const dittoHandle = Bridge.ditto.handleFor(this.ditto);
9522
- return this.ditto.deferCloseAsync(async () => {
9489
+ return this.ditto.deferCloseAsync(async (dittoHandle) => {
9523
9490
  return dittoSmallPeerInfoSetSyncScope(dittoHandle.deref(), syncScope);
9524
9491
  });
9525
9492
  }
@@ -9570,8 +9537,7 @@ class Ditto {
9570
9537
  }
9571
9538
  /** Returns a string identifying the version of the Ditto SDK. */
9572
9539
  get sdkVersion() {
9573
- const dittoHandle = Bridge.ditto.handleFor(this);
9574
- return this.deferClose(() => {
9540
+ return this.deferClose((dittoHandle) => {
9575
9541
  return dittoGetSDKVersion(dittoHandle.deref());
9576
9542
  });
9577
9543
  }
@@ -9644,6 +9610,7 @@ class Ditto {
9644
9610
  if (!Ditto.isEnvironmentSupported()) {
9645
9611
  throw new Error('Ditto does not support this JavaScript environment. Please consult the Ditto JavaScript documentation for a list of supported environments and browsers. You can use `Ditto.isEnvironmentSupported()` to run this check anytime.');
9646
9612
  }
9613
+ loggerInit();
9647
9614
  this.persistenceDirectory = Ditto.initPersistenceDirectory(persistenceDirectory);
9648
9615
  const identityOrDefault = identity !== null && identity !== void 0 ? identity : { type: 'offlinePlayground', appID: '' };
9649
9616
  const validIdentity = Object.freeze(this.validateIdentity(identityOrDefault));
@@ -9957,8 +9924,7 @@ class Ditto {
9957
9924
  this.sync.update({ transportConfig: transportConfigNew, identity, isWebValid, isX509Valid, isSyncActive: this.isSyncActive, ditto: this });
9958
9925
  const configSerializeReady = transportConfigToSerializable(transportConfigNew);
9959
9926
  const configCBOR = CBOR.encode(configSerializeReady);
9960
- const dittoHandle = Bridge.ditto.handleFor(this);
9961
- this.deferClose(() => {
9927
+ this.deferClose((dittoHandle) => {
9962
9928
  dittoSmallPeerInfoCollectionSetTransportConfigData(dittoHandle.deref(), configCBOR);
9963
9929
  });
9964
9930
  }
@@ -9982,6 +9948,10 @@ class Ditto {
9982
9948
  * customized with {@link updateTransportConfig | updateTransportConfig()}
9983
9949
  * or replaced entirely with {@link setTransportConfig | setTransportConfig()}.
9984
9950
  *
9951
+ * Performance of initial sync when bootstrapping new peers can be improved by
9952
+ * calling {@link disableSyncWithV3 | disableSyncWithV3()} before
9953
+ * {@link startSync | startSync()}. Only call that method when all peers in
9954
+ * the mesh are known to be running Ditto v4 or higher.
9985
9955
  *
9986
9956
  * Ditto will prevent the process from exiting until sync is stopped (not
9987
9957
  * relevant when running in the browser).
@@ -10041,11 +10011,11 @@ class Ditto {
10041
10011
  return new Observer(this.transportConditionsManager, token, { stopsWhenFinalized: true });
10042
10012
  }
10043
10013
  /**
10044
- * Removes all sync metadata for any remote peers which aren't currently
10045
- * connected. This method shouldn't usually be called. Manually running
10046
- * garbage collection often will result in slower sync times. Ditto
10047
- * automatically runs a garbage a collection process in the background at
10048
- * optimal times.
10014
+ * Removes all sync metadata for remote peers that aren't currently connected.
10015
+ *
10016
+ * This method shouldn't usually be called. Manually running garbage
10017
+ * collection often will result in slower sync times. Ditto automatically runs
10018
+ * a garbage a collection process in the background at optimal times.
10049
10019
  *
10050
10020
  * Manually running garbage collection is typically only useful during testing
10051
10021
  * if large amounts of data are being generated. Alternatively, if an entire
@@ -10053,28 +10023,31 @@ class Ditto {
10053
10023
  * isn't necessary, then garbage collection could be run after evicting the
10054
10024
  * old data.
10055
10025
  *
10056
- * Only available in Node environments at the moment, no-op in the browser.
10026
+ * This method does not have any effect when running Ditto in a browser.
10057
10027
  */
10058
- runGarbageCollection() {
10059
- const dittoHandle = Bridge.ditto.handleFor(this);
10060
- return this.deferClose(() => {
10061
- dittoRunGarbageCollection(dittoHandle.deref());
10028
+ async runGarbageCollection() {
10029
+ return this.deferCloseAsync(async (dittoHandle) => {
10030
+ return dittoRunGarbageCollection(dittoHandle.deref());
10062
10031
  });
10063
10032
  }
10064
10033
  /**
10065
- * Explicitly opt-in to disabling the ability to sync with Ditto peers running
10066
- * any version of the SDK in the v3 (or lower) series of releases.
10034
+ * Disable sync with peers running version 3 or lower of the Ditto SDK.
10035
+ *
10036
+ * Required for the execution of mutating DQL statements.
10037
+ *
10038
+ * This setting spreads to other peers on connection. Those peers will in turn
10039
+ * spread it further until all peers in the mesh take on the same setting.
10040
+ * This is irreversible and will persist across restarts of the Ditto
10041
+ * instance.
10067
10042
  *
10068
- * Assuming this succeeds then this peer will only be able to sync with other
10069
- * peers using SDKs in the v4 (or higher) series of releases. Note that this
10070
- * disabling of sync spreads to peers that sync with a peer that has disabled,
10071
- * or has (transitively) had disabled, syncing with v3 SDK peers.
10043
+ * Calling this method before starting sync is recommended whenever possible.
10044
+ * This improves performance of initial sync when this peer has never before
10045
+ * connected to a Ditto mesh for which sync with v3 peers is disabled.
10072
10046
  *
10073
10047
  * @throws {Error} if called in a React Native environment.
10074
10048
  */
10075
10049
  async disableSyncWithV3() {
10076
- const dittoHandle = Bridge.ditto.handleFor(this);
10077
- return this.deferCloseAsync(async () => {
10050
+ return this.deferCloseAsync(async (dittoHandle) => {
10078
10051
  await dittoDisableSyncWithV3(dittoHandle.deref());
10079
10052
  });
10080
10053
  }
@@ -10127,15 +10100,20 @@ class Ditto {
10127
10100
  * Makes sure that the closure is executed only if the Ditto instance hasn't
10128
10101
  * been closed yet.
10129
10102
  *
10103
+ * The closure is given a {@link Handle | handle} to the Ditto instance that
10104
+ * is valid while the closure is executing.
10105
+ *
10130
10106
  * @param closure the synchronous closure to execute.
10131
10107
  * @returns the result of the closure.
10132
10108
  * @throws if the Ditto instance was closed before calling this method.
10133
- * @internal */
10109
+ * @internal
10110
+ */
10134
10111
  deferClose(closure) {
10135
10112
  if (!this.deferCloseAllowed) {
10136
10113
  throw new Error(`Can't perform operation using a Ditto instance that has been closed.`);
10137
10114
  }
10138
- return closure();
10115
+ const dittoHandle = Bridge.ditto.handleFor(this);
10116
+ return closure(dittoHandle);
10139
10117
  }
10140
10118
  /**
10141
10119
  * Makes sure that the closure is executed to completion before the Ditto
@@ -10144,15 +10122,20 @@ class Ditto {
10144
10122
  * Any calls to {@link close | `Ditto.close()`} will wait until the closure
10145
10123
  * has completed before closing the Ditto instance.
10146
10124
  *
10125
+ * The closure is given a {@link Handle | handle} to the Ditto instance that
10126
+ * is valid while the closure is executing.
10127
+ *
10147
10128
  * @param closure the asynchronous closure to execute.
10148
10129
  * @returns the result of the closure.
10149
10130
  * @throws if the Ditto instance was closed before calling this method.
10150
- * @internal */
10131
+ * @internal
10132
+ */
10151
10133
  async deferCloseAsync(closure) {
10152
10134
  if (!this.deferCloseAllowed) {
10153
10135
  throw new Error(`Can't perform operation using a Ditto instance that has been closed.`);
10154
10136
  }
10155
- const pendingOperation = closure();
10137
+ const dittoHandle = Bridge.ditto.handleFor(this);
10138
+ const pendingOperation = closure(dittoHandle);
10156
10139
  this.pendingOperations.add(pendingOperation);
10157
10140
  let result;
10158
10141
  try {
@@ -10214,8 +10197,7 @@ class Ditto {
10214
10197
  return validIdentity;
10215
10198
  }
10216
10199
  setSyncActive(flag) {
10217
- const dittoHandle = Bridge.ditto.handleFor(this);
10218
- this.deferClose(() => {
10200
+ this.deferClose((dittoHandle) => {
10219
10201
  if (flag && IdentityTypesRequiringOfflineLicenseToken.includes(this.identity.type) && !this.isActivated) {
10220
10202
  throw new Error('Sync could not be started because Ditto has not yet been activated. This can be achieved with a successful call to `setOfflineOnlyLicenseToken`. If you need to obtain a license token then please visit https://portal.ditto.live.');
10221
10203
  }
@@ -10235,8 +10217,7 @@ class Ditto {
10235
10217
  });
10236
10218
  }
10237
10219
  makeDefaultTransportConfig() {
10238
- const dittoHandle = Bridge.ditto.handleFor(this);
10239
- return this.deferClose(() => {
10220
+ return this.deferClose((dittoHandle) => {
10240
10221
  const transportConfig = new TransportConfig();
10241
10222
  if (transportsBLEIsAvailable(dittoHandle.deref())) {
10242
10223
  transportConfig.peerToPeer.bluetoothLE.isEnabled = true;
@@ -10349,12 +10330,14 @@ const CUSTOM_INSPECT_SYMBOL = Symbol.for('nodejs.util.inspect.custom');
10349
10330
  * It’s a reference type serving as a “cursor”, allowing for efficient access of
10350
10331
  * the underlying data in various formats.
10351
10332
  *
10352
- * The {@link QueryResultItem.value | value } property is lazily
10353
- * materialized and kept in memory until it goes out of scope. To reduce the
10354
- * memory footprint, structure your code such that items can be processed as a
10355
- * stream, i.e. one by one (or in batches) and
10356
- * {@link QueryResultItem.dematerialize | dematerialize() } them
10357
- * right after use.
10333
+ * The {@link QueryResultItem.value | value } property is lazily materialized
10334
+ * and kept in memory until it goes out of scope. To reduce the memory
10335
+ * footprint, structure your code such that items can be processed as a stream,
10336
+ * i.e. one by one (or in batches) and
10337
+ * {@link QueryResultItem.dematerialize | dematerialize() } them right after
10338
+ * use.
10339
+ *
10340
+ * @template T The type of the item's {@link QueryResultItem.value | value }.
10358
10341
  */
10359
10342
  class QueryResultItem {
10360
10343
  /**
@@ -10474,22 +10457,6 @@ function getBridgeLoad() {
10474
10457
  return countsByType;
10475
10458
  }
10476
10459
 
10477
- //
10478
- // Copyright © 2021 DittoLive Incorporated. All rights reserved.
10479
- //
10480
- // HACK: don't export these publicly, only needed internally.
10481
- /** @internal */
10482
- class StaticTCPClient {
10483
- }
10484
-
10485
- //
10486
- // Copyright © 2021 DittoLive Incorporated. All rights reserved.
10487
- //
10488
- // HACK: don't export these publicly, only needed internally.
10489
- /** @internal */
10490
- class WebsocketClient {
10491
- }
10492
-
10493
10460
  //
10494
10461
  // Copyright © 2021 DittoLive Incorporated. All rights reserved.
10495
10462
  //
@@ -10505,8 +10472,6 @@ Bridge.document.registerType(Document);
10505
10472
  Bridge.queryResultItem.registerType(QueryResultItem);
10506
10473
  Bridge.queryResult.registerType(QueryResult);
10507
10474
  Bridge.mutableDocument.registerType(MutableDocument);
10508
- Bridge.staticTCPClient.registerType(StaticTCPClient);
10509
- Bridge.websocketClient.registerType(WebsocketClient);
10510
10475
  Bridge.ditto.registerType(Ditto);
10511
10476
 
10512
10477
  exports.Attachment = Attachment;