{"_id":"ducks","_rev":"49-b06bc705b9c09c3314190cce500352e1","name":"ducks","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","dist-tags":{"latest":"1.0.2","next":"1.3.2"},"versions":{"0.1.0":{"name":"ducks","version":"0.1.0","description":"Flux impl with DI","author":{"name":"Sergey Kamardin","email":"gobwas@gmail.com","url":"https://github.com/gobwas"},"repository":{"type":"git","url":"https://github.com/gobwas/ducks"},"license":"MIT","keywords":["ducks","flux","di"],"dependencies":{"bussy":"^0.1.0"},"devDependencies":{},"scripts":{"test":"mocha ./test"},"main":"./index.js","gitHead":"ba1475d977716bf835c350cec5f56658aaae2adb","bugs":{"url":"https://github.com/gobwas/ducks/issues"},"homepage":"https://github.com/gobwas/ducks","_id":"ducks@0.1.0","_shasum":"839582cb2db776bf08bb44d8173c3e59924de522","_from":".","_npmVersion":"2.7.4","_nodeVersion":"0.12.2","_npmUser":{"name":"gobwas","email":"gobwas@gmail.com"},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"dist":{"shasum":"839582cb2db776bf08bb44d8173c3e59924de522","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.1.0.tgz","integrity":"sha512-4Hh3VcKOqaYX/TY5IAcoMI07HEqhr2IEHsoS0HV6vqsLGBHFAxGnPt+nNt0J+rVecKm3PdlVlnAhNqBNfySU4g==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEmcWJnhtgWuqntmKoCk2M9yts3iCBfr5mJbPA1gB6cJAiAmowaPJAQNZ3ntt5Mxt0K367kBN3lv6AiYrbJxGyHQJg=="}]},"directories":{},"deprecated":"will be removed soon"},"0.1.1":{"name":"ducks","version":"0.1.1","description":"Flux impl with DI","author":{"name":"Sergey Kamardin","email":"gobwas@gmail.com","url":"https://github.com/gobwas"},"repository":{"type":"git","url":"https://github.com/gobwas/ducks"},"license":"MIT","keywords":["ducks","flux","di"],"dependencies":{"bussy":"^0.1.0"},"devDependencies":{},"peerDependencies":{"react":"~0.13","lodash":"~3.10.1","react-router":"^0.13.3"},"scripts":{"test":"mocha ./test"},"main":"./index.js","gitHead":"8a09de2a0ff6177ee899aba0e707e9cf49689188","bugs":{"url":"https://github.com/gobwas/ducks/issues"},"homepage":"https://github.com/gobwas/ducks","_id":"ducks@0.1.1","_shasum":"42296e44bca0280adda028f760bc2c4e3180329d","_from":".","_npmVersion":"2.7.4","_nodeVersion":"0.12.2","_npmUser":{"name":"gobwas","email":"gobwas@gmail.com"},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"dist":{"shasum":"42296e44bca0280adda028f760bc2c4e3180329d","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.1.1.tgz","integrity":"sha512-yfHC+oeFOPfy10FyXlwD+i3RfoJqANM8dt5UPFkh2uADKNwEZbT/504/670+I0rwUTp096M+JkZfLl5vu4WUFA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBzLGjt1SWUUOXKiKLh2zIZUBDrrkmVM8jeQP6ff7Z2gAiAL1WdeyfQQofd+mK3eqMw2XPh92Db3aPJVENS7B3odXA=="}]},"directories":{},"deprecated":"will be removed soon"},"0.1.2":{"name":"ducks","version":"0.1.2","description":"Flux impl with DI","author":{"name":"Sergey Kamardin","email":"gobwas@gmail.com","url":"https://github.com/gobwas"},"repository":{"type":"git","url":"https://github.com/gobwas/ducks"},"license":"MIT","keywords":["ducks","flux","di"],"dependencies":{"bussy":"^0.1.0"},"devDependencies":{},"peerDependencies":{"react":"~0.13","lodash":"~3.10.1","react-router":"^0.13.3"},"scripts":{"test":"mocha ./test"},"main":"./index.js","gitHead":"18d72aeaf307b29d010159a5c3615bae9c160925","bugs":{"url":"https://github.com/gobwas/ducks/issues"},"homepage":"https://github.com/gobwas/ducks","_id":"ducks@0.1.2","_shasum":"ff247d40c0b76beb52bf6073206ed9e7dc61ffa1","_from":".","_npmVersion":"2.7.4","_nodeVersion":"0.12.2","_npmUser":{"name":"gobwas","email":"gobwas@gmail.com"},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"dist":{"shasum":"ff247d40c0b76beb52bf6073206ed9e7dc61ffa1","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.1.2.tgz","integrity":"sha512-Edc/h2AveZXoL2PVCmaDSFtPjCmpbFyKmXtKI3Z/6+yZyR8O7BAjecxKQ7qAt4Ue9XvgXuuulCYLAy931qUeow==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFFv+GpJmbR6V63PKIYGOsEtaHvE4a3Xmff3ZKkymaQaAiAqHT0hDG32HOKvuiFSdXttHu5DY4vJa2DjnqYBUDW5kA=="}]},"directories":{},"deprecated":"will be removed soon"},"0.2.0":{"name":"ducks","version":"0.2.0","description":"Redux Ducks Interface Enforcement by TypeScript","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆 Ducks is A Redux Modular Proposal Implementation for Easily Managing and Using Your Ducks Reducer Bundle Packages.\n\n![Ducks](https://huan.github.io/ducks/images/ducks.png)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks-orange)](https://github.com/alexnm/re-ducks)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middware support. The goal of Ducks is to help you organizing your code for the long term.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Binding `store` to `operators` and `selectors` by currying for maximum convenience.\n\n### Todo-list\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\n## The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module...\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n## The Re-Ducks Extionsion: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n## Extensions\n\n1. Perfrect TypeScript(v3.7) Typing Support powered by [typesafe-actions](https://github.com/piotrwitek/typesafe-actions).\n\n1. selectors...: Currying a State\n1. operators ...  Currying a Dispatch\n1. namespaces...\n\n1. sagas...\n1. epics...\n\nnesting ducks?\n\nDucks++ is to define a string constant inside the duck to determine where the state is stored in the store; \n[Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22)\n\n## Requirements\n\n1. Node.js v12+\n1. Browsers\n\n## Usage\n\n### 1 Setup Ducks\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n}\n```\n\n### 2 Load Ducks\n\n```ts\nimport { Ducks, Duck }    from 'ducks'\nimport { CounterDuckAPI } from 'ducks/examples/counter/'\n\nconst counter = new Duck(CounterDuckAPI)\nconst ducks   = new Ducks({ counter })\n```\n\n### 3 Create Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are set!\n\nA full example that demostrate how to use Ducks can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\nnpm install\nnpm start\n```\n\n## API References\n\n### 3.1 Shortcut to Configure the Store\n\nIf you only use Redux with Ducks, then you can use the shortcut from the Ducks to get the configured store:\n\n```ts\nconst store = ducks.getStore()\n```\n\nThe `ducks.getStore()` will do exact the same as the above `createStore()` codes.\n\n## References\n\nin `compose()`, `ducks.enhancer()` must be put before `applyMiddleware`\n\n```ts\n  ducks.enhancer(),\n  applyMiddleware(\n```\n\n### `reduceReducersFromMapObject`\n\n\n> We planed to directly use [reduce-reducers](https://github.com/redux-utilities/reduce-reducers) before, however it does not support types well.\n> The `ReturnType` of it can not reflect the data type of the reducer returned state.\n\nInspired from <https://github.com/redux-utilities/reduce-reducers/>\n\nKnowned Issues: <https://stackoverflow.com/a/44371190/1123955>\n\n```ts\nconst addAndMult = reduceReducers(reducerAdd, reducerMult) \n\nconst initial = addAndMult(undefined)\n/*\n * {\n *   sum: 0,\n *   totalOperations: 0\n * }\n *\n * First, reducerAdd is called, which gives us initial state { sum: 0 }\n * Second, reducerMult is called, which doesn't have payload, so it\n * just returns state unchanged.\n * That's why there isn't any `product` prop.\n */\n```\n\n\n\n## Developing Tools\n\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n\n## Links\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n\n## Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware Lifecycle - Impure and asynchronous; but still redux](https://hackernoon.com/\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n## Articles\n\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\nredux-middleware-lifecycle-7d8defa4db7e)\n- [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n\n### Sagas\n\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n## Relate Libraries\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [redux-dynamic-modules - Modularize Redux by dynamically loading reducers and middlewares.](https://github.com/microsoft/redux-dynamic-modules)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Related Projects\n\n- [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n## Resources\n\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n## Concepts\n\nRedux Ducks API compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction)\n\n### DDD (Domain Driven Design)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### ES (Event Sourcing()\n\nDon't store system state, store events that brought system to this state.\n\n### CQRS (Command Query Responsibility Segregation)\n\n\n/**\n * CQRS - Command Query Responsibility Segregation\n *  https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs\n *\n *  1. `operations` for Command\n *  2. `selectors` for Query\n */\n\nSystem is divided in two \"sides\":\n\n- Write Side accepts commands and generate events that stored in the Event Store.\n- Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master\n\n### v0.2 (May 2020)\n\nThanks [@gobwas](https://github.com/gobwas) for letting me use this great NPM module name `ducks` for my project, Appreciate it!\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)) Microsoft Regional Director \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"e13244ca15c8041f8587592e36528193e0781713","_id":"ducks@0.2.0","_nodeVersion":"12.16.3","_npmVersion":"6.14.4","dist":{"integrity":"sha512-WhiqMXS+rD6yYcPv0FOruogBCX5OSw/H5/fup1m+BXkluynAw1N9t8hoUTWYnNyxvCd0SEqol89ahTsKc7ABxA==","shasum":"bda0d768cfec437aa1aaf5db2d6f2a78675cb207","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.0.tgz","fileCount":289,"unpackedSize":549889,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJexuEECRA9TVsSAnZWagAAbf0P/iloj9FB30ohkbosesCi\ngU2WL70yOkez2IpGfgh2HY1o10PO4CC5gvPLwYoBT9WV5o3jR4vNaBItPzoe\n3mkSk9xZAdI93xwDbANvb5+3qpmIGX0T0DfB4nKl4DUQyHuG1Ll+mIm1bf92\nNUM8txBxEZYXs329z0RBviEZuSDcfukKxCpf6vSTUYv0cBQzkJBl8gGdk15R\nYt7EG/O6hmPPMAeYpuUCdvon78Z/CvGrFvtxMoHc2rQTOjbU9fEl+ktXUxrO\nv5MKqt69kWgIcRUAg5ZRbrKGBeaZFn6PG0JT1rfe/E6YtzqkhRnhQztE9DMr\neLOLxb1/oUsIlnP7J9VvUm7OwUiZJyEfI3IcGfZzQLcOzZu2jzDTPDvcSj0u\nzrsnVzPpnigTjEwEsZKjulLMUsMe2kK5ewfsZmwURN1gV//BiU9U0ed6LEsJ\nRr1Z7mJtAFAEeE2v0R/goUcJdt0cXf1zEcwwShMPfZyWj5sNZQnpBc5jVsTs\n8nz68U6q5AZxE/WsktUwnPsHUQ2mOw4Up5sKs5sXZmdwRK+4G2bw3lcDjUHw\nBCR8lw0y/0M2f+BDKGH+UbOcc3gQk8AKdcbfIL7uaTizCl+5WfMIRb+e5ItI\nL3r01C995TlYryIaziS/ncaGSbxg8JAX7YE/Kd+2o7z7NWQ629nWpQqlQiII\nD2TT\r\n=3KnB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQClaRqXAkRspztScSNWAo+sKQIxjL5lr6PkMsjG2yNZdwIgMwCnoylBGooYmj2VvkH2JYUWLd3aJtKjEUDspvizrHg="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.0_1590092035046_0.9907849275849416"},"_hasShrinkwrap":false},"0.2.2":{"name":"ducks","version":"0.2.2","description":"Redux Ducks Interface Enforcement by TypeScript","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"true || markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"8d3ce4bf84a7862efa63d8fe9d4508c367a86bd1","_id":"ducks@0.2.2","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-sk6+C42Ry82mnpJPfiA/rnfDqgERNEeBDSzpg51uAz2XpsKG/4vBPkHQNSyjmzbIN7jD6XBQ+WUYHu98XDDrRw==","shasum":"fcf95421b1d4b6db5cbb2b7389ec7ce35878d069","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.2.tgz","fileCount":289,"unpackedSize":547669,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJexuPjCRA9TVsSAnZWagAAnT8P/1q7mGWWrB3KdbSV0fwz\nfKuv1MPAY37l4F4Ovim1Se6PtRtH6d2P6bE93+p5EPn2iiBeImFmPQ7Hizqf\nIBySWvxD5ZoC+FtItpwbwbwoz38cDtgzNPY1qIGau/GUxtQGSNtec73Oya4A\n+iiFbw1yv1MstH48Vj3HIiOnQq1Ilv1azymB1ar+lxTYp9xeUvC3FIZZJKWj\nFegBvTW//j3DHxpz/BhK5jvTgiZ4jBzeKvdemyP3IeeyE0YDh2rjv3VAEpGm\n5x7UR/Fzq3ukaZti5AIzPZo9x7UoOUHaB3KtA87MdPHrtBzNTbiHBeQ263Qx\nQJtZYhoIQfMALoR2nkhG1ovmimDaOy4dfplsLJWtHFTTK06Maa7aQgrsh5x0\nUTCDDuGi7+aGj2bESlAmgyAldE8i04FA7H+HKf3zDdpW87MCxEB1GJ1ROp3A\nsqw/M/bxEABLuJmjyrXNE/tZrEWzuKPe1vdip+4dczW2gi+snYTuufiXX2qb\n8l5WU+HG04r119upl+5zF/4ZmpRN/hOEWOzl9jmztXtf9kUsP5AKK51uxPiz\nM+aqRKtTxJgJZL29TyG3SYMa880R7/l2t521kbAvSSS773g5i6OOsqZpJx6N\nRVRGIZ6l+ocPrtNBYjLwqy3sAqgNA3KFsbCt/GifbPMSqelcc2t/csXWnYma\n7YJw\r\n=sPdw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGzP3fnkfIxDd0tURaBWeFR3kI/3rZzXt39yJslWaORFAiEAhy4bWUo+hbcRkvZFeL5YIIXudgwwa6j02nFDegR1C8w="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.2_1590092771256_0.39910995158730134"},"_hasShrinkwrap":false},"0.2.3":{"name":"ducks","version":"0.2.3","description":"🦆🦆🦆 Ducks is a Reducer Bundle Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"true || markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"dc77023f1cda257551636b519d687fa1e661d4e5","_id":"ducks@0.2.3","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-71W7uiq+JgKai+P+JN72wyWMRsFIEIOcbbRaqw7HkNf8iXfeWwUPN2UASr3xI10Ggwtbr9U3IS98nzXWMt8Emg==","shasum":"34a4c71cac2ced1f95afc596fd8a209f4e43ac32","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.3.tgz","fileCount":289,"unpackedSize":547974,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJex0BXCRA9TVsSAnZWagAAoU8P/0Rz+Yzw2S6or0dbmV0r\nt/abkZ7aZCM16fBKA8/HY5KFc5EoVfvZhSq+hT9MaQFM6qQVuWOLcnnp+GW3\nHaC1NLsyKkfy5gwIDYJgs28npThEGZabbTWMEc0e5MLy0eef5fF12J/2RFBQ\ncugEn0MNrLJ6NuDrza2387K6N+YUBP6WZVRrL2MMfZwEbyYEq00bZtBIdtJd\n15RMaNXWgKWJWZ5hoouk/rdXpMeNUneRk7jhLZOQ1hGqwtEFxKM1QKwKcguO\nZEoGMWb/UK25sJ4tUimtoDRBID7gz7d47Wx6eD2ovBZBPfhIjM4P2mUHEE5G\nnB+imH91MW8Wt7Ur+xlUAbb6SX9bPk8UylxgKAGHsZBU+crGm07BM5xkD1eF\nXUdl1CZ5+fhp3gmAPv0mnnlWjuK/z4DnpC5YTY2khevxys5oQkJJSX8WX5oK\nXQ9Hoh/hdRcSMoHGy+kQOF9id2N3q9+4sEo56ho91ji1JJyCFFZTBpwpe2wb\n0gLdf770Xl4G0EZIPAddVxsQ/Fnc9Nh2ay4ATejXv6Grl2KOkWiKP9oowagp\nOAlEI2IWQ3QYkIU9ebzc2lJ9qdLSYWSWEMZ598FgrTKA1KCSBzK1hlu4g2k5\nDuYLVk6If5hs/+nqhnd9H0v96hLGyaYQhl5hdLeuq8eXXNONeAQxNIS4C5bu\n/ToO\r\n=u0Sl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEeL3XkUA9sGFFDX7WB3DABVR4CsjLX/L7sCD/6WbzEmAiBMRVFu+1X7Fi9BYu5V4gTlnGQes3H4nDs02AaubAu80A=="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.3_1590116438734_0.8370516557557026"},"_hasShrinkwrap":false},"0.2.5":{"name":"ducks","version":"0.2.5","description":"🦆🦆🦆 Ducks is a Reducer Bundle Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"true || markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"48d79b11abd6a30f55d21e0a9fec498034e03bfa","_id":"ducks@0.2.5","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-92oF5PmGn3qSGQ7t7t5DedyxbR9UDzlHFyL4Onap9x/TRJCB4h1RImeXlAk286IMPWPpmkN+sh6UIkrFtjeUGw==","shasum":"60c3a3ab9832b992ca439a0e9ed9bd7f7fabd4f4","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.5.tgz","fileCount":289,"unpackedSize":549489,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJex0QECRA9TVsSAnZWagAAAsUQAJmDjXFmTaouGnQKTys1\nvu4keCCym/o7K1SgnELn0QMKcdVLMNpGHfZazfQYmxfyKUk4vXj3id1W9iKA\nn2ZX8aYXWVSVPIE0+fMTSxElZWc+NhGug0fk8GVlkBsFYbugZtEx23vR+Ynq\ncdi8dnkbFHyoZmVdoiifICBAc7m3+Ijsucr5o7D1/+40fngSoM2yctRHSgis\nxyhLC2N19DKaQyfnZgnl0zdAUtRYG6CvjCBAfIdOYA8iqaN+rsx2yFOprnBE\nLDV5aMqwwyel5i9p/BlTgm5bUE1pdLhTXTaRjgikHFt2coviUllArmgQknFP\nm7+ytTjj1GwIJx1UiBIg4lF4NLlOTGGfNHmb7akkEwOqA4gAiQVp3g3iZH+i\nbBFDRKSrMyO5ktfIXuWYBNahXR4LgVZB3vCEHeZNX6jGnRM5vU19yuy4NZld\nSciBlT+YXcoq+vqSm5Cl6jpkmPiBcdWGXOM4wMoQuI66PatyMwpA11FCGDJy\njXX6DX0mfBSOVJ+CahSa+Lx38PLBSQYG8Ze7h78pF/GFtbUMHEjvBtj4ZzjF\nPQS+cRdrqTrIolIpn0Kpd4FPb53qhuieKV+DwlQ0YfZbUfP2udi1SO4rhri4\nIxnisiV9TN68VFMZVAW6WW+1KXiLG6gWrh2O764vCKp3YY+qlnaANVa1ehC+\nDJqQ\r\n=gr9P\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIF5YlItRsFTa7htalTzG0G4vIS9VaCA4KfaPe0D+nIeMAiBSvAO54pXY/iYeugqYfxSExYZoHJ+mHB9tImfjLhPURQ=="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.5_1590117379802_0.6021184215790829"},"_hasShrinkwrap":false},"0.2.6":{"name":"ducks","version":"0.2.6","description":"🦆🦆🦆 Ducks is a Reducer Bundle Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"72b25c5726a066c66edb2071eb20366363b11d37","_id":"ducks@0.2.6","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-TXkF9WJ6cQM1Eih/f536KMBdSQeUKqc6GppkylnXmC7y4npEP4pe6pEHI0CBO05dg27eFTdJqW8vp3cZoNCSPA==","shasum":"6fd2f5b14d91b7308dfbd9df56f8174e2e0729a8","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.6.tgz","fileCount":290,"unpackedSize":560873,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJex7nICRA9TVsSAnZWagAAOCcP/1JKKy/lvR6M7se5Gt/a\nsefwbvBazU8gKTCCQuqQS8Ech/HTef8TRZ4K8hXFEh62y5j9AocXT1DvOJ0q\n3AmCkO9pkC4YuRLAIPk3wG2FwvU0a/P20K/kVUk3QomYT5gw0Pdg7uWrt5wy\nzQyN39KxyiwBPi7mLHhuMPBO+t1GDYoh5ZOyiPRQ/dOZx1Ofp9SW0cp3FynO\n4CJ/zz0BPKm7cdEWahn7ndBcFA4y4CDVDFKU/aILJEJ96UPzMTHDPt3iSZ+7\nZUL5OH/XwxeM7ic0wkfvihfWtTrHpiRBCVXxWbQ15GBuMH24D4k9F5/B45PQ\ncdGNC8Zq1ujc7NCJeSn9PUy3f+GrX4R48BXwvTGciM7EupQl24Uz7ZRAbL8u\nx2E+9UWk2kBzP6+rSFN8h+SqYhjOt0eI1evJlRbl7ahzfgV+u/yigykLz6BQ\nBDd49aBSWdcVkTfIFnmIaO/fKOqOTmCXkLSgIoDcpb7H2d9kkr1RK1pmiL4I\nlV1DAdj1VdRG27tYhzOyV6i5boZoxrwzaYby5d1JEZxPCp9G+iz2xEAHuKjv\nGxXQw3vjpT4IE/Yf/c5tO2htV9M4GGUJCIoT6agSb8Y/Q6RfJdhb1VVQL4Lf\nlRvZcgvq0ds/H7TwJSoq53QcULBX7xQz5CAlbjT/lEnI2kfH2t2WtdgmQSpA\nXdAu\r\n=F02p\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCK/W3oWXQhEygIC5oxQZZSbcT9jO1jyHD0uEIWTxc1HAIgHHzgXrC7qLO7f82wpcOmelZOsiil3NzYssjyNaJemiI="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.6_1590147527696_0.6353236591289162"},"_hasShrinkwrap":false},"0.2.7":{"name":"ducks","version":"0.2.7","description":"🦆🦆🦆 Ducks is a Reducer Bundle Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"967caa9ea1a7802e2aa090bf8c65129f3a062a67","_id":"ducks@0.2.7","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-b2WIYuyJ19Md/cYgFGzZEToSnmtnlBEsz6SsHRCFJ0DZ5dGzurTK5pI849avQWxVi6lno96BHymwIGz5hfwq2Q==","shasum":"72af6280938ad286ff63474f25fb6e990c719a49","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.7.tgz","fileCount":290,"unpackedSize":561081,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJex8RGCRA9TVsSAnZWagAAj/4P/1a2fCfccdLqW/ydywen\njyeIuh036oBa4iJCFz8kgY1m3Fj7CIHKSVlT+ldHopeYVn/tIrAkKS7L6Lft\nfsRRvC+vO7YWPCXqJWaZpQ60OCVrBI1DaQ0M2Zd9QAm2OopyQ25daC/kj3lU\nTp/gwf11zmFHkke5MfyTSerHvwTQvvpSaF0+zM4w626gZyyIC0nbUihMse9/\nqNsUwxz2lgnkyvtCzby8kwhIEPfOc1NuRxHo6CKsZchSxSJFd5YqQDYvD5Vy\nv7gvZFXGrqpYUuiI++imzCJqqdAwb6XnBIUM0P7yGDnfSIHkOxb3usKFjEvM\nPRkWGGJpTjHUX+LYrjpsBzolSBQOaC+fRxkYvDyuAbqIC3uVQXPDBWmJnzGi\nzWNQfuchg0JtBbBPJqEo1HDPfm0NIf4nYXWNohX1HWlMm5+fNdWAn5LLoayi\nmvqV+sHu2QEEjKWc7MCJ9Hce2wmzlB87IU8l2iWAl9n8Pvu1z8SQcJAgDx1u\ndtspvAZEMj4WKTH/HOF/iuKM/2LL7n318aDK/0MudBIWJ7bxDZu/rYVuZjcD\n8MpTNKHwf2IRd5TowvZmv9DPA1XJD2PtEmbuCWw2gcN8NOoX132QXZ1bam/7\n10PDK91P3BSGZZxZ+cVjBc4wwoQTNZL6+aoro52xMSPIYq5CIbyIFv5RhW0H\np4zb\r\n=G3Ie\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD60CBS27ku88EdbFqGWtTEzYPmqRQfcL/ugxniaF/ieAIhANfd3asOzzpP1hAe+m5HkNHWTXHfVtGPV874Qc5d7gOo"}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.7_1590150213385_0.7529002927167614"},"_hasShrinkwrap":false},"0.2.8":{"name":"ducks","version":"0.2.8","description":"🦆🦆🦆 Ducks is a Reducer Bundle Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"ded84c6a8e3beac5ca25671e8556a8ebd78c9978","_id":"ducks@0.2.8","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-sjk8ahPHKHhGO+rguknMVdpQG2BGOMTjIclvvES+J9p1tdPOood8LTpaTqZZyoKY4bZRXXOkGSDi8Iwx3Q6Lzg==","shasum":"733a436ec0c4962c85a8da2db573c03b0b59db0d","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.8.tgz","fileCount":290,"unpackedSize":475162,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJex8j+CRA9TVsSAnZWagAAIOkQAI5w173rx/QzL8yBwArj\ntf9SQeH5kPF0KmbubWwFWGPjdBLD0NSoc8oGusjirFoW7gjZqN7le98kNEOd\nKqFnr8yEnBsBxaOCxfbxzFcKr4NqPPMwInajz/VvARtkedLSUUtnL7b1/8W0\nN0pMWqJRxlGEaFZ3L7qzaqNDZmq4E2q5TytQV6jNlLMzqjVw4RV5kKkPAy43\n78CSxraV4LUqHttVpz/Y2rVgfwq/95bV/szVXrOvo2eGu7xilPmktQkbUz8G\nJd9osE2WmbU/cKyCvRmLv3RqboEYVTAKsM7lHkakg009qhEGhR+qb6CE00ST\nJQ/22+ZZkkSDr2uycloCVUqnb424zSw9tY7OSXw8+MoxeRpjqs8ix+5/2SU2\niibXIT26uZqfPkJrOIPDhV6TGfB1XDxZTxS31bwvh4oO0RUtHzGFUwL0vH4s\n5MgPx0W7AefyL8eXRuy3T5AeJSiCxyrJEo6fP9kjG5QAAA7nOhzIi4jtLPX2\nsFpWV1ydybdbxseSy/D6J3lSZy8mZa3pZ1Gp881xWE1tIZqAARz9PCmqFyfD\n8T03e0oubvow3FNaHmnoBUeR3NrpR1y8qhJtcnuDbYgKmg64GglBAy5jTYSq\nlCJedUYZI/VkSvn3va23jm6fwNcvHsmfwImmTKXGPhOJGFUm6YpYkrPOIHSn\nzToR\r\n=nHb1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDR1KUDCiqojWOnlMC6sIG5dHw56rfSG10LZeRwW+82tgIhAKx9A5dxD1v5beTVSRYOYEZPdDA2YBagB422mnUIriUW"}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.8_1590151422025_0.8638629595391238"},"_hasShrinkwrap":false},"0.2.9":{"name":"ducks","version":"0.2.9","description":"🦆🦆🦆 Ducks is a Reducer Bundle Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"e2afb44603ec13e3f900f30e8d118aa354a67497","_id":"ducks@0.2.9","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-m6U2qFDw9unpb7A4TppD2amgJ621jRaedCt7O4AVYFRolLHRFzPahILGCTb9lNoueqnkiIzrZDxkUKSIG36ZOg==","shasum":"faa0bf6b6f9ddb9baf6ed6ac6472c8d66aec3990","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.9.tgz","fileCount":290,"unpackedSize":475179,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJex81DCRA9TVsSAnZWagAAVbkP/ih/od+hQ2MGLl33msj8\nIQ9ujoqdHTtFsSQbCde09nPFIyFCXr+4OJuxNgXc1gC2qTLMG542tWfWUTAE\nzBrA14A2xnuo3Qnr6KT3UPfM78L0H3NMzaGQpL1YHtvqlULPvZJAV1YSjl+j\nHmQUeXba1bgt1xt8dMk4wzhDDs0bua2B8V0NYyTdjXbyFKG0VfqLLi0gy2fO\n/DKxh6v/AMH5iec6PIIe9IuhNWTZ6zjYKytB1Q0aBn6ImjGssk9mfqfAUD2v\nyu2vG6OVYAdU25qxLF0sbtSAugiZkIIqU07UP7SAHk2S+wVSqgT+yiKYwXMX\nX7z4KWT3Svy4e6tOWVQYK3otsDz3oHRlCHhbgT0Ow415O4kQ2pKVwNVSCcg4\nIspzZHYtuGYoRG07Yc1RTjotbBMGO4RWn296ih6N8yF77HaWOmMEQVb/uVFa\n2XJWb6GZQ/V+6SAhaHuXDNhTpDDPLme1ap/YOtvmVOj477JRkEkLZiwm2R5u\nW8jEyelmIBlRAQOuC6V+SKCubXtMIrBOlAnTwKnr4GuuKmOC9a73Opu3KF/v\nl2xJcnY9we/pFARjARTo8I75LyhgxHYHpymsPUqp4IsG0c24BpWGmbh7cGbL\nmRsH5T7rE/M8oPMmT72o9nb08+q4vq9Iwen1q7sSW/tdhF1rVi6pwdAiQytn\nj4d0\r\n=avGK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHV8Zu93vTUAkxAHNhczGSFPZFbNeMwp8w60C+K85FfoAiEA7eWzYyC66ODxDLmAsRG970ObE6+nwqPU/GxKXo8hOec="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.9_1590152514183_0.22008700856326557"},"_hasShrinkwrap":false},"0.2.14":{"name":"ducks","version":"0.2.14","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"cc4ea9ae9138e145fb267150a2fd6db31af07dff","_id":"ducks@0.2.14","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-PWLLOjAZtRPun53XJsf8Vp6hHFyosR99VzscC1tpRJMHTFuL/Zq7lvnqa/uheGyih/dg08A2ROVS4JpZ2sgz+w==","shasum":"81d3cafed8d47d2060376bd21a04fd29f012117a","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.14.tgz","fileCount":290,"unpackedSize":477926,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeyRPvCRA9TVsSAnZWagAAMO4QAJo1rPRO2ZOI4hiZUexM\njRDRq67glWd03AfWSWIQIVmkWvPEjVePWkkRK7zLQRAcCTrhnZz4AUO1p1js\nNn5SHZL15JcFqAfSSWVG3E/+m8ppsZ6nJUDvF4BOC76LtjqRo138YlDzSie/\niwWXcH5AIBYc4R5c4mbQtlCxvz0eKw8wR0cR0JzNJtGnbMLrLPJngk0/GNkR\nfYR4vgV2OOazeCeCEMJScb09J/xhe1h+4fZWV6UtmNuftk+GbhM3Wdn+XQ3z\nzAsPdILp3nYsfvx2KSCap/z72q4h4URV7FdtRJmQJWLzlE2sUEJIJyZSNX/W\nsTg2h50bwhHU2qTACzee2mkwXQfADxF4Alrrh1UU11969lyhqYd/s1CCx9t2\nxioTz1MuKPzBBDoh8uwPT9SVXZ0SeLBa/5TzvseaOni6KkiFZNAUgMoKMDxC\njVqH+kF4PKzgMX2S20kjzDUCSSHCIWbNBsB11R5xpFFMETnLW7TAoA25H+D3\nVyvgB7io12pUAHl8cXYYRk1R9fSUen1ZNKrZm0/0O4KP6EYWkt8kHDqlcA1D\nFmnQVWfUmvCf1XmwC8CKZ1O5piOhHRDxz6i5Yc7518SkG+I9XRg1MdCQNAbw\n/swojsZ+bNeQvmsiqvFIDBpO+Zmwy7bgYI1AEfCJ4aZ4lp4T/dHxIf1bsOaC\n6rIr\r\n=u/1l\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHL6cdAYifs/hdvYg6DYm+WngGgOScdTBsl2i1I/dOKgAiEAjbELoOWOfX1DHf086KDip0hwPtLXYnID8/a0c71kpZI="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.14_1590236142405_0.35176501815908234"},"_hasShrinkwrap":false},"0.2.15":{"name":"ducks","version":"0.2.15","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"9c275943002e7085840ac30ef4fd689a495288e7","_id":"ducks@0.2.15","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-kwyTPx5INU4YyMtB8/JPVFUQi05Zcz/OF84Vipwhc33enzLk5je3smz0GCGeRmaL07KWSkK6q2J5zCISpyMVbA==","shasum":"e601bc365569c5cc98e48482c60c16b695b7d19d","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.15.tgz","fileCount":295,"unpackedSize":481632,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeyTZeCRA9TVsSAnZWagAAPOAQAJWhJk33yzTz+dmY3+FS\nk1xNFnZLbjK+NaLlTMZMHGFQp+/VJoIxsSR6W814Fl+Lxyez4AT/SHEGI7DJ\n/5i6c9nDvDyf2KNzDiZGEmUTxfcDUZfEQSmmPGDOe31SKwcUxfQLW/72x0+4\nAtTVMRk/J/MgQ6SOqyQRweldnokdykOKcs8A9vj0f0F5eeJ61Sikn7BeVqL8\nJHLyCUDu2V1ofhFg5Y1CXXj4zg22wcqPZ01sNAEQVQssXaNO7FiPBwttNj1E\n1+KOldyxWjXEkZh8PoeArzOs3raeT3VmqiPdYKjy+v4pYOB4HuBDN+AFX0RK\n52j1fu7T+WmRINRmB+prc5PM1sfAa9stf8M2LUtqJmchofpd9lncxZ9sRQGn\nJFku5kXxrCSjd7BPGIvgNBo4AdyTjgmekNSzC/hnmNijgtJ1QNV7W80Wkssb\n6MYpc2mDiALAF1AoxDsOqyzMYwnTKVEDLRitgEo4ai4EYBKow2tjoRCZoWUC\n3xSMrmG5VZI7nxG6+3IkexaLFz3pVzPIOONaixT3Gmy927ufjfejGcRrVGLZ\nNqUcSbVhziNA8IsdwMBbPVPq+xebbgwUzWVMul3gdGDSEgr09OK043Dgm8Nn\nTzmdHpLFi5rejsoLb6rtebcU95SWr3AqlHfDeBqy8u1CEn2otLViOTzeW/ja\n/B4K\r\n=UZ45\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDBjv7Sicf4MGyQVcxCziao/C1OGPxWHvD5hfcOcvy3/gIhAMEqcTpfnwF8mdWeP/CvGdCX5KCqLBmjYawTiKJNOlRp"}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.15_1590244957671_0.4752629208502215"},"_hasShrinkwrap":false},"0.2.16":{"name":"ducks","version":"0.2.16","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"f5b0fe3eb46611cbe45d1acc6415dcad6318cc2c","_id":"ducks@0.2.16","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-Og3hFkb2DAMKpkO0KvHwfyVN6pF6o70kmLaJ+hUDVSVmNcfDUeRQPBHO6zgxGnjvSacpjIpG8OsG9uW+5bdK1g==","shasum":"3ce5267be216eac5d2ea6c5af6ce4c665605bfca","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.16.tgz","fileCount":300,"unpackedSize":483207,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeypwiCRA9TVsSAnZWagAAypYP/RGIFrz3qT6AW2mDTvGS\n52PEvpr5thjReGHAsRr9waSXhavEblMW1/EQkw73tzkL/3NJydzbNQtu4kuw\n+WyPn6kK8WOGOqs9TxYVqI/b/d0dTwf2kcYD/6owmfuTsfE+YmfS8TlBAQar\n6HbJXfufzsROaBwZyaHlx+j0KoM0FSRt+xPuhKQqoZRmuqgYMOeyjWEl1N6W\nW/BOrhCHIPqD9d/nYXsVadV3tIeVPxTlijrXe7zEFJKUSvBKOxXPS4zleHNc\nREb4zKUjAS6jPrsnI79FN5L7e394zyOYuvE2A0bUyuWmfXyrY8oTTkWqD9VH\nNCXgGcVJAPNcly7DkvSu0z3MggBFb0Uj/budf7YJGZkwJH5qsjuJiHGYY7cC\nKLhOqh38fZjGXJru5hmF3RiXtpe+7H0xwnW2VlCM2Y8lvVO5lmq3SK65bv5v\npVNTbYiOZQnU2dh1cQqUkMUH/qVtbufAIZH8nJIJ/ar1Sx7pOOKvzfxwwfTC\nBtKiy4bSVSbsH492gpfBTnTc4cmKb1uw30mjZhzvayzDBLZWnRxbOanT8ldj\nguskugA+zU4rl3yqM/Q0i/zM/ynnVuU9SDJlQmiwQg7HW9uDe6H7NmJYVF8M\nVAuJNcCguZvWWMSWose/B7ajq90wWzwy6UYTjUWBq0Xy6xSptBrY8VvyLgDp\nO6q8\r\n=9Bv+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICW0MTfJNAAOSqIwaGT87/9W1FIIisyvqgbVawJ/ei+qAiEAhS2gC5N1NebX3MRtfuT6LJb+oMPb4X8IEUs2hHCV798="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.16_1590336546293_0.21216382621818197"},"_hasShrinkwrap":false},"0.2.17":{"name":"ducks","version":"0.2.17","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"c04db7a2aa7c4d777acc7f51dd6b3084d9a5edae","_id":"ducks@0.2.17","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-ve/FPfXQ36FopOfJUK2S3yr/+3C0PizDNs0/4WQZT8ogun5nnlJyNTzzmB/dNSvIm/rHoql7EBFw647Oloep8Q==","shasum":"3f151bd34b6ebcf08babd50752687ab285de4a48","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.17.tgz","fileCount":300,"unpackedSize":508794,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJezSdDCRA9TVsSAnZWagAA+SQP/i05016JVzvEeluQMCag\nvuuq8d86zSZqMsBCkXnHo5aSIKA/KWFY8YDd3vxcADkScr5RFF3k+M0DMCed\nWrA3ENk1ilG9+62OR+/2PWp/fyXTy+I3LvXOo+RawfdpkQ5HGIJbvTm32u17\nOEZH/hk4CUkq+Ingf2bNP8axaBAQzi7OIn/8HTRGdrLdTrSiBkD/JY3SbBRt\nczN7BX16LTNyUuGaoLfEA2Efh4onyxEUpLsh431anRZhOQgdDWWZXHaQXOiG\ny2UCmkWtN//EolYqxQ8/osodxAYPQufXBuQUxCsWgT8rRGTjI342N3ELrbkf\n9kh0jIFTmjTsEWNWagNvbjZ/CsIgTM4SyYM0R/sN7GUNGUZ2CV7/2kKi/r8I\nTIwQ3Pt2SE/rcmZfaGcGUDJYP4ZOvu92X72Ri25nmD0mFLBnBRgoN7kZaiue\nuGFiAaOBDmyXPSd88ztLfirnN0B7ui+a7D0Rzx4+6Jg3WTuPZsXn5saR84m8\nEVvDehELjRGKIH+89zPpbHFnuaO3gfE8Dd9BbwRaENqOR+PFLkETuE1KqOoH\nFkoKRacQLKeambDnsnYiwLOYbnXI7mGTcVqhY2MeSwApkmv5+OPoKZ9BRp4z\n175t9Lp/TrP3A8D2l6lcRYkOO2AJUqIZOJUJbHnTm/htQ2A6DuRAzU+Xmhjc\nT3/I\r\n=Y9iN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDmhWRozDek4fLlL24geW8mtmnJqGXCsBmqGifkynDVqAIhANT7pQUyefknY2xJ8qwsD7nJuikWw1H9hAPZtKM3xWqB"}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.17_1590503234826_0.23478630060156824"},"_hasShrinkwrap":false},"0.2.18":{"name":"ducks","version":"0.2.18","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"1cfc8dbae6929c7a2abd3046361b41a04392587a","_id":"ducks@0.2.18","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-3tDZmoxvFkCUt5RiPU2k2zgOcf/oX3VQ77ZDVlqBD0ra3N79UAkoX7RwVN6CbfNkDNqkxXGQzfS453xbEXgnYA==","shasum":"099b6d62b534ed1e738f95494df48d28101ea795","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.18.tgz","fileCount":300,"unpackedSize":509128,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJezSjJCRA9TVsSAnZWagAA2TMP/3oe6w4V3yO6ukUoZAGa\nEChadVQ9eXJ5UsYxv8XvAAgnpfovjwKKjefYZXEeDsbqj9da+00vutkXpv64\nF0+R0PeMRFN46voHd0LWts3jIUUv60vq+ln3F9H5IJDOjrxsAXk8SFv8FY+n\nbooEj1W3vfh6atlioWafhzt4wSQ5uj9fhnuIsWmihiTGDK8u4EgT642Hcafy\niHezpQiePRv5zq8jJtcOZgZA4WVUVUDbaJTtZ533RWIunhIGsYUjG0/yscUR\nEE6QlCvNDwChdZsBOpOC0oVzAYL66eJE5hX5eMM0sOShkQuFKx2CcrkLErKU\nLgPt74trOlZ2oaAyu/8U9NSApq25krsoh1eEsrGQjDvyuFsiJc/C2yOSQz10\n71vgX7sL0qRv3s8PcmXU7KEFrE7Gf7DfN5ijFczBrRZttyhc9b3PsYkK9oDK\nbRNdKMAHSyijCQgVT7YiKoVk4ly50ayaf2LeRy2/Ofqp6DCFvWG34rhqBiQl\nZsxF+StrRAxC3z3tRCypaMP1FdyNBF1PzEvFDkUSqP0zepC3B0lSxSYvSaWh\ntk08Ju1KOojxlM1ZV3QA081z1y4MIQ9CflOSydb0rMdETpSC2qUqEO6cP3qT\naW69JAZ+x091MsDQwUV5CKJ/dqLijqgq29TOiV0qoEc1f/7king/H3AVWd0B\nCWxO\r\n=bdtu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCr+vsPAp+Z1X/6i+0G2kXRlj8j6tx5yV0ZE3NbFchh0gIgYOh8DAioq6+07y1x19ytnqYjbwdQ22hzvtN7nzkPm/E="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.18_1590503625346_0.3733706531522629"},"_hasShrinkwrap":false},"0.2.19":{"name":"ducks","version":"0.2.19","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"47d2cabd9ff0ceeae44c828c56333a6ef2a7ff5b","_id":"ducks@0.2.19","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-5/4flqWRhy9TR84omHgjDmDFvIFSyEjdlBGiaFAUGYN1+wZVGGGFLl/Yuj6sj12ocZBq1uZIogmPYLf2tkTPhA==","shasum":"cee05890cb27c31b090c1872fe3530e73e8773ef","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.19.tgz","fileCount":300,"unpackedSize":509602,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJezS+wCRA9TVsSAnZWagAAFWoP+QEX24N1iYpDOwW/ENRJ\n7epQcnmqmGFLyQqXzRrgE/poxWHKI1heY03tIK5tNis7rZhKuxCP+SA//yCs\npvPoj9HXJZJ2LsL8/PMLi1GFLqa+tNia3lmhXJ499sXACz9YUZ0fA9jwz+zd\nd09UE9rBBqBvOThVwrCdveqM71dnO0RGDdo+8Sr4hprdsfpru3s0nQ89pMTe\nnYP0tdpCpYTxP8SBMz1YTVIARU5Z2/kg8WcXU5f6ror67BrSJl1i5fjWBBt+\n8Fqs4p8cryIA800rMSR/JSfMqJs3gHq747bclHNHerFnuGXLsz9J48BsPtvH\nusmfTjTyoavuiFc0YbcNmDHa29JPZkEjROe6K1SEYPfQRpMBvQQ2JiFifVcd\nvCgzyCrZK5gRDfbGZAgwNJrCAgZqB7he3QujrzmXZjhtutu5F+uoclNdHTRj\nF+NomUsSFM+4DNjij9YZJrk7unyxE/Jq7Bg04TcDU+uItK1oWVynpvyqes6+\nLZv93euQOnusbDwJBFvOENIqk5rnnh7gJQPLstkhGEzodAeI1OVB36bESYD4\nWMjBpQh/+nd/ttsV/6InqLzqRuL+ayeg7suJAzIlxQEXr4QdEH2wxE1xtB8Q\nQ8Be7criNPObhdM9Gmy908rkPeK6W6Ve4nQcQWGiT8BNwu4XAd/a+fJb1qiR\ntaJv\r\n=PXwt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDbPolbfQZhRvWbQUZb9FC/4bcE2BZ5S/hN7IkXH+GThAIhANS2axTS2OhU/M+rS+93mPd7VilfWEhcsXlADthVc/N3"}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.19_1590505391361_0.4996093122759595"},"_hasShrinkwrap":false},"0.2.20":{"name":"ducks","version":"0.2.20","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"51063c28f6f1ad240bc3d4a046f6c2d217d52018","_id":"ducks@0.2.20","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-T1hrFl1CQCeAgvxMRcGqARqm0W+fYFSLdbM4+0wGwqkbDyuNx4rbDdKrZeWljArPnkru6vDo1ErAwio8cZfZMA==","shasum":"b887807775dc27d0fca61652177ae0a72be749ad","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.20.tgz","fileCount":300,"unpackedSize":509514,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJezTgfCRA9TVsSAnZWagAAnHIP/3H53L5xfz9yWUj4Miyu\n+oea/zNoJg7WW5eGtrbdNTPizLT0aMiHXzv8Mo0G8Nh8CBJWBJRByV8a+kyi\nDAFEtz4RFu60iwI4sOQGfU/o1ZMqqGgM3QppMhQAOvzYDbvdJT+h0ItWbzNI\nWtC2jtk/Iig+dhrZzGnJUXmBM3ID+D7T14AsWjgGh8iUqqFHdnEpKTw1bbGt\nF0uYDKTum+JQts7oXcNRL2rTE7/4ZFrWU3cti9jH/mvQLad4Q9V12H5h8WjM\nP9IGEZ3MSPVX+gpjn+pjei9NzvUj6Sjr1j4Kbzmc/wgF25XevZETquTVwD8o\nkkBTs/w/svDj4IJCflFixwCot+NM3FnoFgGh8B0YcB8mCl013qnKrNU6UG6/\nAVTcfiqy8U2+WqSWV1IkeJPoGzZ2e3iqk+gpkWiyolqRGR+yR6E/+CYtHFtH\nmDR+hpa6KvFdE11eWZyo1AHKzpVt+KBh3A+S0R/cWN8K3IgX4ctI0tkRtgHb\nw9b/S8dGy9khBwEPq7AcsBKOtp4VaFgdR0xOg/2bIaPCNw3m99ZSNR3121CK\nMjcQqMzDOT5H36yIMGOvuQe6rmVBYpebUJQHZRsUfRWWGE1IrCOjIWrTMMPV\n0gZjLJ2PJdNE8Vm93rd6nMhhKhzPlz9Xw8IuCVpFatbGOQptkXG42Csp8r5R\nrbQQ\r\n=G6A/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGqV0uFaf5bVN7xgAjWziWBLDM68uNuKLtqlwFRygObxAiBi7jkzBAoh54io1NKjsCsj9qb9aez8VEy+QxS0FFNW/w=="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.20_1590507551368_0.8191047675451155"},"_hasShrinkwrap":false},"0.2.21":{"name":"ducks","version":"0.2.21","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{"reduce-reducers":"^1.0.4"},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"74d1d8c7e6840673df46a024f25767578a120c42","_id":"ducks@0.2.21","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-7atyeNGZ6reEDNGm3bV5w8ye4t07cxvE8DwDWuFx9rfGGi+nAmergbHkbMFLUV8n6Iau0o5pSOzyZzaTmBmYEg==","shasum":"102495a7c8b52a9091cd169acb1044b52241c543","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.2.21.tgz","fileCount":300,"unpackedSize":509760,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJezTkbCRA9TVsSAnZWagAAZP8QAIRDaLasOh6ofdBDBjVy\n2PYMqRArT8NRrNvYZLmIgcZMXUdD0g43UYjjaXYmWQbW49bTv4uz/bXsSfuH\nOd3d6uGSd+mJCUTfDlS58yA53DBWgi3VlH5XvTpf4poVnpboHtkY79ceD8eO\nbltV/J8ek2dhz8hMjBAzVPXT0rbnItdEdsacW30gYcG0DYHyC8caQKgvKKG2\nXGNjvz7LbwmXk7lO8pNsmt+3UAIB9BCTreKb4JYSB7DWpHkUf0HVG4ZsHTm6\nFCmJfOr5yR/1GaWGnDz24zqID8pmjKnYNA3chjpiu3MEG24D1NSnVDJODEmc\nCfamxSuGJ8PFFH9W+Q35qLbMEtdGr0s7fDD0VF/m0Qy/wMm8NAUWSI8zqT/I\nLycREQPryodpRTZZqX1aZq6ECZXpTHmfbDFj9oQ1Rsu6Or8szfwsM1I0twy0\n07pFU5IqzwcAp3SylU+Jk1L0Xe9P3OVx8j35iif+l20oih1bhc+voM/Fq+Qh\ndcWNNmPScK6eU9dBH+wsOVYzbleABOdyyscIKlsNL/BvlEcFCc2BydQVX/4C\n/RRwxoC6M40GcmwVPQrGf7Ab4B3gbGYeUL3IJBAnc0Xjz8BoQVNu+F5tb+fv\nlpOhEpibQ1e/grv1T6OAv7y4bOiQboYD03ZZqYULK9Uh9BX2uCKCAb8cA/TG\nQA8L\r\n=MWZO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIALGF17tADyHKo+AYK3+ZH+9QOWU2FpOIiFFC9dW/5BAAiEA6aWDRuOkeAP3gJHRv58jYn52GYzqX0jh2puFv6nT98w="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.2.21_1590507802536_0.08194823443443378"},"_hasShrinkwrap":false},"0.4.3":{"name":"ducks","version":"0.4.3","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"852753394308ca75e61577a6d0f9dbec8e0f99d6","_id":"ducks@0.4.3","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-dXjwRqIDGVFBKDZ2dSJIXimzpaVcAAdPK14pZstHXQybWmV58sZewsXWCpgVSWZodCrg5muHz5/ElKI3y5+qNg==","shasum":"ff829978a4e6a4ed99a835fc497d9bf3303dfb4c","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.4.3.tgz","fileCount":315,"unpackedSize":531255,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe0zA5CRA9TVsSAnZWagAA7MEP/0lZzJayqAWJfMx0sK2w\nMTQgf5pJ+4usG60fjD3/UjzAet6i4F5Ryosjw46G1zEAOHe733BojGrhkwVU\nLQVbJ6Jjk+1IXHgx5wahTMgb9GwQrbVh/v0b7J50Ih8HZmsljxDRhuwJG4h6\nQh95XuPCKNTEYpUy2gwp99dJazi+A7eOW33oTZSJkJDceAULlnTCl5pCz6Cr\nIdOvt5B/c85nlEWWKjvaz4+tDYkeaM4qFg5w+TeJV9Lgksq1Ml8uPIg+bcqJ\nimck2Sf7aULVIz79JbPv2hBa42OL3k3gTXvHY+nyDg3niaZdvN+F7bWA+fYm\nGN2L09OasSlZ4nlZSzXnprWHsljZ6eZ6CQkhs/IVIFVRE7VdchlwN3wCQ7wF\n2A28Oi6RVtGGV46booSwxW1yc2j0OmXhRkElsJkA2F78Sft0jQoEZqLw7pSM\nt4zK4I+npn2lpZOBx5K7c6j55CkchLcFzlC2kPW25g72p8XurRsN1vWVuB5s\nFmk4c+AJ9bf0fwyAYtKC9cHHcPAA+ceSkTlwyuBVn8rShupLB2MUuBUWcLyW\nGjlQvQa2VpFs2d1w772Khphjjm0RVPaseNNAV6qX9xGY3PAyDAzlFTaEWpRL\nmOvB35KljedT70VON320QUMy48qMKAXjBZuY4y6eSgv3rXsyTyecazblY2+/\nWQQX\r\n=Dc3e\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCaBLnLN7VzwQjYo8nVj5AoXmfzx6Jd0y7LmPWGHkFR6AIgKOkS5uNSIAVdtJVXwCA0eHqyhGKmIvLFrv1gWJa7JT8="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.4.3_1590898744615_0.1844441690058085"},"_hasShrinkwrap":false},"0.4.4":{"name":"ducks","version":"0.4.4","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"78881cb10f394b0562f925415ac4875966b70bae","_id":"ducks@0.4.4","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-+hbup2XRkX2Ju3KjccS03mYOpKGL6tRwazNUGt9ZBUYsql+80dynDvRLm9u1fGylQC2Z1gFDMdIafXxGGRdhVg==","shasum":"249d5137872d58d79faff479f6d7e801d102b28d","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.4.4.tgz","fileCount":315,"unpackedSize":531291,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe0zaLCRA9TVsSAnZWagAACSAP/3qAfA+U4tmsQ+dAJXup\nxS4AhVe3/R8sdEnIDRrkvoEutegz/3NI2KRsFYkriWJ86trncH7ewD18ei6q\nbWElh4b51evT5z22WKhEFRkJn2JqOOoxm/+AbQn0KxPggIEFWd4Iw9k8QfLv\ntGsh1JnraHfFikBDY2p29DrI0b7FBI5kV50mtf5qVPwMaFBnmSl/ZIGotT0H\n6yuW1OpxC9cz61sJg5ZL8cVG9yhWrwbrpMKxGfF46gdNrjeOaB05S+4m54br\n8+pbVeUS64rQdZ34HMGXPMJP27hDCv0atvfYJ7jjnbhjpOJM0ZzwLhuZgwZi\nQGPo4LZp839Q9M2DQ/Q+2Bs4U3eTNrJ0O+he8GhpDRMCgkQ5eZxoiHg+OwoK\n63cLoHfY28HS2dhQOUeZmjkU1xUzsd368VKWk5JWIeWx3xHOe9IYT9p2biXw\nzbuvdCz0vdr4LyP37aluzowFIaawNWrvJ0lnCGo3D+mAqhZMy6rE/mXbi+/4\nQa8twRYmV6o14CuC42ZpjvVp7RuaRIPLX2tClU9vtokxLaqtXicDf6lypyDB\nxaRpJjTunpjlxiJrSW9tax2HaNlh/fXmzIssG+3w2TerPB7gcEeMx0gwZUJq\nsWiyNqbd3JYyQo1PNh8xKXWbk4eG/KYr639/iBC9Ugh1QvkR/BkSrLYWMmYh\n+YB9\r\n=NVMY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBl3zeFqYuWjaY40s9yhVzYf1iKdvtamzNr8RPDLUHTTAiEAjaMtgM0PJjJ5v7KZyYc/ltCeYQcTI3nDj+XgB72ZWDY="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.4.4_1590900362480_0.2157577919589846"},"_hasShrinkwrap":false},"0.4.5":{"name":"ducks","version":"0.4.5","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"5f11d710a90893b8e62f76fdb158f8a41c76eca3","_id":"ducks@0.4.5","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-kFbqxL0PnAooYYp0LOg5Auqe82JvVLbwVcVUYOfRFWX5PKQxneCKIVPMJIOWcTAsocjMVLHXfZOdVsaeOTTZoA==","shasum":"dc1acbc71b10d3d23cb7617505dc4d750ef4cc19","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.4.5.tgz","fileCount":315,"unpackedSize":531472,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe00Z5CRA9TVsSAnZWagAARKoP/0+zjDR/7v4X5SUdXKOJ\nJWXYDsEZ7Strln29nPC0s6uN6tRoU+qHyxMX72mjdw3jEvCPVX2H6d7cVYnk\nEMXlb6HcjUchH1GWzun+Jm3pod25nHx9P3BuUewq5Pe3Lu2J5I/9FMT6klTD\n38j82UceE+/zl7ulqIGJlC2stWU0xLQAYlJk0AqpsfLlCrqctEqLc45KFpT9\nxie5JLkgwsAl9zT53lnwe6Vfwgdvx29mrdfV5/cRVjtAeV6foIuOaWVpFZJ4\nAlNS4NPjtOinkyyTaoYC97cE5zWWpFfW2EYdewkiGrSk2lwPx4ovGhLhmtDY\nfIWCjXF1k9iDw7nhdIK6c/Ujt9gA+5q5mUsKB14a3a4NUIHUuH/MDizJMbN0\nAYCXt7NdMX4DYbEin2BWm9KPfAw9ft1ZJxADovJ6AOHv0Qx6tbLEn8Cac0wO\nDo6Rc1RW4slUgLdJwtf6NzoynCsA3e9RWJ5JsQafqUo6yp7KC8FXZAB6WvYC\n9XyxRYhRYqfBbpLI2gmaxz/IlZXaJAQ1wtdVwpOvaQxnQx5L9Ltre6GXri+O\nn2PmB59VIBZum/FqGIU15NRy//7v6/GhEP2t6oNxVrUT155zt8uxyqUrsxNZ\np8JduCMty+s1hC94dQ1SFJMWt6JC2Xm+bhJGXM5uXBnXd7T61u7rwbgwOh96\nw/pV\r\n=4QUb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD+dWXqIJej9bpq3mirdzceHQ0xcqwfmoZ8XViSuQQL1AIgN1Biex60NPSvYe1nd6p0piwe4Ej40sdZPNlE7hEPTtg="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.4.5_1590904440755_0.3789926942019999"},"_hasShrinkwrap":false},"0.4.6":{"name":"ducks","version":"0.4.6","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"1ccdf48fed82565efe3a234bc244ea901f5dfce2","_id":"ducks@0.4.6","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-vMtUunUChI/XVknE2fpMcRL3FCphCWHo191ncq1pefWHrsunS2mpE/DUHJoqdrtgUwg18/Ykl2ZIy0dXOwdQhA==","shasum":"849664b9a2b1dd44acac3e66d08006e0a6933c82","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.4.6.tgz","fileCount":320,"unpackedSize":535138,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe00/CCRA9TVsSAnZWagAAthgP/RTDaH7tiOc8qX4YK9ml\nXJErCD+GVP0O5HkKdK0Qy5dXRAzdmWrZrmQl1r3QZakISoE4AXtS0G576H73\nfmFNeUr0D6mqNOpXjZFvBVGx69B/zZ8paJZPH0xcpyCmhWkAgavdoWkFuNy3\nte4y6N979AY0OYLiR1g03eG6RzYk/OnR2ulMIx2KFyq8nKEiFJblTDsEcJFp\nQSHHQ2fnK+5NsdxPnabDI141IASY4JRuhI9u3DjPMtxtX5laaYrYem9PK8BB\nf1LU39BmMafBuFTguBgCN003XhCVj9RdeJkfDNBwpH4Lbu2uyh6P5u4+DoN/\nPDvkdssMUJ5J/BJXT9aFmme20wsGdqWY3rB1+53eCANC+KYmylV+84CCT5Hg\nO3LbalMbgdwrWzOpDpcy9XOLb8yKRRQCXg+VB4bDyatfGCP/xkj9mqA1b9uG\n1KakrU2Tn2RpiKY/2Hy19ZanarXSHmizjeiLkDHdmpy0PQF8dy+OSvSOQGhw\nL9BeWi/wXVgjJds7tD0W6YWE4qDPLCKy8JLUrPvtLVx3Fqt6/S0ZulwlwuoX\nlRuxMZC0zi1cFW4t7Tk/qUmq9+J366T4r4w4GV2Zgaz68hohvsQ44T4E4X04\nuTADVadme6Q3/ARChdnVCanOw55yS50WRh6g61y2JzG8Fpg4pxYaQ2+EtGOK\nLI2l\r\n=sf3o\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICo8tbyEhDjHElrfpSO3KtwRQhwfo1Qm9g/2ib6UahMDAiAEoCcYFUZyeElv8vGpqYEjhl1yQeA32tn7tewDLVHaQw=="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.4.6_1590906817515_0.763078181005391"},"_hasShrinkwrap":false},"0.4.7":{"name":"ducks","version":"0.4.7","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"815d88251194971aae0fb574c4f77e035432f05d","_id":"ducks@0.4.7","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-5GEM24O4Kx/P7jtRfHyqqhx2lTkFi3OQFtEFfQkczTxY+8YdN8HBzCJnWfMgUXAcnppP4O4ANi6ZOp88KndZWQ==","shasum":"3bf2521e7f78f15384f2144428a15249448a45d4","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.4.7.tgz","fileCount":320,"unpackedSize":535206,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe06ydCRA9TVsSAnZWagAAZRMP/1t8hZ4XfN3P1tBzSGwG\naGlXlK60OaN4JXK8nzNler2TyB0ISUHU77Z+gFPm91QLdPN30JYgsYOha+la\nFV3XmQykUIHU1fvDFuXh69PkSVwUlhWxBtEa6qo3FB8DCe+1XVQ21Y4HT2Ve\nAgyDjH+SWzGt6nN4DRuJ2Pj7QsmKwzBRB23uXA9+RvSFK24PDEMNX3Hy7yl+\nuHlUw2a322e2iLclEhyyzEm2cy2H2Xna9RQ+Nf3hh7tjyOseIePGLQJovGli\ndZfszP3Y2KjyOzLOhMPxdNMY8VqnzBDTuzdskO/ZkSstFdRq4gdh9lCth+di\netW3sDrnZ+uTM9oWtBaHxVA9SRqklbWhATrZbCuBwr7iIXQsA44TD9KAfNnY\nIaAcECTrC9WdcW0VZKRoIPhTWD2OHfqx298Dfrr57ITkAG87xpxoT0wrERaG\nT1ytCFtxJm3YEme1GiAllHp/jolCKfs2slYDk84fdokSTIEP1gsLZJoP2Tq7\nZh1BX4uRp1sMPHbn05QJZy3uh8mnQJU9gptjnXakkTCzrsIyFNj7C/+4O2tM\niEsJHFA2kbtJNthEzG1S7Y+xk8YikCVEyqjlw/mbO2CJrImr9f/cYnM4zLGm\nwCaq6Za9ejrMwXtAgL54qQsuYulsjZILnW+FmlJPLl4NAUHc6yMr6uqlI+SO\njTHQ\r\n=w4QI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHykDYhhCQXX6w5d4/1yWau3ESXN5qvltgRUoKoPj3a3AiACHM1sf+54OFtX434na450GZZfjGbTKp0hz14lgeG6UA=="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.4.7_1590930588537_0.902462661248788"},"_hasShrinkwrap":false},"0.5.3":{"name":"ducks","version":"0.5.3","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Api Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following Ducks `Api`:\n\n    ```ts\n    export interface Api {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      sagas?: SagasMapObject,\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v12+, or Browser with ES2019 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Setup Ducks Api\n\nCreate the Ducks Api module file: `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Create Ducks & Ducksify Api\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({ counter: counterApi })\nconst counter = ducks.ducksify(counterApi)\n```\n\n### 3 Configure Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducks Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterApi  from './counter'    // Vanilla Duck: +1\nimport * as dingDongApi from './ding-dong'  // Observable Middleware\nimport * as pingPongApi from './ping-pong'  // Saga Middleware\nimport * as switcherApi from './switcher'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterApi,\n  switcher : switcherApi,\n  dingDong : dingDongApi,\n  pingPong : pingPongApi,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nThe above example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Api`s that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating the `Api` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDucksApi` that accepts a `Api` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Api`\n\nThe Ducks `Api` is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface).\n\nExample:\n\nDuck `Api` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions'\nimport * as operations  from './operations'\nimport * as selectors   from './selectors'\nimport * as types       from './types'\n\nimport reducer from './reducers'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is in charge of managing the `Api`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `ApisMapObject` to initialize the `Ducks` (`{ counter: counterApi }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Duck` class so that we will have a more convenience way to use it.\n\n1. Return all Ducks: `const { counter } = ducks.ducksify()`\n1. Return the Duck for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Duck for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({ counter: counterAPI })\nconst store = ducks.configureStore()\n\n// 1. Return all Ducks\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Duck for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Duck for api: `counterApi`\nconst counterByApi = ducks.ducksify(counterApi)\nassert(counterByApi === counter)\n```\n\nComparing the Api with the Duck (ducksified Api), we will get the following differences: (`counter` is the ducksified `counterApi`)\n\nFor `selectors`:\n\n```diff\n- counterApi.selectors.getTotal(store.getState().counter)()\n+ counter.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterApi.operations.tap(store.dispatch)()\n+ counter.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDucksApi()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDucksApi } from 'ducks'\nimport * as counterApi from './counter'\n\nvalidateDucksApi(counterApi) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)) Microsoft Regional Director \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"49666b51736783c8dd57942e0079672f1f7c4f15","_id":"ducks@0.5.3","_nodeVersion":"13.14.0","_npmVersion":"6.14.4","dist":{"integrity":"sha512-VN2bG3tgBZ6bsyp4JTQeuSObccHDkpidG/Vdqe+2ArPedEm4kyrLRRsRdi5XMz/lLXCVBuQ/nvL93jAuYx9Okw==","shasum":"0b4d31614984a8d4fbbb32274072ff4daae43b97","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.5.3.tgz","fileCount":310,"unpackedSize":532757,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe0+8mCRA9TVsSAnZWagAAFi8P/jdet3x73+0y3dRPaLuO\nV3SiZ8LRZco2My1nRPq7mW9aBD/EjUcM0KcPr8wipvXMdcnJdBsUyz3ASbRl\nMSCqJoywQkDzLcwsvunDjL+LRm+aiUSO6feiMnLmaWhnFxOMsThDXZR/6/kn\nVxV+hWkka+rbgCJaQVP4TdZMHqyTCeXos1zgoS893ITfjcxLiaQDN/MKW0RY\n4F6Pd5/w4P9/06AYNzTD/pus7TFcY9oa5n7FcpMp25BAUsSsOcJX7ZV3Y0Ox\nqORBav/Z2BVoM0gSBY+UufignjoBfs5GkVv9uaL+MXXeFjb5mZBBuSX6qLSx\nmObQJu7amkfwAjW1A/L0OKrE69hxETe1SWLMWq5ZAKKgy4XdfXbkkfmM52vi\nD9WcYy+1/7c16E4zjGtiYECsNQ0EW78/5REfu8/9JgFiMGi6PVqQ9PiruDYZ\n5AhTGwlOL1NyOyiJkILEREn43Yz0qtjsnArUott4IC1i6fiD3VrBf4aIyVie\nb+qqgej+2tb0ip2CqMMCVJfzbzL7NvkRpA+rW4iqb/2rYs9NQN/mo5LHjWCZ\nKIndnlBKxdW9aAAidbdNLIm8PSH2uSZ7M/xyOJbNnL28BISXxubSURaZxEWU\nkk5znfAG65jDI0nlajHHokSRrIeUOwi7fQyvIjItAa4zlK4pTpbLw/4G/2qb\nRPgv\r\n=fvNd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC3m9NNy+E/Gp2zF88+AeMyjL/q5qJKck70mMOX5osU8QIgF76cmKIYroqPjkhfbdaaEtLGx5tmJpHBHhaW/i9LCks="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.5.3_1590947622332_0.871129540677289"},"_hasShrinkwrap":false},"0.5.4":{"name":"ducks","version":"0.5.4","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Api Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following Ducks `Api`:\n\n    ```ts\n    export interface Api {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      sagas?: SagasMapObject,\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v12+, or Browser with ES2019 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Setup Ducks Api\n\nCreate the Ducks Api module file: `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Create Ducks & Ducksify Api\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({ counter: counterApi })\nconst counter = ducks.ducksify(counterApi)\n```\n\n### 3 Configure Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducks Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterApi  from './counter'    // Vanilla Duck: +1\nimport * as dingDongApi from './ding-dong'  // Observable Middleware\nimport * as pingPongApi from './ping-pong'  // Saga Middleware\nimport * as switcherApi from './switcher'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterApi,\n  switcher : switcherApi,\n  dingDong : dingDongApi,\n  pingPong : pingPongApi,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nThe above example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Api`s that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating the `Api` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDucksApi` that accepts a `Api` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Api`\n\nThe Ducks `Api` is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface).\n\nExample:\n\nDuck `Api` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions'\nimport * as operations  from './operations'\nimport * as selectors   from './selectors'\nimport * as types       from './types'\n\nimport reducer from './reducers'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is in charge of managing the `Api`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `ApisMapObject` to initialize the `Ducks` (`{ counter: counterApi }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Duck` class so that we will have a more convenience way to use it.\n\n1. Return all Ducks: `const { counter } = ducks.ducksify()`\n1. Return the Duck for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Duck for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({ counter: counterAPI })\nconst store = ducks.configureStore()\n\n// 1. Return all Ducks\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Duck for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Duck for api: `counterApi`\nconst counterByApi = ducks.ducksify(counterApi)\nassert(counterByApi === counter)\n```\n\nComparing the Api with the Duck (ducksified Api), we will get the following differences: (`counter` is the ducksified `counterApi`)\n\nFor `selectors`:\n\n```diff\n- counterApi.selectors.getTotal(store.getState().counter)()\n+ counter.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterApi.operations.tap(store.dispatch)()\n+ counter.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDucksApi()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDucksApi } from 'ducks'\nimport * as counterApi from './counter'\n\nvalidateDucksApi(counterApi) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)) Microsoft Regional Director \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"a47f845ebb6866505b52e80c40f7a448dbac8b08","_id":"ducks@0.5.4","_nodeVersion":"14.3.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-ucIAOAc4RZxWSpLOvXRZ9lHP7bslErpzdtg8ptod/3081ZR02YLpYAU16LuqnX6M56vklbZF2GpMUjpWdi6CCQ==","shasum":"49277a6dfbfef65f1b47866050f5791878db2b7b","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.5.4.tgz","fileCount":310,"unpackedSize":532761,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe0/BfCRA9TVsSAnZWagAAu3EQAJZqxnqjYACjIlCyfqtp\nesbGkEaEj2Am5IB9riGYczldjy9pgd6Xt8W2khgxJzdl1mGhxH7k6BptJpP8\nAT5CdPwOMik5zcGckECvFADhsCdfiWAwHQOPhk+iXK4QssgILyRCJPZ4LTDS\nmd3X9SZuTkhSP2L0Xq7XZ71bXm6MK9QZGf3S3w9G2iKOXl1fD0HzwxABxeJ9\nBZOmYPmzByP2YQsP5m2jD+ushoX6SNfqNXbkOugkV/F+M7CMHlEemuAcGCBB\nKqIQirWHSsCY0ehbR2bL42KTboTCqW+n/GN64oMylUHT7KpDsEKJU6+1SDGE\n+KWp/HFHZ1CtPQiK8M0qMKwVi8SOrW86ET0vc4kWt/RQmxhmHEeVmfXB7KLi\n4O5qd7dl34wKfEbw99fCxCAXDi27WyO+V6vcwR/73B6a4/mmd6kqW/uOUutP\nZpuv5N1Q2nixk19olUqCkXiZvePTR5QjAUJ1cAEoLGisXGNec/YSynlih34y\nwVoFa2bx55bL8VRt11AtSFoQBEcayg2fcpYJHk8j5UaOK/EeiWTl1fVdrb9X\n05V6Gq6Qs723TINcSKR9kxR5MjkRAM7OIshiqEwO/zMCU76tksoGfof8iMyM\n7JY1tPGTGCZLIM+qSV0bFGVeHeSvcCmovFoNhDvGqktMaNahuqV+WVSkZ/h0\nfumo\r\n=YGBz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCxrh0knpzfayzxetf8XJt3ruyGGwsGK0n3qCXiyq45ygIgdGD8fL9n65UfoRgrDG4llwzfEZrKpwEF8x6xonbkLNs="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.5.4_1590947934973_0.040463453282073125"},"_hasShrinkwrap":false},"0.5.5":{"name":"ducks","version":"0.5.5","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Api Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following Ducks `Api`:\n\n    ```ts\n    export interface Api {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      sagas?: SagasMapObject,\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v12+, or Browser with ES2019 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Setup Ducks Api\n\nCreate the Ducks Api module file: `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Create Ducks & Ducksify Api\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({ counter: counterApi })\nconst counter = ducks.ducksify(counterApi)\n```\n\n### 3 Configure Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducks Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterApi  from './counter'    // Vanilla Duck: +1\nimport * as dingDongApi from './ding-dong'  // Observable Middleware\nimport * as pingPongApi from './ping-pong'  // Saga Middleware\nimport * as switcherApi from './switcher'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterApi,\n  switcher : switcherApi,\n  dingDong : dingDongApi,\n  pingPong : pingPongApi,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nThe above example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Api`s that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating the `Api` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDucksApi` that accepts a `Api` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Api`\n\nThe Ducks `Api` is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface).\n\nExample:\n\nDuck `Api` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions'\nimport * as operations  from './operations'\nimport * as selectors   from './selectors'\nimport * as types       from './types'\n\nimport reducer from './reducers'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is in charge of managing the `Api`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `ApisMapObject` to initialize the `Ducks` (`{ counter: counterApi }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Duck` class so that we will have a more convenience way to use it.\n\n1. Return all Ducks: `const { counter } = ducks.ducksify()`\n1. Return the Duck for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Duck for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({ counter: counterAPI })\nconst store = ducks.configureStore()\n\n// 1. Return all Ducks\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Duck for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Duck for api: `counterApi`\nconst counterByApi = ducks.ducksify(counterApi)\nassert(counterByApi === counter)\n```\n\nComparing the Api with the Duck (ducksified Api), we will get the following differences: (`counter` is the ducksified `counterApi`)\n\nFor `selectors`:\n\n```diff\n- counterApi.selectors.getTotal(store.getState().counter)()\n+ counter.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterApi.operations.tap(store.dispatch)()\n+ counter.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDucksApi()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDucksApi } from 'ducks'\nimport * as counterApi from './counter'\n\nvalidateDucksApi(counterApi) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)) Microsoft Regional Director \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"511fbc36cdbca393b2ae3b04437b709640d35bda","_id":"ducks@0.5.5","_nodeVersion":"14.3.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-0VpHbOxkDP+2w05qtYQjxkNGV92qECYOK3ALk5j6lRKDaGWkO+16OQDU3buMyTCKS7d6+ejujwFPgYmrgeUC1w==","shasum":"ee11bf6eff632ab5220905dd44b84adf583dd1e3","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.5.5.tgz","fileCount":310,"unpackedSize":532980,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe1I1wCRA9TVsSAnZWagAAauUP/RJwWJE+uWtTGr0zhWUz\n/VK+CBHau0FRVX+Fq5FZXZrQ7WhvbCq/D8U8CEEk4X+H06ulRdoI4YHWUxVH\n2HkogAwYbyM1SFVOz5UJjoknx5SKA6QF9VuECUiTEVF+ksp0tLoecj5K+ylb\nbNMXSLLbubHm3kGc20V7Mc3Rqk7GrrtYi8ynHdvulhZx5qvNdFjoBLOoMMvJ\nrJTfdv7Mwn4bSaeO0a5twNXG8GG/c/raNQzwRHiz37sZBI0hFFRpHgmLNIQn\n7dOhiloa1E6JgxozjD4B7d4H99t/mLg0a48cBKjJE0BqIBMf88IWyJopqoPs\nkKu5pUQCCYobdptZtdQyZTDgCnuDbY7qGYBZuFe89EkQCB2GGZ+JiUGi55nG\nWKo0hiZrdttpoYLCpem9LOpwHf3uTt4dg60Md22+pSkkkjWovHxMckO4N2BL\n/MAFH6fPaFgktNFEitC1q7jfMzpN9oya0nZMYiNYkw+UBwsyHcswwI+vTquu\nYznWJyucMx19592VnACgPR4Tpu371Poycvq5Fld/LGmFSJ0hyEX5KFvdrs+W\n7SulBk9Zgb/0k3Ll7frO7K/L6gJQ5h78GUaUWFxAHaabSTPn+JkVbU/J+YlX\nVSAJq+cJQwTyrXv1oFccKwkYzQQwfoLyO6utMNNm3gXmqr3/aFnwYD0cfpUu\ndxZT\r\n=QCE/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCqgB8F9MqngrpvT+pXd65ZdMBTH64ZUhxcSWx3cPCDGAIgcDDeGyUMDGKmyh8CTzLSiqkS0KRhFdU0iXpoUJ5iCe0="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.5.5_1590988144063_0.8690906578977786"},"_hasShrinkwrap":false},"0.5.6":{"name":"ducks","version":"0.5.6","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Api Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following Ducks `Api`:\n\n    ```ts\n    export interface Api {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      sagas?: SagasMapObject,\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v12+, or Browser with ES2019 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Setup Ducks Api\n\nCreate the Ducks Api module file: `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Create Ducks & Ducksify Api\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({ counter: counterApi })\nconst counter = ducks.ducksify(counterApi)\n```\n\n### 3 Configure Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducks Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterApi  from './counter'    // Vanilla Duck: +1\nimport * as dingDongApi from './ding-dong'  // Observable Middleware\nimport * as pingPongApi from './ping-pong'  // Saga Middleware\nimport * as switcherApi from './switcher'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterApi,\n  switcher : switcherApi,\n  dingDong : dingDongApi,\n  pingPong : pingPongApi,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nThe above example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Api`s that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating the `Api` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDucksApi` that accepts a `Api` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Api`\n\nThe Ducks `Api` is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--api-interface).\n\nExample:\n\nDuck `Api` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions'\nimport * as operations  from './operations'\nimport * as selectors   from './selectors'\nimport * as types       from './types'\n\nimport reducer from './reducers'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is in charge of managing the `Api`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `ApisMapObject` to initialize the `Ducks` (`{ counter: counterApi }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Duck` class so that we will have a more convenience way to use it.\n\n1. Return all Ducks: `const { counter } = ducks.ducksify()`\n1. Return the Duck for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Duck for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({ counter: counterAPI })\nconst store = ducks.configureStore()\n\n// 1. Return all Ducks\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Duck for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Duck for api: `counterApi`\nconst counterByApi = ducks.ducksify(counterApi)\nassert(counterByApi === counter)\n```\n\nComparing the Api with the Duck (ducksified Api), we will get the following differences: (`counter` is the ducksified `counterApi`)\n\nFor `selectors`:\n\n```diff\n- counterApi.selectors.getTotal(store.getState().counter)()\n+ counter.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterApi.operations.tap(store.dispatch)()\n+ counter.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDucksApi()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDucksApi } from 'ducks'\nimport * as counterApi from './counter'\n\nvalidateDucksApi(counterApi) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)) Microsoft Regional Director \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"d86001a9d82f7d246396709894225f41cc8b2704","_id":"ducks@0.5.6","_nodeVersion":"14.3.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-UA1UNxgGtBxeCUEARPRzk5MXAJNzVqv6W13TkiuxMlDaizoeb3hc0E4Ekb3Gc+HVsg8+GrGUOaufy7uzOOMeyA==","shasum":"c244a0ff4b1adaf463b8727abd1cf245f307645d","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.5.6.tgz","fileCount":310,"unpackedSize":535925,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe1UwzCRA9TVsSAnZWagAAaFEQAIwI5UHbkdd6k8Z5HMMI\nsjIn+iKe+NF7rQ0OnO3mow5slCdL93gmYAr/frj6wnnVgYNigiMUTyNyotLf\nqBi8zxJRmTmc7sA233P4nDDiU1uEgwY2I1GJ58l8miGfpJURqtjgBUzO4BxN\n7InUBGFvRM9SU8PxoxhsVDQseIMkDNH+NEzCqZcnuq/kC3vjiXsuTd3PWLu0\nJpnRA6DhP9LybQN5ZqAjpAFYxxMFXnCwRY3aPtyJieYa3ty70e20tnFdJtim\nFoJ7vJez5rOeVlEWmEmCYQrdnLvdi4+4tJ+LJThVyU3ciaNxe/t5iS0elarQ\nJ0JHtAhfvTtOkTnNJdfT5TTpJCM4IeF159vET0RoDwSMVdPDulkcQs7Z01/h\njZiLxnGuuQiavg6iHE4V4kL3d7H0rhQdaSYmLZZlLSEXM8Ib/o71qfPTehjz\nDIhrGDF6JfNrSDS+Ce8qWR5lJfmpmJgrUsGUvnCCLJAXrGuBO0fF4ZqxplEb\nK0xqWiKioYqvqgZFkLdXCDNcRhZz8o2Xa56ZBjnypDgFdUX7Ib+dh1PyGLb/\nYj/BIAC8n3fcVDjCJqYxnsUJ/TrVOkCp8cuiyGYNNpanOLneDs9Z0bIVHHDc\n8YMtUi4o4tnIx9xqwPpiqdxIRfVMfvYVu26DfHcX9QAV/A0hUW/OOCeFjt3V\nlfhO\r\n=50qC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICjz6TxQ1563tZJNBN3+o8Ii2OLl35tM/V8tmfTfxzh2AiAY51UAsTn6ovYiXlkIa670ghSPv3tSMZ5p0muWeWdgcw=="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.5.6_1591036979135_0.757973370181328"},"_hasShrinkwrap":false},"0.6.1":{"name":"ducks","version":"0.6.1","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"e551fd09036e62cc2f8c5af50dc1b257221873fb","_id":"ducks@0.6.1","_nodeVersion":"14.3.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-5kpEzGSgIunPyzp+732KKLPwaA+aJjCppsJFG+wRWssIbOMvyseJc2jWq/AuIx2ML+Bwt0iQo5M0govgDjjgXQ==","shasum":"809264d03b84da55ed94429734dda16b17c51f33","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.6.1.tgz","fileCount":310,"unpackedSize":535927,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe1VPSCRA9TVsSAnZWagAApMQP/12zNlTgA+WI5fah7KF5\n7um4fKAjdFE67Q9Os/CK/M1KXEAUR32+ghxa4ZFgloHZDUQ4WJFhH1sQCuzv\nQk80zW7qMU8FS2b4iKP7qRCebIa0ODeXxgToVlT6DXncskAkiAaRIrXrBerI\ndVBv95r6Kd+7Mw029UYI1DQn9jGUKh8bfzqTG5wrwin4S1RS/t69NGWQirNs\nwJmgdHelgvZKiy2JIUShHVcnQ+0uyWFSjT7iCckkV4XYaHAt+z8++NoibEHM\n/0VWJzf7eIboqPP9JRjHKTXjEO710AH/yZNGwYz2vIO/qCDvF5KgokRI+8zv\nJVXJPEKgk5rMk3MlTSRJhI0YPkqgYKIO3zbsuRCY7j64F2mw3+SjX1CuPDgr\nuHU6umvCZnkDc29JJlxyCbszLNUdQdEW6WLd5C5qYXsLdkVrQU2RQ6UDXZD8\n5aHe2TWeHcXOBKYs2bmF6z8mwa2xUJd3pb0Q4GQOLpjXxWzL4D9efK5LbW4O\nnKhWeffX9UAiviOtJUwS0jAYoHNoXHA83NdTQ2Nwd+4sY3n8pvuqLhYsf2NB\nZhXyY0OIl7yIY1TBmCn+8uRd1VDp+M9Ov1w51N4Ui/BS1VuslA1ECKhzXr5s\nUmC7EeVACCXGkIK7kci034KYAYNDJ+8o/jc8aeZQ1wlBPZV6Tv62wl2h64xR\n9G/5\r\n=KcWO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFtcP2xGRurVXIFf8cT/4ncuyXiDGpUwAf0pt4DNLuspAiEA7hy9IVwVY7pVmlTb4kpZ0q8xOg4Jpz0psKfp4K8Bx8s="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.6.1_1591038930138_0.5171793899242911"},"_hasShrinkwrap":false},"0.6.2":{"name":"ducks","version":"0.6.2","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"178fb22a567231d27ff6b3bf780dade161b9297a","_id":"ducks@0.6.2","_nodeVersion":"14.3.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-s3HHquKzl2W1SlVDO0ESPCQLmu/6NyjK44EIBXJE4l0IemEVU6/0uKlpVtA//aO0QG8IHfkz+ZHgxlT4uX7tIw==","shasum":"8f7bfe40d7f5ab7050515a60f40c866d104a2ead","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.6.2.tgz","fileCount":310,"unpackedSize":535937,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe2SmaCRA9TVsSAnZWagAAFm0P+wec8s/x4UcPieEF69N3\nMC8fYzw0L+JiFIncz5Oalq5f8r1kE2KJdwMhaHKCW3bK3Su3SWrdACQ0azSf\nLneviAv+kfINCbiOWwB7PnQq9CMi/i9c4TmLThGY+QI6DzqiKM1pAKNnN7/x\nBiKBgexL8VIQ1oFzBU1awRb0bFtCKCKM3gJ6Y7ukuHiFvMgl6gS0hTQkovQz\nMNx8gvp1QF1C96DNOCpxGTpZEuy4yrD/jlDi2Fb2+5UombTb0bMvjQ3lde2L\nZjHudzKZtmTEOhDAw13qXiSZdFNUiD3BbIFYt/sKQoUUpBR9eVPmV4R0y29d\ng100kiI9G5uVm+CrSVxR4JqicWk8s4zOzyxZecC41rx57FdQUPnKv+mqfnKl\npze5bMN8AfiV6I+DD0B5uQIi6F79lghw8tBmqXZV5JgXCqkyuF0GHlnCQEj0\nK6Kn6oy2VOnYo1Pia4srXCr8CDg/5NCscOLIDK7xxO6SGVoAj3smM23XZH/U\nxDZS9V843KSjd5SYwB2X7zpDp3WWh8Lc/pSzoh7/fDoSMXWPMpXQQH3aZlQS\nrP25RynzNs7xQhwhlI93otj5SO1HWiO5rbp5zslUyHRgrJeOyrosMi2IuVU5\nJVpoZXCUslXwF223eiQ2XzwsUZpnLzjVU/YCONKJGxBtVg1LVZnOuvi/TFHT\n1BRV\r\n=rzDf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCyXdoO19uWZogVmH91f5wX5RdujUhnZOU2wj8eNMPZvwIgN6UR8d7ufLnUb9g+lROZFcrDVaULxJoi3v3vaKp9PJU="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.6.2_1591290266083_0.8618719638265182"},"_hasShrinkwrap":false},"0.7.2":{"name":"ducks","version":"0.7.2","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Ducksify Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following `Duck` interface:\n\n    ```ts\n    export interface Duck {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      sagas?: SagasMapObject,\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v12+, or Browser with ES2019 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Create Redux Reducer Bundle as a `Duck`\n\nFor example, let's create a Duck module file named `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Manage the Bundles with `Ducks` Manager\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterDuck from './counter'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst counter = ducks.ducksify(counterDuck)\n```\n\n### 3 Configure Redux Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducksify Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterDuck  from './counter'    // Vanilla Duck: +1\nimport * as dingDongDuck from './ding-dong'  // Observable Middleware\nimport * as pingPongDuck from './ping-pong'  // Saga Middleware\nimport * as switcherDuck from './switcher'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterDuck,\n  switcher : switcherDuck,\n  dingDong : dingDongDuck,\n  pingPong : pingPongDuck,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nThe above example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Redux Reducer Bundle`s with the `Duck` interface that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating your `Duck` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDuck` that accepts a `Duck` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Duck`\n\nThe `Duck` is a interface which is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface).\n\nExample:\n\n`Duck` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions'\nimport * as operations  from './operations'\nimport * as selectors   from './selectors'\nimport * as types       from './types'\n\nimport reducer from './reducers'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is the manager for `Duck`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `DucksMapObject` to initialize the `Ducks` (`{ counter: counterDuck }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksMapObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Bundle` class so that we will have a more convenience way to use it.\n\n1. Return all Bundles: `const { counter } = ducks.ducksify()`\n1. Return the Bundle for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Bundle for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterDuck from './counter'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst store = ducks.configureStore()\n\n// 1. Return all Bundles\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Bundle for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Bundle for api: `counterDuck`\nconst counterByApi = ducks.ducksify(counterDuck)\nassert(counterByApi === counter)\n```\n\nComparing the Duck with the Bundle (ducksified Duck), we will get the following differences: (`counterBundle` is the ducksified `counterDuck`)\n\nFor `selectors`:\n\n```diff\n- counterDuck.selectors.getTotal(store.getState().counter)()\n+ counterBundle.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterDuck.operations.tap(store.dispatch)()\n+ counterBundle.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDuck()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDuck } from 'ducks'\nimport * as counterDuck from './counter'\n\nvalidateDuck(counterDuck) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master\n\n### v0.8 (Jun 5, 2020)\n\nRenaming for better names with more more intuition.\n\n1. Rename `interface Api` to `interface Duck`\n1. Rename `class Duck` to `class Bundle`\n1. Rename `function validateDucksApi` to `function validateDuck`\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)) Microsoft Regional Director \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"edf9044509eae27522adf01f2898538aac9a6ff6","_id":"ducks@0.7.2","_nodeVersion":"14.3.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-VT1ur3cIeyjGx2bvbmwh8HNs5NxOtT7PsnBhr1Tyz+Me7zvnE5rxaBoeRdS7SIK1aLyOmZl7HZ2OvOFnxz9W5w==","shasum":"8d31c85bbc0bfa2545ce3404e007ac6a56bab70d","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.7.2.tgz","fileCount":345,"unpackedSize":586037,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe2gWdCRA9TVsSAnZWagAAq00P/03Vwu4gAYNoCikKZeSz\nuo8HuSqWTQYmyahThRq554B2UDbMtXchsT5LIWvlfMIyy7mxZn3WgV8lISqu\n0eWvd98dcu+TJQulra3Aq8D9LsyXJ5lZaQjSxcLKZl+8N/DdVZNdxbCFHBsL\nPk8oQjuelqr8AtrcZTZNTikH8BvbL8IyeN5sEw0mme7qgkMMa53E28ooDUF1\nFce8TUc3HWNkSpD3h6vvrVEb/rxKLybQmFp2ySMcn4emuEu0IW7ZiwkDZcLK\nDreLbcWXkG0RYmPWTU/4R/aKg4XxHIo63rHk48CvHxECIfzz8S9GeUeLT+7r\nX8JT/yfYVLyjhQph0IqZAIaAdlt+xxZjL4fx3QKKIbRLiJ8JTBHKPHIqKBvU\n2Wj3Z3jWzqwb0Y1Enl9PIMBcK/SeigltzxvSREqIhk46RQgNPB5RJW3B4wiD\nEnyDb4mTp6NA6vHR1JGRq3kAze1UOW12LBEP1VunltbYp/aZ+t2L3a/mqAPE\n2qLSm39QHG2ArgH7hjdEM7EB6LQYC+9ePCBG3c8532UaxxmycyTVVFB2Yjoh\nvVfNK7DKJJD4kZR/SMhV9GXkmaxWNxmWWLCC1XzGeNM9VVXe2GMUGycJMo0d\ng0oBfa7lDAy9kn2r6vfpfxbZfeC1BEj5EIYAh3npN+t/cCSoaJvIb7qdhi/d\ncIrW\r\n=h2Dw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCrLy0j/kXSmTCJipmNr3/cAq93Jh4K+272HP3tlY8hEwIhAMNbL5tO/QhJf+xZ0DlqHYC4Dr73Wyf/+NSJijL9lbP0"}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.7.2_1591346588961_0.7892200867871917"},"_hasShrinkwrap":false},"0.7.5":{"name":"ducks","version":"0.7.5","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Ducksify Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following `Duck` interface:\n\n    ```ts\n    export interface Duck {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      sagas?: SagasMapObject,\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v12+, or Browser with ES2019 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Create Redux Reducer Bundle as a `Duck`\n\nFor example, let's create a Duck module file named `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Manage the Bundles with `Ducks` Manager\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterDuck from './counter'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst counter = ducks.ducksify(counterDuck)\n```\n\n### 3 Configure Redux Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducksify Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\nTalk is cheap, show me the code: the following example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterDuck  from './counter'    // Vanilla Duck: +1\nimport * as dingDongDuck from './ding-dong'  // Observable Middleware\nimport * as pingPongDuck from './ping-pong'  // Saga Middleware\nimport * as switcherDuck from './switcher'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterDuck,\n  switcher : switcherDuck,\n  dingDong : dingDongDuck,\n  pingPong : pingPongDuck,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nI hope you will like this clean and beautiful `Ducksify` way with using Ducks!\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Redux Reducer Bundle`s with the `Duck` interface that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating your `Duck` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDuck` that accepts a `Duck` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Duck`\n\nThe `Duck` is a interface which is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface).\n\nExample:\n\n`Duck` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions'\nimport * as operations  from './operations'\nimport * as selectors   from './selectors'\nimport * as types       from './types'\n\nimport reducer from './reducers'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is the manager for `Duck`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `DucksMapObject` to initialize the `Ducks` (`{ counter: counterDuck }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksMapObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Bundle` class so that we will have a more convenience way to use it.\n\n1. Return all Bundles: `const { counter } = ducks.ducksify()`\n1. Return the Bundle for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Bundle for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterDuck from './counter'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst store = ducks.configureStore()\n\n// 1. Return all Bundles\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Bundle for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Bundle for api: `counterDuck`\nconst counterByApi = ducks.ducksify(counterDuck)\nassert(counterByApi === counter)\n```\n\nComparing the Duck with the Bundle (ducksified Duck), we will get the following differences: (`counterBundle` is the ducksified `counterDuck`)\n\nFor `selectors`:\n\n```diff\n- counterDuck.selectors.getTotal(store.getState().counter)()\n+ counterBundle.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterDuck.operations.tap(store.dispatch)()\n+ counterBundle.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDuck()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDuck } from 'ducks'\nimport * as counterDuck from './counter'\n\nvalidateDuck(counterDuck) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master\n\n### v0.8 (Jun 5, 2020)\n\nRenaming for better names with a better straightforward intuition.\n\n1. Rename `interface Api` to `interface Duck`\n1. Rename `class Duck` to `class Bundle`\n1. Rename `function validateDucksApi` to `function validateDuck`\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)), Microsoft Regional Director, \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"122db41f0d9bf480f2ef01f93cda9915f9bb5ee5","_id":"ducks@0.7.5","_nodeVersion":"14.3.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-pSq6f13KVbvmaOEiwIpKJCG8K67QgB/pRn6D5BDlcMJFWYZBenfVt9gXSuZPKOGse8aIfl43R7LUtVSWFznJPg==","shasum":"b74308bf40101150b178e3ff25faac907fcc533d","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.7.5.tgz","fileCount":345,"unpackedSize":586171,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe2gnGCRA9TVsSAnZWagAAHZQP/2FsYn6sz/MWOdkJKJeR\nQSyNSeY5YZJyO2Lec7n6rLHeQilNeban0oCtSt6KWC1OielLPStulBwKW4FA\njHagzdOBUZ9+lJ91l8cPzbdG+Mm+1yA3R8I000D9cXMzihPs7d4/b/Py3BXk\n/OZZCp2FK9QefjQXXQuHGRm8QS3lizi46wpzMyuCkAIkmS6DVkRf4yn89uXx\nfLD0XXQCLKx77i+kDuSSUMfB5xNckpqqq/QhrNhtkZmWL/JTNOCemiLnV+Kh\nk/01RRJc0UsYlGolVV1UgiriKBb3ZakSQxNKNL81TX6EvWnMX4WPGOdbsBS8\n2vscBBOiF9+MZR1eW3m130G2DLw94YCJPt4wSssCwpE8cjjl1YY8Y/DkBW5V\nqqvw5CQVlnU6fjLEYLPsZbHnU0VE4ATmCgAtX9CyuCUBnV0HTWhMDAE8r+GV\n2uRTCLfsWlxQpUw7bxXQ+sSVCW/nkxVzVUAOkMvtjGONJH5GJIRQ9zGLJbSE\nudnpC3LKunIXp66V/NxHgIxTGykPgQq0YiTVpFKkcEPENrcZMNfzEDqzNiGS\npgjekW10F/qTZl3mZosMAaBOIzSvi12YwSjkIyvkyWiw6T1Eyut9PsPSLS8Y\nMNBpW/lFQZeG107xXhFj7YYsYRR+Ha6aVyvRrxOeCNRi8ZFMKU9WeZ0bjBBR\nb7Ob\r\n=FszQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIA7R4WVep9UNgUq++xYo1qPakb2x52/CG7Bg1abT/J5TAiBGAMxSPi2C8ReHF6TxmCXpeaCPC91Rg8lHB3RTXx9l7Q=="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.7.5_1591347654050_0.034551848124336315"},"_hasShrinkwrap":false},"0.7.6":{"name":"ducks","version":"0.7.6","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Ducksify Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following `Duck` interface:\n\n    ```ts\n    export interface Duck {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      sagas?: SagasMapObject,\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v12+, or Browser with ES2019 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Create Redux Reducer Bundle as a `Duck`\n\nFor example, let's create a Duck module file named `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Manage the Bundles with `Ducks` Manager\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterDuck from './counter'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst counter = ducks.ducksify(counterDuck)\n```\n\n### 3 Configure Redux Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducksify Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\nTalk is cheap, show me the code: the following example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterDuck  from './counter'    // Vanilla Duck: +1\nimport * as dingDongDuck from './ding-dong'  // Observable Middleware\nimport * as pingPongDuck from './ping-pong'  // Saga Middleware\nimport * as switcherDuck from './switcher'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterDuck,\n  switcher : switcherDuck,\n  dingDong : dingDongDuck,\n  pingPong : pingPongDuck,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nI hope you will like this clean and beautiful `Ducksify` way with using Ducks!\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Redux Reducer Bundle`s with the `Duck` interface that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating your `Duck` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDuck` that accepts a `Duck` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Duck`\n\nThe `Duck` is a interface which is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface).\n\nExample:\n\n`Duck` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions'\nimport * as operations  from './operations'\nimport * as selectors   from './selectors'\nimport * as types       from './types'\n\nimport reducer from './reducers'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is the manager for `Duck`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `DucksMapObject` to initialize the `Ducks` (`{ counter: counterDuck }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksMapObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Bundle` class so that we will have a more convenience way to use it.\n\n1. Return all Bundles: `const { counter } = ducks.ducksify()`\n1. Return the Bundle for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Bundle for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterDuck from './counter'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst store = ducks.configureStore()\n\n// 1. Return all Bundles\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Bundle for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Bundle for api: `counterDuck`\nconst counterByApi = ducks.ducksify(counterDuck)\nassert(counterByApi === counter)\n```\n\nComparing the Duck with the Bundle (ducksified Duck), we will get the following differences: (`counterBundle` is the ducksified `counterDuck`)\n\nFor `selectors`:\n\n```diff\n- counterDuck.selectors.getTotal(store.getState().counter)()\n+ counterBundle.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterDuck.operations.tap(store.dispatch)()\n+ counterBundle.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDuck()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDuck } from 'ducks'\nimport * as counterDuck from './counter'\n\nvalidateDuck(counterDuck) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master\n\n### v0.8 (Jun 5, 2020)\n\nRenaming for better names with a better straightforward intuition.\n\n1. Rename `interface Api` to `interface Duck`\n1. Rename `class Duck` to `class Bundle`\n1. Rename `function validateDucksApi` to `function validateDuck`\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)), Microsoft Regional Director, \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"1e2a1591dee360eb306f62f610911a4bdc953f38","_id":"ducks@0.7.6","_nodeVersion":"14.3.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-xnZff+p7grDPJSn3tRh+SfBFdwxGBXPDrDG54dIyym2hP56PTwHtzYQFcQ47ef4rmHCqiUIUOjS+Yve34aP6tw==","shasum":"686acee540fd0a84f4c0ecd7514bf0cfc75b4e0e","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.7.6.tgz","fileCount":345,"unpackedSize":586472,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe2vwyCRA9TVsSAnZWagAAtFMP/ivTdawlOyiLFI+4hbS4\nr0OW7nEoh3pF7XU/Ua1m/ALM1XjvdDX2n7Z0UadYRIbddOBc8Ptw2yVnaP3S\n2nOXheFgXZQO/KwQf18BXSO685eFTj+2ho1EWvDCI0quwgSVg4w/HzINkhbM\nqOeKypbATc1RzU/zA53+xYXYUaKKVLNATtyCBi9U+AkXPzEZAaGRv1/riOSA\n7AqhWSLVm1N53gfEvv1dX0mASIjlXt0nPDUlGoHe/jiqzF+oNyKngy+kvjPX\nOrekXz1rn6d7fid8xIrIjWiuzkEcJgr639i1F719XXPxnJ1N5sqIKHDcx6Ce\nW2wp+p5aLdKGuKZ9NAROgA5KMdlNDb6BPCctqyzGmtNy1BoOC1cyz9WIr9kz\ny9ffGvcGJAn0cJJ8ygBd7KT3SqQGa1+ZI6OpJCaK+fJZ88zUVBLOmmRFnMJ4\nv04Axt+PO55+59heYFvg4yJX6RwSc9b3GMVD/PwnEdy7t82RiCMdun77+egs\n7p7u55YgDD79QTxh3Xhe45rrbAy7yt0TAlHhMj90CcnnQCplEAdADZ5U/UXP\nbmQ8ttj+N04+g2OARbx6Og+rChECZVKWXZNblpT2qNX/bOXCPcVRew1stBwg\nI/s5G2whHniJXCThgG9RDhGT45BKjiRaOLDnLf0JUJzvhpBt1qq9lFk2hMkn\nZ2fm\r\n=QlV9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDq53kCUGcFKn+2oyHMPHnBKpKoXHPFJXNjVpl6mOTELAIgKpYb976WO+4LtTiO/MIsDx9k33LaJiRfmvM+hYJe/+U="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.7.6_1591409713891_0.5213922307321031"},"_hasShrinkwrap":false},"0.8.1":{"name":"ducks","version":"0.8.1","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"27aefecfe69dce2bd38c48faa5d72a8e2aac8656","_id":"ducks@0.8.1","_nodeVersion":"14.3.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-JG5enJSw46wo1TrrtV9G1c7Dhi1sR8y0c9MbHJB7A0dxjdB8TgbSi91ronytIXSqe0KhwlmQZVSIwrVoB0S5OA==","shasum":"c2a8e67aa754f4cb949d312746b652e42f8e19da","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.8.1.tgz","fileCount":345,"unpackedSize":586474,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe2vxwCRA9TVsSAnZWagAAbCsP/3Zrf0cUtVgATrAdRZQk\nKierU2NTMu43ELgUT6rfjUtaXLeo6L2+mEREnT2IH05BeMst92dHYJiPebqm\nin/iCncTRQ+KLTXIqYH3+AGe2JeLkp7a6XKNsjdQ13VBS/A9aur3MBlHGane\nBlkrGu5P6FpHuUoj3kcV/xCV9zvRBHD090wlNASTfyvDuRWgJ2RLCIkduatG\nIQSLzigkn5ysNST41vjyMRqNDnMC4kfnzQC/hCxQX7j0QC0hGS/xT3ytXuEg\nFoE1cS2MgI25zF6RGA/IaBpeVKSG9tpUboiWT/fp8DolCgx9omhbvZR5Bp/l\nAPvbZ0QjQMlCt+IDEP+kscUnE0VMV3fiKbFvQU4NRP8VgXG5FrM68m7iqH0v\nBF7XpfwFOfbq40yCWotv0X6TrkGgiRMKeIwHwlcxQwOgNfa2Z7qGiYjYFYZ4\nN6FC3uJRr7yBQLuWs+/imK3G0U7C8Es0cZJDN8VRbBhDjKRDIb9dig2xRrwA\nQOgmxjG7eweLMSzIK3LXRY93+xtU5nUm6VVeMgcCXLr7SkkvJ5f/45apiZ9E\nxq+KKF8fLUobXEjjdoaxE6ZWyKdb//QkfcS7ewDUmwIGlKvYHKUlaEKXrXuO\neQI6p7ds99lc+IqPT2IlJHzSsGXwYqS/6T1AYdBrWQsmAd0ffFqBxrNDjvXx\nd8er\r\n=JhYs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCicHUQUCjD53P/FqZPGjQ/sHCR0oIhxGp+ktqpeGtXbwIhAJM111nIQDdLvz8wBjKxvkN1fuBCQqRVnhR4jr8tjobh"}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.8.1_1591409775361_0.5653292422091394"},"_hasShrinkwrap":false},"0.10.1":{"name":"ducks","version":"0.10.1","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"40deb29378660ac52ca2f91c91064833d83bde34","_id":"ducks@0.10.1","_nodeVersion":"14.3.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-+ZQ9NvaTHxXcRwW1TwfH5SBs19dQgVHzyi2deYfQKJlZ4X+tMb8pOczF5Cq947UZI2QUHGi4XJtf9X887qNVSw==","shasum":"f872e53d07ae5dde9224c8151f7f9b0a5504ea7b","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.10.1.tgz","fileCount":345,"unpackedSize":587551,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe21NBCRA9TVsSAnZWagAAavEP/0cmDgl+CIYZVJdegmwW\nX6WX4yYAPO86PNnt4IQWxlnSFukT68yTOejsq2sMj98ABmiJmAB/2ger96xw\nTfhb7SK7NyHNGyKmvtED4RiKHmhunxpeCQaCcjkfJw1bJi6AXqKxDGTx6SsT\n+67wMpGf0zBt6ar74we99jEVQ7TYR5UkGn72DuUfIoQuoQGmCC+p1rJFpPWl\nqs3HhxgcCcVk84R88tvfP7gxaX5pOp9fZR0GDfNmMd9lMWNWlb4mlIIfe5yw\nDTyDW4J3sIjMSHHcIs6ZSVsEumSl69S50yPLVgJ90P9cq2ptMqOPYp2EFPg9\nkmesuIbN/p2QRHXp4h3vJ6HGJPgATDtKkdSB0fpwrXeLS0FvkYs+rMGjcLDj\nURG8Lcfi7wU5i2MvBeOesZAdCq1PQALegd4sZnZQ1b17e/ELVEkbNJZ5g83F\n+Z2fvkN4BMA9qBlw/GA3kSgM0JPG0X/AAmKxa/MrSIK6CRnNjBx6T2tyhM82\nwPZ3yJWk7QmsA491kXvZyUHtggHUg5UwkesNRuCOHLLCPzDGiboV3+ibDFJg\nwmkSlE4xN3sFVAHdCzr4u53ZE2UjM2QfYHrSNO/Wcvurmy50Xh8YMIMZiEOO\nuvSGQdMHPZyjs3OnbRr+akFQ4chMBgUc9im13IXh0N9qVfYmPJcGZE44ofsi\ncl/m\r\n=njgh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC3dYVzKxd89KUvcDIEbIWdVf3hG2k1maK+0i2E+KQEUQIhAPq/G3v7iSS0ThLwJs6bL16glV8oglw4OZ5AeFcx1UHL"}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.10.1_1591432000954_0.398985482884471"},"_hasShrinkwrap":false},"0.10.2":{"name":"ducks","version":"0.10.2","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","main":"dist/src/index.js","typings":"dist/src/index.d.ts","directories":{"doc":"docs"},"scripts":{"clean":"shx rm -fr dist/*","dist":"npm run clean && tsc","pack":"npm pack","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --noEmit","start":"npm run quack","quack":"ts-node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"blue-tape -r ts-node/register \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","dependencies":{},"devDependencies":{"@chatie/eslint-config":"^0.8.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.10.1","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","glob":"^7.1.6","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","redux-observable":"^1.2.0","redux-saga":"^1.1.3","shx":"^0.3.2","tstest":"^0.4.10","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux":"^4.0.5"},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"4891e85dc2f6bb4d27e58a7f51435d425f307c66","_id":"ducks@0.10.2","_nodeVersion":"14.3.0","_npmVersion":"6.14.5","dist":{"integrity":"sha512-42MywaxznqG+bLGNs40AY0957S3zXxBOzBF+V9pIW2gj1nSWfs0AYkeYpXhkTRPO1RkKwlFoVFTKy9G7ugAQvg==","shasum":"25613b200415d62ec223006d7dfde86a2605bfca","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.10.2.tgz","fileCount":345,"unpackedSize":588420,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe21TFCRA9TVsSAnZWagAAb+sP/3aaJv9ZHzC2jVRTR0+Q\nQHnKGRd8ONWqvXBJpVHxxSLEaIbcJiyR/eBtQqsVxta5DozLqzLomOC9sUS8\nzLDKbk4GRBDE1tJ6ZXbiZBwJ9A0NiDDb0chMDCyTFWz75e+kB7ybmr0rqxd3\n39cWPRBWh4mgsrIg3P+99p6e7DWZuGyaQ+6oe3uUqO0V09FVlsCl39Xnkx/h\nCTJfPAxN6MfFIcvLUSzq0hFj+ToedHDEviOo4C5q9edlaletG+qYgTfqXNR2\nE1BBUisq0MDHN8ShHthaLjsUskV7TKo66f8raYQzj4NfIoIz2b5+ZIe5LB7C\nxzBhdp4xwd9yN8S1k7jL8soG/e5zpWxgHsLs9HBUAgdB9HFMTNdu7lDsEJn8\nPt+gqtAdVp/mJPgs7F6kof0ocbylvkl6LiHzjtakuvTbJVMXZnMzQgkgm/0+\nTzez31llZjKTesSTzuaM38BndwVG00hI38MmgQNCM2HewaBtzCg3xzt8jfj2\nb1gwG7sQyumvMnpkVttJy4mAoLfuYgFIpxHYUKdDfkrjs2V9865BsgxJtris\nKZXXjrxGGMJE9SzB7uhDpqcQ7Ye4Dqe3HeWz3Qx7+eBBijsdPXxUgBEg+MgU\nnKmpm1Q211zMOMpzJKMgQeWnlYBIs6pzAGjVxMcMmmkOC4EtMGaMf95QK3Kx\nJOiU\r\n=HB9y\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCd4BIkNd/5hJDPpewMGnCgc1bOsCYMhZGugMchF706BwIgYObjI1PNDYk2c1wLT0EhCIGRSyjRTNz5b90EFuwhMq8="}]},"maintainers":[{"name":"gobwas","email":"gobwas@gmail.com"}],"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.10.2_1591432389027_0.17095278461019103"},"_hasShrinkwrap":false},"0.11.5":{"name":"ducks","version":"0.11.5","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=14"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --isolatedModules --noEmit","start":"npm run quack","quack":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"tap --node-arg=--loader=ts-node/esm --node-arg=--no-warnings \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","devDependencies":{"@chatie/eslint-config":"^0.14.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.20.2","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","@types/redux-saga":"^0.10.5","cross-env":"^7.0.3","glob":"^7.1.6","npm-run-all":"^4.1.5","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","rxjs":"^7.3.0","shx":"^0.3.3","tstest":"^0.5.16","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"dependencies":{"redux-observable":"^2.0.0-rc2"},"peerDependencies":{"redux":"^4.0.5"},"tap":{"check-coverage":false},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Ducksify Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following `Duck` interface:\n\n    ```ts\n    export interface Duck {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      // Disabled temporary. See: https://github.com/huan/ducks/issues/4\n      // sagas?: SagasMapObject,\n\n      setDucks?: (ducks: Ducks<any>) => void\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v14+, or Browser with ES2020 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Create Redux Reducer Bundle as a `Duck`\n\nFor example, let's create a Duck module file named `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Manage the Bundles with `Ducks` Manager\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst counter = ducks.ducksify(counterDuck)\n```\n\n### 3 Configure Redux Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducksify Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\n### Talk is cheap, show me the code\n\nThe following example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterDuck  from './counter.js'    // Vanilla Duck: +1\nimport * as dingDongDuck from './ding-dong.js'  // Observable Middleware\nimport * as pingPongDuck from './ping-pong.js'  // Saga Middleware\nimport * as switcherDuck from './switcher.js'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterDuck,\n  switcher : switcherDuck,\n  dingDong : dingDongDuck,\n  pingPong : pingPongDuck,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nI hope you will like this clean and beautiful `Ducksify` way with using Ducks!\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Redux Reducer Bundle`s with the `Duck` interface that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating your `Duck` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDuck` that accepts a `Duck` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Duck`\n\nThe `Duck` is a interface which is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface).\n\nExample:\n\n`Duck` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions.js'\nimport * as operations  from './operations.js'\nimport * as selectors   from './selectors.js'\nimport * as types       from './types.js'\n\nimport reducer from './reducers.js'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is the manager for `Duck`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter.js'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `DucksMapObject` to initialize the `Ducks` (`{ counter: counterDuck }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksMapObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Bundle` class so that we will have a more convenience way to use it.\n\n1. Return all Bundles: `const { counter } = ducks.ducksify()`\n1. Return the Bundle for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Bundle for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst store = ducks.configureStore()\n\n// 1. Return all Bundles\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Bundle for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Bundle for api: `counterDuck`\nconst counterByApi = ducks.ducksify(counterDuck)\nassert(counterByApi === counter)\n```\n\nComparing the Duck with the Bundle (ducksified Duck), we will get the following differences: (`counterBundle` is the ducksified `counterDuck`)\n\nFor `selectors`:\n\n```diff\n- counterDuck.selectors.getTotal(store.getState().counter)()\n+ counterBundle.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterDuck.operations.tap(store.dispatch)()\n+ counterBundle.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDuck()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDuck } from 'ducks'\nimport * as counterDuck from './counter.js'\n\nvalidateDuck(counterDuck) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master v0.11 (Sep 2021)\n\n1. Disable `saga` support temporary due to ([#4](https://github.com/huan/ducks/issues/4))\n1. ES Modules support\n\n### v0.10 (Jun 6, 2020)\n\nAdd `setDucks()` to `Duck` API interface,\nso that all the `Duck` can get the `Ducks` instance\n(if needed, by providing a `setDucks()` method from the API),\nwhich helps the `Duck`s talk to each others.\n\n### v0.8 (Jun 5, 2020)\n\nRenaming for better names with a better straightforward intuition.\n\n1. Rename `interface Api` to `interface Duck`\n1. Rename `class Duck` to `class Bundle`\n1. Rename `function validateDucksApi` to `function validateDuck`\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Badge\n\n### Powered by Ducks\n\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n### Ducksify\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)), Microsoft Regional Director, \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"d48bf58c038af3e4e0e1b5b042e5310bd1b946a4","_id":"ducks@0.11.5","_nodeVersion":"16.9.1","_npmVersion":"7.21.1","dist":{"integrity":"sha512-f1ENlqAkyAUDAFVukn9UHtw2DEtKWUhJ5MfcIFjhDaNIvUT4PbLp7FflzPvW23/1lnCQru1SWpGJs4BxbVU/vA==","shasum":"2bfc8643cd08d9c1b6327f5314023425b7791969","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.11.5.tgz","fileCount":561,"unpackedSize":676015,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE+LrBD/krErJoJOPAR8A5MmAdExrM20NR02mrWYY5ZeAiEA7sf8Ik4OJUA/xmehF/+fuHp/yRtacebjrRhaWkbjYeY="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.11.5_1631972642386_0.5563950590478361"},"_hasShrinkwrap":false},"0.11.6":{"name":"ducks","version":"0.11.6","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=14"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --isolatedModules --noEmit","start":"npm run quack","quack":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"tap --node-arg=--loader=ts-node/esm --node-arg=--no-warnings \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","devDependencies":{"@chatie/eslint-config":"^0.14.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.20.2","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","@types/redux-saga":"^0.10.5","cross-env":"^7.0.3","glob":"^7.1.6","npm-run-all":"^4.1.5","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","rxjs":"^7.3.0","shx":"^0.3.3","tstest":"^0.5.16","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"dependencies":{"redux-observable":"^2.0.0-rc2"},"peerDependencies":{"redux":"^4.0.5"},"tap":{"check-coverage":false},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Ducksify Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following `Duck` interface:\n\n    ```ts\n    export interface Duck {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      // Disabled temporary. See: https://github.com/huan/ducks/issues/4\n      // sagas?: SagasMapObject,\n\n      setDucks?: (ducks: Ducks<any>) => void\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v14+, or Browser with ES2020 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Create Redux Reducer Bundle as a `Duck`\n\nFor example, let's create a Duck module file named `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Manage the Bundles with `Ducks` Manager\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst counter = ducks.ducksify(counterDuck)\n```\n\n### 3 Configure Redux Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducksify Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\n### Talk is cheap, show me the code\n\nThe following example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterDuck  from './counter.js'    // Vanilla Duck: +1\nimport * as dingDongDuck from './ding-dong.js'  // Observable Middleware\nimport * as pingPongDuck from './ping-pong.js'  // Saga Middleware\nimport * as switcherDuck from './switcher.js'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterDuck,\n  switcher : switcherDuck,\n  dingDong : dingDongDuck,\n  pingPong : pingPongDuck,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nI hope you will like this clean and beautiful `Ducksify` way with using Ducks!\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Redux Reducer Bundle`s with the `Duck` interface that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating your `Duck` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDuck` that accepts a `Duck` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Duck`\n\nThe `Duck` is a interface which is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface).\n\nExample:\n\n`Duck` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions.js'\nimport * as operations  from './operations.js'\nimport * as selectors   from './selectors.js'\nimport * as types       from './types.js'\n\nimport reducer from './reducers.js'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is the manager for `Duck`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter.js'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `DucksMapObject` to initialize the `Ducks` (`{ counter: counterDuck }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksMapObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Bundle` class so that we will have a more convenience way to use it.\n\n1. Return all Bundles: `const { counter } = ducks.ducksify()`\n1. Return the Bundle for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Bundle for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst store = ducks.configureStore()\n\n// 1. Return all Bundles\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Bundle for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Bundle for api: `counterDuck`\nconst counterByApi = ducks.ducksify(counterDuck)\nassert(counterByApi === counter)\n```\n\nComparing the Duck with the Bundle (ducksified Duck), we will get the following differences: (`counterBundle` is the ducksified `counterDuck`)\n\nFor `selectors`:\n\n```diff\n- counterDuck.selectors.getTotal(store.getState().counter)()\n+ counterBundle.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterDuck.operations.tap(store.dispatch)()\n+ counterBundle.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDuck()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDuck } from 'ducks'\nimport * as counterDuck from './counter.js'\n\nvalidateDuck(counterDuck) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master v0.11 (Sep 2021)\n\n1. Disable `saga` support temporary due to ([#4](https://github.com/huan/ducks/issues/4))\n1. ES Modules support\n\n### v0.10 (Jun 6, 2020)\n\nAdd `setDucks()` to `Duck` API interface,\nso that all the `Duck` can get the `Ducks` instance\n(if needed, by providing a `setDucks()` method from the API),\nwhich helps the `Duck`s talk to each others.\n\n### v0.8 (Jun 5, 2020)\n\nRenaming for better names with a better straightforward intuition.\n\n1. Rename `interface Api` to `interface Duck`\n1. Rename `class Duck` to `class Bundle`\n1. Rename `function validateDucksApi` to `function validateDuck`\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Badge\n\n### Powered by Ducks\n\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n### Ducksify\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)), Microsoft Regional Director, \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"f416043b96904e4ff02f11e29d3ef1cb9250b3cf","_id":"ducks@0.11.6","_nodeVersion":"16.9.1","_npmVersion":"7.21.1","dist":{"integrity":"sha512-fAlNKoSg0keYDTTDuDwFLpneXty/ynyv6Sd1SYHB+5OWLbR27LmBXog+FwzCyk7wVv79ROpm+9ozHLJuEyGw2Q==","shasum":"46fc9fa0d939560f151991cbd4c6778e1b041e2c","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.11.6.tgz","fileCount":561,"unpackedSize":676015,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDlsOM4a5O9NZ6v+xL04werjH2kUiB7Y5wLQ4ywJQXAowIhANBrDJ5P/WCHy0y7K+8LW86jYzKXTwZCEB/CeKfDZM+H"}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.11.6_1631972748188_0.43709514019038576"},"_hasShrinkwrap":false},"0.11.7":{"name":"ducks","version":"0.11.7","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=14"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --isolatedModules --noEmit","start":"npm run quack","quack":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"tap --node-arg=--loader=ts-node/esm --node-arg=--no-warnings \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","devDependencies":{"@chatie/eslint-config":"^0.14.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.20.2","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","@types/redux-saga":"^0.10.5","cross-env":"^7.0.3","glob":"^7.1.6","npm-run-all":"^4.1.5","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","rxjs":"^7.3.0","shx":"^0.3.3","tstest":"^0.5.16","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"dependencies":{"redux-observable":"^2.0.0"},"peerDependencies":{"redux":"^4.0.5"},"tap":{"check-coverage":false},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Ducksify Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following `Duck` interface:\n\n    ```ts\n    export interface Duck {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      // Disabled temporary. See: https://github.com/huan/ducks/issues/4\n      // sagas?: SagasMapObject,\n\n      setDucks?: (ducks: Ducks<any>) => void\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v14+, or Browser with ES2020 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Create Redux Reducer Bundle as a `Duck`\n\nFor example, let's create a Duck module file named `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Manage the Bundles with `Ducks` Manager\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst counter = ducks.ducksify(counterDuck)\n```\n\n### 3 Configure Redux Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducksify Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\n### Talk is cheap, show me the code\n\nThe following example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterDuck  from './counter.js'    // Vanilla Duck: +1\nimport * as dingDongDuck from './ding-dong.js'  // Observable Middleware\nimport * as pingPongDuck from './ping-pong.js'  // Saga Middleware\nimport * as switcherDuck from './switcher.js'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterDuck,\n  switcher : switcherDuck,\n  dingDong : dingDongDuck,\n  pingPong : pingPongDuck,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nI hope you will like this clean and beautiful `Ducksify` way with using Ducks!\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Redux Reducer Bundle`s with the `Duck` interface that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating your `Duck` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDuck` that accepts a `Duck` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Duck`\n\nThe `Duck` is a interface which is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface).\n\nExample:\n\n`Duck` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions.js'\nimport * as operations  from './operations.js'\nimport * as selectors   from './selectors.js'\nimport * as types       from './types.js'\n\nimport reducer from './reducers.js'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is the manager for `Duck`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter.js'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `DucksMapObject` to initialize the `Ducks` (`{ counter: counterDuck }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksMapObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Bundle` class so that we will have a more convenience way to use it.\n\n1. Return all Bundles: `const { counter } = ducks.ducksify()`\n1. Return the Bundle for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Bundle for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst store = ducks.configureStore()\n\n// 1. Return all Bundles\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Bundle for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Bundle for api: `counterDuck`\nconst counterByApi = ducks.ducksify(counterDuck)\nassert(counterByApi === counter)\n```\n\nComparing the Duck with the Bundle (ducksified Duck), we will get the following differences: (`counterBundle` is the ducksified `counterDuck`)\n\nFor `selectors`:\n\n```diff\n- counterDuck.selectors.getTotal(store.getState().counter)()\n+ counterBundle.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterDuck.operations.tap(store.dispatch)()\n+ counterBundle.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDuck()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDuck } from 'ducks'\nimport * as counterDuck from './counter.js'\n\nvalidateDuck(counterDuck) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master v0.11 (Sep 2021)\n\n1. Disable `saga` support temporary due to ([#4](https://github.com/huan/ducks/issues/4))\n1. ES Modules support\n\n### v0.10 (Jun 6, 2020)\n\nAdd `setDucks()` to `Duck` API interface,\nso that all the `Duck` can get the `Ducks` instance\n(if needed, by providing a `setDucks()` method from the API),\nwhich helps the `Duck`s talk to each others.\n\n### v0.8 (Jun 5, 2020)\n\nRenaming for better names with a better straightforward intuition.\n\n1. Rename `interface Api` to `interface Duck`\n1. Rename `class Duck` to `class Bundle`\n1. Rename `function validateDucksApi` to `function validateDuck`\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Badge\n\n### Powered by Ducks\n\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n### Ducksify\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)), Microsoft Regional Director, \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"40c7026c26f0f9c10cf8bbffe526d78c7459e70b","_id":"ducks@0.11.7","_nodeVersion":"16.9.1","_npmVersion":"7.21.1","dist":{"integrity":"sha512-K9/QKQ0tsjCB0BM75KhQUneHaoyKDilz+yg8JFIwFyE8cydVWlTsl4Nc4P0UH3jKQQz0/sgNNYujga6te7DlRw==","shasum":"f717266e47305525429d2a3d757bcf273532b38b","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.11.7.tgz","fileCount":561,"unpackedSize":675999,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD6wJa3Nrc3vkfqZYyf8ISRU1ZzwSmXm6FV7aRG8TStQgIhAKEX26qhT0jOXukL+ZKvxqUKA6HyvQxofCgP9tbo5qF4"}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.11.7_1631974508487_0.3996021309740263"},"_hasShrinkwrap":false},"0.11.10":{"name":"ducks","version":"0.11.10","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --isolatedModules --noEmit","start":"npm run quack","quack":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"tap --node-arg=--loader=ts-node/esm --node-arg=--no-warnings \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","devDependencies":{"@chatie/eslint-config":"^0.14.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.20.2","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","@types/redux-saga":"^0.10.5","cross-env":"^7.0.3","glob":"^7.1.6","npm-run-all":"^4.1.5","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","rxjs":"^7.3.0","shx":"^0.3.3","tstest":"^0.5.16","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux-observable":"^2.0.0","redux":"^4.0.5"},"tap":{"check-coverage":false},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Ducksify Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following `Duck` interface:\n\n    ```ts\n    export interface Duck {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      // Disabled temporary. See: https://github.com/huan/ducks/issues/4\n      // sagas?: SagasMapObject,\n\n      setDucks?: (ducks: Ducks<any>) => void\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v16+, or Browser with ES2020 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Create Redux Reducer Bundle as a `Duck`\n\nFor example, let's create a Duck module file named `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Manage the Bundles with `Ducks` Manager\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst counter = ducks.ducksify(counterDuck)\n```\n\n### 3 Configure Redux Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducksify Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\n### Talk is cheap, show me the code\n\nThe following example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterDuck  from './counter.js'    // Vanilla Duck: +1\nimport * as dingDongDuck from './ding-dong.js'  // Observable Middleware\nimport * as pingPongDuck from './ping-pong.js'  // Saga Middleware\nimport * as switcherDuck from './switcher.js'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterDuck,\n  switcher : switcherDuck,\n  dingDong : dingDongDuck,\n  pingPong : pingPongDuck,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nI hope you will like this clean and beautiful `Ducksify` way with using Ducks!\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Redux Reducer Bundle`s with the `Duck` interface that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating your `Duck` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDuck` that accepts a `Duck` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Duck`\n\nThe `Duck` is a interface which is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface).\n\nExample:\n\n`Duck` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions.js'\nimport * as operations  from './operations.js'\nimport * as selectors   from './selectors.js'\nimport * as types       from './types.js'\n\nimport reducer from './reducers.js'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is the manager for `Duck`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter.js'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `DucksMapObject` to initialize the `Ducks` (`{ counter: counterDuck }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksMapObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Bundle` class so that we will have a more convenience way to use it.\n\n1. Return all Bundles: `const { counter } = ducks.ducksify()`\n1. Return the Bundle for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Bundle for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst store = ducks.configureStore()\n\n// 1. Return all Bundles\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Bundle for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Bundle for api: `counterDuck`\nconst counterByApi = ducks.ducksify(counterDuck)\nassert(counterByApi === counter)\n```\n\nComparing the Duck with the Bundle (ducksified Duck), we will get the following differences: (`counterBundle` is the ducksified `counterDuck`)\n\nFor `selectors`:\n\n```diff\n- counterDuck.selectors.getTotal(store.getState().counter)()\n+ counterBundle.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterDuck.operations.tap(store.dispatch)()\n+ counterBundle.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDuck()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDuck } from 'ducks'\nimport * as counterDuck from './counter.js'\n\nvalidateDuck(counterDuck) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master v0.11 (Sep 2021)\n\n1. Disable `saga` support temporary due to ([#4](https://github.com/huan/ducks/issues/4))\n1. ES Modules support\n\n### v0.10 (Jun 6, 2020)\n\nAdd `setDucks()` to `Duck` API interface,\nso that all the `Duck` can get the `Ducks` instance\n(if needed, by providing a `setDucks()` method from the API),\nwhich helps the `Duck`s talk to each others.\n\n### v0.8 (Jun 5, 2020)\n\nRenaming for better names with a better straightforward intuition.\n\n1. Rename `interface Api` to `interface Duck`\n1. Rename `class Duck` to `class Bundle`\n1. Rename `function validateDucksApi` to `function validateDuck`\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Badge\n\n### Powered by Ducks\n\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n### Ducksify\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)), Microsoft Regional Director, \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"f3b67e97e15a97fd967a7427bbb350b8515d405c","_id":"ducks@0.11.10","_nodeVersion":"16.9.1","_npmVersion":"7.21.1","dist":{"integrity":"sha512-THJJYtEWCpxJZn7jeQZkd2Ma64MAD0Dg7QFFh0arsTzhJT3YZ6EC5DtFdK19vhjWczKrPAsS+2fMOJLnc+BDPw==","shasum":"815a83bc7275504f0540c64f34f7e4aad0d2f8ea","tarball":"https://registry.npmjs.org/ducks/-/ducks-0.11.10.tgz","fileCount":561,"unpackedSize":675979,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDg38qUvZO3RTuzDhzFQXXKrG40KiVQk8jPXUdc/jOQ0QIhANWpAfEdVwzEyXPu0uc21Z4w8X6mfWQmyPRrDHbgSSxe"}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_0.11.10_1631982096523_0.09325080873317915"},"_hasShrinkwrap":false},"1.0.1":{"name":"ducks","version":"1.0.1","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --isolatedModules --noEmit","start":"npm run quack","quack":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"tap --node-arg=--loader=ts-node/esm --node-arg=--no-warnings \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","devDependencies":{"@chatie/eslint-config":"^0.14.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.20.2","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","@types/redux-saga":"^0.10.5","cross-env":"^7.0.3","glob":"^7.1.6","npm-run-all":"^4.1.5","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","rxjs":"^7.3.0","shx":"^0.3.3","tstest":"^0.5.16","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux-observable":"^2.0.0","redux":"^4.0.5"},"tap":{"check-coverage":false},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"6a7ee4754acdc42237d2c22187bb54959924278e","_id":"ducks@1.0.1","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-cV2aznVkfPqaJXCIJCqvTR2vAKQS7rVvH2aNtkHFdM8Z0/vsXIlhezejTZrBWYa6P7S6UK6+PNdIPzPb9euBnQ==","shasum":"6e849ff80ebb5b6081c48a65184e687833e3b794","tarball":"https://registry.npmjs.org/ducks/-/ducks-1.0.1.tgz","fileCount":561,"unpackedSize":676023,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCID66LHqQwOaMEHNRp89lcVjHEPqoUGU6nBphPexunJ/eAiBGQsiLdqOYV+PvyUlOOL21oMkjKbWj5QXY01/UZSPZXg=="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_1.0.1_1635478385333_0.06938550589124093"},"_hasShrinkwrap":false},"1.0.2":{"name":"ducks","version":"1.0.2","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm run lint:es && npm run lint:ts && npm run lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --isolatedModules --noEmit","start":"npm run quack","quack":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"tap --node-arg=--loader=ts-node/esm --node-arg=--no-warnings \"src/**/*.spec.ts\" \"src/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","devDependencies":{"@chatie/eslint-config":"^0.14.1","@chatie/git-scripts":"^0.6.1","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^0.20.2","@types/glob":"^7.1.1","@types/redux-mock-store":"^1.0.2","@types/redux-saga":"^0.10.5","cross-env":"^7.0.3","glob":"^7.1.6","npm-run-all":"^4.1.5","pkg-jq":"^0.2.4","reduce-reducers":"^1.0.4","redux":"^4.0.5","redux-mock-store":"^1.5.4","rxjs":"^7.3.0","shx":"^0.3.3","tstest":"^0.5.16","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux-observable":"^2.0.0","redux":"^4.0.5"},"tap":{"check-coverage":false},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"latest"},"gitHead":"36c4d98473519fd65de0e08f7a59838be3905b7a","_id":"ducks@1.0.2","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-CDLrkP4g5E3IG0kAPrlVgavrgtNwn528DsXFZq3dSOx+DaS5nnoH9eEOXJ1emXtPVwiVF50pOYvWGF42miaJgg==","shasum":"e1aaccfe9dc0d8ff24380a0f7b81643928cb6904","tarball":"https://registry.npmjs.org/ducks/-/ducks-1.0.2.tgz","fileCount":561,"unpackedSize":676156,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCpPl0Q3Y+F34jFGOaJ5lB7xAJtlIVrIrzVZWA5BMwIAwIgbGHRdiWRDTXKQ7PwepUyqDCMBQxhWUD+HTeorOSWpqg="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_1.0.2_1635478493742_0.9895116827878103"},"_hasShrinkwrap":false},"1.1.1":{"name":"ducks","version":"1.1.1","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es lint:ts lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --isolatedModules --noEmit","start":"npm run quack","quack":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","devDependencies":{"@chatie/eslint-config":"^1.0.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^1.0.3","@types/glob":"^7.2.0","@types/redux-mock-store":"^1.0.3","@types/redux-saga":"^0.10.5","cross-env":"^7.0.3","glob":"^7.2.0","npm-run-all":"^4.1.5","pkg-jq":"^0.2.11","reduce-reducers":"^1.0.4","redux":"^4.1.2","redux-mock-store":"^1.5.4","rxjs":"^7.4.0","shx":"^0.3.3","tstest":"^1.0.1","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux-observable":"^2.0.0","redux":"^4.1.2"},"tap":{"check-coverage":false},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM](https://github.com/huan/ducks/actions/workflows/npm.yml/badge.svg)](https://github.com/huan/ducks/actions/workflows/npm.yml)\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Ducksify Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following `Duck` interface:\n\n    ```ts\n    export interface Duck {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      // Disabled temporary. See: https://github.com/huan/ducks/issues/4\n      // sagas?: SagasMapObject,\n\n      setDucks?: (ducks: Ducks<any>) => void\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v16+, or Browser with ES2020 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Create Redux Reducer Bundle as a `Duck`\n\nFor example, let's create a Duck module file named `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Manage the Bundles with `Ducks` Manager\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst counter = ducks.ducksify(counterDuck)\n```\n\n### 3 Configure Redux Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducksify Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\n### Talk is cheap, show me the code\n\nThe following example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterDuck  from './counter.js'    // Vanilla Duck: +1\nimport * as dingDongDuck from './ding-dong.js'  // Observable Middleware\nimport * as pingPongDuck from './ping-pong.js'  // Saga Middleware\nimport * as switcherDuck from './switcher.js'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterDuck,\n  switcher : switcherDuck,\n  dingDong : dingDongDuck,\n  pingPong : pingPongDuck,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nI hope you will like this clean and beautiful `Ducksify` way with using Ducks!\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Redux Reducer Bundle`s with the `Duck` interface that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating your `Duck` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDuck` that accepts a `Duck` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Duck`\n\nThe `Duck` is a interface which is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface).\n\nExample:\n\n`Duck` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions.js'\nimport * as operations  from './operations.js'\nimport * as selectors   from './selectors.js'\nimport * as types       from './types.js'\n\nimport reducer from './reducers.js'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is the manager for `Duck`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter.js'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `DucksMapObject` to initialize the `Ducks` (`{ counter: counterDuck }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksMapObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Bundle` class so that we will have a more convenience way to use it.\n\n1. Return all Bundles: `const { counter } = ducks.ducksify()`\n1. Return the Bundle for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Bundle for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst store = ducks.configureStore()\n\n// 1. Return all Bundles\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Bundle for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Bundle for api: `counterDuck`\nconst counterByApi = ducks.ducksify(counterDuck)\nassert(counterByApi === counter)\n```\n\nComparing the Duck with the Bundle (ducksified Duck), we will get the following differences: (`counterBundle` is the ducksified `counterDuck`)\n\nFor `selectors`:\n\n```diff\n- counterDuck.selectors.getTotal(store.getState().counter)()\n+ counterBundle.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterDuck.operations.tap(store.dispatch)()\n+ counterBundle.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDuck()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDuck } from 'ducks'\nimport * as counterDuck from './counter.js'\n\nvalidateDuck(counterDuck) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master v1.0 (Oct 29, 2021)\n\nRelease v1.0 of Redux Ducks\n\nv0.11 (Sep 2021)\n\n1. Disable `saga` support temporary due to ([#4](https://github.com/huan/ducks/issues/4))\n1. ES Modules support\n\n### v0.10 (Jun 6, 2020)\n\nAdd `setDucks()` to `Duck` API interface,\nso that all the `Duck` can get the `Ducks` instance\n(if needed, by providing a `setDucks()` method from the API),\nwhich helps the `Duck`s talk to each others.\n\n### v0.8 (Jun 5, 2020)\n\nRenaming for better names with a better straightforward intuition.\n\n1. Rename `interface Api` to `interface Duck`\n1. Rename `class Duck` to `class Bundle`\n1. Rename `function validateDucksApi` to `function validateDuck`\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Badge\n\n### Powered by Ducks\n\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n### Ducksify\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)), Microsoft Regional Director, \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"b9659c0d4a532922470901e1fbdb89e0475f0232","_id":"ducks@1.1.1","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-mbiwbHB67IvJAULzk7vvKSDFSqPk1w2BEzpK++dad+OFwaho+wHizlcwpGwNn6sY/qOl0S6qOy4+Tcph4xE5rg==","shasum":"dfbb424396f479fa2a2d80a9f4116da21a7f60c2","tarball":"https://registry.npmjs.org/ducks/-/ducks-1.1.1.tgz","fileCount":561,"unpackedSize":679798,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDvIGFr3cSVF6P82zerzhWEEoMJusGav5W901r0aCM20gIgY1fS4HBCEItVwRDAnZeeQE7FwlX1fnbVqzfTancVV1U="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_1.1.1_1636818780615_0.03313651207517987"},"_hasShrinkwrap":false},"1.1.2":{"name":"ducks","version":"1.1.2","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es lint:ts lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --isolatedModules --noEmit","start":"npm run quack","quack":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","devDependencies":{"@chatie/eslint-config":"^1.0.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^4.5.3","@types/glob":"^7.2.0","@types/redux-mock-store":"^1.0.3","@types/redux-saga":"^0.10.5","glob":"^7.2.0","reduce-reducers":"^1.0.4","redux":"^4.1.2","redux-mock-store":"^1.5.4","rxjs":"^7.4.0","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux-observable":"^2.0.0","redux":"^4.1.2"},"tap":{"check-coverage":false},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM](https://github.com/huan/ducks/actions/workflows/npm.yml/badge.svg)](https://github.com/huan/ducks/actions/workflows/npm.yml)\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Ducksify Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following `Duck` interface:\n\n    ```ts\n    export interface Duck {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      // Disabled temporary. See: https://github.com/huan/ducks/issues/4\n      // sagas?: SagasMapObject,\n\n      setDucks?: (ducks: Ducks<any>) => void\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v16+, or Browser with ES2020 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Create Redux Reducer Bundle as a `Duck`\n\nFor example, let's create a Duck module file named `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Manage the Bundles with `Ducks` Manager\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst counter = ducks.ducksify(counterDuck)\n```\n\n### 3 Configure Redux Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducksify Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\n### Talk is cheap, show me the code\n\nThe following example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterDuck  from './counter.js'    // Vanilla Duck: +1\nimport * as dingDongDuck from './ding-dong.js'  // Observable Middleware\nimport * as pingPongDuck from './ping-pong.js'  // Saga Middleware\nimport * as switcherDuck from './switcher.js'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterDuck,\n  switcher : switcherDuck,\n  dingDong : dingDongDuck,\n  pingPong : pingPongDuck,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nI hope you will like this clean and beautiful `Ducksify` way with using Ducks!\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Redux Reducer Bundle`s with the `Duck` interface that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating your `Duck` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDuck` that accepts a `Duck` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Duck`\n\nThe `Duck` is a interface which is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface).\n\nExample:\n\n`Duck` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions.js'\nimport * as operations  from './operations.js'\nimport * as selectors   from './selectors.js'\nimport * as types       from './types.js'\n\nimport reducer from './reducers.js'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is the manager for `Duck`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter.js'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `DucksMapObject` to initialize the `Ducks` (`{ counter: counterDuck }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksMapObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Bundle` class so that we will have a more convenience way to use it.\n\n1. Return all Bundles: `const { counter } = ducks.ducksify()`\n1. Return the Bundle for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Bundle for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst store = ducks.configureStore()\n\n// 1. Return all Bundles\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Bundle for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Bundle for api: `counterDuck`\nconst counterByApi = ducks.ducksify(counterDuck)\nassert(counterByApi === counter)\n```\n\nComparing the Duck with the Bundle (ducksified Duck), we will get the following differences: (`counterBundle` is the ducksified `counterDuck`)\n\nFor `selectors`:\n\n```diff\n- counterDuck.selectors.getTotal(store.getState().counter)()\n+ counterBundle.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterDuck.operations.tap(store.dispatch)()\n+ counterBundle.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDuck()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDuck } from 'ducks'\nimport * as counterDuck from './counter.js'\n\nvalidateDuck(counterDuck) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master v1.0 (Oct 29, 2021)\n\nRelease v1.0 of Redux Ducks\n\nv0.11 (Sep 2021)\n\n1. Disable `saga` support temporary due to ([#4](https://github.com/huan/ducks/issues/4))\n1. ES Modules support\n\n### v0.10 (Jun 6, 2020)\n\nAdd `setDucks()` to `Duck` API interface,\nso that all the `Duck` can get the `Ducks` instance\n(if needed, by providing a `setDucks()` method from the API),\nwhich helps the `Duck`s talk to each others.\n\n### v0.8 (Jun 5, 2020)\n\nRenaming for better names with a better straightforward intuition.\n\n1. Rename `interface Api` to `interface Duck`\n1. Rename `class Duck` to `class Bundle`\n1. Rename `function validateDucksApi` to `function validateDuck`\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Badge\n\n### Powered by Ducks\n\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n### Ducksify\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)), Microsoft Regional Director, \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"1ca3af2a9b05ef261ef59e6da7f3c86821da78d4","_id":"ducks@1.1.2","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-fz9IYzqQLGB/hLfyRpKoTWbDVnLN8rJsUydkNvBZpmyJNU2OGtida7ax5ZAX1aTMBMdOhrBldMQJVd2x2j4KIQ==","shasum":"a97402d59ead0bcfe516bdb5d81925087a39f50b","tarball":"https://registry.npmjs.org/ducks/-/ducks-1.1.2.tgz","fileCount":561,"unpackedSize":679046,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhmpY9CRA9TVsSAnZWagAAI48P/3Twg+SpVe65MDwXCgTK\neulZqhQg+SCBRAIFDnSKZrigM7UqZ3Dk5jAO1d0eJwYlOyOURd37g8MEaPoi\nOFLbu+8GyrUKBGEJOxxkFCob+KgTn0hooMZhSijDAkbfUbrhDoSZ8HdajMZ/\n90CH5EzMmYDjpAMg5a5vbuZK52LKkvTq7POxJgGDA6AoI3PMSoPgyX4IdjkQ\naYpNqoxvfa5cL7KaR5f98FlyEpU2ygYEv3Tx51G91Yx1NqfvLBKyGaFLhAWn\nIdTedDOQ5+uefNNxzH97xSdVPuzthEdDcr8NsWajowT2/n199AH+76XijGSN\nJ2WqWdnX2SgGvSVr64CKEVDqB5LqkeIljNnAjxJIW1Jg+rzcwwv45btfpIib\nzdBqsF14KBOT/uWXGAYLB9iyq+6If7mQJ2s23Pew+5kCN+nB/K/FB8Nb3j14\nevePUi3Hu1K87WcQZgZsFFklbLUFOcipGyEXvyIqt+kvPR8XT5Q9s9sjXcuu\no5Tth8sSx8uc4+1MwHEqbAAcr5C5riacXx/RCA0lINMdGZunqdCrjfGY5gmq\nWPtMY6zjrFMOwK85VOmouMLx8mMa/1bw4jcNaNr/hji9OW/ynZQmkRJ5hI+O\n9J05B2S7nx2vJjGHhmqjijAt3fXkPGfB0R09+Ini8C+vow1rRYiLtXjqBCFL\nRLBH\r\n=XH3E\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCP6vT6ewTpZaK53PsH7txdYERF7xAVPdqXAtzPJBp3CQIhAIn9h3nUe3rafiuvmcYAO5Z/KPwKI7GVSYw/tvgGdp46"}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_1.1.2_1637520957561_0.47331126854671357"},"_hasShrinkwrap":false},"1.3.2":{"name":"ducks","version":"1.3.2","description":"🦆🦆🦆 Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.","type":"module","exports":{".":{"import":"./dist/esm/src/mod.js","require":"./dist/cjs/src/mod.js"}},"typings":"./dist/esm/src/mod.d.ts","engines":{"node":">=16","npm":">=7"},"scripts":{"build":"tsc && tsc -p tsconfig.cjs.json","clean":"shx rm -fr dist/*","dist":"npm-run-all clean build dist:commonjs","dist:commonjs":"jq -n \"{ type: \\\"commonjs\\\" }\" > dist/cjs/package.json","lint":"npm-run-all lint:es lint:ts lint:md","lint:md":"markdownlint README.md","lint:ts":"tsc --isolatedModules --noEmit","start":"npm run quack","quack":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" node examples/quack.ts","test":"npm run lint && npm run test:unit","test:pack":"bash -x scripts/npm-pack-testing.sh","test:unit":"cross-env NODE_OPTIONS=\"--no-warnings --loader=ts-node/esm\" tap \"src/**/*.spec.ts\" \"examples/**/*.spec.ts\" \"tests/**/*.spec.ts\"","lint:es":"eslint --ignore-pattern tests/fixtures/ '{bin,examples,scripts,src,tests}/**/*.ts'"},"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"keywords":["redux","ducks"],"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"license":"Apache-2.0","bugs":{"url":"https://github.com/huan/ducks/issues"},"homepage":"https://github.com/huan/ducks#readme","devDependencies":{"@chatie/eslint-config":"^1.0.4","@chatie/git-scripts":"^0.6.2","@chatie/semver":"^0.4.7","@chatie/tsconfig":"^4.5.3","@types/glob":"^7.2.0","@types/redux-mock-store":"^1.0.3","@types/redux-saga":"^0.10.5","glob":"^7.2.0","reduce-reducers":"^1.0.4","redux":"^4.1.2","redux-mock-store":"^1.5.4","rxjs":"^7.4.0","typesafe-actions":"^5.1.0","utility-types":"^3.10.0"},"peerDependencies":{"redux-observable":"^2.0.0","redux":"^4.1.2"},"tap":{"check-coverage":false},"git":{"scripts":{"pre-push":"npx git-scripts-pre-push"}},"publishConfig":{"tag":"next"},"readme":"# ducks\n\n[![NPM](https://github.com/huan/ducks/actions/workflows/npm.yml/badge.svg)](https://github.com/huan/ducks/actions/workflows/npm.yml)\n[![NPM Version](https://img.shields.io/npm/v/ducks?color=yellow)](https://www.npmjs.com/package/ducks)\n[![NPM](https://github.com/huan/ducks/workflows/NPM/badge.svg)](https://github.com/huan/ducks/actions?query=workflow%3ANPM)\n\n🦆🦆🦆Ducks is a Reducer Bundles Manager that Implementing the Redux Ducks Modular Proposal with Great Convenience.\n\n[![Ducks](https://huan.github.io/ducks/images/ducks.png)](https://github.com/huan/ducks)\n\n> Image Credit: [Alamy](https://www.alamy.com/cute-duck-and-little-ducks-over-white-background-colorful-design-vector-illustration-image185379753.html)\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n[![Re-Ducks Extended](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nDucks offers a method of handling redux module packaging, installing, and running with your Redux store, with middleware support.\n\n> Java has jars and beans. Ruby has gems. I suggest we call these reducer bundles \"ducks\", as in the last syllable of \"redux\".  \n> &mdash; Erik Rasmussen, 2015 ([link](https://github.com/erikras/ducks-modular-redux#name))\n\n- [Product Hunt - Ducks](https://www.producthunt.com/posts/ducks)\n\n## Goal\n\nThe goal of Ducks is to:\n\n1. Organizing your code for the long term.\n1. Maximum your convenience when using Redux Ducks.\n1. Type-safe with strong typing with TypeScript Generic Templates.\n\n## Features\n\n1. Implemented the specification from [Ducks Modular Proposal, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n1. Easy connecting ducks to store by adding one enhancer to redux. (that's all you need to do!)\n1. Fully typing with all APIs by TypeScript\n1. Currying `operators` and `selectors` by binding the `Store` to them for maximum convenience.\n\nTodo-list:\n\n- [ ] Ducks middleware support\n- [ ] Provides a Ducks Management interface for adding/deleting a duck module dynamically\n\n## Motivation\n\nI'm building my redux ducks module for Wechaty Redux project and ...\n\nTo be written.\n\nAt last, I decide to write my own manager for ducks, which will implement the following two specifications, with my own Ducksify Extension:\n\n1. The Ducks Modular Proposal\n1. The Re-Ducks Extension: Duck Folders\n1. The Ducksify Extension: Currying `selectors` and `operators`\n\n### 1 The Ducks Modular Proposal\n\n[![Ducks Modular Proposal](https://img.shields.io/badge/Redux-Ducks%202015-yellow)](https://github.com/erikras/ducks-modular-redux)\n\nThe specification has rules that a module:\n\n1. MUST `export default` a function called `reducer()`\n1. MUST `export` its action creators as functions\n1. MUST have action types in the form `npm-module-or-app/reducer/ACTION_TYPE`\n1. MAY export its action types as `UPPER_SNAKE_CASE`, if an external reducer needs to listen for them, or if it is a published reusable library\n\nHere's the full version of Ducks proposal: [Redux Reducer Bundles, A proposal for bundling reducers, action types and actions when using Redux, Erik Rasmussen, 2015](https://github.com/erikras/ducks-modular-redux)\n\n### 2 The Re-Ducks Extension: Duck Folders\n\n[![Re-Ducks Extension](https://img.shields.io/badge/Redux-Re--Ducks%202016-orange)](https://github.com/alexnm/re-ducks)\n\n`Re-Ducks` is an extension to the original proposal for the ducks redux modular architecture.\n\nBy defining a ducks with duck folders instead of a duck file, it defines the **duck** folder would like:\n\n```sh\nduck/\n├── actions.js\n├── index.js\n├── operations.js\n├── reducers.js\n├── selectors.js\n├── tests.js\n├── types.js\n├── utils.js\n```\n\n> NOTE: Each concept from your app will have a similar folder.\n\n#### General rules for a duck folder\n\nA duck folder:\n\n1. MUST contain the **entire logic** for handling **only ONE** concept in your app, ex: product, cart, session, etc.\n1. MUST have an `index.js` file that exports according to the original duck rules.\n1. MUST keep code with similar purpose in the same file, ex: reducers, selectors, actions, etc.\n1. MUST contain the **tests** related to the duck.\n\nHere's the full version of Re-ducks proposal: [Building on the duck legacy, An attempt to extend the original proposal for redux modular architecture, Alex Moldovan, 2016](https://github.com/alexnm/re-ducks) and [blog](https://medium.com/better-programming/scaling-your-redux-app-with-ducks-6115955638be#.4ppptx7oq)\n\n### 3 Ducksify Extension: Currying & Ducksify Interface\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\nIn order to build a fully modularized Ducks, we define the **Ducksify** extension with the following rules:\n\n1. MUST export its module interface as the following `Duck` interface:\n\n    ```ts\n    export interface Duck {\n      /**\n       * Ducks Modular Proposal (https://github.com/erikras/ducks-modular-redux)\n      */\n      default: Reducer,\n\n      actions    : ActionCreatorsMapObject,\n      operations?: OperationsMapObject,\n      selectors? : SelectorsMapObject,\n      types?     : TypesMapObject,\n\n      /**\n       * Ducksify Extension (https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n      */\n      middlewares?: MiddlewaresMapObject,\n      epics?: EpicsMapObject,\n      // Disabled temporary. See: https://github.com/huan/ducks/issues/4\n      // sagas?: SagasMapObject,\n\n      setDucks?: (ducks: Ducks<any>) => void\n    }\n    ```\n\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `selectors.*` with a `State` object\n1. MUST support [Currying](https://stackoverflow.com/a/36321/1123955) the first argument for `operations.*` with a `Dispatch` function\n1. MAY export its middlewares functions called `*Middleware()`\n1. MAY export its saga functions called `*Saga()`\n1. MAY export its epic functions called `*Epic()`\n1. MAY use [typesafe-actions](https://github.com/piotrwitek/typesafe-actions) to creating reducers, actions, and middlewares.\n1. If we has `sagas`, `epics`, or `middlewares`, the **duck** folder would like:\n\n    ```sh\n    duck/\n    ├── epics.js\n    ├── sagas.js\n    ├── middlewares.js\n    ```\n\n## Requirements\n\nNode.js v16+, or Browser with ES2020 Support\n\n## Install\n\n```sh\nnpm install ducks\n```\n\n## Usage\n\n### 1 Create Redux Reducer Bundle as a `Duck`\n\nFor example, let's create a Duck module file named `counter.ts`:\n\n```ts\nexport const types      = { TAP: 'ducks/examples/counter/TAP' }\nexport const actions    = { tap: () => ({ type: TAP }) }\nexport const operations = { tap: dispatch => dispatch(actions.tap()) }\nexport const selectors  = { getTotal: state => () => state.total }\n\nconst initialState = { total: 0 }\nexport default function reducer (state = initialState, action) {\n  if (action.type === types.TAP) {\n    return ({\n      ...state,\n      total: (state.total || 0) + 1,\n    })\n  }\n  return state\n}\n```\n\n### 2 Manage the Bundles with `Ducks` Manager\n\n```ts\nimport { Ducks }       from 'ducks'\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst counter = ducks.ducksify(counterDuck)\n```\n\n### 3 Configure Redux Store\n\n```ts\nimport { createStore } from 'redux'\n\nconst store = createStore(\n  state => state,     // Your other reducers\n  ducks.enhancer(),   // Add ducks to your store (that's all you need to do!)\n)\n```\n\nYou are all set!\n\n### 4 Using Ducks\n\nThe Vanilla Style and Ducksify Style is doing exactly the same thing.\n\n#### The Vanilla Style\n\n```ts\nstore.dispatch(counterApi.actions.tap())\nconsole.info('getTotal:', counterApi.selectors.getTotal(store.getState().counter)))\n// Output: getTotal: 1\n```\n\n#### The Ducksify Style\n\n```ts\ncounter.operations.tap()\nconsole.info('getTotal:', counter.selectors.getTotal()))\n// Output: getTotal: 2\n```\n\nIt turns out that the Ducksify Style is more clear and easy to use by currying them with the store as their first argument.\n\nThat's it!\n\n## Examples\n\nLet's get to know more about Ducks by **quack**!\n\nThe following is the full example which demonstrate how to use Ducks.\n\nIt shows that:\n\n1. How to import duck modules with easy and clean way.\n1. Ducks supports `redux-observable` and `redux-saga` out-of-the-box with zero configuration.\n1. How to stick with the best practices to write a redux reducer bundle by following the ducks modular proposal.\n\n### Talk is cheap, show me the code\n\nThe following example code can be found at [examples/quack.ts](examples/quack.ts), you can try it by running the following commands:\n\n```sh\ngit clone git@github.com:huan/ducks.git\ncd ducks\n\nnpm install\nnpm start\n```\n\n```ts\nimport { createStore } from 'redux'\nimport { Duck, Ducks } from 'ducks'\n\nimport * as counterDuck  from './counter.js'    // Vanilla Duck: +1\nimport * as dingDongDuck from './ding-dong.js'  // Observable Middleware\nimport * as pingPongDuck from './ping-pong.js'  // Saga Middleware\nimport * as switcherDuck from './switcher.js'   // Type Safe Actions: ON/OFF\n\nconst ducks = new Ducks({\n  counter  : counterDuck,\n  switcher : switcherDuck,\n  dingDong : dingDongDuck,\n  pingPong : pingPongDuck,\n})\n\nconst {\n  counter,\n  dingDong,\n  pingPong,\n  switcher,\n} = ducks.ducksify()\n\nconst store = createStore(\n  state => state,     // Here's our normal Redux Reducer\n  ducks.enhancer(),   // We use Ducks by adding this enhancer to our store, and that's it!\n)\n\n/**\n * Vanilla: Counter\n */\nassert.strictEqual(counter.selectors.getCounter(), 0)\ncounter.operations.tap()\nassert.strictEqual(counter.selectors.getCounter(), 1)\n\n/**\n * TypeSafe Actions: Switchers\n */\nassert.strictEqual(switcher.selectors.getStatus(), false)\nswitcher.operations.toggle()\nassert.strictEqual(switcher.selectors.getStatus(), true)\n\n/**\n * Epic Middleware: DingDong\n */\nassert.strictEqual(dingDong.selectors.getDong(), 0)\ndingDong.operations.ding()\nassert.strictEqual(dingDong.selectors.getDong(), 1)\n\n/**\n * Saga Middleware: PingPong\n */\nassert.strictEqual(pingPong.selectors.getPong(), 0)\npingPong.operations.ping()\nassert.strictEqual(pingPong.selectors.getPong(), 1)\n\nconsole.info('store state:', store.getState())\n```\n\nI hope you will like this clean and beautiful `Ducksify` way with using Ducks!\n\n## Api References\n\nDucks is very easy to use, because one of the goals of designing it is to maximum the convenience.\n\nWe use `Ducks` to manage `Redux Reducer Bundle`s with the `Duck` interface that following the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux).\n\nFor validating your `Duck` form the redux module (a.k.a reducer bundle), we have a validating helper function `validateDuck` that accepts a `Duck` to make sure it's valid (it will throws an Error when it's not).\n\n### 1 `Duck`\n\nThe `Duck` is a interface which is defined from the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), extended from both [Re-Ducks](https://github.com/alexnm/re-ducks) and [Ducksify](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface).\n\nExample:\n\n`Duck` counter example from our [examples](examples/counter/index.ts)\n\n```ts\nimport * as actions     from './actions.js'\nimport * as operations  from './operations.js'\nimport * as selectors   from './selectors.js'\nimport * as types       from './types.js'\n\nimport reducer from './reducers.js'\n\nexport {\n  actions,\n  operations,\n  selectors,\n  types,\n}\n\nexport default reducer\n```\n\n### 2 `Ducks`\n\nThe `Ducks` class is the manager for `Duck`s and connecting them to the Redux Store by providing a `enhancer()` to Redux `createStore()`.\n\n```ts\nimport { Ducks } from 'ducks'\nimport * as counterApi from './counter.js'\n\nconst ducks = new Ducks({\n  counter: counterApi,\n})\n\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n// Duck will be ready to use after the store has been created.\n```\n\nThere is one important thing that we need to figure out is that when we are passing the `DucksMapObject` to initialize the `Ducks` (`{ counter: counterDuck }` in the above case), the key name of this Api will become the mount point(name space) for its state.\n\nChoose your key name wisely because it will inflect the state structure and the typing for your store.\n\n> There's project named [Ducks++: Redux Reducer Bundles, Djamel Hassaine, 2017](https://medium.com/@DjamelH/ducks-redux-reducer-bundles-44267f080d22) to solve the mount point (namespace) problem, however, we are just use the keys in the `DucksMapObject` to archive the same goal.\n\n#### 2.1 `Ducks#enhancer()`\n\nReturns a `StoreEnhancer` for using with the Redux store creator, which is the most important and the only one who are in charge of initializing everything for the Ducks.\n\n```ts\nconst store = createStore(\n  state => state,\n  ducks.enhancer(),\n)\n```\n\nIf you have other enhancers need to be used with the Ducks, for example, the `applyMiddleware()` enhancer from the Redux, you can use `compose()` from Redux to archive that:\n\n```ts\nimport { applyMiddleware, compose, createStore } from 'redux'\nimport { Ducks } from 'ducks'\n// ...\nconst store = createStore(\n  state => state,\n  compose(\n    ducks.enhancer(),\n    applyMiddleware(\n      // ...\n    ),\n  )\n)\n```\n\n> NOTE: our `enhancer()` should be put to the most left in the `compose()` argument list, because it would be better to make it to be the most outside one to be called.\n\n#### 2.2 `Ducks#configureStore()`\n\nIf you only use Redux with Ducks without any other reducers, then you can use `configureStore()` shortcut from the Ducks to get the configured store.\n\n```ts\nconst store = ducks.configureStore(preloadedStates)\n```\n\nThe above code will be equals to the following naive Redux `createStore()` codes because the `configureStore()` is just a shortcut of that for our convenience.\n\n```ts\n// This is exactly what `ducks.configureStore()` does:\nconst store = createStore(\n  state => state,\n  preloadedStates,\n  ducks.enhancer(),\n)\n```\n\n#### 2.3 `Ducks#ducksify()`\n\n`ducksify()` will encapsulate the `Api` into the `Bundle` class so that we will have a more convenience way to use it.\n\n1. Return all Bundles: `const { counter } = ducks.ducksify()`\n1. Return the Bundle for _namespace_: `const counter = ducks.ducksify('counter')\n1. Return the Bundle for _api_: `const counter = ducks.ducksify(counterApi)\n\nFor example:\n\n```ts\nimport * as counterDuck from './counter.js'\n\nconst ducks = new Ducks({ counter: counterDuck })\nconst store = ducks.configureStore()\n\n// 1. Return all Bundles\nconst { counter } = ducks.ducksify()\n\n// 2. Return the Bundle for namespace: `counter`\nconst counterByName = ducks.ducksify('counter')\nassert(counterByName === counter)\n\n// 3. Return the Bundle for api: `counterDuck`\nconst counterByApi = ducks.ducksify(counterDuck)\nassert(counterByApi === counter)\n```\n\nComparing the Duck with the Bundle (ducksified Duck), we will get the following differences: (`counterBundle` is the ducksified `counterDuck`)\n\nFor `selectors`:\n\n```diff\n- counterDuck.selectors.getTotal(store.getState().counter)()\n+ counterBundle.selectors.getTotal()\n```\n\nFor `operations`:\n\n```diff\n- counterDuck.operations.tap(store.dispatch)()\n+ counterBundle.operations.tap()\n```\n\nAs you see, the above differences showed that the ducksified api will give you great convenience by currying the `Store` inside itself.\n\n### 4 `validateDuck()`\n\nTo make sure your Ducks Api is following the specification of the [ducks modular proposal](https://github.com/erikras/ducks-modular-redux), we provide a validating function to check it.\n\n```ts\nimport { validateDuck } from 'ducks'\nimport * as counterDuck from './counter.js'\n\nvalidateDuck(counterDuck) // will throw if the counterApi is invalid.\n```\n\n## Resources\n\n- [Redux - Store enhancer](https://redux.js.org/glossary#store-enhancer)\n- [Typesafe utilities designed to reduce types verbosity and complexity in Redux Architecture](https://github.com/piotrwitek/typesafe-actions)\n- [Conditional Type Checks](https://github.com/dsherret/conditional-type-checks)\n- [Redux Ecosystem Links - A categorized list of addon libraries for Redux, as well as other libraries that are closely related](https://github.com/markerikson/redux-ecosystem-links)\n\n### Modular\n\n- [Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018](https://www.youtube.com/watch?v=jr7D4VAzNig&t=960s)\n- [Redux: Another implementation for Selector Pattern](https://stackoverflow.com/q/53265572/1123955)\n- [Scaling your Redux App with ducks](https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/)\n- [Where do I put my business logic in a React-Redux application?](https://medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1)\n- [Redux Ecosystem Links - A categorized list of Redux-related addons, libraries, and utilities](https://github.com/markerikson/redux-ecosystem-links)\n- [Modular Reducers and Selectors](https://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/)\n\n### Middlewares\n\n- [ducksMiddleware - Extract all available middleware from a ducks object and creates a middleware with all available middleware.](https://github.com/drpicox/ducks-middleware)\n- [Exploring Redux middleware - Nine simple stand-alone experiments to understand Redux Middlewares](https://blog.krawaller.se/posts/exploring-redux-middleware/)\n- [Redux Middleware LifeCycle - Impure and asynchronous; but still redux](https://hackernoon.com/)\n- [Understanding Redux Middleware](https://medium.com/@meagle/understanding-87566abcfb7a)\n- [You Aren’t Using Redux Middleware Enough](https://medium.com/@jacobp100/you-arent-using-redux-middleware-enough-94ffe991e6)\n- [Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability](https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/)\n- [This collection of common Redux-saga patterns will make your life easier.](https://medium.com/free-code-camp/redux-saga-common-patterns-48437892e11c)\n- [Lost with Redux and sagas? Implement them yourself!](https://blog.castiel.me/posts/2019-08-03-lost-redux-saga-reimplement-them/)\n\n### Relate Libraries\n\n1. Microsoft Redux Dynamic Modules: Modularize Redux by dynamically loading reducers and middlewares.\n    - [microsoft/redux-dynamic-modules](https://github.com/microsoft/redux-dynamic-modules) is a library that aims to make Redux Reducers and middleware easy to modular-ize and add/remove dynamically.\n1. [ioof-holdings/redux-dynostore - These libraries provide tools for building dynamic Redux stores.](https://github.com/ioof-holdings/redux-dynostore)\n1. [reSolve - A Redux-Inspired Backend](https://medium.com/resolvejs/resolve-redux-backend-ebcfc79bbbea)\n1. [redux-dynamic-middlewares - Allow add or remove redux middlewares dynamically](https://github.com/pofigizm/redux-dynamic-middlewares)\n\n### Other Links\n\n- [redux-operations - Solves challenging redux problems in a clean, understandable, debuggable fasion](https://github.com/mattkrick/redux-operations)\n- [Dynamically inject reducers in your react reduc app. HMR and SSR compatible.](https://github.com/GuillaumeCisco/redux-reducers-injector)\n- [Helper for loading sagas asynchronously using redux](https://github.com/GuillaumeCisco/redux-sagas-injector)\n- [💉 inject reducer and saga anywhere in the application.](https://github.com/marcelmokos/redux-inject-reducer-and-saga)\n- [Paradux - a Redux reducer wrapper that adds a little bit of fun uncertainty](https://github.com/asteridux/paradux)\n- [Allows dynamically injecting reducers into a redux store at runtime](https://github.com/randallknutson/redux-injector)\n- [redux-optimistic-ui - a reducer enhancer to enable type-agnostic optimistic updates](https://github.com/mattkrick/redux-optimistic-ui)\n- [Reduce Reducers - Reduce multiple reducers into a single reducer from left to right](https://github.com/redux-utilities/reduce-reducers)\n- [Utilities that embrace best practices while working with redux in a universal application.](https://github.com/ImmoweltGroup/redux-lumbergh)\n- [createReduxDuckling() to spawn Redux Ducks as unique child instances called Ducklings.](https://github.com/sammysaglam/redux-ducklings)\n- [Modular and Extensible Redux Reducer Bundles (ducks-modular-redux)](https://github.com/investtools/extensible-duck)\n- [Composable ducklings](https://github.com/pghalliday/redux-duckling)\n- [Factory for simple creation and use of redux ducks.](https://github.com/espen42/duckfactory)\n- [tiny-duck - Composable redux reducers](https://github.com/LockedOn/tiny-duck)\n- [reduxModuleCreator - RMC is a tool for creating not coupled, reusable and testable modules based on Redux.](https://github.com/mtnt/reduxModuleCreator)\n\n## Future Thoughts\n\nRedux Ducks Api compares with CQRS, Event Sourcing, and DDD:\n\n| Ducks       | CQRS    | Event Sourcing | DDD  |\n| :---        | :---    | :---           | :--- |\n| actions     | Domain Aggregates with Command handlers\n| - creator   | Command |\n| - payload   | Event   | Event          |      |\n| selectors   | Query   |\n| operations  | Command + Event |\n| middlewares | Aggregate? | Saga ? |\n| types       | ??\n| reducers    | Reducers to calculate Aggregate state\n\n> [reSolve](https://reimagined.github.io/resolve/docs/introduction) is a Node.js library for Redux & CQRS\n\n### Domain Driven Design (DDD)\n\nDomain aggregate is a business model unit. Business logic is mostly in command handlers for the aggregate.\n\n### Event Sourcing (ES)\n\nDon't store system state, store events that brought system to this state.\n\n### Command Query Responsibility Segregation (CQRS)\n\n[CQRS](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) system is divided in two \"sides\":\n\n1. Write Side accepts commands and generate events that stored in the Event Store.\n1. Read Side applies events to Read Models, and process queries.\n\n## History\n\n### master v1.0 (Oct 29, 2021)\n\nRelease v1.0 of Redux Ducks\n\nv0.11 (Sep 2021)\n\n1. Disable `saga` support temporary due to ([#4](https://github.com/huan/ducks/issues/4))\n1. ES Modules support\n\n### v0.10 (Jun 6, 2020)\n\nAdd `setDucks()` to `Duck` API interface,\nso that all the `Duck` can get the `Ducks` instance\n(if needed, by providing a `setDucks()` method from the API),\nwhich helps the `Duck`s talk to each others.\n\n### v0.8 (Jun 5, 2020)\n\nRenaming for better names with a better straightforward intuition.\n\n1. Rename `interface Api` to `interface Duck`\n1. Rename `class Duck` to `class Bundle`\n1. Rename `function validateDucksApi` to `function validateDuck`\n\n### v0.6 (Jun 1, 2020)\n\nRefactoring the `Ducks` with better Api interface.\n\n1. Added `ducksify()` method for get `Duck` instance by `namespace` or `api`.\n\n### v0.4 (May 30, 2020)\n\nFix the TypeScript Generic Template typing problems:\n\n1. Protect String Literal Types in Action Types [#1](https://github.com/huan/ducks/issues/1)\n1. Property 'payload' is missing in type 'AnyAction' [#2](https://github.com/huan/ducks/issues/2)\n\n### v0.2 (May, 1 2020)\n\n1. Published the very first version of [Ducks Modular Proposal](https://github.com/erikras/ducks-modular-redux) to Ducks!\n\n## Thanks\n\n[@gobwas](https://github.com/gobwas) is the gentleman who owned this [ducks](https://www.npmjs.com/package/ducks) NPM module name, and he's so kind for letting me use this great NPM module name `ducks` for my project. Appreciate it!\n\n## Badge\n\n### Powered by Ducks\n\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Powered by Ducks](https://img.shields.io/badge/Powered%20by-Ducks-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n### Ducksify\n\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n\n```md\n[![Ducksify Extension](https://img.shields.io/badge/Redux-Ducksify%202020-yellowgreen)](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)\n```\n\n## Author\n\n[Huan LI](https://github.com/huan) ([李卓桓](http://linkedin.com/in/zixia)), Microsoft Regional Director, \\<zixia@zixia.net\\>\n\n[![Profile of Huan LI (李卓桓) on StackOverflow](https://stackexchange.com/users/flair/265499.png)](https://stackexchange.com/users/265499)\n\n## Copyright & License\n\n- Code & Docs © 2020 Huan LI (李卓桓) \\<zixia@zixia.net\\>\n- Code released under the Apache-2.0 License\n- Docs released under Creative Commons\n","readmeFilename":"README.md","gitHead":"04e8804b60ba54ad8fb10760f37fe7210ddf0db8","_id":"ducks@1.3.2","_nodeVersion":"16.14.0","_npmVersion":"8.3.1","dist":{"integrity":"sha512-NrGqqA8v0QZdxOmLMGSHvNLyxa6lHsZ197CMCK0u/VYIi9wsfGNuTuPPyL9SZJOvw0ImsbM7xk+/w33WdFRMrA==","shasum":"57a19397524a8bdedcc6acb1731a56158f21d48f","tarball":"https://registry.npmjs.org/ducks/-/ducks-1.3.2.tgz","fileCount":561,"unpackedSize":684855,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiIwQ6ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmpggQ//VnlT/eNV80qsfaojbOC7huHAkUEOCtBWwk1PdVktQA7nZQLA\r\nCYXI5V6Wo5Gu1XDkdhSgXPbVnB+NPcAPrQHxOALo3YgTqSI+KOAWj3W7czYd\r\naOQHcOkD3Uj0DD3HwXKYZA+yKuSbTGYNTwvdR0nN2/ZJTzjo8M63dNQ7Odgy\r\nTArcL8OPehECBKDMW6YLqI0RXgtE1WArKiudOYwu70PtOZnf+9lkqYmnuYZY\r\nLmyfeO1zbCP26nBWb8xNCpw6sloNC6DGSnBa4BdBLJHQB9svjKJFln+Hbbs1\r\nTUnrlU+W8K4lQt6EYbp+dcS6ncYoo/ea0VJa7qjCUKeVSldFO8+d1X8CBEjG\r\njQtpPI7ahmdCYGAx4jXKyzJi9eMVl8f68Agtr2oHO/uzzUhSDLZCsY1M/4BF\r\nBpdfbWeVf10NpNOVveEHm7xRF3byJT5nWbDBhRuv1Uop5/2U3cG4/vEg/4fM\r\n30UEGnvjKSwgx0nVHU8YQ3/56VEURLats2UoX/NKYNL1xDE/SLUUFa8ZueSY\r\n9eFX2hRPj04d8btX4IHfQmEyoxSBcgc2pbkl3P34Vvpal9S6iudzD+3rHDBX\r\nI2e5xeEOm9EoLNIcekQ+qyeDmijJAZQA3P5uhUo7tIWHfhCAetapLXXX1DBk\r\nhnwf8k7DJsokDm6BZKiw0L4BkqKGSFaNSbQ=\r\n=MNNm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGCJnt/wWy9E9sbNk6V17mFtRS1F3M3f1wJ0ERMqCrhdAiEAl0ePC5fSEilC8bKVHOySJr2e1FhFbQPek67D+ZlJllg="}]},"_npmUser":{"name":"zixia","email":"zixia@zixia.net"},"directories":{},"maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ducks_1.3.2_1646462010121_0.11977069999970058"},"_hasShrinkwrap":false}},"readme":"","maintainers":[{"name":"zixia","email":"zixia@zixia.net"}],"time":{"modified":"2022-06-16T01:23:27.298Z","created":"2015-08-10T11:15:57.040Z","0.1.0":"2015-08-10T11:15:57.040Z","0.1.1":"2015-08-11T11:10:12.217Z","0.1.2":"2015-08-11T11:20:59.677Z","0.2.0":"2020-05-21T20:13:55.326Z","0.2.2":"2020-05-21T20:26:11.435Z","0.2.3":"2020-05-22T03:00:38.890Z","0.2.5":"2020-05-22T03:16:20.154Z","0.2.6":"2020-05-22T11:38:47.878Z","0.2.7":"2020-05-22T12:23:33.574Z","0.2.8":"2020-05-22T12:43:42.213Z","0.2.9":"2020-05-22T13:01:54.484Z","0.2.14":"2020-05-23T12:15:42.641Z","0.2.15":"2020-05-23T14:42:37.968Z","0.2.16":"2020-05-24T16:09:06.517Z","0.2.17":"2020-05-26T14:27:14.962Z","0.2.18":"2020-05-26T14:33:45.518Z","0.2.19":"2020-05-26T15:03:11.622Z","0.2.20":"2020-05-26T15:39:11.582Z","0.2.21":"2020-05-26T15:43:22.688Z","0.4.3":"2020-05-31T04:19:04.807Z","0.4.4":"2020-05-31T04:46:02.676Z","0.4.5":"2020-05-31T05:54:00.973Z","0.4.6":"2020-05-31T06:33:37.718Z","0.4.7":"2020-05-31T13:09:48.743Z","0.5.3":"2020-05-31T17:53:42.511Z","0.5.4":"2020-05-31T17:58:55.136Z","0.5.5":"2020-06-01T05:09:04.262Z","0.5.6":"2020-06-01T18:42:59.349Z","0.6.1":"2020-06-01T19:15:30.319Z","0.6.2":"2020-06-04T17:04:26.271Z","0.7.2":"2020-06-05T08:43:09.116Z","0.7.5":"2020-06-05T09:00:54.242Z","0.7.6":"2020-06-06T02:15:14.278Z","0.8.1":"2020-06-06T02:16:15.562Z","0.10.1":"2020-06-06T08:26:41.099Z","0.10.2":"2020-06-06T08:33:09.291Z","0.11.5":"2021-09-18T13:44:02.575Z","0.11.6":"2021-09-18T13:45:48.402Z","0.11.7":"2021-09-18T14:15:08.920Z","0.11.10":"2021-09-18T16:21:36.711Z","1.0.1":"2021-10-29T03:33:05.508Z","1.0.2":"2021-10-29T03:34:53.937Z","1.1.1":"2021-11-13T15:53:00.788Z","1.1.2":"2021-11-21T18:55:57.738Z","1.3.2":"2022-03-05T06:33:30.304Z"},"homepage":"https://github.com/huan/ducks#readme","keywords":["redux","ducks"],"repository":{"type":"git","url":"git+https://github.com/huan/ducks.git"},"author":{"name":"Huan LI","email":"zixia@zixia.net","url":"李卓桓"},"bugs":{"url":"https://github.com/huan/ducks/issues"},"license":"Apache-2.0","readmeFilename":""}