UNPKG

rxdb-server

Version:
149 lines (148 loc) 6.08 kB
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