@squidcloud/backend 1.0.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/dist/backend/src/actions.d.ts +13 -0
- package/dist/backend/src/index.d.ts +3 -0
- package/dist/backend/src/metadata.d.ts +234 -0
- package/dist/backend/src/project.d.ts +4 -0
- package/dist/backend/src/service.d.ts +10 -0
- package/dist/common/src/api.types.d.ts +10 -0
- package/dist/common/src/application.schemas.d.ts +608 -0
- package/dist/common/src/application.types.d.ts +120 -0
- package/dist/common/src/backend-function.schemas.d.ts +3 -0
- package/dist/common/src/backend-function.types.d.ts +7 -0
- package/dist/common/src/bundle-api.types.d.ts +86 -0
- package/dist/common/src/bundle-data.types.d.ts +45 -0
- package/dist/common/src/communication.types.d.ts +4 -0
- package/dist/common/src/context.types.d.ts +22 -0
- package/dist/common/src/document.types.d.ts +29 -0
- package/dist/common/src/graphql.types.d.ts +8 -0
- package/dist/common/src/http-status.enum.d.ts +50 -0
- package/dist/common/src/index.d.ts +40 -0
- package/dist/common/src/integration.types.d.ts +247 -0
- package/dist/common/src/logger.types.d.ts +22 -0
- package/dist/common/src/metrics.schemas.d.ts +3 -0
- package/dist/common/src/metrics.types.d.ts +52 -0
- package/dist/common/src/mutation.context.d.ts +14 -0
- package/dist/common/src/mutation.schemas.d.ts +5 -0
- package/dist/common/src/mutation.types.d.ts +66 -0
- package/dist/common/src/named-query.schemas.d.ts +3 -0
- package/dist/common/src/named-query.types.d.ts +9 -0
- package/dist/common/src/query/index.d.ts +2 -0
- package/dist/common/src/query/query-context.d.ts +41 -0
- package/dist/common/src/query/simple-query-builder.d.ts +14 -0
- package/dist/common/src/query.schemas.d.ts +5 -0
- package/dist/common/src/query.types.d.ts +118 -0
- package/dist/common/src/schema/schema.types.d.ts +34 -0
- package/dist/common/src/secret.schemas.d.ts +6 -0
- package/dist/common/src/secret.types.d.ts +30 -0
- package/dist/common/src/socket.schemas.d.ts +3 -0
- package/dist/common/src/socket.types.d.ts +68 -0
- package/dist/common/src/time-units.d.ts +5 -0
- package/dist/common/src/trigger.types.d.ts +17 -0
- package/dist/common/src/types.d.ts +15 -0
- package/dist/common/src/utils/array.d.ts +7 -0
- package/dist/common/src/utils/assert.d.ts +6 -0
- package/dist/common/src/utils/error.d.ts +4 -0
- package/dist/common/src/utils/lock.manager.d.ts +14 -0
- package/dist/common/src/utils/object.d.ts +4 -0
- package/dist/common/src/utils/serialization.d.ts +5 -0
- package/dist/common/src/utils/url.d.ts +1 -0
- package/dist/common/src/utils/validation.d.ts +30 -0
- package/dist/index.js +12 -0
- package/dist/index.js.LICENSE.txt +38 -0
- package/dist/node_modules/json-schema-typed/draft-2020-12.d.ts +1239 -0
- package/dist/typescript-client/src/api.manager.d.ts +14 -0
- package/dist/typescript-client/src/backend-function.manager.d.ts +13 -0
- package/dist/typescript-client/src/collection-reference.d.ts +16 -0
- package/dist/typescript-client/src/collection-reference.factory.d.ts +11 -0
- package/dist/typescript-client/src/data.manager.d.ts +140 -0
- package/dist/typescript-client/src/db.dao.d.ts +20 -0
- package/dist/typescript-client/src/destruct.manager.d.ts +7 -0
- package/dist/typescript-client/src/document-reference.d.ts +18 -0
- package/dist/typescript-client/src/document-reference.factory.d.ts +9 -0
- package/dist/typescript-client/src/graphql-client.d.ts +9 -0
- package/dist/typescript-client/src/graphql-client.factory.d.ts +9 -0
- package/dist/typescript-client/src/index.d.ts +4 -0
- package/dist/typescript-client/src/mutation/mutation-sender.d.ts +11 -0
- package/dist/typescript-client/src/named-query.manager.d.ts +13 -0
- package/dist/typescript-client/src/query/query-builder.factory.d.ts +41 -0
- package/dist/typescript-client/src/query/query-subscription.manager.d.ts +55 -0
- package/dist/typescript-client/src/query/query.types.d.ts +7 -0
- package/dist/typescript-client/src/rpc.manager.d.ts +23 -0
- package/dist/typescript-client/src/socket.manager.d.ts +27 -0
- package/dist/typescript-client/src/squid.d.ts +48 -0
- package/dist/typescript-client/src/state/action.applier.d.ts +7 -0
- package/dist/typescript-client/src/state/actions.d.ts +29 -0
- package/dist/typescript-client/src/state/path_trie.d.ts +27 -0
- package/dist/typescript-client/src/state/state.service.d.ts +22 -0
- package/dist/typescript-client/src/types.d.ts +2 -0
- package/package.json +26 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ApiEndpointId, ClientId, IntegrationId } from '@squidcloud/common';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { RpcManager } from './rpc.manager';
|
|
4
|
+
import { SocketManager } from './socket.manager';
|
|
5
|
+
export declare class ApiManager {
|
|
6
|
+
private readonly clientId;
|
|
7
|
+
private readonly rpcManager;
|
|
8
|
+
private readonly socketManager;
|
|
9
|
+
private readonly apiServerUrlOverrideMapping;
|
|
10
|
+
private readonly ongoingApiExecutions;
|
|
11
|
+
constructor(clientId: ClientId, rpcManager: RpcManager, socketManager: SocketManager, apiServerUrlOverrideMapping?: Record<IntegrationId, string>);
|
|
12
|
+
callApiAndSubscribe<T>(integrationId: IntegrationId, endpointId: ApiEndpointId, request: Record<string, any>): Observable<T>;
|
|
13
|
+
private handleApiResponse;
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ClientId } from '@squidcloud/common';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { RpcManager } from './rpc.manager';
|
|
4
|
+
import { SocketManager } from './socket.manager';
|
|
5
|
+
export declare class BackendFunctionManager {
|
|
6
|
+
private readonly clientId;
|
|
7
|
+
private readonly rpcManager;
|
|
8
|
+
private readonly socketManager;
|
|
9
|
+
private readonly ongoingFunctionExecutions;
|
|
10
|
+
constructor(clientId: ClientId, rpcManager: RpcManager, socketManager: SocketManager);
|
|
11
|
+
executeFunctionAndSubscribe<T>(functionName: string, ...params: any[]): Observable<T>;
|
|
12
|
+
private handleFunctionResponse;
|
|
13
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DocId, DocIdObj, IntegrationId, UserFacingDocType } from '@squidcloud/common';
|
|
2
|
+
import { DocumentReference } from './document-reference';
|
|
3
|
+
import { DocumentReferenceFactory } from './document-reference.factory';
|
|
4
|
+
import { QueryBuilder, QueryBuilderFactory } from './query/query-builder.factory';
|
|
5
|
+
import { Alias } from './query/query.types';
|
|
6
|
+
export declare class CollectionReference<T extends UserFacingDocType> {
|
|
7
|
+
private readonly collectionName;
|
|
8
|
+
private integrationId;
|
|
9
|
+
private readonly documentReferenceFactory;
|
|
10
|
+
private readonly queryBuilderFactory;
|
|
11
|
+
private readonly documents;
|
|
12
|
+
constructor(collectionName: string, integrationId: IntegrationId, documentReferenceFactory: DocumentReferenceFactory, queryBuilderFactory: QueryBuilderFactory);
|
|
13
|
+
doc(docId: DocId | DocIdObj): DocumentReference<T>;
|
|
14
|
+
query(): Omit<QueryBuilder<T, any, Record<Alias, DocumentReference<T>>, false>, 'join'>;
|
|
15
|
+
joinQuery<A extends Alias>(alias: A): QueryBuilder<T, A, Record<A, DocumentReference<T>>, true>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CollectionName, IntegrationId, UserFacingDocType } from '@squidcloud/common';
|
|
2
|
+
import { CollectionReference } from './collection-reference';
|
|
3
|
+
import { DocumentReferenceFactory } from './document-reference.factory';
|
|
4
|
+
import { QueryBuilderFactory } from './query/query-builder.factory';
|
|
5
|
+
export declare class CollectionReferenceFactory {
|
|
6
|
+
private readonly documentReferenceFactory;
|
|
7
|
+
private readonly queryBuilderFactory;
|
|
8
|
+
private readonly collections;
|
|
9
|
+
constructor(documentReferenceFactory: DocumentReferenceFactory, queryBuilderFactory: QueryBuilderFactory);
|
|
10
|
+
get<T extends UserFacingDocType>(collectionName: CollectionName, integrationId: IntegrationId): CollectionReference<T>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { DocType, FullDocIdStr, LockManager, Mutation } from '@squidcloud/common';
|
|
2
|
+
import { DbDao } from './db.dao';
|
|
3
|
+
import { DestructManager } from './destruct.manager';
|
|
4
|
+
import { MutationSender } from './mutation/mutation-sender';
|
|
5
|
+
import { QueryBuilderFactory } from './query/query-builder.factory';
|
|
6
|
+
import { QuerySubscriptionManager } from './query/query-subscription.manager';
|
|
7
|
+
import { SocketManagerInterface } from './socket.manager';
|
|
8
|
+
import { TransactionId } from './types';
|
|
9
|
+
export declare class DataManager {
|
|
10
|
+
private readonly dbDao;
|
|
11
|
+
private readonly mutationSender;
|
|
12
|
+
private readonly socketManager;
|
|
13
|
+
private readonly querySubscriptionManager;
|
|
14
|
+
private readonly queryBuilderFactory;
|
|
15
|
+
private readonly lockManager;
|
|
16
|
+
private readonly destructManager;
|
|
17
|
+
private readonly fullDocIdToLocalTimestamp;
|
|
18
|
+
private currentTransactionId;
|
|
19
|
+
/**
|
|
20
|
+
* During a batch, any update to a document that may trigger an update to a query is collected here and once the batch
|
|
21
|
+
* ends, the relevant subscribes to these queries will be updated.
|
|
22
|
+
*/
|
|
23
|
+
private readonly batchClientRequestIds;
|
|
24
|
+
/**
|
|
25
|
+
* In this map we save timestamps for documents that are available locally or recently deleted but need to remain
|
|
26
|
+
* here so if a mutation comes from the server we know whether to apply it or not based on the timestamp. For
|
|
27
|
+
* example, if a document is removed locally and immediately after, an update is received from the server - In that
|
|
28
|
+
* case, it may be the update pre-dates the data that was available locally a second ago. For that reason, the
|
|
29
|
+
* timestamp needs to be kept and even for removed documents it will be kept for ~20 seconds more.
|
|
30
|
+
*
|
|
31
|
+
* Eventually, this map is used as a gatekeeper for preventing old versions of a document (based on timestamp) to
|
|
32
|
+
* appear on the client.
|
|
33
|
+
*/
|
|
34
|
+
private readonly docToTimestamp;
|
|
35
|
+
/**
|
|
36
|
+
* In the case of a local change (outgoing change) without a server timestamp, an incoming server update cannot be
|
|
37
|
+
* applied and needs to be queued until the local state allows it. In this case the incoming update will be queued in
|
|
38
|
+
* this map. Any future incoming server update to the same document will override the previous update in case it has
|
|
39
|
+
* a later timestamp.
|
|
40
|
+
*/
|
|
41
|
+
private readonly pendingIncomingUpdates;
|
|
42
|
+
/**
|
|
43
|
+
* A mutation sent to the server will be stored in this map until it receives a timestamp from the server. These
|
|
44
|
+
* mutations were already applied locally and were sent to the server or about to be sent if sentToServer=false
|
|
45
|
+
* (or are queued in the MutationSender due to a lock). The existence of these pending mutations indicates the data
|
|
46
|
+
* manager to:
|
|
47
|
+
* 1 - Not apply any incoming server mutation while there are outgoing mutations without a timestamp
|
|
48
|
+
* 2 - Not delete the local document even if there are no queries related to this document - there is a chance
|
|
49
|
+
* that there will be a future query that will need this document and the query needs to return the local version
|
|
50
|
+
* of the document.
|
|
51
|
+
* 3 - Even when all outgoing mutations have a timestamp, it may be that there is a pending query in flight that will
|
|
52
|
+
* need to return the document. In this case, the local document may be different from the server. Hence, it
|
|
53
|
+
* cannot accept the server change and will wait for another update from the server. For this purpose, timestamp
|
|
54
|
+
* will be stored in docsToTimestamp for ~20 more seconds.
|
|
55
|
+
*
|
|
56
|
+
* Note: Only one entry per fullDocId can be with sentToServer=false. This is true since all updates to the same doc
|
|
57
|
+
* in the same batch are appended (and reduced) to the same outgoing mutation object.
|
|
58
|
+
*/
|
|
59
|
+
private readonly pendingOutgoingMutations;
|
|
60
|
+
/**
|
|
61
|
+
* A subject for whether there are outgoing mutations. If there are outgoing mutations, any incoming update from the
|
|
62
|
+
* server will be delayed until all the outgoing mutations will be acknowledged by the server.
|
|
63
|
+
* This mechanism is needed to avoid this case:
|
|
64
|
+
*
|
|
65
|
+
* collection.docRef('a').delete();
|
|
66
|
+
* collection.snapshots().subscribe((res) => {
|
|
67
|
+
* // The result here may include doc with id='a' since the delete mutation was not acknowledged.
|
|
68
|
+
* });
|
|
69
|
+
*
|
|
70
|
+
* If we wait for the acknowledgment message, we will have a server timestamp and will be able to ignore the incoming
|
|
71
|
+
* result for document with id='a'.
|
|
72
|
+
*/
|
|
73
|
+
private readonly outgoingMutationsEmpty;
|
|
74
|
+
private readonly docsToResync;
|
|
75
|
+
private deleteExpiredTimestampsInterval;
|
|
76
|
+
private handleIncomingMessages;
|
|
77
|
+
constructor(dbDao: DbDao, mutationSender: MutationSender, socketManager: SocketManagerInterface, querySubscriptionManager: QuerySubscriptionManager, queryBuilderFactory: QueryBuilderFactory, lockManager: LockManager, destructManager: DestructManager);
|
|
78
|
+
getProperties(fullDocIdStr: FullDocIdStr): DocType | undefined;
|
|
79
|
+
isDirty(fullDocIdStr: FullDocIdStr): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Runs the provided function without sending mutations to the server while collecting the updates to the different
|
|
82
|
+
* queries. Local updates will still be applied. Once the batch finishes, all the updates will be sent to the server
|
|
83
|
+
* and the different queries will be notified. runInTransaction may be invoked inside another runInTransaction, only
|
|
84
|
+
* the top level batch will trigger updates to the server.
|
|
85
|
+
*/
|
|
86
|
+
runInTransaction(fn: (transactionId: TransactionId) => Promise<void>, transactionId?: TransactionId): Promise<void>;
|
|
87
|
+
/** Applies a mutation done from the client (from DocumentReference) and sends it to the server. */
|
|
88
|
+
applyOutgoingMutation(mutation: Mutation, transactionId: TransactionId | undefined): Promise<void>;
|
|
89
|
+
/** Same as runInTransaction with the exception that the passed function runs synchronously. */
|
|
90
|
+
private runInTransactionSync;
|
|
91
|
+
/** Remove properties from the document record that should not be sent to the server. */
|
|
92
|
+
private removeInternalProperties;
|
|
93
|
+
/** Listens and handles mutations and snapshots notifications from the socketManager. */
|
|
94
|
+
private handleNotifications;
|
|
95
|
+
private handleIncomingMutations;
|
|
96
|
+
private handleIncomingQuerySnapshots;
|
|
97
|
+
/**
|
|
98
|
+
* Returns a boolean for whether some updates were ignored because the client knows of a later timestamp for those
|
|
99
|
+
* documents.
|
|
100
|
+
*/
|
|
101
|
+
private applyIncomingUpdates;
|
|
102
|
+
private addPendingIncomingUpdate;
|
|
103
|
+
private maybeApplyIncomingUpdate;
|
|
104
|
+
private destruct;
|
|
105
|
+
private stopDeleteExpiredTimestampsJob;
|
|
106
|
+
/**
|
|
107
|
+
* Removes entries from the docToTimestamp map for all the documents that are no longer relevant for this client.
|
|
108
|
+
* If a document exists locally, remove it as well.
|
|
109
|
+
* Cases a document is considered not relevant anymore:
|
|
110
|
+
* 1 - There are no outgoing or incoming updates for this document AND:
|
|
111
|
+
* a - The document was deleted on the server and this client already received a notification about it OR
|
|
112
|
+
* b - The document no longer has a query that will keep it up-to-date
|
|
113
|
+
*/
|
|
114
|
+
private startDeleteExpiredTimestampsJob;
|
|
115
|
+
/**
|
|
116
|
+
* Returns whether it is safe to remove the document locally. A document is safe to be removed if:
|
|
117
|
+
* 1 - It has no pending incoming mutations
|
|
118
|
+
* 2 - All the outgoing mutations already have timestamp
|
|
119
|
+
* 3 - The document is orphan - there is no outgoing query for it
|
|
120
|
+
*/
|
|
121
|
+
private isDocumentSafeForDelete;
|
|
122
|
+
/**
|
|
123
|
+
* Updates the document with the new properties, returns true if an update was done or false in case the doc did not
|
|
124
|
+
* change.
|
|
125
|
+
*/
|
|
126
|
+
private applyLocalDbUpdateFromSnapshot;
|
|
127
|
+
private finishTransaction;
|
|
128
|
+
private sendAllUnsentOutgoingMutations;
|
|
129
|
+
private sendMutationsForIntegration;
|
|
130
|
+
private removeOutgoingMutation;
|
|
131
|
+
private resyncFailedUpdates;
|
|
132
|
+
private groupOutgoingMutationsByIntegrationId;
|
|
133
|
+
/**
|
|
134
|
+
* Handles the case that due to some change (an incoming or outgoing change to a document), a document becomes orphan.
|
|
135
|
+
* That is, there are no ongoing queries that will keep it up-to-date.
|
|
136
|
+
* An orphan document should not stay locally since it may be stale after some time.
|
|
137
|
+
*/
|
|
138
|
+
private handleOrphanDocs;
|
|
139
|
+
private removeDocumentLocally;
|
|
140
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DocType, FullDocIdStr, Query } from '@squidcloud/common';
|
|
2
|
+
export type DbId = number;
|
|
3
|
+
export declare class DbDao {
|
|
4
|
+
private readonly db;
|
|
5
|
+
private readonly dbIdToDoc;
|
|
6
|
+
private readonly fullDocIdToDbId;
|
|
7
|
+
constructor();
|
|
8
|
+
saveDocument(fullDocIdStr: FullDocIdStr, properties: DocType | undefined): DbId | undefined;
|
|
9
|
+
removeDocumentFromDb(fullDocIdStr: FullDocIdStr): void;
|
|
10
|
+
isDbDifferentThanInMemory(fullDocIdStr: FullDocIdStr): boolean;
|
|
11
|
+
getDocumentProperties(fullDocIdStr: FullDocIdStr): DocType;
|
|
12
|
+
getDocumentPropertiesOrUndefined(fullDocIdStr: FullDocIdStr): DocType | undefined;
|
|
13
|
+
executeQuery(query: Query): Array<DocType>;
|
|
14
|
+
private convertToDocType;
|
|
15
|
+
private convertToLokiCondition;
|
|
16
|
+
private getDbCollection;
|
|
17
|
+
private getDbIdToDocForCollection;
|
|
18
|
+
/** Converts multiple == conditions to $in, and multiple != conditions to $nin */
|
|
19
|
+
private applyEqualityConditions;
|
|
20
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FullDocIdStr, Paths, UserFacingDocType } from '@squidcloud/common';
|
|
2
|
+
import { DataManager } from './data.manager';
|
|
3
|
+
import { QueryBuilderFactory } from './query/query-builder.factory';
|
|
4
|
+
import { TransactionId } from './types';
|
|
5
|
+
export declare class DocumentReference<T extends UserFacingDocType = any> {
|
|
6
|
+
readonly fullDocId: FullDocIdStr;
|
|
7
|
+
private readonly dataManager;
|
|
8
|
+
private readonly queryBuilderFactory;
|
|
9
|
+
constructor(fullDocId: FullDocIdStr, dataManager: DataManager, queryBuilderFactory: QueryBuilderFactory);
|
|
10
|
+
data(): T;
|
|
11
|
+
get(): Promise<DocumentReference<T> | undefined>;
|
|
12
|
+
isDirty(): boolean;
|
|
13
|
+
update(data: Partial<Record<Paths<T>, any>>, transactionId?: TransactionId): Promise<void>;
|
|
14
|
+
setInPath(path: Paths<T>, value: any, transactionId?: TransactionId): Promise<void>;
|
|
15
|
+
deleteInPath(path: Paths<T>, transactionId?: TransactionId): Promise<void>;
|
|
16
|
+
insert(data: T, transactionId?: TransactionId): Promise<void>;
|
|
17
|
+
delete(transactionId?: TransactionId): Promise<void>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FullDocIdStr } from '@squidcloud/common';
|
|
2
|
+
import { DataManager } from './data.manager';
|
|
3
|
+
import { DocumentReference } from './document-reference';
|
|
4
|
+
import { QueryBuilderFactory } from './query/query-builder.factory';
|
|
5
|
+
export declare class DocumentReferenceFactory {
|
|
6
|
+
private dataManager;
|
|
7
|
+
create(fullDocId: FullDocIdStr, queryBuilderFactory: QueryBuilderFactory): DocumentReference;
|
|
8
|
+
setDataManager(dataManager: DataManager): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GraphQLRequest, IntegrationId } from '@squidcloud/common';
|
|
2
|
+
import { RpcManager } from './rpc.manager';
|
|
3
|
+
export declare class GraphQLClient {
|
|
4
|
+
private readonly rpcManager;
|
|
5
|
+
private readonly client;
|
|
6
|
+
constructor(rpcManager: RpcManager, integrationId: IntegrationId);
|
|
7
|
+
query<T = any>(request: GraphQLRequest): Promise<T>;
|
|
8
|
+
mutate<T = Record<string, any>>(request: GraphQLRequest): Promise<T | null | undefined>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IntegrationId } from '@squidcloud/common';
|
|
2
|
+
import { GraphQLClient } from './graphql-client';
|
|
3
|
+
import { RpcManager } from './rpc.manager';
|
|
4
|
+
export declare class GraphQLClientFactory {
|
|
5
|
+
private readonly rpcManager;
|
|
6
|
+
private readonly clientsMap;
|
|
7
|
+
constructor(rpcManager: RpcManager);
|
|
8
|
+
get(integrationId: IntegrationId): GraphQLClient;
|
|
9
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ClientId, DocTimestamp, IntegrationId, LockManager, Mutation } from '@squidcloud/common';
|
|
2
|
+
import { RpcManager } from '../rpc.manager';
|
|
3
|
+
import { QuerySubscriptionManager } from '../query/query-subscription.manager';
|
|
4
|
+
export declare class MutationSender {
|
|
5
|
+
private readonly clientId;
|
|
6
|
+
private readonly rpcManager;
|
|
7
|
+
private readonly lockManager;
|
|
8
|
+
private readonly querySubscriptionManager;
|
|
9
|
+
constructor(clientId: ClientId, rpcManager: RpcManager, lockManager: LockManager, querySubscriptionManager: QuerySubscriptionManager);
|
|
10
|
+
sendMutations(mutations: Array<Mutation>, integrationId: IntegrationId): Promise<DocTimestamp>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ClientId, IntegrationId, QueryName } from '@squidcloud/common';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { RpcManager } from './rpc.manager';
|
|
4
|
+
import { SocketManager } from './socket.manager';
|
|
5
|
+
export declare class NamedQueryManager {
|
|
6
|
+
private readonly clientId;
|
|
7
|
+
private readonly rpcManager;
|
|
8
|
+
private readonly socketManager;
|
|
9
|
+
private readonly ongoingNamedQueryExecutions;
|
|
10
|
+
constructor(clientId: ClientId, rpcManager: RpcManager, socketManager: SocketManager);
|
|
11
|
+
executeNamedQueryAndSubscribe<T>(integrationId: IntegrationId, queryName: QueryName, params: Record<string, any>): Observable<T>;
|
|
12
|
+
private handleNamedQueryResponse;
|
|
13
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { CollectionName, FieldName, FullDocIdStr, IntegrationId, Operator, PrimitiveFieldType, Query, UserFacingDocType } from '@squidcloud/common';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { DocumentReference } from '../document-reference';
|
|
4
|
+
import { DocumentReferenceFactory } from '../document-reference.factory';
|
|
5
|
+
import { QuerySubscriptionManager } from './query-subscription.manager';
|
|
6
|
+
import { Alias } from './query.types';
|
|
7
|
+
export declare class QueryBuilderFactory {
|
|
8
|
+
private readonly querySubscriptionManager;
|
|
9
|
+
private readonly documentReferenceFactory;
|
|
10
|
+
constructor(querySubscriptionManager: QuerySubscriptionManager, documentReferenceFactory: DocumentReferenceFactory);
|
|
11
|
+
getForDocument<MyDocType extends UserFacingDocType, ReturnType extends Record<Alias, DocumentReference<MyDocType>>>(fullDocId: FullDocIdStr): Omit<QueryBuilder<MyDocType, any, ReturnType, false>, 'join'>;
|
|
12
|
+
get<MyDocType extends UserFacingDocType, ReturnType extends Record<Alias, DocumentReference<MyDocType>>>(collectionName: CollectionName, integrationId: IntegrationId): Omit<QueryBuilder<MyDocType, any, ReturnType, false>, 'join'>;
|
|
13
|
+
getForJoin<MyDocType extends UserFacingDocType, MyAlias extends Alias, ReturnType extends Record<MyAlias, DocumentReference<MyDocType>>>(collectionName: CollectionName, integrationId: IntegrationId, alias: MyAlias): QueryBuilder<MyDocType, MyAlias, ReturnType, true>;
|
|
14
|
+
}
|
|
15
|
+
export declare class QueryBuilder<MyDocType extends UserFacingDocType, MyAlias extends Alias, ReturnType extends Record<MyAlias, DocumentReference<MyDocType> | undefined>, SupportsJoin extends boolean> {
|
|
16
|
+
private readonly collectionName;
|
|
17
|
+
private readonly integrationId;
|
|
18
|
+
private readonly querySubscriptionManager;
|
|
19
|
+
private readonly documentReferenceFactory;
|
|
20
|
+
private readonly alias;
|
|
21
|
+
private readonly supportsJoin;
|
|
22
|
+
private readonly queryBuilderFactory;
|
|
23
|
+
private readonly simpleQueryBuilder;
|
|
24
|
+
private readonly joins;
|
|
25
|
+
/** Record that maps the right alias to the left condition */
|
|
26
|
+
private readonly joinConditions;
|
|
27
|
+
constructor(collectionName: CollectionName, integrationId: IntegrationId, querySubscriptionManager: QuerySubscriptionManager, documentReferenceFactory: DocumentReferenceFactory, alias: MyAlias, supportsJoin: SupportsJoin, queryBuilderFactory: QueryBuilderFactory);
|
|
28
|
+
where(fieldName: (keyof MyDocType & FieldName) | string, operator: Operator | 'in' | 'not in', value: PrimitiveFieldType | Array<PrimitiveFieldType>): SupportsJoin extends true ? this : Omit<this, 'join'>;
|
|
29
|
+
limit(limit: number): SupportsJoin extends true ? this : Omit<this, 'join'>;
|
|
30
|
+
sortBy(fieldName: keyof MyDocType & FieldName, asc?: boolean): SupportsJoin extends true ? this : Omit<this, 'join'>;
|
|
31
|
+
join<J extends UserFacingDocType, RightAlias extends Alias, RightReturnType extends Record<RightAlias, DocumentReference<J> | undefined>>(queryBuilder: QueryBuilder<J, RightAlias, RightReturnType, true>, leftFieldName: keyof MyDocType & FieldName, rightFieldName: keyof J & FieldName): QueryBuilder<MyDocType, MyAlias, ReturnType & Partial<RightReturnType>, true>;
|
|
32
|
+
snapshot(): SupportsJoin extends true ? Promise<Array<ReturnType>> : Promise<Array<DocumentReference<MyDocType>>>;
|
|
33
|
+
snapshots(subscribe?: boolean): SupportsJoin extends true ? Observable<Array<ReturnType>> : Observable<Array<DocumentReference<MyDocType>>>;
|
|
34
|
+
changes(): Observable<Changes<MyDocType>>;
|
|
35
|
+
build(): Query;
|
|
36
|
+
}
|
|
37
|
+
export interface Changes<MyDocType extends UserFacingDocType> {
|
|
38
|
+
inserts: Array<DocumentReference<MyDocType>>;
|
|
39
|
+
updates: Array<DocumentReference<MyDocType>>;
|
|
40
|
+
deletes: Array<MyDocType>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ClientId, ClientRequestId, DocType, FullDocIdStr, Query, QuerySubscriptionId } from '@squidcloud/common';
|
|
2
|
+
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
|
3
|
+
import { DbDao } from '../db.dao';
|
|
4
|
+
import { DestructManager } from '../destruct.manager';
|
|
5
|
+
import { RpcManager } from '../rpc.manager';
|
|
6
|
+
import { Alias, JoinCondition } from './query.types';
|
|
7
|
+
export declare class QuerySubscriptionManager {
|
|
8
|
+
private readonly rpcManager;
|
|
9
|
+
private readonly clientId;
|
|
10
|
+
private readonly dbDao;
|
|
11
|
+
private readonly destructManager;
|
|
12
|
+
readonly safeToSendQueriesToServer: BehaviorSubject<boolean>;
|
|
13
|
+
onOrphanDocuments: Subject<string[]>;
|
|
14
|
+
private readonly ongoingQueries;
|
|
15
|
+
private readonly inflightQueriesCount;
|
|
16
|
+
/**
|
|
17
|
+
* The two maps below maintain the relation between document ids we know about locally to clientRequestIds (queries).
|
|
18
|
+
* This relation is used for determining whether a document can be safely removed.
|
|
19
|
+
*/
|
|
20
|
+
private readonly clientRequestIdToLocalDocuments;
|
|
21
|
+
private readonly localDocumentToClientRequestIds;
|
|
22
|
+
private readonly queryMappingManager;
|
|
23
|
+
constructor(rpcManager: RpcManager, clientId: ClientId, dbDao: DbDao, destructManager: DestructManager);
|
|
24
|
+
hasOngoingQuery(clientRequestId: ClientRequestId): boolean;
|
|
25
|
+
getQuery(clientRequestId: ClientRequestId): Query;
|
|
26
|
+
setGotResponseFromServer(clientRequestId: ClientRequestId): void;
|
|
27
|
+
findQueriesForDocument(doc: DocType, fullDocId: FullDocIdStr): Array<QuerySubscriptionId>;
|
|
28
|
+
/**
|
|
29
|
+
* Given the new document's properties, finds all the queries that should be notified with the new properties and
|
|
30
|
+
* updates the internal mappings (fullDocId --> client request Ids and, clientRequestId --> fullDocIds).
|
|
31
|
+
* Returns an array with all the previous and current client request ids (basically all the client request ids that
|
|
32
|
+
* will need to be notified due to the change of properties).
|
|
33
|
+
*/
|
|
34
|
+
setClientRequestIdsForLocalDoc(fullDocId: FullDocIdStr, properties: DocType | undefined): Array<ClientRequestId>;
|
|
35
|
+
errorOutAllQueries(fullDocId: FullDocIdStr, err: any): void;
|
|
36
|
+
notifyAllSubscriptions(clientRequestIds: ClientRequestId[]): void;
|
|
37
|
+
processQuery(query: Query, rootAlias: Alias, joins: Record<string, Query>, joinConditions: Record<Alias, JoinCondition>, subscribe: boolean): Observable<Array<Record<Alias, DocType | undefined>>>;
|
|
38
|
+
hasOngoingQueryForDocId(fullDocIdStr: string): boolean;
|
|
39
|
+
private removeClientRequestId;
|
|
40
|
+
waitForAllQueriesToFinish(): Promise<void>;
|
|
41
|
+
private registerQueryFinalizer;
|
|
42
|
+
/** Creates a graph of ongoing queries and returns the root of the graph. */
|
|
43
|
+
private createOngoingQueryGraph;
|
|
44
|
+
private collectAllObservables;
|
|
45
|
+
private joinResults;
|
|
46
|
+
private join;
|
|
47
|
+
private getOngoingQueriesBfs;
|
|
48
|
+
private updateOngoingQueryWithNewDataFromSupportingQuery;
|
|
49
|
+
private allOngoingQueriesGotServerResult;
|
|
50
|
+
private completeAllSupportedQueries;
|
|
51
|
+
private destruct;
|
|
52
|
+
hasSubscription(clientRequestId: ClientRequestId): boolean;
|
|
53
|
+
/** Sends the query request to the server and makes sure to unsubscribe once the subject completes. */
|
|
54
|
+
private sendQueryToServer;
|
|
55
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ApiKey } from '@squidcloud/common';
|
|
2
|
+
import { DestructManager } from './destruct.manager';
|
|
3
|
+
import { SocketManagerInterface } from './socket.manager';
|
|
4
|
+
export declare class RpcManager {
|
|
5
|
+
private readonly rpcEndpoint;
|
|
6
|
+
private readonly socketManager;
|
|
7
|
+
private readonly staticHeaders;
|
|
8
|
+
private readonly onGoingRpcsCounter;
|
|
9
|
+
constructor(rpcEndpoint: string, socketManager: SocketManagerInterface, destructManager: DestructManager, apiKey?: ApiKey);
|
|
10
|
+
setStaticHeader(key: string, value: string): void;
|
|
11
|
+
deleteStaticHeader(key: string): void;
|
|
12
|
+
getEndpoint(): string;
|
|
13
|
+
getStaticHeaders(): Record<string, string>;
|
|
14
|
+
post<T>(path: string, message: any): Promise<T>;
|
|
15
|
+
}
|
|
16
|
+
export declare class RpcError extends Error {
|
|
17
|
+
readonly statusCode: number;
|
|
18
|
+
readonly statusText: string;
|
|
19
|
+
readonly headers: Headers;
|
|
20
|
+
readonly url: string;
|
|
21
|
+
readonly body: string;
|
|
22
|
+
constructor(statusCode: number, statusText: string, headers: Headers, url: string, body: string);
|
|
23
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ClientId, MessageFromClient, MessageToClient } from '@squidcloud/common';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { DestructManager } from './destruct.manager';
|
|
4
|
+
export interface SocketManagerInterface {
|
|
5
|
+
observeNotifications(): Observable<MessageToClient>;
|
|
6
|
+
observeConnectionReady(): Observable<boolean>;
|
|
7
|
+
sendMessage(message: MessageFromClient): void;
|
|
8
|
+
}
|
|
9
|
+
export declare class SocketManager implements SocketManagerInterface {
|
|
10
|
+
private readonly clientId;
|
|
11
|
+
private readonly socketIoEndpoint;
|
|
12
|
+
private readonly messageNotificationWrapper;
|
|
13
|
+
private readonly destructManager;
|
|
14
|
+
private readonly webSocketObserver;
|
|
15
|
+
private readonly allMessagesObserver;
|
|
16
|
+
private readonly connectionReady;
|
|
17
|
+
private readonly seenMessageIds;
|
|
18
|
+
private socket;
|
|
19
|
+
private firstConnection;
|
|
20
|
+
constructor(clientId: ClientId, socketIoEndpoint: string, messageNotificationWrapper: (fn: () => any) => any, destructManager: DestructManager);
|
|
21
|
+
observeNotifications(): Observable<MessageToClient>;
|
|
22
|
+
observeConnectionReady(): Observable<boolean>;
|
|
23
|
+
sendMessage(message: MessageFromClient): void;
|
|
24
|
+
private connect;
|
|
25
|
+
private setupMessageAcknowledgments;
|
|
26
|
+
private destruct;
|
|
27
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ApiEndpointId, ApiKey, AppId, CollectionName, IntegrationId, QueryName, UserFacingDocType } from '@squidcloud/common';
|
|
2
|
+
import { CollectionReference } from './collection-reference';
|
|
3
|
+
import { TransactionId } from './types';
|
|
4
|
+
import { GraphQLClient } from './graphql-client';
|
|
5
|
+
export interface SquidOptions {
|
|
6
|
+
messageNotificationWrapper?: (fn: () => any) => any;
|
|
7
|
+
appId: AppId;
|
|
8
|
+
apiKey?: ApiKey;
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
apiServerUrlOverrideMapping?: Record<IntegrationId, string>;
|
|
11
|
+
}
|
|
12
|
+
/** Reference to the squid db. Provides all the available actions on the DB. */
|
|
13
|
+
export declare class Squid {
|
|
14
|
+
private readonly socketManager;
|
|
15
|
+
private readonly clientId;
|
|
16
|
+
private readonly rpcManager;
|
|
17
|
+
private readonly dataManager;
|
|
18
|
+
private readonly documentReferenceFactory;
|
|
19
|
+
private readonly dbDao;
|
|
20
|
+
private readonly lockManager;
|
|
21
|
+
private readonly querySubscriptionManager;
|
|
22
|
+
private readonly queryBuilderFactory;
|
|
23
|
+
private readonly collectionReferenceFactory;
|
|
24
|
+
private readonly backendFunctionManager;
|
|
25
|
+
private readonly namedQueryManager;
|
|
26
|
+
private readonly apiManager;
|
|
27
|
+
private readonly graphqlClientFactory;
|
|
28
|
+
private readonly destructManager;
|
|
29
|
+
private static readonly squidInstancesMap;
|
|
30
|
+
constructor(options: SquidOptions);
|
|
31
|
+
/**
|
|
32
|
+
* This method is a factory method for creating a Squid instance
|
|
33
|
+
*/
|
|
34
|
+
static getInstance(options: SquidOptions): Squid;
|
|
35
|
+
static getInstances(): Array<Squid>;
|
|
36
|
+
/**
|
|
37
|
+
* Sets the auth id token (OpenId) that will be sent to the server and will be used for providing the Auth object
|
|
38
|
+
* to the security rules.
|
|
39
|
+
*/
|
|
40
|
+
setAuthIdToken(idToken: string | undefined): void;
|
|
41
|
+
collection<T extends UserFacingDocType>(collectionName: CollectionName, integrationId?: IntegrationId): CollectionReference<T>;
|
|
42
|
+
runInTransaction(fn: (transactionId: TransactionId) => Promise<void>): Promise<void>;
|
|
43
|
+
executeFunction<T = any>(functionName: string, ...params: any[]): Promise<T>;
|
|
44
|
+
executeNamedQuery<T = any>(integrationId: IntegrationId, queryName: QueryName, params: Record<string, any>): Promise<T>;
|
|
45
|
+
callApi<T = any>(integrationId: IntegrationId, endpointId: ApiEndpointId, request?: Record<string, any>): Promise<T>;
|
|
46
|
+
graphql(integrationId: IntegrationId): GraphQLClient;
|
|
47
|
+
destruct(): Promise<void>;
|
|
48
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BaseAction } from './actions';
|
|
2
|
+
export type StateLeafNode = string | boolean | number | null | undefined | object | Array<StateLeafNode> | State;
|
|
3
|
+
export type State = {
|
|
4
|
+
[key: string]: StateLeafNode;
|
|
5
|
+
};
|
|
6
|
+
export declare function apply(state: State, action: BaseAction): State;
|
|
7
|
+
export declare function isStateObject(state: StateLeafNode): state is State;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { StateLeafNode } from './action.applier';
|
|
2
|
+
export declare enum ActionType {
|
|
3
|
+
DELETE_PATH = "DELETE_PATH",
|
|
4
|
+
SET_PATH = "SET_PATH",
|
|
5
|
+
BATCH_ACTION = "BATCH_ACTION"
|
|
6
|
+
}
|
|
7
|
+
export declare interface BaseAction {
|
|
8
|
+
type: ActionType;
|
|
9
|
+
}
|
|
10
|
+
export declare interface PathAction extends BaseAction {
|
|
11
|
+
path: string[];
|
|
12
|
+
}
|
|
13
|
+
export type DeletePathAction = PathAction;
|
|
14
|
+
export declare interface SetPathAction extends PathAction {
|
|
15
|
+
payload?: StateLeafNode;
|
|
16
|
+
}
|
|
17
|
+
export declare interface BatchAction extends BaseAction {
|
|
18
|
+
payload: BaseAction[];
|
|
19
|
+
}
|
|
20
|
+
export declare interface StateMessage {
|
|
21
|
+
type: 'ACTIONS';
|
|
22
|
+
payload: BaseAction[];
|
|
23
|
+
}
|
|
24
|
+
export declare function isPathAction(action: BaseAction): action is PathAction;
|
|
25
|
+
export declare function isSetPathAction(action: BaseAction): action is SetPathAction;
|
|
26
|
+
export declare function isDeletePathAction(action: BaseAction): action is DeletePathAction;
|
|
27
|
+
export declare function isBatchAction(action: BaseAction): action is BatchAction;
|
|
28
|
+
export declare function extractAllPathActions(action: BaseAction): PathAction[];
|
|
29
|
+
export declare function getSingleAction(actions: BaseAction[]): BaseAction;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { BaseAction } from './actions';
|
|
2
|
+
export declare class PathTrie<T> {
|
|
3
|
+
private root;
|
|
4
|
+
getOrCreatePathTrieNode(path: string[], nodeData?: T): PathTrieNode<T>;
|
|
5
|
+
getPathTrieNode(path: string[]): PathTrieNode<T> | undefined;
|
|
6
|
+
getPathTrie(path: string[]): PathTrie<T> | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* If the callback returns false, it will not iterate into the children of the current node.
|
|
9
|
+
*/
|
|
10
|
+
iterateBfs(callback: (data: T, path: string[]) => void | boolean): void;
|
|
11
|
+
removeNode(path: string[]): void;
|
|
12
|
+
clearNodeData(path: string[]): void;
|
|
13
|
+
getNodeList(path: string[]): Array<PathTrieNode<T>>;
|
|
14
|
+
private iterateInternal;
|
|
15
|
+
}
|
|
16
|
+
export declare class PathTrieNode<T> {
|
|
17
|
+
children: Map<string, PathTrieNode<T>>;
|
|
18
|
+
nodeData: T | undefined;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Returns a trie which contains all the paths affected by the action. For
|
|
22
|
+
* example, if the action contains a path action applied on path [A, B, C], then
|
|
23
|
+
* [A], [A, B], [A, B, C] will be in the returned trie. Moreover, if
|
|
24
|
+
* subscriptionTree is provided and contains [A, B, C, ...], then [A, B, C, ...]
|
|
25
|
+
* will also be included in the returned trie.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getPathTrieFromAction(action: BaseAction, subscriptionTree?: PathTrie<{}>): PathTrie<boolean>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { State, StateLeafNode } from './action.applier';
|
|
3
|
+
import { BaseAction } from './actions';
|
|
4
|
+
export declare class StateService {
|
|
5
|
+
private readonly subscriptionsTree;
|
|
6
|
+
private state;
|
|
7
|
+
private batchCount;
|
|
8
|
+
private readonly batchedActions;
|
|
9
|
+
dispatch(action: BaseAction): void;
|
|
10
|
+
runInBatch(fn: () => unknown): void;
|
|
11
|
+
observePath<T>(path: string[], pathsToExcludeFn?: () => Array<string[]>): Observable<T>;
|
|
12
|
+
setKeyInPath<T extends State>(path: string[], key: keyof T & string, value: T[keyof T] & StateLeafNode, noopIfSame?: boolean): void;
|
|
13
|
+
setPartial<T extends State>(path: string[], partialState: Partial<T>, noopIfSame?: boolean): void;
|
|
14
|
+
setInPath(path: string[], payload: StateLeafNode, noopIfSame?: boolean): void;
|
|
15
|
+
pushToArray(path: string[], payload: StateLeafNode): void;
|
|
16
|
+
deletePath(path: string[]): void;
|
|
17
|
+
getState(): State;
|
|
18
|
+
getStateInPath<T extends StateLeafNode>(path: string[]): T;
|
|
19
|
+
destroy(): void;
|
|
20
|
+
private getOrCreateSubjectForPath;
|
|
21
|
+
private dispatchSubscriptions;
|
|
22
|
+
}
|