├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── dist ├── index.js ├── lib │ ├── combineUrl.js │ ├── createAction.js │ ├── createEventSource.js │ ├── eventHandlers.js │ └── sendRequest.js └── reducers.js ├── docs └── Introduction.md ├── package.json ├── src ├── index.js ├── lib │ ├── combineUrl.js │ ├── createAction.js │ ├── createEventSource.js │ ├── eventHandlers.js │ └── sendRequest.js └── reducers.js └── test ├── createAction.js └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build 3 | lib-cov 4 | *.seed 5 | *.log 6 | *.csv 7 | *.dat 8 | *.out 9 | *.pid 10 | *.gz 11 | _book 12 | 13 | pids 14 | logs 15 | results 16 | package-lock.json 17 | npm-debug.log 18 | node_modules 19 | *.sublime* 20 | *.node 21 | coverage 22 | *.orig 23 | .idea 24 | sandbox 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4" 4 | env: 5 | - CXX=g++-4.8 6 | addons: 7 | apt: 8 | sources: 9 | - ubuntu-toolchain-r-test 10 | packages: 11 | - g++-4.8 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Contra 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

Dead-simple API/EventSource actions for Redux

4 |

5 | 6 | This is a work in progress - There is sparse documentation, no tests, and it's not on npm. Use at your own risk while we finish up! 7 | 8 | ## Install 9 | 10 | One command and you're ready to roll: 11 | 12 | ``` 13 | npm install tahoe 14 | ``` 15 | 16 | **Now**, check out the [documentation](http://shasta.tools/tahoe/docs) to get started! 17 | 18 | ## Example 19 | 20 | Coming soon 21 | 22 | [downloads-image]: http://img.shields.io/npm/dm/tahoe.svg 23 | [npm-url]: https://npmjs.org/package/tahoe 24 | [npm-image]: http://img.shields.io/npm/v/tahoe.svg 25 | 26 | [travis-url]: https://travis-ci.org/shastajs/tahoe 27 | [travis-image]: https://travis-ci.org/shastajs/tahoe.png?branch=master 28 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _createAction = require('./lib/createAction'); 8 | 9 | var _createAction2 = _interopRequireDefault(_createAction); 10 | 11 | var _reducers = require('./reducers'); 12 | 13 | var reducers = _interopRequireWildcard(_reducers); 14 | 15 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } 16 | 17 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 18 | 19 | exports.default = { 20 | createAction: _createAction2.default, 21 | reducers: reducers 22 | }; 23 | module.exports = exports['default']; 24 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC5qcyJdLCJuYW1lcyI6WyJyZWR1Y2VycyIsImNyZWF0ZUFjdGlvbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7Ozs7QUFDQTs7SUFBWUEsUTs7Ozs7O2tCQUVHO0FBQ2JDLHNDQURhO0FBRWJELFlBQVVBO0FBRkcsQyIsImZpbGUiOiJpbmRleC5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjcmVhdGVBY3Rpb24gZnJvbSAnLi9saWIvY3JlYXRlQWN0aW9uJ1xuaW1wb3J0ICogYXMgcmVkdWNlcnMgZnJvbSAnLi9yZWR1Y2VycydcblxuZXhwb3J0IGRlZmF1bHQge1xuICBjcmVhdGVBY3Rpb24sXG4gIHJlZHVjZXJzOiByZWR1Y2Vyc1xufVxuIl19 -------------------------------------------------------------------------------- /dist/lib/combineUrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _extends2 = require('babel-runtime/helpers/extends'); 8 | 9 | var _extends3 = _interopRequireDefault(_extends2); 10 | 11 | var _url = require('url'); 12 | 13 | var _url2 = _interopRequireDefault(_url); 14 | 15 | var _qs = require('qs'); 16 | 17 | var _qs2 = _interopRequireDefault(_qs); 18 | 19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 20 | 21 | exports.default = function (endpoint, query) { 22 | var parsed = _url2.default.parse(endpoint); 23 | 24 | var q = _qs2.default.stringify((0, _extends3.default)({}, _qs2.default.parse(parsed.query, { strictNullHandling: true }), query), { strictNullHandling: true }); 25 | 26 | return _url2.default.format({ 27 | protocol: parsed.protocol, 28 | auth: parsed.auth, 29 | port: parsed.port, 30 | host: parsed.host, 31 | pathname: parsed.pathname, 32 | search: q 33 | }); 34 | }; 35 | 36 | module.exports = exports['default']; 37 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvY29tYmluZVVybC5qcyJdLCJuYW1lcyI6WyJlbmRwb2ludCIsInF1ZXJ5IiwicGFyc2VkIiwidXJsIiwicGFyc2UiLCJxIiwicXMiLCJzdHJpbmdpZnkiLCJzdHJpY3ROdWxsSGFuZGxpbmciLCJmb3JtYXQiLCJwcm90b2NvbCIsImF1dGgiLCJwb3J0IiwiaG9zdCIsInBhdGhuYW1lIiwic2VhcmNoIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBQUE7Ozs7QUFDQTs7Ozs7O2tCQUVlLFVBQUNBLFFBQUQsRUFBV0MsS0FBWCxFQUFxQjtBQUNsQyxNQUFNQyxTQUFTQyxjQUFJQyxLQUFKLENBQVVKLFFBQVYsQ0FBZjs7QUFFQSxNQUFNSyxJQUFJQyxhQUFHQyxTQUFILDRCQUNMRCxhQUFHRixLQUFILENBQVNGLE9BQU9ELEtBQWhCLEVBQXVCLEVBQUVPLG9CQUFvQixJQUF0QixFQUF2QixDQURLLEVBRUxQLEtBRkssR0FHUCxFQUFFTyxvQkFBb0IsSUFBdEIsRUFITyxDQUFWOztBQUtBLFNBQU9MLGNBQUlNLE1BQUosQ0FBVztBQUNoQkMsY0FBVVIsT0FBT1EsUUFERDtBQUVoQkMsVUFBTVQsT0FBT1MsSUFGRztBQUdoQkMsVUFBTVYsT0FBT1UsSUFIRztBQUloQkMsVUFBTVgsT0FBT1csSUFKRztBQUtoQkMsY0FBVVosT0FBT1ksUUFMRDtBQU1oQkMsWUFBUVY7QUFOUSxHQUFYLENBQVA7QUFRRCxDIiwiZmlsZSI6ImNvbWJpbmVVcmwuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdXJsIGZyb20gJ3VybCdcbmltcG9ydCBxcyBmcm9tICdxcydcblxuZXhwb3J0IGRlZmF1bHQgKGVuZHBvaW50LCBxdWVyeSkgPT4ge1xuICBjb25zdCBwYXJzZWQgPSB1cmwucGFyc2UoZW5kcG9pbnQpXG5cbiAgY29uc3QgcSA9IHFzLnN0cmluZ2lmeSh7XG4gICAgLi4ucXMucGFyc2UocGFyc2VkLnF1ZXJ5LCB7IHN0cmljdE51bGxIYW5kbGluZzogdHJ1ZSB9KSxcbiAgICAuLi5xdWVyeVxuICB9LCB7IHN0cmljdE51bGxIYW5kbGluZzogdHJ1ZSB9KVxuXG4gIHJldHVybiB1cmwuZm9ybWF0KHtcbiAgICBwcm90b2NvbDogcGFyc2VkLnByb3RvY29sLFxuICAgIGF1dGg6IHBhcnNlZC5hdXRoLFxuICAgIHBvcnQ6IHBhcnNlZC5wb3J0LFxuICAgIGhvc3Q6IHBhcnNlZC5ob3N0LFxuICAgIHBhdGhuYW1lOiBwYXJzZWQucGF0aG5hbWUsXG4gICAgc2VhcmNoOiBxXG4gIH0pXG59XG4iXX0= -------------------------------------------------------------------------------- /dist/lib/createAction.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.mergeOptions = undefined; 7 | 8 | var _regenerator = require('babel-runtime/regenerator'); 9 | 10 | var _regenerator2 = _interopRequireDefault(_regenerator); 11 | 12 | var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); 13 | 14 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); 15 | 16 | var _lodash = require('lodash.mapvalues'); 17 | 18 | var _lodash2 = _interopRequireDefault(_lodash); 19 | 20 | var _lodash3 = require('lodash.merge'); 21 | 22 | var _lodash4 = _interopRequireDefault(_lodash3); 23 | 24 | var _sendRequest = require('./sendRequest'); 25 | 26 | var _sendRequest2 = _interopRequireDefault(_sendRequest); 27 | 28 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 29 | 30 | var reserved = ['onResponse', 'onError', 'onGlobalError']; 31 | var result = function result(fn, arg) { 32 | return typeof fn === 'function' ? fn(arg) : fn; 33 | }; 34 | 35 | // TODO:0 check entities cache in store and dont fetch if we have it already 36 | 37 | /* 38 | app must have redux-thunk installed 39 | possible options: 40 | 41 | - subset (optional)(string) 42 | - tail (default false)(boolean) 43 | - method (required)(get, post, put, delete, or patch) 44 | - params (object) 45 | - endpoint (required)(url tring) 46 | - collection (default false)(boolean) 47 | - fresh (default to false)(boolean) 48 | 49 | all options can either be a value, or a function that returns a value. 50 | if you define a function, it will receive options.params as an argument 51 | */ 52 | 53 | // merge our multitude of option objects together 54 | // defaults = options defined in createAction 55 | // opt = options specified in action creator 56 | var isReserved = function isReserved(k) { 57 | return reserved.indexOf(k) !== -1; 58 | }; 59 | 60 | var resolveFunctions = function resolveFunctions(o, params) { 61 | return (0, _lodash2.default)(o, function (v, k) { 62 | return isReserved(k) ? v : result(v, params); 63 | }); 64 | }; 65 | 66 | var mergeOptions = exports.mergeOptions = function mergeOptions(defaults, opt) { 67 | var defaultParams = defaults.params ? result(defaults.params) : {}; 68 | var optParams = opt.params ? result(opt.params) : {}; 69 | var params = (0, _lodash4.default)({}, optParams, defaultParams); 70 | return (0, _lodash4.default)({}, resolveFunctions(opt, params), resolveFunctions(defaults, params)); 71 | }; 72 | 73 | exports.default = function () { 74 | var defaults = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 75 | 76 | var nfn = function nfn() { 77 | var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 78 | 79 | var options = mergeOptions(defaults, opt); 80 | if (!options.method) throw new Error('Missing method'); 81 | if (!options.endpoint) throw new Error('Missing endpoint'); 82 | var fn = function () { 83 | var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(dispatch) { 84 | return _regenerator2.default.wrap(function _callee$(_context) { 85 | while (1) { 86 | switch (_context.prev = _context.next) { 87 | case 0: 88 | return _context.abrupt('return', (0, _sendRequest2.default)({ options: options, dispatch: dispatch })); 89 | 90 | case 1: 91 | case 'end': 92 | return _context.stop(); 93 | } 94 | } 95 | }, _callee, undefined); 96 | })); 97 | 98 | return function fn(_x3) { 99 | return _ref.apply(this, arguments); 100 | }; 101 | }(); 102 | fn.options = options; 103 | return fn; 104 | }; 105 | nfn.options = defaults; 106 | return nfn; 107 | }; 108 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvY3JlYXRlQWN0aW9uLmpzIl0sIm5hbWVzIjpbInJlc2VydmVkIiwicmVzdWx0IiwiZm4iLCJhcmciLCJpc1Jlc2VydmVkIiwiayIsImluZGV4T2YiLCJyZXNvbHZlRnVuY3Rpb25zIiwibyIsInBhcmFtcyIsInYiLCJtZXJnZU9wdGlvbnMiLCJkZWZhdWx0cyIsIm9wdCIsImRlZmF1bHRQYXJhbXMiLCJvcHRQYXJhbXMiLCJuZm4iLCJvcHRpb25zIiwibWV0aG9kIiwiRXJyb3IiLCJlbmRwb2ludCIsImRpc3BhdGNoIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFBQTs7OztBQUNBOzs7O0FBQ0E7Ozs7OztBQUVBLElBQU1BLFdBQVcsQ0FDZixZQURlLEVBRWYsU0FGZSxFQUdmLGVBSGUsQ0FBakI7QUFLQSxJQUFNQyxTQUFTLFNBQVRBLE1BQVMsQ0FBQ0MsRUFBRCxFQUFLQyxHQUFMO0FBQUEsU0FBYSxPQUFPRCxFQUFQLEtBQWMsVUFBZCxHQUEyQkEsR0FBR0MsR0FBSCxDQUEzQixHQUFxQ0QsRUFBbEQ7QUFBQSxDQUFmOztBQUVBOztBQUVBOzs7Ozs7Ozs7Ozs7Ozs7O0FBZ0JBO0FBQ0E7QUFDQTtBQUNBLElBQU1FLGFBQWEsU0FBYkEsVUFBYSxDQUFDQyxDQUFEO0FBQUEsU0FBT0wsU0FBU00sT0FBVCxDQUFpQkQsQ0FBakIsTUFBd0IsQ0FBQyxDQUFoQztBQUFBLENBQW5COztBQUVBLElBQU1FLG1CQUFtQixTQUFuQkEsZ0JBQW1CLENBQUNDLENBQUQsRUFBSUMsTUFBSjtBQUFBLFNBQ3ZCLHNCQUFVRCxDQUFWLEVBQWEsVUFBQ0UsQ0FBRCxFQUFJTCxDQUFKO0FBQUEsV0FDWEQsV0FBV0MsQ0FBWCxJQUFnQkssQ0FBaEIsR0FBb0JULE9BQU9TLENBQVAsRUFBVUQsTUFBVixDQURUO0FBQUEsR0FBYixDQUR1QjtBQUFBLENBQXpCOztBQUtPLElBQU1FLHNDQUFlLFNBQWZBLFlBQWUsQ0FBQ0MsUUFBRCxFQUFXQyxHQUFYLEVBQW1CO0FBQzdDLE1BQU1DLGdCQUFnQkYsU0FBU0gsTUFBVCxHQUFrQlIsT0FBT1csU0FBU0gsTUFBaEIsQ0FBbEIsR0FBNEMsRUFBbEU7QUFDQSxNQUFNTSxZQUFZRixJQUFJSixNQUFKLEdBQWFSLE9BQU9ZLElBQUlKLE1BQVgsQ0FBYixHQUFrQyxFQUFwRDtBQUNBLE1BQU1BLFNBQVMsc0JBQU0sRUFBTixFQUFVTSxTQUFWLEVBQXFCRCxhQUFyQixDQUFmO0FBQ0EsU0FBTyxzQkFBTSxFQUFOLEVBQVVQLGlCQUFpQk0sR0FBakIsRUFBc0JKLE1BQXRCLENBQVYsRUFBeUNGLGlCQUFpQkssUUFBakIsRUFBMkJILE1BQTNCLENBQXpDLENBQVA7QUFDRCxDQUxNOztrQkFPUSxZQUFtQjtBQUFBLE1BQWxCRyxRQUFrQix1RUFBUCxFQUFPOztBQUNoQyxNQUFNSSxNQUFNLFNBQU5BLEdBQU0sR0FBYztBQUFBLFFBQWJILEdBQWEsdUVBQVAsRUFBTzs7QUFDeEIsUUFBTUksVUFBVU4sYUFBYUMsUUFBYixFQUF1QkMsR0FBdkIsQ0FBaEI7QUFDQSxRQUFJLENBQUNJLFFBQVFDLE1BQWIsRUFBcUIsTUFBTSxJQUFJQyxLQUFKLENBQVUsZ0JBQVYsQ0FBTjtBQUNyQixRQUFJLENBQUNGLFFBQVFHLFFBQWIsRUFBdUIsTUFBTSxJQUFJRCxLQUFKLENBQVUsa0JBQVYsQ0FBTjtBQUN2QixRQUFNakI7QUFBQSwwRkFBSyxpQkFBT21CLFFBQVA7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLGlEQUFvQiwyQkFBWSxFQUFFSixnQkFBRixFQUFXSSxrQkFBWCxFQUFaLENBQXBCOztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLE9BQUw7O0FBQUE7QUFBQTtBQUFBO0FBQUEsT0FBTjtBQUNBbkIsT0FBR2UsT0FBSCxHQUFhQSxPQUFiO0FBQ0EsV0FBT2YsRUFBUDtBQUNELEdBUEQ7QUFRQWMsTUFBSUMsT0FBSixHQUFjTCxRQUFkO0FBQ0EsU0FBT0ksR0FBUDtBQUNELEMiLCJmaWxlIjoiY3JlYXRlQWN0aW9uLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IG1hcFZhbHVlcyBmcm9tICdsb2Rhc2gubWFwdmFsdWVzJ1xuaW1wb3J0IG1lcmdlIGZyb20gJ2xvZGFzaC5tZXJnZSdcbmltcG9ydCBzZW5kUmVxdWVzdCBmcm9tICcuL3NlbmRSZXF1ZXN0J1xuXG5jb25zdCByZXNlcnZlZCA9IFtcbiAgJ29uUmVzcG9uc2UnLFxuICAnb25FcnJvcicsXG4gICdvbkdsb2JhbEVycm9yJ1xuXVxuY29uc3QgcmVzdWx0ID0gKGZuLCBhcmcpID0+IHR5cGVvZiBmbiA9PT0gJ2Z1bmN0aW9uJyA/IGZuKGFyZykgOiBmblxuXG4vLyBUT0RPOjAgY2hlY2sgZW50aXRpZXMgY2FjaGUgaW4gc3RvcmUgYW5kIGRvbnQgZmV0Y2ggaWYgd2UgaGF2ZSBpdCBhbHJlYWR5XG5cbi8qXG5hcHAgbXVzdCBoYXZlIHJlZHV4LXRodW5rIGluc3RhbGxlZFxucG9zc2libGUgb3B0aW9uczpcblxuLSBzdWJzZXQgKG9wdGlvbmFsKShzdHJpbmcpXG4tIHRhaWwgKGRlZmF1bHQgZmFsc2UpKGJvb2xlYW4pXG4tIG1ldGhvZCAocmVxdWlyZWQpKGdldCwgcG9zdCwgcHV0LCBkZWxldGUsIG9yIHBhdGNoKVxuLSBwYXJhbXMgKG9iamVjdClcbi0gZW5kcG9pbnQgKHJlcXVpcmVkKSh1cmwgdHJpbmcpXG4tIGNvbGxlY3Rpb24gKGRlZmF1bHQgZmFsc2UpKGJvb2xlYW4pXG4tIGZyZXNoIChkZWZhdWx0IHRvIGZhbHNlKShib29sZWFuKVxuXG5hbGwgb3B0aW9ucyBjYW4gZWl0aGVyIGJlIGEgdmFsdWUsIG9yIGEgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGEgdmFsdWUuXG5pZiB5b3UgZGVmaW5lIGEgZnVuY3Rpb24sIGl0IHdpbGwgcmVjZWl2ZSBvcHRpb25zLnBhcmFtcyBhcyBhbiBhcmd1bWVudFxuKi9cblxuLy8gbWVyZ2Ugb3VyIG11bHRpdHVkZSBvZiBvcHRpb24gb2JqZWN0cyB0b2dldGhlclxuLy8gZGVmYXVsdHMgPSBvcHRpb25zIGRlZmluZWQgaW4gY3JlYXRlQWN0aW9uXG4vLyBvcHQgPSBvcHRpb25zIHNwZWNpZmllZCBpbiBhY3Rpb24gY3JlYXRvclxuY29uc3QgaXNSZXNlcnZlZCA9IChrKSA9PiByZXNlcnZlZC5pbmRleE9mKGspICE9PSAtMVxuXG5jb25zdCByZXNvbHZlRnVuY3Rpb25zID0gKG8sIHBhcmFtcykgPT5cbiAgbWFwVmFsdWVzKG8sICh2LCBrKSA9PlxuICAgIGlzUmVzZXJ2ZWQoaykgPyB2IDogcmVzdWx0KHYsIHBhcmFtcylcbiAgKVxuXG5leHBvcnQgY29uc3QgbWVyZ2VPcHRpb25zID0gKGRlZmF1bHRzLCBvcHQpID0+IHtcbiAgY29uc3QgZGVmYXVsdFBhcmFtcyA9IGRlZmF1bHRzLnBhcmFtcyA/IHJlc3VsdChkZWZhdWx0cy5wYXJhbXMpIDoge31cbiAgY29uc3Qgb3B0UGFyYW1zID0gb3B0LnBhcmFtcyA/IHJlc3VsdChvcHQucGFyYW1zKSA6IHt9XG4gIGNvbnN0IHBhcmFtcyA9IG1lcmdlKHt9LCBvcHRQYXJhbXMsIGRlZmF1bHRQYXJhbXMpXG4gIHJldHVybiBtZXJnZSh7fSwgcmVzb2x2ZUZ1bmN0aW9ucyhvcHQsIHBhcmFtcyksIHJlc29sdmVGdW5jdGlvbnMoZGVmYXVsdHMsIHBhcmFtcykpXG59XG5cbmV4cG9ydCBkZWZhdWx0IChkZWZhdWx0cyA9IHt9KSA9PiB7XG4gIGNvbnN0IG5mbiA9IChvcHQgPSB7fSkgPT4ge1xuICAgIGNvbnN0IG9wdGlvbnMgPSBtZXJnZU9wdGlvbnMoZGVmYXVsdHMsIG9wdClcbiAgICBpZiAoIW9wdGlvbnMubWV0aG9kKSB0aHJvdyBuZXcgRXJyb3IoJ01pc3NpbmcgbWV0aG9kJylcbiAgICBpZiAoIW9wdGlvbnMuZW5kcG9pbnQpIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBlbmRwb2ludCcpXG4gICAgY29uc3QgZm4gPSBhc3luYyAoZGlzcGF0Y2gpID0+IHNlbmRSZXF1ZXN0KHsgb3B0aW9ucywgZGlzcGF0Y2ggfSlcbiAgICBmbi5vcHRpb25zID0gb3B0aW9uc1xuICAgIHJldHVybiBmblxuICB9XG4gIG5mbi5vcHRpb25zID0gZGVmYXVsdHNcbiAgcmV0dXJuIG5mblxufVxuIl19 -------------------------------------------------------------------------------- /dist/lib/createEventSource.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _regenerator = require('babel-runtime/regenerator'); 8 | 9 | var _regenerator2 = _interopRequireDefault(_regenerator); 10 | 11 | var _keys = require('babel-runtime/core-js/object/keys'); 12 | 13 | var _keys2 = _interopRequireDefault(_keys); 14 | 15 | var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); 16 | 17 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); 18 | 19 | var _combineUrl = require('./combineUrl'); 20 | 21 | var _combineUrl2 = _interopRequireDefault(_combineUrl); 22 | 23 | var _eventHandlers = require('./eventHandlers'); 24 | 25 | var _eventHandlers2 = _interopRequireDefault(_eventHandlers); 26 | 27 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 28 | 29 | var tryParse = function tryParse(_ref) { 30 | var data = _ref.data, 31 | options = _ref.options, 32 | dispatch = _ref.dispatch; 33 | 34 | try { 35 | return JSON.parse(data); 36 | } catch (err) { 37 | dispatch({ 38 | type: 'tahoe.failure', 39 | meta: options, 40 | payload: err 41 | }); 42 | } 43 | }; 44 | 45 | exports.default = function () { 46 | var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(_ref3) { 47 | var options = _ref3.options, 48 | dispatch = _ref3.dispatch; 49 | var finalUrl, src; 50 | return _regenerator2.default.wrap(function _callee$(_context) { 51 | while (1) { 52 | switch (_context.prev = _context.next) { 53 | case 0: 54 | finalUrl = (0, _combineUrl2.default)(options.endpoint, options.query); 55 | src = new EventSource(finalUrl, { withCredentials: options.withCredentials }); 56 | 57 | // wire up listeners n shiz 58 | 59 | (0, _keys2.default)(_eventHandlers2.default).forEach(function (eventName) { 60 | var handler = _eventHandlers2.default[eventName]; 61 | src.addEventListener(eventName, function (_ref4) { 62 | var data = _ref4.data; 63 | 64 | var parsed = data && tryParse({ options: options, dispatch: dispatch, data: data }); 65 | if (data && typeof parsed === 'undefined') return; 66 | handler({ options: options, dispatch: dispatch, data: parsed }); 67 | }, false); 68 | }); 69 | 70 | case 3: 71 | case 'end': 72 | return _context.stop(); 73 | } 74 | } 75 | }, _callee, undefined); 76 | })); 77 | 78 | return function (_x) { 79 | return _ref2.apply(this, arguments); 80 | }; 81 | }(); 82 | 83 | module.exports = exports['default']; 84 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvY3JlYXRlRXZlbnRTb3VyY2UuanMiXSwibmFtZXMiOlsidHJ5UGFyc2UiLCJkYXRhIiwib3B0aW9ucyIsImRpc3BhdGNoIiwiSlNPTiIsInBhcnNlIiwiZXJyIiwidHlwZSIsIm1ldGEiLCJwYXlsb2FkIiwiZmluYWxVcmwiLCJlbmRwb2ludCIsInF1ZXJ5Iiwic3JjIiwiRXZlbnRTb3VyY2UiLCJ3aXRoQ3JlZGVudGlhbHMiLCJoYW5kbGVycyIsImZvckVhY2giLCJldmVudE5hbWUiLCJoYW5kbGVyIiwiYWRkRXZlbnRMaXN0ZW5lciIsInBhcnNlZCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7Ozs7QUFDQTs7Ozs7O0FBRUEsSUFBTUEsV0FBVyxTQUFYQSxRQUFXLE9BQWlDO0FBQUEsTUFBOUJDLElBQThCLFFBQTlCQSxJQUE4QjtBQUFBLE1BQXhCQyxPQUF3QixRQUF4QkEsT0FBd0I7QUFBQSxNQUFmQyxRQUFlLFFBQWZBLFFBQWU7O0FBQ2hELE1BQUk7QUFDRixXQUFPQyxLQUFLQyxLQUFMLENBQVdKLElBQVgsQ0FBUDtBQUNELEdBRkQsQ0FFRSxPQUFPSyxHQUFQLEVBQVk7QUFDWkgsYUFBUztBQUNQSSxZQUFNLGVBREM7QUFFUEMsWUFBTU4sT0FGQztBQUdQTyxlQUFTSDtBQUhGLEtBQVQ7QUFLRDtBQUNGLENBVkQ7Ozt1RkFZZTtBQUFBLFFBQVNKLE9BQVQsU0FBU0EsT0FBVDtBQUFBLFFBQWtCQyxRQUFsQixTQUFrQkEsUUFBbEI7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ1BPLG9CQURPLEdBQ0ksMEJBQVdSLFFBQVFTLFFBQW5CLEVBQTZCVCxRQUFRVSxLQUFyQyxDQURKO0FBRVBDLGVBRk8sR0FFRCxJQUFJQyxXQUFKLENBQWdCSixRQUFoQixFQUEwQixFQUFFSyxpQkFBaUJiLFFBQVFhLGVBQTNCLEVBQTFCLENBRkM7O0FBSWI7O0FBQ0EsZ0NBQVlDLHVCQUFaLEVBQXNCQyxPQUF0QixDQUE4QixVQUFDQyxTQUFELEVBQWU7QUFDM0Msa0JBQU1DLFVBQVVILHdCQUFTRSxTQUFULENBQWhCO0FBQ0FMLGtCQUFJTyxnQkFBSixDQUFxQkYsU0FBckIsRUFBZ0MsaUJBQWM7QUFBQSxvQkFBWGpCLElBQVcsU0FBWEEsSUFBVzs7QUFDNUMsb0JBQU1vQixTQUFTcEIsUUFBUUQsU0FBUyxFQUFFRSxnQkFBRixFQUFXQyxrQkFBWCxFQUFxQkYsVUFBckIsRUFBVCxDQUF2QjtBQUNBLG9CQUFJQSxRQUFRLE9BQU9vQixNQUFQLEtBQWtCLFdBQTlCLEVBQTJDO0FBQzNDRix3QkFBUSxFQUFFakIsZ0JBQUYsRUFBV0Msa0JBQVgsRUFBcUJGLE1BQU1vQixNQUEzQixFQUFSO0FBQ0QsZUFKRCxFQUlHLEtBSkg7QUFLRCxhQVBEOztBQUxhO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEciLCJmaWxlIjoiY3JlYXRlRXZlbnRTb3VyY2UuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgY29tYmluZVVybCBmcm9tICcuL2NvbWJpbmVVcmwnXG5pbXBvcnQgaGFuZGxlcnMgZnJvbSAnLi9ldmVudEhhbmRsZXJzJ1xuXG5jb25zdCB0cnlQYXJzZSA9ICh7IGRhdGEsIG9wdGlvbnMsIGRpc3BhdGNoIH0pID0+IHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gSlNPTi5wYXJzZShkYXRhKVxuICB9IGNhdGNoIChlcnIpIHtcbiAgICBkaXNwYXRjaCh7XG4gICAgICB0eXBlOiAndGFob2UuZmFpbHVyZScsXG4gICAgICBtZXRhOiBvcHRpb25zLFxuICAgICAgcGF5bG9hZDogZXJyXG4gICAgfSlcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBhc3luYyAoeyBvcHRpb25zLCBkaXNwYXRjaCB9KSA9PiB7XG4gIGNvbnN0IGZpbmFsVXJsID0gY29tYmluZVVybChvcHRpb25zLmVuZHBvaW50LCBvcHRpb25zLnF1ZXJ5KVxuICBjb25zdCBzcmMgPSBuZXcgRXZlbnRTb3VyY2UoZmluYWxVcmwsIHsgd2l0aENyZWRlbnRpYWxzOiBvcHRpb25zLndpdGhDcmVkZW50aWFscyB9KVxuXG4gIC8vIHdpcmUgdXAgbGlzdGVuZXJzIG4gc2hpelxuICBPYmplY3Qua2V5cyhoYW5kbGVycykuZm9yRWFjaCgoZXZlbnROYW1lKSA9PiB7XG4gICAgY29uc3QgaGFuZGxlciA9IGhhbmRsZXJzW2V2ZW50TmFtZV1cbiAgICBzcmMuYWRkRXZlbnRMaXN0ZW5lcihldmVudE5hbWUsICh7IGRhdGEgfSkgPT4ge1xuICAgICAgY29uc3QgcGFyc2VkID0gZGF0YSAmJiB0cnlQYXJzZSh7IG9wdGlvbnMsIGRpc3BhdGNoLCBkYXRhIH0pXG4gICAgICBpZiAoZGF0YSAmJiB0eXBlb2YgcGFyc2VkID09PSAndW5kZWZpbmVkJykgcmV0dXJuXG4gICAgICBoYW5kbGVyKHsgb3B0aW9ucywgZGlzcGF0Y2gsIGRhdGE6IHBhcnNlZCB9KVxuICAgIH0sIGZhbHNlKVxuICB9KVxufVxuIl19 -------------------------------------------------------------------------------- /dist/lib/eventHandlers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var handlers = {}; 8 | handlers.open = function (_ref) { 9 | var options = _ref.options, 10 | dispatch = _ref.dispatch; 11 | return dispatch({ 12 | type: 'tahoe.tail.open', 13 | meta: options 14 | }); 15 | }; 16 | 17 | handlers.insert = function (_ref2) { 18 | var options = _ref2.options, 19 | dispatch = _ref2.dispatch, 20 | next = _ref2.data.next; 21 | return dispatch({ 22 | type: 'tahoe.tail.insert', 23 | meta: options, 24 | payload: { 25 | raw: next 26 | } 27 | }); 28 | }; 29 | 30 | handlers.update = function (_ref3) { 31 | var options = _ref3.options, 32 | dispatch = _ref3.dispatch, 33 | _ref3$data = _ref3.data, 34 | prev = _ref3$data.prev, 35 | next = _ref3$data.next; 36 | return dispatch({ 37 | type: 'tahoe.tail.update', 38 | meta: options, 39 | payload: { 40 | raw: { 41 | prev: prev, 42 | next: next 43 | } 44 | } 45 | }); 46 | }; 47 | 48 | handlers.delete = function (_ref4) { 49 | var options = _ref4.options, 50 | dispatch = _ref4.dispatch, 51 | prev = _ref4.data.prev; 52 | return dispatch({ 53 | type: 'tahoe.tail.delete', 54 | meta: options, 55 | payload: { 56 | raw: prev 57 | } 58 | }); 59 | }; 60 | 61 | exports.default = handlers; 62 | module.exports = exports['default']; 63 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvZXZlbnRIYW5kbGVycy5qcyJdLCJuYW1lcyI6WyJoYW5kbGVycyIsIm9wZW4iLCJvcHRpb25zIiwiZGlzcGF0Y2giLCJ0eXBlIiwibWV0YSIsImluc2VydCIsIm5leHQiLCJkYXRhIiwicGF5bG9hZCIsInJhdyIsInVwZGF0ZSIsInByZXYiLCJkZWxldGUiXSwibWFwcGluZ3MiOiI7Ozs7OztBQUNBLElBQU1BLFdBQVcsRUFBakI7QUFDQUEsU0FBU0MsSUFBVCxHQUFnQjtBQUFBLE1BQUdDLE9BQUgsUUFBR0EsT0FBSDtBQUFBLE1BQVlDLFFBQVosUUFBWUEsUUFBWjtBQUFBLFNBQ2RBLFNBQVM7QUFDUEMsVUFBTSxpQkFEQztBQUVQQyxVQUFNSDtBQUZDLEdBQVQsQ0FEYztBQUFBLENBQWhCOztBQU1BRixTQUFTTSxNQUFULEdBQWtCO0FBQUEsTUFBR0osT0FBSCxTQUFHQSxPQUFIO0FBQUEsTUFBWUMsUUFBWixTQUFZQSxRQUFaO0FBQUEsTUFBOEJJLElBQTlCLFNBQXNCQyxJQUF0QixDQUE4QkQsSUFBOUI7QUFBQSxTQUNoQkosU0FBUztBQUNQQyxVQUFNLG1CQURDO0FBRVBDLFVBQU1ILE9BRkM7QUFHUE8sYUFBUztBQUNQQyxXQUFLSDtBQURFO0FBSEYsR0FBVCxDQURnQjtBQUFBLENBQWxCOztBQVNBUCxTQUFTVyxNQUFULEdBQWtCO0FBQUEsTUFBR1QsT0FBSCxTQUFHQSxPQUFIO0FBQUEsTUFBWUMsUUFBWixTQUFZQSxRQUFaO0FBQUEseUJBQXNCSyxJQUF0QjtBQUFBLE1BQThCSSxJQUE5QixjQUE4QkEsSUFBOUI7QUFBQSxNQUFvQ0wsSUFBcEMsY0FBb0NBLElBQXBDO0FBQUEsU0FDaEJKLFNBQVM7QUFDUEMsVUFBTSxtQkFEQztBQUVQQyxVQUFNSCxPQUZDO0FBR1BPLGFBQVM7QUFDUEMsV0FBSztBQUNIRSxjQUFNQSxJQURIO0FBRUhMLGNBQU1BO0FBRkg7QUFERTtBQUhGLEdBQVQsQ0FEZ0I7QUFBQSxDQUFsQjs7QUFhQVAsU0FBU2EsTUFBVCxHQUFrQjtBQUFBLE1BQUdYLE9BQUgsU0FBR0EsT0FBSDtBQUFBLE1BQVlDLFFBQVosU0FBWUEsUUFBWjtBQUFBLE1BQThCUyxJQUE5QixTQUFzQkosSUFBdEIsQ0FBOEJJLElBQTlCO0FBQUEsU0FDaEJULFNBQVM7QUFDUEMsVUFBTSxtQkFEQztBQUVQQyxVQUFNSCxPQUZDO0FBR1BPLGFBQVM7QUFDUEMsV0FBS0U7QUFERTtBQUhGLEdBQVQsQ0FEZ0I7QUFBQSxDQUFsQjs7a0JBU2VaLFEiLCJmaWxlIjoiZXZlbnRIYW5kbGVycy5qcyIsInNvdXJjZXNDb250ZW50IjpbIlxuY29uc3QgaGFuZGxlcnMgPSB7fVxuaGFuZGxlcnMub3BlbiA9ICh7IG9wdGlvbnMsIGRpc3BhdGNoIH0pID0+XG4gIGRpc3BhdGNoKHtcbiAgICB0eXBlOiAndGFob2UudGFpbC5vcGVuJyxcbiAgICBtZXRhOiBvcHRpb25zXG4gIH0pXG5cbmhhbmRsZXJzLmluc2VydCA9ICh7IG9wdGlvbnMsIGRpc3BhdGNoLCBkYXRhOiB7IG5leHQgfSB9KSA9PlxuICBkaXNwYXRjaCh7XG4gICAgdHlwZTogJ3RhaG9lLnRhaWwuaW5zZXJ0JyxcbiAgICBtZXRhOiBvcHRpb25zLFxuICAgIHBheWxvYWQ6IHtcbiAgICAgIHJhdzogbmV4dFxuICAgIH1cbiAgfSlcblxuaGFuZGxlcnMudXBkYXRlID0gKHsgb3B0aW9ucywgZGlzcGF0Y2gsIGRhdGE6IHsgcHJldiwgbmV4dCB9IH0pID0+XG4gIGRpc3BhdGNoKHtcbiAgICB0eXBlOiAndGFob2UudGFpbC51cGRhdGUnLFxuICAgIG1ldGE6IG9wdGlvbnMsXG4gICAgcGF5bG9hZDoge1xuICAgICAgcmF3OiB7XG4gICAgICAgIHByZXY6IHByZXYsXG4gICAgICAgIG5leHQ6IG5leHRcbiAgICAgIH1cbiAgICB9XG4gIH0pXG5cblxuaGFuZGxlcnMuZGVsZXRlID0gKHsgb3B0aW9ucywgZGlzcGF0Y2gsIGRhdGE6IHsgcHJldiB9IH0pID0+XG4gIGRpc3BhdGNoKHtcbiAgICB0eXBlOiAndGFob2UudGFpbC5kZWxldGUnLFxuICAgIG1ldGE6IG9wdGlvbnMsXG4gICAgcGF5bG9hZDoge1xuICAgICAgcmF3OiBwcmV2XG4gICAgfVxuICB9KVxuXG5leHBvcnQgZGVmYXVsdCBoYW5kbGVyc1xuIl19 -------------------------------------------------------------------------------- /dist/lib/sendRequest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _regenerator = require('babel-runtime/regenerator'); 8 | 9 | var _regenerator2 = _interopRequireDefault(_regenerator); 10 | 11 | var _promise = require('babel-runtime/core-js/promise'); 12 | 13 | var _promise2 = _interopRequireDefault(_promise); 14 | 15 | var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); 16 | 17 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); 18 | 19 | var _superagent = require('superagent'); 20 | 21 | var _superagent2 = _interopRequireDefault(_superagent); 22 | 23 | var _createEventSource = require('./createEventSource'); 24 | 25 | var _createEventSource2 = _interopRequireDefault(_createEventSource); 26 | 27 | var _qs = require('qs'); 28 | 29 | var _qs2 = _interopRequireDefault(_qs); 30 | 31 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 32 | 33 | var createResponseHandler = function createResponseHandler(_ref) { 34 | var options = _ref.options, 35 | dispatch = _ref.dispatch, 36 | reject = _ref.reject, 37 | resolve = _ref.resolve; 38 | 39 | var debug = options.method.toUpperCase() + ' ' + options.endpoint; 40 | return function (err, res) { 41 | if (!res && !err) { 42 | err = new Error('Connection failed: ' + debug); 43 | } 44 | if (err) { 45 | err.res = res; 46 | dispatch({ 47 | type: 'tahoe.failure', 48 | meta: options, 49 | payload: err 50 | }); 51 | if (options.onGlobalError) options.onGlobalError(err, res); 52 | if (options.onError) options.onError(err, res); 53 | return reject(err); 54 | } 55 | 56 | // handle json responses 57 | dispatch({ 58 | type: 'tahoe.success', 59 | meta: options, 60 | payload: { 61 | raw: res.body, 62 | text: res.text 63 | } 64 | }); 65 | if (options.onResponse) options.onResponse(res); 66 | resolve(res); 67 | }; 68 | }; 69 | 70 | exports.default = function () { 71 | var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(_ref3) { 72 | var options = _ref3.options, 73 | dispatch = _ref3.dispatch; 74 | var req; 75 | return _regenerator2.default.wrap(function _callee$(_context) { 76 | while (1) { 77 | switch (_context.prev = _context.next) { 78 | case 0: 79 | dispatch({ 80 | type: 'tahoe.request', 81 | payload: options 82 | }); 83 | 84 | if (!options.tail) { 85 | _context.next = 3; 86 | break; 87 | } 88 | 89 | return _context.abrupt('return', (0, _createEventSource2.default)({ options: options, dispatch: dispatch })); 90 | 91 | case 3: 92 | req = _superagent2.default[options.method.toLowerCase()](options.endpoint); 93 | 94 | if (options.headers) { 95 | req.set(options.headers); 96 | } 97 | if (options.query) { 98 | req.query(typeof options.query === 'string' ? options.query : _qs2.default.stringify(options.query, { strictNullHandling: true })); 99 | } 100 | if (options.body) { 101 | req.send(options.body); 102 | } 103 | if (options.withCredentials) { 104 | req.withCredentials(); 105 | } 106 | 107 | return _context.abrupt('return', new _promise2.default(function (resolve, reject) { 108 | req.end(createResponseHandler({ 109 | options: options, 110 | dispatch: dispatch, 111 | reject: reject, 112 | resolve: resolve 113 | })); 114 | })); 115 | 116 | case 9: 117 | case 'end': 118 | return _context.stop(); 119 | } 120 | } 121 | }, _callee, undefined); 122 | })); 123 | 124 | return function (_x) { 125 | return _ref2.apply(this, arguments); 126 | }; 127 | }(); 128 | 129 | module.exports = exports['default']; 130 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9saWIvc2VuZFJlcXVlc3QuanMiXSwibmFtZXMiOlsiY3JlYXRlUmVzcG9uc2VIYW5kbGVyIiwib3B0aW9ucyIsImRpc3BhdGNoIiwicmVqZWN0IiwicmVzb2x2ZSIsImRlYnVnIiwibWV0aG9kIiwidG9VcHBlckNhc2UiLCJlbmRwb2ludCIsImVyciIsInJlcyIsIkVycm9yIiwidHlwZSIsIm1ldGEiLCJwYXlsb2FkIiwib25HbG9iYWxFcnJvciIsIm9uRXJyb3IiLCJyYXciLCJib2R5IiwidGV4dCIsIm9uUmVzcG9uc2UiLCJ0YWlsIiwicmVxIiwicmVxdWVzdCIsInRvTG93ZXJDYXNlIiwiaGVhZGVycyIsInNldCIsInF1ZXJ5IiwicXMiLCJzdHJpbmdpZnkiLCJzdHJpY3ROdWxsSGFuZGxpbmciLCJzZW5kIiwid2l0aENyZWRlbnRpYWxzIiwiZW5kIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTs7OztBQUNBOzs7O0FBQ0E7Ozs7OztBQUVBLElBQU1BLHdCQUF3QixTQUF4QkEscUJBQXdCLE9BQTRDO0FBQUEsTUFBekNDLE9BQXlDLFFBQXpDQSxPQUF5QztBQUFBLE1BQWhDQyxRQUFnQyxRQUFoQ0EsUUFBZ0M7QUFBQSxNQUF0QkMsTUFBc0IsUUFBdEJBLE1BQXNCO0FBQUEsTUFBZEMsT0FBYyxRQUFkQSxPQUFjOztBQUN4RSxNQUFNQyxRQUFXSixRQUFRSyxNQUFSLENBQWVDLFdBQWYsRUFBWCxTQUEyQ04sUUFBUU8sUUFBekQ7QUFDQSxTQUFPLFVBQUNDLEdBQUQsRUFBTUMsR0FBTixFQUFjO0FBQ25CLFFBQUksQ0FBQ0EsR0FBRCxJQUFRLENBQUNELEdBQWIsRUFBa0I7QUFDaEJBLFlBQU0sSUFBSUUsS0FBSix5QkFBZ0NOLEtBQWhDLENBQU47QUFDRDtBQUNELFFBQUlJLEdBQUosRUFBUztBQUNQQSxVQUFJQyxHQUFKLEdBQVVBLEdBQVY7QUFDQVIsZUFBUztBQUNQVSxjQUFNLGVBREM7QUFFUEMsY0FBTVosT0FGQztBQUdQYSxpQkFBU0w7QUFIRixPQUFUO0FBS0EsVUFBSVIsUUFBUWMsYUFBWixFQUEyQmQsUUFBUWMsYUFBUixDQUFzQk4sR0FBdEIsRUFBMkJDLEdBQTNCO0FBQzNCLFVBQUlULFFBQVFlLE9BQVosRUFBcUJmLFFBQVFlLE9BQVIsQ0FBZ0JQLEdBQWhCLEVBQXFCQyxHQUFyQjtBQUNyQixhQUFPUCxPQUFPTSxHQUFQLENBQVA7QUFDRDs7QUFFRDtBQUNBUCxhQUFTO0FBQ1BVLFlBQU0sZUFEQztBQUVQQyxZQUFNWixPQUZDO0FBR1BhLGVBQVM7QUFDUEcsYUFBS1AsSUFBSVEsSUFERjtBQUVQQyxjQUFNVCxJQUFJUztBQUZIO0FBSEYsS0FBVDtBQVFBLFFBQUlsQixRQUFRbUIsVUFBWixFQUF3Qm5CLFFBQVFtQixVQUFSLENBQW1CVixHQUFuQjtBQUN4Qk4sWUFBUU0sR0FBUjtBQUNELEdBM0JEO0FBNEJELENBOUJEOzs7dUZBZ0NlO0FBQUEsUUFBU1QsT0FBVCxTQUFTQSxPQUFUO0FBQUEsUUFBa0JDLFFBQWxCLFNBQWtCQSxRQUFsQjtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDYkEscUJBQVM7QUFDUFUsb0JBQU0sZUFEQztBQUVQRSx1QkFBU2I7QUFGRixhQUFUOztBQURhLGlCQU1UQSxRQUFRb0IsSUFOQztBQUFBO0FBQUE7QUFBQTs7QUFBQSw2Q0FPSixpQ0FBa0IsRUFBRXBCLGdCQUFGLEVBQVdDLGtCQUFYLEVBQWxCLENBUEk7O0FBQUE7QUFVUG9CLGVBVk8sR0FVREMscUJBQVF0QixRQUFRSyxNQUFSLENBQWVrQixXQUFmLEVBQVIsRUFBc0N2QixRQUFRTyxRQUE5QyxDQVZDOztBQVdiLGdCQUFJUCxRQUFRd0IsT0FBWixFQUFxQjtBQUNuQkgsa0JBQUlJLEdBQUosQ0FBUXpCLFFBQVF3QixPQUFoQjtBQUNEO0FBQ0QsZ0JBQUl4QixRQUFRMEIsS0FBWixFQUFtQjtBQUNqQkwsa0JBQUlLLEtBQUosQ0FBVSxPQUFPMUIsUUFBUTBCLEtBQWYsS0FBeUIsUUFBekIsR0FDTjFCLFFBQVEwQixLQURGLEdBRU5DLGFBQUdDLFNBQUgsQ0FBYTVCLFFBQVEwQixLQUFyQixFQUE0QixFQUFFRyxvQkFBb0IsSUFBdEIsRUFBNUIsQ0FGSjtBQUdEO0FBQ0QsZ0JBQUk3QixRQUFRaUIsSUFBWixFQUFrQjtBQUNoQkksa0JBQUlTLElBQUosQ0FBUzlCLFFBQVFpQixJQUFqQjtBQUNEO0FBQ0QsZ0JBQUlqQixRQUFRK0IsZUFBWixFQUE2QjtBQUMzQlYsa0JBQUlVLGVBQUo7QUFDRDs7QUF4QlksNkNBMEJOLHNCQUFZLFVBQUM1QixPQUFELEVBQVVELE1BQVYsRUFBcUI7QUFDdENtQixrQkFBSVcsR0FBSixDQUFRakMsc0JBQXNCO0FBQzVCQyxnQ0FENEI7QUFFNUJDLGtDQUY0QjtBQUc1QkMsOEJBSDRCO0FBSTVCQztBQUo0QixlQUF0QixDQUFSO0FBTUQsYUFQTSxDQTFCTTs7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxHIiwiZmlsZSI6InNlbmRSZXF1ZXN0LmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHJlcXVlc3QgZnJvbSAnc3VwZXJhZ2VudCdcbmltcG9ydCBjcmVhdGVFdmVudFNvdXJjZSBmcm9tICcuL2NyZWF0ZUV2ZW50U291cmNlJ1xuaW1wb3J0IHFzIGZyb20gJ3FzJ1xuXG5jb25zdCBjcmVhdGVSZXNwb25zZUhhbmRsZXIgPSAoeyBvcHRpb25zLCBkaXNwYXRjaCwgcmVqZWN0LCByZXNvbHZlIH0pID0+IHtcbiAgY29uc3QgZGVidWcgPSBgJHtvcHRpb25zLm1ldGhvZC50b1VwcGVyQ2FzZSgpfSAke29wdGlvbnMuZW5kcG9pbnR9YFxuICByZXR1cm4gKGVyciwgcmVzKSA9PiB7XG4gICAgaWYgKCFyZXMgJiYgIWVycikge1xuICAgICAgZXJyID0gbmV3IEVycm9yKGBDb25uZWN0aW9uIGZhaWxlZDogJHtkZWJ1Z31gKVxuICAgIH1cbiAgICBpZiAoZXJyKSB7XG4gICAgICBlcnIucmVzID0gcmVzXG4gICAgICBkaXNwYXRjaCh7XG4gICAgICAgIHR5cGU6ICd0YWhvZS5mYWlsdXJlJyxcbiAgICAgICAgbWV0YTogb3B0aW9ucyxcbiAgICAgICAgcGF5bG9hZDogZXJyXG4gICAgICB9KVxuICAgICAgaWYgKG9wdGlvbnMub25HbG9iYWxFcnJvcikgb3B0aW9ucy5vbkdsb2JhbEVycm9yKGVyciwgcmVzKVxuICAgICAgaWYgKG9wdGlvbnMub25FcnJvcikgb3B0aW9ucy5vbkVycm9yKGVyciwgcmVzKVxuICAgICAgcmV0dXJuIHJlamVjdChlcnIpXG4gICAgfVxuXG4gICAgLy8gaGFuZGxlIGpzb24gcmVzcG9uc2VzXG4gICAgZGlzcGF0Y2goe1xuICAgICAgdHlwZTogJ3RhaG9lLnN1Y2Nlc3MnLFxuICAgICAgbWV0YTogb3B0aW9ucyxcbiAgICAgIHBheWxvYWQ6IHtcbiAgICAgICAgcmF3OiByZXMuYm9keSxcbiAgICAgICAgdGV4dDogcmVzLnRleHRcbiAgICAgIH1cbiAgICB9KVxuICAgIGlmIChvcHRpb25zLm9uUmVzcG9uc2UpIG9wdGlvbnMub25SZXNwb25zZShyZXMpXG4gICAgcmVzb2x2ZShyZXMpXG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgYXN5bmMgKHsgb3B0aW9ucywgZGlzcGF0Y2ggfSkgPT4ge1xuICBkaXNwYXRjaCh7XG4gICAgdHlwZTogJ3RhaG9lLnJlcXVlc3QnLFxuICAgIHBheWxvYWQ6IG9wdGlvbnNcbiAgfSlcblxuICBpZiAob3B0aW9ucy50YWlsKSB7XG4gICAgcmV0dXJuIGNyZWF0ZUV2ZW50U291cmNlKHsgb3B0aW9ucywgZGlzcGF0Y2ggfSlcbiAgfVxuXG4gIGNvbnN0IHJlcSA9IHJlcXVlc3Rbb3B0aW9ucy5tZXRob2QudG9Mb3dlckNhc2UoKV0ob3B0aW9ucy5lbmRwb2ludClcbiAgaWYgKG9wdGlvbnMuaGVhZGVycykge1xuICAgIHJlcS5zZXQob3B0aW9ucy5oZWFkZXJzKVxuICB9XG4gIGlmIChvcHRpb25zLnF1ZXJ5KSB7XG4gICAgcmVxLnF1ZXJ5KHR5cGVvZiBvcHRpb25zLnF1ZXJ5ID09PSAnc3RyaW5nJ1xuICAgICAgPyBvcHRpb25zLnF1ZXJ5XG4gICAgICA6IHFzLnN0cmluZ2lmeShvcHRpb25zLnF1ZXJ5LCB7IHN0cmljdE51bGxIYW5kbGluZzogdHJ1ZSB9KSlcbiAgfVxuICBpZiAob3B0aW9ucy5ib2R5KSB7XG4gICAgcmVxLnNlbmQob3B0aW9ucy5ib2R5KVxuICB9XG4gIGlmIChvcHRpb25zLndpdGhDcmVkZW50aWFscykge1xuICAgIHJlcS53aXRoQ3JlZGVudGlhbHMoKVxuICB9XG5cbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICByZXEuZW5kKGNyZWF0ZVJlc3BvbnNlSGFuZGxlcih7XG4gICAgICBvcHRpb25zLFxuICAgICAgZGlzcGF0Y2gsXG4gICAgICByZWplY3QsXG4gICAgICByZXNvbHZlXG4gICAgfSkpXG4gIH0pXG59XG4iXX0= -------------------------------------------------------------------------------- /dist/reducers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.api = undefined; 7 | 8 | var _reduxActions = require('redux-actions'); 9 | 10 | var _immutable = require('immutable'); 11 | 12 | var toImmutable = function toImmutable(v) { 13 | return (0, _immutable.fromJS)(v, function (key, value) { 14 | return _immutable.Iterable.isIndexed(value) ? value.toList() : value.toOrderedMap(); 15 | }); 16 | }; 17 | 18 | var initialState = (0, _immutable.OrderedMap)({ 19 | subsets: (0, _immutable.OrderedMap)() 20 | }); 21 | 22 | // subset state 23 | var createSubset = function createSubset(state, _ref) { 24 | var _ref$payload = _ref.payload, 25 | subset = _ref$payload.subset, 26 | fresh = _ref$payload.fresh; 27 | 28 | if (!subset) return state; 29 | var path = ['subsets', subset]; 30 | if (!fresh && state.hasIn(path)) return state; 31 | var record = (0, _immutable.OrderedMap)({ 32 | id: subset, 33 | pending: true 34 | }); 35 | return state.setIn(path, record); 36 | }; 37 | 38 | var setSubsetData = function setSubsetData(state, _ref2) { 39 | var subset = _ref2.meta.subset, 40 | _ref2$payload = _ref2.payload, 41 | raw = _ref2$payload.raw, 42 | text = _ref2$payload.text; 43 | 44 | if (!subset) return state; 45 | var path = ['subsets', subset]; 46 | if (!state.hasIn(path)) return state; // subset doesnt exist 47 | return state.updateIn(path, function (subset) { 48 | return subset.set('data', toImmutable(raw)).set('text', text).set('pending', false).set('error', null); 49 | }); 50 | }; 51 | 52 | var setSubsetError = function setSubsetError(state, _ref3) { 53 | var subset = _ref3.meta.subset, 54 | payload = _ref3.payload; 55 | 56 | if (!subset) return state; 57 | var path = ['subsets', subset]; 58 | if (!state.hasIn(path)) return state; // subset doesnt exist 59 | return state.updateIn(path, function (subset) { 60 | return subset.delete('data').delete('text').set('error', payload).set('pending', false); 61 | }); 62 | }; 63 | 64 | var setSubsetOpen = function setSubsetOpen(state, _ref4) { 65 | var _ref4$meta = _ref4.meta, 66 | subset = _ref4$meta.subset, 67 | collection = _ref4$meta.collection; 68 | 69 | if (!subset) return state; 70 | var path = ['subsets', subset]; 71 | if (!state.hasIn(path)) return state; // subset doesnt exist 72 | return state.updateIn(path, function (subset) { 73 | return subset.set('pending', false).set('data', collection ? (0, _immutable.List)() : (0, _immutable.OrderedMap)()); 74 | }); 75 | }; 76 | 77 | var insertSubsetDataItem = function insertSubsetDataItem(state, _ref5) { 78 | var _ref5$meta = _ref5.meta, 79 | subset = _ref5$meta.subset, 80 | collection = _ref5$meta.collection, 81 | raw = _ref5.payload.raw; 82 | 83 | if (!subset) return state; 84 | var path = ['subsets', subset]; 85 | if (!state.hasIn(path)) return state; // subset doesnt exist 86 | var newData = toImmutable(raw); 87 | return state.updateIn(path, function (subset) { 88 | return subset.set('pending', false).update('data', function (data) { 89 | // first event, initialize the value 90 | if (data == null && collection) return (0, _immutable.List)([newData]); 91 | // value exists, either push or replace 92 | return collection ? data.push(newData) : newData; 93 | }); 94 | }); 95 | }; 96 | 97 | var updateSubsetDataItem = function updateSubsetDataItem(state, _ref6) { 98 | var _ref6$meta = _ref6.meta, 99 | subset = _ref6$meta.subset, 100 | collection = _ref6$meta.collection, 101 | raw = _ref6.payload.raw; 102 | 103 | if (!subset) return state; 104 | var path = ['subsets', subset]; 105 | if (!state.hasIn(path)) return state; // subset doesnt exist 106 | var dataPath = [].concat(path, ['data']); 107 | if (!state.hasIn(dataPath)) return state; // subset has no data to update 108 | var next = toImmutable(raw.next); 109 | return state.updateIn(dataPath, function (data) { 110 | // not a list item, replace with new value 111 | if (!collection) return next; 112 | 113 | // list item, find the index and do the update 114 | var idx = data.findIndex(function (i) { 115 | return i.get('id') === raw.prev.id; 116 | }); 117 | if (idx == null) return data; // not our data? 118 | return data.set(idx, next); 119 | }); 120 | }; 121 | var deleteSubsetDataItem = function deleteSubsetDataItem(state, _ref7) { 122 | var _ref7$meta = _ref7.meta, 123 | subset = _ref7$meta.subset, 124 | collection = _ref7$meta.collection, 125 | raw = _ref7.payload.raw; 126 | 127 | if (!subset) return state; 128 | var path = ['subsets', subset]; 129 | if (!state.hasIn(path)) return state; // subset doesnt exist 130 | var dataPath = [].concat(path, ['data']); 131 | if (!state.hasIn(dataPath)) return state; // subset has no data to update 132 | 133 | // not a list, just wipe the val 134 | if (!collection) { 135 | return state.removeIn(dataPath); 136 | } 137 | // item in a list, remove the specific item 138 | return state.updateIn(dataPath, function (data) { 139 | var idx = data.findIndex(function (i) { 140 | return i.get('id') === raw.id; 141 | }); 142 | if (idx == null) return data; // not our data? 143 | return data.delete(idx); 144 | }); 145 | }; 146 | 147 | // exported actions 148 | var api = exports.api = (0, _reduxActions.handleActions)({ 149 | 'tahoe.request': createSubset, 150 | 'tahoe.failure': setSubsetError, 151 | 'tahoe.success': setSubsetData, 152 | 'tahoe.tail.open': setSubsetOpen, 153 | 'tahoe.tail.insert': insertSubsetDataItem, 154 | 'tahoe.tail.update': updateSubsetDataItem, 155 | 'tahoe.tail.delete': deleteSubsetDataItem 156 | }, initialState); 157 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9yZWR1Y2Vycy5qcyJdLCJuYW1lcyI6WyJ0b0ltbXV0YWJsZSIsInYiLCJrZXkiLCJ2YWx1ZSIsIkl0ZXJhYmxlIiwiaXNJbmRleGVkIiwidG9MaXN0IiwidG9PcmRlcmVkTWFwIiwiaW5pdGlhbFN0YXRlIiwic3Vic2V0cyIsImNyZWF0ZVN1YnNldCIsInN0YXRlIiwicGF5bG9hZCIsInN1YnNldCIsImZyZXNoIiwicGF0aCIsImhhc0luIiwicmVjb3JkIiwiaWQiLCJwZW5kaW5nIiwic2V0SW4iLCJzZXRTdWJzZXREYXRhIiwibWV0YSIsInJhdyIsInRleHQiLCJ1cGRhdGVJbiIsInNldCIsInNldFN1YnNldEVycm9yIiwiZGVsZXRlIiwic2V0U3Vic2V0T3BlbiIsImNvbGxlY3Rpb24iLCJpbnNlcnRTdWJzZXREYXRhSXRlbSIsIm5ld0RhdGEiLCJ1cGRhdGUiLCJkYXRhIiwicHVzaCIsInVwZGF0ZVN1YnNldERhdGFJdGVtIiwiZGF0YVBhdGgiLCJuZXh0IiwiaWR4IiwiZmluZEluZGV4IiwiaSIsImdldCIsInByZXYiLCJkZWxldGVTdWJzZXREYXRhSXRlbSIsInJlbW92ZUluIiwiYXBpIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBQUE7O0FBQ0E7O0FBRUEsSUFBTUEsY0FBYyxTQUFkQSxXQUFjLENBQUNDLENBQUQ7QUFBQSxTQUNsQix1QkFBT0EsQ0FBUCxFQUFVLFVBQUNDLEdBQUQsRUFBTUMsS0FBTjtBQUFBLFdBQ1JDLG9CQUFTQyxTQUFULENBQW1CRixLQUFuQixJQUE0QkEsTUFBTUcsTUFBTixFQUE1QixHQUE2Q0gsTUFBTUksWUFBTixFQURyQztBQUFBLEdBQVYsQ0FEa0I7QUFBQSxDQUFwQjs7QUFLQSxJQUFNQyxlQUFlLDJCQUFXO0FBQzlCQyxXQUFTO0FBRHFCLENBQVgsQ0FBckI7O0FBSUE7QUFDQSxJQUFNQyxlQUFlLFNBQWZBLFlBQWUsQ0FBQ0MsS0FBRCxRQUEyQztBQUFBLDBCQUFqQ0MsT0FBaUM7QUFBQSxNQUF0QkMs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LFNBQUYsRUFBYUYsTUFBYixDQUFiO0FBQ0EsTUFBSSxDQUFDRixNQUFNSyxLQUFOLENBQVlELElBQVosQ0FBTCxFQUF3QixPQUFPSixLQUFQLENBSGtFLENBR3JEO0FBQ3JDLE1BQU0wQixxQkFBZ0J0QixJQUFoQixHQUFzQixNQUF0QixFQUFOO0FBQ0EsTUFBSSxDQUFDSixNQUFNSyxLQUFOLENBQVlxQixRQUFaLENBQUwsRUFBNEIsT0FBTzFCLEtBQVAsQ0FMOEQsQ0FLakQ7O0FBRXpDO0FBQ0EsTUFBSSxDQUFDbUIsVUFBTCxFQUFpQjtBQUNmLFdBQU9uQixNQUFNa0MsUUFBTixDQUFlUixRQUFmLENBQVA7QUFDRDtBQUNEO0FBQ0EsU0FBTzFCLE1BQU1jLFFBQU4sQ0FBZVksUUFBZixFQUF5QixVQUFDSCxJQUFELEVBQVU7QUFDeEMsUUFBTUssTUFBTUwsS0FBS00sU0FBTCxDQUFlLFVBQUNDLENBQUQ7QUFBQSxhQUFPQSxFQUFFQyxHQUFGLENBQU0sSUFBTixNQUFnQm5CLElBQUlMLEVBQTNCO0FBQUEsS0FBZixDQUFaO0FBQ0EsUUFBSXFCLE9BQU8sSUFBWCxFQUFpQixPQUFPTCxJQUFQLENBRnVCLENBRVg7QUFDN0IsV0FBT0EsS0FBS04sTUFBTCxDQUFZVyxHQUFaLENBQVA7QUFDRCxHQUpNLENBQVA7QUFLRCxDQWpCRDs7QUFtQkE7QUFDTyxJQUFNTyxvQkFBTSxpQ0FBYztBQUMvQixtQkFBaUJwQyxZQURjO0FBRS9CLG1CQUFpQmlCLGNBRmM7QUFHL0IsbUJBQWlCTixhQUhjO0FBSS9CLHFCQUFtQlEsYUFKWTtBQUsvQix1QkFBcUJFLG9CQUxVO0FBTS9CLHVCQUFxQkssb0JBTlU7QUFPL0IsdUJBQXFCUTtBQVBVLENBQWQsRUFRaEJwQyxZQVJnQixDQUFaIiwiZmlsZSI6InJlZHVjZXJzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaGFuZGxlQWN0aW9ucyB9IGZyb20gJ3JlZHV4LWFjdGlvbnMnXG5pbXBvcnQgeyBPcmRlcmVkTWFwLCBMaXN0LCBmcm9tSlMsIEl0ZXJhYmxlIH0gZnJvbSAnaW1tdXRhYmxlJ1xuXG5jb25zdCB0b0ltbXV0YWJsZSA9ICh2KSA9PlxuICBmcm9tSlModiwgKGtleSwgdmFsdWUpID0+XG4gICAgSXRlcmFibGUuaXNJbmRleGVkKHZhbHVlKSA/IHZhbHVlLnRvTGlzdCgpIDogdmFsdWUudG9PcmRlcmVkTWFwKClcbiAgKVxuXG5jb25zdCBpbml0aWFsU3RhdGUgPSBPcmRlcmVkTWFwKHtcbiAgc3Vic2V0czogT3JkZXJlZE1hcCgpXG59KVxuXG4vLyBzdWJzZXQgc3RhdGVcbmNvbnN0IGNyZWF0ZVN1YnNldCA9IChzdGF0ZSwgeyBwYXlsb2FkOiB7IHN1YnNldCwgZnJlc2ggfSB9KSA9PiB7XG4gIGlmICghc3Vic2V0KSByZXR1cm4gc3RhdGVcbiAgY29uc3QgcGF0aCA9IFsgJ3N1YnNldHMnLCBzdWJzZXQgXVxuICBpZiAoIWZyZXNoICYmIHN0YXRlLmhhc0luKHBhdGgpKSByZXR1cm4gc3RhdGVcbiAgY29uc3QgcmVjb3JkID0gT3JkZXJlZE1hcCh7XG4gICAgaWQ6IHN1YnNldCxcbiAgICBwZW5kaW5nOiB0cnVlXG4gIH0pXG4gIHJldHVybiBzdGF0ZS5zZXRJbihwYXRoLCByZWNvcmQpXG59XG5cbmNvbnN0IHNldFN1YnNldERhdGEgPSAoc3RhdGUsIHsgbWV0YTogeyBzdWJzZXQgfSwgcGF5bG9hZDogeyByYXcsIHRleHQgfSB9KSA9PiB7XG4gIGlmICghc3Vic2V0KSByZXR1cm4gc3RhdGVcbiAgY29uc3QgcGF0aCA9IFsgJ3N1YnNldHMnLCBzdWJzZXQgXVxuICBpZiAoIXN0YXRlLmhhc0luKHBhdGgpKSByZXR1cm4gc3RhdGUgLy8gc3Vic2V0IGRvZXNudCBleGlzdFxuICByZXR1cm4gc3RhdGUudXBkYXRlSW4ocGF0aCwgKHN1YnNldCkgPT5cbiAgICBzdWJzZXRcbiAgICAgIC5zZXQoJ2RhdGEnLCB0b0ltbXV0YWJsZShyYXcpKVxuICAgICAgLnNldCgndGV4dCcsIHRleHQpXG4gICAgICAuc2V0KCdwZW5kaW5nJywgZmFsc2UpXG4gICAgICAuc2V0KCdlcnJvcicsIG51bGwpXG4gIClcbn1cblxuY29uc3Qgc2V0U3Vic2V0RXJyb3IgPSAoc3RhdGUsIHsgbWV0YTogeyBzdWJzZXQgfSwgcGF5bG9hZCB9KSA9PiB7XG4gIGlmICghc3Vic2V0KSByZXR1cm4gc3RhdGVcbiAgY29uc3QgcGF0aCA9IFsgJ3N1YnNldHMnLCBzdWJzZXQgXVxuICBpZiAoIXN0YXRlLmhhc0luKHBhdGgpKSByZXR1cm4gc3RhdGUgLy8gc3Vic2V0IGRvZXNudCBleGlzdFxuICByZXR1cm4gc3RhdGUudXBkYXRlSW4ocGF0aCwgKHN1YnNldCkgPT5cbiAgICBzdWJzZXRcbiAgICAgIC5kZWxldGUoJ2RhdGEnKVxuICAgICAgLmRlbGV0ZSgndGV4dCcpXG4gICAgICAuc2V0KCdlcnJvcicsIHBheWxvYWQpXG4gICAgICAuc2V0KCdwZW5kaW5nJywgZmFsc2UpXG4gIClcbn1cblxuY29uc3Qgc2V0U3Vic2V0T3BlbiA9IChzdGF0ZSwgeyBtZXRhOiB7IHN1YnNldCwgY29sbGVjdGlvbiB9IH0pID0+IHtcbiAgaWYgKCFzdWJzZXQpIHJldHVybiBzdGF0ZVxuICBjb25zdCBwYXRoID0gWyAnc3Vic2V0cycsIHN1YnNldCBdXG4gIGlmICghc3RhdGUuaGFzSW4ocGF0aCkpIHJldHVybiBzdGF0ZSAvLyBzdWJzZXQgZG9lc250IGV4aXN0XG4gIHJldHVybiBzdGF0ZS51cGRhdGVJbihwYXRoLCAoc3Vic2V0KSA9PlxuICAgIHN1YnNldFxuICAgICAgLnNldCgncGVuZGluZycsIGZhbHNlKVxuICAgICAgLnNldCgnZGF0YScsIGNvbGxlY3Rpb24gPyBMaXN0KCkgOiBPcmRlcmVkTWFwKCkpXG4gIClcbn1cblxuY29uc3QgaW5zZXJ0U3Vic2V0RGF0YUl0ZW0gPSAoc3RhdGUsIHsgbWV0YTogeyBzdWJzZXQsIGNvbGxlY3Rpb24gfSwgcGF5bG9hZDogeyByYXcgfSB9KSA9PiB7XG4gIGlmICghc3Vic2V0KSByZXR1cm4gc3RhdGVcbiAgY29uc3QgcGF0aCA9IFsgJ3N1YnNldHMnLCBzdWJzZXQgXVxuICBpZiAoIXN0YXRlLmhhc0luKHBhdGgpKSByZXR1cm4gc3RhdGUgLy8gc3Vic2V0IGRvZXNudCBleGlzdFxuICBjb25zdCBuZXdEYXRhID0gdG9JbW11dGFibGUocmF3KVxuICByZXR1cm4gc3RhdGUudXBkYXRlSW4ocGF0aCwgKHN1YnNldCkgPT5cbiAgICBzdWJzZXRcbiAgICAgIC5zZXQoJ3BlbmRpbmcnLCBmYWxzZSlcbiAgICAgIC51cGRhdGUoJ2RhdGEnLCAoZGF0YSkgPT4ge1xuICAgICAgICAvLyBmaXJzdCBldmVudCwgaW5pdGlhbGl6ZSB0aGUgdmFsdWVcbiAgICAgICAgaWYgKGRhdGEgPT0gbnVsbCAmJiBjb2xsZWN0aW9uKSByZXR1cm4gTGlzdChbIG5ld0RhdGEgXSlcbiAgICAgICAgLy8gdmFsdWUgZXhpc3RzLCBlaXRoZXIgcHVzaCBvciByZXBsYWNlXG4gICAgICAgIHJldHVybiBjb2xsZWN0aW9uID8gZGF0YS5wdXNoKG5ld0RhdGEpIDogbmV3RGF0YVxuICAgICAgfSlcbiAgKVxufVxuXG5jb25zdCB1cGRhdGVTdWJzZXREYXRhSXRlbSA9IChzdGF0ZSwgeyBtZXRhOiB7IHN1YnNldCwgY29sbGVjdGlvbiB9LCBwYXlsb2FkOiB7IHJhdyB9IH0pID0+IHtcbiAgaWYgKCFzdWJzZXQpIHJldHVybiBzdGF0ZVxuICBjb25zdCBwYXRoID0gWyAnc3Vic2V0cycsIHN1YnNldCBdXG4gIGlmICghc3RhdGUuaGFzSW4ocGF0aCkpIHJldHVybiBzdGF0ZSAvLyBzdWJzZXQgZG9lc250IGV4aXN0XG4gIGNvbnN0IGRhdGFQYXRoID0gWyAuLi5wYXRoLCAnZGF0YScgXVxuICBpZiAoIXN0YXRlLmhhc0luKGRhdGFQYXRoKSkgcmV0dXJuIHN0YXRlIC8vIHN1YnNldCBoYXMgbm8gZGF0YSB0byB1cGRhdGVcbiAgY29uc3QgbmV4dCA9IHRvSW1tdXRhYmxlKHJhdy5uZXh0KVxuICByZXR1cm4gc3RhdGUudXBkYXRlSW4oZGF0YVBhdGgsIChkYXRhKSA9PiB7XG4gICAgLy8gbm90IGEgbGlzdCBpdGVtLCByZXBsYWNlIHdpdGggbmV3IHZhbHVlXG4gICAgaWYgKCFjb2xsZWN0aW9uKSByZXR1cm4gbmV4dFxuXG4gICAgLy8gbGlzdCBpdGVtLCBmaW5kIHRoZSBpbmRleCBhbmQgZG8gdGhlIHVwZGF0ZVxuICAgIGNvbnN0IGlkeCA9IGRhdGEuZmluZEluZGV4KChpKSA9PiBpLmdldCgnaWQnKSA9PT0gcmF3LnByZXYuaWQpXG4gICAgaWYgKGlkeCA9PSBudWxsKSByZXR1cm4gZGF0YSAvLyBub3Qgb3VyIGRhdGE/XG4gICAgcmV0dXJuIGRhdGEuc2V0KGlkeCwgbmV4dClcbiAgfSlcbn1cbmNvbnN0IGRlbGV0ZVN1YnNldERhdGFJdGVtID0gKHN0YXRlLCB7IG1ldGE6IHsgc3Vic2V0LCBjb2xsZWN0aW9uIH0sIHBheWxvYWQ6IHsgcmF3IH0gfSkgPT4ge1xuICBpZiAoIXN1YnNldCkgcmV0dXJuIHN0YXRlXG4gIGNvbnN0IHBhdGggPSBbICdzdWJzZXRzJywgc3Vic2V0IF1cbiAgaWYgKCFzdGF0ZS5oYXNJbihwYXRoKSkgcmV0dXJuIHN0YXRlIC8vIHN1YnNldCBkb2VzbnQgZXhpc3RcbiAgY29uc3QgZGF0YVBhdGggPSBbIC4uLnBhdGgsICdkYXRhJyBdXG4gIGlmICghc3RhdGUuaGFzSW4oZGF0YVBhdGgpKSByZXR1cm4gc3RhdGUgLy8gc3Vic2V0IGhhcyBubyBkYXRhIHRvIHVwZGF0ZVxuXG4gIC8vIG5vdCBhIGxpc3QsIGp1c3Qgd2lwZSB0aGUgdmFsXG4gIGlmICghY29sbGVjdGlvbikge1xuICAgIHJldHVybiBzdGF0ZS5yZW1vdmVJbihkYXRhUGF0aClcbiAgfVxuICAvLyBpdGVtIGluIGEgbGlzdCwgcmVtb3ZlIHRoZSBzcGVjaWZpYyBpdGVtXG4gIHJldHVybiBzdGF0ZS51cGRhdGVJbihkYXRhUGF0aCwgKGRhdGEpID0+IHtcbiAgICBjb25zdCBpZHggPSBkYXRhLmZpbmRJbmRleCgoaSkgPT4gaS5nZXQoJ2lkJykgPT09IHJhdy5pZClcbiAgICBpZiAoaWR4ID09IG51bGwpIHJldHVybiBkYXRhIC8vIG5vdCBvdXIgZGF0YT9cbiAgICByZXR1cm4gZGF0YS5kZWxldGUoaWR4KVxuICB9KVxufVxuXG4vLyBleHBvcnRlZCBhY3Rpb25zXG5leHBvcnQgY29uc3QgYXBpID0gaGFuZGxlQWN0aW9ucyh7XG4gICd0YWhvZS5yZXF1ZXN0JzogY3JlYXRlU3Vic2V0LFxuICAndGFob2UuZmFpbHVyZSc6IHNldFN1YnNldEVycm9yLFxuICAndGFob2Uuc3VjY2Vzcyc6IHNldFN1YnNldERhdGEsXG4gICd0YWhvZS50YWlsLm9wZW4nOiBzZXRTdWJzZXRPcGVuLFxuICAndGFob2UudGFpbC5pbnNlcnQnOiBpbnNlcnRTdWJzZXREYXRhSXRlbSxcbiAgJ3RhaG9lLnRhaWwudXBkYXRlJzogdXBkYXRlU3Vic2V0RGF0YUl0ZW0sXG4gICd0YWhvZS50YWlsLmRlbGV0ZSc6IGRlbGV0ZVN1YnNldERhdGFJdGVtXG59LCBpbml0aWFsU3RhdGUpXG4iXX0= -------------------------------------------------------------------------------- /docs/Introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Test page 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tahoe", 3 | "version": "1.1.1", 4 | "description": "Dead-simple API/EventSource actions for Redux", 5 | "main": "dist/index.js", 6 | "keywords": [ 7 | "redux", 8 | "react", 9 | "immutable", 10 | "api", 11 | "rest", 12 | "http", 13 | "request", 14 | "resource", 15 | "actions", 16 | "shasta", 17 | "shastajs", 18 | "shastaplugin" 19 | ], 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/shastajs/tahoe.git" 23 | }, 24 | "author": "Contra (http://contra.io)", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/shastajs/tahoe/issues" 28 | }, 29 | "homepage": "https://github.com/shastajs/tahoe#readme", 30 | "files": [ 31 | "dist" 32 | ], 33 | "scripts": { 34 | "preversion": "npm run clean && npm run build", 35 | "build": "babel src --out-dir dist", 36 | "clean": "rimraf dist", 37 | "lint": "eslint src", 38 | "test": "npm run-script lint && npm run test:node && npm run test:browser", 39 | "test:node": "mocha --compilers js:babel-register --recursive --reporter spec", 40 | "test:browser": "mochify --transform babelify --recursive --reporter spec" 41 | }, 42 | "devDependencies": { 43 | "babel-cli": "^6.26.0", 44 | "babel-core": "^6.26.0", 45 | "babel-eslint": "^8.2.5", 46 | "babel-loader": "^7.1.3", 47 | "babel-plugin-add-module-exports": "^0.2.1", 48 | "babel-plugin-transform-runtime": "^6.4.3", 49 | "babel-preset-es2015": "^6.3.13", 50 | "babel-preset-es2015-loose": "^8.0.0", 51 | "babel-preset-react": "^6.3.13", 52 | "babel-preset-stage-0": "^6.3.13", 53 | "babel-register": "^6.26.0", 54 | "babelify": "^8.0.0", 55 | "eslint": "^4.18.1", 56 | "eslint-cli": "^1.1.1", 57 | "eslint-config-rackt": "^1.1.1", 58 | "eslint-plugin-react": "^7.10.0", 59 | "mocha": "^5.0.0", 60 | "mochify": "^5.0.0", 61 | "rimraf": "^2.6.2", 62 | "should": "^13.2.1" 63 | }, 64 | "babel": { 65 | "sourceMaps": "inline", 66 | "presets": [ 67 | "es2015", 68 | "react", 69 | "stage-0" 70 | ], 71 | "plugins": [ 72 | "transform-runtime", 73 | "add-module-exports" 74 | ] 75 | }, 76 | "eslintConfig": { 77 | "parser": "babel-eslint", 78 | "extends": "rackt", 79 | "plugins": [ 80 | "react" 81 | ], 82 | "env": { 83 | "browser": true, 84 | "node": true, 85 | "es6": true 86 | }, 87 | "globals": { 88 | "__DEV__": true, 89 | "__PROD__": true, 90 | "__INITIAL_STATE__": true 91 | }, 92 | "rules": { 93 | "semi": [ 94 | 2, 95 | "never" 96 | ] 97 | } 98 | }, 99 | "dependencies": { 100 | "babel-runtime": "^6.26.0", 101 | "immutable": "^3.8.2", 102 | "lodash.mapvalues": "^4.6.0", 103 | "lodash.merge": "^4.6.1", 104 | "qs": "^6.5.1", 105 | "redux-actions": "^2.2.1", 106 | "superagent": "^3.8.2", 107 | "url": "^0.11.0", 108 | "url-join": "^4.0.0" 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import createAction from './lib/createAction' 2 | import * as reducers from './reducers' 3 | 4 | export default { 5 | createAction, 6 | reducers: reducers 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/combineUrl.js: -------------------------------------------------------------------------------- 1 | import url from 'url' 2 | import qs from 'qs' 3 | 4 | export default (endpoint, query) => { 5 | const parsed = url.parse(endpoint) 6 | 7 | const q = qs.stringify({ 8 | ...qs.parse(parsed.query, { strictNullHandling: true }), 9 | ...query 10 | }, { strictNullHandling: true }) 11 | 12 | return url.format({ 13 | protocol: parsed.protocol, 14 | auth: parsed.auth, 15 | port: parsed.port, 16 | host: parsed.host, 17 | pathname: parsed.pathname, 18 | search: q 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/createAction.js: -------------------------------------------------------------------------------- 1 | import mapValues from 'lodash.mapvalues' 2 | import merge from 'lodash.merge' 3 | import sendRequest from './sendRequest' 4 | 5 | const reserved = [ 6 | 'onResponse', 7 | 'onError', 8 | 'onGlobalError' 9 | ] 10 | const result = (fn, arg) => typeof fn === 'function' ? fn(arg) : fn 11 | 12 | // TODO:0 check entities cache in store and dont fetch if we have it already 13 | 14 | /* 15 | app must have redux-thunk installed 16 | possible options: 17 | 18 | - subset (optional)(string) 19 | - tail (default false)(boolean) 20 | - method (required)(get, post, put, delete, or patch) 21 | - params (object) 22 | - endpoint (required)(url tring) 23 | - collection (default false)(boolean) 24 | - fresh (default to false)(boolean) 25 | 26 | all options can either be a value, or a function that returns a value. 27 | if you define a function, it will receive options.params as an argument 28 | */ 29 | 30 | // merge our multitude of option objects together 31 | // defaults = options defined in createAction 32 | // opt = options specified in action creator 33 | const isReserved = (k) => reserved.indexOf(k) !== -1 34 | 35 | const resolveFunctions = (o, params) => 36 | mapValues(o, (v, k) => 37 | isReserved(k) ? v : result(v, params) 38 | ) 39 | 40 | export const mergeOptions = (defaults, opt) => { 41 | const defaultParams = defaults.params ? result(defaults.params) : {} 42 | const optParams = opt.params ? result(opt.params) : {} 43 | const params = merge({}, optParams, defaultParams) 44 | return merge({}, resolveFunctions(opt, params), resolveFunctions(defaults, params)) 45 | } 46 | 47 | export default (defaults = {}) => { 48 | const nfn = (opt = {}) => { 49 | const options = mergeOptions(defaults, opt) 50 | if (!options.method) throw new Error('Missing method') 51 | if (!options.endpoint) throw new Error('Missing endpoint') 52 | const fn = async (dispatch) => sendRequest({ options, dispatch }) 53 | fn.options = options 54 | return fn 55 | } 56 | nfn.options = defaults 57 | return nfn 58 | } 59 | -------------------------------------------------------------------------------- /src/lib/createEventSource.js: -------------------------------------------------------------------------------- 1 | import combineUrl from './combineUrl' 2 | import handlers from './eventHandlers' 3 | 4 | const tryParse = ({ data, options, dispatch }) => { 5 | try { 6 | return JSON.parse(data) 7 | } catch (err) { 8 | dispatch({ 9 | type: 'tahoe.failure', 10 | meta: options, 11 | payload: err 12 | }) 13 | } 14 | } 15 | 16 | export default async ({ options, dispatch }) => { 17 | const finalUrl = combineUrl(options.endpoint, options.query) 18 | const src = new EventSource(finalUrl, { withCredentials: options.withCredentials }) 19 | 20 | // wire up listeners n shiz 21 | Object.keys(handlers).forEach((eventName) => { 22 | const handler = handlers[eventName] 23 | src.addEventListener(eventName, ({ data }) => { 24 | const parsed = data && tryParse({ options, dispatch, data }) 25 | if (data && typeof parsed === 'undefined') return 26 | handler({ options, dispatch, data: parsed }) 27 | }, false) 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /src/lib/eventHandlers.js: -------------------------------------------------------------------------------- 1 | 2 | const handlers = {} 3 | handlers.open = ({ options, dispatch }) => 4 | dispatch({ 5 | type: 'tahoe.tail.open', 6 | meta: options 7 | }) 8 | 9 | handlers.insert = ({ options, dispatch, data: { next } }) => 10 | dispatch({ 11 | type: 'tahoe.tail.insert', 12 | meta: options, 13 | payload: { 14 | raw: next 15 | } 16 | }) 17 | 18 | handlers.update = ({ options, dispatch, data: { prev, next } }) => 19 | dispatch({ 20 | type: 'tahoe.tail.update', 21 | meta: options, 22 | payload: { 23 | raw: { 24 | prev: prev, 25 | next: next 26 | } 27 | } 28 | }) 29 | 30 | 31 | handlers.delete = ({ options, dispatch, data: { prev } }) => 32 | dispatch({ 33 | type: 'tahoe.tail.delete', 34 | meta: options, 35 | payload: { 36 | raw: prev 37 | } 38 | }) 39 | 40 | export default handlers 41 | -------------------------------------------------------------------------------- /src/lib/sendRequest.js: -------------------------------------------------------------------------------- 1 | import request from 'superagent' 2 | import createEventSource from './createEventSource' 3 | import qs from 'qs' 4 | 5 | const createResponseHandler = ({ options, dispatch, reject, resolve }) => { 6 | const debug = `${options.method.toUpperCase()} ${options.endpoint}` 7 | return (err, res) => { 8 | if (!res && !err) { 9 | err = new Error(`Connection failed: ${debug}`) 10 | } 11 | if (err) { 12 | err.res = res 13 | dispatch({ 14 | type: 'tahoe.failure', 15 | meta: options, 16 | payload: err 17 | }) 18 | if (options.onGlobalError) options.onGlobalError(err, res) 19 | if (options.onError) options.onError(err, res) 20 | return reject(err) 21 | } 22 | 23 | // handle json responses 24 | dispatch({ 25 | type: 'tahoe.success', 26 | meta: options, 27 | payload: { 28 | raw: res.body, 29 | text: res.text 30 | } 31 | }) 32 | if (options.onResponse) options.onResponse(res) 33 | resolve(res) 34 | } 35 | } 36 | 37 | export default async ({ options, dispatch }) => { 38 | dispatch({ 39 | type: 'tahoe.request', 40 | payload: options 41 | }) 42 | 43 | if (options.tail) { 44 | return createEventSource({ options, dispatch }) 45 | } 46 | 47 | const req = request[options.method.toLowerCase()](options.endpoint) 48 | if (options.headers) { 49 | req.set(options.headers) 50 | } 51 | if (options.query) { 52 | req.query(typeof options.query === 'string' 53 | ? options.query 54 | : qs.stringify(options.query, { strictNullHandling: true })) 55 | } 56 | if (options.body) { 57 | req.send(options.body) 58 | } 59 | if (options.withCredentials) { 60 | req.withCredentials() 61 | } 62 | 63 | return new Promise((resolve, reject) => { 64 | req.end(createResponseHandler({ 65 | options, 66 | dispatch, 67 | reject, 68 | resolve 69 | })) 70 | }) 71 | } 72 | -------------------------------------------------------------------------------- /src/reducers.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | import { OrderedMap, List, fromJS, Iterable } from 'immutable' 3 | 4 | const toImmutable = (v) => 5 | fromJS(v, (key, value) => 6 | Iterable.isIndexed(value) ? value.toList() : value.toOrderedMap() 7 | ) 8 | 9 | const initialState = OrderedMap({ 10 | subsets: OrderedMap() 11 | }) 12 | 13 | // subset state 14 | const createSubset = (state, { payload: { subset, fresh } }) => { 15 | if (!subset) return state 16 | const path = [ 'subsets', subset ] 17 | if (!fresh && state.hasIn(path)) return state 18 | const record = OrderedMap({ 19 | id: subset, 20 | pending: true 21 | }) 22 | return state.setIn(path, record) 23 | } 24 | 25 | const setSubsetData = (state, { meta: { subset }, payload: { raw, text } }) => { 26 | if (!subset) return state 27 | const path = [ 'subsets', subset ] 28 | if (!state.hasIn(path)) return state // subset doesnt exist 29 | return state.updateIn(path, (subset) => 30 | subset 31 | .set('data', toImmutable(raw)) 32 | .set('text', text) 33 | .set('pending', false) 34 | .set('error', null) 35 | ) 36 | } 37 | 38 | const setSubsetError = (state, { meta: { subset }, payload }) => { 39 | if (!subset) return state 40 | const path = [ 'subsets', subset ] 41 | if (!state.hasIn(path)) return state // subset doesnt exist 42 | return state.updateIn(path, (subset) => 43 | subset 44 | .delete('data') 45 | .delete('text') 46 | .set('error', payload) 47 | .set('pending', false) 48 | ) 49 | } 50 | 51 | const setSubsetOpen = (state, { meta: { subset, collection } }) => { 52 | if (!subset) return state 53 | const path = [ 'subsets', subset ] 54 | if (!state.hasIn(path)) return state // subset doesnt exist 55 | return state.updateIn(path, (subset) => 56 | subset 57 | .set('pending', false) 58 | .set('data', collection ? List() : OrderedMap()) 59 | ) 60 | } 61 | 62 | const insertSubsetDataItem = (state, { meta: { subset, collection }, payload: { raw } }) => { 63 | if (!subset) return state 64 | const path = [ 'subsets', subset ] 65 | if (!state.hasIn(path)) return state // subset doesnt exist 66 | const newData = toImmutable(raw) 67 | return state.updateIn(path, (subset) => 68 | subset 69 | .set('pending', false) 70 | .update('data', (data) => { 71 | // first event, initialize the value 72 | if (data == null && collection) return List([ newData ]) 73 | // value exists, either push or replace 74 | return collection ? data.push(newData) : newData 75 | }) 76 | ) 77 | } 78 | 79 | const updateSubsetDataItem = (state, { meta: { subset, collection }, payload: { raw } }) => { 80 | if (!subset) return state 81 | const path = [ 'subsets', subset ] 82 | if (!state.hasIn(path)) return state // subset doesnt exist 83 | const dataPath = [ ...path, 'data' ] 84 | if (!state.hasIn(dataPath)) return state // subset has no data to update 85 | const next = toImmutable(raw.next) 86 | return state.updateIn(dataPath, (data) => { 87 | // not a list item, replace with new value 88 | if (!collection) return next 89 | 90 | // list item, find the index and do the update 91 | const idx = data.findIndex((i) => i.get('id') === raw.prev.id) 92 | if (idx == null) return data // not our data? 93 | return data.set(idx, next) 94 | }) 95 | } 96 | const deleteSubsetDataItem = (state, { meta: { subset, collection }, payload: { raw } }) => { 97 | if (!subset) return state 98 | const path = [ 'subsets', subset ] 99 | if (!state.hasIn(path)) return state // subset doesnt exist 100 | const dataPath = [ ...path, 'data' ] 101 | if (!state.hasIn(dataPath)) return state // subset has no data to update 102 | 103 | // not a list, just wipe the val 104 | if (!collection) { 105 | return state.removeIn(dataPath) 106 | } 107 | // item in a list, remove the specific item 108 | return state.updateIn(dataPath, (data) => { 109 | const idx = data.findIndex((i) => i.get('id') === raw.id) 110 | if (idx == null) return data // not our data? 111 | return data.delete(idx) 112 | }) 113 | } 114 | 115 | // exported actions 116 | export const api = handleActions({ 117 | 'tahoe.request': createSubset, 118 | 'tahoe.failure': setSubsetError, 119 | 'tahoe.success': setSubsetData, 120 | 'tahoe.tail.open': setSubsetOpen, 121 | 'tahoe.tail.insert': insertSubsetDataItem, 122 | 'tahoe.tail.update': updateSubsetDataItem, 123 | 'tahoe.tail.delete': deleteSubsetDataItem 124 | }, initialState) 125 | -------------------------------------------------------------------------------- /test/createAction.js: -------------------------------------------------------------------------------- 1 | /*global it: true, describe: true, beforeEach: true */ 2 | /*eslint no-console: 0*/ 3 | 4 | import { fromJS, Map } from 'immutable' 5 | import should from 'should' 6 | import { createAction } from '../src' 7 | import { mergeOptions } from '../src/lib/createAction' 8 | 9 | describe('createAction', () => { 10 | it('should exist', (done) => { 11 | should.exist(createAction) 12 | done() 13 | }) 14 | describe('mergeOptions', () => { 15 | const opt = { 16 | tail: true, 17 | onResponse: () => 'response', 18 | onError: () => 'error', 19 | method: 'GET', 20 | params: { 21 | string: '/other' 22 | }, 23 | query: { testing: 'abc' } 24 | } 25 | 26 | const defaults = { 27 | tail: false, 28 | collection: false, 29 | endpoint: (params) => `${params.string}/test`, 30 | query: () => ({ test: 123 }) 31 | } 32 | 33 | it('should exist', (done) => { 34 | should.exist(mergeOptions) 35 | done() 36 | }) 37 | it('should apply defaults and convert non reserved functions to values', (done) => { 38 | const result = mergeOptions(opt, defaults) 39 | const expected = fromJS(opt).withMutations((updated) => { 40 | updated.set('endpoint', '/other/test') 41 | updated.set('collection', false) 42 | updated.set('query', Map({ 43 | test: 123, 44 | testing: 'abc' 45 | })) 46 | }) 47 | should(result).be.deepEqual(expected.toJS()) 48 | done() 49 | }) 50 | }) 51 | }) 52 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | /*global it: true, describe: true */ 2 | /*eslint no-console: 0*/ 3 | 4 | import should from 'should' 5 | import lib from '../src' 6 | 7 | describe('lib', () => { 8 | it('should exist', (done) => { 9 | should.exist(lib) 10 | done() 11 | }) 12 | }) 13 | --------------------------------------------------------------------------------