rxdb-server
Version:
RxDB Server Plugin
149 lines (148 loc) • 6.08 kB
JavaScript
import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
import { ensureNotFalsy, flatClone, promiseWait, addRxPlugin, newRxError } from 'rxdb/plugins/core';
import { RxDBLeaderElectionPlugin } from 'rxdb/plugins/leader-election';
import { RxReplicationState, startReplicationOnLeaderShip } from 'rxdb/plugins/replication';
import { Subject } from 'rxjs';
import { parseResponse } from "./helpers.js";
import { EventSource } from 'eventsource';
import { customFetchWithFixedHeaders } from "../../utils.js";
export * from "./types.js";
export var RxServerReplicationState = /*#__PURE__*/function (_RxReplicationState) {
function RxServerReplicationState(replicationIdentifier, collection, pull, push, live = true, retryTime = 1000 * 5, autoStart = true, headers = {}) {
var _this;
_this = _RxReplicationState.call(this, replicationIdentifier, collection, '_deleted', pull, push, live, retryTime, autoStart) || this;
_this.outdatedClient$ = new Subject();
_this.unauthorized$ = new Subject();
_this.forbidden$ = new Subject();
_this.replicationIdentifier = replicationIdentifier;
_this.collection = collection;
_this.pull = pull;
_this.push = push;
_this.live = live;
_this.retryTime = retryTime;
_this.autoStart = autoStart;
_this.headers = headers;
_this.onCancel.push(() => {
_this.outdatedClient$.complete();
_this.unauthorized$.complete();
_this.forbidden$.complete();
});
return _this;
}
_inheritsLoose(RxServerReplicationState, _RxReplicationState);
var _proto = RxServerReplicationState.prototype;
_proto.setHeaders = function setHeaders(headers) {
this.headers = flatClone(headers);
};
return RxServerReplicationState;
}(RxReplicationState);
export function replicateServer(options) {
if (!options.pull && !options.push) {
throw newRxError('UT3', {
collection: options.collection.name,
args: {
replicationIdentifier: options.replicationIdentifier
}
});
}
options.live = typeof options.live === 'undefined' ? true : options.live;
options.waitForLeadership = typeof options.waitForLeadership === 'undefined' ? true : options.waitForLeadership;
var collection = options.collection;
addRxPlugin(RxDBLeaderElectionPlugin);
var pullStream$ = new Subject();
var replicationPrimitivesPull;
if (options.pull) {
replicationPrimitivesPull = {
async handler(checkpointOrNull, batchSize) {
var lwt = checkpointOrNull && checkpointOrNull.lwt ? checkpointOrNull.lwt : 0;
var id = checkpointOrNull && checkpointOrNull.id ? checkpointOrNull.id : '';
var url = options.url + ("/pull?lwt=" + lwt + "&id=" + id + "&limit=" + batchSize);
var response = await fetch(url, {
method: 'GET',
credentials: 'include',
headers: Object.assign({
'Accept': 'application/json',
'Content-Type': 'application/json'
}, replicationState.headers)
});
var data = await parseResponse(replicationState, response);
return {
documents: data.documents,
checkpoint: data.checkpoint
};
},
batchSize: ensureNotFalsy(options.pull).batchSize,
modifier: ensureNotFalsy(options.pull).modifier,
stream$: pullStream$.asObservable()
};
}
var replicationPrimitivesPush;
if (options.push) {
replicationPrimitivesPush = {
async handler(changeRows) {
var response = await fetch(options.url + '/push', {
method: 'POST',
credentials: 'include',
headers: Object.assign({
'Accept': 'application/json',
'Content-Type': 'application/json'
}, replicationState.headers),
body: JSON.stringify(changeRows)
});
var conflictsArray = await parseResponse(replicationState, response);
return conflictsArray;
},
batchSize: options.push.batchSize,
modifier: options.push.modifier
};
}
var replicationState = new RxServerReplicationState(options.replicationIdentifier, collection, replicationPrimitivesPull, replicationPrimitivesPush, options.live, options.retryTime, options.autoStart, options.headers);
/**
* Use long polling to get live changes for the pull.stream$
*/
if (options.live && options.pull) {
var startBefore = replicationState.start.bind(replicationState);
replicationState.start = async () => {
var useEventSource = options.eventSource ? options.eventSource : EventSource;
var eventSource;
var refreshEventSource = () => {
eventSource = new useEventSource(options.url + '/pullStream', {
withCredentials: true,
/**
* Sending headers is not supported by the Browser EventSource API,
* only by the npm module we use. In react-native you might have
* to set another EventSource implementation.
* @link https://www.npmjs.com/package/eventsource
*/
fetch: customFetchWithFixedHeaders(replicationState.headers)
});
// TODO check for 426 errors and handle them
eventSource.onerror = err => {
if (err.code === 401) {
replicationState.unauthorized$.next();
eventSource.close();
promiseWait(replicationState.retryTime).then(() => refreshEventSource());
} else {
pullStream$.next('RESYNC');
}
};
eventSource.onopen = x => {
pullStream$.next('RESYNC');
};
eventSource.onmessage = event => {
var eventData = JSON.parse(event.data);
pullStream$.next({
documents: eventData.documents,
checkpoint: eventData.checkpoint
});
};
};
refreshEventSource();
replicationState.onCancel.push(() => eventSource && eventSource.close());
return startBefore();
};
}
startReplicationOnLeaderShip(options.waitForLeadership, replicationState);
return replicationState;
}
//# sourceMappingURL=index.js.map