@dittolive/ditto 4.11.2-rc.1 → 4.12.0-experimental-untangle.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/node/ditto.cjs.js CHANGED
@@ -106,6 +106,8 @@ class Observer {
106
106
  }
107
107
  Observer.finalizationRegistry = new FinalizationRegistry(Observer.finalize);
108
108
 
109
+ const isReactNativeBuild = false;
110
+
109
111
  //
110
112
  // Copyright © 2021 DittoLive Incorporated. All rights reserved.
111
113
  //
@@ -118,14 +120,21 @@ const privateToken$1 = Symbol('privateConstructorToken');
118
120
  * assigned to a property during an update of a document.
119
121
  *
120
122
  * Not available in React Native environments.
123
+ *
124
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
121
125
  */
122
126
  class Counter {
123
- /** The value of the counter. */
127
+ /**
128
+ * The value of the counter.
129
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
130
+ */
124
131
  get value() {
125
132
  return this._value;
126
133
  }
127
134
  /**
128
135
  * Creates a new counter that can be used as part of a document's content.
136
+ *
137
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
129
138
  */
130
139
  constructor() {
131
140
  this._value = 0.0;
@@ -147,6 +156,8 @@ class Counter {
147
156
  *
148
157
  * This class can't be instantiated directly, it's returned automatically for
149
158
  * any counter property within an update block via {@link MutableDocumentPath.counter}.
159
+ *
160
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
150
161
  */
151
162
  class MutableCounter extends Counter {
152
163
  /**
@@ -156,8 +167,8 @@ class MutableCounter extends Counter {
156
167
  * {@link PendingCursorOperation.update | PendingCursorOperation.update()} and
157
168
  * {@link PendingIDSpecificOperation.update | PendingIDSpecificOperation.update()},
158
169
  * otherwise an exception is thrown.
159
- *
160
170
  * @throws {Error} when called in a React Native environment.
171
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
161
172
  */
162
173
  increment(amount) {
163
174
  const mutDoc = this.mutDoc;
@@ -191,14 +202,23 @@ const privateToken = '@ditto.ff82dae89821c5ab822a8b539056bce4';
191
202
  * assigned to a property during an update of a document.
192
203
  *
193
204
  * Not available in React Native environments.
205
+ *
206
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
207
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
194
208
  */
195
209
  class Register {
196
- /** Returns the value of the register. */
210
+ /**
211
+ * Returns the value of the register.
212
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
213
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
214
+ */
197
215
  get value() {
198
216
  return this['@ditto.value'];
199
217
  }
200
218
  /**
201
219
  * Creates a new Register that can be used as part of a document's content.
220
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
221
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
202
222
  */
203
223
  constructor(value) {
204
224
  this['@ditto.value'] = value;
@@ -224,12 +244,17 @@ class Register {
224
244
  * {@link MutableDocumentPath.register}.
225
245
  *
226
246
  * Not available in React Native environments.
247
+ *
248
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
249
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
227
250
  */
228
251
  class MutableRegister extends Register {
229
252
  /**
230
253
  * Returns the value of the register.
231
254
  *
232
255
  * Not available in React Native environments.
256
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
257
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
233
258
  */
234
259
  get value() {
235
260
  return super.value;
@@ -238,6 +263,9 @@ class MutableRegister extends Register {
238
263
  * Convenience setter, equivalent to {@link set | set()}.
239
264
  *
240
265
  * Not available in React Native environments.
266
+ *
267
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
268
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
241
269
  */
242
270
  set value(value) {
243
271
  this.set(value);
@@ -251,6 +279,9 @@ class MutableRegister extends Register {
251
279
  * otherwise an exception is thrown.
252
280
  *
253
281
  * Not available in React Native environments.
282
+ *
283
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
284
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
254
285
  */
255
286
  set(value) {
256
287
  const mutableDocument = this['@ditto.mutableDocument'];
@@ -382,6 +413,8 @@ function ditto_validate_document_id(...args) { return ditto.ditto_validate_docum
382
413
  function ditto_write_transaction(...args) { return ditto.ditto_write_transaction(...args) }
383
414
  function ditto_write_transaction_commit(...args) { return ditto.ditto_write_transaction_commit(...args) }
384
415
  function ditto_write_transaction_rollback(...args) { return ditto.ditto_write_transaction_rollback(...args) }
416
+ function dittoffi_DEFAULT_DATABASE_ID(...args) { return ditto.dittoffi_DEFAULT_DATABASE_ID(...args) }
417
+ function dittoffi_DITTO_DEVELOPMENT_PROVIDER(...args) { return ditto.dittoffi_DITTO_DEVELOPMENT_PROVIDER(...args) }
385
418
  function dittoffi_authentication_status_free(...args) { return ditto.dittoffi_authentication_status_free(...args) }
386
419
  function dittoffi_authentication_status_is_authenticated(...args) { return ditto.dittoffi_authentication_status_is_authenticated(...args) }
387
420
  function dittoffi_authentication_status_user_id(...args) { return ditto.dittoffi_authentication_status_user_id(...args) }
@@ -396,8 +429,11 @@ function dittoffi_crypto_generate_secure_random_token(...args) { return ditto.di
396
429
  function dittoffi_differ_diff(...args) { return ditto.dittoffi_differ_diff(...args) }
397
430
  function dittoffi_differ_free(...args) { return ditto.dittoffi_differ_free(...args) }
398
431
  function dittoffi_differ_new(...args) { return ditto.dittoffi_differ_new(...args) }
432
+ function dittoffi_ditto_absolute_persistence_directory(...args) { return ditto.dittoffi_ditto_absolute_persistence_directory(...args) }
433
+ function dittoffi_ditto_config_default(...args) { return ditto.dittoffi_ditto_config_default(...args) }
399
434
  function dittoffi_ditto_is_activated(...args) { return ditto.dittoffi_ditto_is_activated(...args) }
400
435
  function dittoffi_ditto_is_sync_active(...args) { return ditto.dittoffi_ditto_is_sync_active(...args) }
436
+ function dittoffi_ditto_open_throws(...args) { return ditto.dittoffi_ditto_open_throws(...args) }
401
437
  function dittoffi_ditto_set_authentication_status_handler(...args) { return ditto.dittoffi_ditto_set_authentication_status_handler(...args) }
402
438
  function dittoffi_ditto_set_cloud_sync_enabled(...args) { return ditto.dittoffi_ditto_set_cloud_sync_enabled(...args) }
403
439
  function dittoffi_ditto_stop_sync(...args) { return ditto.dittoffi_ditto_stop_sync(...args) }
@@ -413,7 +449,9 @@ function dittoffi_logger_try_export_to_file_async(...args) { return ditto.dittof
413
449
  function dittoffi_presence_peer_metadata_json(...args) { return ditto.dittoffi_presence_peer_metadata_json(...args) }
414
450
  function dittoffi_presence_set_connection_request_handler(...args) { return ditto.dittoffi_presence_set_connection_request_handler(...args) }
415
451
  function dittoffi_presence_try_set_peer_metadata_json(...args) { return ditto.dittoffi_presence_try_set_peer_metadata_json(...args) }
452
+ function dittoffi_query_result_commit_id(...args) { return ditto.dittoffi_query_result_commit_id(...args) }
416
453
  function dittoffi_query_result_free(...args) { return ditto.dittoffi_query_result_free(...args) }
454
+ function dittoffi_query_result_has_commit_id(...args) { return ditto.dittoffi_query_result_has_commit_id(...args) }
417
455
  function dittoffi_query_result_item_at(...args) { return ditto.dittoffi_query_result_item_at(...args) }
418
456
  function dittoffi_query_result_item_cbor(...args) { return ditto.dittoffi_query_result_item_cbor(...args) }
419
457
  function dittoffi_query_result_item_count(...args) { return ditto.dittoffi_query_result_item_count(...args) }
@@ -553,6 +591,19 @@ var DittoCRDTType;
553
591
  DittoCRDTType[DittoCRDTType["rga"] = 3] = "rga";
554
592
  DittoCRDTType[DittoCRDTType["rwMap"] = 4] = "rwMap";
555
593
  })(DittoCRDTType || (DittoCRDTType = {}));
594
+ // ------------------------------------------------------------- Constants --
595
+ /** @internal */
596
+ function DITTO_DEVELOPMENT_PROVIDER() {
597
+ ensureInitialized();
598
+ const providerCString = dittoffi_DITTO_DEVELOPMENT_PROVIDER();
599
+ return refCStringToString(providerCString);
600
+ }
601
+ /** @internal */
602
+ function DEFAULT_DATABASE_ID() {
603
+ ensureInitialized();
604
+ const idCString = dittoffi_DEFAULT_DATABASE_ID();
605
+ return refCStringToString(idCString);
606
+ }
556
607
  // ------------------------------------------------------------- Differ --------
557
608
  function differNew() {
558
609
  ensureInitialized();
@@ -881,6 +932,23 @@ function queryResultMutatedDocumentIDs(queryResultPointer) {
881
932
  }
882
933
  return rv;
883
934
  }
935
+ /**
936
+ * @internal
937
+ */
938
+ function queryResultHasCommitID(queryResultPointer) {
939
+ ensureInitialized();
940
+ return dittoffi_query_result_has_commit_id(queryResultPointer);
941
+ }
942
+ /**
943
+ * @internal
944
+ */
945
+ function queryResultCommitID(queryResultPointer) {
946
+ ensureInitialized();
947
+ const commitId = dittoffi_query_result_commit_id(queryResultPointer);
948
+ // the FFI function returns a number or BigInt, we convert it to BigInt
949
+ // to simplify the API
950
+ return BigInt(commitId);
951
+ }
884
952
  /**
885
953
  * The result CBOR contains a map/object with fields and values. No CRDTs are
886
954
  * present there as they are not needed. By default only values from registers
@@ -1083,7 +1151,7 @@ function loggerSetLogFile(path) {
1083
1151
  }
1084
1152
  }
1085
1153
  /** @internal */
1086
- async function loggerTryExportToFileAsync(path) {
1154
+ async function loggerTryExportToFile(path) {
1087
1155
  ensureInitialized();
1088
1156
  const pathBytes = bytesFromString(path);
1089
1157
  const result = await new Promise((resolve, reject) => {
@@ -1299,7 +1367,34 @@ function transactionFree(transaction) {
1299
1367
  ensureInitialized();
1300
1368
  dittoffi_transaction_free(transaction);
1301
1369
  }
1302
- // ---------------------------------------------------------------- Ditto ------
1370
+ // --------------------------------------------------------- Ditto Config ------
1371
+ /** @internal */
1372
+ function dittoConfigDefault() {
1373
+ ensureInitialized();
1374
+ const cborBytes = dittoffi_ditto_config_default();
1375
+ return boxCBytesIntoBuffer(cborBytes);
1376
+ }
1377
+ /** @internal */
1378
+ function dittoAbsolutePersistenceDirectory(dittoPointer) {
1379
+ ensureInitialized();
1380
+ const cString = dittoffi_ditto_absolute_persistence_directory(dittoPointer);
1381
+ return boxCStringIntoString(cString);
1382
+ }
1383
+ /** @internal */
1384
+ function dittoOpenThrows(configCBOR, transportConfigMode, defaultRootDirectory) {
1385
+ ensureInitialized();
1386
+ const defaultRootDirectoryPointer = bytesFromString(defaultRootDirectory);
1387
+ // // Debug: Log CBOR bytes in hex format. The output can be pasted to https://cbor.me
1388
+ // // to visualize the CBOR structure.
1389
+ // const hexBytes = Array.from(configCBOR)
1390
+ // .map((byte) => byte.toString(16).padStart(2, '0').toUpperCase())
1391
+ // .join(' ');
1392
+ // console.log(`DEBUG: CBOR bytes (${configCBOR.length} bytes):`);
1393
+ // console.log(hexBytes);
1394
+ const result = dittoffi_ditto_open_throws(configCBOR, transportConfigMode, defaultRootDirectoryPointer);
1395
+ throwOnErrorResult(result.error, 'dittoffi_ditto_open_throws');
1396
+ return result.success;
1397
+ }
1303
1398
  /** @internal */
1304
1399
  function dittoTryNewBlocking(path, identityConfig, historyTracking, transportConfigMode) {
1305
1400
  ensureInitialized();
@@ -1449,7 +1544,7 @@ function dittoIsSyncActive(ditto) {
1449
1544
  return dittoffi_ditto_is_sync_active(ditto);
1450
1545
  }
1451
1546
  /** @internal */
1452
- function dittoStartSync(ditto) {
1547
+ function dittoTryStartSync(ditto) {
1453
1548
  ensureInitialized();
1454
1549
  const result = dittoffi_ditto_try_start_sync(ditto);
1455
1550
  throwOnErrorResult(result.error, 'dittoffi_ditto_try_start_sync');
@@ -1729,8 +1824,8 @@ function withTransportsError(ffiFunction, ...args) {
1729
1824
  }
1730
1825
  // ---------------------------------------------------------------- Other ------
1731
1826
  /** @internal */
1732
- let isInitialized = false;
1733
- isInitialized = true;
1827
+ let isInitialized$1 = false;
1828
+ isInitialized$1 = true;
1734
1829
  /** @internal */
1735
1830
  function initSDKVersion(platform, language, semVer) {
1736
1831
  ensureInitialized();
@@ -1750,6 +1845,19 @@ function tryVerifyLicense(ditto, license) {
1750
1845
  const result = dittoffi_try_verify_license(ditto, licenseBuffer);
1751
1846
  throwOnErrorResult(result.error, 'dittoffi_try_verify_license');
1752
1847
  }
1848
+ /**
1849
+ * Returns the platform-dependent default device name.
1850
+ *
1851
+ * @internal
1852
+ */
1853
+ // FIXME: Move this to Ditto core.
1854
+ function defaultDeviceName() {
1855
+ // FIXME: Check if device name stays the same on sdk and core levels (AR-5950).
1856
+ {
1857
+ const os = require('os');
1858
+ return os.hostname();
1859
+ }
1860
+ }
1753
1861
  // -------------------------------------------------------------- Private ------
1754
1862
  // HACK: this is a left-over error code still in use which will be removed
1755
1863
  // in the near future. Until then, we hard-code it here, just like the
@@ -1821,7 +1929,7 @@ function errorMessage() {
1821
1929
  }
1822
1930
  /** @internal */
1823
1931
  function ensureInitialized() {
1824
- if (!isInitialized) {
1932
+ if (!isInitialized$1) {
1825
1933
  throw new Error('Ditto needs to be initialized before using any of its API, please make sure to call `await init()` first.');
1826
1934
  }
1827
1935
  }
@@ -1856,6 +1964,8 @@ const ERROR_CODES = {
1856
1964
  //
1857
1965
  /** Error when authentication failed */
1858
1966
  'authentication/failed-to-authenticate': 'Ditto failed to authenticate.',
1967
+ /** Error when the required expiration handler is not set before starting sync. */
1968
+ 'authentication/expiration-handler-missing': 'The expiration handler must be set before starting sync.',
1859
1969
  //
1860
1970
  // IO errors
1861
1971
  //
@@ -1930,6 +2040,8 @@ const ERROR_CODES = {
1930
2040
  'validation/invalid-json': 'The value provided is not valid JSON.',
1931
2041
  /** A validation error where the TransportConfig is invalid for the active platform. */
1932
2042
  'validation/invalid-transport-config': 'The TransportConfig is invalid for the active platform.',
2043
+ /** A validation error where the {@link DittoConfig} is invalid. */
2044
+ 'validation/invalid-ditto-config': 'The DittoConfig provided is invalid.',
1933
2045
  /** A validation error where a value is required to be a JavaScript object */
1934
2046
  'validation/not-an-object': 'The value provided is not of type object.',
1935
2047
  /** The value provided can not be serialized as JSON. */
@@ -1971,6 +2083,12 @@ const DEFAULT_STATUS_CODE_MAPPING = {
1971
2083
  ActivationNotActivated: ['activation/not-activated'],
1972
2084
  ActivationUnnecessary: ['activation/unnecessary'],
1973
2085
  //
2086
+ // Authenticaion errors
2087
+ //
2088
+ AuthenticationExpirationHandlerMissing: [
2089
+ 'authentication/expiration-handler-missing',
2090
+ ],
2091
+ //
1974
2092
  // Input/output errors
1975
2093
  //
1976
2094
  IoAlreadyExists: ['io/already-exists'],
@@ -2018,6 +2136,7 @@ const DEFAULT_STATUS_CODE_MAPPING = {
2018
2136
  CborUnsupported: ['internal', 'Unsupported CBOR encoding.'],
2019
2137
  ValidationDepthLimitExceeded: ['validation/depth-limit-exceeded'],
2020
2138
  ValidationInvalidCbor: ['validation/invalid-cbor'],
2139
+ ValidationInvalidDittoConfig: ['validation/invalid-ditto-config'],
2021
2140
  ValidationInvalidJson: ['validation/invalid-json'],
2022
2141
  ValidationInvalidTransportConfig: ['validation/invalid-transport-config'],
2023
2142
  ValidationNotAMap: ['validation/not-an-object'],
@@ -2274,11 +2393,13 @@ class AttachmentToken {
2274
2393
 
2275
2394
  // NOTE: this is patched up with the actual build version by Jake task
2276
2395
  // build:package and has to be a valid semantic version as defined here: https://semver.org.
2277
- const fullBuildVersionString = '4.11.2-rc.1';
2396
+ const fullBuildVersionString = '4.12.0-experimental-untangle.0';
2278
2397
 
2279
2398
  //
2280
2399
  // Copyright © 2021 DittoLive Incorporated. All rights reserved.
2281
2400
  //
2401
+ let isInitialized = false;
2402
+ let initPromise = null;
2282
2403
  // Replacing {custom-sdk-name} with any string that doesn't contain '{' in the
2283
2404
  // final build output switches the SDK_NAME to the custom name.
2284
2405
  const SDK_NAME = '{custom-sdk-name}'.includes('{')
@@ -2290,7 +2411,17 @@ const SDK_NAME = '{custom-sdk-name}'.includes('{')
2290
2411
  *
2291
2412
  * @param options - Dictionary with global {@link InitOptions | initialization options}.
2292
2413
  */
2293
- async function init(options = {}) {
2414
+ function init(options = {}) {
2415
+ // If we have already completed initialization just return the resolved Promise
2416
+ if (isInitialized)
2417
+ return initPromise;
2418
+ // If initialization is in flight return the already created promise
2419
+ if (initPromise)
2420
+ return initPromise;
2421
+ initPromise = (async () => {
2422
+ isInitialized = true;
2423
+ })();
2424
+ return initPromise;
2294
2425
  }
2295
2426
  {
2296
2427
  switch (process.platform) {
@@ -2345,6 +2476,7 @@ class Logger {
2345
2476
  * @param path can be `null`, in which case the current logging file, if any,
2346
2477
  * is unregistered, otherwise, the file path must be within an already
2347
2478
  * existing directory.
2479
+ * @deprecated this mehod is deprecated and will be removed in a future version.
2348
2480
  */
2349
2481
  static setLogFile(path) {
2350
2482
  if (path) {
@@ -2359,6 +2491,8 @@ class Logger {
2359
2491
  /**
2360
2492
  * Convenience method, takes the path part of the URL and calls
2361
2493
  * {@link setLogFile | setLogFile()} with it.
2494
+ *
2495
+ * @deprecated this method is deprecated and will be removed in a future version.
2362
2496
  */
2363
2497
  static setLogFileURL(url) {
2364
2498
  var _a;
@@ -2381,6 +2515,8 @@ class Logger {
2381
2515
  /**
2382
2516
  * Represents whether or not emojis should be used as the log level
2383
2517
  * indicator in the logs.
2518
+ *
2519
+ * @deprecated This property is deprecated and will be removed in a future version.
2384
2520
  */
2385
2521
  static get emojiLogLevelHeadingsEnabled() {
2386
2522
  return loggerEmojiHeadingsEnabledGet();
@@ -2501,7 +2637,7 @@ class Logger {
2501
2637
  // c.f. httpes://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation
2502
2638
  normalizedPath = `\\\\?\\${path}`;
2503
2639
  }
2504
- return mapFFIErrorsAsync(() => loggerTryExportToFileAsync(normalizedPath));
2640
+ return mapFFIErrorsAsync(() => loggerTryExportToFile(normalizedPath));
2505
2641
  }
2506
2642
  /**
2507
2643
  * Logs the message for the given `level`.
@@ -3568,11 +3704,16 @@ class CBOR {
3568
3704
  //
3569
3705
  // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3570
3706
  //
3571
- /** Represents a unique identifier for a {@link Document}. */
3707
+ /**
3708
+ * Represents a unique identifier for a {@link Document}.
3709
+ *
3710
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
3711
+ */
3572
3712
  class DocumentID {
3573
3713
  /**
3574
3714
  * Returns the value of the receiver, lazily decoded from its CBOR
3575
3715
  * representation if needed.
3716
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
3576
3717
  */
3577
3718
  get value() {
3578
3719
  let value = this['@ditto.value'];
@@ -3623,6 +3764,8 @@ class DocumentID {
3623
3764
  /**
3624
3765
  * Returns `true` if passed in `documentID` is equal to the receiver,
3625
3766
  * otherwise returns `false`.
3767
+ *
3768
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
3626
3769
  */
3627
3770
  equals(documentID) {
3628
3771
  const left = this['@ditto.cbor'];
@@ -3645,6 +3788,8 @@ class DocumentID {
3645
3788
  *
3646
3789
  * If you need a string representation to be used directly in a query,
3647
3790
  * please use `toQueryCompatibleString()` instead.
3791
+ *
3792
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
3648
3793
  */
3649
3794
  toString() {
3650
3795
  return documentIDQueryCompatible(this['@ditto.cbor'], 'WithoutQuotes');
@@ -4376,6 +4521,9 @@ function checkForUnsupportedValues(jsObj) {
4376
4521
  * - `incremented`
4377
4522
  *
4378
4523
  * Not available in React Native environments.
4524
+ *
4525
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
4526
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
4379
4527
  */
4380
4528
  class UpdateResult {
4381
4529
  // ----------------------------------------------------------- Internal ------
@@ -4680,16 +4828,19 @@ class KeyPath {
4680
4828
  * method of {@link Document}.
4681
4829
  *
4682
4830
  * Not available in React Native environments.
4831
+ *
4832
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
4833
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
4683
4834
  */
4684
4835
  class DocumentPath {
4685
4836
  /**
4686
- * Returns a new document path instance with the passed in key-path or
4687
- * index appended.
4837
+ * Returns a new document path instance with the passed in key-path or index
4838
+ * appended.
4688
4839
  *
4689
4840
  * A key-path can be a single property name or multiple property names
4690
- * separated by a dot. Indexes can also be specified as part of the key
4691
- * path using the square bracket syntax. The empty string returns a document
4692
- * path representing the same portion of the document as the receiver. If a
4841
+ * separated by a dot. Indexes can also be specified as part of the key path
4842
+ * using the square bracket syntax. The empty string returns a document path
4843
+ * representing the same portion of the document as the receiver. If a
4693
4844
  * key-path starts with a property name and is prefixed by a dot, the dot is
4694
4845
  * ignored.
4695
4846
  *
@@ -4702,6 +4853,8 @@ class DocumentPath {
4702
4853
  * - `documentPath.at('.mileage')`
4703
4854
  *
4704
4855
  * @throws {Error} when called in a React Native environment.
4856
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
4857
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4705
4858
  */
4706
4859
  at(keyPathOrIndex) {
4707
4860
  if (typeof keyPathOrIndex === 'string') {
@@ -4727,6 +4880,8 @@ class DocumentPath {
4727
4880
  * returns the corresponding object or value.
4728
4881
  *
4729
4882
  * @throws {Error} when called in a React Native environment.
4883
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
4884
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4730
4885
  */
4731
4886
  get value() {
4732
4887
  return this.underlyingValueForPathType('Any');
@@ -4736,6 +4891,8 @@ class DocumentPath {
4736
4891
  * {@link Counter} if possible, otherwise returns `null`.
4737
4892
  *
4738
4893
  * @throws {Error} when called in a React Native environment.
4894
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
4895
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4739
4896
  */
4740
4897
  get counter() {
4741
4898
  const underlyingValue = this.underlyingValueForPathType('Counter');
@@ -4748,6 +4905,8 @@ class DocumentPath {
4748
4905
  * {@link Register} if possible, otherwise returns `null`.
4749
4906
  *
4750
4907
  * @throws {Error} when called in a React Native environment.
4908
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
4909
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4751
4910
  */
4752
4911
  get register() {
4753
4912
  const underlyingValue = this.underlyingValueForPathType('Register');
@@ -4760,6 +4919,8 @@ class DocumentPath {
4760
4919
  * {@link AttachmentToken} if possible, otherwise returns `null`.
4761
4920
  *
4762
4921
  * @throws {Error} when called in a React Native environment.
4922
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
4923
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4763
4924
  */
4764
4925
  get attachmentToken() {
4765
4926
  const underlyingValue = this.underlyingValueForPathType('Attachment');
@@ -4791,6 +4952,9 @@ class DocumentPath {
4791
4952
  * {@link MutableDocument.at | at()} method of {@link MutableDocument}.
4792
4953
  *
4793
4954
  * Not available in React Native environments.
4955
+ *
4956
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
4957
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
4794
4958
  */
4795
4959
  class MutableDocumentPath {
4796
4960
  /**
@@ -4798,8 +4962,8 @@ class MutableDocumentPath {
4798
4962
  * index appended.
4799
4963
  *
4800
4964
  * A key-path can be a single property name or multiple property names
4801
- * separated by a dot. Indexes can also be specified as part of the key
4802
- * path using square brackets syntax. The empty string returns a document path
4965
+ * separated by a dot. Indexes can also be specified as part of the key path
4966
+ * using square brackets syntax. The empty string returns a document path
4803
4967
  * representing the same portion of the document as the receiver. If a key
4804
4968
  * path starts with a property name and is prefixed by a dot, the dot is
4805
4969
  * ignored.
@@ -4813,6 +4977,8 @@ class MutableDocumentPath {
4813
4977
  * - `mutableDocumentPath.at('.mileage')`
4814
4978
  *
4815
4979
  * @throws {Error} when called in a React Native environment.
4980
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
4981
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4816
4982
  */
4817
4983
  at(keyPathOrIndex) {
4818
4984
  if (typeof keyPathOrIndex === 'string') {
@@ -4838,6 +5004,8 @@ class MutableDocumentPath {
4838
5004
  * returns the corresponding object or value.
4839
5005
  *
4840
5006
  * @throws {Error} when called in a React Native environment.
5007
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5008
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4841
5009
  */
4842
5010
  get value() {
4843
5011
  return this.underlyingValueForPathType('Any');
@@ -4847,6 +5015,8 @@ class MutableDocumentPath {
4847
5015
  * {@link MutableCounter} if possible, otherwise returns `null`.
4848
5016
  *
4849
5017
  * @throws {Error} when called in a React Native environment.
5018
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5019
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4850
5020
  */
4851
5021
  get counter() {
4852
5022
  const underlyingValue = this.underlyingValueForPathType('Counter');
@@ -4859,6 +5029,8 @@ class MutableDocumentPath {
4859
5029
  * {@link MutableRegister} if possible, otherwise returns `null`.
4860
5030
  *
4861
5031
  * @throws {Error} when called in a React Native environment.
5032
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5033
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4862
5034
  */
4863
5035
  get register() {
4864
5036
  const underlyingValue = this.underlyingValueForPathType('Register');
@@ -4871,6 +5043,8 @@ class MutableDocumentPath {
4871
5043
  * {@link AttachmentToken} if possible, otherwise returns `null`.
4872
5044
  *
4873
5045
  * @throws {Error} when called in a React Native environment.
5046
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5047
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4874
5048
  */
4875
5049
  get attachmentToken() {
4876
5050
  const underlyingValue = this.underlyingValueForPathType('Attachment');
@@ -4887,6 +5061,8 @@ class MutableDocumentPath {
4887
5061
  * value is `false`.
4888
5062
  *
4889
5063
  * @throws {Error} when called in a React Native environment.
5064
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5065
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4890
5066
  */
4891
5067
  set(value, isDefault) {
4892
5068
  return this['@ditto.set'](value, isDefault);
@@ -4895,6 +5071,8 @@ class MutableDocumentPath {
4895
5071
  * Removes a value at the document's key-path defined by the receiver.
4896
5072
  *
4897
5073
  * @throws {Error} when called in a React Native environment.
5074
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5075
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4898
5076
  */
4899
5077
  remove() {
4900
5078
  return this['@ditto.remove']();
@@ -4967,8 +5145,8 @@ class MutableDocumentPath {
4967
5145
  }
4968
5146
  /** @private */
4969
5147
  recordUpdateResult(updateResult) {
4970
- // OPTIMIZE: not sure how much of a performance hit this
4971
- // clone-modify-freeze dance implies. Investigate and fix.
5148
+ // OPTIMIZE: not sure how much of a performance hit this clone-modify-freeze
5149
+ // dance implies. Investigate and fix.
4972
5150
  const updateResults = this.mutableDocument['@ditto.updateResults'].slice();
4973
5151
  updateResults.push(updateResult);
4974
5152
  Object.freeze(updateResults);
@@ -4987,12 +5165,18 @@ const CUSTOM_INSPECT_SYMBOL$1 = Symbol.for('nodejs.util.inspect.custom');
4987
5165
  * A document belonging to a {@link Collection} with an inner value.
4988
5166
  *
4989
5167
  * Not available in React Native environments.
5168
+ *
5169
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
5170
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
4990
5171
  */
4991
5172
  class Document {
4992
5173
  /**
4993
5174
  * Returns a hash that represents the passed in document(s).
4994
5175
  *
4995
5176
  * @throws {Error} when called in a React Native environment.
5177
+ *
5178
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5179
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
4996
5180
  */
4997
5181
  static hash(documentOrMany) {
4998
5182
  const documents = documentsFrom(documentOrMany);
@@ -5004,6 +5188,9 @@ class Document {
5004
5188
  * represents the passed in document(s).
5005
5189
  *
5006
5190
  * @throws {Error} when called in a React Native environment.
5191
+ *
5192
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5193
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5007
5194
  */
5008
5195
  static hashMnemonic(documentOrMany) {
5009
5196
  const documents = documentsFrom(documentOrMany);
@@ -5014,6 +5201,8 @@ class Document {
5014
5201
  * Returns the document ID.
5015
5202
  *
5016
5203
  * @throws {Error} when called in a React Native environment.
5204
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5205
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5017
5206
  */
5018
5207
  get id() {
5019
5208
  let id = this['@ditto.id'];
@@ -5029,6 +5218,8 @@ class Document {
5029
5218
  * Returns the document path at the root of the document.
5030
5219
  *
5031
5220
  * @throws {Error} when called in a React Native environment.
5221
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5222
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5032
5223
  */
5033
5224
  get path() {
5034
5225
  return new DocumentPath(this, '', false);
@@ -5039,6 +5230,8 @@ class Document {
5039
5230
  * again.
5040
5231
  *
5041
5232
  * @throws {Error} when called in a React Native environment.
5233
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5234
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5042
5235
  */
5043
5236
  get value() {
5044
5237
  let value = this['@ditto.value'];
@@ -5052,6 +5245,8 @@ class Document {
5052
5245
  * Convenience method, same as calling `path.at()`.
5053
5246
  *
5054
5247
  * @throws {Error} when called in a React Native environment.
5248
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5249
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5055
5250
  */
5056
5251
  at(keyPathOrIndex) {
5057
5252
  return this.path.at(keyPathOrIndex);
@@ -5089,12 +5284,12 @@ class Document {
5089
5284
  }
5090
5285
  // -----------------------------------------------------------------------------
5091
5286
  // REFACTOR: adapt the mutable document proxying to the way it is done for
5092
- // Document, i.e. only use the proxy to dispatch and delegate to actual
5093
- // methods on the corresponding classes. The way it is right now is that
5094
- // most of the code of this code is duplicated within the MutableDocument,
5095
- // the MutableDocumentPath classes and the proxy implementation. Also make
5096
- // sure to proxy the mutable document right within its constructor. Same
5097
- // for mutable and immutable document path.
5287
+ // Document, i.e. only use the proxy to dispatch and delegate to actual methods
5288
+ // on the corresponding classes. The way it is right now is that most of the
5289
+ // code of this code is duplicated within the MutableDocument, the
5290
+ // MutableDocumentPath classes and the proxy implementation. Also make sure to
5291
+ // proxy the mutable document right within its constructor. Same for mutable and
5292
+ // immutable document path.
5098
5293
  /**
5099
5294
  * A representation of a {@link Document} that can be mutated via
5100
5295
  * {@link MutableDocumentPath}. You don't create or interact with a
@@ -5103,12 +5298,17 @@ class Document {
5103
5298
  * {@link PendingIDSpecificOperation.update | PendingIDSpecificOperation}.
5104
5299
  *
5105
5300
  * Not available in React Native environments.
5301
+ *
5302
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
5303
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
5106
5304
  */
5107
5305
  class MutableDocument {
5108
5306
  /**
5109
5307
  * Returns the ID of the document.
5110
5308
  *
5111
5309
  * @throws {Error} when called in a React Native environment.
5310
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5311
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5112
5312
  */
5113
5313
  get id() {
5114
5314
  let id = this['@ditto.id'];
@@ -5124,6 +5324,8 @@ class MutableDocument {
5124
5324
  * Returns the document path at the root of the document.
5125
5325
  *
5126
5326
  * @throws {Error} when called in a React Native environment.
5327
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5328
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5127
5329
  */
5128
5330
  get path() {
5129
5331
  return new MutableDocumentPath(this, '', false);
@@ -5132,6 +5334,8 @@ class MutableDocument {
5132
5334
  * Convenience property, same as `path.value`.
5133
5335
  *
5134
5336
  * @throws {Error} when called in a React Native environment.
5337
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5338
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5135
5339
  */
5136
5340
  get value() {
5137
5341
  return this.path.value;
@@ -5140,6 +5344,8 @@ class MutableDocument {
5140
5344
  * Convenience method, same as calling `path.at()`.
5141
5345
  *
5142
5346
  * @throws {Error} when called in a React Native environment.
5347
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5348
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5143
5349
  */
5144
5350
  at(keyPathOrIndex) {
5145
5351
  return this.path.at(keyPathOrIndex);
@@ -5160,8 +5366,8 @@ class MutableDocument {
5160
5366
  return `${this.constructor.name}(${this.id})`;
5161
5367
  }
5162
5368
  /**
5163
- * Defines a custom inspect function for Node.js that will be used when
5164
- * the object is inspected with console.log() or util.inspect().
5369
+ * Defines a custom inspect function for Node.js that will be used when the
5370
+ * object is inspected with console.log() or util.inspect().
5165
5371
  *
5166
5372
  * @internal */
5167
5373
  [CUSTOM_INSPECT_SYMBOL$1](_depth, _inspectOptions, inspect) {
@@ -5190,15 +5396,22 @@ function documentsFrom(documentOrMany) {
5190
5396
  /**
5191
5397
  * Maps a {@link DocumentID} to an array of
5192
5398
  * {@link UpdateResult | update results}. This is the data structure you get
5193
- * when {@link PendingCursorOperation.update | updating} a set of documents
5194
- * with detailed info about the performed updates.
5399
+ * when {@link PendingCursorOperation.update | updating} a set of documents with
5400
+ * detailed info about the performed updates.
5195
5401
  *
5196
5402
  * Not available in React Native environments.
5403
+ *
5404
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
5405
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
5197
5406
  */
5198
5407
  class UpdateResultsMap {
5199
5408
  /**
5200
5409
  * Returns an array of {@link UpdateResult | update results} associated with
5201
5410
  * the `documentID` or undefined if not found.
5411
+ *
5412
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5413
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5414
+
5202
5415
  */
5203
5416
  get(documentIDOrValue) {
5204
5417
  const documentID = documentIDOrValue instanceof DocumentID
@@ -5210,6 +5423,10 @@ class UpdateResultsMap {
5210
5423
  /**
5211
5424
  * Returns all contained keys, i.e. {@link DocumentID | document IDs}
5212
5425
  * contained in this map.
5426
+ *
5427
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5428
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5429
+
5213
5430
  */
5214
5431
  keys() {
5215
5432
  return this.documentIDs.slice();
@@ -5246,14 +5463,17 @@ class UpdateResultsMap {
5246
5463
  //
5247
5464
  /**
5248
5465
  * Not available in React Native environments.
5466
+ *
5467
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5468
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5249
5469
  */
5250
5470
  class BasePendingCursorOperation {
5251
5471
  /**
5252
5472
  * Sorts the documents that match the query provided in the preceding
5253
5473
  * `find`-like function call.
5254
5474
  *
5255
- * Documents that are missing the field to sort by will appear at
5256
- * the beginning of the results when sorting in ascending order.
5475
+ * Documents that are missing the field to sort by will appear at the
5476
+ * beginning of the results when sorting in ascending order.
5257
5477
  *
5258
5478
  * @param query Name or path of the field to sort by.
5259
5479
  *
@@ -5263,6 +5483,8 @@ class BasePendingCursorOperation {
5263
5483
  * @throws {Error} when called in a React Native environment.
5264
5484
  * @return A cursor that you can chain further function calls and then either
5265
5485
  * get the matching documents immediately or get updates about them over time.
5486
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5487
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5266
5488
  */
5267
5489
  sort(query, direction = 'ascending') {
5268
5490
  this.orderBys.push({
@@ -5286,6 +5508,8 @@ class BasePendingCursorOperation {
5286
5508
  * @throws {Error} when called in a React Native environment.
5287
5509
  * @return A cursor that you can chain further function calls and then either
5288
5510
  * get the matching documents immediately or get updates about them over time.
5511
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5512
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5289
5513
  */
5290
5514
  offset(offset) {
5291
5515
  // REFACTOR: factor out parameter validation.
@@ -5313,6 +5537,8 @@ class BasePendingCursorOperation {
5313
5537
  * @throws {Error} when called in a React Native environment.
5314
5538
  * @return A cursor that you can chain further function calls and then either
5315
5539
  * get the matching documents immediately or get updates about them over time.
5540
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5541
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5316
5542
  */
5317
5543
  limit(limit) {
5318
5544
  // REFACTOR: factor out parameter validation.
@@ -5339,6 +5565,7 @@ class BasePendingCursorOperation {
5339
5565
  * @throws {Error} when called in a React Native environment.
5340
5566
  * @returns An array promise containing {@link Document | documents} matching
5341
5567
  * the query generated by the preceding function chaining.
5568
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
5342
5569
  */
5343
5570
  async exec() {
5344
5571
  const ditto = this.collection.store.ditto;
@@ -5453,6 +5680,8 @@ class BasePendingCursorOperation {
5453
5680
  * Live queries and subscriptions are only available outside of a transaction.
5454
5681
  *
5455
5682
  * Not available in React Native environments.
5683
+ *
5684
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
5456
5685
  */
5457
5686
  class BasePendingIDSpecificOperation {
5458
5687
  /**
@@ -5462,6 +5691,9 @@ class BasePendingIDSpecificOperation {
5462
5691
  * @returns The {@link Document} promise with the ID provided in the
5463
5692
  * {@link Collection.findByID | findByID()} call or `undefined` if the document was
5464
5693
  * not found.
5694
+ *
5695
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
5696
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
5465
5697
  */
5466
5698
  async exec() {
5467
5699
  const ditto = this.collection.store.ditto;
@@ -5793,23 +6025,67 @@ class ObserverManager {
5793
6025
  //
5794
6026
  // Copyright © 2021 DittoLive Incorporated. All rights reserved.
5795
6027
  //
5796
- const AuthenticationStatus = {
5797
- fromFFI(ffiAuthenticationStatus) {
5798
- const isAuthenticated = authenticationStatusIsAuthenticated(ffiAuthenticationStatus);
5799
- const userID = authenticationStatusUserID(ffiAuthenticationStatus);
5800
- authenticationStatusFree(ffiAuthenticationStatus);
5801
- return {
5802
- isAuthenticated,
5803
- userID,
5804
- };
5805
- },
5806
- };
6028
+ function authenticationStatusFromFFI(ffiAuthenticationStatus) {
6029
+ const isAuthenticated = authenticationStatusIsAuthenticated(ffiAuthenticationStatus);
6030
+ const userID = authenticationStatusUserID(ffiAuthenticationStatus);
6031
+ authenticationStatusFree(ffiAuthenticationStatus);
6032
+ return {
6033
+ isAuthenticated,
6034
+ userID,
6035
+ };
6036
+ }
5807
6037
  // -----------------------------------------------------------------------------
5808
6038
  /**
5809
6039
  * Log in to a remote authentication service, using an
5810
6040
  * `OnlineWithAuthentication` or an `Online` identity.
5811
6041
  */
5812
6042
  class Authenticator {
6043
+ /**
6044
+ * The built-in development authentication provider to be used together with
6045
+ * development authentication tokens.
6046
+ *
6047
+ * This API is in **preview** as part of the new configuration APIs that replace
6048
+ * the legacy {@link Identity}-based initialization.
6049
+ *
6050
+ * @see {@link Authenticator.login | Authenticator.login()} for more information
6051
+ * about the `provider` parameter.
6052
+ */
6053
+ static get DEVELOPMENT_PROVIDER() {
6054
+ return DITTO_DEVELOPMENT_PROVIDER();
6055
+ }
6056
+ /**
6057
+ * The handler that will be called when authentication for this Ditto instance
6058
+ * is about to expire.
6059
+ *
6060
+ * This API is in **preview** and provides a replacement for the phased out
6061
+ * {@link AuthenticationHandler} interface.
6062
+ *
6063
+ * **Important:** If the Ditto instance is configured with a
6064
+ * {@link DittoConfigConnectServer} this property **must** be set and the
6065
+ * handler **must** properly authenticate when called.
6066
+ *
6067
+ * @see {@link setExpirationHandler}
6068
+ */
6069
+ get expirationHandler() {
6070
+ throw new Error(`Authenticator.expirationHandler is only available when using a ` +
6071
+ `DittoConfig with a ConfigConnectServer.`);
6072
+ }
6073
+ /**
6074
+ * Sets the handler that will be called when authentication for this Ditto
6075
+ * instance is about to expire.
6076
+ *
6077
+ * This API is in **preview** and provides a replacement for the phased out
6078
+ * {@link AuthenticationHandler} interface.
6079
+ *
6080
+ * Assign a handler function to be notified before authentication expires,
6081
+ * allowing you to login or perform other necessary actions.
6082
+ *
6083
+ * @see {@link expirationHandler}
6084
+ */
6085
+ async setExpirationHandler(handler) {
6086
+ throw new Error(`Authenticator.expirationHandler is only available when using a ` +
6087
+ `DittoConfig with a ConfigConnectServer.`);
6088
+ }
5813
6089
  /**
5814
6090
  Returns the current authentication status.
5815
6091
  */
@@ -5821,15 +6097,16 @@ class Authenticator {
5821
6097
  *
5822
6098
  * Returns a promise that resolves to a `LoginResult` object. When the login
5823
6099
  * attempt is successful, the `error` property of the response will be `null`,
5824
- * otherwise it will contain a `DittoError` object with details about the
5825
- * error.
6100
+ * otherwise it will contain a {@link DittoError} object with details about
6101
+ * the error.
5826
6102
  *
5827
6103
  * If the authentication service provides additional client info, it will be
5828
6104
  * returned in the `clientInfo` property of the response, whether the login
5829
6105
  * attempt was successful or not.
5830
6106
  *
5831
6107
  * @param token The authentication token required to log in.
5832
- * @param provider The name of the authentication provider.
6108
+ * @param provider The name of the authentication provider. Use
6109
+ * {@link Authenticator.DEVELOPMENT_PROVIDER} with development tokens.
5833
6110
  * @throws {@link DittoError} `authentication/failed-to-authenticate` if the
5834
6111
  * Ditto instance is closed.
5835
6112
  * @returns A promise that resolves to a `LoginResult` object.
@@ -5856,6 +6133,8 @@ class Authenticator {
5856
6133
  * @param username the username component of the credentials used for log in.
5857
6134
  * @param password the password component of the credentials used for log in.
5858
6135
  * @param provider the name of the authentication provider.
6136
+ * @deprecated this method is deprecated and will be removed in a future
6137
+ * version.
5859
6138
  */
5860
6139
  loginWithUsernameAndPassword(username, password, provider) {
5861
6140
  throw new Error(`Authenticator.loginWithUsernameAndPassword() is abstract and must be implemented by subclasses.`);
@@ -5958,13 +6237,28 @@ class OnlineAuthenticator extends Authenticator {
5958
6237
  Logger.info('Authenticator is null, ignoring authentication status change');
5959
6238
  return;
5960
6239
  }
5961
- const authenticationStatus = AuthenticationStatus.fromFFI(ffiAuthenticationStatus);
6240
+ const authenticationStatus = authenticationStatusFromFFI(ffiAuthenticationStatus);
5962
6241
  authenticator.authenticationStatusUpdated(authenticationStatus);
5963
6242
  });
5964
6243
  });
5965
6244
  this.updateAndNotify(false);
5966
6245
  }
5967
6246
  '@ditto.authenticationExpiring'(secondsRemaining) {
6247
+ const ditto = this.ditto.deref();
6248
+ const isLegacyIdentity = ditto !== null && ditto.configOrParameters.isParameters;
6249
+ // Handle new-style expiration handler first
6250
+ if (!isLegacyIdentity) {
6251
+ void ditto.deferCloseAsync(async () => {
6252
+ try {
6253
+ await this.expirationHandler(ditto, secondsRemaining);
6254
+ }
6255
+ catch (error) {
6256
+ Logger.error(`Authentication expiration handler failed: ${error.message}`);
6257
+ }
6258
+ });
6259
+ return;
6260
+ }
6261
+ // Fallback to legacy authentication handler
5968
6262
  const authenticationHandler = this.authenticationHandler;
5969
6263
  if (secondsRemaining > 0)
5970
6264
  authenticationHandler.authenticationExpiringSoon(this, secondsRemaining);
@@ -6009,6 +6303,171 @@ class OnlineAuthenticator extends Authenticator {
6009
6303
  }
6010
6304
  }
6011
6305
  // -----------------------------------------------------------------------------
6306
+ /**
6307
+ * OnlineAuthenticatorV2 exclusively supports the new DittoConfig-based API,
6308
+ *
6309
+ * @internal
6310
+ */
6311
+ class OnlineAuthenticatorV2 extends Authenticator {
6312
+ get expirationHandler() {
6313
+ const ditto = this.ditto.deref();
6314
+ if (!ditto || ditto.isClosed) {
6315
+ Logger.error('Ditto instance is closed, cannot get authentication expiration handler.');
6316
+ return null;
6317
+ }
6318
+ return this._expirationHandler;
6319
+ }
6320
+ async setExpirationHandler(handler) {
6321
+ const ditto = this.ditto.deref();
6322
+ if (!ditto || ditto.isClosed) {
6323
+ Logger.error('Ditto instance is closed, cannot set authentication expiration handler.');
6324
+ }
6325
+ this._expirationHandler = handler;
6326
+ // Register the expiration handler with the FFI layer.
6327
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6328
+ try {
6329
+ const providerPointer = dittoAuthClientMakeLoginProvider(this.makeFFFIAuthenticationExpirationHandler());
6330
+ await dittoAuthSetLoginProvider(dittoHandle.deref(), providerPointer);
6331
+ }
6332
+ catch (error) {
6333
+ Logger.error(`Failed to set authentication expiration handler: ${error.message}`);
6334
+ }
6335
+ });
6336
+ }
6337
+ constructor(keepAlive, ditto) {
6338
+ super(keepAlive);
6339
+ // -----------------------------------------------------------------------------
6340
+ /** @internal */
6341
+ this._expirationHandler = null;
6342
+ if (ditto.configOrParameters.isParameters) {
6343
+ throw new Error('OnlineAuthenticatorV2 can only be used with the new DittoConfig-based API.');
6344
+ }
6345
+ this.loginSupported = ditto.config.connect.type === 'server';
6346
+ this.ditto = new WeakRef(ditto);
6347
+ // Set up authentication status handler like OnlineAuthenticator does
6348
+ const weakThis = new WeakRef(this);
6349
+ ditto.deferClose((dittoHandle) => {
6350
+ dittoSetAuthenticationStatusHandler(dittoHandle.deref(), function (ffiAuthenticationStatus) {
6351
+ const authenticator = weakThis.deref();
6352
+ if (authenticator == null) {
6353
+ Logger.info('Authenticator is null, ignoring authentication status change');
6354
+ return;
6355
+ }
6356
+ const authenticationStatus = authenticationStatusFromFFI(ffiAuthenticationStatus);
6357
+ authenticator.authenticationStatusUpdated(authenticationStatus);
6358
+ });
6359
+ });
6360
+ // Initialize status by querying current state
6361
+ this.updateAndNotify(false);
6362
+ }
6363
+ async login(token, provider) {
6364
+ const ditto = this.ditto.deref();
6365
+ if (!ditto || ditto.isClosed) {
6366
+ throw new DittoError('authentication/failed-to-authenticate', 'Ditto instance is closed');
6367
+ }
6368
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6369
+ const { clientInfo, error: ffiError } = await dittoAuthClientLoginWithTokenAndFeedback(dittoHandle.deref(), token, provider);
6370
+ const error = ffiError != null
6371
+ ? DittoError.fromFFIError(ffiError, 'authentication/failed-to-authenticate')
6372
+ : null;
6373
+ return { clientInfo, error };
6374
+ });
6375
+ }
6376
+ async loginWithToken(token, provider) {
6377
+ const ditto = this.ditto.deref();
6378
+ if (!ditto || ditto.isClosed)
6379
+ return;
6380
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6381
+ await dittoAuthClientLoginWithToken(dittoHandle.deref(), token, provider);
6382
+ });
6383
+ }
6384
+ async loginWithUsernameAndPassword(username, password, provider) {
6385
+ const ditto = this.ditto.deref();
6386
+ if (!ditto || ditto.isClosed)
6387
+ return;
6388
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6389
+ await dittoAuthClientLoginWithUsernameAndPassword(dittoHandle.deref(), username, password, provider);
6390
+ });
6391
+ }
6392
+ async logout(cleanupFn) {
6393
+ const ditto = this.ditto.deref();
6394
+ if (!ditto || ditto.isClosed)
6395
+ return;
6396
+ return ditto.deferCloseAsync(async (dittoHandle) => {
6397
+ await dittoAuthClientLogout(dittoHandle.deref());
6398
+ ditto.stopSync();
6399
+ cleanupFn === null || cleanupFn === void 0 ? void 0 : cleanupFn(ditto);
6400
+ });
6401
+ }
6402
+ authenticationStatusUpdated(authenticationStatus) {
6403
+ const previousStatus = this.status;
6404
+ this._status = authenticationStatus;
6405
+ const sameStatus = !!previousStatus.isAuthenticated ===
6406
+ !!authenticationStatus.isAuthenticated &&
6407
+ previousStatus.userID === authenticationStatus.userID;
6408
+ if (!sameStatus)
6409
+ this.observerManager.notify(authenticationStatus);
6410
+ }
6411
+ updateAndNotify(shouldNotify) {
6412
+ const ditto = this.ditto.deref();
6413
+ if (!ditto) {
6414
+ Logger.debug('Unable to update auth status and notify, related Ditto object does not exist anymore.');
6415
+ return;
6416
+ }
6417
+ const dittoHandle = Bridge.ditto.handleFor(ditto);
6418
+ const dittoPointer = dittoHandle.derefOrNull();
6419
+ if (!dittoPointer) {
6420
+ Logger.debug('Unable to update auth status and notify, related Ditto object does not exist anymore.');
6421
+ return;
6422
+ }
6423
+ const isAuthenticated = dittoAuthClientIsWebValid(dittoPointer);
6424
+ const userID = dittoAuthClientUserID(dittoPointer);
6425
+ const status = { isAuthenticated, userID };
6426
+ if (shouldNotify) {
6427
+ // We don't need to set the `_status` property here because it's done in
6428
+ // `authenticationStatusUpdated`.
6429
+ this.authenticationStatusUpdated(status);
6430
+ }
6431
+ else {
6432
+ this._status = status;
6433
+ }
6434
+ }
6435
+ makeFFFIAuthenticationExpirationHandler() {
6436
+ const weakAuthenticator = new WeakRef(this);
6437
+ return (secondsUntilExpiration) => {
6438
+ const authenticator = weakAuthenticator.deref();
6439
+ if (!authenticator) {
6440
+ // If owning authenticator has gone out of scope, we sure don't need to
6441
+ // notify anyone about the expiration.
6442
+ return;
6443
+ }
6444
+ const ditto = authenticator.ditto.deref();
6445
+ if (!ditto) {
6446
+ // Same if Ditto went out of scope.
6447
+ return;
6448
+ }
6449
+ if (authenticator.expirationHandler != null) {
6450
+ // This is being called from FFI so no point in awaiting the
6451
+ // deferCloseAsync promise.
6452
+ void ditto.deferCloseAsync(async () => {
6453
+ try {
6454
+ await authenticator.expirationHandler(ditto, secondsUntilExpiration);
6455
+ }
6456
+ catch (error) {
6457
+ Logger.error('The authentication handler set via `ditto.auth.setExpirationHandler()` ' +
6458
+ `failed: ${error.message}`);
6459
+ }
6460
+ });
6461
+ }
6462
+ else {
6463
+ Logger.error('Authentication required but no expiration handler is set. ' +
6464
+ 'Please set an expiration handler using ' +
6465
+ '`ditto.auth.setExpirationHandler()`.');
6466
+ }
6467
+ };
6468
+ }
6469
+ }
6470
+ // -----------------------------------------------------------------------------
6012
6471
  /** @internal */
6013
6472
  class NotAvailableAuthenticator extends Authenticator {
6014
6473
  async login(token, provider) {
@@ -6037,27 +6496,260 @@ const IdentityTypesRequiringOfflineLicenseToken = [
6037
6496
  'sharedKey',
6038
6497
  'offlinePlayground',
6039
6498
  ];
6499
+ /**
6500
+ * Registers the given identity with Ditto FFI and returns a pointer to the
6501
+ * identity configuration.
6502
+ *
6503
+ * @internal
6504
+ * @deprecated
6505
+ */
6506
+ function makeIdentityConfig(identity) {
6507
+ var _a, _b, _c;
6508
+ if (identity.type === 'offlinePlayground') {
6509
+ return dittoIdentityConfigMakeOfflinePlayground(identity.appID, (_a = identity.siteID) !== null && _a !== void 0 ? _a : 0);
6510
+ }
6511
+ if (identity.type === 'manual') {
6512
+ return dittoIdentityConfigMakeManual(identity.certificate);
6513
+ }
6514
+ if (identity.type === 'sharedKey') {
6515
+ return dittoIdentityConfigMakeSharedKey(identity.appID, identity.sharedKey, identity.siteID);
6516
+ }
6517
+ if (identity.type === 'onlinePlayground') {
6518
+ const authURL = (_b = identity.customAuthURL) !== null && _b !== void 0 ? _b : defaultAuthURL(identity.appID);
6519
+ return dittoIdentityConfigMakeOnlinePlayground(identity.appID, identity.token, authURL);
6520
+ }
6521
+ if (identity.type === 'onlineWithAuthentication') {
6522
+ const authURL = (_c = identity.customAuthURL) !== null && _c !== void 0 ? _c : defaultAuthURL(identity.appID);
6523
+ return dittoIdentityConfigMakeOnlineWithAuthentication(identity.appID, authURL);
6524
+ }
6525
+ }
6040
6526
 
6041
6527
  //
6042
- // Copyright © 2021 DittoLive Incorporated. All rights reserved.
6528
+ // Copyright © 2025 DittoLive Incorporated. All rights reserved.
6043
6529
  //
6044
6530
  /**
6045
- * Restore a `TransportConfig` from its serializable representation.
6531
+ * The default identity that is used when no identity is specified while
6532
+ * creating a Ditto instance.
6046
6533
  *
6047
6534
  * @internal
6535
+ * @deprecated This is used for backward compatibility with the legacy
6536
+ * {@link DittoConfig} constructor.
6048
6537
  */
6049
- function transportConfigFromDeserializable(serialized) {
6050
- const peerToPeerJSON = serialized['peer_to_peer'];
6051
- const bluetoothLEJSON = peerToPeerJSON['bluetooth_le'];
6052
- const bluetoothLEEnabled = bluetoothLEJSON['enabled'];
6053
- const awdlJSON = peerToPeerJSON['awdl'];
6054
- const awdlEnabled = awdlJSON['enabled'];
6055
- const lanJSON = peerToPeerJSON['lan'];
6056
- const lanEnabled = lanJSON['enabled'];
6057
- const lanMdnsEnabled = lanJSON['mdns_enabled'];
6058
- const lanMulticastEnabled = lanJSON['multicast_enabled'];
6059
- const connectJSON = serialized['connect'];
6060
- const connectTcpServers = connectJSON['tcp_servers'];
6538
+ const DEFAULT_IDENTITY = {
6539
+ type: 'offlinePlayground',
6540
+ appID: '',
6541
+ };
6542
+ /**
6543
+ * A configuration object for initializing a {@link Ditto} instance.
6544
+ *
6545
+ * Encapsulates all the parameters required to configure a Ditto instance,
6546
+ * including identity, connectivity, and persistence.
6547
+ *
6548
+ * This API is in **preview** and will become the standard way to initialize
6549
+ * Ditto instances in v5, replacing the legacy {@link Identity}-based
6550
+ * initialization.
6551
+ */
6552
+ class DittoConfig {
6553
+ /**
6554
+ * The default database ID, used when no database ID is provided.
6555
+ *
6556
+ * @see {@link DittoConfig.databaseID | database_id} for more information about the
6557
+ * `databaseID` parameter.
6558
+ */
6559
+ static get DEFAULT_DATABASE_ID() {
6560
+ return DEFAULT_DATABASE_ID();
6561
+ }
6562
+ /**
6563
+ * Returns a default {@link DittoConfig} instance with standard settings.
6564
+ *
6565
+ * This is useful as a starting point or for quickly creating a basic
6566
+ * configuration, but for production use you should customize the
6567
+ * configuration as needed.
6568
+ */
6569
+ static get default() {
6570
+ const configCBOR = dittoConfigDefault();
6571
+ const ffiConfig = CBOR.decode(configCBOR);
6572
+ return fromFFICBORData(ffiConfig);
6573
+ }
6574
+ /**
6575
+ * Initializes a new {@link DittoConfig} instance with the new API.
6576
+ */
6577
+ constructor(id, connect, persistenceDirectory) {
6578
+ this._isFrozen = false;
6579
+ // The logger is initialized here to ensure that users have a chance to set
6580
+ // a minimum log level before the logger starts emitting logs.
6581
+ loggerInit();
6582
+ // New API: DittoConfig(id, connect, persistenceDirectory?)
6583
+ if (typeof id !== 'string')
6584
+ throw new TypeError('Expected id to be a string, but got: ' + typeof id);
6585
+ if (typeof connect !== 'object') {
6586
+ throw new TypeError(`Expected connect to be an object, but got: ` + typeof connect);
6587
+ }
6588
+ if (persistenceDirectory != null &&
6589
+ typeof persistenceDirectory !== 'string') {
6590
+ throw new TypeError(`Expected persistenceDirectory to be undefined or a string, but got: ` +
6591
+ typeof persistenceDirectory);
6592
+ }
6593
+ this.databaseID = id;
6594
+ this.connect = connect;
6595
+ this.persistenceDirectory = persistenceDirectory;
6596
+ this.validate();
6597
+ }
6598
+ /**
6599
+ * Returns true if the receiver has been frozen using
6600
+ * {@link DittoConfig.freeze | freeze()}.
6601
+ */
6602
+ get isFrozen() {
6603
+ return this._isFrozen;
6604
+ }
6605
+ /**
6606
+ * Deep freezes the receiver such that it can't be modified anymore.
6607
+ *
6608
+ * Use {@link DittoConfig.copy | copy()} to create a copy of the receiver that
6609
+ * is not frozen.
6610
+ *
6611
+ * Warning: this does not freeze legacy
6612
+ * {@link AuthenticationHandler | authentication handlers} referenced by the
6613
+ * identity. Changes inside the authentication handlers will be reflected in the
6614
+ * frozen {@link DittoConfig}.
6615
+ *
6616
+ * @see {@link DittoConfig.isFrozen}
6617
+ */
6618
+ freeze() {
6619
+ if (this.isFrozen)
6620
+ return this;
6621
+ this._isFrozen = true;
6622
+ Object.freeze(this.connect);
6623
+ Object.freeze(this);
6624
+ return this;
6625
+ }
6626
+ /**
6627
+ * Returns a deep copy of the receiver.
6628
+ *
6629
+ * The copy is not frozen, so it's properties can be modified.
6630
+ *
6631
+ * Warning: This does not create copies of
6632
+ * {@link AuthenticationHandler | authentication handlers} referenced by the
6633
+ * identity. Changes inside the authentication handlers will be reflected in the
6634
+ * copy.
6635
+ */
6636
+ copy() {
6637
+ // New config structure
6638
+ const copy = new DittoConfig(this.databaseID, { ...this.connect }, this.persistenceDirectory);
6639
+ return copy;
6640
+ }
6641
+ /** @internal */
6642
+ toCBOR() {
6643
+ try {
6644
+ const ffiConfig = toFFICBORData(this);
6645
+ // Logger.info(
6646
+ // `Converting DittoConfig to CBOR: ${JSON.stringify(ffiConfig, null, 2)}`,
6647
+ // );
6648
+ return CBOR.encode(ffiConfig);
6649
+ }
6650
+ catch (error) {
6651
+ throw new DittoError('validation/invalid-ditto-config', `Failed to convert DittoConfig to CBOR: ${error.message}`);
6652
+ }
6653
+ }
6654
+ /**
6655
+ * Validates the config structure.
6656
+ *
6657
+ * Only covers type and presence validation as anything beyond that is handled
6658
+ * by core.
6659
+ */
6660
+ validate() {
6661
+ if (!this.databaseID) {
6662
+ throw new DittoError('validation/invalid-ditto-config', '`id` must be provided for DittoConfig.');
6663
+ }
6664
+ if (typeof this.databaseID !== 'string') {
6665
+ throw new DittoError('validation/invalid-ditto-config', `\`id\` must be of type string, but is of type '${typeof this.databaseID}': ${this.databaseID}`);
6666
+ }
6667
+ if (!this.connect) {
6668
+ throw new DittoError('validation/invalid-ditto-config', '`connect` must be provided for DittoConfig.');
6669
+ }
6670
+ if (typeof this.connect !== 'object') {
6671
+ throw new DittoError('validation/invalid-ditto-config', `\`connect\` must be an object, but is of type '${typeof this.connect}'.`);
6672
+ }
6673
+ }
6674
+ }
6675
+ /**
6676
+ * Converts a {@link DittoConfig} into a plain JS object that conforms to the
6677
+ * expected shape used in FFI.
6678
+ *
6679
+ * @internal
6680
+ */
6681
+ function toFFICBORData(config) {
6682
+ var _a;
6683
+ let connectFFI;
6684
+ if (config.connect.type === 'server') {
6685
+ connectFFI = {
6686
+ type: 'server',
6687
+ url: config.connect.url,
6688
+ };
6689
+ }
6690
+ else if (config.connect.type === 'smallPeersOnly') {
6691
+ connectFFI = {
6692
+ type: 'small_peers_only',
6693
+ };
6694
+ if (config.connect.privateKey)
6695
+ connectFFI.private_key = config.connect.privateKey;
6696
+ }
6697
+ else {
6698
+ throw new DittoError('validation/invalid-ditto-config', `Unsupported connect type: ${config.connect.type}`);
6699
+ }
6700
+ const ffiConfig = {
6701
+ database_id: config.databaseID,
6702
+ connect: connectFFI,
6703
+ persistence_directory: (_a = config.persistenceDirectory) !== null && _a !== void 0 ? _a : null, // MUST not be undefined
6704
+ experimental: {}, // Currently no experimental features in JS SDK
6705
+ };
6706
+ return ffiConfig;
6707
+ }
6708
+ /**
6709
+ * Converts a FFI {@link DittoConfig} into a {@link DittoConfig} instance.
6710
+ *
6711
+ * @internal
6712
+ */
6713
+ function fromFFICBORData(data) {
6714
+ let connect;
6715
+ if (data.connect.type === 'server') {
6716
+ connect = {
6717
+ type: 'server',
6718
+ url: data.connect.url,
6719
+ };
6720
+ }
6721
+ else {
6722
+ connect = {
6723
+ type: 'smallPeersOnly',
6724
+ };
6725
+ if (data.connect.private_key)
6726
+ connect.privateKey = data.connect.private_key;
6727
+ }
6728
+ return new DittoConfig(data.database_id, connect, data.persistence_directory);
6729
+ }
6730
+
6731
+ //
6732
+ // Copyright © 2021 DittoLive Incorporated. All rights reserved.
6733
+ //
6734
+ /**
6735
+ * Restore a `TransportConfig` from its serializable representation.
6736
+ *
6737
+ * @internal
6738
+ */
6739
+ function transportConfigFromDeserializable(serialized) {
6740
+ const peerToPeerJSON = serialized['peer_to_peer'];
6741
+ const bluetoothLEJSON = peerToPeerJSON['bluetooth_le'];
6742
+ const bluetoothLEEnabled = bluetoothLEJSON['enabled'];
6743
+ const awdlJSON = peerToPeerJSON['awdl'];
6744
+ const awdlEnabled = awdlJSON['enabled'];
6745
+ const lanJSON = peerToPeerJSON['lan'];
6746
+ const lanEnabled = lanJSON['enabled'];
6747
+ const lanMdnsEnabled = lanJSON['mdns_enabled'];
6748
+ const lanMulticastEnabled = lanJSON['multicast_enabled'];
6749
+ const wifiAwareJSON = peerToPeerJSON['wifi_aware'];
6750
+ const wifiAwareEnabled = wifiAwareJSON['enabled'];
6751
+ const connectJSON = serialized['connect'];
6752
+ const connectTcpServers = connectJSON['tcp_servers'];
6061
6753
  const connectWebsocketURLs = connectJSON['websocket_urls'];
6062
6754
  const connectRetryInterval = connectJSON['retry_interval'];
6063
6755
  const listenJSON = serialized['listen'];
@@ -6082,6 +6774,7 @@ function transportConfigFromDeserializable(serialized) {
6082
6774
  config.peerToPeer.lan.isEnabled = lanEnabled;
6083
6775
  config.peerToPeer.lan.isMdnsEnabled = lanMdnsEnabled;
6084
6776
  config.peerToPeer.lan.isMulticastEnabled = lanMulticastEnabled;
6777
+ config.peerToPeer.wifiAware.isEnabled = wifiAwareEnabled;
6085
6778
  config.connect.tcpServers = connectTcpServers;
6086
6779
  config.connect.websocketURLs = connectWebsocketURLs;
6087
6780
  config.connect.retryInterval = connectRetryInterval;
@@ -6120,6 +6813,9 @@ function transportConfigToSerializable(config) {
6120
6813
  awdl: {
6121
6814
  enabled: peerToPeer.awdl.isEnabled,
6122
6815
  },
6816
+ wifi_aware: {
6817
+ enabled: peerToPeer.wifiAware.isEnabled,
6818
+ },
6123
6819
  lan: {
6124
6820
  enabled: peerToPeer.lan.isEnabled,
6125
6821
  mdns_enabled: peerToPeer.lan.isMdnsEnabled,
@@ -6168,13 +6864,18 @@ const NO_PREFERRED_ROUTE_HINT = 0;
6168
6864
  * use to sync data.
6169
6865
  *
6170
6866
  * A Ditto object comes with a default transport configuration where all
6171
- * available peer-to-peer transports are enabled. You can customize this by
6172
- * copying that or initializing a new `TransportConfig`, adjusting its
6173
- * properties, and supplying it to `setTransportConfig()` on `Ditto`.
6867
+ * available transports are enabled (for example, regarding peer-to-peer transports,
6868
+ * Bluetooth LE and LAN on every platform, plus AWDL on Apple platforms or
6869
+ * Wi‑Fi Aware on Android). You can customize this by copying that or
6870
+ * initializing a new `TransportConfig`, adjusting its properties, and supplying
6871
+ * it to `setTransportConfig()` on `Ditto`.
6174
6872
  *
6175
6873
  * When you initialize a new `TransportConfig` instance, all transports are
6176
6874
  * disabled. You must enable each one explicitly.
6177
6875
  *
6876
+ * Platform‑supported transports can also be toggled in a single call with
6877
+ * {@link setAvailablePeerToPeerEnabled | setAvailablePeerToPeerEnabled()}.
6878
+ *
6178
6879
  * Peer-to-peer transports will automatically discover peers in the vicinity
6179
6880
  * and create connections without any configuration. These are configured via
6180
6881
  * the `peerToPeer` property. To turn each one on, set its `isEnabled` property
@@ -6201,6 +6902,7 @@ class TransportConfig {
6201
6902
  bluetoothLE: { isEnabled: false },
6202
6903
  awdl: { isEnabled: false },
6203
6904
  lan: { isEnabled: false, isMdnsEnabled: true, isMulticastEnabled: true },
6905
+ wifiAware: { isEnabled: false },
6204
6906
  };
6205
6907
  this.connect = {
6206
6908
  tcpServers: [],
@@ -6226,12 +6928,36 @@ class TransportConfig {
6226
6928
  };
6227
6929
  }
6228
6930
  /**
6229
- * Enables all peer-to-peer transports. Throws if receiver is frozen.
6931
+ * Enables or disables _every_ peer-to-peer transport protocols defined in
6932
+ * {@link peerToPeer} regardless of whether the current platform
6933
+ * can actually drive those transport implementations.
6934
+ *
6935
+ * Throws if receiver is frozen.
6936
+ *
6937
+ * @deprecated Use {@link setAvailablePeerToPeerEnabled | setAvailablePeerToPeerEnabled()}. instead.
6230
6938
  */
6231
6939
  setAllPeerToPeerEnabled(enabled) {
6232
6940
  this.peerToPeer.bluetoothLE.isEnabled = enabled;
6233
6941
  this.peerToPeer.lan.isEnabled = enabled;
6234
6942
  this.peerToPeer.awdl.isEnabled = enabled;
6943
+ this.peerToPeer.wifiAware.isEnabled = enabled;
6944
+ }
6945
+ /**
6946
+ * Enables or disables the peer-to-peer transport protocols defined in
6947
+ * {@link TransportConfigPeerToPeer} that are supported on the current platform.
6948
+ *
6949
+ * You can check the list of available transports for each platform at
6950
+ * https://ditto.com/link/sdk-latest-compatibility
6951
+ */
6952
+ setAvailablePeerToPeerEnabled(enabled) {
6953
+ const isNodeMacOS = process.platform === 'darwin';
6954
+ const isReactNative = isReactNativeBuild;
6955
+ const isReactNativeiOS = isReactNative;
6956
+ this.peerToPeer.bluetoothLE.isEnabled = enabled;
6957
+ this.peerToPeer.lan.isEnabled = enabled;
6958
+ this.peerToPeer.wifiAware.isEnabled = false;
6959
+ this.peerToPeer.awdl.isEnabled =
6960
+ isNodeMacOS || isReactNativeiOS ? enabled : false;
6235
6961
  }
6236
6962
  /**
6237
6963
  * Returns `true` if the transport configuration is frozen, otherwise
@@ -6250,6 +6976,7 @@ class TransportConfig {
6250
6976
  Object.freeze(this.peerToPeer.bluetoothLE);
6251
6977
  Object.freeze(this.peerToPeer.awdl);
6252
6978
  Object.freeze(this.peerToPeer.lan);
6979
+ Object.freeze(this.peerToPeer.wifiAware);
6253
6980
  Object.freeze(this.peerToPeer);
6254
6981
  Object.freeze(this.connect.tcpServers);
6255
6982
  Object.freeze(this.connect.websocketURLs);
@@ -6258,6 +6985,7 @@ class TransportConfig {
6258
6985
  Object.freeze(this.listen.http);
6259
6986
  Object.freeze(this.listen);
6260
6987
  Object.freeze(this.global);
6988
+ Object.freeze(this);
6261
6989
  return this;
6262
6990
  }
6263
6991
  /**
@@ -6272,6 +7000,7 @@ class TransportConfig {
6272
7000
  copy.peerToPeer.lan.isMdnsEnabled = this.peerToPeer.lan.isMdnsEnabled;
6273
7001
  copy.peerToPeer.lan.isMulticastEnabled =
6274
7002
  this.peerToPeer.lan.isMulticastEnabled;
7003
+ copy.peerToPeer.wifiAware.isEnabled = this.peerToPeer.wifiAware.isEnabled;
6275
7004
  copy.connect.tcpServers = this.connect.tcpServers.slice();
6276
7005
  copy.connect.websocketURLs = this.connect.websocketURLs.slice();
6277
7006
  copy.connect.retryInterval = this.connect.retryInterval;
@@ -6517,31 +7246,43 @@ class AttachmentFetcher {
6517
7246
  * Used to subscribe to receive updates from remote peers about matching
6518
7247
  * documents.
6519
7248
  *
6520
- * While {@link Subscription} objects remain in scope they ensure that
6521
- * documents in the collection specified and that match the query provided will
6522
- * try to be kept up-to-date with the latest changes from remote peers.
7249
+ * While {@link Subscription} objects remain in scope they ensure that documents
7250
+ * in the collection specified and that match the query provided will try to be
7251
+ * kept up-to-date with the latest changes from remote peers.
6523
7252
  *
6524
7253
  * This class is used by Ditto's query builder APIs.
6525
7254
  * @see {@link SyncSubscription} for the DQL equivalent.
6526
7255
  *
6527
7256
  * Not available in React Native environments.
7257
+ *
7258
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
7259
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
6528
7260
  */
6529
7261
  class Subscription {
6530
7262
  /**
6531
7263
  * Returns `true` if subscription has been explicitly cancelled, `false`
6532
7264
  * otherwise.
7265
+ *
7266
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7267
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6533
7268
  */
6534
7269
  get isCancelled() {
6535
7270
  return this._isCancelled;
6536
7271
  }
6537
7272
  /**
6538
7273
  * The name of the collection that the subscription is based on.
7274
+ *
7275
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7276
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6539
7277
  */
6540
7278
  get collectionName() {
6541
7279
  return this.collection.name;
6542
7280
  }
6543
7281
  /**
6544
7282
  * Cancels a subscription and releases all associated resources.
7283
+ *
7284
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7285
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6545
7286
  */
6546
7287
  cancel() {
6547
7288
  if (!this.isCancelled) {
@@ -6568,6 +7309,9 @@ class Subscription {
6568
7309
  };
6569
7310
  this.manager = collection.store.ditto.subscriptionManager;
6570
7311
  this.manager.add(this);
7312
+ Logger.warning(`Subscription is deprecated, use ditto.sync.registerSubscription() instead. ` +
7313
+ `For more information see: ` +
7314
+ `https://ditto.com/link/dql-legacy-to-dql-adoption`);
6571
7315
  }
6572
7316
  }
6573
7317
 
@@ -6580,22 +7324,29 @@ class Subscription {
6580
7324
  * mutations. All subsequent events are of type {@link LiveQueryEventUpdate}.
6581
7325
  *
6582
7326
  * Not available in React Native environments.
7327
+ *
7328
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
7329
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
6583
7330
  */
6584
7331
  class LiveQueryEventInitial {
6585
7332
  constructor() {
6586
7333
  /**
6587
- * Whether or not this is the initial event being delivered. Always `true`
6588
- * for `LiveQueryEventInitial`.
7334
+ * Whether or not this is the initial event being delivered. Always `true` for
7335
+ * `LiveQueryEventInitial`.
7336
+ *
7337
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7338
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6589
7339
  */
6590
7340
  this.isInitial = true;
6591
7341
  }
6592
7342
  /**
6593
7343
  * Returns a hash that represents the set of matching documents.
6594
7344
  *
6595
- * @deprecated use {@link Document.hash | Document.hash()} instead.
7345
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7346
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6596
7347
  */
6597
7348
  hash(documents) {
6598
- Logger.warning('LiveQueryEventInitial.hash() is deprecated, use Document.hash() instead');
7349
+ Logger.warning('Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption');
6599
7350
  const documentHandles = Bridge.document.handlesFor(documents);
6600
7351
  return documentsHash(documentHandles.deref());
6601
7352
  }
@@ -6603,10 +7354,11 @@ class LiveQueryEventInitial {
6603
7354
  * Returns a pattern of words that together create a mnemonic, which
6604
7355
  * represents the set of matching documents.
6605
7356
  *
6606
- * @deprecated use {@link Document.hashMnemonic | Document.hashMnemonic()} instead.
7357
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7358
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6607
7359
  */
6608
7360
  hashMnemonic(documents) {
6609
- Logger.warning('LiveQueryEventInitial.hashMnemonic() is deprecated, use Document.hashMnemonic() instead');
7361
+ Logger.warning('Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption');
6610
7362
  const documentHandles = Bridge.document.handlesFor(documents);
6611
7363
  return documentsHashMnemonic(documentHandles.deref());
6612
7364
  }
@@ -6617,13 +7369,17 @@ class LiveQueryEventInitial {
6617
7369
  * covered by a (live) query.
6618
7370
  *
6619
7371
  * Not available in React Native environments.
7372
+ *
7373
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
7374
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
6620
7375
  */
6621
7376
  class LiveQueryEventUpdate {
6622
7377
  /**
6623
7378
  * Returns a hash that represents the set of matching documents.
6624
7379
  *
6625
7380
  * @throws {Error} when called in a React Native environment.
6626
- * @deprecated use {@link Document.hash | Document.hash()} instead.
7381
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7382
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6627
7383
  */
6628
7384
  hash(documents) {
6629
7385
  Logger.warning('LiveQueryEventUpdate.hash() is deprecated, use Document.hash() instead');
@@ -6635,7 +7391,8 @@ class LiveQueryEventUpdate {
6635
7391
  * represents the set of matching documents.
6636
7392
  *
6637
7393
  * @throws {Error} when called in a React Native environment.
6638
- * @deprecated use {@link Document.hashMnemonic | Document.hashMnemonic()} instead.
7394
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7395
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6639
7396
  */
6640
7397
  hashMnemonic(documents) {
6641
7398
  Logger.warning('LiveQueryEventUpdate.hashMnemonic() is deprecated, use Document.hashMnemonic() instead');
@@ -6647,6 +7404,9 @@ class LiveQueryEventUpdate {
6647
7404
  /**
6648
7405
  * Whether or not this is the initial event being delivered. Always `false`
6649
7406
  * for `LiveQueryEventUpdate`.
7407
+ *
7408
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7409
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6650
7410
  */
6651
7411
  this.isInitial = false;
6652
7412
  this.oldDocuments = params.oldDocuments;
@@ -6660,6 +7420,9 @@ class LiveQueryEventUpdate {
6660
7420
  /**
6661
7421
  * Provides information about a live query event relating to a single document
6662
7422
  * live query.
7423
+ *
7424
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
7425
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
6663
7426
  */
6664
7427
  class SingleDocumentLiveQueryEvent {
6665
7428
  /**
@@ -6676,7 +7439,8 @@ class SingleDocumentLiveQueryEvent {
6676
7439
  * Returns a pattern of words that together create a mnemonic, which
6677
7440
  * represents the set of matching documents.
6678
7441
  *
6679
- * @deprecated use {@link Document.hashMnemonic | Document.hashMnemonic()} instead.
7442
+ * @deprecated use {@link Document.hashMnemonic | Document.hashMnemonic()}
7443
+ * instead.
6680
7444
  */
6681
7445
  hashMnemonic(document) {
6682
7446
  Logger.warning('SingleDocumentLiveQueryEvent.hashMnemonic() is deprecated, use Document.hashMnemonic() instead');
@@ -6708,13 +7472,24 @@ class SingleDocumentLiveQueryEvent {
6708
7472
  * documents matching a query then you must call {@link stop | stop()}.
6709
7473
  *
6710
7474
  * Not available in React Native environments.
7475
+ *
7476
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
7477
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
6711
7478
  */
6712
7479
  class LiveQuery {
6713
- /** The name of the collection that the live query is based on. */
7480
+ /**
7481
+ * The name of the collection that the live query is based on.
7482
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7483
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7484
+ */
6714
7485
  get collectionName() {
6715
7486
  return this.collection.name;
6716
7487
  }
6717
- /** Returns true if the receiver has been stopped. */
7488
+ /**
7489
+ * Returns true if the receiver has been stopped.
7490
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7491
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7492
+ */
6718
7493
  get isStopped() {
6719
7494
  return !this.liveQueryManager;
6720
7495
  }
@@ -6722,11 +7497,17 @@ class LiveQuery {
6722
7497
  * Stop the live query from delivering updates.
6723
7498
  *
6724
7499
  * @throws {Error} when called in a React Native environment.
7500
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7501
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6725
7502
  */
6726
7503
  stop() {
6727
7504
  if (!this.isStopped)
6728
7505
  this.liveQueryManager.stopLiveQuery(this);
6729
7506
  }
7507
+ /**
7508
+ * The ID of this live query.
7509
+ * @internal
7510
+ */
6730
7511
  get liveQueryID() {
6731
7512
  return this._liveQueryID;
6732
7513
  }
@@ -6744,6 +7525,9 @@ class LiveQuery {
6744
7525
  this.liveQueryManager = null;
6745
7526
  const collectionName = collection.name;
6746
7527
  const weakDitto = new WeakRef(collection.store.ditto);
7528
+ Logger.warning(`LiveQuery is deprecated, use ditto.store.registerObserver() instead. ` +
7529
+ `For more information see: ` +
7530
+ `https://ditto.com/link/dql-legacy-to-dql-adoption`);
6747
7531
  let liveQueryID = undefined;
6748
7532
  const signalNext = async () => {
6749
7533
  const ditto = weakDitto.deref();
@@ -6817,6 +7601,9 @@ class LiveQuery {
6817
7601
  * Update and remove functionality is also exposed through this object.
6818
7602
  *
6819
7603
  * Not available in React Native environments.
7604
+ *
7605
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
7606
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
6820
7607
  */
6821
7608
  class PendingCursorOperation extends BasePendingCursorOperation {
6822
7609
  sort(propertyPath, direction = 'ascending') {
@@ -6882,6 +7669,8 @@ class PendingCursorOperation extends BasePendingCursorOperation {
6882
7669
  * @returns A {@link Subscription} object that must be kept in scope for as
6883
7670
  * long as you want to keep receiving updates for documents that match the
6884
7671
  * query specified in the preceding chain.
7672
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7673
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6885
7674
  */
6886
7675
  subscribe() {
6887
7676
  const subscription = new Subscription(this.collection, this.query, this.queryArgsCBOR, this.orderBys, this.currentLimit, this.currentOffset);
@@ -6891,11 +7680,11 @@ class PendingCursorOperation extends BasePendingCursorOperation {
6891
7680
  /**
6892
7681
  * Enables you to listen for changes that occur in a collection locally.
6893
7682
  *
6894
- * The `handler` block will be called when local changes are
6895
- * made to documents that match the query generated by the chain of operations
6896
- * that precedes the call to {@link PendingCursorOperation.observeLocal | observeLocal()}.
6897
- * The returned {@link LiveQuery} object must be kept in scope for as long as
6898
- * you want the provided `handler` to be called when an update occurs.
7683
+ * The `handler` block will be called when local changes are made to documents
7684
+ * that match the query generated by the chain of operations that precedes the
7685
+ * call to {@link PendingCursorOperation.observeLocal | observeLocal()}. The
7686
+ * returned {@link LiveQuery} object must be kept in scope for as long as you
7687
+ * want the provided `handler` to be called when an update occurs.
6899
7688
  *
6900
7689
  * This won't subscribe to receive changes made remotely by others and so it
6901
7690
  * will only fire updates when a local change is made. If you want to receive
@@ -6913,17 +7702,20 @@ class PendingCursorOperation extends BasePendingCursorOperation {
6913
7702
  *
6914
7703
  * @return A {@link LiveQuery} object that must be kept in scope for as long
6915
7704
  * as you want to keep receiving updates.
7705
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7706
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6916
7707
  */
6917
7708
  observeLocal(handler) {
6918
7709
  return this._observe(handler, false);
6919
7710
  }
6920
7711
  /**
6921
- * Enables you to listen for changes that occur in a collection locally and
6922
- * to signal when you are ready for the live query to deliver the next event.
7712
+ * Enables you to listen for changes that occur in a collection locally and to
7713
+ * signal when you are ready for the live query to deliver the next event.
6923
7714
  *
6924
- * The `handler` block will be called when local changes are
6925
- * made to documents that match the query generated by the chain of operations
6926
- * that precedes the call to {@link PendingCursorOperation.observeLocalWithNextSignal | observeLocalWithNextSignal()}.
7715
+ * The `handler` block will be called when local changes are made to documents
7716
+ * that match the query generated by the chain of operations that precedes the
7717
+ * call to
7718
+ * {@link PendingCursorOperation.observeLocalWithNextSignal | observeLocalWithNextSignal()}.
6927
7719
  * The returned {@link LiveQuery} object must be kept in scope for as long as
6928
7720
  * you want the provided `handler` to be called when an update occurs.
6929
7721
  *
@@ -6936,14 +7728,15 @@ class PendingCursorOperation extends BasePendingCursorOperation {
6936
7728
  * update occurs.
6937
7729
  *
6938
7730
  * @param handler A closure that will be called every time there is a
6939
- * transaction committed to the store that involves modifications to
6940
- * documents matching the query in the collection that this method was called
6941
- * on.
7731
+ * transaction committed to the store that involves modifications to documents
7732
+ * matching the query in the collection that this method was called on.
6942
7733
  *
6943
7734
  * @throws {Error} when called in a React Native environment.
6944
7735
  *
6945
7736
  * @return A {@link LiveQuery} object that must be kept in scope for as long
6946
7737
  * as you want to keep receiving updates.
7738
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7739
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
6947
7740
  */
6948
7741
  observeLocalWithNextSignal(handler) {
6949
7742
  return this._observe(handler, true);
@@ -6952,6 +7745,8 @@ class PendingCursorOperation extends BasePendingCursorOperation {
6952
7745
  /** @internal */
6953
7746
  constructor(query, queryArgs, collection) {
6954
7747
  super(query, queryArgs, collection);
7748
+ Logger.warning(`Cursor operations are deprecated, use DQL (Ditto Query Language) instead. ` +
7749
+ `See https://ditto.com/link/dql-legacy-to-dql-adoption`);
6955
7750
  }
6956
7751
  /** @internal */
6957
7752
  _observe(handler, waitForNextSignal) {
@@ -6995,6 +7790,8 @@ class PendingCursorOperation extends BasePendingCursorOperation {
6995
7790
  * {@link Collection.findByID | findByID()} call.
6996
7791
  *
6997
7792
  * Update and remove functionality is also exposed through this object.
7793
+ *
7794
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
6998
7795
  */
6999
7796
  class PendingIDSpecificOperation extends BasePendingIDSpecificOperation {
7000
7797
  async remove() {
@@ -7038,6 +7835,9 @@ class PendingIDSpecificOperation extends BasePendingIDSpecificOperation {
7038
7835
  *
7039
7836
  * @returns A {@link Subscription} object that must be kept in scope for as
7040
7837
  * long as you want to keep receiving updates for the document.
7838
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7839
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7840
+
7041
7841
  */
7042
7842
  subscribe() {
7043
7843
  const subscription = new Subscription(this.collection, this.query, null, [], -1, 0);
@@ -7054,25 +7854,28 @@ class PendingIDSpecificOperation extends BasePendingIDSpecificOperation {
7054
7854
  * via {@link PendingIDSpecificOperation.subscribe | subscribe()} for the same
7055
7855
  * document ID.
7056
7856
  *
7057
- * The returned {@link LiveQuery} object must be kept in scope for as long
7058
- * as you want the provided `handler` to be called when an update
7059
- * occurs.
7857
+ * The returned {@link LiveQuery} object must be kept in scope for as long as
7858
+ * you want the provided `handler` to be called when an update occurs.
7060
7859
  *
7061
7860
  * @param handler A block that will be called every time there is a
7062
7861
  * transaction committed to the store that involves a modification to the
7063
7862
  * document with the relevant ID in the collection that
7064
- * {@link PendingIDSpecificOperation.observeLocal | observeLocal()} was called on.
7863
+ * {@link PendingIDSpecificOperation.observeLocal | observeLocal()} was called
7864
+ * on.
7065
7865
  *
7066
7866
  * @returns A {@link LiveQuery} object that must be kept in scope for as long
7067
7867
  * as you want to keep receiving updates.
7868
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7869
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7870
+
7068
7871
  */
7069
7872
  observeLocal(handler) {
7070
7873
  return this._observe(handler, false);
7071
7874
  }
7072
7875
  /**
7073
7876
  * Enables you to listen for changes that occur in relation to a document
7074
- * locally and to signal when you are ready for the live query to deliver
7075
- * the next event.
7877
+ * locally and to signal when you are ready for the live query to deliver the
7878
+ * next event.
7076
7879
  *
7077
7880
  * This won't subscribe to receive changes made remotely by others and so it
7078
7881
  * will only fire updates when a local change is made. If you want to receive
@@ -7080,17 +7883,20 @@ class PendingIDSpecificOperation extends BasePendingIDSpecificOperation {
7080
7883
  * via {@link PendingIDSpecificOperation.subscribe | subscribe()} for the same
7081
7884
  * document ID.
7082
7885
  *
7083
- * The returned {@link LiveQuery} object must be kept in scope for as long
7084
- * as you want the provided `handler` to be called when an update
7085
- * occurs.
7886
+ * The returned {@link LiveQuery} object must be kept in scope for as long as
7887
+ * you want the provided `handler` to be called when an update occurs.
7086
7888
  *
7087
7889
  * @param handler A block that will be called every time there is a
7088
7890
  * transaction committed to the store that involves a modification to the
7089
7891
  * document with the relevant ID in the collection that
7090
- * {@link PendingIDSpecificOperation.observeLocal | observeLocal()} was called on.
7892
+ * {@link PendingIDSpecificOperation.observeLocal | observeLocal()} was called
7893
+ * on.
7091
7894
  *
7092
7895
  * @returns A {@link LiveQuery} object that must be kept in scope for as long
7093
7896
  * as you want to keep receiving updates.
7897
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
7898
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7899
+
7094
7900
  */
7095
7901
  observeLocalWithNextSignal(handler) {
7096
7902
  return this._observe(handler, true);
@@ -7098,6 +7904,8 @@ class PendingIDSpecificOperation extends BasePendingIDSpecificOperation {
7098
7904
  /** @internal */
7099
7905
  constructor(documentID, collection) {
7100
7906
  super(documentID, collection);
7907
+ Logger.warning(`Cursor operations are deprecated, use DQL (Ditto Query Language) instead. ` +
7908
+ `See https://ditto.com/link/dql-legacy-to-dql-adoption`);
7101
7909
  }
7102
7910
  /** @internal */
7103
7911
  _observe(handler, waitForNextSignal) {
@@ -7162,6 +7970,8 @@ class PendingIDSpecificOperation extends BasePendingIDSpecificOperation {
7162
7970
  * object.
7163
7971
  *
7164
7972
  * Not available in React Native environments.
7973
+ *
7974
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
7165
7975
  */
7166
7976
  class Collection {
7167
7977
  /**
@@ -7180,16 +7990,21 @@ class Collection {
7180
7990
  * strings in quotation marks and arrays in square brackets, for example.
7181
7991
  *
7182
7992
  * Find more information about the query string format in the documentation's
7183
- * section on {@link https://docs.ditto.live/javascript/common/concepts/querying Querying}
7993
+ * section on {@link https://ditto.com/link/js-common-concepts-querying Querying}
7184
7994
  *
7185
7995
  * @throws {Error} when called in a React Native environment.
7186
7996
  * @param query The query to run against the collection.
7187
7997
  * @param queryArgs The arguments to use to replace placeholders in the
7188
7998
  * provided query.
7999
+ *
8000
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
7189
8001
  */
7190
8002
  find(query, queryArgs) {
7191
8003
  return new PendingCursorOperation(query, queryArgs !== null && queryArgs !== void 0 ? queryArgs : null, this);
7192
8004
  }
8005
+ /**
8006
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
8007
+ */
7193
8008
  findAll() {
7194
8009
  return this.find('true');
7195
8010
  }
@@ -7206,12 +8021,20 @@ class Collection {
7206
8021
  *
7207
8022
  * @param id The ID of the document to find.
7208
8023
  * @throws {Error} when called in a React Native environment.
8024
+ *
8025
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
7209
8026
  */
7210
8027
  findByID(id) {
7211
8028
  const documentID = id instanceof DocumentID ? id : new DocumentID(id);
7212
8029
  return new PendingIDSpecificOperation(documentID, this);
7213
8030
  }
8031
+ /**
8032
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see: https://ditto.com/link/dql-legacy-to-dql-adoption
8033
+ */
7214
8034
  async upsert(value, options = {}) {
8035
+ Logger.warning(`Collection.upsert() is deprecated, use ditto.store.execute() instead. ` +
8036
+ `For more information see: ` +
8037
+ `https://ditto.com/link/dql-legacy-to-dql-adoption`);
7215
8038
  return this.store.ditto.deferCloseAsync(async (dittoHandle) => {
7216
8039
  var _a;
7217
8040
  const writeStrategy = (_a = options.writeStrategy) !== null && _a !== void 0 ? _a : 'merge';
@@ -7351,12 +8174,51 @@ class QueryResult {
7351
8174
  * this method once and keep the return value for as long as needed.
7352
8175
  *
7353
8176
  * @returns an array of document IDs
8177
+ * @deprecated Use mutatedDocumentIDsV2() instead. This method will be removed
8178
+ * in a future version.
7354
8179
  */
7355
8180
  mutatedDocumentIDs() {
7356
8181
  const queryResultHandle = Bridge.queryResult.handleFor(this);
7357
8182
  const affectedCBORIDs = queryResultMutatedDocumentIDs(queryResultHandle.deref());
7358
8183
  return affectedCBORIDs.map((id) => new DocumentID(id, true));
7359
8184
  }
8185
+ /**
8186
+ * IDs of documents that were mutated _locally_ by a _mutating_ DQL query
8187
+ * passed to {@link Store.execute | `execute()`}. Empty array if no documents
8188
+ * have been mutated.
8189
+ *
8190
+ * **Note: Query results received from a {@link StoreObserver} never contain
8191
+ * mutated document IDs because a store observer is always registered using a
8192
+ * non-mutating `SELECT` query.
8193
+ *
8194
+ * **Important:** The returned document IDs are not cached, make sure to call
8195
+ * this method once and keep the return value for as long as needed.
8196
+ *
8197
+ * @returns an array of document ID values as JSON-compatible values
8198
+ */
8199
+ mutatedDocumentIDsV2() {
8200
+ const queryResultHandle = Bridge.queryResult.handleFor(this);
8201
+ const affectedCBORIDs = queryResultMutatedDocumentIDs(queryResultHandle.deref());
8202
+ return affectedCBORIDs.map((cborID) => CBOR.decode(cborID));
8203
+ }
8204
+ /**
8205
+ * The commit ID associated with this query result, if any.
8206
+ *
8207
+ * This ID uniquely identifies the commit in which this change was accepted
8208
+ * into the _local_ store. The commit ID is available for all query results
8209
+ * involving insertions, updates, or deletions. This ID can be used to track
8210
+ * whether a local change has been synced to other peers.
8211
+ *
8212
+ * For write transactions, the commit ID is only available after the
8213
+ * transaction has been successfully committed. Queries executed within an
8214
+ * uncommitted transaction will not have a commit ID.
8215
+ */
8216
+ get commitID() {
8217
+ const queryResultHandle = Bridge.queryResult.handleFor(this);
8218
+ if (queryResultHasCommitID(queryResultHandle.deref()))
8219
+ return queryResultCommitID(queryResultHandle.deref());
8220
+ return null;
8221
+ }
7360
8222
  // ----------------------------------------------------- Internal ------------
7361
8223
  /** @internal */
7362
8224
  constructor(queryResultPointer) {
@@ -7486,6 +8348,9 @@ class StoreObserver {
7486
8348
  * or moved since the last event.
7487
8349
  *
7488
8350
  * Not available in React Native environments.
8351
+ *
8352
+ * @deprecated Use DQL (Ditto Query Language) instead. For more details and
8353
+ * guidance, visit: https://ditto.com/link/dql.
7489
8354
  */
7490
8355
  class CollectionsEvent {
7491
8356
  /** @internal */
@@ -7535,6 +8400,9 @@ class CollectionsEvent {
7535
8400
  * like to receive updates from them about the collections that they know about.
7536
8401
  *
7537
8402
  * Not available in React Native environments.
8403
+ *
8404
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
8405
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
7538
8406
  */
7539
8407
  class PendingCollectionsOperation {
7540
8408
  /**
@@ -7550,6 +8418,8 @@ class PendingCollectionsOperation {
7550
8418
  *
7551
8419
  * @return A {@link PendingCollectionsOperation} that you can chain further
7552
8420
  * function calls to.
8421
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
8422
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7553
8423
  */
7554
8424
  sort(propertyPath, direction = 'ascending') {
7555
8425
  // The return value is ignored here because we don't want to await the
@@ -7572,6 +8442,8 @@ class PendingCollectionsOperation {
7572
8442
  *
7573
8443
  * @return A {@link PendingCollectionsOperation} that you can chain further
7574
8444
  * function calls to.
8445
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
8446
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7575
8447
  */
7576
8448
  offset(offset) {
7577
8449
  // The return value is ignored here because we don't want to await the
@@ -7588,6 +8460,8 @@ class PendingCollectionsOperation {
7588
8460
  *
7589
8461
  * @return A {@link PendingCollectionsOperation} that you can chain further
7590
8462
  * function calls to.
8463
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
8464
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7591
8465
  */
7592
8466
  limit(limit) {
7593
8467
  // The return value is ignored here because we don't want to await the
@@ -7607,6 +8481,8 @@ class PendingCollectionsOperation {
7607
8481
  * @return A {@link Subscription} object that must be kept in scope for as
7608
8482
  * long as you want to keep receiving updates from other devices about the
7609
8483
  * collections that they know about.
8484
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
8485
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7610
8486
  */
7611
8487
  subscribe() {
7612
8488
  return this.pendingCursorOperation.subscribe();
@@ -7619,8 +8495,8 @@ class PendingCollectionsOperation {
7619
8495
  * you want the provided `handler` to be called when an update occurs.
7620
8496
  *
7621
8497
  * This won't subscribe to receive updates from other devices and so it will
7622
- * only fire when a local change to the known about collections occurs. If
7623
- * you want to receive remote updates as well, then create a subscription via
8498
+ * only fire when a local change to the known about collections occurs. If you
8499
+ * want to receive remote updates as well, then create a subscription via
7624
8500
  * {@link PendingCollectionsOperation.subscribe | subscribe()}.
7625
8501
  *
7626
8502
  * @param handler A closure that will be called every time there is an update
@@ -7630,6 +8506,8 @@ class PendingCollectionsOperation {
7630
8506
  *
7631
8507
  * @return A {@link LiveQuery} object that must be kept in scope for as long
7632
8508
  * as you want to keep receiving updates.
8509
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
8510
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7633
8511
  */
7634
8512
  observeLocal(handler) {
7635
8513
  return this._observe(handler, false);
@@ -7642,8 +8520,8 @@ class PendingCollectionsOperation {
7642
8520
  * you want the provided `handler` to be called when an update occurs.
7643
8521
  *
7644
8522
  * This won't subscribe to receive updates from other devices and so it will
7645
- * only fire when a local change to the known about collections occurs. If
7646
- * you want to receive remote updates as well, then create a subscription via
8523
+ * only fire when a local change to the known about collections occurs. If you
8524
+ * want to receive remote updates as well, then create a subscription via
7647
8525
  * {@link PendingCollectionsOperation.subscribe | subscribe()}.
7648
8526
  *
7649
8527
  * @param handler A closure that will be called every time there is an update
@@ -7653,6 +8531,8 @@ class PendingCollectionsOperation {
7653
8531
  *
7654
8532
  * @return A {@link LiveQuery} object that must be kept in scope for as long
7655
8533
  * as you want to keep receiving updates.
8534
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
8535
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7656
8536
  */
7657
8537
  observeLocalWithNextSignal(handler) {
7658
8538
  return this._observe(handler, true);
@@ -7665,6 +8545,8 @@ class PendingCollectionsOperation {
7665
8545
  *
7666
8546
  * @return A list of {@link Collection}s based on the preceding function
7667
8547
  * chaining.
8548
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
8549
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7668
8550
  */
7669
8551
  async exec() {
7670
8552
  const documents = await this.pendingCursorOperation.exec();
@@ -7743,6 +8625,9 @@ function collectionsFromDocuments(documents, store) {
7743
8625
  * Live queries and subscriptions are only available outside of transactions.
7744
8626
  *
7745
8627
  * Not available in React Native environments.
8628
+ *
8629
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
8630
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
7746
8631
  */
7747
8632
  class WriteTransactionPendingCursorOperation extends BasePendingCursorOperation {
7748
8633
  sort(propertyPath, direction = 'ascending') {
@@ -7805,6 +8690,10 @@ class WriteTransactionPendingCursorOperation extends BasePendingCursorOperation
7805
8690
  //
7806
8691
  // Copyright © 2023 DittoLive Incorporated. All rights reserved.
7807
8692
  //
8693
+ /**
8694
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
8695
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
8696
+ */
7808
8697
  class WriteTransactionPendingIDSpecificOperation extends BasePendingIDSpecificOperation {
7809
8698
  async remove() {
7810
8699
  const ditto = this.collection.store.ditto;
@@ -7876,6 +8765,9 @@ class WriteTransactionPendingIDSpecificOperation extends BasePendingIDSpecificOp
7876
8765
  * and using its `scoped` method.
7877
8766
  *
7878
8767
  * Not available in React Native environments.
8768
+ *
8769
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
8770
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
7879
8771
  */
7880
8772
  class WriteTransactionCollection {
7881
8773
  /**
@@ -7888,6 +8780,8 @@ class WriteTransactionCollection {
7888
8780
  * @param queryArgs These arguments replace placeholders in the provided
7889
8781
  * query.
7890
8782
  * @throws {Error} when called in a React Native environment.
8783
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
8784
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7891
8785
  */
7892
8786
  find(query, queryArgs) {
7893
8787
  return new WriteTransactionPendingCursorOperation(query, queryArgs !== null && queryArgs !== void 0 ? queryArgs : null, this);
@@ -7897,6 +8791,8 @@ class WriteTransactionCollection {
7897
8791
  * the query `"true"`.
7898
8792
  *
7899
8793
  * @throws {Error} when called in a React Native environment.
8794
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
8795
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7900
8796
  */
7901
8797
  findAll() {
7902
8798
  return this.find('true');
@@ -7905,10 +8801,13 @@ class WriteTransactionCollection {
7905
8801
  * Generates a {@link WriteTransactionPendingIDSpecificOperation} with the
7906
8802
  * provided document ID.
7907
8803
  *
7908
- * The returned object can be used to find and return the document. It can also be used to update, remove or evict the document.
8804
+ * The returned object can be used to find and return the document. It can
8805
+ * also be used to update, remove or evict the document.
7909
8806
  *
7910
8807
  * @param id The ID of the document to find.
7911
8808
  * @throws {Error} when called in a React Native environment.
8809
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
8810
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7912
8811
  */
7913
8812
  findByID(id) {
7914
8813
  const documentID = id instanceof DocumentID ? id : new DocumentID(id);
@@ -7956,6 +8855,9 @@ class WriteTransactionCollection {
7956
8855
  * Perform writes in a transaction.
7957
8856
  *
7958
8857
  * Create a write transaction using {@link Store.write | ditto.store.write}.
8858
+ *
8859
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information see:
8860
+ * https://ditto.com/link/dql-legacy-to-dql-adoption
7959
8861
  */
7960
8862
  class WriteTransaction {
7961
8863
  /**
@@ -7967,6 +8869,8 @@ class WriteTransaction {
7967
8869
  * {@link WriteTransaction} object.
7968
8870
  *
7969
8871
  * @throws {Error} when called in a React Native environment.
8872
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
8873
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
7970
8874
  * */
7971
8875
  scoped(toCollectionNamed) {
7972
8876
  if (typeof toCollectionNamed !== 'string')
@@ -8042,7 +8946,7 @@ class TransactionInfo {
8042
8946
  * For more information on creating and using transactions, refer to the
8043
8947
  * {@link Store.transaction | ditto.store.transaction()} method. For a comprehensive guide on
8044
8948
  * transactions, please visit the
8045
- * [Ditto documentation](https://docs.ditto.live/sdk/latest/crud/transactions).
8949
+ * [Ditto documentation](https://ditto.com/link/sdk-latest-crud-transactions).
8046
8950
  */
8047
8951
  class Transaction {
8048
8952
  constructor(store) {
@@ -8221,16 +9125,18 @@ class Store {
8221
9125
  return storeObserver;
8222
9126
  }
8223
9127
  /**
8224
- * Returns the collection for the given name. If the collection doesn't
8225
- * exist yet, it will be created automatically as soon as the first
8226
- * entry is inserted.
8227
- * A collection name is valid if:
9128
+ * Returns the collection for the given name. If the collection doesn't exist
9129
+ * yet, it will be created automatically as soon as the first entry is
9130
+ * inserted. A collection name is valid if:
8228
9131
  * * its length is less than 100
8229
9132
  * * it is not empty
8230
9133
  * * it does not contain the char '\0'
8231
9134
  * * it does not begin with "$TS_"
8232
9135
  *
8233
9136
  * @throws {Error} when called in a React Native environment.
9137
+ *
9138
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
9139
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
8234
9140
  */
8235
9141
  collection(name) {
8236
9142
  return new Collection(name, this);
@@ -8243,15 +9149,19 @@ class Store {
8243
9149
  * fetch or observe the collections in the store
8244
9150
  *
8245
9151
  * @throws {Error} when called in a React Native environment.
9152
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
9153
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
8246
9154
  */
8247
9155
  collections() {
8248
9156
  return new PendingCollectionsOperation(this);
8249
9157
  }
8250
9158
  /**
8251
- * Returns the names of all available collections in the store of the
8252
- * related {@link Ditto} instance.
9159
+ * Returns the names of all available collections in the store of the related
9160
+ * {@link Ditto} instance.
8253
9161
  *
8254
9162
  * @throws {Error} when called in a React Native environment.
9163
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
9164
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
8255
9165
  */
8256
9166
  collectionNames() {
8257
9167
  return this.ditto.deferClose((dittoHandle) => {
@@ -8280,13 +9190,22 @@ class Store {
8280
9190
  /**
8281
9191
  * Initiate a write transaction in a callback.
8282
9192
  *
8283
- * Allows you to group multiple operations together that affect multiple documents, potentially across multiple collections.
9193
+ * Allows you to group multiple operations together that affect multiple
9194
+ * documents, potentially across multiple collections.
8284
9195
  *
8285
- * @param callback is given access to a {@link WriteTransaction | write transaction object} that can be used to perform operations on the store.
9196
+ * @param callback is given access to a
9197
+ * {@link WriteTransaction | write transaction object} that can be used to
9198
+ * perform operations on the store.
8286
9199
  * @throws {Error} when called in a React Native environment.
8287
- * @returns a list of `WriteTransactionResult`s. There is a result for each operation performed as part of the write transaction.
9200
+ * @returns a list of `WriteTransactionResult`s. There is a result for each
9201
+ * operation performed as part of the write transaction.
9202
+ *
9203
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
9204
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
8288
9205
  */
8289
9206
  async write(callback) {
9207
+ Logger.warning(`ditto.store.write() is deprecated, use ditto.store.transaction() instead. ` +
9208
+ `See https://ditto.com/link/dql-legacy-to-dql-adoption`);
8290
9209
  // Run caller's callback, rolling back if needed.
8291
9210
  return this.ditto.deferCloseAsync(async () => {
8292
9211
  const transaction = await WriteTransaction.init(this.ditto);
@@ -8577,7 +9496,7 @@ class Store {
8577
9496
  * are executed at all, providing strong consistency guarantees. Certain mesh
8578
9497
  * configurations may impose limitations on these guarantees. For more
8579
9498
  * details, refer to the [Ditto
8580
- * documentation](https://docs.ditto.live/sdk/latest/crud/transactions).
9499
+ * documentation](https://ditto.com/link/sdk-latest-crud-transactions).
8581
9500
  *
8582
9501
  * Transactions are initiated as read-write by default, and only one
8583
9502
  * read-write transaction can be executed at any given time. Any other
@@ -8710,9 +9629,12 @@ class Store {
8710
9629
  //
8711
9630
  // -----------------------------------------------------------------------------
8712
9631
  /**
8713
- * Returns a string representation of the given address. Use this function
8714
- * to compare multiple addresses or whenever you need the address to be a key
8715
- * in a hash object.
9632
+ * Returns a string representation of the given address. Use this function to
9633
+ * compare multiple addresses or whenever you need the address to be a key in a
9634
+ * hash object.
9635
+ *
9636
+ * @deprecated Use `peerKeyString` to identify a peer. It is accessible via
9637
+ * {@link Peer}, {@link Connection}, and {@link ConnectionRequest}.
8716
9638
  */
8717
9639
  function addressToString(address) {
8718
9640
  return `${address.siteId}-${address.pubkey}`;
@@ -9165,6 +10087,9 @@ class TransportConditionsManager extends ObserverManager {
9165
10087
  case 'Mdns':
9166
10088
  apiConditionSource = 'MDNS';
9167
10089
  break;
10090
+ case 'WiFiAware':
10091
+ apiConditionSource = 'WiFiAware';
10092
+ break;
9168
10093
  }
9169
10094
  /* eslint-enable */
9170
10095
  /* eslint-disable */
@@ -9283,6 +10208,54 @@ class SyncSubscription {
9283
10208
  * Access this object via {@link Ditto.sync | Ditto.sync} on any Ditto instance.
9284
10209
  */
9285
10210
  class Sync {
10211
+ /**
10212
+ * Returns `true` if sync is active, otherwise returns `false`. Use
10213
+ * {@link Sync.start | ditto.sync.start()} to activate and
10214
+ * {@link Sync.stop | ditto.sync.stop()} to deactivate sync.
10215
+ */
10216
+ get isActive() {
10217
+ return this.ditto.isSyncActive;
10218
+ }
10219
+ /**
10220
+ * Starts the network transports. Ditto will connect to other devices.
10221
+ *
10222
+ * By default Ditto will enable all peer-to-peer transport types. On **Node**,
10223
+ * this means BluetoothLE, WiFi/LAN, and AWDL. On the **Web**, only connecting
10224
+ * via Websockets is supported. The default network configuration can be
10225
+ * modified with {@link Ditto.updateTransportConfig | updateTransportConfig()}
10226
+ * or replaced with {@link Ditto.setTransportConfig | setTransportConfig()}.
10227
+ *
10228
+ * Performance of initial sync when bootstrapping new peers can be improved by
10229
+ * calling {@link Ditto.disableSyncWithV3 | disableSyncWithV3()} before
10230
+ * {@link start | start()}. Only call that method when all peers in the mesh
10231
+ * are known to be running Ditto v4 or higher.
10232
+ *
10233
+ * Ditto will prevent the process from exiting until sync is stopped (not
10234
+ * relevant when running in the browser).
10235
+ *
10236
+ * **NOTE**: the BluetoothLE transport on Linux is experimental, this method
10237
+ * panics if no BluetoothLE hardware is available. Therefore, contrary to the
10238
+ * above, the BluetoothLE transport is temporarily disabled by default on
10239
+ * Linux.
10240
+ *
10241
+ * @see {@link Sync.isActive | ditto.sync.isActive}
10242
+ * @see {@link Sync.stop | ditto.sync.stop()}
10243
+ */
10244
+ start() {
10245
+ this.ditto.startSync();
10246
+ }
10247
+ /**
10248
+ * Stops all network transports.
10249
+ *
10250
+ * You may continue to use the Ditto store locally but no data will sync to or
10251
+ * from other devices.
10252
+ *
10253
+ * @see {@link Sync.isActive | ditto.sync.isActive}
10254
+ * @see {@link Sync.start | ditto.sync.start()}
10255
+ */
10256
+ stop() {
10257
+ this.ditto.stopSync();
10258
+ }
9286
10259
  /**
9287
10260
  * Installs and returns a sync subscription for a query, configuring Ditto to
9288
10261
  * receive updates from other peers for documents matching that query. The
@@ -9667,6 +10640,8 @@ class SmallPeerInfo {
9667
10640
  * `BigPeerOnly` to replicate collected info to the Big Peer.
9668
10641
  *
9669
10642
  * @throws when set to a value other than `BigPeerOnly` or `LocalPeerOnly`.
10643
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
10644
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
9670
10645
  */
9671
10646
  get syncScope() {
9672
10647
  return this.ditto.deferClose((dittoHandle) => {
@@ -9679,13 +10654,13 @@ class SmallPeerInfo {
9679
10654
  });
9680
10655
  }
9681
10656
  /**
9682
- * Determines which "kind" of peers the small peer info will be
9683
- * replicated to.
10657
+ * Determines which "kind" of peers the small peer info will be replicated to.
9684
10658
  *
9685
10659
  * Defaults to `LocalPeerOnly`, which means no replication. Set this to
9686
10660
  * `BigPeerOnly` to replicate collected info to the Big Peer.
9687
10661
  *
9688
- * @deprecated use {@link SmallPeerInfo.syncScope} instead.
10662
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
10663
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
9689
10664
  */
9690
10665
  async getSyncScope() {
9691
10666
  return this.ditto.deferClose((dittoHandle) => {
@@ -9699,7 +10674,8 @@ class SmallPeerInfo {
9699
10674
  *
9700
10675
  * @param syncScope the new sync scope.
9701
10676
  * @throws when set to a value other than `BigPeerOnly` or `LocalPeerOnly`.
9702
- * @deprecated use {@link SmallPeerInfo.syncScope} instead.
10677
+ * @deprecated Use DQL (Ditto Query Language) instead. For more information
10678
+ * see: https://ditto.com/link/dql-legacy-to-dql-adoption
9703
10679
  */
9704
10680
  async setSyncScope(syncScope) {
9705
10681
  return this.ditto.deferClose((dittoHandle) => {
@@ -9712,13 +10688,251 @@ class SmallPeerInfo {
9712
10688
  }
9713
10689
  }
9714
10690
 
10691
+ //
10692
+ // Copyright © 2025 DittoLive Incorporated. All rights reserved.
10693
+ //
10694
+ const AUTH_HANDLER_NOOP = {
10695
+ authenticationRequired(_authenticator) { },
10696
+ authenticationExpiringSoon(_authenticator, _secondsRemaining) { },
10697
+ authenticationStatusDidChange(_authenticator) { },
10698
+ };
10699
+ /**
10700
+ * The name of the directory, relative to the current working directory, that
10701
+ * will be used for persistence if no other directory is specified.
10702
+ *
10703
+ * @internal
10704
+ * @deprecated The new Ditto configuration APIs define the default in core
10705
+ */
10706
+ const DEFAULT_PERSISTENCE_DIRECTORY = 'ditto';
10707
+ /**
10708
+ * @internal
10709
+ */
10710
+ class ConfigOrParameters {
10711
+ get isConfig() {
10712
+ return this._config !== undefined;
10713
+ }
10714
+ get isParameters() {
10715
+ return this._parameters !== undefined;
10716
+ }
10717
+ get kind() {
10718
+ if (this.isConfig && !this.isParameters) {
10719
+ return 'config';
10720
+ }
10721
+ else if (this.isParameters && !this.isConfig) {
10722
+ return 'parameters';
10723
+ }
10724
+ else {
10725
+ throw new DittoError('internal', 'ConfigOrParameters is neither a config nor parameters');
10726
+ }
10727
+ }
10728
+ get config() {
10729
+ switch (this.kind) {
10730
+ case 'config':
10731
+ return this._config;
10732
+ case 'parameters':
10733
+ const identity = this._parameters.identity;
10734
+ switch (identity.type) {
10735
+ case 'onlineWithAuthentication':
10736
+ case 'onlinePlayground':
10737
+ return new DittoConfig(identity.appID, {
10738
+ type: 'server',
10739
+ url: this.urlFrom(identity.customAuthURL, identity.appID),
10740
+ }, this._parameters.persistenceDirectory);
10741
+ case 'sharedKey':
10742
+ return new DittoConfig(identity.appID, {
10743
+ type: 'smallPeersOnly',
10744
+ privateKey: identity.sharedKey,
10745
+ }, this._parameters.persistenceDirectory);
10746
+ case 'offlinePlayground':
10747
+ return new DittoConfig(identity.appID, {
10748
+ type: 'smallPeersOnly',
10749
+ }, this._parameters.persistenceDirectory);
10750
+ case 'manual':
10751
+ Logger.warning("Can't create a `DittoConfig` from a `manual` " +
10752
+ ' identity, manual identities are being phased out and ' +
10753
+ 'not supported with the `DittoConfig`-based APIs anymore. ' +
10754
+ "Mapping onto `{ type: 'smallPeersOnly' }`.");
10755
+ return new DittoConfig(DittoConfig.DEFAULT_DATABASE_ID, {
10756
+ type: 'smallPeersOnly',
10757
+ }, this._parameters.persistenceDirectory);
10758
+ }
10759
+ }
10760
+ }
10761
+ get identity() {
10762
+ switch (this.kind) {
10763
+ case 'parameters':
10764
+ return this._parameters.identity;
10765
+ case 'config':
10766
+ const { databaseID: id, connect } = this._config;
10767
+ switch (connect.type) {
10768
+ case 'server':
10769
+ return {
10770
+ type: 'onlineWithAuthentication',
10771
+ appID: id,
10772
+ authHandler: AUTH_HANDLER_NOOP,
10773
+ enableDittoCloudSync: false,
10774
+ customAuthURL: connect.url,
10775
+ };
10776
+ case 'smallPeersOnly':
10777
+ if (connect.privateKey) {
10778
+ return {
10779
+ type: 'sharedKey',
10780
+ appID: id,
10781
+ sharedKey: connect.privateKey,
10782
+ };
10783
+ }
10784
+ else {
10785
+ return {
10786
+ type: 'offlinePlayground',
10787
+ appID: id,
10788
+ };
10789
+ }
10790
+ }
10791
+ }
10792
+ }
10793
+ get persistenceDirectory() {
10794
+ switch (this.kind) {
10795
+ case 'parameters':
10796
+ return this._parameters.persistenceDirectory;
10797
+ case 'config':
10798
+ return this._config.persistenceDirectory;
10799
+ }
10800
+ }
10801
+ constructor(identityOrConfig, persistenceDirectory) {
10802
+ // Not supported by the JS SDK
10803
+ this.passphrase = null;
10804
+ this.historyTrackingEnabled = false;
10805
+ if (identityOrConfig instanceof DittoConfig) {
10806
+ this._config = identityOrConfig;
10807
+ this._parameters = undefined;
10808
+ }
10809
+ else {
10810
+ const persistenceDirectoryValidated = this.validatePersistenceDirectory(persistenceDirectory);
10811
+ this.validateIdentity(identityOrConfig);
10812
+ this._parameters = {
10813
+ identity: identityOrConfig,
10814
+ persistenceDirectory: persistenceDirectoryValidated,
10815
+ };
10816
+ this._config = undefined;
10817
+ }
10818
+ }
10819
+ /**
10820
+ * Returns a copy having sensitive data replaced with a placeholder
10821
+ */
10822
+ redactingSensitiveData() {
10823
+ switch (this.kind) {
10824
+ case 'config':
10825
+ const configCopy = this._config.copy();
10826
+ if (configCopy.connect.type === 'smallPeersOnly' &&
10827
+ configCopy.connect.privateKey != null)
10828
+ configCopy.connect.privateKey = '[REDACTED]';
10829
+ return new ConfigOrParameters(configCopy);
10830
+ case 'parameters':
10831
+ const identityCopy = { ...this._parameters.identity };
10832
+ if (identityCopy.type === 'sharedKey')
10833
+ identityCopy.sharedKey = '[REDACTED]';
10834
+ return new ConfigOrParameters(identityCopy, this._parameters.persistenceDirectory);
10835
+ }
10836
+ }
10837
+ validateIdentity(identity) {
10838
+ var _a, _b;
10839
+ if (!identity || typeof identity !== 'object') {
10840
+ throw new TypeError('Expected `identity` to be an object, but got: ' + typeof identity);
10841
+ }
10842
+ const validIdentity = { ...identity };
10843
+ // @ts-expect-error we validate the existence of the value below.
10844
+ const appID = identity.appID;
10845
+ if (![
10846
+ 'offlinePlayground',
10847
+ 'sharedKey',
10848
+ 'manual',
10849
+ 'onlinePlayground',
10850
+ 'onlineWithAuthentication',
10851
+ ].includes(identity.type))
10852
+ throw new Error(`Unknown identity type: ${identity.type}`);
10853
+ if ((identity.type === 'offlinePlayground' ||
10854
+ identity.type === 'sharedKey' ||
10855
+ identity.type === 'onlinePlayground' ||
10856
+ identity.type === 'onlineWithAuthentication') &&
10857
+ typeof appID === 'undefined')
10858
+ throw new Error(`Property .appID must be given for identity, but isn't.`);
10859
+ if (typeof appID !== 'undefined' && typeof appID !== 'string') {
10860
+ throw new Error(`Property .appID must be be of type string, but is of type '${typeof appID}': ${appID}`);
10861
+ }
10862
+ if ((identity.type === 'offlinePlayground' ||
10863
+ identity.type === 'sharedKey') &&
10864
+ typeof identity.siteID !== 'undefined') {
10865
+ const siteID = identity.siteID;
10866
+ const isSiteIDNumberOrBigInt = typeof siteID === 'number' || typeof siteID === 'bigint';
10867
+ if (!isSiteIDNumberOrBigInt)
10868
+ throw new Error('siteID must be a number or BigInt');
10869
+ if (siteID < 0)
10870
+ throw new Error('siteID must be >= 0');
10871
+ if (siteID > BigInt('0xffffffffffffffff'))
10872
+ throw new Error('siteID must be < 2^64');
10873
+ }
10874
+ if (identity.type === 'offlinePlayground') {
10875
+ if (typeof identity.siteID !== 'undefined') {
10876
+ Logger.warning(`Property .siteID is deprecated and should no longer be specified in an offline playground identity.`);
10877
+ }
10878
+ }
10879
+ if (identity.type === 'sharedKey') {
10880
+ if (typeof identity.siteID !== 'undefined') {
10881
+ Logger.warning(`Property .siteID is deprecated and should no longer be specified in a shared key identity.`);
10882
+ }
10883
+ // No validations of the remainder of the properties yet.
10884
+ }
10885
+ if (identity.type === 'manual') ;
10886
+ if (identity.type === 'onlinePlayground') {
10887
+ const token = identity.token;
10888
+ if (typeof token === 'undefined') {
10889
+ throw new Error(`Property .token must be given for identity but isn't. You can find the corresponding token on the Ditto Portal.`);
10890
+ }
10891
+ if (typeof token !== 'undefined' && typeof token !== 'string') {
10892
+ throw new Error(`Property .token of identity must be be of type string, but is of type '${typeof token}': ${token}`);
10893
+ }
10894
+ }
10895
+ if (identity.type === 'onlineWithAuthentication') {
10896
+ const authHandlerType = typeof identity.authHandler;
10897
+ if (authHandlerType !== 'object') {
10898
+ throw new TypeError(`Property .authHandler on identity of type onlineWithAuthentication must be an object, but is of type '${authHandlerType}'.`);
10899
+ }
10900
+ const expiringSoonType = typeof ((_a = identity.authHandler) === null || _a === void 0 ? void 0 : _a.authenticationExpiringSoon);
10901
+ const authenticationRequiredType = typeof ((_b = identity.authHandler) === null || _b === void 0 ? void 0 : _b.authenticationRequired);
10902
+ if (expiringSoonType !== 'function') {
10903
+ throw new TypeError(`Property .authHandler.authenticationExpiringSoon on identity of type onlineWithAuthentication must be a function, but is of type '${expiringSoonType}'.`);
10904
+ }
10905
+ if (authenticationRequiredType !== 'function') {
10906
+ throw new TypeError(`Property .authHandler.authenticationRequired on identity of type onlineWithAuthentication must be a function, but is of type '${authenticationRequiredType}'.`);
10907
+ }
10908
+ }
10909
+ return validIdentity;
10910
+ }
10911
+ /**
10912
+ * Returns the default persistence directory if the given path is null and
10913
+ * throws an error if the given path is empty or contains only whitespace.
10914
+ *
10915
+ * @deprecated this is only used by the legacy `DittoConfig` constructor.
10916
+ */
10917
+ validatePersistenceDirectory(persistenceDirectory) {
10918
+ if (persistenceDirectory == null)
10919
+ return DEFAULT_PERSISTENCE_DIRECTORY;
10920
+ if (persistenceDirectory.trim().length === 0) {
10921
+ throw new Error(`Invalid persistenceDirectory: '${persistenceDirectory}'`);
10922
+ }
10923
+ return persistenceDirectory;
10924
+ }
10925
+ urlFrom(customAuthURL, appID) {
10926
+ if (customAuthURL != null)
10927
+ return customAuthURL;
10928
+ return `https://${appID}.cloud.ditto.live`;
10929
+ }
10930
+ }
10931
+
9715
10932
  //
9716
10933
  // Copyright © 2021 DittoLive Incorporated. All rights reserved.
9717
10934
  //
9718
10935
  // -----------------------------------------------------------------------------
9719
- // The name of the directory, relative to cwd, that will be used for persistence
9720
- // if no other directory is specified.
9721
- const DEFAULT_PERSISTENCE_DIRECTORY = 'ditto';
9722
10936
  /**
9723
10937
  * Ditto is the entry point for accessing Ditto-related functionality.
9724
10938
  */
@@ -9730,6 +10944,163 @@ class Ditto {
9730
10944
  // Requires having called FFI.initSDKVersion() first.
9731
10945
  return dittoGetSDKSemver();
9732
10946
  }
10947
+ /**
10948
+ * The default root directory used for Ditto data persistence.
10949
+ *
10950
+ * This property returns the platform-dependent directory where Ditto stores
10951
+ * its data when a relative persistence directory path (or `null`) is
10952
+ * provided.
10953
+ *
10954
+ * **Node.js**
10955
+ *
10956
+ * - On macOS, this is the `~/Library/Application Support/ditto` directory.
10957
+ * - On Windows, this is the `~/AppData/Roaming/ditto` directory.
10958
+ * - On Linux, this is the `~/.local/share/ditto` directory.
10959
+ *
10960
+ * Note that sandboxed environments, such as Electron apps running under
10961
+ * Apple's App Sandbox, can require setting a
10962
+ * {@link DittoConfig.persistenceDirectory | custom persistence directory} as
10963
+ * these default directories may not be accessible.
10964
+ *
10965
+ * **React Native**
10966
+ *
10967
+ * - On iOS and macOS, this is the Application Support directory.
10968
+ * - On Android, this is the app's internal files directory.
10969
+ *
10970
+ * **Browsers**
10971
+ *
10972
+ * In browsers, this returns an empty string as there is no file system
10973
+ * access.
10974
+ *
10975
+ * @returns A string representing the default root directory.
10976
+ * @throws {DittoError} `sdk/unsupported` if the current environment is not
10977
+ * supported by Ditto.
10978
+ * @see {@link DittoConfig.persistenceDirectory} for more information on
10979
+ * configuring the persistence directory.
10980
+ */
10981
+ static get DEFAULT_ROOT_DIRECTORY() {
10982
+ {
10983
+ const { homedir } = require('os');
10984
+ const path = require('path');
10985
+ if (process.platform === 'darwin') {
10986
+ return path.join(homedir(), 'Library', 'Application Support', 'ditto');
10987
+ }
10988
+ else if (process.platform === 'win32') {
10989
+ return path.join(homedir(), 'AppData', 'Roaming', 'ditto');
10990
+ }
10991
+ else {
10992
+ // Linux
10993
+ return path.join(homedir(), '.local', 'share', 'ditto');
10994
+ }
10995
+ }
10996
+ }
10997
+ /**
10998
+ * Asynchronously creates and returns a new `Ditto` instance using the
10999
+ * provided configuration.
11000
+ *
11001
+ * This is the recommended way to initialize Ditto in async environments.
11002
+ *
11003
+ * This API is in **preview** and will become the standard way to initialize
11004
+ * Ditto instances in v5, replacing the legacy
11005
+ * {@link Ditto.constructor | Ditto constructor}.
11006
+ *
11007
+ * In Ditto 4.x, this method is only partially `async` and blocks for a
11008
+ * significant portion of the initialization process. It will become fully
11009
+ * `async` in Ditto 5.x.
11010
+ *
11011
+ * @param config - The configuration to initialize the new Ditto instance
11012
+ * with. Defaults to {@link DittoConfig.default}.
11013
+ *
11014
+ * @returns The newly created `Ditto` instance.
11015
+ *
11016
+ * @throws {@link DittoError} with code `persistenceDirectoryLocked` if the
11017
+ * chosen persistence directory is already in use by another Ditto instance.
11018
+ *
11019
+ * @throws {@link DittoError} with code `invalidDittoConfig` if the passed in
11020
+ * `DittoConfig`'s contents do not meet the required validation criteria.
11021
+ * For detailed information on the validation requirements, consult the
11022
+ * documentation of the individual properties of `DittoConfig`.
11023
+ *
11024
+ * @throws May throw other {@link DittoError}s for other initialization
11025
+ * failures.
11026
+ *
11027
+ * @see {@link openSync | Ditto.openSync()} for a blocking, non-async
11028
+ * alternative.
11029
+ */
11030
+ static async open(config = DittoConfig.default) {
11031
+ if (!(config instanceof DittoConfig)) {
11032
+ throw new TypeError(`Ditto.open() expects a DittoConfig, but got ${typeof config}`);
11033
+ }
11034
+ if (typeof config.connect !== 'object') {
11035
+ throw new TypeError(`Ditto.open() expects a DittoConfig with a \`connect\` property, but got ${typeof config.connect}`);
11036
+ }
11037
+ if (!Ditto.isEnvironmentSupported()) {
11038
+ throw new Error('Ditto does not support this JavaScript environment. Please consult ' +
11039
+ 'the Ditto JavaScript documentation for a list of supported ' +
11040
+ 'environments and browsers. You can use ' +
11041
+ '`Ditto.isEnvironmentSupported()` to run this check anytime.');
11042
+ }
11043
+ // FIXME: Failures in error reporting in the async open method
11044
+ //
11045
+ // const dittoPointer = await mapFFIErrorsAsync(async () =>
11046
+ // FFI.dittoOpenAsyncThrows(
11047
+ // config.toCBOR(),
11048
+ // 'PlatformDependent',
11049
+ // Ditto.DEFAULT_ROOT_DIRECTORY,
11050
+ // ),
11051
+ // );
11052
+ const dittoPointer = mapFFIErrors(() => dittoOpenThrows(config.toCBOR(), 'PlatformDependent', Ditto.DEFAULT_ROOT_DIRECTORY));
11053
+ // We are passing undocumented parameters to the constructor
11054
+ // @ts-expect-error ts(2554)
11055
+ return new Ditto(null, null, config, dittoPointer);
11056
+ }
11057
+ /**
11058
+ * Synchronously creates and returns a new `Ditto` instance using the provided
11059
+ * configuration.
11060
+ *
11061
+ * This is a blocking convenience method for initializing Ditto, intended for
11062
+ * use in non-async environments.
11063
+ *
11064
+ * This API is in **preview** and will become the standard way to initialize
11065
+ * Ditto instances in v5, replacing the legacy
11066
+ * {@link Ditto.constructor | Ditto constructor}.
11067
+ *
11068
+ * @param config - The configuration to initialize the new Ditto instance
11069
+ * with. Defaults to {@link DittoConfig.default}.
11070
+ *
11071
+ * @returns The newly created `Ditto` instance.
11072
+ *
11073
+ * @throws {@link DittoError} with code `persistenceDirectoryLocked` if the
11074
+ * chosen persistence directory is already in use by another Ditto instance.
11075
+ *
11076
+ * @throws {@link DittoError} with code `invalidDittoConfig` if the passed in
11077
+ * `DittoConfig`'s contents do not meet the required validation criteria.
11078
+ * For detailed information on the validation requirements, consult the
11079
+ * documentation of the individual properties of `DittoConfig`.
11080
+ *
11081
+ * @throws May throw other {@link DittoError}s for other initialization
11082
+ * failures.
11083
+ *
11084
+ * @see {@link open | Ditto.open()} for an async alternative.
11085
+ */
11086
+ static openSync(config = DittoConfig.default) {
11087
+ if (!(config instanceof DittoConfig)) {
11088
+ throw new TypeError(`Ditto.openSync() expects a DittoConfig, but got ${typeof config}`);
11089
+ }
11090
+ if (typeof config.connect !== 'object') {
11091
+ throw new TypeError(`Ditto.open() expects a DittoConfig with a \`connect\` property, but got ${typeof config.connect}`);
11092
+ }
11093
+ if (!Ditto.isEnvironmentSupported()) {
11094
+ throw new Error('Ditto does not support this JavaScript environment. Please consult ' +
11095
+ 'the Ditto JavaScript documentation for a list of supported ' +
11096
+ 'environments and browsers. You can use ' +
11097
+ '`Ditto.isEnvironmentSupported()` to run this check anytime.');
11098
+ }
11099
+ const dittoPointer = mapFFIErrors(() => dittoOpenThrows(config.toCBOR(), 'PlatformDependent', Ditto.DEFAULT_ROOT_DIRECTORY));
11100
+ // We are passing undocumented parameters to the constructor
11101
+ // @ts-expect-error ts(2554)
11102
+ return new Ditto(null, null, config, dittoPointer);
11103
+ }
9733
11104
  /**
9734
11105
  * Configure a custom identifier for this peer.
9735
11106
  *
@@ -9751,12 +11122,29 @@ class Ditto {
9751
11122
  }
9752
11123
  this._deviceName = value;
9753
11124
  }
9754
- /** Returns a string identifying the version of the Ditto SDK. */
11125
+ /**
11126
+ * Returns a string identifying the version of the Ditto SDK. *
11127
+ *
11128
+ * @deprecated This property is deprecated, use {@link Ditto.VERSION} instead.
11129
+ */
9755
11130
  get sdkVersion() {
9756
11131
  return this.deferClose((dittoHandle) => {
9757
11132
  return dittoGetSDKVersion(dittoHandle.deref());
9758
11133
  });
9759
11134
  }
11135
+ /**
11136
+ * The (validated) identity this Ditto instance was initialized with.
11137
+ *
11138
+ * **Phased out in 4.x.** This API will be replaced by {@link DittoConfig} in
11139
+ * v5.
11140
+ */
11141
+ get identity() {
11142
+ if (this.configOrParameters.isConfig) {
11143
+ Logger.warning('Accessing legacy `identity` property on a Ditto instance initialized ' +
11144
+ 'with the new DittoConfig API. The mapping may not be exact.');
11145
+ }
11146
+ return this.configOrParameters.identity;
11147
+ }
9760
11148
  /**
9761
11149
  * The path this Ditto instance was initialized with, if no path was given at
9762
11150
  * construction time, the default value is returned (see constructor).
@@ -9765,9 +11153,80 @@ class Ditto {
9765
11153
  * new 'Ditto.persistenceDirectory' property instead.
9766
11154
  */
9767
11155
  get path() {
9768
- Logger.warning("⚠️ Deprecation Warning: The 'Ditto.path' property is deprecated. Please update your code to use the new 'Ditto.persistenceDirectory' property instead.");
11156
+ Logger.warning("'Ditto.path' is deprecated. Use 'Ditto.persistenceDirectory' instead.");
9769
11157
  return this.persistenceDirectory;
9770
11158
  }
11159
+ /**
11160
+ * The configuration used to initialize this `Ditto` instance.
11161
+ *
11162
+ * This API is in **preview** and provides a read-only property to access the
11163
+ * configuration used during initialization of a `Ditto` instance in v5.
11164
+ *
11165
+ * Note: Sensitive data such as passphrases and private keys are redacted from
11166
+ * the returned configuration and replaced with the string `[REDACTED]`.
11167
+ *
11168
+ * If this instance was initialized using the deprecated parameter-based APIs,
11169
+ * the returned configuration will be an incomplete approximation, since there
11170
+ * is no exact 1:1 mapping between the old parameters and the new
11171
+ * {@link DittoConfig}. In this case, a warning will be logged.
11172
+ *
11173
+ * - Warning: Accessing this property on a `Ditto` instance created with the
11174
+ * deprecated parameter-based APIs may result in a partially filled
11175
+ * configuration. Prefer using the new `DittoConfig`-based initialization
11176
+ * methods {@link Ditto.open | Ditto.open()} and
11177
+ * {@link Ditto.openSync | Ditto.openSync()} whenever possible.
11178
+ */
11179
+ get config() {
11180
+ if (this.configOrParameters.isParameters) {
11181
+ Logger.warning(`Attempted to access property 'config' of a 'Ditto' ` +
11182
+ `instance initialized using the deprecated parameter-based APIs. ` +
11183
+ `Since there is no exact 1:1 mapping between the old parameters ` +
11184
+ `and the new 'DittoConfig', the returned configuration will be an ` +
11185
+ `incomplete approximation.`);
11186
+ }
11187
+ return this.configOrParameters.config;
11188
+ }
11189
+ /**
11190
+ * The persistence directory used by Ditto to persist data, represented by an
11191
+ * absolute path.
11192
+ *
11193
+ * It is not recommended to directly read or write to this directory as its
11194
+ * structure and contents are managed by Ditto and may change in future
11195
+ * versions.
11196
+ *
11197
+ * When {@link Logger} is enabled, logs may be written to this directory even
11198
+ * after a Ditto instance was deallocated. Please refer to the documentation
11199
+ * of {@link Logger} for more information.
11200
+ *
11201
+ * In browsers, this string acts as a namespace for the in-memory data store
11202
+ * and does not correspond to a file system directory.
11203
+ */
11204
+ get absolutePersistenceDirectory() {
11205
+ return this.deferClose((dittoHandle) => {
11206
+ return dittoAbsolutePersistenceDirectory(dittoHandle.deref());
11207
+ });
11208
+ }
11209
+ /**
11210
+ * Path to the local directory used for persistent data storage.
11211
+ *
11212
+ * Defaults to 'ditto'. In environments without file system access, such as
11213
+ * browsers, this is used as a namespace for the internal data store.
11214
+ *
11215
+ * It is not recommended to directly read or write to this directory as its
11216
+ * structure and contents are managed by Ditto and may change in future
11217
+ * versions.
11218
+ *
11219
+ * When {@link Logger} is enabled, logs may be written to this directory even
11220
+ * after a Ditto instance was {@link Ditto.close | closed}. Please refer to
11221
+ * the documentation of {@link Logger} for more information.
11222
+ *
11223
+ * @deprecated replaced by
11224
+ * {@link Ditto.absolutePersistenceDirectory | absolutePersistenceDirectory},
11225
+ * which guarantees an absolute path.
11226
+ */
11227
+ get persistenceDirectory() {
11228
+ return this.configOrParameters.persistenceDirectory;
11229
+ }
9771
11230
  /**
9772
11231
  * Returns `true` if an offline license token has been set, otherwise returns `false`.
9773
11232
  *
@@ -9790,6 +11249,8 @@ class Ditto {
9790
11249
  * Returns `true` if sync is active, otherwise returns `false`. Use
9791
11250
  * {@link startSync | startSync()} to activate and
9792
11251
  * {@link stopSync | stopSync()} to deactivate sync.
11252
+ *
11253
+ * @deprecated use {@link Sync.isActive | ditto.sync.isActive} instead.
9793
11254
  */
9794
11255
  get isSyncActive() {
9795
11256
  return this.deferClose((dittoHandle) => {
@@ -9803,12 +11264,17 @@ class Ditto {
9803
11264
  * using this to create a Ditto instance in the web browser will throw an
9804
11265
  * exception.
9805
11266
  *
11267
+ * **Phased out in 4.x** — replaced by
11268
+ * {@link Ditto.open | Ditto.open()} and
11269
+ * {@link Ditto.openSync | Ditto.openSync()} factory methods. This API will be
11270
+ * replaced by the new factory methods in v5.
11271
+ *
9806
11272
  * @param identity - Identity for the new Ditto instance, defaults to
9807
11273
  * `offlinePlayground` with `appID` being the empty string `''`.
9808
11274
  *
9809
11275
  * @param persistenceDirectory optional string containing a directory path
9810
- * that Ditto will use for persistence. Defaults to `"ditto"`. On Windows,
9811
- * the path will be automatically normalized.
11276
+ * that Ditto will use for persistence. Defaults to `"ditto"`. On Windows, the
11277
+ * path will be automatically normalized.
9812
11278
  *
9813
11279
  * @see {@link Ditto.identity}
9814
11280
  * @see {@link Ditto.persistenceDirectory}
@@ -9816,81 +11282,83 @@ class Ditto {
9816
11282
  * @throws {Error} for other failures during initialization of Ditto and
9817
11283
  * validation of the provided identity.
9818
11284
  */
11285
+ // NOTE: This constructor takes undocumented additional parameters so that the
11286
+ // async part of making a new Ditto instance can be done in Ditto.open() and
11287
+ // this constructor uses the outputs of that to set up the Ditto instance.
9819
11288
  constructor(identity, persistenceDirectory) {
9820
- var _a, _b;
11289
+ var _a, _b, _c, _d, _e;
9821
11290
  // ------------------------------------------------------------ Private ------
9822
11291
  this.deferCloseAllowed = true;
9823
11292
  this._isClosed = false;
9824
11293
  /** Set of pending operations that need to complete before the Ditto instance can be closed in a safe manner. */
9825
11294
  this.pendingOperations = new Set();
9826
11295
  if (!Ditto.isEnvironmentSupported()) {
9827
- 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.');
11296
+ throw new Error('Ditto does not support this JavaScript environment. Please consult ' +
11297
+ 'the Ditto JavaScript documentation for a list of supported ' +
11298
+ 'environments and browsers. You can use ' +
11299
+ '`Ditto.isEnvironmentSupported()` to run this check anytime.');
11300
+ }
11301
+ let dittoPointer = null;
11302
+ let configOrParameters;
11303
+ // See `Ditto.open()` and `Ditto.openSync()` where this constructor is
11304
+ // called with undocumented parameters:
11305
+ // - DittoConfig instance
11306
+ // - FFI.Pointer<FFI.FFIDitto>
11307
+ if (arguments.length === 4 && arguments[2] instanceof DittoConfig) {
11308
+ // the constructor was called from Ditto.open() or Ditto.openSync()
11309
+ if (identity != null || persistenceDirectory != null) {
11310
+ throw new DittoError('internal', 'identity and persistenceDirectory params must be null when constructing Ditto with DittoConfig');
11311
+ }
11312
+ configOrParameters = new ConfigOrParameters(arguments[2]);
11313
+ dittoPointer = arguments[3];
9828
11314
  }
9829
- loggerInit();
9830
- this.persistenceDirectory =
9831
- Ditto.initPersistenceDirectory(persistenceDirectory);
9832
- const identityOrDefault = identity !== null && identity !== void 0 ? identity : {
9833
- type: 'offlinePlayground',
9834
- appID: '',
9835
- };
9836
- const validIdentity = Object.freeze(this.validateIdentity(identityOrDefault));
9837
- this.identity = Object.freeze(validIdentity);
9838
- // Check if device name stays the same on sdk and core levels (#10729).
9839
- {
9840
- const os = require('os');
9841
- this._deviceName = os.hostname();
11315
+ else {
11316
+ // the constructor was called directly
11317
+ const identityOrDefault = identity !== null && identity !== void 0 ? identity : DEFAULT_IDENTITY;
11318
+ configOrParameters = new ConfigOrParameters(identityOrDefault, persistenceDirectory);
11319
+ }
11320
+ this.configOrParameters = configOrParameters.redactingSensitiveData();
11321
+ // Legacy Ditto initialization
11322
+ if (dittoPointer == null) {
11323
+ const identityConfig = makeIdentityConfig(configOrParameters.identity);
11324
+ // History tracking is an experimental and deprecated feature that is not
11325
+ // supported in the JS SDK.
11326
+ const historyTracking = 'Disabled';
11327
+ // The JS SDK, unlike (nearly all of) the other SDKs, expects its `TransportConfig`s to have
11328
+ // certain transports enabled/disabled by default. Specifically, it expects this to be
11329
+ // determined for P2P transports based on the environment. We specify this here by setting
11330
+ // `transportConfigMode` to 'PlatformDependent'.
11331
+ const transportConfigMode = 'PlatformDependent';
11332
+ dittoPointer = mapFFIErrors(() => dittoTryNewBlocking(configOrParameters.persistenceDirectory, identityConfig, historyTracking, transportConfigMode));
9842
11333
  }
9843
- this.keepAlive = new KeepAlive();
9844
- // WORKAROUND: the login provider triggers the registered callback right
9845
- // when the auth client is being constructed. At this point, we don't have
9846
- // the auth client, which would be needed to perform a login, nor did we
9847
- // have a chance to create an authenticator. Therefore catch that first
9848
- // callback, store the seconds remaining and proceed with propagating
9849
- // it after all pieces are in place.
9850
- let secondsRemainingUntilAuthenticationExpires = null;
9851
- const weakThis = new WeakRef(this);
9852
- const identityConfig = (() => {
9853
- var _a, _b, _c;
9854
- if (validIdentity.type === 'offlinePlayground') {
9855
- return dittoIdentityConfigMakeOfflinePlayground(validIdentity.appID, (_a = validIdentity.siteID) !== null && _a !== void 0 ? _a : 0);
9856
- }
9857
- if (validIdentity.type === 'manual') {
9858
- return dittoIdentityConfigMakeManual(validIdentity.certificate);
9859
- }
9860
- if (validIdentity.type === 'sharedKey') {
9861
- return dittoIdentityConfigMakeSharedKey(validIdentity.appID, validIdentity.sharedKey, validIdentity.siteID);
9862
- }
9863
- if (validIdentity.type === 'onlinePlayground') {
9864
- const authURL = (_b = validIdentity.customAuthURL) !== null && _b !== void 0 ? _b : defaultAuthURL(validIdentity.appID);
9865
- return dittoIdentityConfigMakeOnlinePlayground(validIdentity.appID, validIdentity.token, authURL);
9866
- }
9867
- if (validIdentity.type === 'onlineWithAuthentication') {
9868
- const authURL = (_c = validIdentity.customAuthURL) !== null && _c !== void 0 ? _c : defaultAuthURL(validIdentity.appID);
9869
- return dittoIdentityConfigMakeOnlineWithAuthentication(validIdentity.appID, authURL);
9870
- }
9871
- throw new Error(`Can't create Ditto, unsupported identity type: ${validIdentity}`);
9872
- })();
9873
- // History tracking is an experimental feature that is not supported in the JS SDK.
9874
- const historyTracking = 'Disabled';
9875
- // The JS SDK, unlike (nearly all of) the other SDKs, expects its `TransportConfig`s to have
9876
- // certain transports enabled/disabled by default. Specifically, it expects this to be
9877
- // determined for P2P transports based on the environment. We specify this here by setting
9878
- // `transportConfigMode` to 'PlatformDependent'.
9879
- const transportConfigMode = 'PlatformDependent';
9880
- const dittoPointer = mapFFIErrors(() => dittoTryNewBlocking(this.persistenceDirectory, identityConfig, historyTracking, transportConfigMode));
9881
- const appID = dittoAuthClientGetAppID(dittoPointer);
9882
- const siteID = dittoAuthClientGetSiteID(dittoPointer);
9883
11334
  Bridge.ditto.bridge(dittoPointer, this);
11335
+ this._deviceName = defaultDeviceName();
11336
+ // WORKAROUND (only for legacy identity): the login provider triggers the
11337
+ // registered callback right when the auth client is being constructed. At
11338
+ // this point, we don't have the auth client, which would be needed to
11339
+ // perform a login, nor did we have a chance to create an authenticator.
11340
+ // Therefore catch that first callback, store the seconds remaining and
11341
+ // proceed with propagating it after all pieces are in place.
11342
+ let secondsRemainingUntilAuthenticationExpires = null;
9884
11343
  let enableDittoCloudSync = false;
9885
- // IMPORTANT: Keeping the auth client around accumulates run-times and
9886
- // resources which becomes a problem specifically in tests (where we use one
9887
- // Ditto instance per test). We therefore keep it only if needed, i.e.
9888
- // _only_ for the onlineWithAuthentication and online identities and
9889
- // transfer ownership of it to the authenticator.
9890
- if (validIdentity.type === 'onlineWithAuthentication') {
9891
- enableDittoCloudSync = (_a = validIdentity.enableDittoCloudSync) !== null && _a !== void 0 ? _a : true;
9892
- this.auth = new OnlineAuthenticator(this.keepAlive, this, validIdentity.authHandler);
9893
- const loginProviderX = dittoAuthClientMakeLoginProvider(function (secondsRemaining) {
11344
+ this.keepAlive = new KeepAlive();
11345
+ if (configOrParameters.isConfig) {
11346
+ // For the new config, no auth callback handler is set up in the Ditto
11347
+ // constructor. Instead, it is set up every time an expiration handler is
11348
+ // set.
11349
+ this.auth = new OnlineAuthenticatorV2(this.keepAlive, this);
11350
+ }
11351
+ else if (((_a = configOrParameters.identity) === null || _a === void 0 ? void 0 : _a.type) === 'onlineWithAuthentication') {
11352
+ // IMPORTANT: Keeping the auth client around accumulates run-times and
11353
+ // resources which becomes a problem specifically in tests (where we use one
11354
+ // Ditto instance per test). We therefore keep it only if needed, i.e.
11355
+ // _only_ for the onlineWithAuthentication and online identities and
11356
+ // transfer ownership of it to the authenticator.
11357
+ enableDittoCloudSync =
11358
+ (_c = (_b = configOrParameters.identity) === null || _b === void 0 ? void 0 : _b.enableDittoCloudSync) !== null && _c !== void 0 ? _c : true;
11359
+ this.auth = new OnlineAuthenticator(this.keepAlive, this, configOrParameters.identity.authHandler);
11360
+ const weakThis = new WeakRef(this);
11361
+ const loginProviderPointer = dittoAuthClientMakeLoginProvider(function (secondsRemaining) {
9894
11362
  const strongThis = weakThis.deref();
9895
11363
  if (!strongThis) {
9896
11364
  Logger.warning(`Internal inconsistency, LoginProvider callback fired after the corresponding Ditto instance has been deallocated.`);
@@ -9909,10 +11377,11 @@ class Ditto {
9909
11377
  // auth all happens in the background and so there are no guarantees we
9910
11378
  // need to uphold by making sure things are in a certain state before the
9911
11379
  // constructor finishes
9912
- void dittoAuthSetLoginProvider(dittoPointer, loginProviderX);
11380
+ void dittoAuthSetLoginProvider(dittoPointer, loginProviderPointer);
9913
11381
  }
9914
- else if (validIdentity.type === 'onlinePlayground') {
9915
- enableDittoCloudSync = (_b = validIdentity.enableDittoCloudSync) !== null && _b !== void 0 ? _b : true;
11382
+ else if (((_d = configOrParameters.identity) === null || _d === void 0 ? void 0 : _d.type) === 'onlinePlayground') {
11383
+ enableDittoCloudSync =
11384
+ (_e = configOrParameters.identity.enableDittoCloudSync) !== null && _e !== void 0 ? _e : true;
9916
11385
  this.auth = new OnlineAuthenticator(this.keepAlive, this, {
9917
11386
  authenticationRequired: function (authenticator) {
9918
11387
  // No-op.
@@ -9930,8 +11399,8 @@ class Ditto {
9930
11399
  //
9931
11400
  // Assign instance properties.
9932
11401
  //
9933
- this.appID = appID;
9934
- this.siteID = siteID;
11402
+ this.appID = dittoAuthClientGetAppID(dittoPointer);
11403
+ this.siteID = dittoAuthClientGetSiteID(dittoPointer);
9935
11404
  this.sync = new Sync(this);
9936
11405
  this.store = new Store(this);
9937
11406
  this.smallPeerInfo = new SmallPeerInfo(this);
@@ -9944,7 +11413,8 @@ class Ditto {
9944
11413
  disableDeadlockTimeoutWhenDebugging();
9945
11414
  // WORKAROUND: see description above where the
9946
11415
  // secondsRemainingUntilAuthenticationExpires variable is declared.
9947
- if (secondsRemainingUntilAuthenticationExpires != null) {
11416
+ if (configOrParameters.isParameters &&
11417
+ secondsRemainingUntilAuthenticationExpires != null) {
9948
11418
  this.auth['@ditto.authenticationExpiring'](secondsRemainingUntilAuthenticationExpires);
9949
11419
  }
9950
11420
  }
@@ -10025,69 +11495,6 @@ class Ditto {
10025
11495
  }
10026
11496
  return !isIE && hasRequiredAPIs;
10027
11497
  }
10028
- /**
10029
- * Validates and creates the given directory and returns its path.
10030
- *
10031
- * Any string containing non-whitespace characters is considered valid.
10032
- * Defaults to `ditto` if no path or an invalid path is given. In web
10033
- * environments, the given path is returned as-is if it is valid.
10034
- *
10035
- * @param path optional string containing a writable directory path
10036
- * @returns validated path
10037
- * @internal
10038
- */
10039
- static initPersistenceDirectory(path) {
10040
- let validatedPath;
10041
- if (path == null)
10042
- validatedPath = DEFAULT_PERSISTENCE_DIRECTORY;
10043
- else if (path.trim().length === 0)
10044
- throw new Error(`Invalid argument for path parameter: '${path}'`);
10045
- else
10046
- validatedPath = path;
10047
- {
10048
- const fs = require('fs');
10049
- const path = require('path');
10050
- if (process.platform === 'win32') {
10051
- // Normalize the path on Windows to prevent issues with its max path
10052
- // length (if needed). Windows has a hard limit at 260 characters
10053
- // for file paths [1]. When this limit is exceeded reads and writes
10054
- // may fail.
10055
- //
10056
- // [1]: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation
10057
- if (!validatedPath.startsWith('\\\\?\\'))
10058
- validatedPath = `\\\\?\\${path.resolve(validatedPath)}`;
10059
- }
10060
- const absolutePath = path.resolve(validatedPath);
10061
- // We check if the directory exists before creating it to be able to
10062
- // provide a more helpful error message in case the directory is not
10063
- // writable.
10064
- let isDirectoryExisting = false;
10065
- try {
10066
- fs.statSync(absolutePath);
10067
- isDirectoryExisting = true;
10068
- }
10069
- catch (error) {
10070
- // On Windows, permissions can prevent us from checking if the directory
10071
- // exists: https://github.com/nodejs/node/issues/35853
10072
- if (error.code === 'EPERM') {
10073
- throw new Error(`Missing read or write permissions for the persistence directory path '${absolutePath}'. Please update the permissions or use a different path.`);
10074
- }
10075
- }
10076
- if (!isDirectoryExisting) {
10077
- try {
10078
- fs.mkdirSync(absolutePath, { recursive: true });
10079
- }
10080
- catch (error) {
10081
- throw new Error(`Failed to create persistence directory at path '${absolutePath}'.\n\n${error}`);
10082
- }
10083
- }
10084
- // Caveat: It is still possible that these permissions are revoked during runtime.
10085
- if (!isDirectoryWritable(absolutePath)) {
10086
- throw new Error(`Missing read or write permissions for the persistence directory path '${absolutePath}'. Please update the permissions or use a different path.`);
10087
- }
10088
- }
10089
- return validatedPath;
10090
- }
10091
11498
  /**
10092
11499
  * Activate a `Ditto` instance by setting an offline only license token. You
10093
11500
  * cannot initiate sync with `Ditto` before you have activated it. The offline
@@ -10098,7 +11505,7 @@ class Ditto {
10098
11505
  * with. You can find yours on the [Ditto portal](https://portal.ditto.live).
10099
11506
  */
10100
11507
  setOfflineOnlyLicenseToken(licenseToken) {
10101
- if (IdentityTypesRequiringOfflineLicenseToken.includes(this.identity.type)) {
11508
+ if (IdentityTypesRequiringOfflineLicenseToken.includes(this.configOrParameters.identity.type)) {
10102
11509
  this.deferClose((dittoHandle) => {
10103
11510
  mapFFIErrors(() => {
10104
11511
  tryVerifyLicense(dittoHandle.deref(), licenseToken);
@@ -10106,7 +11513,10 @@ class Ditto {
10106
11513
  });
10107
11514
  }
10108
11515
  else {
10109
- Logger.error(`The identity type '${this.identity.type}' does not require an offline license token.`);
11516
+ const errorMessage = this.configOrParameters.isConfig
11517
+ ? `The connect type '${this.config.connect.type}' does not require an offline license token.`
11518
+ : `The identity type '${this.identity.type}' does not require an offline license token.`;
11519
+ Logger.error(errorMessage);
10110
11520
  }
10111
11521
  }
10112
11522
  /**
@@ -10179,17 +11589,27 @@ class Ditto {
10179
11589
  *
10180
11590
  * @see {@link isSyncActive}
10181
11591
  * @see {@link stopSync | stopSync()}
11592
+ * @deprecated use {@link Sync.start | ditto.sync.start()} instead.
10182
11593
  */
10183
11594
  startSync() {
10184
11595
  this.deferClose((dittoHandle) => {
10185
- if (IdentityTypesRequiringOfflineLicenseToken.includes(this.identity.type) &&
11596
+ if (IdentityTypesRequiringOfflineLicenseToken.includes(this.configOrParameters.identity.type) &&
10186
11597
  !this.isActivated) {
10187
11598
  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.');
10188
11599
  }
10189
11600
  if (!this.isSyncActive)
10190
11601
  this.keepAlive.retain('sync');
10191
11602
  this._deviceName = dittoSetDeviceName(dittoHandle.deref(), this.deviceName);
10192
- dittoStartSync(dittoHandle.deref());
11603
+ try {
11604
+ mapFFIErrors(() => dittoTryStartSync(dittoHandle.deref()));
11605
+ }
11606
+ catch (error) {
11607
+ // Don't keep the process alive if starting sync failed and sync is not
11608
+ // already active.
11609
+ if (!this.isSyncActive)
11610
+ this.keepAlive.release('sync');
11611
+ throw error;
11612
+ }
10193
11613
  });
10194
11614
  }
10195
11615
  /**
@@ -10200,6 +11620,7 @@ class Ditto {
10200
11620
  *
10201
11621
  * @see {@link isSyncActive}
10202
11622
  * @see {@link startSync | startSync()}
11623
+ * @deprecated use {@link Sync.stop | ditto.sync.stop()} instead.
10203
11624
  */
10204
11625
  stopSync() {
10205
11626
  this.deferClose((dittoHandle) => {
@@ -10257,6 +11678,8 @@ class Ditto {
10257
11678
  * old data.
10258
11679
  *
10259
11680
  * This method does not have any effect when running Ditto in a browser.
11681
+ *
11682
+ * @deprecated this method is deprecated and will be removed in v5.0.0.
10260
11683
  */
10261
11684
  async runGarbageCollection() {
10262
11685
  return this.deferCloseAsync(async (dittoHandle) => {
@@ -10306,7 +11729,8 @@ class Ditto {
10306
11729
  this.transportConditionsManager.close();
10307
11730
  this.subscriptionManager.close();
10308
11731
  if (this.keepAlive.isActive) {
10309
- throw new Error('Internal inconsistency, still kept alive after the Ditto object has been close()-ed. ');
11732
+ throw new Error('Internal inconsistency, still kept alive after the Ditto object has been close()-ed. Active IDs: ' +
11733
+ this.keepAlive.currentIDs().join(', '));
10310
11734
  }
10311
11735
  // Await all pending operations before closing. Rejected promises are
10312
11736
  // ignored because they are handled at the original call site.
@@ -10382,55 +11806,6 @@ class Ditto {
10382
11806
  }
10383
11807
  return result;
10384
11808
  }
10385
- validateIdentity(identity) {
10386
- const validIdentity = { ...identity };
10387
- // @ts-expect-error we validate the existence of the value below.
10388
- const appID = identity.appID;
10389
- if (![
10390
- 'offlinePlayground',
10391
- 'sharedKey',
10392
- 'manual',
10393
- 'onlinePlayground',
10394
- 'onlineWithAuthentication',
10395
- ].includes(identity.type)) {
10396
- throw new Error(`Can't create Ditto instance, unknown identity type: ${identity.type}`);
10397
- }
10398
- if ((identity.type === 'offlinePlayground' ||
10399
- identity.type === 'sharedKey' ||
10400
- identity.type === 'onlinePlayground' ||
10401
- identity.type === 'onlineWithAuthentication') &&
10402
- typeof appID === 'undefined')
10403
- throw new Error(`Property .appID must be given for identity, but isn't.`);
10404
- if (typeof appID !== 'undefined' && typeof appID !== 'string') {
10405
- throw new Error(`Property .appID must be be of type string, but is of type '${typeof appID}': ${appID}`);
10406
- }
10407
- if ((identity.type === 'offlinePlayground' ||
10408
- identity.type === 'sharedKey') &&
10409
- typeof identity.siteID !== 'undefined') {
10410
- const siteID = identity.siteID;
10411
- const isSiteIDNumberOrBigInt = typeof siteID === 'number' || typeof siteID === 'bigint';
10412
- if (!isSiteIDNumberOrBigInt) {
10413
- throw new Error("Can't create Ditto instance, siteID must be a number or BigInt");
10414
- }
10415
- if (siteID < 0)
10416
- throw new Error("Can't create Ditto instance, siteID must be >= 0");
10417
- if (siteID > BigInt('0xffffffffffffffff'))
10418
- throw new Error("Can't create Ditto instance, siteID must be < 2^64");
10419
- }
10420
- if (identity.type === 'sharedKey') ;
10421
- if (identity.type === 'manual') ;
10422
- if (identity.type === 'onlinePlayground') {
10423
- const token = identity.token;
10424
- if (typeof token === 'undefined') {
10425
- throw new Error(`Property .token must be given for identity but isn't. You can find the corresponding token on the Ditto Portal.`);
10426
- }
10427
- if (typeof token !== 'undefined' && typeof token !== 'string') {
10428
- throw new Error(`Property .token of identity must be be of type string, but is of type '${typeof token}': ${token}`);
10429
- }
10430
- }
10431
- if (identity.type === 'onlineWithAuthentication') ;
10432
- return validIdentity;
10433
- }
10434
11809
  }
10435
11810
  /**
10436
11811
  * Returns true if the current JS environment supports all required APIs.
@@ -10476,54 +11851,6 @@ const disableDeadlockTimeoutWhenDebugging = () => {
10476
11851
  }
10477
11852
  }
10478
11853
  };
10479
- /**
10480
- * Return true if we have read and write permissions for the given directory.
10481
- *
10482
- * Always returns `true` in the browser.
10483
- *
10484
- * Uses `fs.accessSync()` on all platforms except Windows, where ACLs are not
10485
- * checked by that method [1]. On Windows, we try writing and removing a temp
10486
- * file to the given path instead.
10487
- *
10488
- * [1]:
10489
- * https://nodejs.org/docs/latest-v18.x/api/fs.html#fsaccesspath-mode-callback
10490
- *
10491
- * @internal
10492
- */
10493
- const isDirectoryWritable = (directoryPath) => {
10494
- {
10495
- const fs = require('fs');
10496
- const path = require('path');
10497
- if (process.platform === 'win32') {
10498
- const persistenceDirectory = path.resolve(directoryPath);
10499
- const testFilePath = path.join(persistenceDirectory, 'ditto-permissions-test.txt');
10500
- const testFileContents = 'permissions test';
10501
- try {
10502
- fs.writeFileSync(testFilePath, testFileContents);
10503
- const fileContents = fs.readFileSync(testFilePath, 'utf8');
10504
- if (fileContents !== testFileContents) {
10505
- Logger.debug(`Failed to read back test file contents, expected '${testFileContents}' but got '${fileContents}'`);
10506
- return false;
10507
- }
10508
- fs.unlinkSync(testFilePath);
10509
- }
10510
- catch (error) {
10511
- Logger.debug(`Failed to access persistence directory: ${error === null || error === void 0 ? void 0 : error.message}`);
10512
- return false;
10513
- }
10514
- }
10515
- else {
10516
- try {
10517
- fs.accessSync(directoryPath, fs.constants.W_OK | fs.constants.R_OK);
10518
- }
10519
- catch (error) {
10520
- Logger.debug(`Failed to access persistence directory: ${error === null || error === void 0 ? void 0 : error.message}`);
10521
- return false;
10522
- }
10523
- }
10524
- }
10525
- return true;
10526
- };
10527
11854
 
10528
11855
  //
10529
11856
  // Copyright © 2025 DittoLive Incorporated. All rights reserved.
@@ -10741,7 +12068,6 @@ Bridge.ditto.registerType(Ditto);
10741
12068
  exports.Attachment = Attachment;
10742
12069
  exports.AttachmentFetcher = AttachmentFetcher;
10743
12070
  exports.AttachmentToken = AttachmentToken;
10744
- exports.AuthenticationStatus = AuthenticationStatus;
10745
12071
  exports.Authenticator = Authenticator;
10746
12072
  exports.BasePendingCursorOperation = BasePendingCursorOperation;
10747
12073
  exports.BasePendingIDSpecificOperation = BasePendingIDSpecificOperation;
@@ -10750,9 +12076,11 @@ exports.Collection = Collection;
10750
12076
  exports.CollectionsEvent = CollectionsEvent;
10751
12077
  exports.ConnectionRequest = ConnectionRequest;
10752
12078
  exports.Counter = Counter;
12079
+ exports.DEFAULT_IDENTITY = DEFAULT_IDENTITY;
10753
12080
  exports.Diff = Diff;
10754
12081
  exports.Differ = Differ;
10755
12082
  exports.Ditto = Ditto;
12083
+ exports.DittoConfig = DittoConfig;
10756
12084
  exports.DittoError = DittoError;
10757
12085
  exports.Document = Document;
10758
12086
  exports.DocumentID = DocumentID;
@@ -10771,6 +12099,7 @@ exports.MutableRegister = MutableRegister;
10771
12099
  exports.NotAvailableAuthenticator = NotAvailableAuthenticator;
10772
12100
  exports.Observer = Observer;
10773
12101
  exports.OnlineAuthenticator = OnlineAuthenticator;
12102
+ exports.OnlineAuthenticatorV2 = OnlineAuthenticatorV2;
10774
12103
  exports.PendingCollectionsOperation = PendingCollectionsOperation;
10775
12104
  exports.PendingCursorOperation = PendingCursorOperation;
10776
12105
  exports.PendingIDSpecificOperation = PendingIDSpecificOperation;
@@ -10799,6 +12128,7 @@ exports.checkAPIs = checkAPIs;
10799
12128
  exports.disableDeadlockTimeoutWhenDebugging = disableDeadlockTimeoutWhenDebugging;
10800
12129
  exports.getBridgeLoad = getBridgeLoad;
10801
12130
  exports.init = init;
12131
+ exports.makeIdentityConfig = makeIdentityConfig;
10802
12132
  exports.mapFFIErrors = mapFFIErrors;
10803
12133
  exports.mapFFIErrorsAsync = mapFFIErrorsAsync;
10804
12134
  exports.transportConfigFromDeserializable = transportConfigFromDeserializable;