@dittolive/ditto 4.1.1 → 4.2.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/README.md +2 -2
- package/node/ditto.cjs.js +199 -90
- package/node/ditto.darwin-arm64.node +0 -0
- package/node/ditto.darwin-x64.node +0 -0
- package/node/ditto.linux-arm.node +0 -0
- package/node/ditto.linux-x64.node +0 -0
- package/node/ditto.win32-x64.node +0 -0
- package/node/transports.darwin-arm64.node +0 -0
- package/node/transports.darwin-x64.node +0 -0
- package/package.json +1 -1
- package/types/ditto.d.ts +112 -8
- package/web/ditto.es6.js +1 -1
- package/web/ditto.umd.js +1 -1
- package/web/ditto.wasm +0 -0
package/README.md
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*Ditto is a cross platform SDK that allows mobile, web, and IoT apps to sync
|
|
4
4
|
with and even without connectivity.*
|
|
5
5
|
|
|
6
|
-
Version: **4.
|
|
6
|
+
Version: **4.2.0**
|
|
7
7
|
|
|
8
8
|
Please visit [ditto.live](https://ditto.live) for more info as well as the
|
|
9
|
-
[API Reference](https://software.ditto.live/js/Ditto/4.
|
|
9
|
+
[API Reference](https://software.ditto.live/js/Ditto/4.2.0/api-reference/) for this particular version.
|
|
10
10
|
|
|
11
11
|
--------------------------------------------------------------------------------
|
|
12
12
|
|
package/node/ditto.cjs.js
CHANGED
|
@@ -289,9 +289,7 @@ function ditto_add_internal_ble_server_transport(...args) { return ditto.ditto_a
|
|
|
289
289
|
function ditto_add_internal_mdns_client_transport(...args) { return ditto.ditto_add_internal_mdns_client_transport(...args) }
|
|
290
290
|
function ditto_add_internal_mdns_server_transport(...args) { return ditto.ditto_add_internal_mdns_server_transport(...args) }
|
|
291
291
|
function ditto_add_multicast_transport(...args) { return ditto.ditto_add_multicast_transport(...args) }
|
|
292
|
-
function ditto_add_static_tcp_client(...args) { return ditto.ditto_add_static_tcp_client(...args) }
|
|
293
292
|
function ditto_add_subscription(...args) { return ditto.ditto_add_subscription(...args) }
|
|
294
|
-
function ditto_add_websocket_client(...args) { return ditto.ditto_add_websocket_client(...args) }
|
|
295
293
|
function ditto_auth_client_get_site_id(...args) { return ditto.ditto_auth_client_get_site_id(...args) }
|
|
296
294
|
function ditto_auth_client_is_web_valid(...args) { return ditto.ditto_auth_client_is_web_valid(...args) }
|
|
297
295
|
function ditto_auth_client_is_x509_valid(...args) { return ditto.ditto_auth_client_is_x509_valid(...args) }
|
|
@@ -326,7 +324,9 @@ function ditto_document_set_cbor_with_timestamp(...args) { return ditto.ditto_do
|
|
|
326
324
|
function ditto_documents_hash(...args) { return ditto.ditto_documents_hash(...args) }
|
|
327
325
|
function ditto_documents_hash_mnemonic(...args) { return ditto.ditto_documents_hash_mnemonic(...args) }
|
|
328
326
|
function ditto_error_message(...args) { return ditto.ditto_error_message(...args) }
|
|
327
|
+
function ditto_experimental_add_dql_subscription(...args) { return ditto.ditto_experimental_add_dql_subscription(...args) }
|
|
329
328
|
function ditto_experimental_exec_query_str(...args) { return ditto.ditto_experimental_exec_query_str(...args) }
|
|
329
|
+
function ditto_experimental_remove_dql_subscription(...args) { return ditto.ditto_experimental_remove_dql_subscription(...args) }
|
|
330
330
|
function ditto_free(...args) { return ditto.ditto_free(...args) }
|
|
331
331
|
function ditto_free_attachment_handle(...args) { return ditto.ditto_free_attachment_handle(...args) }
|
|
332
332
|
function ditto_get_collection_names(...args) { return ditto.ditto_get_collection_names(...args) }
|
|
@@ -369,6 +369,8 @@ function ditto_resolve_attachment(...args) { return ditto.ditto_resolve_attachme
|
|
|
369
369
|
function ditto_run_garbage_collection(...args) { return ditto.ditto_run_garbage_collection(...args) }
|
|
370
370
|
function ditto_set_connect_retry_interval(...args) { return ditto.ditto_set_connect_retry_interval(...args) }
|
|
371
371
|
function ditto_set_device_name(...args) { return ditto.ditto_set_device_name(...args) }
|
|
372
|
+
function ditto_set_static_tcp_clients(...args) { return ditto.ditto_set_static_tcp_clients(...args) }
|
|
373
|
+
function ditto_set_static_websocket_clients(...args) { return ditto.ditto_set_static_websocket_clients(...args) }
|
|
372
374
|
function ditto_set_sync_group(...args) { return ditto.ditto_set_sync_group(...args) }
|
|
373
375
|
function ditto_shutdown(...args) { return ditto.ditto_shutdown(...args) }
|
|
374
376
|
function ditto_start_http_server(...args) { return ditto.ditto_start_http_server(...args) }
|
|
@@ -406,9 +408,9 @@ var DittoCRDTType;
|
|
|
406
408
|
DittoCRDTType[DittoCRDTType["rga"] = 3] = "rga";
|
|
407
409
|
DittoCRDTType[DittoCRDTType["rwMap"] = 4] = "rwMap";
|
|
408
410
|
})(DittoCRDTType || (DittoCRDTType = {}));
|
|
409
|
-
//
|
|
411
|
+
// -------------------------------------- Linux & Windows Transports Hack ------
|
|
410
412
|
// HACK: quick and dirty, wrap the internal BLE functions which
|
|
411
|
-
// are currently only used by the Node Linux build. See comment
|
|
413
|
+
// are currently only used by the Node Linux & Windows build. See comment
|
|
412
414
|
// in `sync.ts` -> `Ditto.applyPeerToPeerBluetoothLE()` for details.
|
|
413
415
|
function dittoAddInternalBLEClientTransport(ditto) {
|
|
414
416
|
{
|
|
@@ -643,6 +645,22 @@ function removeSubscription(ditto, collectionName, query, queryArgsCBOR, orderBy
|
|
|
643
645
|
const queryX = bytesFromString(query);
|
|
644
646
|
return ditto_remove_subscription(ditto, collectionNameX, queryX, queryArgsCBOR, orderBy, limit, offset);
|
|
645
647
|
}
|
|
648
|
+
/** @internal */
|
|
649
|
+
function experimentalAddDqlSubscription(ditto, query, queryArgsCBOR) {
|
|
650
|
+
ensureInitialized();
|
|
651
|
+
const queryBuffer = bytesFromString(query);
|
|
652
|
+
const statusCode = ditto_experimental_add_dql_subscription(ditto, queryBuffer, queryArgsCBOR);
|
|
653
|
+
if (statusCode !== 0)
|
|
654
|
+
throw new Error(errorMessage() || `ditto_experimental_add_dql_subscription() failed with error code: ${statusCode}`);
|
|
655
|
+
}
|
|
656
|
+
/** @internal */
|
|
657
|
+
function experimentalRemoveDqlSubscription(ditto, query, queryArgsCBOR) {
|
|
658
|
+
ensureInitialized();
|
|
659
|
+
const queryBuffer = bytesFromString(query);
|
|
660
|
+
const statusCode = ditto_experimental_remove_dql_subscription(ditto, queryBuffer, queryArgsCBOR);
|
|
661
|
+
if (statusCode !== 0)
|
|
662
|
+
throw new Error(errorMessage() || `ditto_experimental_remove_dql_subscription() failed with error code: ${statusCode}`);
|
|
663
|
+
}
|
|
646
664
|
// ------------------------------------------------------------ LiveQuery ------
|
|
647
665
|
/** @internal */
|
|
648
666
|
function liveQueryRegister(ditto, collectionName, query, queryArgsCBOR, orderBy, limit, offset, eventHandler,
|
|
@@ -729,24 +747,10 @@ async function writeTransactionRollback(ditto, transaction) {
|
|
|
729
747
|
if (errorCode !== 0)
|
|
730
748
|
throw new Error(errorMessage() || `ditto_write_transaction_rollback() failed with error code: ${errorCode}`);
|
|
731
749
|
}
|
|
732
|
-
// ------------------------------------------------------ StaticTCPClient ------
|
|
733
|
-
/** @internal */
|
|
734
|
-
function addStaticTCPClient(ditto, address) {
|
|
735
|
-
ensureInitialized();
|
|
736
|
-
const addressBuffer = bytesFromString(address);
|
|
737
|
-
return ditto_add_static_tcp_client(ditto, addressBuffer);
|
|
738
|
-
}
|
|
739
750
|
/** @internal */
|
|
740
751
|
function staticTCPClientFreeHandle(self) {
|
|
741
752
|
static_tcp_client_free_handle(self);
|
|
742
753
|
}
|
|
743
|
-
// ------------------------------------------------------ WebsocketClient ------
|
|
744
|
-
/** @internal */
|
|
745
|
-
function addWebsocketClient(ditto, address, routingHint) {
|
|
746
|
-
ensureInitialized();
|
|
747
|
-
const addressBuffer = bytesFromString(address);
|
|
748
|
-
return ditto_add_websocket_client(ditto, addressBuffer, routingHint);
|
|
749
|
-
}
|
|
750
754
|
/** @internal */
|
|
751
755
|
function websocketClientFreeHandle(self) {
|
|
752
756
|
ensureInitialized();
|
|
@@ -1140,6 +1144,20 @@ async function dittoDisableSyncWithV3(dittoPointer) {
|
|
|
1140
1144
|
if (errorCode !== 0)
|
|
1141
1145
|
throw new Error(errorMessage() || `ditto_disable_sync_with_v3() failed with error code: ${errorCode}`);
|
|
1142
1146
|
}
|
|
1147
|
+
function dittoSetStaticTCPClients(ditto, listOfServers) {
|
|
1148
|
+
ensureInitialized();
|
|
1149
|
+
// TODO(Vincent): add error handling.
|
|
1150
|
+
{
|
|
1151
|
+
const listOfServersBytes = listOfServers.map((server) => bytesFromString(server));
|
|
1152
|
+
ditto_set_static_tcp_clients(ditto, listOfServersBytes);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
function dittoSetStaticWebsocketClients(ditto, listOfServers, routingHint) {
|
|
1156
|
+
ensureInitialized();
|
|
1157
|
+
// TODO(Vincent): add error handling.
|
|
1158
|
+
const listOfServersBytes = listOfServers.map((server) => bytesFromString(server));
|
|
1159
|
+
ditto_set_static_websocket_clients(ditto, listOfServersBytes, routingHint);
|
|
1160
|
+
}
|
|
1143
1161
|
// ------------------------------------------------------ Hash & Mnemonic ------
|
|
1144
1162
|
/** @internal */
|
|
1145
1163
|
function documentsHash(documents) {
|
|
@@ -1452,7 +1470,7 @@ function awdlDestroy(awdl) {
|
|
|
1452
1470
|
|
|
1453
1471
|
// NOTE: this is patched up with the actual build version by Jake task
|
|
1454
1472
|
// build:package and has to be a valid semantic version as defined here: https://semver.org.
|
|
1455
|
-
const fullBuildVersionString = '4.
|
|
1473
|
+
const fullBuildVersionString = '4.2.0';
|
|
1456
1474
|
|
|
1457
1475
|
//
|
|
1458
1476
|
/**
|
|
@@ -5221,6 +5239,125 @@ function collectionsFromDocuments(documents, store) {
|
|
|
5221
5239
|
return collections;
|
|
5222
5240
|
}
|
|
5223
5241
|
|
|
5242
|
+
//
|
|
5243
|
+
/**
|
|
5244
|
+
* Manages `ExperimentalSubscription` instances and removes them when Ditto is
|
|
5245
|
+
* closed.
|
|
5246
|
+
*
|
|
5247
|
+
* @internal
|
|
5248
|
+
*/
|
|
5249
|
+
class ExperimentalSubscriptionManager {
|
|
5250
|
+
constructor(ditto) {
|
|
5251
|
+
this.subscriptions = {};
|
|
5252
|
+
this.finalizationRegistry = new FinalizationRegistry(this.removeWithContextInfo.bind(this));
|
|
5253
|
+
this.ditto = ditto;
|
|
5254
|
+
}
|
|
5255
|
+
/**
|
|
5256
|
+
* Begin tracking a subscription instance and start it.
|
|
5257
|
+
*
|
|
5258
|
+
* @internal
|
|
5259
|
+
*/
|
|
5260
|
+
addSubscription(subscription) {
|
|
5261
|
+
if (this.subscriptions[subscription.contextInfo.id] != null) {
|
|
5262
|
+
throw new Error(`Internal inconsistency, tried to add a subscription that is already tracked: ${subscription.contextInfo.id}`);
|
|
5263
|
+
}
|
|
5264
|
+
const dittoHandle = Bridge.ditto.handleFor(this.ditto);
|
|
5265
|
+
this.ditto.deferClose(() => {
|
|
5266
|
+
experimentalAddDqlSubscription(dittoHandle.deref(), subscription.query, subscription.queryArgsCBOR);
|
|
5267
|
+
});
|
|
5268
|
+
// Only track the subscription after it has been successfully added to Ditto
|
|
5269
|
+
// to avoid tracking a subscription that failed to start.
|
|
5270
|
+
this.subscriptions[subscription.contextInfo.id] = new WeakRef(subscription);
|
|
5271
|
+
this.finalizationRegistry.register(subscription, subscription.contextInfo, subscription);
|
|
5272
|
+
}
|
|
5273
|
+
/**
|
|
5274
|
+
* Stop tracking a subscription instance and cancel it.
|
|
5275
|
+
*
|
|
5276
|
+
* @internal
|
|
5277
|
+
*/
|
|
5278
|
+
removeSubscription(subscription) {
|
|
5279
|
+
if (this.subscriptions[subscription.contextInfo.id] == null) {
|
|
5280
|
+
throw new Error(`Internal inconsistency, tried to remove a subscription that is not tracked: ${subscription.contextInfo.id}`);
|
|
5281
|
+
}
|
|
5282
|
+
this.finalizationRegistry.unregister(subscription);
|
|
5283
|
+
delete this.subscriptions[subscription.contextInfo.id];
|
|
5284
|
+
this.removeWithContextInfo(subscription.contextInfo);
|
|
5285
|
+
}
|
|
5286
|
+
/**
|
|
5287
|
+
* Stop tracking all subscriptions and cancel them.
|
|
5288
|
+
*
|
|
5289
|
+
* @internal
|
|
5290
|
+
*/
|
|
5291
|
+
close() {
|
|
5292
|
+
Logger.debug(`ExperimentalSubscriptionManager.close() with ${this.subscriptions.length} queries`);
|
|
5293
|
+
this.ditto.deferClose(() => {
|
|
5294
|
+
var _a;
|
|
5295
|
+
for (const subscriptionWeakRef of Object.values(this.subscriptions)) {
|
|
5296
|
+
// If this deref fails, the garbage collector has already removed the
|
|
5297
|
+
// subscription and will issue a finalization callback to
|
|
5298
|
+
// `removeWithContextInfo()`.
|
|
5299
|
+
(_a = subscriptionWeakRef.deref()) === null || _a === void 0 ? void 0 : _a.cancel();
|
|
5300
|
+
}
|
|
5301
|
+
});
|
|
5302
|
+
}
|
|
5303
|
+
/**
|
|
5304
|
+
* Remove tracked subscription without unregistering from finalization
|
|
5305
|
+
* registry.
|
|
5306
|
+
*
|
|
5307
|
+
* @internal
|
|
5308
|
+
*/
|
|
5309
|
+
removeWithContextInfo(contextInfo) {
|
|
5310
|
+
const dittoHandle = Bridge.ditto.handleFor(this.ditto);
|
|
5311
|
+
this.ditto.deferClose(() => {
|
|
5312
|
+
experimentalRemoveDqlSubscription(dittoHandle.deref(), contextInfo.query, contextInfo.queryArgsCBOR);
|
|
5313
|
+
delete this.subscriptions[contextInfo.id];
|
|
5314
|
+
});
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5317
|
+
|
|
5318
|
+
//
|
|
5319
|
+
/**
|
|
5320
|
+
* Create a subscription to receive updates from remote peers about documents
|
|
5321
|
+
* matching the subscription's query.
|
|
5322
|
+
*
|
|
5323
|
+
* The subscription will remain active until {@link cancel | cancel()} is called
|
|
5324
|
+
* or the subscription object goes out of scope and is garbage collected.
|
|
5325
|
+
*
|
|
5326
|
+
* @internal
|
|
5327
|
+
*/
|
|
5328
|
+
class ExperimentalSubscription {
|
|
5329
|
+
/**
|
|
5330
|
+
* Cancels a subscription and releases all associated resources.
|
|
5331
|
+
*/
|
|
5332
|
+
cancel() {
|
|
5333
|
+
if (!this.isCancelled) {
|
|
5334
|
+
this['isCancelled'] = true;
|
|
5335
|
+
this.manager.removeSubscription(this);
|
|
5336
|
+
}
|
|
5337
|
+
}
|
|
5338
|
+
// --------------------------- Internal --------------------------------------
|
|
5339
|
+
/** @internal */
|
|
5340
|
+
constructor(manager, query, queryArgsCBOR) {
|
|
5341
|
+
/**
|
|
5342
|
+
* `true` when {@link cancel | cancel()} has been called or the Ditto instance
|
|
5343
|
+
* managing this subscription has been closed.
|
|
5344
|
+
*/
|
|
5345
|
+
// Recording this information on the subscription instance itself allows
|
|
5346
|
+
// working with it even after Ditto has been closed and the subscription
|
|
5347
|
+
// manager can not be accessed anymore.
|
|
5348
|
+
this.isCancelled = false;
|
|
5349
|
+
this.query = query;
|
|
5350
|
+
this.queryArgsCBOR = queryArgsCBOR;
|
|
5351
|
+
this.contextInfo = {
|
|
5352
|
+
id: generateEphemeralToken(),
|
|
5353
|
+
query,
|
|
5354
|
+
queryArgsCBOR,
|
|
5355
|
+
};
|
|
5356
|
+
this.manager = manager;
|
|
5357
|
+
manager.addSubscription(this);
|
|
5358
|
+
}
|
|
5359
|
+
}
|
|
5360
|
+
|
|
5224
5361
|
//
|
|
5225
5362
|
/**
|
|
5226
5363
|
* An addon for the Ditto store that contains experimental features. Accessible
|
|
@@ -5232,21 +5369,28 @@ class ExperimentalStore {
|
|
|
5232
5369
|
/** @internal */
|
|
5233
5370
|
constructor(ditto) {
|
|
5234
5371
|
this.ditto = ditto;
|
|
5372
|
+
this.subscriptionManager = new ExperimentalSubscriptionManager(this.ditto);
|
|
5373
|
+
}
|
|
5374
|
+
/** @internal */
|
|
5375
|
+
close() {
|
|
5376
|
+
this.subscriptionManager.close();
|
|
5235
5377
|
}
|
|
5236
5378
|
/**
|
|
5237
5379
|
* Executes the given query in the local store and returns the result.
|
|
5238
5380
|
*
|
|
5239
5381
|
* Limitations:
|
|
5240
5382
|
*
|
|
5241
|
-
* -
|
|
5242
|
-
*
|
|
5383
|
+
* - Supports `SELECT * FROM <collection name>` with optional `WHERE
|
|
5384
|
+
* <expression>`
|
|
5385
|
+
* - No query parameters as function arguments yet
|
|
5243
5386
|
* - No transactions
|
|
5244
5387
|
*
|
|
5245
5388
|
* @internal
|
|
5246
5389
|
* @param query a Ditto Query Language query string
|
|
5247
5390
|
* @returns a promise for an array of Ditto documents matching the query
|
|
5248
|
-
|
|
5391
|
+
*/
|
|
5249
5392
|
async execute(query) {
|
|
5393
|
+
Logger.debug(`ExperimentalStore.execute(query = ${query})`);
|
|
5250
5394
|
const ditto = this.ditto;
|
|
5251
5395
|
const dittoHandle = Bridge.ditto.handleFor(ditto);
|
|
5252
5396
|
return ditto.deferCloseAsync(async () => {
|
|
@@ -5261,9 +5405,21 @@ class ExperimentalStore {
|
|
|
5261
5405
|
return documentPointers.map((documentPointer) => Bridge.document.bridge(documentPointer));
|
|
5262
5406
|
});
|
|
5263
5407
|
}
|
|
5264
|
-
/**
|
|
5265
|
-
|
|
5266
|
-
|
|
5408
|
+
/**
|
|
5409
|
+
* Subscribes the device to updates specified by a DQL query to collections
|
|
5410
|
+
* that other devices know about.
|
|
5411
|
+
*
|
|
5412
|
+
* The returned {@link ExperimentalSubscription} object must be kept in scope
|
|
5413
|
+
* for as long as you want to keep receiving updates.
|
|
5414
|
+
*
|
|
5415
|
+
* @internal
|
|
5416
|
+
* @param query a Ditto Query Language query string of the form SELECT * FROM
|
|
5417
|
+
* collection WHERE expression
|
|
5418
|
+
* @returns {@link ExperimentalSubscription} object
|
|
5419
|
+
*/
|
|
5420
|
+
subscribe(query) {
|
|
5421
|
+
Logger.debug(`ExperimentalStore.subscribe(query = ${query})`);
|
|
5422
|
+
return new ExperimentalSubscription(this.subscriptionManager, query, null);
|
|
5267
5423
|
}
|
|
5268
5424
|
}
|
|
5269
5425
|
|
|
@@ -6031,8 +6187,6 @@ class Sync {
|
|
|
6031
6187
|
this.ditto = ditto;
|
|
6032
6188
|
this.parameters = parameters;
|
|
6033
6189
|
this.state = stateFrom(parameters);
|
|
6034
|
-
this.staticTCPClientsByAddress = {};
|
|
6035
|
-
this.websocketClientsByURL = {};
|
|
6036
6190
|
}
|
|
6037
6191
|
update(parameters) {
|
|
6038
6192
|
this['parameters'] = { ...parameters };
|
|
@@ -6216,70 +6370,17 @@ class Sync {
|
|
|
6216
6370
|
const ditto = this.ditto;
|
|
6217
6371
|
const dittoHandle = Bridge.ditto.handleFor(ditto);
|
|
6218
6372
|
ditto.deferClose(() => {
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
const desiredTCPServers = stateNew.effectiveTransportConfig.connect.tcpServers;
|
|
6222
|
-
const tcpServersToConnectToSet = new Set(desiredTCPServers);
|
|
6223
|
-
for (const tcpServer of currentTCPServers)
|
|
6224
|
-
tcpServersToConnectToSet.delete(tcpServer);
|
|
6225
|
-
const tcpServersToDisconnectFromSet = new Set(currentTCPServers);
|
|
6226
|
-
for (const tcpServer of desiredTCPServers)
|
|
6227
|
-
tcpServersToDisconnectFromSet.delete(tcpServer);
|
|
6228
|
-
const tcpServersToConnectTo = tcpServersToConnectToSet.values();
|
|
6229
|
-
const tcpServersToDisconnectFrom = tcpServersToDisconnectFromSet.values();
|
|
6230
|
-
for (const tcpServer of tcpServersToConnectTo) {
|
|
6231
|
-
const staticTCPClientPointer = addStaticTCPClient(dittoHandle.deref(), tcpServer);
|
|
6232
|
-
const staticTCPClient = Bridge.staticTCPClient.bridge(staticTCPClientPointer);
|
|
6233
|
-
this.staticTCPClientsByAddress[tcpServer] = staticTCPClient;
|
|
6234
|
-
}
|
|
6235
|
-
for (const tcpServer of tcpServersToDisconnectFrom) {
|
|
6236
|
-
// REFACTOR: we have to make sure freeing the tcpServer handle is done
|
|
6237
|
-
// BEFORE the Ditto instance itself is freed.
|
|
6238
|
-
const staticTCPClient = this.staticTCPClientsByAddress[tcpServer];
|
|
6239
|
-
if (!staticTCPClient)
|
|
6240
|
-
throw new Error(`Internal inconsistency, can't disconnect from TCP address '${tcpServer}', no staticTCPClient found.`);
|
|
6241
|
-
const staticTCPClientPointer = Bridge.staticTCPClient.handleFor(staticTCPClient).deref();
|
|
6242
|
-
// Unregister to avoid double-free for this pointer, then free manually:
|
|
6243
|
-
Bridge.staticTCPClient.unregister(staticTCPClient);
|
|
6244
|
-
staticTCPClientFreeHandle(staticTCPClientPointer);
|
|
6245
|
-
delete this.staticTCPClientsByAddress[tcpServer];
|
|
6246
|
-
}
|
|
6373
|
+
const tcpServers = stateNew.effectiveTransportConfig.connect.tcpServers;
|
|
6374
|
+
dittoSetStaticTCPClients(dittoHandle.deref(), tcpServers);
|
|
6247
6375
|
});
|
|
6248
6376
|
}
|
|
6249
6377
|
updateConnectWebsocketURLs(stateOld, stateNew) {
|
|
6250
6378
|
const ditto = this.ditto;
|
|
6251
6379
|
const dittoHandle = Bridge.ditto.handleFor(ditto);
|
|
6252
6380
|
ditto.deferClose(() => {
|
|
6253
|
-
|
|
6254
|
-
// IDEA: normalize URLs so that we don't connect to the same URL twice?
|
|
6255
|
-
const currentWebsocketURLs = Object.getOwnPropertyNames(this.websocketClientsByURL);
|
|
6256
|
-
const desiredWebsocketURLs = stateNew.effectiveTransportConfig.connect.websocketURLs.slice();
|
|
6257
|
-
const websocketURLsToConnectToSet = new Set(desiredWebsocketURLs);
|
|
6258
|
-
for (const websocketURL of currentWebsocketURLs)
|
|
6259
|
-
websocketURLsToConnectToSet.delete(websocketURL);
|
|
6260
|
-
const websocketURLsToDisconnectFromSet = new Set(currentWebsocketURLs);
|
|
6261
|
-
for (const websocketURL of desiredWebsocketURLs)
|
|
6262
|
-
websocketURLsToDisconnectFromSet.delete(websocketURL);
|
|
6263
|
-
const websocketURLsToConnectTo = websocketURLsToConnectToSet.values();
|
|
6264
|
-
const websocketURLsToDisconnectFrom = websocketURLsToDisconnectFromSet.values();
|
|
6381
|
+
const websocketURLs = stateNew.effectiveTransportConfig.connect.websocketURLs;
|
|
6265
6382
|
const routingHint = stateNew.effectiveTransportConfig.global.routingHint;
|
|
6266
|
-
|
|
6267
|
-
const websocketClientPointer = addWebsocketClient(dittoHandle.deref(), websocketURL, routingHint);
|
|
6268
|
-
const websocketClient = Bridge.websocketClient.bridge(websocketClientPointer);
|
|
6269
|
-
this.websocketClientsByURL[websocketURL] = websocketClient;
|
|
6270
|
-
}
|
|
6271
|
-
for (const websocketURL of websocketURLsToDisconnectFrom) {
|
|
6272
|
-
// REFACTOR: we have to make sure freeing the websocket handle is done
|
|
6273
|
-
// BEFORE the Ditto instance itself is freed.
|
|
6274
|
-
const websocketClient = this.websocketClientsByURL[websocketURL];
|
|
6275
|
-
if (!websocketClient)
|
|
6276
|
-
throw new Error(`Internal inconsistency, can't disconnect from websocket URL '${websocketURL}', no websocketClient found.`);
|
|
6277
|
-
const websocketClientPointer = Bridge.websocketClient.handleFor(websocketClient).deref();
|
|
6278
|
-
// Unregister to avoid double-free for this pointer, then free manually:
|
|
6279
|
-
Bridge.websocketClient.unregister(websocketClient);
|
|
6280
|
-
websocketClientFreeHandle(websocketClientPointer);
|
|
6281
|
-
delete this.websocketClientsByURL[websocketURL];
|
|
6282
|
-
}
|
|
6383
|
+
dittoSetStaticWebsocketClients(dittoHandle.deref(), websocketURLs, routingHint);
|
|
6283
6384
|
});
|
|
6284
6385
|
}
|
|
6285
6386
|
updateGlobal(stateOld, stateNew) {
|
|
@@ -6381,7 +6482,7 @@ class SubscriptionManager {
|
|
|
6381
6482
|
constructor(ditto) {
|
|
6382
6483
|
this.ditto = ditto;
|
|
6383
6484
|
this.subscriptions = {};
|
|
6384
|
-
this.finalizationRegistry = new FinalizationRegistry(this.
|
|
6485
|
+
this.finalizationRegistry = new FinalizationRegistry(this.removeWithContextInfo.bind(this));
|
|
6385
6486
|
}
|
|
6386
6487
|
/**
|
|
6387
6488
|
* Begin tracking a subscription instance and start it.
|
|
@@ -6406,7 +6507,7 @@ class SubscriptionManager {
|
|
|
6406
6507
|
throw new Error(`Internal inconsistency, tried to remove a subscription that is not tracked: ${subscription.contextInfo.id}`);
|
|
6407
6508
|
}
|
|
6408
6509
|
this.finalizationRegistry.unregister(subscription);
|
|
6409
|
-
this.
|
|
6510
|
+
this.removeWithContextInfo(subscription.contextInfo);
|
|
6410
6511
|
}
|
|
6411
6512
|
/**
|
|
6412
6513
|
* Stop tracking all subscriptions and cancel them.
|
|
@@ -6429,7 +6530,7 @@ class SubscriptionManager {
|
|
|
6429
6530
|
* registry.
|
|
6430
6531
|
*
|
|
6431
6532
|
* @internal */
|
|
6432
|
-
|
|
6533
|
+
removeWithContextInfo(contextInfo) {
|
|
6433
6534
|
const ditto = this.ditto;
|
|
6434
6535
|
const dittoHandle = Bridge.ditto.handleFor(ditto);
|
|
6435
6536
|
ditto.deferClose(() => {
|
|
@@ -6732,8 +6833,13 @@ class Ditto {
|
|
|
6732
6833
|
})();
|
|
6733
6834
|
const dittoPointer = dittoMake(uninitializedDittoX, identityConfig);
|
|
6734
6835
|
dittoAuthClientSetValidityListener(dittoPointer, function (...args) {
|
|
6735
|
-
|
|
6736
|
-
|
|
6836
|
+
const ditto = weakThis.deref();
|
|
6837
|
+
if (ditto == null || ditto.isClosed) {
|
|
6838
|
+
Logger.info('Ditto is closed, ignoring auth client validity change');
|
|
6839
|
+
}
|
|
6840
|
+
else {
|
|
6841
|
+
ditto.authClientValidityChanged(...args);
|
|
6842
|
+
}
|
|
6737
6843
|
});
|
|
6738
6844
|
const isWebValid = dittoAuthClientIsWebValid(dittoPointer);
|
|
6739
6845
|
const isX509Valid = dittoAuthClientIsX509Valid(dittoPointer);
|
|
@@ -7244,7 +7350,8 @@ const disableDeadlockTimeoutWhenDebugging = () => {
|
|
|
7244
7350
|
*
|
|
7245
7351
|
* Use this in testing to ensure that all objects are properly garbage collected at the end of tests.
|
|
7246
7352
|
*
|
|
7247
|
-
* @returns an object with a key per bridge type,
|
|
7353
|
+
* @returns an object with a key per bridge type, set to the count of registered
|
|
7354
|
+
* objects.
|
|
7248
7355
|
*/
|
|
7249
7356
|
function getBridgeLoad() {
|
|
7250
7357
|
const countsByType = {};
|
|
@@ -7300,6 +7407,8 @@ exports.Document = Document;
|
|
|
7300
7407
|
exports.DocumentID = DocumentID;
|
|
7301
7408
|
exports.DocumentPath = DocumentPath;
|
|
7302
7409
|
exports.ExperimentalStore = ExperimentalStore;
|
|
7410
|
+
exports.ExperimentalSubscription = ExperimentalSubscription;
|
|
7411
|
+
exports.ExperimentalSubscriptionManager = ExperimentalSubscriptionManager;
|
|
7303
7412
|
exports.IdentityTypesRequiringOfflineLicenseToken = IdentityTypesRequiringOfflineLicenseToken;
|
|
7304
7413
|
exports.KeepAlive = KeepAlive;
|
|
7305
7414
|
exports.LiveQuery = LiveQuery;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dittolive/ditto",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Ditto is a cross-platform embeddable NoSQL database that can sync with or without an internet connection.",
|
|
5
5
|
"homepage": "https://ditto.live",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
package/types/ditto.d.ts
CHANGED
|
@@ -1348,7 +1348,7 @@ declare class SubscriptionManager {
|
|
|
1348
1348
|
* registry.
|
|
1349
1349
|
*
|
|
1350
1350
|
* @internal */
|
|
1351
|
-
private
|
|
1351
|
+
private removeWithContextInfo;
|
|
1352
1352
|
}
|
|
1353
1353
|
|
|
1354
1354
|
/**
|
|
@@ -2638,6 +2638,94 @@ declare class PendingCollectionsOperation implements PromiseLike<Collection[]> {
|
|
|
2638
2638
|
private readonly pendingCursorOperation;
|
|
2639
2639
|
}
|
|
2640
2640
|
|
|
2641
|
+
/**
|
|
2642
|
+
* Manages `ExperimentalSubscription` instances and removes them when Ditto is
|
|
2643
|
+
* closed.
|
|
2644
|
+
*
|
|
2645
|
+
* @internal
|
|
2646
|
+
*/
|
|
2647
|
+
declare class ExperimentalSubscriptionManager {
|
|
2648
|
+
constructor(ditto: Ditto);
|
|
2649
|
+
/**
|
|
2650
|
+
* Begin tracking a subscription instance and start it.
|
|
2651
|
+
*
|
|
2652
|
+
* @internal
|
|
2653
|
+
*/
|
|
2654
|
+
addSubscription(subscription: ExperimentalSubscription): void;
|
|
2655
|
+
/**
|
|
2656
|
+
* Stop tracking a subscription instance and cancel it.
|
|
2657
|
+
*
|
|
2658
|
+
* @internal
|
|
2659
|
+
*/
|
|
2660
|
+
removeSubscription(subscription: ExperimentalSubscription): void;
|
|
2661
|
+
/**
|
|
2662
|
+
* Stop tracking all subscriptions and cancel them.
|
|
2663
|
+
*
|
|
2664
|
+
* @internal
|
|
2665
|
+
*/
|
|
2666
|
+
close(): void;
|
|
2667
|
+
private readonly ditto;
|
|
2668
|
+
private subscriptions;
|
|
2669
|
+
private finalizationRegistry;
|
|
2670
|
+
/**
|
|
2671
|
+
* Remove tracked subscription without unregistering from finalization
|
|
2672
|
+
* registry.
|
|
2673
|
+
*
|
|
2674
|
+
* @internal
|
|
2675
|
+
*/
|
|
2676
|
+
private removeWithContextInfo;
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
/**
|
|
2680
|
+
* Contains all information required to deregister a subscription
|
|
2681
|
+
* in Ditto Core, even when the subscription instance itself has
|
|
2682
|
+
* already been garbage collected.
|
|
2683
|
+
*
|
|
2684
|
+
* @internal
|
|
2685
|
+
*/
|
|
2686
|
+
type ExperimentalSubscriptionContextInfo = {
|
|
2687
|
+
/** Unique ID per `ExperimentalSubscription` instance. */
|
|
2688
|
+
id: string;
|
|
2689
|
+
query: string;
|
|
2690
|
+
queryArgsCBOR: Uint8Array | null;
|
|
2691
|
+
};
|
|
2692
|
+
/**
|
|
2693
|
+
* Create a subscription to receive updates from remote peers about documents
|
|
2694
|
+
* matching the subscription's query.
|
|
2695
|
+
*
|
|
2696
|
+
* The subscription will remain active until {@link cancel | cancel()} is called
|
|
2697
|
+
* or the subscription object goes out of scope and is garbage collected.
|
|
2698
|
+
*
|
|
2699
|
+
* @internal
|
|
2700
|
+
*/
|
|
2701
|
+
declare class ExperimentalSubscription {
|
|
2702
|
+
/**
|
|
2703
|
+
* Documents matching this query will be included in the subscription.
|
|
2704
|
+
*/
|
|
2705
|
+
readonly query: string;
|
|
2706
|
+
/**
|
|
2707
|
+
* `true` when {@link cancel | cancel()} has been called or the Ditto instance
|
|
2708
|
+
* managing this subscription has been closed.
|
|
2709
|
+
*/
|
|
2710
|
+
readonly isCancelled = false;
|
|
2711
|
+
/**
|
|
2712
|
+
* Cancels a subscription and releases all associated resources.
|
|
2713
|
+
*/
|
|
2714
|
+
cancel(): void;
|
|
2715
|
+
/** @internal */
|
|
2716
|
+
constructor(manager: ExperimentalSubscriptionManager, query: string, queryArgsCBOR: Uint8Array | null);
|
|
2717
|
+
/** @internal */
|
|
2718
|
+
contextInfo: ExperimentalSubscriptionContextInfo;
|
|
2719
|
+
/**
|
|
2720
|
+
* The corresponding named arguments for {@link query}, if any.
|
|
2721
|
+
*
|
|
2722
|
+
* @internal
|
|
2723
|
+
*/
|
|
2724
|
+
readonly queryArgsCBOR: Uint8Array | null;
|
|
2725
|
+
/** @internal */
|
|
2726
|
+
private manager;
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2641
2729
|
/**
|
|
2642
2730
|
* An addon for the Ditto store that contains experimental features. Accessible
|
|
2643
2731
|
* on `ditto.store.experimental`.
|
|
@@ -2652,22 +2740,37 @@ declare class ExperimentalStore {
|
|
|
2652
2740
|
readonly ditto: Ditto;
|
|
2653
2741
|
/** @internal */
|
|
2654
2742
|
constructor(ditto: Ditto);
|
|
2743
|
+
/** @internal */
|
|
2744
|
+
close(): void;
|
|
2655
2745
|
/**
|
|
2656
2746
|
* Executes the given query in the local store and returns the result.
|
|
2657
2747
|
*
|
|
2658
2748
|
* Limitations:
|
|
2659
2749
|
*
|
|
2660
|
-
* -
|
|
2661
|
-
*
|
|
2750
|
+
* - Supports `SELECT * FROM <collection name>` with optional `WHERE
|
|
2751
|
+
* <expression>`
|
|
2752
|
+
* - No query parameters as function arguments yet
|
|
2662
2753
|
* - No transactions
|
|
2663
2754
|
*
|
|
2664
2755
|
* @internal
|
|
2665
2756
|
* @param query a Ditto Query Language query string
|
|
2666
2757
|
* @returns a promise for an array of Ditto documents matching the query
|
|
2667
|
-
|
|
2758
|
+
*/
|
|
2668
2759
|
execute(query: string): Promise<Document[]>;
|
|
2669
|
-
/**
|
|
2670
|
-
|
|
2760
|
+
/**
|
|
2761
|
+
* Subscribes the device to updates specified by a DQL query to collections
|
|
2762
|
+
* that other devices know about.
|
|
2763
|
+
*
|
|
2764
|
+
* The returned {@link ExperimentalSubscription} object must be kept in scope
|
|
2765
|
+
* for as long as you want to keep receiving updates.
|
|
2766
|
+
*
|
|
2767
|
+
* @internal
|
|
2768
|
+
* @param query a Ditto Query Language query string of the form SELECT * FROM
|
|
2769
|
+
* collection WHERE expression
|
|
2770
|
+
* @returns {@link ExperimentalSubscription} object
|
|
2771
|
+
*/
|
|
2772
|
+
subscribe(query: string): ExperimentalSubscription;
|
|
2773
|
+
private subscriptionManager;
|
|
2671
2774
|
}
|
|
2672
2775
|
|
|
2673
2776
|
/**
|
|
@@ -3048,7 +3151,8 @@ declare abstract class BasePendingCursorOperation implements PromiseLike<Documen
|
|
|
3048
3151
|
*
|
|
3049
3152
|
* Use this in testing to ensure that all objects are properly garbage collected at the end of tests.
|
|
3050
3153
|
*
|
|
3051
|
-
* @returns an object with a key per bridge type,
|
|
3154
|
+
* @returns an object with a key per bridge type, set to the count of registered
|
|
3155
|
+
* objects.
|
|
3052
3156
|
*/
|
|
3053
3157
|
declare function getBridgeLoad(): {
|
|
3054
3158
|
[bridgeName: string]: number;
|
|
@@ -3062,5 +3166,5 @@ declare class CBOR {
|
|
|
3062
3166
|
static decode(data: Uint8Array): any;
|
|
3063
3167
|
}
|
|
3064
3168
|
|
|
3065
|
-
export { Address, Attachment, AttachmentFetchEvent, AttachmentFetchEventCompleted, AttachmentFetchEventDeleted, AttachmentFetchEventProgress, AttachmentFetchEventType, AttachmentFetcher, AttachmentToken, AuthenticationHandler, AuthenticationStatus, Authenticator, BasePendingCursorOperation, BasePendingIDSpecificOperation, CBOR, Collection, CollectionInterface, CollectionsEvent, CollectionsEventParams, CollectionsObservationHandler, ConditionSource, Connection, ConnectionType, Counter, CustomLogCallback, Ditto, Document, DocumentID, DocumentIDValue, DocumentPath, DocumentValue, ExperimentalStore, Identity, IdentityManual, IdentityOfflinePlayground, IdentityOnlinePlayground, IdentityOnlineWithAuthentication, IdentitySharedKey, IdentityTypesRequiringOfflineLicenseToken, InitOptions, KeepAlive, LiveQuery, LiveQueryEvent, LiveQueryEventInitial, LiveQueryEventUpdate, LiveQueryEventUpdateParams, LiveQueryMove, LogLevel, Logger, MutableCounter, MutableDocument, MutableDocumentPath, MutableRegister, NotAvailableAuthenticator, Observer, ObserverOptions, OnlineAuthenticator, Peer, PendingCollectionsOperation, PendingCursorOperation, PendingIDSpecificOperation, Presence, PresenceConnectionType, PresenceGraph, QueryArguments, QueryObservationHandler, Register, RemotePeer, SingleDocumentLiveQueryEvent, SingleObservationHandler, SortDirection, Store, Subscription, TransportCondition, TransportConfig, TransportConfigConnect, TransportConfigGlobal, TransportConfigLan, TransportConfigListen, TransportConfigListenHTTP, TransportConfigListenTCP, TransportConfigPeerToPeer, UpdateResult, UpdateResultType, UpdateResultsMap, UpsertOptions, Value, WebAssemblyModule, WriteStrategy, WriteTransaction, WriteTransactionCollection, WriteTransactionPendingCursorOperation, WriteTransactionPendingIDSpecificOperation, WriteTransactionResult, addressToString, checkAPIs, disableDeadlockTimeoutWhenDebugging, getBridgeLoad, init, validateDocumentIDCBOR, validateDocumentIDValue };
|
|
3169
|
+
export { Address, Attachment, AttachmentFetchEvent, AttachmentFetchEventCompleted, AttachmentFetchEventDeleted, AttachmentFetchEventProgress, AttachmentFetchEventType, AttachmentFetcher, AttachmentToken, AuthenticationHandler, AuthenticationStatus, Authenticator, BasePendingCursorOperation, BasePendingIDSpecificOperation, CBOR, Collection, CollectionInterface, CollectionsEvent, CollectionsEventParams, CollectionsObservationHandler, ConditionSource, Connection, ConnectionType, Counter, CustomLogCallback, Ditto, Document, DocumentID, DocumentIDValue, DocumentPath, DocumentValue, ExperimentalStore, ExperimentalSubscription, ExperimentalSubscriptionContextInfo, ExperimentalSubscriptionManager, Identity, IdentityManual, IdentityOfflinePlayground, IdentityOnlinePlayground, IdentityOnlineWithAuthentication, IdentitySharedKey, IdentityTypesRequiringOfflineLicenseToken, InitOptions, KeepAlive, LiveQuery, LiveQueryEvent, LiveQueryEventInitial, LiveQueryEventUpdate, LiveQueryEventUpdateParams, LiveQueryMove, LogLevel, Logger, MutableCounter, MutableDocument, MutableDocumentPath, MutableRegister, NotAvailableAuthenticator, Observer, ObserverOptions, OnlineAuthenticator, Peer, PendingCollectionsOperation, PendingCursorOperation, PendingIDSpecificOperation, Presence, PresenceConnectionType, PresenceGraph, QueryArguments, QueryObservationHandler, Register, RemotePeer, SingleDocumentLiveQueryEvent, SingleObservationHandler, SortDirection, Store, Subscription, TransportCondition, TransportConfig, TransportConfigConnect, TransportConfigGlobal, TransportConfigLan, TransportConfigListen, TransportConfigListenHTTP, TransportConfigListenTCP, TransportConfigPeerToPeer, UpdateResult, UpdateResultType, UpdateResultsMap, UpsertOptions, Value, WebAssemblyModule, WriteStrategy, WriteTransaction, WriteTransactionCollection, WriteTransactionPendingCursorOperation, WriteTransactionPendingIDSpecificOperation, WriteTransactionResult, addressToString, checkAPIs, disableDeadlockTimeoutWhenDebugging, getBridgeLoad, init, validateDocumentIDCBOR, validateDocumentIDValue };
|
|
3066
3170
|
//# sourceMappingURL=ditto.d.ts.map
|