UNPKG

@vyer-technologies/relay-offline

Version:

Forked from @wora Relay Offline Capabilities

160 lines 6.44 kB
import { Environment as RelayEnvironment, Observable as RelayObservable, } from 'relay-runtime'; import RelayDefaultHandlerProvider from 'relay-runtime/lib/handlers/RelayDefaultHandlerProvider'; import { OfflineFirst } from '@vyer-technologies/offline-first'; import resolveImmediate from 'relay-runtime/lib/util/resolveImmediate'; import { v4 as uuid } from 'uuid'; import warning from 'fbjs/lib/warning'; import { PublishQueue } from '@vyer-technologies/relay-store'; export class Environment extends RelayEnvironment { _rehydrated = typeof window === 'undefined'; _relayStoreOffline; promisesRestore; constructor(config, persistOfflineOptions = {}) { super(config); const persistOptionsStoreOffline = { prefix: 'relay-offline', serialize: true, ...persistOfflineOptions, }; this._publishQueue = new PublishQueue(config.store, config.handlerProvider ?? RelayDefaultHandlerProvider, this._getDataID, this._missingFieldHandlers); this._relayStoreOffline = new OfflineFirst(persistOptionsStoreOffline); this.setOfflineOptions(); if (this._rehydrated) { this.promisesRestore = Promise.resolve(true); } this._store.setCheckGC(() => this.isOnline()); } setOfflineOptions(offlineOptions = {}) { const { onComplete, onDiscard, network, ...others } = offlineOptions; const options = { execute: (offlineRecord) => this.executeStoreOffline(network, offlineRecord), ...others, }; if (onComplete) { options.onComplete = (options) => { const { offlineRecord, response } = options; const { request: { payload: { operation }, }, id, } = offlineRecord; const snapshot = this.lookup(operation.fragment); return onComplete({ id, offlinePayload: offlineRecord, snapshot: snapshot.data, response }); }; } if (onDiscard) { options.onDiscard = (options) => { const { offlineRecord, error } = options; const { id } = offlineRecord; return onDiscard({ id, offlinePayload: offlineRecord, error }); }; } this._relayStoreOffline.setOfflineOptions(options); } executeStoreOffline(network = this.getNetwork(), offline) { const { request: { payload }, } = offline; const { operation, uploadables, cacheConfig } = payload; const request = operation.request ? operation.request : operation; const netCacheConfig = request.cacheConfig || cacheConfig || { force: true }; netCacheConfig.metadata = { ...netCacheConfig.metadata, offline, }; return network.execute(request.node.params, request.variables, netCacheConfig, uploadables).toPromise(); } clearCache() { return Promise.all([this._store.purge()]).then((_result) => { return true; }); } dispose() { this.getStoreOffline().dispose(); } hydrate() { if (!this.promisesRestore) { this.promisesRestore = Promise.all([this.getStoreOffline().hydrate(), this._store.hydrate()]) .then((_result) => { this._rehydrated = true; const updateRecords = this._store.__getUpdatedRecordIDs(); Object.keys(this._store.getSource().toJSON()).forEach((key) => { updateRecords.add(key); }); this._store.notify(); return true; }) .catch((error) => { this._rehydrated = false; throw error; }); } return this.promisesRestore; } isRehydrated() { return this._rehydrated; } isOnline() { return this.getStoreOffline().isOnline(); } getStoreOffline() { return this._relayStoreOffline; } retain(operation, configRetain) { return this._store.retain(operation, configRetain); } disposePersisted(id) { return this._store.disposePersisted(id); } executeMutationOffline({ operation, optimisticResponse, optimisticUpdater, updater, uploadables, }) { let optimisticConfig; if (optimisticResponse || optimisticUpdater) { optimisticConfig = { operation, response: optimisticResponse, updater: optimisticUpdater, }; } warning(!!optimisticConfig, 'commitMutation offline: no optimistic responses configured. the mutation will not perform any store updates.'); const source = RelayObservable.create((sink) => { resolveImmediate(() => { const sinkPublish = optimisticConfig ? this.getStore().getSource()._sink.toJSON() : {}; const backup = {}; Object.keys(sinkPublish).forEach((key) => (backup[key] = this.getStore().getSource()._base.get(key))); sink.next({ data: optimisticResponse ? optimisticResponse : {}, }); const id = uuid(); const payload = { operation, optimisticResponse, uploadables, }; const request = { payload, backup, sink: sinkPublish, }; this.getStoreOffline() .publish({ id, request, serial: true }) .then((_offlineRecord) => { this.getStoreOffline().notify(); sink.complete(); }) .catch((error) => { sink.error(error, true); }); }); }); return this._execute({ createSource: () => source, isClientPayload: false, operation, optimisticConfig, updater: optimisticResponse ? updater : optimisticUpdater, }); } executeMutation(mutationOptions) { if (this.isOnline()) { return super.executeMutation(mutationOptions); } else { return this.executeMutationOffline(mutationOptions); } } } //# sourceMappingURL=Environment.js.map