,
304 | defaultCommit: { type: string },
305 | defaultRollback: { type: string },
306 | persist: (store: any) => any,
307 | persistOptions: {},
308 | persistCallback: (callback: any) => any,
309 | persistAutoRehydrate: (config: ?{}) => (next: any) => any,
310 | offlineStateLens: (state: any) => { get: OfflineState, set: (offlineState: ?OfflineState) => any }
311 | };
312 | ```
313 |
314 | #### Passing configuration to the enhancer
315 | The `offline` store enhancer takes the [configuration object](#configuration-object) as a final parameter:
316 | ```diff
317 | + import { offline } from 'redux-offline';
318 | + import defaultConfig from 'redux-offline/lib/defaults';
319 |
320 | const store = createStore(
321 | reducer,
322 | preloadedState,
323 | - middleware
324 | + compose(middleware, offline(defaultConfig))
325 | );
326 | ```
327 |
328 | #### Overriding default properties
329 | You can override any individual property in the default configuration:
330 | ```diff
331 | import { offline } from 'redux-offline';
332 | import defaultConfig from 'redux-offline/lib/defaults';
333 |
334 | const customConfig = {
335 | ...defaultConfig,
336 | effect: (effect, _action) => Api.send(effect)
337 | }
338 |
339 | const store = createStore(
340 | reducer,
341 | preloadedState,
342 | - middleware
343 | + compose(middleware, offline(customConfig))
344 | );
345 | ```
346 |
347 | #### Only import what you need
348 | The reason for default config is defined as a separate import is, that it pulls in the [redux-persist](https://github.com/rt2zz/redux-persist) dependency and a limited, but non-negligible amount of library code. If you want to minimize your bundle size, you'll want to avoid importing any code you don't use, and bring in only the pieces you need:
349 |
350 | ```diff
351 | import { offline } from 'redux-offline';
352 | import retry from 'redux-offline/lib/defaults/retry';
353 | import discard from 'redux-offline/lib/defaults/discard';
354 |
355 | const myConfig = {
356 | retry,
357 | discard,
358 | effect: (effect, action) => MyCustomApiService.send(effect, action),
359 | detectNetwork: (callback) => MyCustomPingService.startPing(callback),
360 | persist: (store) => MyCustomPersistence.persist(store)
361 | };
362 |
363 | const store = createStore(
364 | reducer,
365 | preloadedState,
366 | - middleware
367 | + compose(middleware, offline(myConfig))
368 | myConfig
369 | );
370 | ```
371 |
372 |
373 | ### I want to...
374 |
375 | #### Change how network requests are made
376 |
377 | Probably the first thing you will want to do is to replace the default `fetch` effects handler. Do this by overriding `config.effect`:
378 | ```js
379 | const config = {
380 | effect: (effect, action) => {
381 | console.log(`Executing effect for ${action.type}`);
382 | return MyApi.send(effect)
383 | }
384 | }
385 | ```
386 |
387 | The first parameter is whatever value is set in `action.meta.offline.effect`. The second parameter is the full action, which may be useful for context. The method is expected to return a Promise. The full signature of the effect handler is: `(effect: any, action: OfflineAction) => Promise`.
388 |
389 |
390 | #### Change how state is saved to disk
391 |
392 | By default, persistence is handled by [redux-persist](https://github.com/rt2zz/redux-persist). The recommended way of customizing
393 | persistence is to configure redux-persist. You can pass any valid configuration
394 | to redux-persist by defining it `config.persistOptions`:
395 | ```js
396 | const config = {
397 | persistOptions: { /*...*/ }
398 | };
399 | ```
400 |
401 | You can pass the callback for redux-persist as well. This function would be called when rehydration is complete. It's useful if you want to delay rendering until rehydration is complete. You can define it in `config.persistCallback`:
402 | ```js
403 | const config = {
404 | persistCallback: () => { /*...*/ }
405 | };
406 | ```
407 |
408 | You can pass your persistAutoRehydrate method. For example in this way you can add a logger to the persistor.
409 | ```js
410 | import { autoRehydrate } from 'redux-persist';
411 |
412 | const config = {
413 | persistAutoRehydrate: () => autoRehydrate({log: true})
414 | };
415 | ```
416 |
417 | If you want to replace redux-persist entirely **(not recommended)**, you can override `config.persist`. The function receives the store instance as a first parameter, and is responsible for setting any subscribers to listen for store changes to persist it.
418 | ```js
419 | const config = {
420 | persist: (store) =>
421 | store.subscribe(() => console.log(store.getState()))
422 | )
423 | }
424 | ```
425 |
426 | If you override `config.store`, you will also need to manage the rehydration of your state manually.
427 |
428 | #### Change how network status is detected
429 |
430 | To replace the default network status detector, override the `config.detectNetwork` method:
431 | ```js
432 | const config = {
433 | detectNetwork: callback => MyCustomDetector.on('change', callback)
434 | }
435 | ```
436 |
437 | The function is passed a callback, which you should call with boolean `true` when the app gets back online, and `false` when it goes offline.
438 |
439 | #### Change how irreconcilable errors are detected
440 |
441 | Actions in the queue are by default discarded when a server returns
442 | a HTTP `4xx` error. To change this, set override the `config.discard` method:
443 | ```js
444 | const config = {
445 | discard: (error, action, retries) => error.permanent || retries > 10;
446 | }
447 | ```
448 |
449 | The method receives the Error returned by the effect reconciler, the action being processed, and a number representing how many times the action has been retried. If the method returns `true`, the action will be discarded; `false`, and it will be retried. The full signature of the method is `(error: any, action: OfflineAction, retries: number) => boolean`. Alternatively, you can return a Promise object that resolve to a boolean, allowing you to detect when to discard asynchronously (for example, doing a request to a server to refresh a token and try again).
450 |
451 | #### Change how network requests are retried
452 |
453 | By default, sending actions is retried on a decaying schedule starting with retries every few seconds, eventually slowing down to an hour before the last retry. These retry delays only apply to scenarios where the device reports being online but the server cannot be reached, or the server is reached but is responding with a non-permanent error.
454 |
455 | To configure the retry duration, override `config.retry`:
456 | ```js
457 | const config = {
458 | retry: (action, retries) => action.meta.urgent ? 100 : 1000 * (retries + 1)
459 | }
460 | ```
461 |
462 | The function receives the action and a number representing how many times the
463 | action has been retried, and should reply with a number representing the amount
464 | of milliseconds to wait until the next retry. If this method returns `null` or
465 | `undefined`, the action will not be retried until the next time the app comes
466 | online, is started, or you manually fire an `Offline/SEND` action.
467 |
468 | #### Change how errors are handled
469 |
470 | Granular error handling is not yet implemented. You can use discard/retry, and
471 | if necessary to purge messages from your queue, you can filter `state.offline.outbox`
472 | in your reducers. Official support coming soon.
473 |
474 | #### Synchronise my state while the app is not open
475 |
476 | Background sync is not yet supported. Coming soon.
477 |
478 | #### Use an [Immutable](https://facebook.github.io/immutable-js/) store
479 |
480 | The `offline` state branch created by Redux Offline needs to be a vanilla JavaScript object.
481 | If your entire store is immutable you should check out [`redux-offline-immutable-config`](https://github.com/anyjunk/redux-offline-immutable-config) which provides drop-in configurations using immutable counterparts and code examples.
482 | If you use Immutable in the rest of your store, but the root object, you should not need extra configurations.
483 |
484 | [Contributions welcome](#contributing).
485 |
486 | #### Choose where the offline middleware is added
487 |
488 | By default, the offline middleware is inserted right before the offline store enhancer as part of its own middleware chain. If you want more control over where the middleware is inserted, consider using the alternative api, `createOffline()`.
489 |
490 | ```js
491 | import { createOffline } from "@redux-offline/redux-offline";
492 | const { middleware, enhanceReducer, enhanceStore } = createOffline(config);
493 | const store = createStore(
494 | enhanceReducer(rootReducer),
495 | initialStore,
496 | compose(applyMiddleware(middleware), enhanceStore)
497 | );
498 | ```
499 |
500 |
501 | ## Contributing
502 |
503 | Improvements and additions welcome. For large changes, please submit a discussion issue before jumping to coding; we'd hate you to waste the effort.
504 |
505 | In lieu of a formal style guide, follow the included eslint rules, and use Prettier to format your code.
506 |
507 | ## Miscellanea
508 |
509 | ### Prior art
510 |
511 | Redux Offline is a distillation of patterns discovered while building apps using previously existing libraries:
512 |
513 | * Forbes Lindesay's [redux-optimist](https://github.com/ForbesLindesay/redux-optimist)
514 | * Zack Story's [redux-persist](https://github.com/rt2zz/redux-persist)
515 |
516 | Without their work, Redux Offline wouldn't exist. If you like the ideas behind Redux Offline, but want to build your own stack from lower-level components, these are good places to start.
517 |
518 | ### License
519 |
520 | MIT
521 |
--------------------------------------------------------------------------------
/docs/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sorodrigo/redux-offline/911129aa73d1eefa0ef51237fb3f4eb36bc0d4b5/docs/logo.png
--------------------------------------------------------------------------------
/docs/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Logo
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Redux Offline
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/examples/basic/README.md:
--------------------------------------------------------------------------------
1 | Visualization of Redux Offline's request resolution.
2 |
3 | ## Installation
4 |
5 | Install and start the server:
6 |
7 | ```bash
8 | yarn && yarn start
9 | ```
10 |
11 | Then, start the client:
12 |
13 | ```bash
14 | cd client
15 | yarn && yarn start
16 | ```
17 |
18 | This launches a Webpack dev server, which hosts the static content. Other requests are proxied to the server launched previously.
19 |
20 | See [Create React App](https://github.com/facebookincubator/create-react-app) for more information.
21 |
--------------------------------------------------------------------------------
/examples/basic/client/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/examples/basic/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@redux-offline/redux-offline": "^2.1.0",
7 | "react": "^16.0.0",
8 | "react-dom": "^16.0.0",
9 | "react-redux": "^5.0.6",
10 | "react-scripts": "1.0.14",
11 | "redux": "^3.7.2"
12 | },
13 | "scripts": {
14 | "start": "react-scripts start",
15 | "alternative": "REACT_APP_OFFLINE_API=alternative react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test --env=jsdom",
18 | "eject": "react-scripts eject"
19 | },
20 | "proxy": "http://localhost:4000"
21 | }
22 |
--------------------------------------------------------------------------------
/examples/basic/client/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sorodrigo/redux-offline/911129aa73d1eefa0ef51237fb3f4eb36bc0d4b5/examples/basic/client/public/favicon.ico
--------------------------------------------------------------------------------
/examples/basic/client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | React App
23 |
24 |
25 |
26 | You need to enable JavaScript to run this app.
27 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/examples/basic/client/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/examples/basic/client/src/actions.js:
--------------------------------------------------------------------------------
1 | function succeedAlways() {
2 | return {
3 | type: 'SUCCEED_ALWAYS',
4 | meta: {
5 | offline: {
6 | effect: { url: '/succeed-always' },
7 | commit: { type: 'SUCCEED_ALWAYS_SUCCESS' },
8 | rollback: { type: 'SUCCEED_ALWAYS_FAILURE' }
9 | }
10 | }
11 | };
12 | }
13 |
14 | function succeedSometimes() {
15 | return {
16 | type: 'SUCCEED_SOMETIMES',
17 | meta: {
18 | offline: {
19 | effect: { url: '/succeed-sometimes' },
20 | commit: { type: 'SUCCEED_SOMETIMES_SUCCESS' },
21 | rollback: { type: 'SUCCEED_SOMETIMES_FAILURE' }
22 | }
23 | }
24 | };
25 | }
26 |
27 | function failSometimes() {
28 | return {
29 | type: 'FAIL_SOMETIMES',
30 | meta: {
31 | offline: {
32 | effect: { url: '/fail-sometimes' },
33 | commit: { type: 'FAIL_SOMETIMES_SUCCESS' },
34 | rollback: { type: 'FAIL_SOMETIMES_FAILURE' }
35 | }
36 | }
37 | };
38 | }
39 |
40 | export { succeedAlways, succeedSometimes, failSometimes };
41 |
--------------------------------------------------------------------------------
/examples/basic/client/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Provider } from 'react-redux';
3 | import MakeRequests from './MakeRequests';
4 | import RequestsQueue from './RequestsQueue';
5 | import SyncStatus from './SyncStatus';
6 | import store from '../store';
7 |
8 | function App() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 | }
19 |
20 | export default App;
21 |
--------------------------------------------------------------------------------
/examples/basic/client/src/components/MakeRequests.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 | import { bindActionCreators } from 'redux';
4 | import { succeedAlways, succeedSometimes, failSometimes } from '../actions';
5 |
6 | function MakeRequests({ succeedAlways, succeedSometimes, failSometimes }) {
7 | return (
8 |
9 | Succeed Always
10 | Succeed Sometimes
11 | Fail Sometimes
12 |
13 | );
14 | }
15 |
16 | function mapDispatchToProps(dispatch) {
17 | return bindActionCreators(
18 | {
19 | succeedAlways,
20 | succeedSometimes,
21 | failSometimes
22 | },
23 | dispatch
24 | );
25 | }
26 |
27 | const ConnectedComponent = connect(null, mapDispatchToProps)(MakeRequests);
28 |
29 | export { MakeRequests as RawComponent };
30 | export default ConnectedComponent;
31 |
--------------------------------------------------------------------------------
/examples/basic/client/src/components/RequestsQueue.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 |
4 | function RequestsQueue({ actions }) {
5 | if (actions.length === 0) {
6 | return There are no requests
;
7 | }
8 |
9 | return (
10 |
11 | {actions.map(action => (
12 |
13 | {action.type}
14 | #{action.meta.transaction}
15 |
16 | ))}
17 |
18 | );
19 | }
20 |
21 | function mapStateToProps(state) {
22 | return {
23 | actions: state.offline.outbox
24 | };
25 | }
26 |
27 | const ConnectedComponent = connect(mapStateToProps)(RequestsQueue);
28 |
29 | export { RequestsQueue as RawComponent };
30 | export default ConnectedComponent;
31 |
--------------------------------------------------------------------------------
/examples/basic/client/src/components/SyncStatus.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { connect } from 'react-redux';
3 |
4 | function SyncStatus({ timer, busy, retryScheduled, attempt }) {
5 | if (!busy && !retryScheduled) {
6 | return Synced
;
7 | } else if (busy) {
8 | return Waiting on request - Attempt #{attempt}
;
9 | }
10 | return (
11 |
12 | Waiting on retry: {timer}s - Attempt #{attempt}
13 |
14 | );
15 | }
16 |
17 | function mapStateToProps(state) {
18 | return {
19 | timer: state.timer,
20 | busy: state.offline.busy,
21 | retryScheduled: state.offline.retryScheduled,
22 | attempt: state.offline.retryCount + 1
23 | };
24 | }
25 |
26 | const ConnectedComponent = connect(mapStateToProps)(SyncStatus);
27 |
28 | export { SyncStatus as RawComponent };
29 | export default ConnectedComponent;
30 |
--------------------------------------------------------------------------------
/examples/basic/client/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/examples/basic/client/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './components/App';
5 | import registerServiceWorker from './registerServiceWorker';
6 |
7 | ReactDOM.render( , document.getElementById('root'));
8 | registerServiceWorker();
9 |
--------------------------------------------------------------------------------
/examples/basic/client/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | const isLocalhost = Boolean(
12 | window.location.hostname === 'localhost' ||
13 | // [::1] is the IPv6 localhost address.
14 | window.location.hostname === '[::1]' ||
15 | // 127.0.0.1/8 is considered localhost for IPv4.
16 | window.location.hostname.match(
17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
18 | )
19 | );
20 |
21 | export default function register() {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (!isLocalhost) {
36 | // Is not local host. Just register service worker
37 | registerValidSW(swUrl);
38 | } else {
39 | // This is running on localhost. Lets check if a service worker still exists or not.
40 | checkValidServiceWorker(swUrl);
41 | }
42 | });
43 | }
44 | }
45 |
46 | function registerValidSW(swUrl) {
47 | navigator.serviceWorker
48 | .register(swUrl)
49 | .then(registration => {
50 | registration.onupdatefound = () => {
51 | const installingWorker = registration.installing;
52 | installingWorker.onstatechange = () => {
53 | if (installingWorker.state === 'installed') {
54 | if (navigator.serviceWorker.controller) {
55 | // At this point, the old content will have been purged and
56 | // the fresh content will have been added to the cache.
57 | // It's the perfect time to display a "New content is
58 | // available; please refresh." message in your web app.
59 | console.log('New content is available; please refresh.');
60 | } else {
61 | // At this point, everything has been precached.
62 | // It's the perfect time to display a
63 | // "Content is cached for offline use." message.
64 | console.log('Content is cached for offline use.');
65 | }
66 | }
67 | };
68 | };
69 | })
70 | .catch(error => {
71 | console.error('Error during service worker registration:', error);
72 | });
73 | }
74 |
75 | function checkValidServiceWorker(swUrl) {
76 | // Check if the service worker can be found. If it can't reload the page.
77 | fetch(swUrl)
78 | .then(response => {
79 | // Ensure service worker exists, and that we really are getting a JS file.
80 | if (
81 | response.status === 404 ||
82 | response.headers.get('content-type').indexOf('javascript') === -1
83 | ) {
84 | // No service worker found. Probably a different app. Reload the page.
85 | navigator.serviceWorker.ready.then(registration => {
86 | registration.unregister().then(() => {
87 | window.location.reload();
88 | });
89 | });
90 | } else {
91 | // Service worker found. Proceed as normal.
92 | registerValidSW(swUrl);
93 | }
94 | })
95 | .catch(() => {
96 | console.log(
97 | 'No internet connection found. App is running in offline mode.'
98 | );
99 | });
100 | }
101 |
102 | export function unregister() {
103 | if ('serviceWorker' in navigator) {
104 | navigator.serviceWorker.ready.then(registration => {
105 | registration.unregister();
106 | });
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/examples/basic/client/src/store.js:
--------------------------------------------------------------------------------
1 | import { applyMiddleware, compose, createStore } from 'redux';
2 | import { offline, createOffline } from '@redux-offline/redux-offline';
3 | import defaultConfig from '@redux-offline/redux-offline/lib/defaults';
4 |
5 | const initialState = {
6 | timer: 0
7 | };
8 | function reducer(state = initialState, action) {
9 | if (action.type === 'Offline/SCHEDULE_RETRY') {
10 | return {
11 | ...state,
12 | timer: action.payload.delay / 1000
13 | };
14 | }
15 | if (action.type === 'TICK') {
16 | return {
17 | ...state,
18 | timer: state.timer === 0 ? 0 : state.timer - 1
19 | };
20 | }
21 | return state;
22 | }
23 |
24 | const config = {
25 | ...defaultConfig,
26 | retry(_action, retries) {
27 | return (retries + 1) * 1000;
28 | }
29 | };
30 |
31 | function tickMiddleware(store) {
32 | return next => action => {
33 | if (action.type === 'Offline/SCHEDULE_RETRY') {
34 | const intervalId = setInterval(() => {
35 | store.dispatch({ type: 'TICK' });
36 | }, 1000);
37 | setTimeout(() => clearInterval(intervalId), action.payload.delay);
38 | }
39 | return next(action);
40 | };
41 | }
42 | const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
43 |
44 | let store;
45 | if (process.env.REACT_APP_OFFLINE_API === 'alternative') {
46 | const { middleware, enhanceReducer, enhanceStore } = createOffline(config);
47 | store = createStore(
48 | enhanceReducer(reducer),
49 | undefined,
50 | composeEnhancers(applyMiddleware(middleware, tickMiddleware), enhanceStore)
51 | );
52 | } else {
53 | store = createStore(
54 | reducer,
55 | composeEnhancers(offline(config), applyMiddleware(tickMiddleware))
56 | );
57 | }
58 |
59 | export default store;
60 |
--------------------------------------------------------------------------------
/examples/basic/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "basic-example",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "node server.js"
7 | },
8 | "dependencies": {
9 | "express": "^4.16.1"
10 | },
11 | "main": "index.js",
12 | "license": "MIT"
13 | }
14 |
--------------------------------------------------------------------------------
/examples/basic/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 |
3 | const app = express();
4 |
5 | app.use((_req, _res, next) => setTimeout(next, 400));
6 |
7 | app.get('/succeed-always', (_req, res) => {
8 | res.status(200).json({ some: 'data' });
9 | });
10 |
11 | app.get('/succeed-sometimes', (_req, res) => {
12 | if (Math.random() < 0.5) {
13 | res.status(500).json({ error: 'server' });
14 | } else {
15 | res.status(200).json({ some: 'data' });
16 | }
17 | });
18 |
19 | app.get('/fail-sometimes', (_req, res) => {
20 | if (Math.random() < 0.5) {
21 | res.status(500).json({ error: 'server' });
22 | } else {
23 | res.status(400).json({ error: 'client' });
24 | }
25 | });
26 |
27 | app.listen(4000);
28 |
--------------------------------------------------------------------------------
/flow-typed/npm/babel-cli_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: 4ed046e8a59cab80808a45c9f5b25815
2 | // flow-typed version: <>/babel-cli_v^6.18.0/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'babel-cli'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'babel-cli' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'babel-cli/bin/babel-doctor' {
26 | declare module.exports: any;
27 | }
28 |
29 | declare module 'babel-cli/bin/babel-external-helpers' {
30 | declare module.exports: any;
31 | }
32 |
33 | declare module 'babel-cli/bin/babel-node' {
34 | declare module.exports: any;
35 | }
36 |
37 | declare module 'babel-cli/bin/babel' {
38 | declare module.exports: any;
39 | }
40 |
41 | declare module 'babel-cli/lib/_babel-node' {
42 | declare module.exports: any;
43 | }
44 |
45 | declare module 'babel-cli/lib/babel-external-helpers' {
46 | declare module.exports: any;
47 | }
48 |
49 | declare module 'babel-cli/lib/babel-node' {
50 | declare module.exports: any;
51 | }
52 |
53 | declare module 'babel-cli/lib/babel/dir' {
54 | declare module.exports: any;
55 | }
56 |
57 | declare module 'babel-cli/lib/babel/file' {
58 | declare module.exports: any;
59 | }
60 |
61 | declare module 'babel-cli/lib/babel/index' {
62 | declare module.exports: any;
63 | }
64 |
65 | declare module 'babel-cli/lib/babel/util' {
66 | declare module.exports: any;
67 | }
68 |
69 | // Filename aliases
70 | declare module 'babel-cli/bin/babel-doctor.js' {
71 | declare module.exports: $Exports<'babel-cli/bin/babel-doctor'>;
72 | }
73 | declare module 'babel-cli/bin/babel-external-helpers.js' {
74 | declare module.exports: $Exports<'babel-cli/bin/babel-external-helpers'>;
75 | }
76 | declare module 'babel-cli/bin/babel-node.js' {
77 | declare module.exports: $Exports<'babel-cli/bin/babel-node'>;
78 | }
79 | declare module 'babel-cli/bin/babel.js' {
80 | declare module.exports: $Exports<'babel-cli/bin/babel'>;
81 | }
82 | declare module 'babel-cli/index' {
83 | declare module.exports: $Exports<'babel-cli'>;
84 | }
85 | declare module 'babel-cli/index.js' {
86 | declare module.exports: $Exports<'babel-cli'>;
87 | }
88 | declare module 'babel-cli/lib/_babel-node.js' {
89 | declare module.exports: $Exports<'babel-cli/lib/_babel-node'>;
90 | }
91 | declare module 'babel-cli/lib/babel-external-helpers.js' {
92 | declare module.exports: $Exports<'babel-cli/lib/babel-external-helpers'>;
93 | }
94 | declare module 'babel-cli/lib/babel-node.js' {
95 | declare module.exports: $Exports<'babel-cli/lib/babel-node'>;
96 | }
97 | declare module 'babel-cli/lib/babel/dir.js' {
98 | declare module.exports: $Exports<'babel-cli/lib/babel/dir'>;
99 | }
100 | declare module 'babel-cli/lib/babel/file.js' {
101 | declare module.exports: $Exports<'babel-cli/lib/babel/file'>;
102 | }
103 | declare module 'babel-cli/lib/babel/index.js' {
104 | declare module.exports: $Exports<'babel-cli/lib/babel/index'>;
105 | }
106 | declare module 'babel-cli/lib/babel/util.js' {
107 | declare module.exports: $Exports<'babel-cli/lib/babel/util'>;
108 | }
109 |
--------------------------------------------------------------------------------
/flow-typed/npm/babel-core_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: ba3cc9e95abaf3c9239b928223c62a9c
2 | // flow-typed version: <>/babel-core_v^6.18.2/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'babel-core'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'babel-core' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'babel-core/lib/api/browser' {
26 | declare module.exports: any;
27 | }
28 |
29 | declare module 'babel-core/lib/api/node' {
30 | declare module.exports: any;
31 | }
32 |
33 | declare module 'babel-core/lib/helpers/get-possible-plugin-names' {
34 | declare module.exports: any;
35 | }
36 |
37 | declare module 'babel-core/lib/helpers/get-possible-preset-names' {
38 | declare module.exports: any;
39 | }
40 |
41 | declare module 'babel-core/lib/helpers/merge' {
42 | declare module.exports: any;
43 | }
44 |
45 | declare module 'babel-core/lib/helpers/normalize-ast' {
46 | declare module.exports: any;
47 | }
48 |
49 | declare module 'babel-core/lib/helpers/resolve-from-possible-names' {
50 | declare module.exports: any;
51 | }
52 |
53 | declare module 'babel-core/lib/helpers/resolve-plugin' {
54 | declare module.exports: any;
55 | }
56 |
57 | declare module 'babel-core/lib/helpers/resolve-preset' {
58 | declare module.exports: any;
59 | }
60 |
61 | declare module 'babel-core/lib/helpers/resolve' {
62 | declare module.exports: any;
63 | }
64 |
65 | declare module 'babel-core/lib/store' {
66 | declare module.exports: any;
67 | }
68 |
69 | declare module 'babel-core/lib/tools/build-external-helpers' {
70 | declare module.exports: any;
71 | }
72 |
73 | declare module 'babel-core/lib/transformation/file/index' {
74 | declare module.exports: any;
75 | }
76 |
77 | declare module 'babel-core/lib/transformation/file/logger' {
78 | declare module.exports: any;
79 | }
80 |
81 | declare module 'babel-core/lib/transformation/file/metadata' {
82 | declare module.exports: any;
83 | }
84 |
85 | declare module 'babel-core/lib/transformation/file/options/build-config-chain' {
86 | declare module.exports: any;
87 | }
88 |
89 | declare module 'babel-core/lib/transformation/file/options/config' {
90 | declare module.exports: any;
91 | }
92 |
93 | declare module 'babel-core/lib/transformation/file/options/index' {
94 | declare module.exports: any;
95 | }
96 |
97 | declare module 'babel-core/lib/transformation/file/options/option-manager' {
98 | declare module.exports: any;
99 | }
100 |
101 | declare module 'babel-core/lib/transformation/file/options/parsers' {
102 | declare module.exports: any;
103 | }
104 |
105 | declare module 'babel-core/lib/transformation/file/options/removed' {
106 | declare module.exports: any;
107 | }
108 |
109 | declare module 'babel-core/lib/transformation/internal-plugins/block-hoist' {
110 | declare module.exports: any;
111 | }
112 |
113 | declare module 'babel-core/lib/transformation/internal-plugins/shadow-functions' {
114 | declare module.exports: any;
115 | }
116 |
117 | declare module 'babel-core/lib/transformation/pipeline' {
118 | declare module.exports: any;
119 | }
120 |
121 | declare module 'babel-core/lib/transformation/plugin-pass' {
122 | declare module.exports: any;
123 | }
124 |
125 | declare module 'babel-core/lib/transformation/plugin' {
126 | declare module.exports: any;
127 | }
128 |
129 | declare module 'babel-core/lib/util' {
130 | declare module.exports: any;
131 | }
132 |
133 | declare module 'babel-core/register' {
134 | declare module.exports: any;
135 | }
136 |
137 | // Filename aliases
138 | declare module 'babel-core/index' {
139 | declare module.exports: $Exports<'babel-core'>;
140 | }
141 | declare module 'babel-core/index.js' {
142 | declare module.exports: $Exports<'babel-core'>;
143 | }
144 | declare module 'babel-core/lib/api/browser.js' {
145 | declare module.exports: $Exports<'babel-core/lib/api/browser'>;
146 | }
147 | declare module 'babel-core/lib/api/node.js' {
148 | declare module.exports: $Exports<'babel-core/lib/api/node'>;
149 | }
150 | declare module 'babel-core/lib/helpers/get-possible-plugin-names.js' {
151 | declare module.exports: $Exports<'babel-core/lib/helpers/get-possible-plugin-names'>;
152 | }
153 | declare module 'babel-core/lib/helpers/get-possible-preset-names.js' {
154 | declare module.exports: $Exports<'babel-core/lib/helpers/get-possible-preset-names'>;
155 | }
156 | declare module 'babel-core/lib/helpers/merge.js' {
157 | declare module.exports: $Exports<'babel-core/lib/helpers/merge'>;
158 | }
159 | declare module 'babel-core/lib/helpers/normalize-ast.js' {
160 | declare module.exports: $Exports<'babel-core/lib/helpers/normalize-ast'>;
161 | }
162 | declare module 'babel-core/lib/helpers/resolve-from-possible-names.js' {
163 | declare module.exports: $Exports<'babel-core/lib/helpers/resolve-from-possible-names'>;
164 | }
165 | declare module 'babel-core/lib/helpers/resolve-plugin.js' {
166 | declare module.exports: $Exports<'babel-core/lib/helpers/resolve-plugin'>;
167 | }
168 | declare module 'babel-core/lib/helpers/resolve-preset.js' {
169 | declare module.exports: $Exports<'babel-core/lib/helpers/resolve-preset'>;
170 | }
171 | declare module 'babel-core/lib/helpers/resolve.js' {
172 | declare module.exports: $Exports<'babel-core/lib/helpers/resolve'>;
173 | }
174 | declare module 'babel-core/lib/store.js' {
175 | declare module.exports: $Exports<'babel-core/lib/store'>;
176 | }
177 | declare module 'babel-core/lib/tools/build-external-helpers.js' {
178 | declare module.exports: $Exports<'babel-core/lib/tools/build-external-helpers'>;
179 | }
180 | declare module 'babel-core/lib/transformation/file/index.js' {
181 | declare module.exports: $Exports<'babel-core/lib/transformation/file/index'>;
182 | }
183 | declare module 'babel-core/lib/transformation/file/logger.js' {
184 | declare module.exports: $Exports<'babel-core/lib/transformation/file/logger'>;
185 | }
186 | declare module 'babel-core/lib/transformation/file/metadata.js' {
187 | declare module.exports: $Exports<'babel-core/lib/transformation/file/metadata'>;
188 | }
189 | declare module 'babel-core/lib/transformation/file/options/build-config-chain.js' {
190 | declare module.exports: $Exports<'babel-core/lib/transformation/file/options/build-config-chain'>;
191 | }
192 | declare module 'babel-core/lib/transformation/file/options/config.js' {
193 | declare module.exports: $Exports<'babel-core/lib/transformation/file/options/config'>;
194 | }
195 | declare module 'babel-core/lib/transformation/file/options/index.js' {
196 | declare module.exports: $Exports<'babel-core/lib/transformation/file/options/index'>;
197 | }
198 | declare module 'babel-core/lib/transformation/file/options/option-manager.js' {
199 | declare module.exports: $Exports<'babel-core/lib/transformation/file/options/option-manager'>;
200 | }
201 | declare module 'babel-core/lib/transformation/file/options/parsers.js' {
202 | declare module.exports: $Exports<'babel-core/lib/transformation/file/options/parsers'>;
203 | }
204 | declare module 'babel-core/lib/transformation/file/options/removed.js' {
205 | declare module.exports: $Exports<'babel-core/lib/transformation/file/options/removed'>;
206 | }
207 | declare module 'babel-core/lib/transformation/internal-plugins/block-hoist.js' {
208 | declare module.exports: $Exports<'babel-core/lib/transformation/internal-plugins/block-hoist'>;
209 | }
210 | declare module 'babel-core/lib/transformation/internal-plugins/shadow-functions.js' {
211 | declare module.exports: $Exports<'babel-core/lib/transformation/internal-plugins/shadow-functions'>;
212 | }
213 | declare module 'babel-core/lib/transformation/pipeline.js' {
214 | declare module.exports: $Exports<'babel-core/lib/transformation/pipeline'>;
215 | }
216 | declare module 'babel-core/lib/transformation/plugin-pass.js' {
217 | declare module.exports: $Exports<'babel-core/lib/transformation/plugin-pass'>;
218 | }
219 | declare module 'babel-core/lib/transformation/plugin.js' {
220 | declare module.exports: $Exports<'babel-core/lib/transformation/plugin'>;
221 | }
222 | declare module 'babel-core/lib/util.js' {
223 | declare module.exports: $Exports<'babel-core/lib/util'>;
224 | }
225 | declare module 'babel-core/register.js' {
226 | declare module.exports: $Exports<'babel-core/register'>;
227 | }
228 |
--------------------------------------------------------------------------------
/flow-typed/npm/babel-eslint_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: 78bf0c72d7a781ce282de76ea9658d5a
2 | // flow-typed version: <>/babel-eslint_v^7.1.1/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'babel-eslint'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'babel-eslint' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'babel-eslint/babylon-to-espree/attachComments' {
26 | declare module.exports: any;
27 | }
28 |
29 | declare module 'babel-eslint/babylon-to-espree/convertTemplateType' {
30 | declare module.exports: any;
31 | }
32 |
33 | declare module 'babel-eslint/babylon-to-espree/index' {
34 | declare module.exports: any;
35 | }
36 |
37 | declare module 'babel-eslint/babylon-to-espree/toAST' {
38 | declare module.exports: any;
39 | }
40 |
41 | declare module 'babel-eslint/babylon-to-espree/toToken' {
42 | declare module.exports: any;
43 | }
44 |
45 | declare module 'babel-eslint/babylon-to-espree/toTokens' {
46 | declare module.exports: any;
47 | }
48 |
49 | // Filename aliases
50 | declare module 'babel-eslint/babylon-to-espree/attachComments.js' {
51 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/attachComments'>;
52 | }
53 | declare module 'babel-eslint/babylon-to-espree/convertTemplateType.js' {
54 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/convertTemplateType'>;
55 | }
56 | declare module 'babel-eslint/babylon-to-espree/index.js' {
57 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/index'>;
58 | }
59 | declare module 'babel-eslint/babylon-to-espree/toAST.js' {
60 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/toAST'>;
61 | }
62 | declare module 'babel-eslint/babylon-to-espree/toToken.js' {
63 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/toToken'>;
64 | }
65 | declare module 'babel-eslint/babylon-to-espree/toTokens.js' {
66 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/toTokens'>;
67 | }
68 | declare module 'babel-eslint/index' {
69 | declare module.exports: $Exports<'babel-eslint'>;
70 | }
71 | declare module 'babel-eslint/index.js' {
72 | declare module.exports: $Exports<'babel-eslint'>;
73 | }
74 |
--------------------------------------------------------------------------------
/flow-typed/npm/babel-loader_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: 958f321748bba5e53bcf8aa662b4a827
2 | // flow-typed version: <>/babel-loader_v^6.2.8/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'babel-loader'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'babel-loader' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'babel-loader/lib/fs-cache' {
26 | declare module.exports: any;
27 | }
28 |
29 | declare module 'babel-loader/lib/index' {
30 | declare module.exports: any;
31 | }
32 |
33 | declare module 'babel-loader/lib/resolve-rc' {
34 | declare module.exports: any;
35 | }
36 |
37 | declare module 'babel-loader/lib/utils/exists' {
38 | declare module.exports: any;
39 | }
40 |
41 | declare module 'babel-loader/lib/utils/read' {
42 | declare module.exports: any;
43 | }
44 |
45 | declare module 'babel-loader/lib/utils/relative' {
46 | declare module.exports: any;
47 | }
48 |
49 | // Filename aliases
50 | declare module 'babel-loader/lib/fs-cache.js' {
51 | declare module.exports: $Exports<'babel-loader/lib/fs-cache'>;
52 | }
53 | declare module 'babel-loader/lib/index.js' {
54 | declare module.exports: $Exports<'babel-loader/lib/index'>;
55 | }
56 | declare module 'babel-loader/lib/resolve-rc.js' {
57 | declare module.exports: $Exports<'babel-loader/lib/resolve-rc'>;
58 | }
59 | declare module 'babel-loader/lib/utils/exists.js' {
60 | declare module.exports: $Exports<'babel-loader/lib/utils/exists'>;
61 | }
62 | declare module 'babel-loader/lib/utils/read.js' {
63 | declare module.exports: $Exports<'babel-loader/lib/utils/read'>;
64 | }
65 | declare module 'babel-loader/lib/utils/relative.js' {
66 | declare module.exports: $Exports<'babel-loader/lib/utils/relative'>;
67 | }
68 |
--------------------------------------------------------------------------------
/flow-typed/npm/babel-plugin-flow-react-proptypes_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: 55569fcfc9cea7240793ba21edcd1750
2 | // flow-typed version: <>/babel-plugin-flow-react-proptypes_v^0.18.1/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'babel-plugin-flow-react-proptypes'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'babel-plugin-flow-react-proptypes' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'babel-plugin-flow-react-proptypes/lib/convertToPropTypes' {
26 | declare module.exports: any;
27 | }
28 |
29 | declare module 'babel-plugin-flow-react-proptypes/lib/index' {
30 | declare module.exports: any;
31 | }
32 |
33 | declare module 'babel-plugin-flow-react-proptypes/lib/makePropTypesAst' {
34 | declare module.exports: any;
35 | }
36 |
37 | declare module 'babel-plugin-flow-react-proptypes/lib/util' {
38 | declare module.exports: any;
39 | }
40 |
41 | // Filename aliases
42 | declare module 'babel-plugin-flow-react-proptypes/lib/convertToPropTypes.js' {
43 | declare module.exports: $Exports<'babel-plugin-flow-react-proptypes/lib/convertToPropTypes'>;
44 | }
45 | declare module 'babel-plugin-flow-react-proptypes/lib/index.js' {
46 | declare module.exports: $Exports<'babel-plugin-flow-react-proptypes/lib/index'>;
47 | }
48 | declare module 'babel-plugin-flow-react-proptypes/lib/makePropTypesAst.js' {
49 | declare module.exports: $Exports<'babel-plugin-flow-react-proptypes/lib/makePropTypesAst'>;
50 | }
51 | declare module 'babel-plugin-flow-react-proptypes/lib/util.js' {
52 | declare module.exports: $Exports<'babel-plugin-flow-react-proptypes/lib/util'>;
53 | }
54 |
--------------------------------------------------------------------------------
/flow-typed/npm/babel-plugin-transform-class-properties_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: e5044bdb64cc3189dd13e3a6a4e88e59
2 | // flow-typed version: <>/babel-plugin-transform-class-properties_v^6.19.0/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'babel-plugin-transform-class-properties'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'babel-plugin-transform-class-properties' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'babel-plugin-transform-class-properties/lib/index' {
26 | declare module.exports: any;
27 | }
28 |
29 | // Filename aliases
30 | declare module 'babel-plugin-transform-class-properties/lib/index.js' {
31 | declare module.exports: $Exports<'babel-plugin-transform-class-properties/lib/index'>;
32 | }
33 |
--------------------------------------------------------------------------------
/flow-typed/npm/babel-plugin-transform-flow-strip-types_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: ee65546d193f4ebf75093922d76833ec
2 | // flow-typed version: <>/babel-plugin-transform-flow-strip-types_v^6.18.0/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'babel-plugin-transform-flow-strip-types'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'babel-plugin-transform-flow-strip-types' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'babel-plugin-transform-flow-strip-types/lib/index' {
26 | declare module.exports: any;
27 | }
28 |
29 | // Filename aliases
30 | declare module 'babel-plugin-transform-flow-strip-types/lib/index.js' {
31 | declare module.exports: $Exports<'babel-plugin-transform-flow-strip-types/lib/index'>;
32 | }
33 |
--------------------------------------------------------------------------------
/flow-typed/npm/babel-plugin-transform-object-rest-spread_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: 466f592e1f789690c0a90a5c3cc07e69
2 | // flow-typed version: <>/babel-plugin-transform-object-rest-spread_v^6.19.0/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'babel-plugin-transform-object-rest-spread'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'babel-plugin-transform-object-rest-spread' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'babel-plugin-transform-object-rest-spread/lib/index' {
26 | declare module.exports: any;
27 | }
28 |
29 | // Filename aliases
30 | declare module 'babel-plugin-transform-object-rest-spread/lib/index.js' {
31 | declare module.exports: $Exports<'babel-plugin-transform-object-rest-spread/lib/index'>;
32 | }
33 |
--------------------------------------------------------------------------------
/flow-typed/npm/babel-preset-latest_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: 633229b4c101f73875920d7eb308ec36
2 | // flow-typed version: <>/babel-preset-latest_v^6.16.0/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'babel-preset-latest'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'babel-preset-latest' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'babel-preset-latest/lib/index' {
26 | declare module.exports: any;
27 | }
28 |
29 | // Filename aliases
30 | declare module 'babel-preset-latest/lib/index.js' {
31 | declare module.exports: $Exports<'babel-preset-latest/lib/index'>;
32 | }
33 |
--------------------------------------------------------------------------------
/flow-typed/npm/babel-preset-react_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: 084a38d54a422566a87df612e48873e2
2 | // flow-typed version: <>/babel-preset-react_v^6.16.0/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'babel-preset-react'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'babel-preset-react' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'babel-preset-react/lib/index' {
26 | declare module.exports: any;
27 | }
28 |
29 | // Filename aliases
30 | declare module 'babel-preset-react/lib/index.js' {
31 | declare module.exports: $Exports<'babel-preset-react/lib/index'>;
32 | }
33 |
--------------------------------------------------------------------------------
/flow-typed/npm/eslint-config-formidable_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: ae00b941adf06d4eddcf3a1ed80ca422
2 | // flow-typed version: <>/eslint-config-formidable_v^2.0.1/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'eslint-config-formidable'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'eslint-config-formidable' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'eslint-config-formidable/configurations/es5-browser' {
26 | declare module.exports: any;
27 | }
28 |
29 | declare module 'eslint-config-formidable/configurations/es5-node' {
30 | declare module.exports: any;
31 | }
32 |
33 | declare module 'eslint-config-formidable/configurations/es5-test' {
34 | declare module.exports: any;
35 | }
36 |
37 | declare module 'eslint-config-formidable/configurations/es5' {
38 | declare module.exports: any;
39 | }
40 |
41 | declare module 'eslint-config-formidable/configurations/es6-browser' {
42 | declare module.exports: any;
43 | }
44 |
45 | declare module 'eslint-config-formidable/configurations/es6-node-test' {
46 | declare module.exports: any;
47 | }
48 |
49 | declare module 'eslint-config-formidable/configurations/es6-node' {
50 | declare module.exports: any;
51 | }
52 |
53 | declare module 'eslint-config-formidable/configurations/es6-react-test' {
54 | declare module.exports: any;
55 | }
56 |
57 | declare module 'eslint-config-formidable/configurations/es6-react' {
58 | declare module.exports: any;
59 | }
60 |
61 | declare module 'eslint-config-formidable/configurations/es6-test' {
62 | declare module.exports: any;
63 | }
64 |
65 | declare module 'eslint-config-formidable/configurations/es6' {
66 | declare module.exports: any;
67 | }
68 |
69 | declare module 'eslint-config-formidable/configurations/off' {
70 | declare module.exports: any;
71 | }
72 |
73 | declare module 'eslint-config-formidable/rules/eslint/best-practices/off' {
74 | declare module.exports: any;
75 | }
76 |
77 | declare module 'eslint-config-formidable/rules/eslint/best-practices/on' {
78 | declare module.exports: any;
79 | }
80 |
81 | declare module 'eslint-config-formidable/rules/eslint/errors/off' {
82 | declare module.exports: any;
83 | }
84 |
85 | declare module 'eslint-config-formidable/rules/eslint/errors/on' {
86 | declare module.exports: any;
87 | }
88 |
89 | declare module 'eslint-config-formidable/rules/eslint/es6/off' {
90 | declare module.exports: any;
91 | }
92 |
93 | declare module 'eslint-config-formidable/rules/eslint/es6/on' {
94 | declare module.exports: any;
95 | }
96 |
97 | declare module 'eslint-config-formidable/rules/eslint/node/off' {
98 | declare module.exports: any;
99 | }
100 |
101 | declare module 'eslint-config-formidable/rules/eslint/node/on' {
102 | declare module.exports: any;
103 | }
104 |
105 | declare module 'eslint-config-formidable/rules/eslint/strict/off' {
106 | declare module.exports: any;
107 | }
108 |
109 | declare module 'eslint-config-formidable/rules/eslint/strict/on' {
110 | declare module.exports: any;
111 | }
112 |
113 | declare module 'eslint-config-formidable/rules/eslint/style/off' {
114 | declare module.exports: any;
115 | }
116 |
117 | declare module 'eslint-config-formidable/rules/eslint/style/on' {
118 | declare module.exports: any;
119 | }
120 |
121 | declare module 'eslint-config-formidable/rules/eslint/variables/off' {
122 | declare module.exports: any;
123 | }
124 |
125 | declare module 'eslint-config-formidable/rules/eslint/variables/on' {
126 | declare module.exports: any;
127 | }
128 |
129 | declare module 'eslint-config-formidable/rules/filenames/off' {
130 | declare module.exports: any;
131 | }
132 |
133 | declare module 'eslint-config-formidable/rules/filenames/on' {
134 | declare module.exports: any;
135 | }
136 |
137 | declare module 'eslint-config-formidable/rules/import/off' {
138 | declare module.exports: any;
139 | }
140 |
141 | declare module 'eslint-config-formidable/rules/import/on' {
142 | declare module.exports: any;
143 | }
144 |
145 | declare module 'eslint-config-formidable/rules/react/off' {
146 | declare module.exports: any;
147 | }
148 |
149 | declare module 'eslint-config-formidable/rules/react/on' {
150 | declare module.exports: any;
151 | }
152 |
153 | // Filename aliases
154 | declare module 'eslint-config-formidable/configurations/es5-browser.js' {
155 | declare module.exports: $Exports<'eslint-config-formidable/configurations/es5-browser'>;
156 | }
157 | declare module 'eslint-config-formidable/configurations/es5-node.js' {
158 | declare module.exports: $Exports<'eslint-config-formidable/configurations/es5-node'>;
159 | }
160 | declare module 'eslint-config-formidable/configurations/es5-test.js' {
161 | declare module.exports: $Exports<'eslint-config-formidable/configurations/es5-test'>;
162 | }
163 | declare module 'eslint-config-formidable/configurations/es5.js' {
164 | declare module.exports: $Exports<'eslint-config-formidable/configurations/es5'>;
165 | }
166 | declare module 'eslint-config-formidable/configurations/es6-browser.js' {
167 | declare module.exports: $Exports<'eslint-config-formidable/configurations/es6-browser'>;
168 | }
169 | declare module 'eslint-config-formidable/configurations/es6-node-test.js' {
170 | declare module.exports: $Exports<'eslint-config-formidable/configurations/es6-node-test'>;
171 | }
172 | declare module 'eslint-config-formidable/configurations/es6-node.js' {
173 | declare module.exports: $Exports<'eslint-config-formidable/configurations/es6-node'>;
174 | }
175 | declare module 'eslint-config-formidable/configurations/es6-react-test.js' {
176 | declare module.exports: $Exports<'eslint-config-formidable/configurations/es6-react-test'>;
177 | }
178 | declare module 'eslint-config-formidable/configurations/es6-react.js' {
179 | declare module.exports: $Exports<'eslint-config-formidable/configurations/es6-react'>;
180 | }
181 | declare module 'eslint-config-formidable/configurations/es6-test.js' {
182 | declare module.exports: $Exports<'eslint-config-formidable/configurations/es6-test'>;
183 | }
184 | declare module 'eslint-config-formidable/configurations/es6.js' {
185 | declare module.exports: $Exports<'eslint-config-formidable/configurations/es6'>;
186 | }
187 | declare module 'eslint-config-formidable/configurations/off.js' {
188 | declare module.exports: $Exports<'eslint-config-formidable/configurations/off'>;
189 | }
190 | declare module 'eslint-config-formidable/rules/eslint/best-practices/off.js' {
191 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/best-practices/off'>;
192 | }
193 | declare module 'eslint-config-formidable/rules/eslint/best-practices/on.js' {
194 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/best-practices/on'>;
195 | }
196 | declare module 'eslint-config-formidable/rules/eslint/errors/off.js' {
197 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/errors/off'>;
198 | }
199 | declare module 'eslint-config-formidable/rules/eslint/errors/on.js' {
200 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/errors/on'>;
201 | }
202 | declare module 'eslint-config-formidable/rules/eslint/es6/off.js' {
203 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/es6/off'>;
204 | }
205 | declare module 'eslint-config-formidable/rules/eslint/es6/on.js' {
206 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/es6/on'>;
207 | }
208 | declare module 'eslint-config-formidable/rules/eslint/node/off.js' {
209 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/node/off'>;
210 | }
211 | declare module 'eslint-config-formidable/rules/eslint/node/on.js' {
212 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/node/on'>;
213 | }
214 | declare module 'eslint-config-formidable/rules/eslint/strict/off.js' {
215 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/strict/off'>;
216 | }
217 | declare module 'eslint-config-formidable/rules/eslint/strict/on.js' {
218 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/strict/on'>;
219 | }
220 | declare module 'eslint-config-formidable/rules/eslint/style/off.js' {
221 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/style/off'>;
222 | }
223 | declare module 'eslint-config-formidable/rules/eslint/style/on.js' {
224 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/style/on'>;
225 | }
226 | declare module 'eslint-config-formidable/rules/eslint/variables/off.js' {
227 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/variables/off'>;
228 | }
229 | declare module 'eslint-config-formidable/rules/eslint/variables/on.js' {
230 | declare module.exports: $Exports<'eslint-config-formidable/rules/eslint/variables/on'>;
231 | }
232 | declare module 'eslint-config-formidable/rules/filenames/off.js' {
233 | declare module.exports: $Exports<'eslint-config-formidable/rules/filenames/off'>;
234 | }
235 | declare module 'eslint-config-formidable/rules/filenames/on.js' {
236 | declare module.exports: $Exports<'eslint-config-formidable/rules/filenames/on'>;
237 | }
238 | declare module 'eslint-config-formidable/rules/import/off.js' {
239 | declare module.exports: $Exports<'eslint-config-formidable/rules/import/off'>;
240 | }
241 | declare module 'eslint-config-formidable/rules/import/on.js' {
242 | declare module.exports: $Exports<'eslint-config-formidable/rules/import/on'>;
243 | }
244 | declare module 'eslint-config-formidable/rules/react/off.js' {
245 | declare module.exports: $Exports<'eslint-config-formidable/rules/react/off'>;
246 | }
247 | declare module 'eslint-config-formidable/rules/react/on.js' {
248 | declare module.exports: $Exports<'eslint-config-formidable/rules/react/on'>;
249 | }
250 |
--------------------------------------------------------------------------------
/flow-typed/npm/eslint-plugin-babel_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: cd853adfb9d273360a0eb4742f04c8e7
2 | // flow-typed version: <>/eslint-plugin-babel_v^4.1.1/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'eslint-plugin-babel'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'eslint-plugin-babel' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'eslint-plugin-babel/ast-utils' {
26 | declare module.exports: any;
27 | }
28 |
29 | declare module 'eslint-plugin-babel/rules/array-bracket-spacing' {
30 | declare module.exports: any;
31 | }
32 |
33 | declare module 'eslint-plugin-babel/rules/arrow-parens' {
34 | declare module.exports: any;
35 | }
36 |
37 | declare module 'eslint-plugin-babel/rules/flow-object-type' {
38 | declare module.exports: any;
39 | }
40 |
41 | declare module 'eslint-plugin-babel/rules/func-params-comma-dangle' {
42 | declare module.exports: any;
43 | }
44 |
45 | declare module 'eslint-plugin-babel/rules/generator-star-spacing' {
46 | declare module.exports: any;
47 | }
48 |
49 | declare module 'eslint-plugin-babel/rules/new-cap' {
50 | declare module.exports: any;
51 | }
52 |
53 | declare module 'eslint-plugin-babel/rules/no-await-in-loop' {
54 | declare module.exports: any;
55 | }
56 |
57 | declare module 'eslint-plugin-babel/rules/no-invalid-this' {
58 | declare module.exports: any;
59 | }
60 |
61 | declare module 'eslint-plugin-babel/rules/object-curly-spacing' {
62 | declare module.exports: any;
63 | }
64 |
65 | declare module 'eslint-plugin-babel/rules/object-shorthand' {
66 | declare module.exports: any;
67 | }
68 |
69 | declare module 'eslint-plugin-babel/rules/semi' {
70 | declare module.exports: any;
71 | }
72 |
73 | declare module 'eslint-plugin-babel/tests/rules/new-cap' {
74 | declare module.exports: any;
75 | }
76 |
77 | declare module 'eslint-plugin-babel/tests/rules/no-invalid-this' {
78 | declare module.exports: any;
79 | }
80 |
81 | declare module 'eslint-plugin-babel/tests/rules/object-curly-spacing' {
82 | declare module.exports: any;
83 | }
84 |
85 | declare module 'eslint-plugin-babel/tests/rules/semi' {
86 | declare module.exports: any;
87 | }
88 |
89 | declare module 'eslint-plugin-babel/tests/RuleTester' {
90 | declare module.exports: any;
91 | }
92 |
93 | // Filename aliases
94 | declare module 'eslint-plugin-babel/ast-utils.js' {
95 | declare module.exports: $Exports<'eslint-plugin-babel/ast-utils'>;
96 | }
97 | declare module 'eslint-plugin-babel/index' {
98 | declare module.exports: $Exports<'eslint-plugin-babel'>;
99 | }
100 | declare module 'eslint-plugin-babel/index.js' {
101 | declare module.exports: $Exports<'eslint-plugin-babel'>;
102 | }
103 | declare module 'eslint-plugin-babel/rules/array-bracket-spacing.js' {
104 | declare module.exports: $Exports<'eslint-plugin-babel/rules/array-bracket-spacing'>;
105 | }
106 | declare module 'eslint-plugin-babel/rules/arrow-parens.js' {
107 | declare module.exports: $Exports<'eslint-plugin-babel/rules/arrow-parens'>;
108 | }
109 | declare module 'eslint-plugin-babel/rules/flow-object-type.js' {
110 | declare module.exports: $Exports<'eslint-plugin-babel/rules/flow-object-type'>;
111 | }
112 | declare module 'eslint-plugin-babel/rules/func-params-comma-dangle.js' {
113 | declare module.exports: $Exports<'eslint-plugin-babel/rules/func-params-comma-dangle'>;
114 | }
115 | declare module 'eslint-plugin-babel/rules/generator-star-spacing.js' {
116 | declare module.exports: $Exports<'eslint-plugin-babel/rules/generator-star-spacing'>;
117 | }
118 | declare module 'eslint-plugin-babel/rules/new-cap.js' {
119 | declare module.exports: $Exports<'eslint-plugin-babel/rules/new-cap'>;
120 | }
121 | declare module 'eslint-plugin-babel/rules/no-await-in-loop.js' {
122 | declare module.exports: $Exports<'eslint-plugin-babel/rules/no-await-in-loop'>;
123 | }
124 | declare module 'eslint-plugin-babel/rules/no-invalid-this.js' {
125 | declare module.exports: $Exports<'eslint-plugin-babel/rules/no-invalid-this'>;
126 | }
127 | declare module 'eslint-plugin-babel/rules/object-curly-spacing.js' {
128 | declare module.exports: $Exports<'eslint-plugin-babel/rules/object-curly-spacing'>;
129 | }
130 | declare module 'eslint-plugin-babel/rules/object-shorthand.js' {
131 | declare module.exports: $Exports<'eslint-plugin-babel/rules/object-shorthand'>;
132 | }
133 | declare module 'eslint-plugin-babel/rules/semi.js' {
134 | declare module.exports: $Exports<'eslint-plugin-babel/rules/semi'>;
135 | }
136 | declare module 'eslint-plugin-babel/tests/rules/new-cap.js' {
137 | declare module.exports: $Exports<'eslint-plugin-babel/tests/rules/new-cap'>;
138 | }
139 | declare module 'eslint-plugin-babel/tests/rules/no-invalid-this.js' {
140 | declare module.exports: $Exports<'eslint-plugin-babel/tests/rules/no-invalid-this'>;
141 | }
142 | declare module 'eslint-plugin-babel/tests/rules/object-curly-spacing.js' {
143 | declare module.exports: $Exports<'eslint-plugin-babel/tests/rules/object-curly-spacing'>;
144 | }
145 | declare module 'eslint-plugin-babel/tests/rules/semi.js' {
146 | declare module.exports: $Exports<'eslint-plugin-babel/tests/rules/semi'>;
147 | }
148 | declare module 'eslint-plugin-babel/tests/RuleTester.js' {
149 | declare module.exports: $Exports<'eslint-plugin-babel/tests/RuleTester'>;
150 | }
151 |
--------------------------------------------------------------------------------
/flow-typed/npm/eslint-plugin-filenames_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: f54017c519a3c3b093e3b989e911c602
2 | // flow-typed version: <>/eslint-plugin-filenames_v^1.1.0/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'eslint-plugin-filenames'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'eslint-plugin-filenames' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'eslint-plugin-filenames/lib/common/getExportedName' {
26 | declare module.exports: any;
27 | }
28 |
29 | declare module 'eslint-plugin-filenames/lib/common/isIgnoredFilename' {
30 | declare module.exports: any;
31 | }
32 |
33 | declare module 'eslint-plugin-filenames/lib/common/isIndexFile' {
34 | declare module.exports: any;
35 | }
36 |
37 | declare module 'eslint-plugin-filenames/lib/common/parseFilename' {
38 | declare module.exports: any;
39 | }
40 |
41 | declare module 'eslint-plugin-filenames/lib/rules/match-exported' {
42 | declare module.exports: any;
43 | }
44 |
45 | declare module 'eslint-plugin-filenames/lib/rules/match-regex' {
46 | declare module.exports: any;
47 | }
48 |
49 | declare module 'eslint-plugin-filenames/lib/rules/no-index' {
50 | declare module.exports: any;
51 | }
52 |
53 | // Filename aliases
54 | declare module 'eslint-plugin-filenames/index' {
55 | declare module.exports: $Exports<'eslint-plugin-filenames'>;
56 | }
57 | declare module 'eslint-plugin-filenames/index.js' {
58 | declare module.exports: $Exports<'eslint-plugin-filenames'>;
59 | }
60 | declare module 'eslint-plugin-filenames/lib/common/getExportedName.js' {
61 | declare module.exports: $Exports<'eslint-plugin-filenames/lib/common/getExportedName'>;
62 | }
63 | declare module 'eslint-plugin-filenames/lib/common/isIgnoredFilename.js' {
64 | declare module.exports: $Exports<'eslint-plugin-filenames/lib/common/isIgnoredFilename'>;
65 | }
66 | declare module 'eslint-plugin-filenames/lib/common/isIndexFile.js' {
67 | declare module.exports: $Exports<'eslint-plugin-filenames/lib/common/isIndexFile'>;
68 | }
69 | declare module 'eslint-plugin-filenames/lib/common/parseFilename.js' {
70 | declare module.exports: $Exports<'eslint-plugin-filenames/lib/common/parseFilename'>;
71 | }
72 | declare module 'eslint-plugin-filenames/lib/rules/match-exported.js' {
73 | declare module.exports: $Exports<'eslint-plugin-filenames/lib/rules/match-exported'>;
74 | }
75 | declare module 'eslint-plugin-filenames/lib/rules/match-regex.js' {
76 | declare module.exports: $Exports<'eslint-plugin-filenames/lib/rules/match-regex'>;
77 | }
78 | declare module 'eslint-plugin-filenames/lib/rules/no-index.js' {
79 | declare module.exports: $Exports<'eslint-plugin-filenames/lib/rules/no-index'>;
80 | }
81 |
--------------------------------------------------------------------------------
/flow-typed/npm/eslint-plugin-import_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: 6aa72b267b236a84ef1428e7844f0925
2 | // flow-typed version: <>/eslint-plugin-import_v^2.2.0/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'eslint-plugin-import'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'eslint-plugin-import' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'eslint-plugin-import/config/electron' {
26 | declare module.exports: any;
27 | }
28 |
29 | declare module 'eslint-plugin-import/config/errors' {
30 | declare module.exports: any;
31 | }
32 |
33 | declare module 'eslint-plugin-import/config/react-native' {
34 | declare module.exports: any;
35 | }
36 |
37 | declare module 'eslint-plugin-import/config/react' {
38 | declare module.exports: any;
39 | }
40 |
41 | declare module 'eslint-plugin-import/config/recommended' {
42 | declare module.exports: any;
43 | }
44 |
45 | declare module 'eslint-plugin-import/config/stage-0' {
46 | declare module.exports: any;
47 | }
48 |
49 | declare module 'eslint-plugin-import/config/warnings' {
50 | declare module.exports: any;
51 | }
52 |
53 | declare module 'eslint-plugin-import/lib/core/importType' {
54 | declare module.exports: any;
55 | }
56 |
57 | declare module 'eslint-plugin-import/lib/core/staticRequire' {
58 | declare module.exports: any;
59 | }
60 |
61 | declare module 'eslint-plugin-import/lib/ExportMap' {
62 | declare module.exports: any;
63 | }
64 |
65 | declare module 'eslint-plugin-import/lib/importDeclaration' {
66 | declare module.exports: any;
67 | }
68 |
69 | declare module 'eslint-plugin-import/lib/index' {
70 | declare module.exports: any;
71 | }
72 |
73 | declare module 'eslint-plugin-import/lib/rules/default' {
74 | declare module.exports: any;
75 | }
76 |
77 | declare module 'eslint-plugin-import/lib/rules/export' {
78 | declare module.exports: any;
79 | }
80 |
81 | declare module 'eslint-plugin-import/lib/rules/extensions' {
82 | declare module.exports: any;
83 | }
84 |
85 | declare module 'eslint-plugin-import/lib/rules/first' {
86 | declare module.exports: any;
87 | }
88 |
89 | declare module 'eslint-plugin-import/lib/rules/imports-first' {
90 | declare module.exports: any;
91 | }
92 |
93 | declare module 'eslint-plugin-import/lib/rules/max-dependencies' {
94 | declare module.exports: any;
95 | }
96 |
97 | declare module 'eslint-plugin-import/lib/rules/named' {
98 | declare module.exports: any;
99 | }
100 |
101 | declare module 'eslint-plugin-import/lib/rules/namespace' {
102 | declare module.exports: any;
103 | }
104 |
105 | declare module 'eslint-plugin-import/lib/rules/newline-after-import' {
106 | declare module.exports: any;
107 | }
108 |
109 | declare module 'eslint-plugin-import/lib/rules/no-absolute-path' {
110 | declare module.exports: any;
111 | }
112 |
113 | declare module 'eslint-plugin-import/lib/rules/no-amd' {
114 | declare module.exports: any;
115 | }
116 |
117 | declare module 'eslint-plugin-import/lib/rules/no-commonjs' {
118 | declare module.exports: any;
119 | }
120 |
121 | declare module 'eslint-plugin-import/lib/rules/no-deprecated' {
122 | declare module.exports: any;
123 | }
124 |
125 | declare module 'eslint-plugin-import/lib/rules/no-duplicates' {
126 | declare module.exports: any;
127 | }
128 |
129 | declare module 'eslint-plugin-import/lib/rules/no-dynamic-require' {
130 | declare module.exports: any;
131 | }
132 |
133 | declare module 'eslint-plugin-import/lib/rules/no-extraneous-dependencies' {
134 | declare module.exports: any;
135 | }
136 |
137 | declare module 'eslint-plugin-import/lib/rules/no-internal-modules' {
138 | declare module.exports: any;
139 | }
140 |
141 | declare module 'eslint-plugin-import/lib/rules/no-mutable-exports' {
142 | declare module.exports: any;
143 | }
144 |
145 | declare module 'eslint-plugin-import/lib/rules/no-named-as-default-member' {
146 | declare module.exports: any;
147 | }
148 |
149 | declare module 'eslint-plugin-import/lib/rules/no-named-as-default' {
150 | declare module.exports: any;
151 | }
152 |
153 | declare module 'eslint-plugin-import/lib/rules/no-named-default' {
154 | declare module.exports: any;
155 | }
156 |
157 | declare module 'eslint-plugin-import/lib/rules/no-namespace' {
158 | declare module.exports: any;
159 | }
160 |
161 | declare module 'eslint-plugin-import/lib/rules/no-nodejs-modules' {
162 | declare module.exports: any;
163 | }
164 |
165 | declare module 'eslint-plugin-import/lib/rules/no-restricted-paths' {
166 | declare module.exports: any;
167 | }
168 |
169 | declare module 'eslint-plugin-import/lib/rules/no-unassigned-import' {
170 | declare module.exports: any;
171 | }
172 |
173 | declare module 'eslint-plugin-import/lib/rules/no-unresolved' {
174 | declare module.exports: any;
175 | }
176 |
177 | declare module 'eslint-plugin-import/lib/rules/no-webpack-loader-syntax' {
178 | declare module.exports: any;
179 | }
180 |
181 | declare module 'eslint-plugin-import/lib/rules/order' {
182 | declare module.exports: any;
183 | }
184 |
185 | declare module 'eslint-plugin-import/lib/rules/prefer-default-export' {
186 | declare module.exports: any;
187 | }
188 |
189 | declare module 'eslint-plugin-import/lib/rules/unambiguous' {
190 | declare module.exports: any;
191 | }
192 |
193 | declare module 'eslint-plugin-import/memo-parser/index' {
194 | declare module.exports: any;
195 | }
196 |
197 | // Filename aliases
198 | declare module 'eslint-plugin-import/config/electron.js' {
199 | declare module.exports: $Exports<'eslint-plugin-import/config/electron'>;
200 | }
201 | declare module 'eslint-plugin-import/config/errors.js' {
202 | declare module.exports: $Exports<'eslint-plugin-import/config/errors'>;
203 | }
204 | declare module 'eslint-plugin-import/config/react-native.js' {
205 | declare module.exports: $Exports<'eslint-plugin-import/config/react-native'>;
206 | }
207 | declare module 'eslint-plugin-import/config/react.js' {
208 | declare module.exports: $Exports<'eslint-plugin-import/config/react'>;
209 | }
210 | declare module 'eslint-plugin-import/config/recommended.js' {
211 | declare module.exports: $Exports<'eslint-plugin-import/config/recommended'>;
212 | }
213 | declare module 'eslint-plugin-import/config/stage-0.js' {
214 | declare module.exports: $Exports<'eslint-plugin-import/config/stage-0'>;
215 | }
216 | declare module 'eslint-plugin-import/config/warnings.js' {
217 | declare module.exports: $Exports<'eslint-plugin-import/config/warnings'>;
218 | }
219 | declare module 'eslint-plugin-import/lib/core/importType.js' {
220 | declare module.exports: $Exports<'eslint-plugin-import/lib/core/importType'>;
221 | }
222 | declare module 'eslint-plugin-import/lib/core/staticRequire.js' {
223 | declare module.exports: $Exports<'eslint-plugin-import/lib/core/staticRequire'>;
224 | }
225 | declare module 'eslint-plugin-import/lib/ExportMap.js' {
226 | declare module.exports: $Exports<'eslint-plugin-import/lib/ExportMap'>;
227 | }
228 | declare module 'eslint-plugin-import/lib/importDeclaration.js' {
229 | declare module.exports: $Exports<'eslint-plugin-import/lib/importDeclaration'>;
230 | }
231 | declare module 'eslint-plugin-import/lib/index.js' {
232 | declare module.exports: $Exports<'eslint-plugin-import/lib/index'>;
233 | }
234 | declare module 'eslint-plugin-import/lib/rules/default.js' {
235 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/default'>;
236 | }
237 | declare module 'eslint-plugin-import/lib/rules/export.js' {
238 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/export'>;
239 | }
240 | declare module 'eslint-plugin-import/lib/rules/extensions.js' {
241 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/extensions'>;
242 | }
243 | declare module 'eslint-plugin-import/lib/rules/first.js' {
244 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/first'>;
245 | }
246 | declare module 'eslint-plugin-import/lib/rules/imports-first.js' {
247 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/imports-first'>;
248 | }
249 | declare module 'eslint-plugin-import/lib/rules/max-dependencies.js' {
250 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/max-dependencies'>;
251 | }
252 | declare module 'eslint-plugin-import/lib/rules/named.js' {
253 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/named'>;
254 | }
255 | declare module 'eslint-plugin-import/lib/rules/namespace.js' {
256 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/namespace'>;
257 | }
258 | declare module 'eslint-plugin-import/lib/rules/newline-after-import.js' {
259 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/newline-after-import'>;
260 | }
261 | declare module 'eslint-plugin-import/lib/rules/no-absolute-path.js' {
262 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-absolute-path'>;
263 | }
264 | declare module 'eslint-plugin-import/lib/rules/no-amd.js' {
265 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-amd'>;
266 | }
267 | declare module 'eslint-plugin-import/lib/rules/no-commonjs.js' {
268 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-commonjs'>;
269 | }
270 | declare module 'eslint-plugin-import/lib/rules/no-deprecated.js' {
271 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-deprecated'>;
272 | }
273 | declare module 'eslint-plugin-import/lib/rules/no-duplicates.js' {
274 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-duplicates'>;
275 | }
276 | declare module 'eslint-plugin-import/lib/rules/no-dynamic-require.js' {
277 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-dynamic-require'>;
278 | }
279 | declare module 'eslint-plugin-import/lib/rules/no-extraneous-dependencies.js' {
280 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-extraneous-dependencies'>;
281 | }
282 | declare module 'eslint-plugin-import/lib/rules/no-internal-modules.js' {
283 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-internal-modules'>;
284 | }
285 | declare module 'eslint-plugin-import/lib/rules/no-mutable-exports.js' {
286 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-mutable-exports'>;
287 | }
288 | declare module 'eslint-plugin-import/lib/rules/no-named-as-default-member.js' {
289 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-named-as-default-member'>;
290 | }
291 | declare module 'eslint-plugin-import/lib/rules/no-named-as-default.js' {
292 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-named-as-default'>;
293 | }
294 | declare module 'eslint-plugin-import/lib/rules/no-named-default.js' {
295 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-named-default'>;
296 | }
297 | declare module 'eslint-plugin-import/lib/rules/no-namespace.js' {
298 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-namespace'>;
299 | }
300 | declare module 'eslint-plugin-import/lib/rules/no-nodejs-modules.js' {
301 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-nodejs-modules'>;
302 | }
303 | declare module 'eslint-plugin-import/lib/rules/no-restricted-paths.js' {
304 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-restricted-paths'>;
305 | }
306 | declare module 'eslint-plugin-import/lib/rules/no-unassigned-import.js' {
307 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-unassigned-import'>;
308 | }
309 | declare module 'eslint-plugin-import/lib/rules/no-unresolved.js' {
310 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-unresolved'>;
311 | }
312 | declare module 'eslint-plugin-import/lib/rules/no-webpack-loader-syntax.js' {
313 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/no-webpack-loader-syntax'>;
314 | }
315 | declare module 'eslint-plugin-import/lib/rules/order.js' {
316 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/order'>;
317 | }
318 | declare module 'eslint-plugin-import/lib/rules/prefer-default-export.js' {
319 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/prefer-default-export'>;
320 | }
321 | declare module 'eslint-plugin-import/lib/rules/unambiguous.js' {
322 | declare module.exports: $Exports<'eslint-plugin-import/lib/rules/unambiguous'>;
323 | }
324 | declare module 'eslint-plugin-import/memo-parser/index.js' {
325 | declare module.exports: $Exports<'eslint-plugin-import/memo-parser/index'>;
326 | }
327 |
--------------------------------------------------------------------------------
/flow-typed/npm/flow-bin_v0.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: 6a5610678d4b01e13bbfbbc62bdaf583
2 | // flow-typed version: 3817bc6980/flow-bin_v0.x.x/flow_>=v0.25.x
3 |
4 | declare module "flow-bin" {
5 | declare module.exports: string;
6 | }
7 |
--------------------------------------------------------------------------------
/flow-typed/npm/redux-logger_vx.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: 62bf4b1b7b6d07346f0aa2b8c5e0d94a
2 | // flow-typed version: <>/redux-logger_v^2.8.2/flow_v0.42.0
3 |
4 | /**
5 | * This is an autogenerated libdef stub for:
6 | *
7 | * 'redux-logger'
8 | *
9 | * Fill this stub out by replacing all the `any` types.
10 | *
11 | * Once filled out, we encourage you to share your work with the
12 | * community by sending a pull request to:
13 | * https://github.com/flowtype/flow-typed
14 | */
15 |
16 | declare module 'redux-logger' {
17 | declare module.exports: any;
18 | }
19 |
20 | /**
21 | * We include stubs for each file inside this npm package in case you need to
22 | * require those files directly. Feel free to delete any files that aren't
23 | * needed.
24 | */
25 | declare module 'redux-logger/dist/index' {
26 | declare module.exports: any;
27 | }
28 |
29 | declare module 'redux-logger/dist/index.min' {
30 | declare module.exports: any;
31 | }
32 |
33 | declare module 'redux-logger/lib/core' {
34 | declare module.exports: any;
35 | }
36 |
37 | declare module 'redux-logger/lib/defaults' {
38 | declare module.exports: any;
39 | }
40 |
41 | declare module 'redux-logger/lib/diff' {
42 | declare module.exports: any;
43 | }
44 |
45 | declare module 'redux-logger/lib/helpers' {
46 | declare module.exports: any;
47 | }
48 |
49 | declare module 'redux-logger/lib/index' {
50 | declare module.exports: any;
51 | }
52 |
53 | declare module 'redux-logger/src/core' {
54 | declare module.exports: any;
55 | }
56 |
57 | declare module 'redux-logger/src/defaults' {
58 | declare module.exports: any;
59 | }
60 |
61 | declare module 'redux-logger/src/diff' {
62 | declare module.exports: any;
63 | }
64 |
65 | declare module 'redux-logger/src/helpers' {
66 | declare module.exports: any;
67 | }
68 |
69 | declare module 'redux-logger/src/index' {
70 | declare module.exports: any;
71 | }
72 |
73 | // Filename aliases
74 | declare module 'redux-logger/dist/index.js' {
75 | declare module.exports: $Exports<'redux-logger/dist/index'>;
76 | }
77 | declare module 'redux-logger/dist/index.min.js' {
78 | declare module.exports: $Exports<'redux-logger/dist/index.min'>;
79 | }
80 | declare module 'redux-logger/lib/core.js' {
81 | declare module.exports: $Exports<'redux-logger/lib/core'>;
82 | }
83 | declare module 'redux-logger/lib/defaults.js' {
84 | declare module.exports: $Exports<'redux-logger/lib/defaults'>;
85 | }
86 | declare module 'redux-logger/lib/diff.js' {
87 | declare module.exports: $Exports<'redux-logger/lib/diff'>;
88 | }
89 | declare module 'redux-logger/lib/helpers.js' {
90 | declare module.exports: $Exports<'redux-logger/lib/helpers'>;
91 | }
92 | declare module 'redux-logger/lib/index.js' {
93 | declare module.exports: $Exports<'redux-logger/lib/index'>;
94 | }
95 | declare module 'redux-logger/src/core.js' {
96 | declare module.exports: $Exports<'redux-logger/src/core'>;
97 | }
98 | declare module 'redux-logger/src/defaults.js' {
99 | declare module.exports: $Exports<'redux-logger/src/defaults'>;
100 | }
101 | declare module 'redux-logger/src/diff.js' {
102 | declare module.exports: $Exports<'redux-logger/src/diff'>;
103 | }
104 | declare module 'redux-logger/src/helpers.js' {
105 | declare module.exports: $Exports<'redux-logger/src/helpers'>;
106 | }
107 | declare module 'redux-logger/src/index.js' {
108 | declare module.exports: $Exports<'redux-logger/src/index'>;
109 | }
110 |
--------------------------------------------------------------------------------
/flow-typed/npm/redux_v3.x.x.js:
--------------------------------------------------------------------------------
1 | // flow-typed signature: ba132c96664f1a05288f3eb2272a3c35
2 | // flow-typed version: c4bbd91cfc/redux_v3.x.x/flow_>=v0.33.x
3 |
4 | declare module 'redux' {
5 |
6 | /*
7 |
8 | S = State
9 | A = Action
10 |
11 | */
12 |
13 | declare type Dispatch }> = (action: A) => A;
14 |
15 | declare type MiddlewareAPI = {
16 | dispatch: Dispatch;
17 | getState(): S;
18 | };
19 |
20 | declare type Store = {
21 | // rewrite MiddlewareAPI members in order to get nicer error messages (intersections produce long messages)
22 | dispatch: Dispatch;
23 | getState(): S;
24 | subscribe(listener: () => void): () => void;
25 | replaceReducer(nextReducer: Reducer): void
26 | };
27 |
28 | declare type Reducer = (state: S, action: A) => S;
29 |
30 | declare type Middleware =
31 | (api: MiddlewareAPI) =>
32 | (next: Dispatch) => Dispatch ;
33 |
34 | declare type StoreCreator = {
35 | (reducer: Reducer, enhancer?: StoreEnhancer): Store;
36 | (reducer: Reducer, preloadedState: S, enhancer?: StoreEnhancer): Store;
37 | };
38 |
39 | declare type StoreEnhancer = (next: StoreCreator) => StoreCreator;
40 |
41 | declare function createStore(reducer: Reducer, enhancer?: StoreEnhancer): Store;
42 | declare function createStore(reducer: Reducer, preloadedState: S, enhancer?: StoreEnhancer): Store;
43 |
44 | declare function applyMiddleware(...middlewares: Array>): StoreEnhancer;
45 |
46 | declare type ActionCreator = (...args: Array) => A;
47 | declare type ActionCreators = { [key: K]: ActionCreator };
48 |
49 | declare function bindActionCreators >(actionCreator: C, dispatch: Dispatch ): C;
50 | declare function bindActionCreators >(actionCreators: C, dispatch: Dispatch ): C;
51 |
52 | declare function combineReducers(reducers: O): Reducer<$ObjMap(r: Reducer) => S>, A>;
53 |
54 | declare function compose(...fns: Array>): Function;
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@redux-offline/redux-offline",
3 | "version": "2.2.0",
4 | "description": "Redux Offline-First Architecture",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "build": "babel src --out-dir lib --ignore '**/__tests__/**'",
8 | "flow:start": "flow server",
9 | "flow:stop": "flow stop",
10 | "flow": "flow; test $? -eq 0 -o $? -eq 2",
11 | "lint": "eslint src/",
12 | "prepublish": "npm run lint && npm run flow && npm run test && npm run build",
13 | "prettier": "eslint src --fix",
14 | "test": "jest",
15 | "test:watch": "jest --watch",
16 | "watch": "npm run build -- --watch"
17 | },
18 | "jest": {
19 | "rootDir": "src"
20 | },
21 | "repository": {
22 | "type": "git",
23 | "url": "git+https://github.com/redux-offline/redux-offline"
24 | },
25 | "author": "",
26 | "license": "MIT",
27 | "bugs": {
28 | "url": "https://github.com/redux-offline/redux-offline/issues"
29 | },
30 | "homepage": "https://github.com/redux-offline/redux-offline#readme",
31 | "devDependencies": {
32 | "babel-cli": "^6.26.0",
33 | "babel-core": "^6.26.0",
34 | "babel-eslint": "^7.2.3",
35 | "babel-plugin-transform-class-properties": "^6.24.1",
36 | "babel-plugin-transform-flow-strip-types": "^6.18.0",
37 | "babel-preset-latest": "^6.24.1",
38 | "babel-preset-stage-3": "^6.24.1",
39 | "eslint": "^4.6.1",
40 | "eslint-config-airbnb-base": "^12.0.0",
41 | "eslint-config-prettier": "^2.4.0",
42 | "eslint-plugin-babel": "^4.1.1",
43 | "eslint-plugin-import": "^2.7.0",
44 | "eslint-plugin-prettier": "^2.2.0",
45 | "flow-bin": "^0.42.0",
46 | "jest": "^19.0.2",
47 | "prettier": "^1.6.1",
48 | "react": "^15.4.2",
49 | "redux": "^3.6.0",
50 | "redux-devtools-instrument": "^1.8.2",
51 | "redux-logger": "^2.8.2",
52 | "redux-persist-node-storage": "^1.0.2"
53 | },
54 | "dependencies": {
55 | "redux-persist": "^4.5.0"
56 | },
57 | "peerDependencies": {
58 | "redux": ">=3"
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/__tests__/defaults/effect.js:
--------------------------------------------------------------------------------
1 | import effectReconciler from '../../defaults/effect';
2 |
3 | function fetch(body) {
4 | return Promise.resolve({
5 | ok: true,
6 | headers: { get: jest.fn(() => 'application/json') },
7 | text: jest.fn(() => Promise.resolve(body))
8 | });
9 | }
10 |
11 | let globalFetch;
12 |
13 | beforeAll(() => {
14 | globalFetch = global.fetch;
15 | });
16 | afterAll(() => {
17 | global.fetch = globalFetch;
18 | });
19 |
20 | test('effector accept JSON stringified object', () => {
21 | const body = {
22 | email: 'email@example.com',
23 | password: 'p4ssw0rd'
24 | };
25 |
26 | global.fetch = jest.fn((url, options) => {
27 | expect(options.headers['content-type']).toEqual('application/json');
28 | expect(JSON.parse(options.body)).toEqual(body);
29 |
30 | return fetch('');
31 | });
32 |
33 | return effectReconciler({ body: JSON.stringify(body) }).then(body2 => {
34 | expect(body2).toEqual(null);
35 | });
36 | });
37 |
38 | test('effector receive JSON and response objects', () => {
39 | const body = { id: 1234 };
40 |
41 | global.fetch = jest.fn(() => fetch(JSON.stringify(body)));
42 |
43 | return effectReconciler({}).then(body2 => {
44 | expect(body2).toEqual(body);
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/src/__tests__/index.js:
--------------------------------------------------------------------------------
1 | import { applyMiddleware, compose, createStore } from "redux";
2 | import { KEY_PREFIX } from "redux-persist/lib/constants"
3 | import { AsyncNodeStorage } from "redux-persist-node-storage";
4 | import instrument from "redux-devtools-instrument";
5 | import { createOffline, offline } from "../index";
6 | import { applyDefaults } from "../config";
7 |
8 | const storage = new AsyncNodeStorage("/tmp/storageDir");
9 | const storageKey = `${KEY_PREFIX}offline`;
10 | function noop() {}
11 |
12 | beforeEach(() => storage.removeItem(storageKey, noop) );
13 |
14 | const defaultConfig = applyDefaults({
15 | effect: jest.fn(() => Promise.resolve()),
16 | persistOptions: { storage }
17 | });
18 |
19 | function defaultReducer(state = {
20 | offline: {
21 | busy: false,
22 | lastTransaction: 0,
23 | online: true,
24 | outbox: [],
25 | receipts: [],
26 | retryToken: 0,
27 | retryCount: 0,
28 | retryScheduled: false,
29 | netInfo: {
30 | isConnectionExpensive: null,
31 | reach: 'none'
32 | }
33 | }
34 | }) {
35 | return state;
36 | }
37 |
38 | test("offline() creates storeEnhancer", () => {
39 | const storeEnhancer = offline(defaultConfig);
40 |
41 | const store = storeEnhancer(createStore)(defaultReducer);
42 | expect(store.dispatch).toEqual(expect.any(Function));
43 | expect(store.getState).toEqual(expect.any(Function));
44 | });
45 |
46 | test("createOffline() creates storeEnhancer", () => {
47 | const { middleware, enhanceReducer, enhanceStore } =
48 | createOffline(defaultConfig);
49 | const reducer = enhanceReducer(defaultReducer);
50 | const store = createStore(reducer, compose(
51 | applyMiddleware(middleware),
52 | enhanceStore
53 | ));
54 | expect(store.dispatch).toEqual(expect.any(Function));
55 | expect(store.getState).toEqual(expect.any(Function));
56 | });
57 |
58 | // see https://github.com/redux-offline/redux-offline/issues/31
59 | test("supports HMR by overriding `replaceReducer()`", () => {
60 | const store = offline(defaultConfig)(createStore)(defaultReducer);
61 | store.replaceReducer(defaultReducer);
62 | store.dispatch({ type: "SOME_ACTION" });
63 | expect(store.getState()).toHaveProperty("offline");
64 | });
65 |
66 | // see https://github.com/redux-offline/redux-offline/issues/4
67 | test("restores offline outbox when rehydrates", () => {
68 | const actions = [{
69 | type: "SOME_OFFLINE_ACTION",
70 | meta: { offline: { effect: {} } }
71 | }];
72 | storage.setItem(
73 | storageKey,
74 | JSON.stringify({ outbox: actions }),
75 | noop
76 | );
77 |
78 | expect.assertions(1);
79 | return new Promise(resolve => {
80 | const store = offline({
81 | ...defaultConfig,
82 | persistCallback() {
83 | const { offline: { outbox } } = store.getState();
84 | expect(outbox).toEqual(actions);
85 | resolve();
86 | }
87 | })(createStore)(defaultReducer);
88 | });
89 | });
90 |
91 | // see https://github.com/jevakallio/redux-offline/pull/91
92 | test("works with devtools store enhancer", () => {
93 | const monitorReducer = state => state;
94 | const store = createStore(
95 | defaultReducer,
96 | compose(offline(defaultConfig), instrument(monitorReducer))
97 | );
98 |
99 | expect(() => {
100 | store.dispatch({ type: "SOME_ACTION" });
101 | }).not.toThrow();
102 | });
103 |
--------------------------------------------------------------------------------
/src/__tests__/middleware.js:
--------------------------------------------------------------------------------
1 | import { createOfflineMiddleware } from '../middleware';
2 | import { completeRetry, scheduleRetry } from '../actions';
3 | import { OFFLINE_SEND } from '../constants';
4 | import send from '../send';
5 |
6 | import offlineStateLens from '../defaults/offlineStateLens'
7 |
8 | const offlineAction = {
9 | type: 'OFFLINE_ACTION_REQUEST',
10 | meta: {
11 | offline: {
12 | effect: { url: '/api/endpoint', method: 'POST' },
13 | commit: { type: 'OFFLINE_ACTION_COMMIT' },
14 | rollback: { type: 'OFFLINE_ACTION_ROLLBACK' }
15 | }
16 | }
17 | };
18 |
19 | const defaultOfflineState = {
20 | busy: false,
21 | lastTransaction: 0,
22 | online: true,
23 | outbox: [offlineAction],
24 | receipts: [],
25 | retryToken: 0,
26 | retryCount: 0,
27 | retryScheduled: false,
28 | netInfo: {
29 | isConnectionExpensive: null,
30 | reach: 'NONE'
31 | }
32 | };
33 |
34 | function setup(offlineState = {}) {
35 | const state = {
36 | offline: { ...defaultOfflineState, ...offlineState }
37 | };
38 | return {
39 | config: {
40 | rehydrate: false,
41 | persist: null,
42 | detectNetwork: null,
43 | batch: jest.fn(outbox => outbox.slice(0, 1)),
44 | effect: jest.fn(),
45 | retry: jest.fn(),
46 | discard: jest.fn(),
47 | offlineStateLens,
48 | },
49 | store: {
50 | getState: jest.fn(() => state),
51 | dispatch: jest.fn()
52 | },
53 | next: jest.fn(action => ({ actions: [action] })),
54 | action: { type: 'NOT_OFFLINE_ACTION' }
55 | };
56 | }
57 |
58 | // NOTE: there is not currently an action creator for this
59 | function offlineSend() {
60 | return { type: OFFLINE_SEND };
61 | }
62 |
63 | jest.mock('../send', () => jest.fn(() => Promise.resolve()));
64 | beforeEach(send.mockClear);
65 |
66 | test('creates middleware', () => {
67 | const { config, store, next, action } = setup();
68 | const middleware = createOfflineMiddleware(config);
69 |
70 | const result = middleware(store)(next)(action);
71 | expect(next).toBeCalled();
72 | expect(result).toEqual(next(action));
73 | });
74 |
75 | describe('on any action', () => {
76 | it('processes outbox when idle', () => {
77 | const { config, store, next, action } = setup();
78 | createOfflineMiddleware(config)(store)(next)(action);
79 | expect(send).toBeCalled();
80 | });
81 |
82 | it('does not process outbox when busy', () => {
83 | const { config, store, next, action } = setup({ busy: true });
84 | createOfflineMiddleware(config)(store)(next)(action);
85 | expect(send).not.toBeCalled();
86 | });
87 |
88 | it('does not process outbox when retry scheduled', () => {
89 | const { config, store, next, action } = setup({ retryScheduled: true });
90 | createOfflineMiddleware(config)(store)(next)(action);
91 | expect(send).not.toBeCalled();
92 | });
93 |
94 | it('does not process outbox when offline', () => {
95 | const { config, store, next, action } = setup({ online: false });
96 | createOfflineMiddleware(config)(store)(next)(action);
97 | expect(send).not.toBeCalled();
98 | });
99 | });
100 |
101 | // TODO: test for double dispatch
102 | describe('on OFFLINE_SEND', () => {
103 | it('processes outbox when idle', () => {
104 | const { config, store, next } = setup();
105 | createOfflineMiddleware(config)(store)(next)(offlineSend());
106 | expect(send).toBeCalled();
107 | });
108 |
109 | it('does not process outbox when busy', () => {
110 | const { config, store, next } = setup({ busy: true });
111 | createOfflineMiddleware(config)(store)(next)(offlineSend());
112 | expect(send).not.toBeCalled();
113 | });
114 |
115 | it('processes outbox when retry scheduled', () => {
116 | const { config, store, next } = setup({ retryScheduled: true });
117 | createOfflineMiddleware(config)(store)(next)(offlineSend());
118 | expect(send).toBeCalled();
119 | });
120 |
121 | it('processes outbox when offline', () => {
122 | const { config, store, next } = setup({ online: false });
123 | createOfflineMiddleware(config)(store)(next)(offlineSend());
124 | expect(send).toBeCalled();
125 | });
126 | });
127 |
128 | // FIXME: completeRetry is supposed to be called with an action
129 | // TODO: wrapping `setTimeout()` in a promise in `after()` is pointless
130 | describe('on OFFLINE_SCHEDULE_RETRY', () => {
131 | jest.useFakeTimers();
132 | const delay = 15000;
133 |
134 | test('dispatches COMPLETE_RETRY after delay', () => {
135 | const { config, store, next } = setup();
136 | createOfflineMiddleware(config)(store)(next)(scheduleRetry(delay));
137 | jest.runTimersToTime(delay);
138 |
139 | expect.assertions(1);
140 | const nextAction = store.getState().offline.outbox[0];
141 | return Promise.resolve().then(() =>
142 | expect(store.dispatch).toBeCalledWith(completeRetry(nextAction)));
143 | });
144 | });
145 |
--------------------------------------------------------------------------------
/src/__tests__/send.js:
--------------------------------------------------------------------------------
1 | import send from '../send';
2 | import { busy, scheduleRetry } from '../actions';
3 | import defaultCommitAction from '../defaults/defaultCommit';
4 | import defaultRollbackAction from '../defaults/defaultRollback';
5 |
6 | const DELAY = 1000;
7 | const completedMeta = {
8 | meta: expect.objectContaining({ completed: expect.any(Boolean) })
9 | };
10 |
11 | function setup(partialConfig) {
12 | const defaultConfig = {
13 | effect: jest.fn(() => Promise.resolve()),
14 | discard: () => false,
15 | retry: () => DELAY,
16 | defaultCommit: defaultCommitAction,
17 | defaultRollback: defaultRollbackAction,
18 | };
19 |
20 | return {
21 | action: {
22 | type: 'REQUEST',
23 | meta: {
24 | offline: {
25 | effect: { url: '/api/resource', method: 'get' },
26 | commit: { type: 'COMMIT' },
27 | rollback: { type: 'ROLLBACK' }
28 | }
29 | }
30 | },
31 | config: { ...defaultConfig, ...partialConfig },
32 | dispatch: jest.fn()
33 | };
34 | }
35 |
36 | test('dispatches busy action', () => {
37 | const { action, config, dispatch } = setup();
38 | send(action, dispatch, config);
39 | expect(dispatch).toBeCalledWith(busy(true));
40 | });
41 |
42 | test('requests resource using effects reconciler', () => {
43 | const { action, config, dispatch } = setup();
44 | send(action, dispatch, config);
45 | expect(config.effect).toBeCalledWith(action.meta.offline.effect, action);
46 | });
47 |
48 | describe('when request succeeds', () => {
49 | test('dispatches complete action', () => {
50 | const effect = () => Promise.resolve();
51 | const { action, config, dispatch } = setup({ effect });
52 | const promise = send(action, dispatch, config);
53 |
54 | const { commit } = action.meta.offline;
55 | expect.assertions(2);
56 | return promise.then(() => {
57 | expect(dispatch).toBeCalledWith(expect.objectContaining(commit));
58 | expect(dispatch).toBeCalledWith(expect.objectContaining(completedMeta));
59 | });
60 | });
61 | });
62 |
63 | describe('when request fails', () => {
64 | test('dispatches schedule retry action', () => {
65 | const effect = () => Promise.reject();
66 | const { action, config, dispatch } = setup({ effect });
67 | const promise = send(action, dispatch, config);
68 |
69 | expect.assertions(1);
70 | return promise.then(() => {
71 | expect(dispatch).toBeCalledWith(scheduleRetry(DELAY));
72 | });
73 | });
74 |
75 | test('dispatches complete action on discard', () => {
76 | const effect = () => Promise.reject();
77 | const discard = () => true;
78 | const { action, config, dispatch } = setup({ effect, discard });
79 | const promise = send(action, dispatch, config);
80 |
81 | const { rollback } = action.meta.offline;
82 | expect.assertions(2);
83 | return promise.then(() => {
84 | expect(dispatch).toBeCalledWith(expect.objectContaining(rollback));
85 | expect(dispatch).toBeCalledWith(expect.objectContaining(completedMeta));
86 | });
87 | });
88 |
89 | test('dispatches complete action with promised discard', () => {
90 | const effect = () => Promise.reject();
91 | const discard = () => Promise.resolve(true);
92 | const { action, config, dispatch } = setup({ effect, discard });
93 | const promise = send(action, dispatch, config);
94 |
95 | const { rollback } = action.meta.offline;
96 | expect.assertions(2);
97 | return promise.then(() => {
98 | expect(dispatch).toBeCalledWith(expect.objectContaining(rollback));
99 | expect(dispatch).toBeCalledWith(expect.objectContaining(completedMeta));
100 | });
101 | });
102 |
103 | test('dispatches complete action when discard throw an exception', () => {
104 | const effect = () => Promise.reject();
105 | const discard = () => {throw new Error};
106 | const { action, config, dispatch } = setup({ effect, discard });
107 | const promise = send(action, dispatch, config);
108 |
109 | const { rollback } = action.meta.offline;
110 | expect.assertions(2);
111 | return promise.then(() => {
112 | expect(dispatch).toBeCalledWith(expect.objectContaining(rollback));
113 | expect(dispatch).toBeCalledWith(expect.objectContaining(completedMeta));
114 | });
115 | });
116 | });
117 |
118 | describe('when request succeeds and commit is undefined', () => {
119 | test('dispatches default commit action', () => {
120 | const effect = () => Promise.resolve();
121 |
122 | const action = {
123 | type: 'REQUEST',
124 | meta: {
125 | offline: {
126 | effect: { type: 'MOCK' },
127 | },
128 | },
129 | };
130 |
131 | const { config, dispatch } = setup({ effect });
132 |
133 | const promise = send(action, dispatch, config)
134 |
135 | return promise.then(() => {
136 | expect(dispatch).toBeCalledWith(expect.objectContaining(defaultCommitAction));
137 | expect(dispatch).toBeCalledWith(expect.objectContaining(completedMeta));
138 | });
139 | });
140 | });
141 |
142 | describe('when request is to be discarded and rollback is undefined', () => {
143 | test('dispatches default rollback action', () => {
144 | const effect = () => Promise.reject();
145 | const discard = () => true;
146 |
147 | const action = {
148 | type: 'REQUEST',
149 | meta: {
150 | offline: {
151 | effect: { type: 'MOCK' },
152 | },
153 | },
154 | };
155 |
156 | const { config, dispatch } = setup({ effect, discard });
157 |
158 | const promise = send(action, dispatch, config)
159 |
160 | return promise.then(() => {
161 | expect(dispatch).toBeCalledWith(expect.objectContaining(defaultRollbackAction));
162 | expect(dispatch).toBeCalledWith(expect.objectContaining(completedMeta));
163 | });
164 | });
165 | });
166 |
--------------------------------------------------------------------------------
/src/actions.js:
--------------------------------------------------------------------------------
1 | import {
2 | OFFLINE_STATUS_CHANGED,
3 | OFFLINE_SCHEDULE_RETRY,
4 | OFFLINE_COMPLETE_RETRY,
5 | OFFLINE_BUSY
6 | } from './constants';
7 |
8 | export const networkStatusChanged = ({ online, netInfo }) => ({
9 | type: OFFLINE_STATUS_CHANGED,
10 | payload: {
11 | online,
12 | netInfo
13 | }
14 | });
15 |
16 | export const scheduleRetry = (delay = 0) => ({
17 | type: OFFLINE_SCHEDULE_RETRY,
18 | payload: {
19 | delay
20 | }
21 | });
22 |
23 | export const completeRetry = action => ({
24 | type: OFFLINE_COMPLETE_RETRY,
25 | payload: action
26 | });
27 |
28 | export const busy = isBusy => ({
29 | type: OFFLINE_BUSY,
30 | payload: { busy: isBusy }
31 | });
32 |
--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* global $Shape */
3 | import type { Config } from './types';
4 | import defaults from './defaults';
5 |
6 | export const applyDefaults = (config: $Shape = {}): Config => ({
7 | ...defaults,
8 | ...config
9 | });
10 |
--------------------------------------------------------------------------------
/src/constants.js:
--------------------------------------------------------------------------------
1 | export const OFFLINE_STATUS_CHANGED = 'Offline/STATUS_CHANGED';
2 | export const OFFLINE_SCHEDULE_RETRY = 'Offline/SCHEDULE_RETRY';
3 | export const OFFLINE_COMPLETE_RETRY = 'Offline/COMPLETE_RETRY';
4 | export const OFFLINE_SEND = 'Offline/SEND';
5 | export const OFFLINE_BUSY = 'Offline/BUSY';
6 | export const RESET_STATE = 'Offline/RESET_STATE';
7 | export const PERSIST_REHYDRATE = 'persist/REHYDRATE';
8 | export const JS_ERROR = 'Offline/JS_ERROR';
9 | export const DEFAULT_COMMIT = 'Offline/DEFAULT_COMMIT';
10 | export const DEFAULT_ROLLBACK = 'Offline/DEFAULT_ROLLBACK';
11 |
--------------------------------------------------------------------------------
/src/defaults/defaultCommit.js:
--------------------------------------------------------------------------------
1 | import { DEFAULT_COMMIT } from '../constants';
2 |
3 | const defaultCommit = {
4 | type: DEFAULT_COMMIT
5 | };
6 |
7 | export default defaultCommit;
8 |
--------------------------------------------------------------------------------
/src/defaults/defaultRollback.js:
--------------------------------------------------------------------------------
1 | import { DEFAULT_ROLLBACK } from '../constants';
2 |
3 | const defaultRollback = {
4 | type: DEFAULT_ROLLBACK
5 | };
6 |
7 | export default defaultRollback;
8 |
--------------------------------------------------------------------------------
/src/defaults/detectNetwork.js:
--------------------------------------------------------------------------------
1 | /* global window */
2 |
3 | const handle = (callback, online) => {
4 | // NetInfo is not supported in browsers, hence we only pass online status
5 | if (window.requestAnimationFrame) {
6 | window.requestAnimationFrame(() => callback({ online }));
7 | } else {
8 | setTimeout(() => callback({ online }), 0);
9 | }
10 | };
11 |
12 | export default callback => {
13 | if (typeof window !== 'undefined' && window.addEventListener) {
14 | window.addEventListener('online', () => handle(callback, true));
15 | window.addEventListener('offline', () => handle(callback, false));
16 | handle(callback, window.navigator.onLine);
17 | }
18 | };
19 |
--------------------------------------------------------------------------------
/src/defaults/detectNetwork.native.js:
--------------------------------------------------------------------------------
1 | /* eslint no-underscore-dangle: 0 */
2 | import { AppState, NetInfo } from 'react-native'; // eslint-disable-line
3 | import LegacyDetectNetwork from './detectNetwork.native.legacy';
4 |
5 | class DetectNetwork {
6 | constructor(callback) {
7 | this._reach = null;
8 | this._isConnected = null;
9 | this._isConnectionExpensive = null;
10 | this._callback = callback;
11 | this._shouldInitUpdateReach = true;
12 |
13 | this._init();
14 | this._addListeners();
15 | }
16 |
17 | /**
18 | * Check props for changes
19 | * @param {string} reach - connection reachability.
20 | * - Cross-platform: [none, wifi, cellular, unknown]
21 | * - Android: [bluetooth, ethernet, wimax]
22 | * @returns {boolean} - Whether the connection reachability or the connection props have changed
23 | * @private
24 | */
25 | _hasChanged = reach => {
26 | if (this._reach !== reach) {
27 | return true;
28 | }
29 | if (this._isConnected !== this._getConnection(reach)) {
30 | return true;
31 | }
32 | return false;
33 | };
34 | /**
35 | * Sets the connection reachability prop
36 | * @param {string} reach - connection reachability.
37 | * - Cross-platform: [none, wifi, cellular, unknown]
38 | * - Android: [bluetooth, ethernet, wimax]
39 | * @returns {void}
40 | * @private
41 | */
42 | _setReach = reach => {
43 | this._reach = reach;
44 | this._isConnected = this._getConnection(reach);
45 | };
46 | /**
47 | * Gets the isConnected prop depending on the connection reachability's value
48 | * @param {string} reach - connection reachability.
49 | * - Cross-platform: [none, wifi, cellular, unknown]
50 | * - Android: [bluetooth, ethernet, wimax]
51 | * @returns {void}
52 | * @private
53 | */
54 | _getConnection = reach => reach !== 'none' && reach !== 'unknown';
55 | /**
56 | * Sets the isConnectionExpensive prop
57 | * @returns {Promise.} Resolves to true if connection is expensive,
58 | * false if not, and null if not supported.
59 | * @private
60 | */
61 | _setIsConnectionExpensive = async () => {
62 | try {
63 | this._isConnectionExpensive = await NetInfo.isConnectionExpensive();
64 | } catch (err) {
65 | // err means that isConnectionExpensive is not supported in iOS
66 | this._isConnectionExpensive = null;
67 | }
68 | };
69 | /**
70 | * Sets the shouldInitUpdateReach flag
71 | * @param {boolean} shouldUpdate - Whether the init method should update the reach prop
72 | * @returns {void}
73 | * @private
74 | */
75 | _setShouldInitUpdateReach = shouldUpdate => {
76 | this._shouldInitUpdateReach = shouldUpdate;
77 | };
78 | /**
79 | * Fetches and sets the connection reachability and the isConnected props,
80 | * if neither of the AppState and NetInfo event listeners have been called
81 | * @returns {Promise.} Resolves when the props have been
82 | * initialized and update.
83 | * @private
84 | */
85 | _init = async () => {
86 | const connectionInfo = await NetInfo.getConnectionInfo();
87 | if (this._shouldInitUpdateReach) {
88 | this._update(connectionInfo.type);
89 | }
90 | };
91 | /**
92 | * Check changes on props and store and dispatch if neccesary
93 | * @param {string} reach - connection reachability.
94 | * - Cross-platform: [none, wifi, cellular, unknown]
95 | * - Android: [bluetooth, ethernet, wimax]
96 | * @returns {void}
97 | * @private
98 | */
99 | _update = reach => {
100 | if (this._hasChanged(reach)) {
101 | this._setReach(reach);
102 | this._dispatch();
103 | }
104 | };
105 |
106 | /**
107 | * Adds listeners for when connection reachability and app state changes to update props
108 | * @returns {void}
109 | * @private
110 | */
111 | _addListeners() {
112 | NetInfo.addEventListener('connectionChange', connectionInfo => {
113 | this._setShouldInitUpdateReach(false);
114 | this._update(connectionInfo.type);
115 | });
116 | AppState.addEventListener('change', async () => {
117 | this._setShouldInitUpdateReach(false);
118 | const connectionInfo = await NetInfo.getConnectionInfo();
119 | this._update(connectionInfo.type);
120 | });
121 | }
122 |
123 | /**
124 | * Executes the given callback to update redux's store with the new internal props
125 | * @returns {Promise.} Resolves after fetching the isConnectionExpensive
126 | * and dispatches actions
127 | * @private
128 | */
129 | _dispatch = async () => {
130 | await this._setIsConnectionExpensive();
131 | this._callback({
132 | online: this._isConnected,
133 | netInfo: {
134 | isConnectionExpensive: this._isConnectionExpensive,
135 | reach: this._reach
136 | }
137 | });
138 | };
139 | }
140 |
141 | const isLegacy = typeof NetInfo.getConnectionInfo === 'undefined';
142 | export default callback =>
143 | isLegacy ? new LegacyDetectNetwork(callback) : new DetectNetwork(callback);
144 |
--------------------------------------------------------------------------------
/src/defaults/detectNetwork.native.legacy.js:
--------------------------------------------------------------------------------
1 | /* eslint no-underscore-dangle: 0 */
2 | import { AppState, NetInfo } from 'react-native'; // eslint-disable-line
3 |
4 | class LegacyDetectNetwork {
5 | constructor(callback) {
6 | this._reach = null;
7 | this._isConnected = null;
8 | this._isConnectionExpensive = null;
9 | this._callback = callback;
10 | this._shouldInitUpdateReach = true;
11 |
12 | this._init();
13 | this._addListeners();
14 | }
15 |
16 | /**
17 | * Check props for changes
18 | * @param {string} reach - connection reachability.
19 | * - iOS: [none, wifi, cell, unknown]
20 | * - Android: [NONE, BLUETOOTH, DUMMY, ETHERNET, MOBILE, MOBILE_DUN, MOBILE_HIPRI,
21 | * MOBILE_MMS, MOBILE_SUPL, VPN, WIFI, WIMAX, UNKNOWN]
22 | * @returns {boolean} - Whether the connection reachability or the connection props have changed
23 | * @private
24 | */
25 | _hasChanged = reach => {
26 | if (this._reach !== reach) {
27 | return true;
28 | }
29 | if (this._isConnected !== this._getConnection(reach)) {
30 | return true;
31 | }
32 | return false;
33 | };
34 | /**
35 | * Sets the connection reachability prop
36 | * @param {string} reach - connection reachability.
37 | * - iOS: [none, wifi, cell, unknown]
38 | * - Android: [NONE, BLUETOOTH, DUMMY, ETHERNET, MOBILE, MOBILE_DUN, MOBILE_HIPRI,
39 | * MOBILE_MMS, MOBILE_SUPL, VPN, WIFI, WIMAX, UNKNOWN]
40 | * @returns {void}
41 | * @private
42 | */
43 | _setReach = reach => {
44 | this._reach = reach;
45 | this._isConnected = this._getConnection(reach);
46 | };
47 | /**
48 | * Gets the isConnected prop depending on the connection reachability's value
49 | * @param {string} reach - connection reachability.
50 | * - iOS: [none, wifi, cell, unknown]
51 | * - Android: [NONE, BLUETOOTH, DUMMY, ETHERNET, MOBILE, MOBILE_DUN, MOBILE_HIPRI,
52 | * MOBILE_MMS, MOBILE_SUPL, VPN, WIFI, WIMAX, UNKNOWN]
53 | * @returns {void}
54 | * @private
55 | */
56 | _getConnection = reach => reach !== 'NONE' && reach !== 'UNKNOWN';
57 | /**
58 | * Sets the isConnectionExpensive prop
59 | * @returns {Promise.} Resolves to true if connection is expensive,
60 | * false if not, and null if not supported.
61 | * @private
62 | */
63 | _setIsConnectionExpensive = async () => {
64 | try {
65 | this._isConnectionExpensive = await NetInfo.isConnectionExpensive();
66 | } catch (err) {
67 | // err means that isConnectionExpensive is not supported in iOS
68 | this._isConnectionExpensive = null;
69 | }
70 | };
71 | /**
72 | * Sets the shouldInitUpdateReach flag
73 | * @param {boolean} shouldUpdate - Whether the init method should update the reach prop
74 | * @returns {void}
75 | * @private
76 | */
77 | _setShouldInitUpdateReach = shouldUpdate => {
78 | this._shouldInitUpdateReach = shouldUpdate;
79 | };
80 | /**
81 | * Fetches and sets the connection reachability and the isConnected props,
82 | * if neither of the AppState and NetInfo event listeners have been called
83 | * @returns {Promise.} Resolves when the props have been
84 | * initialized and update.
85 | * @private
86 | */
87 | _init = async () => {
88 | const reach = await NetInfo.fetch();
89 | if (this._shouldInitUpdateReach) {
90 | this._update(reach);
91 | }
92 | };
93 | /**
94 | * Check changes on props and store and dispatch if neccesary
95 | * @param {string} reach - connection reachability.
96 | * - iOS: [none, wifi, cell, unknown]
97 | * - Android: [NONE, BLUETOOTH, DUMMY, ETHERNET, MOBILE, MOBILE_DUN, MOBILE_HIPRI,
98 | * MOBILE_MMS, MOBILE_SUPL, VPN, WIFI, WIMAX, UNKNOWN]
99 | * @returns {void}
100 | * @private
101 | */
102 | _update = reach => {
103 | const normalizedReach = reach.toUpperCase();
104 | if (this._hasChanged(normalizedReach)) {
105 | this._setReach(normalizedReach);
106 | this._dispatch();
107 | }
108 | };
109 |
110 | /**
111 | * Adds listeners for when connection reachability and app state changes to update props
112 | * @returns {void}
113 | * @private
114 | */
115 | _addListeners() {
116 | NetInfo.addEventListener('change', reach => {
117 | this._setShouldInitUpdateReach(false);
118 | this._update(reach);
119 | });
120 | AppState.addEventListener('change', async () => {
121 | this._setShouldInitUpdateReach(false);
122 | const reach = await NetInfo.fetch();
123 | this._update(reach);
124 | });
125 | }
126 |
127 | /**
128 | * Executes the given callback to update redux's store with the new internal props
129 | * @returns {Promise.} Resolves after fetching the isConnectionExpensive
130 | * and dispatches actions
131 | * @private
132 | */
133 | _dispatch = async () => {
134 | await this._setIsConnectionExpensive();
135 | this._callback({
136 | online: this._isConnected,
137 | netInfo: {
138 | isConnectionExpensive: this._isConnectionExpensive,
139 | reach: this._reach
140 | }
141 | });
142 | };
143 | }
144 |
145 | export default LegacyDetectNetwork;
146 |
--------------------------------------------------------------------------------
/src/defaults/discard.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import type { OfflineAction } from '../types';
4 | import { NetworkError } from './effect';
5 |
6 | export default (
7 | error: NetworkError,
8 | action: OfflineAction,
9 | _retries: number = 0 // eslint-disable-line no-unused-vars
10 | ): boolean => {
11 | // not a network error -> discard
12 | if (!('status' in error)) {
13 | return true;
14 | }
15 |
16 | // discard http 4xx errors
17 | // $FlowFixMe
18 | return error.status >= 400 && error.status < 500;
19 | };
20 |
--------------------------------------------------------------------------------
/src/defaults/effect.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* global fetch */
3 |
4 | import type { OfflineAction } from '../types';
5 |
6 | export function NetworkError(response: {} | string, status: number) {
7 | this.name = 'NetworkError';
8 | this.status = status;
9 | this.response = response;
10 | }
11 |
12 | // $FlowFixMe
13 | NetworkError.prototype = Error.prototype;
14 | NetworkError.prototype.status = null;
15 |
16 | const tryParseJSON = (json: string): ?{} => {
17 | if (!json) {
18 | return null;
19 | }
20 | try {
21 | return JSON.parse(json);
22 | } catch (e) {
23 | throw new Error(`Failed to parse unexpected JSON response: ${json}`);
24 | }
25 | };
26 |
27 | const getResponseBody = (res: any): Promise<{} | string> => {
28 | const contentType = res.headers.get('content-type') || false;
29 | if (contentType && contentType.indexOf('json') >= 0) {
30 | return res.text().then(tryParseJSON);
31 | }
32 | return res.text();
33 | };
34 |
35 | // eslint-disable-next-line no-unused-vars
36 | export default (effect: any, _action: OfflineAction): Promise => {
37 | const { url, ...options } = effect;
38 | const headers = { 'content-type': 'application/json', ...options.headers };
39 | return fetch(url, { ...options, headers }).then(res => {
40 | if (res.ok) {
41 | return getResponseBody(res);
42 | }
43 | return getResponseBody(res).then(body => {
44 | throw new NetworkError(body || '', res.status);
45 | });
46 | });
47 | };
48 |
--------------------------------------------------------------------------------
/src/defaults/index.js:
--------------------------------------------------------------------------------
1 | import persist from './persist';
2 | import detectNetwork from './detectNetwork';
3 | import effect from './effect';
4 | import retry from './retry';
5 | import discard from './discard';
6 | import defaultCommit from './defaultCommit';
7 | import defaultRollback from './defaultRollback';
8 | import persistAutoRehydrate from './persistAutoRehydrate';
9 | import offlineStateLens from './offlineStateLens';
10 |
11 | export default {
12 | rehydrate: true, // backward compatibility, TODO remove in the next breaking change version
13 | persist,
14 | detectNetwork,
15 | effect,
16 | retry,
17 | discard,
18 | defaultCommit,
19 | defaultRollback,
20 | persistAutoRehydrate,
21 | offlineStateLens
22 | };
23 |
--------------------------------------------------------------------------------
/src/defaults/offlineStateLens.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | export default (state: any) => {
3 | const { offline, ...rest } = state;
4 | return {
5 | get: offline,
6 | set: (offlineState: any) =>
7 | typeof offlineState === 'undefined'
8 | ? rest
9 | : { offline: offlineState, ...rest }
10 | };
11 | };
12 |
--------------------------------------------------------------------------------
/src/defaults/persist.js:
--------------------------------------------------------------------------------
1 | // flow
2 | import { persistStore } from 'redux-persist';
3 |
4 | export default persistStore;
5 |
--------------------------------------------------------------------------------
/src/defaults/persist.native.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | // $FlowIgnore
4 | import { AsyncStorage } from 'react-native'; // eslint-disable-line
5 | import { persistStore } from 'redux-persist';
6 |
7 | export default (store: any, options: {}, callback: any) =>
8 | persistStore(store, { storage: AsyncStorage, ...options }, callback);
9 |
--------------------------------------------------------------------------------
/src/defaults/persistAutoRehydrate.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import { autoRehydrate } from 'redux-persist';
3 |
4 | export default autoRehydrate;
5 |
--------------------------------------------------------------------------------
/src/defaults/retry.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | import type { OfflineAction } from '../types';
3 |
4 | const decaySchedule = [
5 | 1000, // After 1 seconds
6 | 1000 * 5, // After 5 seconds
7 | 1000 * 15, // After 15 seconds
8 | 1000 * 30, // After 30 seconds
9 | 1000 * 60, // After 1 minute
10 | 1000 * 60 * 3, // After 3 minutes
11 | 1000 * 60 * 5, // After 5 minutes
12 | 1000 * 60 * 10, // After 10 minutes
13 | 1000 * 60 * 30, // After 30 minutes
14 | 1000 * 60 * 60 // After 1 hour
15 | ];
16 |
17 | export default (action: OfflineAction, retries: number): ?number =>
18 | decaySchedule[retries] || null;
19 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* global $Shape */
3 | import { applyMiddleware, compose } from 'redux';
4 | import type { Config } from './types';
5 | import { createOfflineMiddleware } from './middleware';
6 | import { enhanceReducer } from './updater';
7 | import { applyDefaults } from './config';
8 | import { networkStatusChanged } from './actions';
9 |
10 | // @TODO: Take createStore as config?
11 | const warnIfNotReduxAction = (config: $Shape, key: string) => {
12 | const maybeAction = config[key];
13 |
14 | const isNotReduxAction =
15 | maybeAction === null ||
16 | typeof maybeAction !== 'object' ||
17 | typeof maybeAction.type !== 'string' ||
18 | maybeAction.type === '';
19 |
20 | if (isNotReduxAction && console.warn) {
21 | const msg =
22 | `${key} must be a proper redux action, ` +
23 | `i.e. it must be an object and have a non-empty string type. ` +
24 | `Instead you provided: ${JSON.stringify(maybeAction, null, 2)}`;
25 | console.warn(msg);
26 | }
27 | };
28 |
29 | // eslint-disable-next-line no-unused-vars
30 | let persistor;
31 |
32 | export const offline = (userConfig: $Shape = {}) => (
33 | createStore: any
34 | ) => (reducer: any, preloadedState: any, enhancer: any = x => x) => {
35 | const config = applyDefaults(userConfig);
36 |
37 | warnIfNotReduxAction(config, 'defaultCommit');
38 | warnIfNotReduxAction(config, 'defaultRollback');
39 |
40 | // wraps userland reducer with a top-level
41 | // reducer that handles offline state updating
42 | const offlineReducer = enhanceReducer(reducer, config);
43 |
44 | const offlineMiddleware = applyMiddleware(createOfflineMiddleware(config));
45 |
46 | // create autoRehydrate enhancer if required
47 | const offlineEnhancer =
48 | config.persist && config.rehydrate && config.persistAutoRehydrate
49 | ? compose(offlineMiddleware, config.persistAutoRehydrate())
50 | : offlineMiddleware;
51 |
52 | // create store
53 | const store = offlineEnhancer(createStore)(
54 | offlineReducer,
55 | preloadedState,
56 | enhancer
57 | );
58 |
59 | const baseReplaceReducer = store.replaceReducer.bind(store);
60 | store.replaceReducer = function replaceReducer(nextReducer) {
61 | return baseReplaceReducer(enhanceReducer(nextReducer, config));
62 | };
63 |
64 | // launch store persistor
65 | if (config.persist) {
66 | persistor = config.persist(
67 | store,
68 | config.persistOptions,
69 | config.persistCallback
70 | );
71 | }
72 |
73 | // launch network detector
74 | if (config.detectNetwork) {
75 | config.detectNetwork(online => {
76 | store.dispatch(networkStatusChanged(online));
77 | });
78 | }
79 |
80 | return store;
81 | };
82 |
83 | export const createOffline = (userConfig: $Shape = {}) => {
84 | const config = applyDefaults(userConfig);
85 |
86 | warnIfNotReduxAction(config, 'defaultCommit');
87 | warnIfNotReduxAction(config, 'defaultRollback');
88 |
89 | const enhanceStore = (next: any) => (
90 | reducer: any,
91 | preloadedState: any,
92 | enhancer: any
93 | ) => {
94 | // create autoRehydrate enhancer if required
95 | const createStore =
96 | config.persist && config.rehydrate && config.persistAutoRehydrate
97 | ? config.persistAutoRehydrate()(next)
98 | : next;
99 |
100 | // create store
101 | const store = createStore(reducer, preloadedState, enhancer);
102 |
103 | const baseReplaceReducer = store.replaceReducer.bind(store);
104 | store.replaceReducer = function replaceReducer(nextReducer) {
105 | return baseReplaceReducer(enhanceReducer(nextReducer, config));
106 | };
107 |
108 | // launch store persistor
109 | if (config.persist) {
110 | persistor = config.persist(
111 | store,
112 | config.persistOptions,
113 | config.persistCallback
114 | );
115 | }
116 |
117 | // launch network detector
118 | if (config.detectNetwork) {
119 | config.detectNetwork(online => {
120 | store.dispatch(networkStatusChanged(online));
121 | });
122 | }
123 |
124 | return store;
125 | };
126 |
127 | return {
128 | middleware: createOfflineMiddleware(config),
129 | enhanceReducer(reducer) {
130 | return enhanceReducer(reducer, config);
131 | },
132 | enhanceStore
133 | };
134 | };
135 |
--------------------------------------------------------------------------------
/src/middleware.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import type { AppState, Config } from './types';
4 | import { OFFLINE_SEND, OFFLINE_SCHEDULE_RETRY } from './constants';
5 | import { completeRetry } from './actions';
6 | import send from './send';
7 |
8 | const after = (timeout = 0) =>
9 | new Promise(resolve => setTimeout(resolve, timeout));
10 |
11 | export const createOfflineMiddleware = (config: Config) => (store: any) => (
12 | next: any
13 | ) => (action: any) => {
14 | // allow other middleware to do their things
15 | const result = next(action);
16 |
17 | // find any actions to send, if any
18 | const state: AppState = store.getState();
19 | const offline = config.offlineStateLens(state).get;
20 | const offlineAction = offline.outbox[0];
21 |
22 | // if the are any actions in the queue that we are not
23 | // yet processing, send those actions
24 | if (
25 | offlineAction &&
26 | !offline.busy &&
27 | !offline.retryScheduled &&
28 | offline.online
29 | ) {
30 | send(offlineAction, store.dispatch, config, offline.retryCount);
31 | }
32 |
33 | if (action.type === OFFLINE_SCHEDULE_RETRY) {
34 | after(action.payload.delay).then(() => {
35 | store.dispatch(completeRetry(offlineAction));
36 | });
37 | }
38 |
39 | if (action.type === OFFLINE_SEND && offlineAction && !offline.busy) {
40 | send(offlineAction, store.dispatch, config, offline.retryCount);
41 | }
42 |
43 | return result;
44 | };
45 |
--------------------------------------------------------------------------------
/src/send.js:
--------------------------------------------------------------------------------
1 | import { busy, scheduleRetry } from './actions';
2 | import { JS_ERROR } from './constants';
3 | import type { Config, OfflineAction, ResultAction } from './types';
4 |
5 | const complete = (
6 | action: ResultAction,
7 | success: boolean,
8 | payload: {}
9 | ): ResultAction => ({
10 | ...action,
11 | payload,
12 | meta: { ...action.meta, success, completed: true }
13 | });
14 |
15 | const send = (action: OfflineAction, dispatch, config: Config, retries = 0) => {
16 | const metadata = action.meta.offline;
17 | dispatch(busy(true));
18 | return config
19 | .effect(metadata.effect, action)
20 | .then(result => {
21 | const commitAction = metadata.commit || {
22 | ...config.defaultCommit,
23 | meta: { ...config.defaultCommit.meta, offlineAction: action }
24 | };
25 | try {
26 | dispatch(complete(commitAction, true, result));
27 | } catch (e) {
28 | dispatch(complete({ type: JS_ERROR, payload: e }, false));
29 | }
30 | })
31 | .catch(async error => {
32 | const rollbackAction = metadata.rollback || {
33 | ...config.defaultRollback,
34 | meta: { ...config.defaultRollback.meta, offlineAction: action }
35 | };
36 |
37 | // discard
38 | let mustDiscard = true;
39 | try {
40 | mustDiscard = await config.discard(error, action, retries);
41 | } catch (e) {
42 | console.warn(e);
43 | }
44 |
45 | if (!mustDiscard) {
46 | const delay = config.retry(action, retries);
47 | if (delay != null) {
48 | dispatch(scheduleRetry(delay));
49 | return;
50 | }
51 | }
52 |
53 | dispatch(complete(rollbackAction, false, error));
54 | });
55 | };
56 |
57 | export default send;
58 |
--------------------------------------------------------------------------------
/src/types.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | export type ResultAction = {
4 | type: string,
5 | payload: ?{},
6 | meta: {
7 | success: boolean,
8 | completed: boolean
9 | }
10 | };
11 |
12 | export type OfflineMetadata = {
13 | effect: {},
14 | commit?: ResultAction,
15 | rollback?: ResultAction
16 | };
17 |
18 | export type OfflineAction = {
19 | type: string,
20 | payload?: {},
21 | meta: {
22 | transaction?: number,
23 | offline: OfflineMetadata
24 | }
25 | };
26 |
27 | export type Outbox = Array;
28 |
29 | export type OfflineState = {
30 | lastTransaction: number,
31 | online: boolean,
32 | outbox: Outbox,
33 | retryCount: number,
34 | retryScheduled: boolean
35 | };
36 |
37 | export type AppState = {
38 | offline: OfflineState
39 | };
40 |
41 | type NetworkCallback = (result: boolean) => void;
42 |
43 | export type Config = {
44 | detectNetwork: (callback: NetworkCallback) => void,
45 | persist: (store: any, options: {}, callback: () => void) => any,
46 | effect: (effect: any, action: OfflineAction) => Promise<*>,
47 | retry: (action: OfflineAction, retries: number) => ?number,
48 | discard: (error: any, action: OfflineAction, retries: number) => boolean,
49 | persistOptions: {},
50 | persistCallback: (callback: any) => any,
51 | defaultCommit: { type: string },
52 | defaultRollback: { type: string },
53 | persistAutoRehydrate: (config: ?{}) => (next: any) => any,
54 | offlineStateLens: (
55 | state: any
56 | ) => { get: OfflineState, set: (offlineState: ?OfflineState) => any }
57 | };
58 |
--------------------------------------------------------------------------------
/src/updater.js:
--------------------------------------------------------------------------------
1 | // @flow
2 | /* global $Shape */
3 |
4 | import type {
5 | OfflineState,
6 | OfflineAction,
7 | ResultAction,
8 | Config
9 | } from './types';
10 | import {
11 | OFFLINE_STATUS_CHANGED,
12 | OFFLINE_SCHEDULE_RETRY,
13 | OFFLINE_COMPLETE_RETRY,
14 | OFFLINE_BUSY,
15 | RESET_STATE,
16 | PERSIST_REHYDRATE
17 | } from './constants';
18 |
19 | type ControlAction =
20 | | { type: OFFLINE_STATUS_CHANGED, payload: { online: boolean } }
21 | | { type: OFFLINE_SCHEDULE_RETRY };
22 |
23 | const enqueue = (state: OfflineState, action: any): OfflineState => {
24 | const transaction = state.lastTransaction + 1;
25 | const stamped = { ...action, meta: { ...action.meta, transaction } };
26 | const { outbox } = state;
27 | return {
28 | ...state,
29 | lastTransaction: transaction,
30 | outbox: [...outbox, stamped]
31 | };
32 | };
33 |
34 | const dequeue = (state: OfflineState): OfflineState => {
35 | const [, ...rest] = state.outbox;
36 | return {
37 | ...state,
38 | outbox: rest,
39 | retryCount: 0,
40 | busy: false
41 | };
42 | };
43 |
44 | const initialState: OfflineState = {
45 | busy: false,
46 | lastTransaction: 0,
47 | online: false,
48 | outbox: [],
49 | retryCount: 0,
50 | retryScheduled: false,
51 | netInfo: {
52 | isConnectionExpensive: null,
53 | reach: 'NONE'
54 | }
55 | };
56 |
57 | // @TODO: the typing of this is all kinds of wack
58 |
59 | const offlineUpdater = function offlineUpdater(
60 | state: OfflineState = initialState,
61 | action: ControlAction | OfflineAction | ResultAction
62 | ): OfflineState {
63 | // Update online/offline status
64 | if (
65 | action.type === OFFLINE_STATUS_CHANGED &&
66 | action.payload &&
67 | typeof action.payload.online === 'boolean'
68 | ) {
69 | return {
70 | ...state,
71 | online: action.payload.online,
72 | netInfo: action.payload.netInfo
73 | };
74 | }
75 |
76 | if (action.type === PERSIST_REHYDRATE) {
77 | return {
78 | ...state,
79 | ...action.payload.offline,
80 | online: state.online,
81 | netInfo: state.netInfo,
82 | retryScheduled: initialState.retryScheduled,
83 | retryCount: initialState.retryCount,
84 | busy: initialState.busy
85 | };
86 | }
87 |
88 | if (action.type === OFFLINE_SCHEDULE_RETRY) {
89 | return {
90 | ...state,
91 | busy: false,
92 | retryScheduled: true,
93 | retryCount: state.retryCount + 1
94 | };
95 | }
96 |
97 | if (action.type === OFFLINE_COMPLETE_RETRY) {
98 | return { ...state, retryScheduled: false };
99 | }
100 |
101 | if (
102 | action.type === OFFLINE_BUSY &&
103 | action.payload &&
104 | typeof action.payload.busy === 'boolean'
105 | ) {
106 | return { ...state, busy: action.payload.busy };
107 | }
108 |
109 | // Add offline actions to queue
110 | if (action.meta && action.meta.offline) {
111 | return enqueue(state, action);
112 | }
113 |
114 | // Remove completed actions from queue (success or fail)
115 | if (action.meta && action.meta.completed === true) {
116 | return dequeue(state);
117 | }
118 |
119 | if (action.type === RESET_STATE) {
120 | return { ...initialState, online: state.online, netInfo: state.netInfo };
121 | }
122 |
123 | return state;
124 | };
125 |
126 | export const enhanceReducer = (reducer: any, config: $Shape) => (
127 | state: any,
128 | action: any
129 | ) => {
130 | let offlineState;
131 | let restState;
132 | if (typeof state !== 'undefined') {
133 | offlineState = config.offlineStateLens(state).get;
134 | restState = config.offlineStateLens(state).set();
135 | }
136 |
137 | return config
138 | .offlineStateLens(reducer(restState, action))
139 | .set(offlineUpdater(offlineState, action));
140 | };
141 |
--------------------------------------------------------------------------------