rxdb-server 15.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/LICENSE.txt +555 -0
  2. package/README.md +7 -0
  3. package/dist/cjs/index.js +10 -0
  4. package/dist/cjs/index.js.map +1 -0
  5. package/dist/cjs/plugins/client-rest/index.js +86 -0
  6. package/dist/cjs/plugins/client-rest/index.js.map +1 -0
  7. package/dist/cjs/plugins/client-rest/utils.js +19 -0
  8. package/dist/cjs/plugins/client-rest/utils.js.map +1 -0
  9. package/dist/cjs/plugins/replication-server/helpers.js +38 -0
  10. package/dist/cjs/plugins/replication-server/helpers.js.map +1 -0
  11. package/dist/cjs/plugins/replication-server/index.js +169 -0
  12. package/dist/cjs/plugins/replication-server/index.js.map +1 -0
  13. package/dist/cjs/plugins/replication-server/types.js +2 -0
  14. package/dist/cjs/plugins/replication-server/types.js.map +1 -0
  15. package/dist/cjs/plugins/server/endpoint-replication.js +162 -0
  16. package/dist/cjs/plugins/server/endpoint-replication.js.map +1 -0
  17. package/dist/cjs/plugins/server/endpoint-rest.js +219 -0
  18. package/dist/cjs/plugins/server/endpoint-rest.js.map +1 -0
  19. package/dist/cjs/plugins/server/helper.js +173 -0
  20. package/dist/cjs/plugins/server/helper.js.map +1 -0
  21. package/dist/cjs/plugins/server/index.js +84 -0
  22. package/dist/cjs/plugins/server/index.js.map +1 -0
  23. package/dist/cjs/plugins/server/rx-server.js +51 -0
  24. package/dist/cjs/plugins/server/rx-server.js.map +1 -0
  25. package/dist/cjs/plugins/server/types.js +37 -0
  26. package/dist/cjs/plugins/server/types.js.map +1 -0
  27. package/dist/esm/index.js +4 -0
  28. package/dist/esm/index.js.map +1 -0
  29. package/dist/esm/package.json +1 -0
  30. package/dist/esm/plugins/client-rest/index.js +64 -0
  31. package/dist/esm/plugins/client-rest/index.js.map +1 -0
  32. package/dist/esm/plugins/client-rest/utils.js +13 -0
  33. package/dist/esm/plugins/client-rest/utils.js.map +1 -0
  34. package/dist/esm/plugins/replication-server/helpers.js +32 -0
  35. package/dist/esm/plugins/replication-server/helpers.js.map +1 -0
  36. package/dist/esm/plugins/replication-server/index.js +146 -0
  37. package/dist/esm/plugins/replication-server/index.js.map +1 -0
  38. package/dist/esm/plugins/replication-server/types.js +3 -0
  39. package/dist/esm/plugins/replication-server/types.js.map +1 -0
  40. package/dist/esm/plugins/server/endpoint-replication.js +156 -0
  41. package/dist/esm/plugins/server/endpoint-replication.js.map +1 -0
  42. package/dist/esm/plugins/server/endpoint-rest.js +213 -0
  43. package/dist/esm/plugins/server/endpoint-rest.js.map +1 -0
  44. package/dist/esm/plugins/server/helper.js +157 -0
  45. package/dist/esm/plugins/server/helper.js.map +1 -0
  46. package/dist/esm/plugins/server/index.js +30 -0
  47. package/dist/esm/plugins/server/index.js.map +1 -0
  48. package/dist/esm/plugins/server/rx-server.js +45 -0
  49. package/dist/esm/plugins/server/rx-server.js.map +1 -0
  50. package/dist/esm/plugins/server/types.js +37 -0
  51. package/dist/esm/plugins/server/types.js.map +1 -0
  52. package/dist/types/index.d.ts +1 -0
  53. package/dist/types/plugins/client-rest/index.d.ts +22 -0
  54. package/dist/types/plugins/client-rest/utils.d.ts +2 -0
  55. package/dist/types/plugins/replication-server/helpers.d.ts +2 -0
  56. package/dist/types/plugins/replication-server/index.d.ts +21 -0
  57. package/dist/types/plugins/replication-server/types.d.ts +17 -0
  58. package/dist/types/plugins/server/endpoint-replication.d.ts +20 -0
  59. package/dist/types/plugins/server/endpoint-rest.d.ts +16 -0
  60. package/dist/types/plugins/server/helper.d.ts +23 -0
  61. package/dist/types/plugins/server/index.d.ts +7 -0
  62. package/dist/types/plugins/server/rx-server.d.ts +44 -0
  63. package/dist/types/plugins/server/types.d.ts +66 -0
  64. package/package.json +139 -0
  65. package/plugins/client-rest/index.cjs +2 -0
  66. package/plugins/client-rest/index.d.cts +1 -0
  67. package/plugins/client-rest/index.d.mts +1 -0
  68. package/plugins/client-rest/index.mjs +1 -0
  69. package/plugins/client-rest/index.ts +1 -0
  70. package/plugins/client-rest/package.json +18 -0
  71. package/plugins/replication-server/index.cjs +2 -0
  72. package/plugins/replication-server/index.d.cts +1 -0
  73. package/plugins/replication-server/index.d.mts +1 -0
  74. package/plugins/replication-server/index.mjs +1 -0
  75. package/plugins/replication-server/index.ts +1 -0
  76. package/plugins/replication-server/package.json +18 -0
  77. package/plugins/server/index.cjs +2 -0
  78. package/plugins/server/index.d.cts +1 -0
  79. package/plugins/server/index.d.mts +1 -0
  80. package/plugins/server/index.mjs +1 -0
  81. package/plugins/server/index.ts +1 -0
  82. package/plugins/server/package.json +18 -0
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Returns the auth state by the given request headers.
5
+ * Throws if auth not valid.
6
+ */
7
+
8
+ /**
9
+ * Modifies a given query in a way to limit the results
10
+ * to what the authenticated user is allowed to see.
11
+ * For example the query selector
12
+ * input: {
13
+ * selector: {
14
+ * myField: { $gt: 100 }
15
+ * }
16
+ * }
17
+ * could be modified to restrict the results to only return
18
+ * documents that are "owned" by the user
19
+ * return: {
20
+ * selector: {
21
+ * myField: { $gt: 100 },
22
+ * userId: { $eq: authData.userId }
23
+ * }
24
+ * }
25
+ *
26
+ *
27
+ */
28
+
29
+ /**
30
+ * Validates if a given change is allowed to be performed on the server.
31
+ * Returns true if allowed, false if not.
32
+ * If a client tries to make a non-allowed change,
33
+ * the client will be disconnected.
34
+ */
35
+
36
+ ;
37
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../../src/plugins/server/types.ts"],"sourcesContent":["import type {\n FilledMangoQuery,\n RxDatabase,\n RxReplicationWriteToMasterRow,\n MaybePromise,\n RxCollection,\n WithDeleted\n} from 'rxdb/plugins/core';\nimport { IncomingHttpHeaders } from 'http';\nimport { Express } from 'express';\n\nexport type RxServerOptions<AuthType> = {\n database: RxDatabase;\n authHandler?: RxServerAuthHandler<AuthType>;\n serverApp?: Express;\n appOptions?: any;\n /**\n * [default=localhost]\n */\n hostname?: 'localhost' | '0.0.0.0' | string;\n port: number;\n /**\n * Set a origin for allowed CORS requests.\n * Can be overwritten by the cors option of the endpoints.\n * [default='*']\n */\n cors?: '*' | string;\n};\n\nexport type RxServerAuthData<AuthType> = {\n data: AuthType;\n validUntil: number;\n};\n\n/**\n * Returns the auth state by the given request headers.\n * Throws if auth not valid.\n */\nexport type RxServerAuthHandler<AuthType> =\n (headers: IncomingHttpHeaders) => MaybePromise<RxServerAuthData<AuthType>>;\n\n/**\n * Modifies a given query in a way to limit the results\n * to what the authenticated user is allowed to see.\n * For example the query selector\n * input: {\n * selector: {\n * myField: { $gt: 100 }\n * }\n * }\n * could be modified to restrict the results to only return\n * documents that are \"owned\" by the user\n * return: {\n * selector: {\n * myField: { $gt: 100 },\n * userId: { $eq: authData.userId }\n * }\n * }\n * \n * \n */\nexport type RxServerQueryModifier<AuthType, RxDocType> = (\n authData: RxServerAuthData<AuthType>,\n query: FilledMangoQuery<RxDocType>\n) => FilledMangoQuery<RxDocType>;\n\n/**\n * Validates if a given change is allowed to be performed on the server.\n * Returns true if allowed, false if not.\n * If a client tries to make a non-allowed change,\n * the client will be disconnected.\n */\nexport type RxServerChangeValidator<AuthType, RxDocType> = (\n authData: RxServerAuthData<AuthType>,\n change: RxReplicationWriteToMasterRow<RxDocType>\n) => boolean;\n\n\nexport interface RxServerEndpoint<AuthType, RxDocType> {\n collection: RxCollection<RxDocType>;\n name: string;\n type: 'replication' | 'rest' | string;\n urlPath: string;\n queryModifier?: RxServerQueryModifier<AuthType, RxDocType>;\n changeValidator?: RxServerChangeValidator<AuthType, RxDocType>;\n};\n"],"mappings":";;AAkCA;AACA;AACA;AACA;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAMA;AACA;AACA;AACA;AACA;AACA;;AAcC"}
@@ -0,0 +1,4 @@
1
+ export function wrongImport() {
2
+ throw new Error('You should never import this file, only the server plugins');
3
+ }
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["wrongImport","Error"],"sources":["../../src/index.ts"],"sourcesContent":["export function wrongImport() {\n throw new Error('You should never import this file, only the server plugins');\n}\n"],"mappings":"AAAA,OAAO,SAASA,WAAWA,CAAA,EAAG;EAC1B,MAAM,IAAIC,KAAK,CAAC,4DAA4D,CAAC;AACjF"}
@@ -0,0 +1 @@
1
+ { "type": "module", "sideEffects": false }
@@ -0,0 +1,64 @@
1
+ import { postRequest } from "./utils.js";
2
+ import { Subject } from 'rxjs';
3
+ import EventSource from 'eventsource';
4
+ export var RxRestClient = /*#__PURE__*/function () {
5
+ function RxRestClient(endpointUrl, headers = {}, eventSource = EventSource) {
6
+ this.endpointUrl = endpointUrl;
7
+ this.headers = headers;
8
+ this.eventSource = eventSource;
9
+ }
10
+ var _proto = RxRestClient.prototype;
11
+ _proto.setHeaders = function setHeaders(headers) {
12
+ this.headers = headers;
13
+ };
14
+ _proto.handleError = function handleError(response) {
15
+ if (response.error) {
16
+ throw new Error('Server returned an error ' + JSON.stringify(response));
17
+ }
18
+ };
19
+ _proto.query = async function query(_query) {
20
+ var response = await postRequest(this.endpointUrl + '/query', _query, this.headers);
21
+ this.handleError(response);
22
+ return response;
23
+ };
24
+ _proto.observeQuery = function observeQuery(query) {
25
+ var result = new Subject();
26
+ var queryAsBase64 = btoa(JSON.stringify(query));
27
+ var eventSource = new this.eventSource(this.endpointUrl + '/query/observe?query=' + queryAsBase64, {
28
+ withCredentials: true,
29
+ /**
30
+ * Sending headers is not supported by the Browser EventSource API,
31
+ * only by the npm module we use. In react-native you might have
32
+ * to set another EventSource implementation.
33
+ * @link https://www.npmjs.com/package/eventsource
34
+ */
35
+ headers: this.headers
36
+ });
37
+ eventSource.onmessage = event => {
38
+ var eventData = JSON.parse(event.data);
39
+ result.next(eventData);
40
+ };
41
+ return result.asObservable();
42
+ };
43
+ _proto.get = function get(ids) {
44
+ var response = postRequest(this.endpointUrl + '/get', ids, this.headers);
45
+ this.handleError(response);
46
+ return response;
47
+ };
48
+ _proto.set = function set(docs) {
49
+ var response = postRequest(this.endpointUrl + '/set', docs, this.headers);
50
+ this.handleError(response);
51
+ return response;
52
+ };
53
+ _proto.delete = function _delete(ids) {
54
+ var response = postRequest(this.endpointUrl + '/delete', ids, this.headers);
55
+ this.handleError(response);
56
+ return response;
57
+ };
58
+ return RxRestClient;
59
+ }();
60
+ export function createRestClient(endpointUrl, headers, eventSource = EventSource) {
61
+ return new RxRestClient(endpointUrl, headers, eventSource);
62
+ }
63
+ export * from "./utils.js";
64
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["postRequest","Subject","EventSource","RxRestClient","endpointUrl","headers","eventSource","_proto","prototype","setHeaders","handleError","response","error","Error","JSON","stringify","query","observeQuery","result","queryAsBase64","btoa","withCredentials","onmessage","event","eventData","parse","data","next","asObservable","get","ids","set","docs","delete","_delete","createRestClient"],"sources":["../../../../src/plugins/client-rest/index.ts"],"sourcesContent":["import { ById, MangoQuery, newRxError } from 'rxdb/plugins/core';\nimport { postRequest } from './utils.ts';\nimport { Observable, Subject } from 'rxjs';\nimport EventSource from 'eventsource';\n\nexport class RxRestClient<RxDocType> {\n constructor(\n public readonly endpointUrl: string,\n public headers: ById<string> = {},\n public readonly eventSource: typeof EventSource | any = EventSource\n ) { }\n\n setHeaders(headers: ById<string>) {\n this.headers = headers;\n }\n\n handleError(response: any) {\n if (response.error) {\n throw new Error('Server returned an error ' + JSON.stringify(response));\n }\n }\n\n async query(query: MangoQuery<RxDocType>): Promise<{ documents: RxDocType[] }> {\n const response = await postRequest(\n this.endpointUrl + '/query',\n query,\n this.headers\n );\n this.handleError(response);\n return response;\n }\n\n observeQuery(query: MangoQuery<RxDocType>): Observable<RxDocType[]> {\n const result = new Subject<RxDocType[]>;\n const queryAsBase64 = btoa(JSON.stringify(query));\n const eventSource: EventSource = new this.eventSource(\n this.endpointUrl + '/query/observe?query=' + queryAsBase64,\n {\n withCredentials: true,\n /**\n * Sending headers is not supported by the Browser EventSource API,\n * only by the npm module we use. In react-native you might have\n * to set another EventSource implementation.\n * @link https://www.npmjs.com/package/eventsource\n */\n headers: this.headers\n });\n eventSource.onmessage = event => {\n const eventData = JSON.parse(event.data);\n result.next(eventData);\n };\n return result.asObservable();\n }\n\n get(ids: string[]): Promise<{ documents: RxDocType[] }> {\n const response = postRequest(\n this.endpointUrl + '/get',\n ids,\n this.headers\n );\n this.handleError(response);\n return response;\n }\n\n set(docs: RxDocType[]) {\n const response = postRequest(\n this.endpointUrl + '/set',\n docs,\n this.headers\n );\n this.handleError(response);\n return response;\n }\n\n delete(ids: string[]) {\n const response = postRequest(\n this.endpointUrl + '/delete',\n ids,\n this.headers\n );\n this.handleError(response);\n return response;\n }\n}\n\nexport function createRestClient<RxDocType>(\n endpointUrl: string,\n headers: ById<string>,\n eventSource: typeof EventSource | any = EventSource\n) {\n\n return new RxRestClient<RxDocType>(\n endpointUrl,\n headers,\n eventSource\n );\n}\n\n\nexport * from './utils.ts';\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export async function postRequest(url, body, headers = {}) {
2
+ var request = await fetch(url, {
3
+ method: 'POST',
4
+ headers: Object.assign({
5
+ 'Accept': 'application/json',
6
+ 'Content-Type': 'application/json'
7
+ }, headers),
8
+ body: JSON.stringify(body)
9
+ });
10
+ var response = await request.json();
11
+ return response;
12
+ }
13
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","names":["postRequest","url","body","headers","request","fetch","method","Object","assign","JSON","stringify","response","json"],"sources":["../../../../src/plugins/client-rest/utils.ts"],"sourcesContent":["import { ById } from 'rxdb/plugins/core';\n\nexport async function postRequest(\n url: string,\n body: any,\n headers: ById<string> = {},\n) {\n const request = await fetch(url, {\n method: 'POST',\n headers: Object.assign({\n 'Accept': 'application/json',\n 'Content-Type': 'application/json'\n }, headers),\n body: JSON.stringify(body)\n });\n const response = await request.json();\n return response;\n}\n"],"mappings":"AAEA,OAAO,eAAeA,WAAWA,CAC7BC,GAAW,EACXC,IAAS,EACTC,OAAqB,GAAG,CAAC,CAAC,EAC5B;EACE,IAAMC,OAAO,GAAG,MAAMC,KAAK,CAACJ,GAAG,EAAE;IAC7BK,MAAM,EAAE,MAAM;IACdH,OAAO,EAAEI,MAAM,CAACC,MAAM,CAAC;MACnB,QAAQ,EAAE,kBAAkB;MAC5B,cAAc,EAAE;IACpB,CAAC,EAAEL,OAAO,CAAC;IACXD,IAAI,EAAEO,IAAI,CAACC,SAAS,CAACR,IAAI;EAC7B,CAAC,CAAC;EACF,IAAMS,QAAQ,GAAG,MAAMP,OAAO,CAACQ,IAAI,CAAC,CAAC;EACrC,OAAOD,QAAQ;AACnB"}
@@ -0,0 +1,32 @@
1
+ import { newRxError, nextTick } from 'rxdb/plugins/core';
2
+ export async function parseResponse(replicationState, fetchResponse) {
3
+ if (fetchResponse.status === 426) {
4
+ replicationState.outdatedClient$.next();
5
+ nextTick().then(() => replicationState.cancel());
6
+ throw newRxError('RC_OUTDATED', {
7
+ url: fetchResponse.url
8
+ });
9
+ }
10
+ if (fetchResponse.status === 401) {
11
+ replicationState.unauthorized$.next();
12
+ throw newRxError('RC_UNAUTHORIZED', {
13
+ url: fetchResponse.url
14
+ });
15
+ }
16
+ if (fetchResponse.status === 403) {
17
+ replicationState.forbidden$.next();
18
+ nextTick().then(() => replicationState.cancel());
19
+ throw newRxError('RC_FORBIDDEN', {
20
+ url: fetchResponse.url
21
+ });
22
+ }
23
+ var data = await fetchResponse.json();
24
+ if (data.error) {
25
+ // TODO
26
+ console.log('TODO handle parseResponse error');
27
+ console.dir(data);
28
+ throw data;
29
+ }
30
+ return data;
31
+ }
32
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","names":["newRxError","nextTick","parseResponse","replicationState","fetchResponse","status","outdatedClient$","next","then","cancel","url","unauthorized$","forbidden$","data","json","error","console","log","dir"],"sources":["../../../../src/plugins/replication-server/helpers.ts"],"sourcesContent":["import { newRxError, nextTick } from 'rxdb/plugins/core';\nimport type { RxServerReplicationState } from './index.ts';\n\nexport async function parseResponse(\n replicationState: RxServerReplicationState<any>,\n fetchResponse: Response\n) {\n if (fetchResponse.status === 426) {\n replicationState.outdatedClient$.next();\n nextTick().then(() => replicationState.cancel());\n throw newRxError('RC_OUTDATED', {\n url: fetchResponse.url\n });\n }\n if (fetchResponse.status === 401) {\n replicationState.unauthorized$.next();\n throw newRxError('RC_UNAUTHORIZED', {\n url: fetchResponse.url\n });\n }\n if (fetchResponse.status === 403) {\n replicationState.forbidden$.next();\n nextTick().then(() => replicationState.cancel());\n throw newRxError('RC_FORBIDDEN', {\n url: fetchResponse.url\n });\n }\n const data = await fetchResponse.json();\n\n if (data.error) {\n // TODO\n console.log('TODO handle parseResponse error');\n console.dir(data);\n throw data;\n }\n\n return data;\n}\n"],"mappings":"AAAA,SAASA,UAAU,EAAEC,QAAQ,QAAQ,mBAAmB;AAGxD,OAAO,eAAeC,aAAaA,CAC/BC,gBAA+C,EAC/CC,aAAuB,EACzB;EACE,IAAIA,aAAa,CAACC,MAAM,KAAK,GAAG,EAAE;IAC9BF,gBAAgB,CAACG,eAAe,CAACC,IAAI,CAAC,CAAC;IACvCN,QAAQ,CAAC,CAAC,CAACO,IAAI,CAAC,MAAML,gBAAgB,CAACM,MAAM,CAAC,CAAC,CAAC;IAChD,MAAMT,UAAU,CAAC,aAAa,EAAE;MAC5BU,GAAG,EAAEN,aAAa,CAACM;IACvB,CAAC,CAAC;EACN;EACA,IAAIN,aAAa,CAACC,MAAM,KAAK,GAAG,EAAE;IAC9BF,gBAAgB,CAACQ,aAAa,CAACJ,IAAI,CAAC,CAAC;IACrC,MAAMP,UAAU,CAAC,iBAAiB,EAAE;MAChCU,GAAG,EAAEN,aAAa,CAACM;IACvB,CAAC,CAAC;EACN;EACA,IAAIN,aAAa,CAACC,MAAM,KAAK,GAAG,EAAE;IAC9BF,gBAAgB,CAACS,UAAU,CAACL,IAAI,CAAC,CAAC;IAClCN,QAAQ,CAAC,CAAC,CAACO,IAAI,CAAC,MAAML,gBAAgB,CAACM,MAAM,CAAC,CAAC,CAAC;IAChD,MAAMT,UAAU,CAAC,cAAc,EAAE;MAC7BU,GAAG,EAAEN,aAAa,CAACM;IACvB,CAAC,CAAC;EACN;EACA,IAAMG,IAAI,GAAG,MAAMT,aAAa,CAACU,IAAI,CAAC,CAAC;EAEvC,IAAID,IAAI,CAACE,KAAK,EAAE;IACZ;IACAC,OAAO,CAACC,GAAG,CAAC,iCAAiC,CAAC;IAC9CD,OAAO,CAACE,GAAG,CAACL,IAAI,CAAC;IACjB,MAAMA,IAAI;EACd;EAEA,OAAOA,IAAI;AACf"}
@@ -0,0 +1,146 @@
1
+ import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
2
+ import { ensureNotFalsy, flatClone, promiseWait, addRxPlugin, newRxError } from 'rxdb/plugins/core';
3
+ import { RxDBLeaderElectionPlugin } from 'rxdb/plugins/leader-election';
4
+ import { RxReplicationState, startReplicationOnLeaderShip } from 'rxdb/plugins/replication';
5
+ import { Subject } from 'rxjs';
6
+ import { parseResponse } from "./helpers.js";
7
+ import EventSource from 'eventsource';
8
+ export * from "./types.js";
9
+ export var RxServerReplicationState = /*#__PURE__*/function (_RxReplicationState) {
10
+ _inheritsLoose(RxServerReplicationState, _RxReplicationState);
11
+ function RxServerReplicationState(replicationIdentifier, collection, pull, push, live = true, retryTime = 1000 * 5, autoStart = true, headers = {}) {
12
+ var _this;
13
+ _this = _RxReplicationState.call(this, replicationIdentifier, collection, '_deleted', pull, push, live, retryTime, autoStart) || this;
14
+ _this.outdatedClient$ = new Subject();
15
+ _this.unauthorized$ = new Subject();
16
+ _this.forbidden$ = new Subject();
17
+ _this.replicationIdentifier = replicationIdentifier;
18
+ _this.collection = collection;
19
+ _this.pull = pull;
20
+ _this.push = push;
21
+ _this.live = live;
22
+ _this.retryTime = retryTime;
23
+ _this.autoStart = autoStart;
24
+ _this.headers = headers;
25
+ _this.onCancel.push(() => {
26
+ _this.outdatedClient$.complete();
27
+ _this.unauthorized$.complete();
28
+ _this.forbidden$.complete();
29
+ });
30
+ return _this;
31
+ }
32
+ var _proto = RxServerReplicationState.prototype;
33
+ _proto.setHeaders = function setHeaders(headers) {
34
+ this.headers = flatClone(headers);
35
+ };
36
+ return RxServerReplicationState;
37
+ }(RxReplicationState);
38
+ export function replicateServer(options) {
39
+ if (!options.pull && !options.push) {
40
+ throw newRxError('UT3', {
41
+ collection: options.collection.name,
42
+ args: {
43
+ replicationIdentifier: options.replicationIdentifier
44
+ }
45
+ });
46
+ }
47
+ options.live = typeof options.live === 'undefined' ? true : options.live;
48
+ options.waitForLeadership = typeof options.waitForLeadership === 'undefined' ? true : options.waitForLeadership;
49
+ var collection = options.collection;
50
+ addRxPlugin(RxDBLeaderElectionPlugin);
51
+ var pullStream$ = new Subject();
52
+ var replicationPrimitivesPull;
53
+ if (options.pull) {
54
+ replicationPrimitivesPull = {
55
+ async handler(checkpointOrNull, batchSize) {
56
+ var lwt = checkpointOrNull && checkpointOrNull.lwt ? checkpointOrNull.lwt : 0;
57
+ var id = checkpointOrNull && checkpointOrNull.id ? checkpointOrNull.id : '';
58
+ var url = options.url + ("/pull?lwt=" + lwt + "&id=" + id + "&limit=" + batchSize);
59
+ var response = await fetch(url, {
60
+ method: 'GET',
61
+ headers: Object.assign({
62
+ 'Accept': 'application/json',
63
+ 'Content-Type': 'application/json'
64
+ }, replicationState.headers)
65
+ });
66
+ var data = await await parseResponse(replicationState, response);
67
+ return {
68
+ documents: data.documents,
69
+ checkpoint: data.checkpoint
70
+ };
71
+ },
72
+ batchSize: ensureNotFalsy(options.pull).batchSize,
73
+ modifier: ensureNotFalsy(options.pull).modifier,
74
+ stream$: pullStream$.asObservable()
75
+ };
76
+ }
77
+ var replicationPrimitivesPush;
78
+ if (options.push) {
79
+ replicationPrimitivesPush = {
80
+ async handler(changeRows) {
81
+ var response = await fetch(options.url + '/push', {
82
+ method: 'POST',
83
+ headers: Object.assign({
84
+ 'Accept': 'application/json',
85
+ 'Content-Type': 'application/json'
86
+ }, replicationState.headers),
87
+ body: JSON.stringify(changeRows)
88
+ });
89
+ var conflictsArray = await parseResponse(replicationState, response);
90
+ return conflictsArray;
91
+ },
92
+ batchSize: options.push.batchSize,
93
+ modifier: options.push.modifier
94
+ };
95
+ }
96
+ var replicationState = new RxServerReplicationState(options.replicationIdentifier, collection, replicationPrimitivesPull, replicationPrimitivesPush, options.live, options.retryTime, options.autoStart, options.headers);
97
+
98
+ /**
99
+ * Use long polling to get live changes for the pull.stream$
100
+ */
101
+ if (options.live && options.pull) {
102
+ var startBefore = replicationState.start.bind(replicationState);
103
+ replicationState.start = async () => {
104
+ var useEventSource = options.eventSource ? options.eventSource : EventSource;
105
+ var eventSource;
106
+ var refreshEventSource = () => {
107
+ eventSource = new useEventSource(options.url + '/pullStream', {
108
+ withCredentials: true,
109
+ /**
110
+ * Sending headers is not supported by the Browser EventSource API,
111
+ * only by the npm module we use. In react-native you might have
112
+ * to set another EventSource implementation.
113
+ * @link https://www.npmjs.com/package/eventsource
114
+ */
115
+ headers: replicationState.headers
116
+ });
117
+ // TODO check for 426 errors and handle them
118
+ eventSource.onerror = err => {
119
+ if (err.status === 401) {
120
+ replicationState.unauthorized$.next();
121
+ eventSource.close();
122
+ promiseWait(replicationState.retryTime).then(() => refreshEventSource());
123
+ } else {
124
+ pullStream$.next('RESYNC');
125
+ }
126
+ };
127
+ eventSource.onopen = x => {
128
+ pullStream$.next('RESYNC');
129
+ };
130
+ eventSource.onmessage = event => {
131
+ var eventData = JSON.parse(event.data);
132
+ pullStream$.next({
133
+ documents: eventData.documents,
134
+ checkpoint: eventData.checkpoint
135
+ });
136
+ };
137
+ };
138
+ refreshEventSource();
139
+ replicationState.onCancel.push(() => eventSource && eventSource.close());
140
+ return startBefore();
141
+ };
142
+ }
143
+ startReplicationOnLeaderShip(options.waitForLeadership, replicationState);
144
+ return replicationState;
145
+ }
146
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["ensureNotFalsy","flatClone","promiseWait","addRxPlugin","newRxError","RxDBLeaderElectionPlugin","RxReplicationState","startReplicationOnLeaderShip","Subject","parseResponse","EventSource","RxServerReplicationState","_RxReplicationState","_inheritsLoose","replicationIdentifier","collection","pull","push","live","retryTime","autoStart","headers","_this","call","outdatedClient$","unauthorized$","forbidden$","onCancel","complete","_proto","prototype","setHeaders","replicateServer","options","name","args","waitForLeadership","pullStream$","replicationPrimitivesPull","handler","checkpointOrNull","batchSize","lwt","id","url","response","fetch","method","Object","assign","replicationState","data","documents","checkpoint","modifier","stream$","asObservable","replicationPrimitivesPush","changeRows","body","JSON","stringify","conflictsArray","startBefore","start","bind","useEventSource","eventSource","refreshEventSource","withCredentials","onerror","err","status","next","close","then","onopen","x","onmessage","event","eventData","parse"],"sources":["../../../../src/plugins/replication-server/index.ts"],"sourcesContent":["import {\n ensureNotFalsy,\n flatClone,\n promiseWait,\n RxCollection,\n ReplicationPullOptions,\n ReplicationPushOptions,\n RxReplicationPullStreamItem,\n RxStorageDefaultCheckpoint,\n ById,\n addRxPlugin, \n newRxError\n} from 'rxdb/plugins/core';\nimport { RxDBLeaderElectionPlugin } from 'rxdb/plugins/leader-election';\nimport {\n RxReplicationState,\n startReplicationOnLeaderShip\n} from 'rxdb/plugins/replication';\n\nimport { Subject } from 'rxjs';\nimport { ServerSyncOptions } from './types.ts';\nimport { parseResponse } from './helpers.ts';\nimport EventSource from 'eventsource';\n\nexport * from './types.ts';\n\nexport class RxServerReplicationState<RxDocType> extends RxReplicationState<RxDocType, RxStorageDefaultCheckpoint> {\n public readonly outdatedClient$ = new Subject<void>();\n public readonly unauthorized$ = new Subject<void>();\n public readonly forbidden$ = new Subject<void>();\n\n constructor(\n public readonly replicationIdentifier: string,\n public readonly collection: RxCollection<RxDocType>,\n public readonly pull?: ReplicationPullOptions<RxDocType, RxStorageDefaultCheckpoint>,\n public readonly push?: ReplicationPushOptions<RxDocType>,\n public readonly live: boolean = true,\n public retryTime: number = 1000 * 5,\n public autoStart: boolean = true,\n public headers: ById<string> = {}\n ) {\n super(\n replicationIdentifier,\n collection,\n '_deleted',\n pull,\n push,\n live,\n retryTime,\n autoStart\n );\n\n this.onCancel.push(() => {\n this.outdatedClient$.complete();\n this.unauthorized$.complete();\n this.forbidden$.complete();\n });\n }\n\n setHeaders(headers: ById<string>): void {\n this.headers = flatClone(headers);\n }\n}\n\nexport function replicateServer<RxDocType>(\n options: ServerSyncOptions<RxDocType>\n): RxServerReplicationState<RxDocType> {\n\n if (!options.pull && !options.push) {\n throw newRxError('UT3', {\n collection: options.collection.name,\n args: {\n replicationIdentifier: options.replicationIdentifier\n }\n });\n }\n\n options.live = typeof options.live === 'undefined' ? true : options.live;\n options.waitForLeadership = typeof options.waitForLeadership === 'undefined' ? true : options.waitForLeadership;\n\n const collection = options.collection;\n addRxPlugin(RxDBLeaderElectionPlugin);\n\n const pullStream$: Subject<RxReplicationPullStreamItem<RxDocType, RxStorageDefaultCheckpoint>> = new Subject();\n\n let replicationPrimitivesPull: ReplicationPullOptions<RxDocType, RxStorageDefaultCheckpoint> | undefined;\n if (options.pull) {\n replicationPrimitivesPull = {\n async handler(checkpointOrNull, batchSize) {\n const lwt = checkpointOrNull && checkpointOrNull.lwt ? checkpointOrNull.lwt : 0;\n const id = checkpointOrNull && checkpointOrNull.id ? checkpointOrNull.id : '';\n const url = options.url + `/pull?lwt=${lwt}&id=${id}&limit=${batchSize}`;\n const response = await fetch(url, {\n method: 'GET',\n headers: Object.assign({\n 'Accept': 'application/json',\n 'Content-Type': 'application/json'\n }, replicationState.headers),\n });\n const data = await await parseResponse(replicationState, response);\n return {\n documents: data.documents,\n checkpoint: data.checkpoint\n };\n },\n batchSize: ensureNotFalsy(options.pull).batchSize,\n modifier: ensureNotFalsy(options.pull).modifier,\n stream$: pullStream$.asObservable()\n };\n }\n\n let replicationPrimitivesPush: ReplicationPushOptions<RxDocType> | undefined;\n if (options.push) {\n replicationPrimitivesPush = {\n async handler(changeRows) {\n const response = await fetch(options.url + '/push', {\n method: 'POST',\n headers: Object.assign({\n 'Accept': 'application/json',\n 'Content-Type': 'application/json'\n }, replicationState.headers),\n body: JSON.stringify(changeRows)\n });\n const conflictsArray = await parseResponse(replicationState, response);\n return conflictsArray;\n },\n batchSize: options.push.batchSize,\n modifier: options.push.modifier\n };\n }\n\n const replicationState = new RxServerReplicationState<RxDocType>(\n options.replicationIdentifier,\n collection,\n replicationPrimitivesPull,\n replicationPrimitivesPush,\n options.live,\n options.retryTime,\n options.autoStart,\n options.headers\n );\n\n /**\n * Use long polling to get live changes for the pull.stream$\n */\n if (options.live && options.pull) {\n const startBefore = replicationState.start.bind(replicationState);\n replicationState.start = async () => {\n const useEventSource: typeof EventSource = options.eventSource ? options.eventSource : EventSource;\n let eventSource: EventSource;\n const refreshEventSource = () => {\n eventSource = new useEventSource(options.url + '/pullStream', {\n withCredentials: true,\n /**\n * Sending headers is not supported by the Browser EventSource API,\n * only by the npm module we use. In react-native you might have\n * to set another EventSource implementation.\n * @link https://www.npmjs.com/package/eventsource\n */\n headers: replicationState.headers\n });\n // TODO check for 426 errors and handle them\n eventSource.onerror = (err) => {\n if (err.status === 401) {\n replicationState.unauthorized$.next();\n eventSource.close();\n promiseWait(replicationState.retryTime).then(() => refreshEventSource());\n } else {\n pullStream$.next('RESYNC');\n }\n };\n eventSource.onopen = (x) => {\n pullStream$.next('RESYNC');\n }\n eventSource.onmessage = event => {\n const eventData = JSON.parse(event.data);\n pullStream$.next({\n documents: eventData.documents,\n checkpoint: eventData.checkpoint\n });\n };\n }\n refreshEventSource();\n\n replicationState.onCancel.push(() => eventSource && eventSource.close());\n return startBefore();\n };\n }\n\n startReplicationOnLeaderShip(options.waitForLeadership, replicationState);\n\n return replicationState;\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export {};
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../../src/plugins/replication-server/types.ts"],"sourcesContent":["import type {\n MaybePromise,\n ReplicationOptions,\n ReplicationPullOptions,\n ReplicationPushOptions,\n RxStorageDefaultCheckpoint\n} from 'rxdb/plugins/core';\n\nexport type ServerSyncPullOptions<RxDocType> =\n Omit<ReplicationPullOptions<RxDocType, RxStorageDefaultCheckpoint>, 'handler' | 'stream$'>\n & {\n };\n\nexport type ServerSyncPushOptions<RxDocType> = Omit<ReplicationPushOptions<RxDocType>, 'handler'>\n & {\n};\n\nexport type ServerSyncOptions<RxDocType> = Omit<\n ReplicationOptions<RxDocType, any>,\n 'pull' | 'push'\n> & {\n url: string;\n headers?: { [k: string]: string };\n pull?: ServerSyncPullOptions<RxDocType>;\n push?: ServerSyncPushOptions<RxDocType>;\n\n /**\n * If the EventSource API is not available\n * on the runtime, pass an own implementation here.\n * Mostly used with the \"eventsource\" npm package on Node.js.\n */\n eventSource?: typeof EventSource | any\n};\n"],"mappings":""}
@@ -0,0 +1,156 @@
1
+ import { prepareQuery, getChangedDocumentsSinceQuery } from 'rxdb/plugins/core';
2
+ import { getReplicationHandlerByCollection } from 'rxdb/plugins/replication-websocket';
3
+ import { filter, mergeMap } from 'rxjs';
4
+ import { ensureNotFalsy, getFromMapOrThrow, lastOfArray } from 'rxdb/plugins/utils';
5
+ import { addAuthMiddleware, blockPreviousVersionPaths, closeConnection, docContainsServerOnlyFields, doesContainRegexQuerySelector, getDocAllowedMatcher, mergeServerDocumentFieldsMonad, removeServerOnlyFieldsMonad, setCors, writeSSEHeaders } from "./helper.js";
6
+ export var RxServerReplicationEndpoint = function RxServerReplicationEndpoint(server, name, collection, queryModifier, changeValidator, serverOnlyFields, cors) {
7
+ this.type = 'replication';
8
+ this.server = server;
9
+ this.name = name;
10
+ this.collection = collection;
11
+ this.serverOnlyFields = serverOnlyFields;
12
+ this.cors = cors;
13
+ setCors(this.server, [this.name].join('/'), cors);
14
+ blockPreviousVersionPaths(this.server, [this.name].join('/'), collection.schema.version);
15
+ this.urlPath = [this.name, collection.schema.version].join('/');
16
+ var primaryPath = this.collection.schema.primaryPath;
17
+ var replicationHandler = getReplicationHandlerByCollection(this.server.database, collection.name);
18
+ var authDataByRequest = addAuthMiddleware(this.server, this.urlPath);
19
+ this.queryModifier = (authData, query) => {
20
+ if (doesContainRegexQuerySelector(query.selector)) {
21
+ throw new Error('$regex queries not allowed because of DOS-attacks');
22
+ }
23
+ return queryModifier(authData, query);
24
+ };
25
+ this.changeValidator = (authData, change) => {
26
+ if (change.assumedMasterState && docContainsServerOnlyFields(serverOnlyFields, change.assumedMasterState) || docContainsServerOnlyFields(serverOnlyFields, change.newDocumentState)) {
27
+ return false;
28
+ }
29
+ return changeValidator(authData, change);
30
+ };
31
+ var removeServerOnlyFields = removeServerOnlyFieldsMonad(this.serverOnlyFields);
32
+ var mergeServerDocumentFields = mergeServerDocumentFieldsMonad(this.serverOnlyFields);
33
+ this.server.expressApp.get('/' + this.urlPath + '/pull', async (req, res) => {
34
+ var authData = getFromMapOrThrow(authDataByRequest, req);
35
+ var id = req.query.id ? req.query.id : '';
36
+ var lwt = req.query.lwt ? parseInt(req.query.lwt, 10) : 0;
37
+ var limit = req.query.limit ? parseInt(req.query.limit, 10) : 1;
38
+ var plainQuery = getChangedDocumentsSinceQuery(this.collection.storageInstance, limit, {
39
+ id,
40
+ lwt
41
+ });
42
+ var useQueryChanges = this.queryModifier(ensureNotFalsy(authData), plainQuery);
43
+ var prepared = prepareQuery(this.collection.schema.jsonSchema, useQueryChanges);
44
+ var result = await this.collection.storageInstance.query(prepared);
45
+ var newCheckpoint = result.documents.length === 0 ? {
46
+ id,
47
+ lwt
48
+ } : {
49
+ id: ensureNotFalsy(lastOfArray(result.documents))[primaryPath],
50
+ updatedAt: ensureNotFalsy(lastOfArray(result.documents))._meta.lwt
51
+ };
52
+ var responseDocuments = result.documents.map(d => removeServerOnlyFields(d));
53
+ res.setHeader('Content-Type', 'application/json');
54
+ res.json({
55
+ documents: responseDocuments,
56
+ checkpoint: newCheckpoint
57
+ });
58
+ });
59
+ this.server.expressApp.post('/' + this.urlPath + '/push', async (req, res) => {
60
+ var authData = getFromMapOrThrow(authDataByRequest, req);
61
+ var docDataMatcherWrite = getDocAllowedMatcher(this, ensureNotFalsy(authData));
62
+ var rows = req.body;
63
+ var ids = [];
64
+ rows.forEach(row => ids.push(row.newDocumentState[primaryPath]));
65
+ for (var row of rows) {
66
+ // TODO remove this check
67
+ if (row.assumedMasterState && row.assumedMasterState._meta) {
68
+ throw new Error('body document contains meta!');
69
+ }
70
+ }
71
+
72
+ // ensure all writes are allowed
73
+ var nonAllowedRow = rows.find(row => {
74
+ if (!docDataMatcherWrite(row.newDocumentState) || row.assumedMasterState && !docDataMatcherWrite(row.assumedMasterState)) {
75
+ return true;
76
+ }
77
+ });
78
+ if (nonAllowedRow) {
79
+ closeConnection(res, 403, 'Forbidden');
80
+ return;
81
+ }
82
+ var hasInvalidChange = false;
83
+ var currentStateDocsArray = await this.collection.storageInstance.findDocumentsById(ids, true);
84
+ var currentStateDocs = new Map();
85
+ currentStateDocsArray.forEach(d => currentStateDocs.set(d[primaryPath], d));
86
+ var useRows = rows.map(row => {
87
+ var id = row.newDocumentState[primaryPath];
88
+ var isChangeValid = this.changeValidator(ensureNotFalsy(authData), {
89
+ newDocumentState: removeServerOnlyFields(row.newDocumentState),
90
+ assumedMasterState: removeServerOnlyFields(row.assumedMasterState)
91
+ });
92
+ if (!isChangeValid) {
93
+ hasInvalidChange = true;
94
+ }
95
+ var serverDoc = currentStateDocs.get(id);
96
+ return {
97
+ newDocumentState: mergeServerDocumentFields(row.newDocumentState, serverDoc),
98
+ assumedMasterState: mergeServerDocumentFields(row.assumedMasterState, serverDoc)
99
+ };
100
+ });
101
+ if (hasInvalidChange) {
102
+ closeConnection(res, 403, 'Forbidden');
103
+ return;
104
+ }
105
+ var conflicts = await replicationHandler.masterWrite(useRows);
106
+ res.setHeader('Content-Type', 'application/json');
107
+ res.json(conflicts);
108
+ });
109
+ this.server.expressApp.get('/' + this.urlPath + '/pullStream', async (req, res) => {
110
+ writeSSEHeaders(res);
111
+ var authData = getFromMapOrThrow(authDataByRequest, req);
112
+ var docDataMatcherStream = getDocAllowedMatcher(this, ensureNotFalsy(authData));
113
+ var subscription = replicationHandler.masterChangeStream$.pipe(mergeMap(async changes => {
114
+ /**
115
+ * The auth-data might be expired
116
+ * so we re-run the auth parsing each time
117
+ * before emitting an event.
118
+ */
119
+ var authData;
120
+ try {
121
+ authData = await server.authHandler(req.headers);
122
+ } catch (err) {
123
+ closeConnection(res, 401, 'Unauthorized');
124
+ return null;
125
+ }
126
+ if (changes === 'RESYNC') {
127
+ return changes;
128
+ } else {
129
+ var useDocs = changes.documents.filter(d => docDataMatcherStream(d));
130
+ return {
131
+ documents: useDocs,
132
+ checkpoint: changes.checkpoint
133
+ };
134
+ }
135
+ }), filter(f => f !== null && (f === 'RESYNC' || f.documents.length > 0))).subscribe(filteredAndModified => {
136
+ if (filteredAndModified === 'RESYNC') {
137
+ res.write('data: ' + JSON.stringify(filteredAndModified) + '\n\n');
138
+ } else {
139
+ var responseDocuments = ensureNotFalsy(filteredAndModified).documents.map(d => removeServerOnlyFields(d));
140
+ res.write('data: ' + JSON.stringify({
141
+ documents: responseDocuments,
142
+ checkpoint: ensureNotFalsy(filteredAndModified).checkpoint
143
+ }) + '\n\n');
144
+ }
145
+ });
146
+
147
+ /**
148
+ * @link https://youtu.be/0PcMuYGJPzM?si=AxkczxcMaUwhh8k9&t=363
149
+ */
150
+ req.on('close', () => {
151
+ subscription.unsubscribe();
152
+ res.end();
153
+ });
154
+ });
155
+ };
156
+ //# sourceMappingURL=endpoint-replication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint-replication.js","names":["prepareQuery","getChangedDocumentsSinceQuery","getReplicationHandlerByCollection","filter","mergeMap","ensureNotFalsy","getFromMapOrThrow","lastOfArray","addAuthMiddleware","blockPreviousVersionPaths","closeConnection","docContainsServerOnlyFields","doesContainRegexQuerySelector","getDocAllowedMatcher","mergeServerDocumentFieldsMonad","removeServerOnlyFieldsMonad","setCors","writeSSEHeaders","RxServerReplicationEndpoint","server","name","collection","queryModifier","changeValidator","serverOnlyFields","cors","type","join","schema","version","urlPath","primaryPath","replicationHandler","database","authDataByRequest","authData","query","selector","Error","change","assumedMasterState","newDocumentState","removeServerOnlyFields","mergeServerDocumentFields","expressApp","get","req","res","id","lwt","parseInt","limit","plainQuery","storageInstance","useQueryChanges","prepared","jsonSchema","result","newCheckpoint","documents","length","updatedAt","_meta","responseDocuments","map","d","setHeader","json","checkpoint","post","docDataMatcherWrite","rows","body","ids","forEach","row","push","nonAllowedRow","find","hasInvalidChange","currentStateDocsArray","findDocumentsById","currentStateDocs","Map","set","useRows","isChangeValid","serverDoc","conflicts","masterWrite","docDataMatcherStream","subscription","masterChangeStream$","pipe","changes","authHandler","headers","err","useDocs","f","subscribe","filteredAndModified","write","JSON","stringify","on","unsubscribe","end"],"sources":["../../../../src/plugins/server/endpoint-replication.ts"],"sourcesContent":["import {\n FilledMangoQuery,\n RxCollection,\n RxReplicationHandler,\n RxReplicationWriteToMasterRow,\n RxStorageDefaultCheckpoint,\n StringKeys,\n prepareQuery,\n getChangedDocumentsSinceQuery,\n RxDocumentData\n} from 'rxdb/plugins/core';\nimport { getReplicationHandlerByCollection } from 'rxdb/plugins/replication-websocket';\nimport type { RxServer } from './rx-server.ts';\nimport type {\n RxServerAuthData,\n RxServerChangeValidator,\n RxServerEndpoint,\n RxServerQueryModifier\n} from './types.ts';\nimport { filter, mergeMap } from 'rxjs';\nimport {\n ensureNotFalsy,\n getFromMapOrThrow,\n lastOfArray\n} from 'rxdb/plugins/utils';\n\nimport {\n addAuthMiddleware,\n blockPreviousVersionPaths,\n closeConnection,\n docContainsServerOnlyFields,\n doesContainRegexQuerySelector,\n getDocAllowedMatcher,\n mergeServerDocumentFieldsMonad,\n removeServerOnlyFieldsMonad,\n setCors,\n writeSSEHeaders\n} from './helper.ts';\n\nexport type RxReplicationEndpointMessageType = {\n id: string;\n method: StringKeys<RxReplicationHandler<any, any>> | 'auth';\n params: any[];\n};\n\nexport class RxServerReplicationEndpoint<AuthType, RxDocType> implements RxServerEndpoint<AuthType, RxDocType> {\n readonly type = 'replication';\n readonly urlPath: string;\n readonly changeValidator: RxServerChangeValidator<AuthType, RxDocType>;\n readonly queryModifier: RxServerQueryModifier<AuthType, RxDocType>;\n constructor(\n public readonly server: RxServer<AuthType>,\n public readonly name: string,\n public readonly collection: RxCollection<RxDocType>,\n queryModifier: RxServerQueryModifier<AuthType, RxDocType>,\n changeValidator: RxServerChangeValidator<AuthType, RxDocType>,\n public readonly serverOnlyFields: string[],\n public readonly cors?: string,\n ) {\n setCors(this.server, [this.name].join('/'), cors);\n blockPreviousVersionPaths(this.server, [this.name].join('/'), collection.schema.version);\n\n this.urlPath = [this.name, collection.schema.version].join('/');\n\n const primaryPath = this.collection.schema.primaryPath;\n const replicationHandler = getReplicationHandlerByCollection(this.server.database, collection.name);\n const authDataByRequest = addAuthMiddleware(\n this.server,\n this.urlPath\n );\n\n this.queryModifier = (authData, query) => {\n if (doesContainRegexQuerySelector(query.selector)) {\n throw new Error('$regex queries not allowed because of DOS-attacks');\n }\n return queryModifier(authData, query);\n }\n this.changeValidator = (authData, change) => {\n if (\n (change.assumedMasterState && docContainsServerOnlyFields(serverOnlyFields, change.assumedMasterState)) ||\n docContainsServerOnlyFields(serverOnlyFields, change.newDocumentState)\n ) {\n return false;\n }\n return changeValidator(authData, change);\n }\n const removeServerOnlyFields = removeServerOnlyFieldsMonad<RxDocType>(this.serverOnlyFields);\n const mergeServerDocumentFields = mergeServerDocumentFieldsMonad<RxDocType>(this.serverOnlyFields);\n\n this.server.expressApp.get('/' + this.urlPath + '/pull', async (req, res) => {\n const authData = getFromMapOrThrow(authDataByRequest, req);\n const id = req.query.id ? req.query.id as string : '';\n const lwt = req.query.lwt ? parseInt(req.query.lwt as any, 10) : 0;\n const limit = req.query.limit ? parseInt(req.query.limit as any, 10) : 1;\n const plainQuery = getChangedDocumentsSinceQuery<RxDocType, RxStorageDefaultCheckpoint>(\n this.collection.storageInstance,\n limit,\n { id, lwt }\n );\n const useQueryChanges: FilledMangoQuery<RxDocType> = this.queryModifier(\n ensureNotFalsy(authData),\n plainQuery\n );\n const prepared = prepareQuery<RxDocType>(\n this.collection.schema.jsonSchema,\n useQueryChanges\n );\n const result = await this.collection.storageInstance.query(prepared);\n\n const newCheckpoint = result.documents.length === 0 ? { id, lwt } : {\n id: ensureNotFalsy(lastOfArray(result.documents))[primaryPath],\n updatedAt: ensureNotFalsy(lastOfArray(result.documents))._meta.lwt\n };\n const responseDocuments = result.documents.map(d => removeServerOnlyFields(d));\n res.setHeader('Content-Type', 'application/json');\n res.json({\n documents: responseDocuments,\n checkpoint: newCheckpoint\n });\n });\n this.server.expressApp.post('/' + this.urlPath + '/push', async (req, res) => {\n const authData = getFromMapOrThrow(authDataByRequest, req);\n const docDataMatcherWrite = getDocAllowedMatcher(this, ensureNotFalsy(authData));\n const rows: RxReplicationWriteToMasterRow<RxDocType>[] = req.body;\n const ids: string[] = [];\n rows.forEach(row => ids.push((row.newDocumentState as any)[primaryPath]));\n\n for (const row of rows) {\n // TODO remove this check\n if (row.assumedMasterState && (row.assumedMasterState as any)._meta) {\n throw new Error('body document contains meta!');\n }\n }\n\n // ensure all writes are allowed\n const nonAllowedRow = rows.find(row => {\n if (\n !docDataMatcherWrite(row.newDocumentState as any) ||\n (row.assumedMasterState && !docDataMatcherWrite(row.assumedMasterState as any))\n ) {\n return true;\n }\n });\n if (nonAllowedRow) {\n closeConnection(res, 403, 'Forbidden');\n return;\n }\n let hasInvalidChange = false;\n\n const currentStateDocsArray = await this.collection.storageInstance.findDocumentsById(ids, true);\n const currentStateDocs = new Map<string, RxDocumentData<RxDocType>>();\n currentStateDocsArray.forEach(d => currentStateDocs.set((d as any)[primaryPath], d));\n\n const useRows: typeof rows = rows.map((row) => {\n const id = (row.newDocumentState as any)[primaryPath];\n const isChangeValid = this.changeValidator(ensureNotFalsy(authData), {\n newDocumentState: removeServerOnlyFields(row.newDocumentState),\n assumedMasterState: removeServerOnlyFields(row.assumedMasterState)\n });\n if (!isChangeValid) {\n hasInvalidChange = true;\n }\n\n const serverDoc = currentStateDocs.get(id);\n return {\n newDocumentState: mergeServerDocumentFields(row.newDocumentState, serverDoc),\n assumedMasterState: mergeServerDocumentFields(row.assumedMasterState as any, serverDoc)\n } as typeof row;\n });\n if (hasInvalidChange) {\n closeConnection(res, 403, 'Forbidden');\n return;\n }\n\n const conflicts = await replicationHandler.masterWrite(useRows);\n\n res.setHeader('Content-Type', 'application/json');\n res.json(conflicts);\n });\n this.server.expressApp.get('/' + this.urlPath + '/pullStream', async (req, res) => {\n writeSSEHeaders(res);\n\n const authData = getFromMapOrThrow(authDataByRequest, req);\n const docDataMatcherStream = getDocAllowedMatcher(this, ensureNotFalsy(authData));\n const subscription = replicationHandler.masterChangeStream$.pipe(\n mergeMap(async (changes) => {\n /**\n * The auth-data might be expired\n * so we re-run the auth parsing each time\n * before emitting an event.\n */\n let authData: RxServerAuthData<AuthType>;\n try {\n authData = await server.authHandler(req.headers);\n } catch (err) {\n closeConnection(res, 401, 'Unauthorized');\n return null;\n }\n\n if (changes === 'RESYNC') {\n return changes;\n } else {\n const useDocs = changes.documents.filter(d => docDataMatcherStream(d as any));\n return {\n documents: useDocs,\n checkpoint: changes.checkpoint\n };\n }\n }),\n filter(f => f !== null && (f === 'RESYNC' || f.documents.length > 0))\n ).subscribe(filteredAndModified => {\n if (filteredAndModified === 'RESYNC') {\n res.write('data: ' + JSON.stringify(filteredAndModified) + '\\n\\n');\n } else {\n const responseDocuments = ensureNotFalsy(filteredAndModified).documents.map(d => removeServerOnlyFields(d as any));\n res.write('data: ' + JSON.stringify({ documents: responseDocuments, checkpoint: ensureNotFalsy(filteredAndModified).checkpoint }) + '\\n\\n');\n }\n\n });\n\n /**\n * @link https://youtu.be/0PcMuYGJPzM?si=AxkczxcMaUwhh8k9&t=363\n */\n req.on('close', () => {\n subscription.unsubscribe();\n res.end();\n });\n });\n }\n}\n"],"mappings":"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"}