@squidcloud/client 1.0.113 → 1.0.115
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/dist/cjs/index.js +168 -107
- package/dist/common/src/bundle-api.types.d.ts +3 -0
- package/dist/common/src/socket.types.d.ts +5 -1
- package/dist/typescript-client/src/data.manager.d.ts +3 -1
- package/dist/typescript-client/src/mutation/mutation-sender.d.ts +3 -3
- package/dist/typescript-client/src/query/query-sender.d.ts +33 -0
- package/dist/typescript-client/src/query/query-subscription.manager.d.ts +9 -65
- package/dist/typescript-client/src/query/query.types.d.ts +49 -0
- package/dist/typescript-client/src/rpc.manager.d.ts +1 -4
- package/dist/typescript-client/src/socket.manager.d.ts +0 -1
- package/dist/typescript-client/src/squid.d.ts +1 -0
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -28869,33 +28869,28 @@ const ExecuteFunctionSecureAnnotations = (/* unused pure expression or super */
|
|
|
28869
28869
|
'secureAiAssistantMutation',
|
|
28870
28870
|
]));
|
|
28871
28871
|
/** @internal */
|
|
28872
|
-
function transformParams(
|
|
28872
|
+
function transformParams(params, executeFunctionAnnotationType) {
|
|
28873
28873
|
switch (executeFunctionAnnotationType) {
|
|
28874
|
-
case 'webhook':
|
|
28875
|
-
case 'executable':
|
|
28876
|
-
case 'trigger':
|
|
28877
|
-
case 'transformRead':
|
|
28878
|
-
case 'transformWrite':
|
|
28879
|
-
case 'metadata':
|
|
28880
|
-
return args;
|
|
28881
28874
|
case 'scheduler':
|
|
28882
28875
|
return [];
|
|
28883
28876
|
case 'secureQuery':
|
|
28884
|
-
return [new QueryContext(
|
|
28877
|
+
return [new QueryContext(params[0].query)];
|
|
28885
28878
|
case 'secureMutation':
|
|
28886
|
-
return [new MutationContext(
|
|
28879
|
+
return [new MutationContext(params[0].mutation, params[0].beforeAndAfterDocs, params[0].serverTimestamp)];
|
|
28887
28880
|
case 'secureNamedQuery':
|
|
28888
|
-
return [new NamedQueryContext(
|
|
28881
|
+
return [new NamedQueryContext(params[0])];
|
|
28889
28882
|
case 'secureDistributedLock':
|
|
28890
|
-
return [new DistributedLockContext(
|
|
28883
|
+
return [new DistributedLockContext(params[0].mutex, params[0].exclusive)];
|
|
28891
28884
|
case 'secureGraphQL':
|
|
28892
|
-
return [new GraphqlContext(
|
|
28885
|
+
return [new GraphqlContext(params[0])];
|
|
28893
28886
|
case 'secureApi':
|
|
28894
|
-
return [new ApiCallContext(
|
|
28887
|
+
return [new ApiCallContext(params[0])];
|
|
28895
28888
|
case 'secureAiAssistantChat':
|
|
28896
|
-
return [new AiAssistantChatContext(
|
|
28889
|
+
return [new AiAssistantChatContext(params[0])];
|
|
28897
28890
|
case 'secureAiAssistantMutation':
|
|
28898
|
-
return [new AiAssistantMutationContext(
|
|
28891
|
+
return [new AiAssistantMutationContext(params[0])];
|
|
28892
|
+
default:
|
|
28893
|
+
return params;
|
|
28899
28894
|
}
|
|
28900
28895
|
}
|
|
28901
28896
|
/** @internal */
|
|
@@ -29680,6 +29675,17 @@ const MessageFromClientSchema = {
|
|
|
29680
29675
|
],
|
|
29681
29676
|
};
|
|
29682
29677
|
|
|
29678
|
+
;// CONCATENATED MODULE: ../common/src/socket.types.ts
|
|
29679
|
+
var ClientConnectionState;
|
|
29680
|
+
(function (ClientConnectionState) {
|
|
29681
|
+
// The client just connected to the socket
|
|
29682
|
+
ClientConnectionState["CONNECTED"] = "CONNECTED";
|
|
29683
|
+
// The client disconnected from the socket but Squid still keeps the clientID in case the client reconnects
|
|
29684
|
+
ClientConnectionState["DISCONNECTED"] = "DISCONNECTED";
|
|
29685
|
+
// The client disconnected from the socket and Squid removed the clientID
|
|
29686
|
+
ClientConnectionState["REMOVED"] = "REMOVED";
|
|
29687
|
+
})(ClientConnectionState || (ClientConnectionState = {}));
|
|
29688
|
+
|
|
29683
29689
|
;// CONCATENATED MODULE: ../common/src/time-units.ts
|
|
29684
29690
|
/** @internal */
|
|
29685
29691
|
const SECONDS_PER_MINUTE = 60;
|
|
@@ -32806,7 +32812,7 @@ var promise_pool_dist = __webpack_require__(3910);
|
|
|
32806
32812
|
/** Two transactions cannot run in parallel - this mutex is used for blocking a second transaction. */
|
|
32807
32813
|
const RUN_IN_TRANSACTION_MUTEX = 'dataManager_runInTransaction';
|
|
32808
32814
|
class DataManager {
|
|
32809
|
-
constructor(documentStore, mutationSender, socketManager, querySubscriptionManager, queryBuilderFactory, lockManager, destructManager, documentIdentityService) {
|
|
32815
|
+
constructor(documentStore, mutationSender, socketManager, querySubscriptionManager, queryBuilderFactory, lockManager, destructManager, documentIdentityService, querySender) {
|
|
32810
32816
|
this.documentStore = documentStore;
|
|
32811
32817
|
this.mutationSender = mutationSender;
|
|
32812
32818
|
this.socketManager = socketManager;
|
|
@@ -32815,6 +32821,7 @@ class DataManager {
|
|
|
32815
32821
|
this.lockManager = lockManager;
|
|
32816
32822
|
this.destructManager = destructManager;
|
|
32817
32823
|
this.documentIdentityService = documentIdentityService;
|
|
32824
|
+
this.querySender = querySender;
|
|
32818
32825
|
this.docIdToLocalTimestamp = new Map();
|
|
32819
32826
|
/**
|
|
32820
32827
|
* During a batch, any update to a document that may trigger an update to a query is collected here and once the batch
|
|
@@ -32893,7 +32900,7 @@ class DataManager {
|
|
|
32893
32900
|
* We should not send queries to the server before we know that all outgoing updates were
|
|
32894
32901
|
* applied on the server.
|
|
32895
32902
|
*/
|
|
32896
|
-
this.
|
|
32903
|
+
this.querySender.safeToSendQueriesToServer.next(isEmpty);
|
|
32897
32904
|
});
|
|
32898
32905
|
}
|
|
32899
32906
|
getProperties(squidDocId) {
|
|
@@ -32927,7 +32934,7 @@ class DataManager {
|
|
|
32927
32934
|
async runInTransaction(fn, transactionId) {
|
|
32928
32935
|
if (transactionId) {
|
|
32929
32936
|
assert_assertTruthy(transactionId === this.currentTransactionId, 'Transaction already ended.');
|
|
32930
|
-
return fn(transactionId).then((
|
|
32937
|
+
return fn(transactionId).then(() => Promise.resolve());
|
|
32931
32938
|
}
|
|
32932
32939
|
if (this.lockManager.canGetLock(RUN_IN_TRANSACTION_MUTEX)) {
|
|
32933
32940
|
this.lockManager.lockSync(RUN_IN_TRANSACTION_MUTEX);
|
|
@@ -33050,12 +33057,9 @@ class DataManager {
|
|
|
33050
33057
|
this.handleIncomingMutations(notification.payload);
|
|
33051
33058
|
});
|
|
33052
33059
|
});
|
|
33053
|
-
this.
|
|
33054
|
-
.observeNotifications()
|
|
33055
|
-
.pipe((0,external_rxjs_namespaceObject.filter)((notification) => notification.type === 'query'), map_map((n) => n))
|
|
33056
|
-
.subscribe((notification) => {
|
|
33060
|
+
this.querySubscriptionManager.observeQueryResults().subscribe((queryResult) => {
|
|
33057
33061
|
this.outgoingMutationsEmpty.pipe((0,external_rxjs_namespaceObject.filter)(Boolean), (0,external_rxjs_namespaceObject.take)(1)).subscribe(() => {
|
|
33058
|
-
this.handleIncomingQuerySnapshots(
|
|
33062
|
+
this.handleIncomingQuerySnapshots(queryResult);
|
|
33059
33063
|
});
|
|
33060
33064
|
});
|
|
33061
33065
|
}
|
|
@@ -33288,7 +33292,7 @@ class DataManager {
|
|
|
33288
33292
|
async sendMutationsForIntegration(outgoingMutations, integrationId) {
|
|
33289
33293
|
try {
|
|
33290
33294
|
const { timestamp, idResolutionMap = {}, refreshList = [], } = await this.mutationSender.sendMutations(outgoingMutations.map((outgoingMutation) => outgoingMutation.mutation), integrationId);
|
|
33291
|
-
|
|
33295
|
+
this.documentIdentityService.migrate(idResolutionMap);
|
|
33292
33296
|
refreshList.forEach((docId) => {
|
|
33293
33297
|
this.refreshDocIdToTimestamp.set(idResolutionMap[docId] || docId, timestamp);
|
|
33294
33298
|
});
|
|
@@ -47024,16 +47028,16 @@ class GraphQLClientFactory {
|
|
|
47024
47028
|
;// CONCATENATED MODULE: ./src/mutation/mutation-sender.ts
|
|
47025
47029
|
|
|
47026
47030
|
class MutationSender {
|
|
47027
|
-
constructor(rpcManager, lockManager,
|
|
47031
|
+
constructor(rpcManager, lockManager, querySender) {
|
|
47028
47032
|
this.rpcManager = rpcManager;
|
|
47029
47033
|
this.lockManager = lockManager;
|
|
47030
|
-
this.
|
|
47034
|
+
this.querySender = querySender;
|
|
47031
47035
|
}
|
|
47032
47036
|
async sendMutations(mutations, integrationId) {
|
|
47033
47037
|
const reducedMutations = reduceMutations(mutations);
|
|
47034
47038
|
const mutexes = reducedMutations.map((mutation) => `sendMutation_${getSquidDocId(mutation.squidDocIdObj)}`);
|
|
47035
47039
|
await this.lockManager.lock(...mutexes);
|
|
47036
|
-
await this.
|
|
47040
|
+
await this.querySender.waitForAllQueriesToFinish();
|
|
47037
47041
|
try {
|
|
47038
47042
|
const request = {
|
|
47039
47043
|
mutations: reducedMutations,
|
|
@@ -47602,36 +47606,33 @@ function getStateInPath(obj, path) {
|
|
|
47602
47606
|
class SubscriptionData {
|
|
47603
47607
|
}
|
|
47604
47608
|
|
|
47609
|
+
;// CONCATENATED MODULE: ./src/query/query.types.ts
|
|
47610
|
+
var LimitUnderflowState;
|
|
47611
|
+
(function (LimitUnderflowState) {
|
|
47612
|
+
LimitUnderflowState[LimitUnderflowState["UNKNOWN"] = 0] = "UNKNOWN";
|
|
47613
|
+
LimitUnderflowState[LimitUnderflowState["DISABLED"] = 1] = "DISABLED";
|
|
47614
|
+
LimitUnderflowState[LimitUnderflowState["ENABLED"] = 2] = "ENABLED";
|
|
47615
|
+
})(LimitUnderflowState || (LimitUnderflowState = {}));
|
|
47616
|
+
|
|
47605
47617
|
;// CONCATENATED MODULE: ./src/query/query-subscription.manager.ts
|
|
47606
47618
|
|
|
47607
47619
|
|
|
47608
47620
|
|
|
47609
47621
|
|
|
47610
47622
|
|
|
47623
|
+
|
|
47611
47624
|
// See limitUnderflowState below.
|
|
47612
47625
|
// Exported only for tests
|
|
47613
47626
|
const FETCH_BEYOND_LIMIT = 100;
|
|
47614
47627
|
const LIMIT_UNDERFLOW_TRIGGER = 20;
|
|
47615
|
-
var LimitUnderflowState;
|
|
47616
|
-
(function (LimitUnderflowState) {
|
|
47617
|
-
LimitUnderflowState[LimitUnderflowState["UNKNOWN"] = 0] = "UNKNOWN";
|
|
47618
|
-
LimitUnderflowState[LimitUnderflowState["DISABLED"] = 1] = "DISABLED";
|
|
47619
|
-
LimitUnderflowState[LimitUnderflowState["ENABLED"] = 2] = "ENABLED";
|
|
47620
|
-
})(LimitUnderflowState || (LimitUnderflowState = {}));
|
|
47621
|
-
/** The query mapping requires an app ID, but on the client it doesn't matter, so we use 'client' */
|
|
47622
|
-
const APP_ID = 'client';
|
|
47623
47628
|
class QuerySubscriptionManager {
|
|
47624
|
-
constructor(rpcManager, clientIdService, documentStore, destructManager, documentIdentityService) {
|
|
47629
|
+
constructor(rpcManager, clientIdService, documentStore, destructManager, documentIdentityService, querySender) {
|
|
47625
47630
|
this.rpcManager = rpcManager;
|
|
47626
47631
|
this.clientIdService = clientIdService;
|
|
47627
47632
|
this.documentStore = documentStore;
|
|
47628
47633
|
this.destructManager = destructManager;
|
|
47629
47634
|
this.documentIdentityService = documentIdentityService;
|
|
47630
|
-
|
|
47631
|
-
* As long as there are mutations in flight we do not want to send queries because it causes race conditions,
|
|
47632
|
-
* preventing parallel queries and mutations simplifies the mental model.
|
|
47633
|
-
*/
|
|
47634
|
-
this.safeToSendQueriesToServer = new external_rxjs_namespaceObject.BehaviorSubject(true);
|
|
47635
|
+
this.querySender = querySender;
|
|
47635
47636
|
/**
|
|
47636
47637
|
* An observable used by the data manager, the query subscription manager (this class) identifies when a document no
|
|
47637
47638
|
* longer has queries that it is part of their result, such document is considered orphan. The data manager will mark
|
|
@@ -47640,12 +47641,6 @@ class QuerySubscriptionManager {
|
|
|
47640
47641
|
this.onOrphanDocuments = new external_rxjs_namespaceObject.Subject();
|
|
47641
47642
|
/** All the currently running queries with their full state. */
|
|
47642
47643
|
this.ongoingQueries = new Map();
|
|
47643
|
-
/**
|
|
47644
|
-
* The number of queries that are currently in-flight (about to be sent to the server or sent but did not get a
|
|
47645
|
-
* response yet). This is used by the data manager to prevent it from sending mutations while there are in-flight
|
|
47646
|
-
* queries.
|
|
47647
|
-
*/
|
|
47648
|
-
this.inflightQueriesCount = new external_rxjs_namespaceObject.BehaviorSubject(0);
|
|
47649
47644
|
/**
|
|
47650
47645
|
* The two maps below maintain the relation between document ids we know about locally to clientRequestIds (queries).
|
|
47651
47646
|
* This relation is used for determining whether a document can be safely removed.
|
|
@@ -47657,6 +47652,7 @@ class QuerySubscriptionManager {
|
|
|
47657
47652
|
* queries)
|
|
47658
47653
|
*/
|
|
47659
47654
|
this.queryMappingManager = new ClientQueryMappingManager();
|
|
47655
|
+
this.queryResultsSubject = new external_rxjs_namespaceObject.Subject();
|
|
47660
47656
|
/**
|
|
47661
47657
|
* In the case that a document ID changed on the server, this observable will notify us about the change, and we
|
|
47662
47658
|
* will update the mapping.
|
|
@@ -47667,9 +47663,12 @@ class QuerySubscriptionManager {
|
|
|
47667
47663
|
this.refreshOngoingQueries();
|
|
47668
47664
|
});
|
|
47669
47665
|
this.destructManager.onPreDestruct(() => {
|
|
47670
|
-
this.
|
|
47666
|
+
this.preDestruct();
|
|
47671
47667
|
});
|
|
47672
47668
|
}
|
|
47669
|
+
observeQueryResults() {
|
|
47670
|
+
return this.queryResultsSubject.asObservable();
|
|
47671
|
+
}
|
|
47673
47672
|
/**
|
|
47674
47673
|
* Returns true if the client knows about this clientRequestId. It may happen that it will return false in the case
|
|
47675
47674
|
* that the client unsubscribed from a query but the server sent a mutation update for this clientRequestId.
|
|
@@ -47702,11 +47701,12 @@ class QuerySubscriptionManager {
|
|
|
47702
47701
|
return;
|
|
47703
47702
|
}
|
|
47704
47703
|
ongoingQuery.gotInitialResponse = true;
|
|
47704
|
+
ongoingQuery.isInFlight = false;
|
|
47705
47705
|
}
|
|
47706
47706
|
/** Given a document, returns all the queries that should be notified with the new document properties. */
|
|
47707
47707
|
findQueriesForDocument(doc, squidDocId) {
|
|
47708
47708
|
const { collectionName, integrationId } = parseSquidDocId(squidDocId);
|
|
47709
|
-
const mapping = this.queryMappingManager.getMapping(
|
|
47709
|
+
const mapping = this.queryMappingManager.getMapping(collectionName, integrationId);
|
|
47710
47710
|
if (!mapping)
|
|
47711
47711
|
return [];
|
|
47712
47712
|
return findQueriesForDocumentSync(mapping, doc);
|
|
@@ -47830,10 +47830,7 @@ class QuerySubscriptionManager {
|
|
|
47830
47830
|
* If the parent query has more or equal number results to the given limit - it may be that the sub-query
|
|
47831
47831
|
* may need to see different result from what the parent sees.
|
|
47832
47832
|
*/
|
|
47833
|
-
|
|
47834
|
-
return false;
|
|
47835
|
-
}
|
|
47836
|
-
return true;
|
|
47833
|
+
return candidateParentQuery.dataSubject.value.length < limit;
|
|
47837
47834
|
}
|
|
47838
47835
|
/**
|
|
47839
47836
|
* Given an ongoing query, search for candidate ongoing queries that can serve as a parent.
|
|
@@ -47887,7 +47884,7 @@ class QuerySubscriptionManager {
|
|
|
47887
47884
|
return this.allOngoingQueriesGotInitialResult(rootOngoingQuery);
|
|
47888
47885
|
}), (0,external_rxjs_namespaceObject.startWith)(undefined), (0,external_rxjs_namespaceObject.pairwise)(), filter(([before, after]) => {
|
|
47889
47886
|
return !lodash.isEqual(before, after);
|
|
47890
|
-
}), map_map(([
|
|
47887
|
+
}), map_map(([_ignored, after]) => after),
|
|
47891
47888
|
// This handles 'subscribe = false'
|
|
47892
47889
|
subscribe ? (0,external_rxjs_namespaceObject.tap)() : (0,external_rxjs_namespaceObject.take)(1), (0,external_rxjs_namespaceObject.finalize)(() => {
|
|
47893
47890
|
var _a;
|
|
@@ -47930,12 +47927,6 @@ class QuerySubscriptionManager {
|
|
|
47930
47927
|
this.onOrphanDocuments.next(orphanDocument);
|
|
47931
47928
|
}
|
|
47932
47929
|
}
|
|
47933
|
-
/** Will resolve once all the in-flight queries are done. */
|
|
47934
|
-
async waitForAllQueriesToFinish() {
|
|
47935
|
-
return (0,external_rxjs_namespaceObject.firstValueFrom)(this.inflightQueriesCount.pipe(filter((count) => count === 0))).then(() => {
|
|
47936
|
-
return undefined;
|
|
47937
|
-
});
|
|
47938
|
-
}
|
|
47939
47930
|
/** Register logic for cleaning up the query when it is unsubscribed. */
|
|
47940
47931
|
registerQueryFinalizer(ongoingQuery) {
|
|
47941
47932
|
const clientRequestId = ongoingQuery.clientRequestId;
|
|
@@ -47945,7 +47936,7 @@ class QuerySubscriptionManager {
|
|
|
47945
47936
|
if (ongoingQuery.unsubscribeBlockerCount.value > 0) {
|
|
47946
47937
|
await (0,external_rxjs_namespaceObject.firstValueFrom)((0,external_rxjs_namespaceObject.race)(this.destructManager.observeIsDestructing(), ongoingQuery.unsubscribeBlockerCount.pipe(filter((count) => count === 0))));
|
|
47947
47938
|
}
|
|
47948
|
-
this.queryMappingManager.removeQuery(
|
|
47939
|
+
this.queryMappingManager.removeQuery(querySubscriptionId).then();
|
|
47949
47940
|
this.ongoingQueries.delete(clientRequestId);
|
|
47950
47941
|
if (ongoingQuery.subscribe) {
|
|
47951
47942
|
if (!ongoingQuery.isEmptyForJoin && ongoingQuery.activated) {
|
|
@@ -48162,9 +48153,7 @@ class QuerySubscriptionManager {
|
|
|
48162
48153
|
supportedQuery.dataSubject.complete();
|
|
48163
48154
|
}
|
|
48164
48155
|
}
|
|
48165
|
-
|
|
48166
|
-
this.safeToSendQueriesToServer.next(false);
|
|
48167
|
-
this.safeToSendQueriesToServer.complete();
|
|
48156
|
+
preDestruct() {
|
|
48168
48157
|
this.unsubscribe();
|
|
48169
48158
|
}
|
|
48170
48159
|
unsubscribe() {
|
|
@@ -48186,7 +48175,7 @@ class QuerySubscriptionManager {
|
|
|
48186
48175
|
const query = ongoingQuery.query;
|
|
48187
48176
|
const clientRequestId = ongoingQuery.clientRequestId;
|
|
48188
48177
|
const querySubscriptionId = getQuerySubscriptionId(this.clientIdService.getClientId(), clientRequestId);
|
|
48189
|
-
this.queryMappingManager.addQuery(
|
|
48178
|
+
this.queryMappingManager.addQuery(query, querySubscriptionId);
|
|
48190
48179
|
this.ongoingQueries.set(clientRequestId, ongoingQuery);
|
|
48191
48180
|
const parentOngoingQuery = this.findValidParentOfOngoingQuery(ongoingQuery);
|
|
48192
48181
|
if (parentOngoingQuery) {
|
|
@@ -48281,27 +48270,21 @@ class QuerySubscriptionManager {
|
|
|
48281
48270
|
clientRequestId: ongoingQuery.clientRequestId,
|
|
48282
48271
|
subscribe: ongoingQuery.subscribe,
|
|
48283
48272
|
};
|
|
48284
|
-
|
|
48285
|
-
|
|
48286
|
-
|
|
48287
|
-
|
|
48288
|
-
|
|
48289
|
-
|
|
48290
|
-
|
|
48291
|
-
|
|
48292
|
-
|
|
48293
|
-
|
|
48294
|
-
|
|
48295
|
-
|
|
48296
|
-
|
|
48297
|
-
|
|
48298
|
-
|
|
48299
|
-
ongoingQuery.queryRegistered.next(true);
|
|
48300
|
-
})
|
|
48301
|
-
.finally(() => {
|
|
48302
|
-
this.inflightQueriesCount.next(this.inflightQueriesCount.value - 1);
|
|
48303
|
-
ongoingQuery.isInFlight = false;
|
|
48304
|
-
});
|
|
48273
|
+
ongoingQuery.isInFlight = true;
|
|
48274
|
+
this.querySender
|
|
48275
|
+
.sendQuery(queryRequest)
|
|
48276
|
+
.then((queryResult) => {
|
|
48277
|
+
ongoingQuery.queryRegistered.next(true);
|
|
48278
|
+
this.queryResultsSubject.next(queryResult);
|
|
48279
|
+
})
|
|
48280
|
+
.catch((e) => {
|
|
48281
|
+
DebugLogger.debug('Query error', ongoingQuery.query, e);
|
|
48282
|
+
ongoingQuery.dataSubject.error(e);
|
|
48283
|
+
ongoingQuery.done = true;
|
|
48284
|
+
ongoingQuery.queryRegistered.error('query failed');
|
|
48285
|
+
})
|
|
48286
|
+
.finally(() => {
|
|
48287
|
+
ongoingQuery.isInFlight = false;
|
|
48305
48288
|
});
|
|
48306
48289
|
}
|
|
48307
48290
|
/** naive way to refresh queries/subscriptions when we have a new client id */
|
|
@@ -48384,7 +48367,7 @@ class ClientQueryMappingManager {
|
|
|
48384
48367
|
this.stateService = new StateService();
|
|
48385
48368
|
this.querySubscriptionIdToQuery = {};
|
|
48386
48369
|
}
|
|
48387
|
-
addQuery(
|
|
48370
|
+
addQuery(query, querySubscriptionId) {
|
|
48388
48371
|
this.stateService.runInBatch(() => {
|
|
48389
48372
|
let condCount = 0;
|
|
48390
48373
|
const visitedEqualityFields = new Set();
|
|
@@ -48416,7 +48399,7 @@ class ClientQueryMappingManager {
|
|
|
48416
48399
|
});
|
|
48417
48400
|
this.querySubscriptionIdToQuery[querySubscriptionId] = query;
|
|
48418
48401
|
}
|
|
48419
|
-
async removeQuery(
|
|
48402
|
+
async removeQuery(querySubscriptionId) {
|
|
48420
48403
|
const query = this.querySubscriptionIdToQuery[querySubscriptionId];
|
|
48421
48404
|
if (!query)
|
|
48422
48405
|
return;
|
|
@@ -48442,7 +48425,7 @@ class ClientQueryMappingManager {
|
|
|
48442
48425
|
});
|
|
48443
48426
|
return query;
|
|
48444
48427
|
}
|
|
48445
|
-
getMapping(
|
|
48428
|
+
getMapping(collectionName, integrationId) {
|
|
48446
48429
|
return this.stateService.getStateInPath([
|
|
48447
48430
|
'queryMapping',
|
|
48448
48431
|
collectionName,
|
|
@@ -48471,11 +48454,9 @@ class ClientQueryMappingManager {
|
|
|
48471
48454
|
|
|
48472
48455
|
|
|
48473
48456
|
class RpcManager {
|
|
48474
|
-
constructor(region, appId,
|
|
48457
|
+
constructor(region, appId, destructManager, headers = {}, authManager, clientIdService) {
|
|
48475
48458
|
this.region = region;
|
|
48476
48459
|
this.appId = appId;
|
|
48477
|
-
this.socketManager = socketManager;
|
|
48478
|
-
this.destructManager = destructManager;
|
|
48479
48460
|
this.authManager = authManager;
|
|
48480
48461
|
this.clientIdService = clientIdService;
|
|
48481
48462
|
this.staticHeaders = {};
|
|
@@ -48524,8 +48505,6 @@ class RpcManager {
|
|
|
48524
48505
|
return this.staticHeaders;
|
|
48525
48506
|
}
|
|
48526
48507
|
async ready() {
|
|
48527
|
-
// Waiting for socket connection to be established before sending an RPC request
|
|
48528
|
-
await (0,external_rxjs_namespaceObject.firstValueFrom)((0,external_rxjs_namespaceObject.race)(this.socketManager.observeConnectionReady().pipe((0,external_rxjs_namespaceObject.filter)(Boolean)), this.destructManager.observeIsDestructing()));
|
|
48529
48508
|
await this.authManager.waitForReadyState();
|
|
48530
48509
|
}
|
|
48531
48510
|
async post(path, message) {
|
|
@@ -48545,7 +48524,13 @@ class RpcManager {
|
|
|
48545
48524
|
body: serialization_serializeObj(message),
|
|
48546
48525
|
headers: headers,
|
|
48547
48526
|
});
|
|
48548
|
-
|
|
48527
|
+
const parsedResponse = await this.parseResponse(response);
|
|
48528
|
+
DebugLogger.debug(`received response: ${JSON.stringify(parsedResponse)}`);
|
|
48529
|
+
return parsedResponse;
|
|
48530
|
+
}
|
|
48531
|
+
catch (e) {
|
|
48532
|
+
DebugLogger.debug(`received error: ${JSON.stringify(e)}`);
|
|
48533
|
+
throw e;
|
|
48549
48534
|
}
|
|
48550
48535
|
finally {
|
|
48551
48536
|
this.onGoingRpcCounter.next(this.onGoingRpcCounter.value - 1);
|
|
@@ -48557,7 +48542,7 @@ class RpcManager {
|
|
|
48557
48542
|
try {
|
|
48558
48543
|
text = await response.text();
|
|
48559
48544
|
try {
|
|
48560
|
-
json =
|
|
48545
|
+
json = deserializeObj(text);
|
|
48561
48546
|
}
|
|
48562
48547
|
catch (_a) { }
|
|
48563
48548
|
}
|
|
@@ -48657,7 +48642,6 @@ class SocketManager {
|
|
|
48657
48642
|
this.allMessagesObserver = new external_rxjs_namespaceObject.Subject();
|
|
48658
48643
|
this.connectionReady = new external_rxjs_namespaceObject.BehaviorSubject(false);
|
|
48659
48644
|
this.seenMessageIds = new Set();
|
|
48660
|
-
this.firstConnection = true;
|
|
48661
48645
|
this.destructSubject = new external_rxjs_namespaceObject.Subject();
|
|
48662
48646
|
/**
|
|
48663
48647
|
* On a client disconnecting, we wait for a bit to see if the client reconnects,
|
|
@@ -48731,11 +48715,7 @@ class SocketManager {
|
|
|
48731
48715
|
}
|
|
48732
48716
|
onConnectionReady() {
|
|
48733
48717
|
this.connectionReady.next(true);
|
|
48734
|
-
|
|
48735
|
-
if (!this.firstConnection) {
|
|
48736
|
-
this.sendMessage({ type: 'catchup' });
|
|
48737
|
-
}
|
|
48738
|
-
this.firstConnection = false;
|
|
48718
|
+
this.sendMessage({ type: 'catchup' });
|
|
48739
48719
|
}
|
|
48740
48720
|
onMessage(messagesStr) {
|
|
48741
48721
|
if (messagesStr === 'connectionReady') {
|
|
@@ -48784,6 +48764,85 @@ class SocketManager {
|
|
|
48784
48764
|
}
|
|
48785
48765
|
}
|
|
48786
48766
|
|
|
48767
|
+
;// CONCATENATED MODULE: ./src/query/query-sender.ts
|
|
48768
|
+
|
|
48769
|
+
|
|
48770
|
+
class QuerySender {
|
|
48771
|
+
constructor(rpcManager, destructManager) {
|
|
48772
|
+
this.rpcManager = rpcManager;
|
|
48773
|
+
this.destructManager = destructManager;
|
|
48774
|
+
/**
|
|
48775
|
+
* A collection of query requests awaiting batch dispatch.
|
|
48776
|
+
*/
|
|
48777
|
+
this.pendingQueryRequests = [];
|
|
48778
|
+
/**
|
|
48779
|
+
* As long as there are mutations in flight we do not want to send queries because it causes race conditions,
|
|
48780
|
+
* preventing parallel queries and mutations simplifies the mental model.
|
|
48781
|
+
*/
|
|
48782
|
+
this.safeToSendQueriesToServer = new external_rxjs_namespaceObject.BehaviorSubject(true);
|
|
48783
|
+
/**
|
|
48784
|
+
* The number of queries that are currently in-flight (about to be sent to the server or sent but did not get a
|
|
48785
|
+
* response yet). This is used by the data manager to prevent it from sending mutations while there are in-flight
|
|
48786
|
+
* queries.
|
|
48787
|
+
*/
|
|
48788
|
+
this.inflightQueriesCount = new external_rxjs_namespaceObject.BehaviorSubject(0);
|
|
48789
|
+
this.destructManager.onPreDestruct(() => {
|
|
48790
|
+
this.preDestruct();
|
|
48791
|
+
});
|
|
48792
|
+
}
|
|
48793
|
+
async sendQuery(queryRequest) {
|
|
48794
|
+
const responseSubject = new external_rxjs_namespaceObject.Subject();
|
|
48795
|
+
const responsePromise = (0,external_rxjs_namespaceObject.firstValueFrom)(responseSubject);
|
|
48796
|
+
this.pendingQueryRequests.push({ queryRequest, responseSubject });
|
|
48797
|
+
if (this.pendingQueryBatchTimeout) {
|
|
48798
|
+
clearTimeout(this.pendingQueryBatchTimeout);
|
|
48799
|
+
this.pendingQueryBatchTimeout = undefined;
|
|
48800
|
+
}
|
|
48801
|
+
this.pendingQueryBatchTimeout = setTimeout(() => {
|
|
48802
|
+
this.safeToSendQueriesToServer.pipe(filter(Boolean), (0,external_rxjs_namespaceObject.take)(1)).subscribe(() => {
|
|
48803
|
+
this.processQueryBatch();
|
|
48804
|
+
});
|
|
48805
|
+
}, 0);
|
|
48806
|
+
return responsePromise;
|
|
48807
|
+
}
|
|
48808
|
+
async processQueryBatch() {
|
|
48809
|
+
const queryRequestAndSubjects = this.pendingQueryRequests.splice(0);
|
|
48810
|
+
const pendingQueryRequests = queryRequestAndSubjects.map(({ queryRequest }) => queryRequest);
|
|
48811
|
+
const responseSubjects = queryRequestAndSubjects.map(({ responseSubject }) => responseSubject);
|
|
48812
|
+
this.inflightQueriesCount.next(this.inflightQueriesCount.value + pendingQueryRequests.length);
|
|
48813
|
+
try {
|
|
48814
|
+
const batchResponse = await this.rpcManager.post('query/batchQueries', pendingQueryRequests);
|
|
48815
|
+
for (const { queryRequest, responseSubject } of queryRequestAndSubjects) {
|
|
48816
|
+
const clientRequestId = queryRequest.clientRequestId;
|
|
48817
|
+
const error = batchResponse.errors[clientRequestId];
|
|
48818
|
+
const result = batchResponse.results[clientRequestId];
|
|
48819
|
+
if (error) {
|
|
48820
|
+
responseSubject.error(error);
|
|
48821
|
+
}
|
|
48822
|
+
else {
|
|
48823
|
+
responseSubject.next(result);
|
|
48824
|
+
}
|
|
48825
|
+
}
|
|
48826
|
+
}
|
|
48827
|
+
catch (e) {
|
|
48828
|
+
responseSubjects.forEach((responseSubject) => responseSubject.error(e));
|
|
48829
|
+
}
|
|
48830
|
+
finally {
|
|
48831
|
+
this.inflightQueriesCount.next(this.inflightQueriesCount.value - pendingQueryRequests.length);
|
|
48832
|
+
}
|
|
48833
|
+
}
|
|
48834
|
+
/** Will resolve once all the in-flight queries are done. */
|
|
48835
|
+
async waitForAllQueriesToFinish() {
|
|
48836
|
+
return (0,external_rxjs_namespaceObject.firstValueFrom)(this.inflightQueriesCount.pipe(filter((count) => count === 0))).then(() => {
|
|
48837
|
+
return undefined;
|
|
48838
|
+
});
|
|
48839
|
+
}
|
|
48840
|
+
preDestruct() {
|
|
48841
|
+
this.safeToSendQueriesToServer.next(false);
|
|
48842
|
+
this.safeToSendQueriesToServer.complete();
|
|
48843
|
+
}
|
|
48844
|
+
}
|
|
48845
|
+
|
|
48787
48846
|
;// CONCATENATED MODULE: ./src/squid.ts
|
|
48788
48847
|
|
|
48789
48848
|
|
|
@@ -48807,6 +48866,7 @@ class SocketManager {
|
|
|
48807
48866
|
|
|
48808
48867
|
|
|
48809
48868
|
|
|
48869
|
+
|
|
48810
48870
|
|
|
48811
48871
|
|
|
48812
48872
|
/**
|
|
@@ -48991,18 +49051,19 @@ class Squid {
|
|
|
48991
49051
|
this.clientIdService = new ClientIdService(this.destructManager);
|
|
48992
49052
|
this.authManager = new AuthManager(this.destructManager, options.apiKey);
|
|
48993
49053
|
this.socketManager = new SocketManager(this.clientIdService, options.region, appId, options.messageNotificationWrapper, this.destructManager, this.authManager);
|
|
48994
|
-
this.rpcManager = new RpcManager(options.region, appId, this.
|
|
49054
|
+
this.rpcManager = new RpcManager(options.region, appId, this.destructManager, httpHeaders, this.authManager, this.clientIdService);
|
|
48995
49055
|
this.documentStore = new DocumentStore();
|
|
48996
49056
|
this.lockManager = new LockManager();
|
|
48997
49057
|
this.distributedLockManager = new DistributedLockManager(this.socketManager, this.destructManager);
|
|
48998
49058
|
this.documentIdentityService = new DocumentIdentityService(this.documentStore, this.destructManager);
|
|
48999
49059
|
this.documentReferenceFactory = new DocumentReferenceFactory(this.documentIdentityService);
|
|
49000
|
-
this.
|
|
49060
|
+
this.querySender = new QuerySender(this.rpcManager, this.destructManager);
|
|
49061
|
+
this.querySubscriptionManager = new QuerySubscriptionManager(this.rpcManager, this.clientIdService, this.documentStore, this.destructManager, this.documentIdentityService, this.querySender);
|
|
49001
49062
|
this.localQueryManager = new LocalQueryManager(this.documentStore, this.documentReferenceFactory, this.querySubscriptionManager);
|
|
49002
|
-
const mutationSender = new MutationSender(this.rpcManager, this.lockManager, this.
|
|
49063
|
+
const mutationSender = new MutationSender(this.rpcManager, this.lockManager, this.querySender);
|
|
49003
49064
|
this.queryBuilderFactory = new QueryBuilderFactory(this.querySubscriptionManager, this.localQueryManager, this.documentReferenceFactory, this.documentIdentityService);
|
|
49004
49065
|
this.collectionReferenceFactory = new CollectionReferenceFactory(this.documentReferenceFactory, this.queryBuilderFactory, this.querySubscriptionManager);
|
|
49005
|
-
this.dataManager = new DataManager(this.documentStore, mutationSender, this.socketManager, this.querySubscriptionManager, this.queryBuilderFactory, this.lockManager, this.destructManager, this.documentIdentityService);
|
|
49066
|
+
this.dataManager = new DataManager(this.documentStore, mutationSender, this.socketManager, this.querySubscriptionManager, this.queryBuilderFactory, this.lockManager, this.destructManager, this.documentIdentityService, this.querySender);
|
|
49006
49067
|
this.documentReferenceFactory.setDataManager(this.dataManager);
|
|
49007
49068
|
this.backendFunctionManager = new BackendFunctionManager(this.clientIdService, this.rpcManager, this.socketManager);
|
|
49008
49069
|
this.namedQueryManager = new NamedQueryManager(this.rpcManager, this.socketManager);
|
|
@@ -8,12 +8,15 @@ import { NamedQueryContext } from './named-query.context';
|
|
|
8
8
|
import { GraphqlContext } from './graphql.context';
|
|
9
9
|
import { DistributedLockContext } from './distributed-lock.context';
|
|
10
10
|
import { AiAssistantChatContext, AiAssistantMutationContext } from './ai-assistant.context';
|
|
11
|
+
import { ClientId } from './communication.types';
|
|
12
|
+
import { ClientConnectionState } from './socket.types';
|
|
11
13
|
export type SecureDatabaseAction<T extends DatabaseActionType> = T extends 'all' ? () => boolean | Promise<boolean> : T extends 'read' ? ((context: QueryContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>) : ((context: MutationContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>);
|
|
12
14
|
export type SecureApiAction = ((context: ApiCallContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>);
|
|
13
15
|
export type SecureNamedQueryAction = ((context: NamedQueryContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>);
|
|
14
16
|
export type SecureDistributedLockAction = ((context: DistributedLockContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>);
|
|
15
17
|
export type SecureGraphQLAction = ((context: GraphqlContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>);
|
|
16
18
|
export type SecureAiAssistantAction<T extends AiAssistantActionType> = T extends 'all' ? () => boolean | Promise<boolean> : T extends 'chat' ? ((context: AiAssistantChatContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>) : ((context: AiAssistantMutationContext) => boolean | Promise<boolean>) | (() => boolean | Promise<boolean>);
|
|
19
|
+
export type ClientConnectionStateChangeAction = (clientId: ClientId, clientConnectionState: ClientConnectionState) => Promise<void> | void;
|
|
17
20
|
export type ExecutableAction = (...args: any[]) => any;
|
|
18
21
|
export type TriggerAction = ((request: TriggerRequest) => void | Promise<void>) | (() => void | Promise<void>);
|
|
19
22
|
/** The context provided to a trigger function. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DocTimestamp, LockManager, Mutation, SquidDocId, SquidDocument } from '@squidcloud/common';
|
|
2
|
+
import { QuerySender } from './query/query-sender';
|
|
2
3
|
import { DestructManager } from './destruct.manager';
|
|
3
4
|
import DocumentIdentityService from './document-identity.service';
|
|
4
5
|
import { DocumentStore } from './document-store';
|
|
@@ -20,6 +21,7 @@ export declare class DataManager {
|
|
|
20
21
|
private readonly lockManager;
|
|
21
22
|
private readonly destructManager;
|
|
22
23
|
private readonly documentIdentityService;
|
|
24
|
+
private readonly querySender;
|
|
23
25
|
private readonly docIdToLocalTimestamp;
|
|
24
26
|
private currentTransactionId;
|
|
25
27
|
/**
|
|
@@ -88,7 +90,7 @@ export declare class DataManager {
|
|
|
88
90
|
private readonly refreshDocIdToTimestamp;
|
|
89
91
|
private deleteExpiredTimestampsInterval;
|
|
90
92
|
private handleIncomingMessagesForTests;
|
|
91
|
-
constructor(documentStore: DocumentStore, mutationSender: MutationSender, socketManager: SocketManager, querySubscriptionManager: QuerySubscriptionManager, queryBuilderFactory: QueryBuilderFactory, lockManager: LockManager, destructManager: DestructManager, documentIdentityService: DocumentIdentityService);
|
|
93
|
+
constructor(documentStore: DocumentStore, mutationSender: MutationSender, socketManager: SocketManager, querySubscriptionManager: QuerySubscriptionManager, queryBuilderFactory: QueryBuilderFactory, lockManager: LockManager, destructManager: DestructManager, documentIdentityService: DocumentIdentityService, querySender: QuerySender);
|
|
92
94
|
getProperties(squidDocId: SquidDocId): SquidDocument | undefined;
|
|
93
95
|
/** Whether a document has changes that are out of sync with the server. */
|
|
94
96
|
isDirty(squidDocId: SquidDocId): boolean;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { IntegrationId, LockManager, MutateResponse, Mutation } from '@squidcloud/common';
|
|
2
|
-
import { QuerySubscriptionManager } from '../query/query-subscription.manager';
|
|
3
2
|
import { RpcManager } from '../rpc.manager';
|
|
3
|
+
import { QuerySender } from '../query/query-sender';
|
|
4
4
|
export declare class MutationSender {
|
|
5
5
|
private readonly rpcManager;
|
|
6
6
|
private readonly lockManager;
|
|
7
|
-
private readonly
|
|
8
|
-
constructor(rpcManager: RpcManager, lockManager: LockManager,
|
|
7
|
+
private readonly querySender;
|
|
8
|
+
constructor(rpcManager: RpcManager, lockManager: LockManager, querySender: QuerySender);
|
|
9
9
|
sendMutations(mutations: Array<Mutation>, integrationId: IntegrationId): Promise<MutateResponse>;
|
|
10
10
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { RpcManager } from '../rpc.manager';
|
|
2
|
+
import { QueryRequest, QueryResultData } from '@squidcloud/common';
|
|
3
|
+
import { BehaviorSubject } from 'rxjs';
|
|
4
|
+
import { DestructManager } from '../destruct.manager';
|
|
5
|
+
export declare class QuerySender {
|
|
6
|
+
private readonly rpcManager;
|
|
7
|
+
private readonly destructManager;
|
|
8
|
+
/**
|
|
9
|
+
* A collection of query requests awaiting batch dispatch.
|
|
10
|
+
*/
|
|
11
|
+
private readonly pendingQueryRequests;
|
|
12
|
+
/**
|
|
13
|
+
* A timeout identifier used to ensure that only the last query in rapid succession triggers the batch send process.
|
|
14
|
+
*/
|
|
15
|
+
private pendingQueryBatchTimeout?;
|
|
16
|
+
/**
|
|
17
|
+
* As long as there are mutations in flight we do not want to send queries because it causes race conditions,
|
|
18
|
+
* preventing parallel queries and mutations simplifies the mental model.
|
|
19
|
+
*/
|
|
20
|
+
readonly safeToSendQueriesToServer: BehaviorSubject<boolean>;
|
|
21
|
+
/**
|
|
22
|
+
* The number of queries that are currently in-flight (about to be sent to the server or sent but did not get a
|
|
23
|
+
* response yet). This is used by the data manager to prevent it from sending mutations while there are in-flight
|
|
24
|
+
* queries.
|
|
25
|
+
*/
|
|
26
|
+
private readonly inflightQueriesCount;
|
|
27
|
+
constructor(rpcManager: RpcManager, destructManager: DestructManager);
|
|
28
|
+
sendQuery(queryRequest: QueryRequest): Promise<QueryResultData>;
|
|
29
|
+
private processQueryBatch;
|
|
30
|
+
/** Will resolve once all the in-flight queries are done. */
|
|
31
|
+
waitForAllQueriesToFinish(): Promise<void>;
|
|
32
|
+
private preDestruct;
|
|
33
|
+
}
|
|
@@ -1,70 +1,21 @@
|
|
|
1
|
-
import { Alias, ClientRequestId, JoinCondition, Query, QuerySubscriptionId, SquidDocId, SquidDocument } from '@squidcloud/common';
|
|
2
|
-
import {
|
|
1
|
+
import { Alias, ClientRequestId, JoinCondition, Query, QueryResultData, QuerySubscriptionId, SquidDocId, SquidDocument } from '@squidcloud/common';
|
|
2
|
+
import { Observable, Subject } from 'rxjs';
|
|
3
3
|
import { DestructManager } from '../destruct.manager';
|
|
4
4
|
import DocumentIdentityService from '../document-identity.service';
|
|
5
5
|
import { DocumentStore } from '../document-store';
|
|
6
6
|
import { RpcManager } from '../rpc.manager';
|
|
7
7
|
import { ClientIdService } from '../client-id.service';
|
|
8
|
+
import { OngoingQuery } from './query.types';
|
|
9
|
+
import { QuerySender } from './query-sender';
|
|
8
10
|
export declare const FETCH_BEYOND_LIMIT = 100;
|
|
9
11
|
export declare const LIMIT_UNDERFLOW_TRIGGER = 20;
|
|
10
|
-
interface OngoingQuery {
|
|
11
|
-
clientRequestId: ClientRequestId;
|
|
12
|
-
query: Query;
|
|
13
|
-
supportedQueries: Array<OngoingQuery>;
|
|
14
|
-
supportingOngoingQuery?: OngoingQuery;
|
|
15
|
-
gotInitialResponse: boolean;
|
|
16
|
-
activated: boolean;
|
|
17
|
-
joinCondition?: JoinCondition;
|
|
18
|
-
alias: Alias;
|
|
19
|
-
dataSubject: BehaviorSubject<Array<SquidDocument> | null>;
|
|
20
|
-
queryRegistered: BehaviorSubject<boolean>;
|
|
21
|
-
/**
|
|
22
|
-
* In case that this query is a parent of another query (that is, the other query is a subset of this query), this
|
|
23
|
-
* query should not be unsubscribed from the server until we registered the child query in the server.
|
|
24
|
-
*/
|
|
25
|
-
unsubscribeBlockerCount: BehaviorSubject<number>;
|
|
26
|
-
subscribe: boolean;
|
|
27
|
-
/**
|
|
28
|
-
* In case of joins, and if this ongoing query is the root, this field emits all the supported observables
|
|
29
|
-
* for example A.join(B, {..some join condition..}).join(C, {...some join condition}.
|
|
30
|
-
* This field will emit [A.subject.pipe(), B.subject.pipe(), C.subject.pipe()]. Any new supported queries will be
|
|
31
|
-
* added here.
|
|
32
|
-
*/
|
|
33
|
-
allObservables?: ReplaySubject<Array<Observable<DocsAndAlias>>>;
|
|
34
|
-
isEmptyForJoin: boolean;
|
|
35
|
-
done: boolean;
|
|
36
|
-
isInFlight: boolean;
|
|
37
|
-
forceFetchFromServer: boolean;
|
|
38
|
-
/**
|
|
39
|
-
* If there's a limit, we request `limit + FETCH_BEYOND_LIMIT` documents from the server.
|
|
40
|
-
* If we got that many documents, that means there may be even more. In that case, if our result set goes below
|
|
41
|
-
* `limit + LIMIT_UNDERFLOW_TRIGGER` documents (due to local or remote deletions), we need to resend the query to the
|
|
42
|
-
* server to potentially get more documents.
|
|
43
|
-
* If the number of documents is less than `limit + FETCH_BEYOND_LIMIT`, that means there are not that many documents
|
|
44
|
-
* on the server, so we don't need to resend the query regardless of how small our result size is or becomes.
|
|
45
|
-
*/
|
|
46
|
-
limitUnderflowState: LimitUnderflowState;
|
|
47
|
-
}
|
|
48
|
-
declare enum LimitUnderflowState {
|
|
49
|
-
UNKNOWN = 0,
|
|
50
|
-
DISABLED = 1,
|
|
51
|
-
ENABLED = 2
|
|
52
|
-
}
|
|
53
|
-
interface DocsAndAlias {
|
|
54
|
-
docs: Array<SquidDocument>;
|
|
55
|
-
alias: Alias;
|
|
56
|
-
}
|
|
57
12
|
export declare class QuerySubscriptionManager {
|
|
58
13
|
private readonly rpcManager;
|
|
59
14
|
private readonly clientIdService;
|
|
60
15
|
private readonly documentStore;
|
|
61
16
|
private readonly destructManager;
|
|
62
17
|
private readonly documentIdentityService;
|
|
63
|
-
|
|
64
|
-
* As long as there are mutations in flight we do not want to send queries because it causes race conditions,
|
|
65
|
-
* preventing parallel queries and mutations simplifies the mental model.
|
|
66
|
-
*/
|
|
67
|
-
readonly safeToSendQueriesToServer: BehaviorSubject<boolean>;
|
|
18
|
+
private readonly querySender;
|
|
68
19
|
/**
|
|
69
20
|
* An observable used by the data manager, the query subscription manager (this class) identifies when a document no
|
|
70
21
|
* longer has queries that it is part of their result, such document is considered orphan. The data manager will mark
|
|
@@ -73,12 +24,6 @@ export declare class QuerySubscriptionManager {
|
|
|
73
24
|
onOrphanDocuments: Subject<string[]>;
|
|
74
25
|
/** All the currently running queries with their full state. */
|
|
75
26
|
private readonly ongoingQueries;
|
|
76
|
-
/**
|
|
77
|
-
* The number of queries that are currently in-flight (about to be sent to the server or sent but did not get a
|
|
78
|
-
* response yet). This is used by the data manager to prevent it from sending mutations while there are in-flight
|
|
79
|
-
* queries.
|
|
80
|
-
*/
|
|
81
|
-
private readonly inflightQueriesCount;
|
|
82
27
|
/**
|
|
83
28
|
* The two maps below maintain the relation between document ids we know about locally to clientRequestIds (queries).
|
|
84
29
|
* This relation is used for determining whether a document can be safely removed.
|
|
@@ -90,7 +35,9 @@ export declare class QuerySubscriptionManager {
|
|
|
90
35
|
* queries)
|
|
91
36
|
*/
|
|
92
37
|
private readonly queryMappingManager;
|
|
93
|
-
|
|
38
|
+
private readonly queryResultsSubject;
|
|
39
|
+
constructor(rpcManager: RpcManager, clientIdService: ClientIdService, documentStore: DocumentStore, destructManager: DestructManager, documentIdentityService: DocumentIdentityService, querySender: QuerySender);
|
|
40
|
+
observeQueryResults(): Observable<QueryResultData>;
|
|
94
41
|
/**
|
|
95
42
|
* Returns true if the client knows about this clientRequestId. It may happen that it will return false in the case
|
|
96
43
|
* that the client unsubscribed from a query but the server sent a mutation update for this clientRequestId.
|
|
@@ -144,8 +91,6 @@ export declare class QuerySubscriptionManager {
|
|
|
144
91
|
* Removes a query from the mapping and updates the orphan documents as needed.
|
|
145
92
|
*/
|
|
146
93
|
private removeClientRequestIdMapping;
|
|
147
|
-
/** Will resolve once all the in-flight queries are done. */
|
|
148
|
-
waitForAllQueriesToFinish(): Promise<void>;
|
|
149
94
|
/** Register logic for cleaning up the query when it is unsubscribed. */
|
|
150
95
|
private registerQueryFinalizer;
|
|
151
96
|
/** Creates a graph of ongoing queries and returns the root of the graph. */
|
|
@@ -157,7 +102,7 @@ export declare class QuerySubscriptionManager {
|
|
|
157
102
|
private updateOngoingQueryWithNewDataFromSupportingQuery;
|
|
158
103
|
private allOngoingQueriesGotInitialResult;
|
|
159
104
|
private completeAllSupportedQueries;
|
|
160
|
-
private
|
|
105
|
+
private preDestruct;
|
|
161
106
|
unsubscribe(): void;
|
|
162
107
|
hasSubscription(clientRequestId: ClientRequestId): boolean;
|
|
163
108
|
/** Sends the query request to the server and makes sure to unsubscribe once the subject completes. */
|
|
@@ -183,4 +128,3 @@ export declare class QuerySubscriptionManager {
|
|
|
183
128
|
private refreshOngoingQueries;
|
|
184
129
|
private migrateDocIds;
|
|
185
130
|
}
|
|
186
|
-
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Alias, ClientRequestId, JoinCondition, Query, SquidDocument } from '@squidcloud/common';
|
|
2
|
+
import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs';
|
|
3
|
+
export interface OngoingQuery {
|
|
4
|
+
clientRequestId: ClientRequestId;
|
|
5
|
+
query: Query;
|
|
6
|
+
supportedQueries: Array<OngoingQuery>;
|
|
7
|
+
supportingOngoingQuery?: OngoingQuery;
|
|
8
|
+
gotInitialResponse: boolean;
|
|
9
|
+
activated: boolean;
|
|
10
|
+
joinCondition?: JoinCondition;
|
|
11
|
+
alias: Alias;
|
|
12
|
+
dataSubject: BehaviorSubject<Array<SquidDocument> | null>;
|
|
13
|
+
queryRegistered: BehaviorSubject<boolean>;
|
|
14
|
+
/**
|
|
15
|
+
* In case that this query is a parent of another query (that is, the other query is a subset of this query), this
|
|
16
|
+
* query should not be unsubscribed from the server until we registered the child query in the server.
|
|
17
|
+
*/
|
|
18
|
+
unsubscribeBlockerCount: BehaviorSubject<number>;
|
|
19
|
+
subscribe: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* In case of joins, and if this ongoing query is the root, this field emits all the supported observables
|
|
22
|
+
* for example A.join(B, {...some join condition...}).join(C, {...some join condition}.
|
|
23
|
+
* This field will emit [A.subject.pipe(), B.subject.pipe(), C.subject.pipe()]. Any new supported queries will be
|
|
24
|
+
* added here.
|
|
25
|
+
*/
|
|
26
|
+
allObservables?: ReplaySubject<Array<Observable<DocsAndAlias>>>;
|
|
27
|
+
isEmptyForJoin: boolean;
|
|
28
|
+
done: boolean;
|
|
29
|
+
isInFlight: boolean;
|
|
30
|
+
forceFetchFromServer: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* If there's a limit, we request `limit + FETCH_BEYOND_LIMIT` documents from the server.
|
|
33
|
+
* If we got that many documents, that means there may be even more. In that case, if our result set goes below
|
|
34
|
+
* `limit + LIMIT_UNDERFLOW_TRIGGER` documents (due to local or remote deletions), we need to resend the query to the
|
|
35
|
+
* server to potentially get more documents.
|
|
36
|
+
* If the number of documents is less than `limit + FETCH_BEYOND_LIMIT`, that means there are not that many documents
|
|
37
|
+
* on the server, so we don't need to resend the query regardless of how small our result size is or becomes.
|
|
38
|
+
*/
|
|
39
|
+
limitUnderflowState: LimitUnderflowState;
|
|
40
|
+
}
|
|
41
|
+
export declare enum LimitUnderflowState {
|
|
42
|
+
UNKNOWN = 0,
|
|
43
|
+
DISABLED = 1,
|
|
44
|
+
ENABLED = 2
|
|
45
|
+
}
|
|
46
|
+
export interface DocsAndAlias {
|
|
47
|
+
docs: Array<SquidDocument>;
|
|
48
|
+
alias: Alias;
|
|
49
|
+
}
|
|
@@ -2,17 +2,14 @@ import { SupportedSquidRegion } from '@squidcloud/common';
|
|
|
2
2
|
import { AuthManager } from './auth.manager';
|
|
3
3
|
import { ClientIdService } from './client-id.service';
|
|
4
4
|
import { DestructManager } from './destruct.manager';
|
|
5
|
-
import { SocketManager } from './socket.manager';
|
|
6
5
|
export declare class RpcManager {
|
|
7
6
|
private readonly region;
|
|
8
7
|
private readonly appId;
|
|
9
|
-
private readonly socketManager;
|
|
10
|
-
private readonly destructManager;
|
|
11
8
|
private readonly authManager;
|
|
12
9
|
private readonly clientIdService;
|
|
13
10
|
private readonly staticHeaders;
|
|
14
11
|
private readonly onGoingRpcCounter;
|
|
15
|
-
constructor(region: SupportedSquidRegion, appId: string,
|
|
12
|
+
constructor(region: SupportedSquidRegion, appId: string, destructManager: DestructManager, headers: Record<string, string> | undefined, authManager: AuthManager, clientIdService: ClientIdService);
|
|
16
13
|
awaitAllSettled(): Promise<void>;
|
|
17
14
|
setStaticHeader(key: string, value: string): void;
|
|
18
15
|
deleteStaticHeader(key: string): void;
|
|
@@ -15,7 +15,6 @@ export declare class SocketManager {
|
|
|
15
15
|
private readonly connectionReady;
|
|
16
16
|
private readonly seenMessageIds;
|
|
17
17
|
private socket;
|
|
18
|
-
private firstConnection;
|
|
19
18
|
private destructSubject;
|
|
20
19
|
/**
|
|
21
20
|
* On a client disconnecting, we wait for a bit to see if the client reconnects,
|
|
@@ -73,6 +73,7 @@ export declare class Squid {
|
|
|
73
73
|
private readonly aiClientFactory;
|
|
74
74
|
private readonly _connectionDetails;
|
|
75
75
|
private readonly secretClient;
|
|
76
|
+
private readonly querySender;
|
|
76
77
|
private static readonly squidInstancesMap;
|
|
77
78
|
/**
|
|
78
79
|
* Creates a new instance of Squid with the given options.
|