master 8643bd7b0cd0 cached
101 files
756.0 KB
197.1k tokens
340 symbols
1 requests
Download .txt
Showing preview only (792K chars total). Download the full file or copy to clipboard to get everything.
Repository: feathersjs-ecosystem/feathers-vuex
Branch: master
Commit: 8643bd7b0cd0
Files: 101
Total size: 756.0 KB

Directory structure:
gitextract_asa44tit/

├── .babelrc
├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   ├── contributing.md
│   ├── issue_template.md
│   └── pull_request_template.md
├── .gitignore
├── .istanbul.yml
├── .npmignore
├── .travis.yml
├── .vscode/
│   └── launch.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── docs/
│   ├── .vuepress/
│   │   └── config.js
│   ├── 2.0-major-release.md
│   ├── 3.0-major-release.md
│   ├── api-overview.md
│   ├── auth-plugin.md
│   ├── common-patterns.md
│   ├── composition-api.md
│   ├── data-components.md
│   ├── example-applications.md
│   ├── feathers-vuex-forms.md
│   ├── feathervuex-in-vuejs3-setup.md
│   ├── getting-started.md
│   ├── index.md
│   ├── mixins.md
│   ├── model-classes.md
│   ├── nuxt.md
│   ├── service-plugin.md
│   └── vue-plugin.md
├── mocha.opts
├── notes.old.md
├── package.json
├── src/
│   ├── FeathersVuexCount.ts
│   ├── FeathersVuexFind.ts
│   ├── FeathersVuexFormWrapper.ts
│   ├── FeathersVuexGet.ts
│   ├── FeathersVuexInputWrapper.ts
│   ├── FeathersVuexPagination.ts
│   ├── auth-module/
│   │   ├── auth-module.actions.ts
│   │   ├── auth-module.getters.ts
│   │   ├── auth-module.mutations.ts
│   │   ├── auth-module.state.ts
│   │   ├── make-auth-plugin.ts
│   │   └── types.ts
│   ├── index.ts
│   ├── make-find-mixin.ts
│   ├── make-get-mixin.ts
│   ├── service-module/
│   │   ├── global-clients.ts
│   │   ├── global-models.ts
│   │   ├── make-base-model.ts
│   │   ├── make-service-module.ts
│   │   ├── make-service-plugin.ts
│   │   ├── service-module.actions.ts
│   │   ├── service-module.events.ts
│   │   ├── service-module.getters.ts
│   │   ├── service-module.mutations.ts
│   │   ├── service-module.state.ts
│   │   └── types.ts
│   ├── useFind.ts
│   ├── useGet.ts
│   ├── utils.ts
│   └── vue-plugin/
│       └── vue-plugin.ts
├── stories/
│   ├── .npmignore
│   ├── FeathersVuexFormWrapper.stories.js
│   └── FeathersVuexInputWrapper.stories.js
├── test/
│   ├── auth-module/
│   │   ├── actions.test.js
│   │   └── auth-module.test.ts
│   ├── auth.test.js
│   ├── fixtures/
│   │   ├── fake-data.js
│   │   ├── feathers-client.js
│   │   ├── server.js
│   │   ├── store.js
│   │   └── todos.js
│   ├── index.test.ts
│   ├── make-find-mixin.test.ts
│   ├── service-module/
│   │   ├── make-service-plugin.test.ts
│   │   ├── misconfigured-client.test.ts
│   │   ├── model-base.test.ts
│   │   ├── model-instance-defaults.test.ts
│   │   ├── model-methods.test.ts
│   │   ├── model-relationships.test.ts
│   │   ├── model-serialize.test.ts
│   │   ├── model-temp-ids.test.ts
│   │   ├── model-tests.test.ts
│   │   ├── service-module.actions.test.ts
│   │   ├── service-module.getters.test.ts
│   │   ├── service-module.mutations.test.ts
│   │   ├── service-module.reinitialization.test.ts
│   │   ├── service-module.test.ts
│   │   └── types.ts
│   ├── test-utils.ts
│   ├── use/
│   │   ├── InstrumentComponent.js
│   │   ├── find.test.ts
│   │   └── get.test.ts
│   ├── utils.test.ts
│   └── vue-plugin.test.ts
├── tsconfig.json
└── tsconfig.test.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .babelrc
================================================
{
  "plugins": [ "add-module-exports" ],
  "presets": [
    [ "env", { "modules": false } ],
    "es2015",
    "stage-2"
  ]
}


================================================
FILE: .editorconfig
================================================
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: marshallswain


================================================
FILE: .github/contributing.md
================================================
# Contributing to Feathers

Thank you for contributing to Feathers! :heart: :tada:

This repo is the main core and where most issues are reported. Feathers embraces modularity and is broken up across many repos. To make this easier to manage we currently use [Zenhub](https://www.zenhub.com/) for issue triage and visibility. They have a free browser plugin you can install so that you can see what is in flight at any time, but of course you also always see current issues in Github.

## Report a bug

Before creating an issue please make sure you have checked out the docs, specifically the [FAQ](https://docs.feathersjs.com/help/faq.html) section. You might want to also try searching Github. It's pretty likely someone has already asked a similar question.

If you haven't found your answer please feel free to join our [slack channel](http://slack.feathersjs.com), create an issue on Github, or post on [Stackoverflow](http://stackoverflow.com) using the `feathers` or `feathersjs` tag. We try our best to monitor Stackoverflow but you're likely to get more immediate responses in Slack and Github.

Issues can be reported in the [issue tracker](https://github.com/feathersjs/feathers/issues).  Since feathers combines many modules it can be hard for us to assess the root cause without knowing which modules are being used and what your configuration looks like, so **it helps us immensely if you can link to a simple example that reproduces your issue**.

## Report a Security Concern

We take security very seriously at Feathers. We welcome any peer review of our 100% open source code to ensure nobody's Feathers app is ever compromised or hacked. As a web application developer you are responsible for any security breaches. We do our very best to make sure Feathers is as secure as possible by default.

In order to give the community time to respond and upgrade we strongly urge you report all security issues to us. Send one of the core team members a PM in [Slack](http://slack.feathersjs.com) or email us at hello@feathersjs.com with details and we will respond ASAP.

For full details refer to our [Security docs](https://docs.feathersjs.com/SECURITY.html).

## Pull Requests

We :heart: pull requests and we're continually working to make it as easy as possible for people to contribute, including a [Plugin Generator](https://github.com/feathersjs/generator-feathers-plugin) and a [common test suite](https://github.com/feathersjs/feathers-service-tests) for database adapters.

We prefer small pull requests with minimal code changes. The smaller they are the easier they are to review and merge. A core team member will pick up your PR and review it as soon as they can. They may ask for changes or reject your pull request. This is not a reflection of you as an engineer or a person. Please accept feedback graciously as we will also try to be sensitive when providing it.

Although we generally accept many PRs they can be rejected for many reasons. We will be as transparent as possible but it may simply be that you do not have the same context or information regarding the roadmap that the core team members have. We value the time you take to put together any contributions so we pledge to always be respectful of that time and will try to be as open as possible so that you don't waste it. :smile:

**All PRs (except documentation) should be accompanied with tests and pass the linting rules.**

### Code style

Before running the tests from the `test/` folder `npm test` will run ESlint. You can check your code changes individually by running `npm run lint`.

### ES6 compilation

Feathers uses [Babel](https://babeljs.io/) to leverage the latest developments of the JavaScript language. All code and samples are currently written in ES2015. To transpile the code in this repository run

> npm run compile

__Note:__ `npm test` will run the compilation automatically before the tests.

### Tests

[Mocha](http://mochajs.org/) tests are located in the `test/` folder and can be run using the `npm run mocha` or `npm test` (with ESLint and code coverage) command.

### Documentation

Feathers documentation is contained in Markdown files in the [feathers-docs](https://github.com/feathersjs/feathers-docs) repository. To change the documentation submit a pull request to that repo, referencing any other PR if applicable, and the docs will be updated with the next release.

## External Modules

If you're written something awesome for Feathers, the Feathers ecosystem, or using Feathers please add it to the [showcase](https://docs.feathersjs.com/why/showcase.html). You also might want to check out the [Plugin Generator](https://github.com/feathersjs/generator-feathers-plugin) that can be used to scaffold plugins to be Feathers compliant from the start.

If you think it would be a good core module then please contact one of the Feathers core team members in [Slack](http://slack.feathersjs.com) and we can discuss whether it belongs in core and how to get it there. :beers:

## Contributor Code of Conduct

As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.

We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.

Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.

This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)


================================================
FILE: .github/issue_template.md
================================================
### Steps to reproduce

(First please check that this issue is not already solved as [described
here](https://github.com/feathersjs/feathers/blob/master/.github/contributing.md#report-a-bug))

- [ ] Tell us what broke. The more detailed the better.
- [ ] If you can, please create a simple example that reproduces the issue and link to a gist, jsbin, repo, etc.

### Expected behavior
Tell us what should happen

### Actual behavior
Tell us what happens instead

### System configuration

Tell us about the applicable parts of your setup.

**Module versions** (especially the part that's not working):

**NodeJS version**:

**Operating System**:

**Browser Version**:

**React Native Version**:

**Module Loader**:

================================================
FILE: .github/pull_request_template.md
================================================
### Summary

(If you have not already please refer to the contributing guideline as [described
here](https://github.com/feathersjs/feathers/blob/master/.github/contributing.md#pull-requests))

- [ ] Tell us about the problem your pull request is solving.
- [ ] Are there any open issues that are related to this?
- [ ] Is this PR dependent on PRs in other repos?

If so, please mention them to keep the conversations linked together.

### Other Information

If there's anything else that's important and relevant to your pull
request, mention that information here. This could include
benchmarks, or other information.

Your PR will be reviewed by a core team member and they will work with you to get your changes merged in a timely manner. If merged your PR will automatically be added to the changelog in the next release.

If your changes involve documentation updates please mention that and link the appropriate PR in [feathers-docs](https://github.com/feathersjs/feathers-docs).

Thanks for contributing to Feathers! :heart:

================================================
FILE: .gitignore
================================================
.DS_Store

# Logs
logs
*.log

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directory
# Commenting this out is preferred by some people, see
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
node_modules

# Users Environment Variables
.lock-wscript

# The compiled/babelified modules
lib/

# Editor directories and files
.idea
.vscode/settings.json
*.suo
*.ntvs*
*.njsproj
*.sln
/dist


================================================
FILE: .istanbul.yml
================================================
verbose: false
instrumentation:
  root: ./src/
  excludes:
    - lib/
  include-all-sources: true
reporting:
  print: summary
  reports:
    - html
    - text
    - lcov
  watermarks:
    statements: [50, 80]
    lines: [50, 80]
    functions: [50, 80]
    branches: [50, 80]

================================================
FILE: .npmignore
================================================
.editorconfig
.jshintrc
.travis.yml
.istanbul.yml
.babelrc
.idea/
test/
!lib/


================================================
FILE: .travis.yml
================================================
language: node_js
node_js: node
cache: yarn
addons:
  code_climate:
    repo_token: 'your repo token'
  firefox: "51.0"
services:
  - xvfb
notifications:
  email: false

================================================
FILE: .vscode/launch.json
================================================
{
  // Use IntelliSense to learn about possible Node.js debug attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "TS - Mocha Tests",
      "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
      "args": [
        "--require",
        "ts-node/register",
        "-u",
        "bdd",
        "--timeout",
        "999999",
        "--colors",
        "--recursive",
        "${workspaceFolder}/test/**/*.ts"
      ],
      "env": {
        "TS_NODE_PROJECT": "tsconfig.test.json"
      },
      "internalConsoleOptions": "openOnSessionStart"
    },
    {
      "type": "node",
      "request": "launch",
      "name": "Launch Program",
      "program": "${workspaceRoot}/lib/",
      "cwd": "${workspaceRoot}"
    },
    {
      "type": "node",
      "request": "attach",
      "name": "Attach to Process",
      "port": 5858
    }
  ]
}


================================================
FILE: CHANGELOG.md
================================================
# Change Log

## [v1.0.0-pre.3](https://github.com/feathersjs/feathers-vuex/tree/v1.0.0-pre.3) (2017-08-26)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v1.0.0-pre.2...v1.0.0-pre.3)

**Closed issues:**

- \[Proposal\] Allow existing store modules to provide additional properties like the customActions, etc. [\#36](https://github.com/feathersjs/feathers-vuex/issues/36)

## [v1.0.0-pre.2](https://github.com/feathersjs/feathers-vuex/tree/v1.0.0-pre.2) (2017-08-24)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v1.0.0-pre.1...v1.0.0-pre.2)

## [v1.0.0-pre.1](https://github.com/feathersjs/feathers-vuex/tree/v1.0.0-pre.1) (2017-08-22)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.8.0...v1.0.0-pre.1)

**Closed issues:**

- Update mutation not changing store or backend [\#38](https://github.com/feathersjs/feathers-vuex/issues/38)
- namespaces cannot be arrays for nested modules \(supported by vuex\) [\#34](https://github.com/feathersjs/feathers-vuex/issues/34)
- using deep-assign package [\#15](https://github.com/feathersjs/feathers-vuex/issues/15)

## [v0.8.0](https://github.com/feathersjs/feathers-vuex/tree/v0.8.0) (2017-08-18)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.7.2...v0.8.0)

**Closed issues:**

- How to setup vuex and vue-router to redirect when a store value is not set? [\#37](https://github.com/feathersjs/feathers-vuex/issues/37)
- OAuth with Google and feathers-vuex [\#33](https://github.com/feathersjs/feathers-vuex/issues/33)

**Merged pull requests:**

- Support array namespaces for module nesting [\#35](https://github.com/feathersjs/feathers-vuex/pull/35) ([jskrzypek](https://github.com/jskrzypek))

## [v0.7.2](https://github.com/feathersjs/feathers-vuex/tree/v0.7.2) (2017-08-04)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.7.1...v0.7.2)

**Closed issues:**

- Mapped Action is not a function [\#31](https://github.com/feathersjs/feathers-vuex/issues/31)
- Real time updates stops working sometimes depending on the query [\#28](https://github.com/feathersjs/feathers-vuex/issues/28)

**Merged pull requests:**

- Return Promise.reject for action path of services when catching an er… [\#32](https://github.com/feathersjs/feathers-vuex/pull/32) ([phenrigomes](https://github.com/phenrigomes))

## [v0.7.1](https://github.com/feathersjs/feathers-vuex/tree/v0.7.1) (2017-07-08)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.7.0...v0.7.1)

**Closed issues:**

- errorOnAuthenticate is not reset [\#29](https://github.com/feathersjs/feathers-vuex/issues/29)
- Hoping to support server paging parameters [\#23](https://github.com/feathersjs/feathers-vuex/issues/23)

**Merged pull requests:**

- Fix 29 [\#30](https://github.com/feathersjs/feathers-vuex/pull/30) ([mgesmundo](https://github.com/mgesmundo))

## [v0.7.0](https://github.com/feathersjs/feathers-vuex/tree/v0.7.0) (2017-06-27)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.6.0...v0.7.0)

**Merged pull requests:**

- Remove “feathers” module completely [\#27](https://github.com/feathersjs/feathers-vuex/pull/27) ([marshallswain](https://github.com/marshallswain))

## [v0.6.0](https://github.com/feathersjs/feathers-vuex/tree/v0.6.0) (2017-06-27)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.5.0...v0.6.0)

**Merged pull requests:**

- Allow customizing a service’s default store [\#26](https://github.com/feathersjs/feathers-vuex/pull/26) ([marshallswain](https://github.com/marshallswain))

## [v0.5.0](https://github.com/feathersjs/feathers-vuex/tree/v0.5.0) (2017-06-27)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.4.2...v0.5.0)

**Closed issues:**

- Are feathers-reactive and RxJS dependencies necessary? [\#22](https://github.com/feathersjs/feathers-vuex/issues/22)
- Weird / destructive behaviour using mapActions service find between components [\#21](https://github.com/feathersjs/feathers-vuex/issues/21)
- removeItems action added after create when upgrading version from version 0.4.0 to 0.4.1 [\#19](https://github.com/feathersjs/feathers-vuex/issues/19)

**Merged pull requests:**

- Remove all non-serializable data from the state [\#25](https://github.com/feathersjs/feathers-vuex/pull/25) ([marshallswain](https://github.com/marshallswain))
- Opt in to `autoRemove` [\#24](https://github.com/feathersjs/feathers-vuex/pull/24) ([marshallswain](https://github.com/marshallswain))

## [v0.4.2](https://github.com/feathersjs/feathers-vuex/tree/v0.4.2) (2017-06-07)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.4.1...v0.4.2)

**Closed issues:**

- What is the benefit to convert data in feathers to vuex instead of accessing feathers services directly? [\#18](https://github.com/feathersjs/feathers-vuex/issues/18)
- items not being removed from the list - fix proposal [\#12](https://github.com/feathersjs/feathers-vuex/issues/12)

**Merged pull requests:**

- QuickFix: Use idField for removal [\#20](https://github.com/feathersjs/feathers-vuex/pull/20) ([cmeissl](https://github.com/cmeissl))

## [v0.4.1](https://github.com/feathersjs/feathers-vuex/tree/v0.4.1) (2017-05-26)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.4.0...v0.4.1)

**Closed issues:**

- Is possible to upload a file using feathers-vuex? [\#11](https://github.com/feathersjs/feathers-vuex/issues/11)
- Integration with Nuxt [\#8](https://github.com/feathersjs/feathers-vuex/issues/8)

**Merged pull requests:**

- Bugfix - add params to patch action service call [\#14](https://github.com/feathersjs/feathers-vuex/pull/14) ([ndamjan](https://github.com/ndamjan))
- fix item removal in addOrUpdateList \(\#12\) [\#13](https://github.com/feathersjs/feathers-vuex/pull/13) ([ndamjan](https://github.com/ndamjan))

## [v0.4.0](https://github.com/feathersjs/feathers-vuex/tree/v0.4.0) (2017-05-01)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.3.1...v0.4.0)

## [v0.3.1](https://github.com/feathersjs/feathers-vuex/tree/v0.3.1) (2017-05-01)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.3.0...v0.3.1)

## [v0.3.0](https://github.com/feathersjs/feathers-vuex/tree/v0.3.0) (2017-05-01)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.2.2...v0.3.0)

**Merged pull requests:**

- Node: Keep functions out of Vuex state [\#9](https://github.com/feathersjs/feathers-vuex/pull/9) ([marshallswain](https://github.com/marshallswain))

## [v0.2.2](https://github.com/feathersjs/feathers-vuex/tree/v0.2.2) (2017-04-28)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.2.1...v0.2.2)

## [v0.2.1](https://github.com/feathersjs/feathers-vuex/tree/v0.2.1) (2017-04-18)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.2.0...v0.2.1)

**Closed issues:**

- `clearList` mutation behaves unexpectedly if `current` isn't defined [\#5](https://github.com/feathersjs/feathers-vuex/issues/5)

**Merged pull requests:**

- Fix clearList unexpected behavior. Closes \#5 [\#6](https://github.com/feathersjs/feathers-vuex/pull/6) ([silvestreh](https://github.com/silvestreh))

## [v0.2.0](https://github.com/feathersjs/feathers-vuex/tree/v0.2.0) (2017-04-18)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.1.1...v0.2.0)

**Merged pull requests:**

- Actions [\#4](https://github.com/feathersjs/feathers-vuex/pull/4) ([marshallswain](https://github.com/marshallswain))

## [v0.1.1](https://github.com/feathersjs/feathers-vuex/tree/v0.1.1) (2017-04-18)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.1.0...v0.1.1)

## [v0.1.0](https://github.com/feathersjs/feathers-vuex/tree/v0.1.0) (2017-04-18)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.0.5...v0.1.0)

**Merged pull requests:**

- Service tests clear list [\#3](https://github.com/feathersjs/feathers-vuex/pull/3) ([marshallswain](https://github.com/marshallswain))
- add before-install script [\#2](https://github.com/feathersjs/feathers-vuex/pull/2) ([marshallswain](https://github.com/marshallswain))

## [v0.0.5](https://github.com/feathersjs/feathers-vuex/tree/v0.0.5) (2017-04-15)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.0.4...v0.0.5)

**Merged pull requests:**

- Update readme.md [\#1](https://github.com/feathersjs/feathers-vuex/pull/1) ([marshallswain](https://github.com/marshallswain))

## [v0.0.4](https://github.com/feathersjs/feathers-vuex/tree/v0.0.4) (2017-04-12)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.0.3...v0.0.4)

## [v0.0.3](https://github.com/feathersjs/feathers-vuex/tree/v0.0.3) (2017-03-15)
[Full Changelog](https://github.com/feathersjs/feathers-vuex/compare/v0.0.2...v0.0.3)

## [v0.0.2](https://github.com/feathersjs/feathers-vuex/tree/v0.0.2) (2017-03-15)


\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*

================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2016 Feathers

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



================================================
FILE: README.md
================================================
# Feathers-Vuex

[![Build Status](https://travis-ci.org/feathersjs-ecosystem/feathers-vuex.png?branch=master)](https://travis-ci.org/feathersjs-ecosystem/feathers-vuex)
[![Dependency Status](https://img.shields.io/david/feathersjs-ecosystem/feathers-vuex.svg?style=flat-square)](https://david-dm.org/feathersjs-ecosystem/feathers-vuex)
[![Download Status](https://img.shields.io/npm/dm/feathers-vuex.svg?style=flat-square)](https://www.npmjs.com/package/feathers-vuex)
[![Greenkeeper badge](https://badges.greenkeeper.io/feathersjs-ecosystem/feathers-vuex.svg)](https://greenkeeper.io/)

`Feathers-Vuex` is a first class integration of FeathersJS and Vuex. It implements many Redux best practices under the hood, eliminates _a lot_ of boilerplate code with flexible data modeling, and still allows you to easily customize the Vuex store.

![feathers-vuex service logo](./service-logo.png)

## Demo & Documentation

[Demo](https://codesandbox.io/s/xk52mqm7o)

See [https://vuex.feathersjs.com](https://vuex.feathersjs.com) for full documentation.

## Installation

```bash
npm install feathers-vuex --save
```

```bash
yarn add feathers-vuex
```

IMPORTANT: Feathers-Vuex is (and requires to be) published in ES6 format for full compatibility with JS classes. If your project uses Babel, it must be configured properly. See the [Project Configuration](https://vuex.feathersjs.com/getting-started.html#project-configuration) section for more information.

## Contributing

This repo is pre-configured to work with the Visual Studio Code debugger. After running `yarn install`, use the "Mocha Tests" debug script for a smooth debugging experience.

## License

Copyright (c) Forever and Ever, or at least the current year.

Licensed under the [MIT license](https://github.com/feathersjs-ecosystem/feathers-vuex/blob/master/LICENSE).


================================================
FILE: docs/.vuepress/config.js
================================================
module.exports = {
  title: 'FeathersVuex',
  description: 'Integration of FeathersJS, Vue, and Nuxt for the artisan developer',
  head: [['link', { rel: 'icon', href: '/favicon.ico' }]],
  theme: 'default-prefers-color-scheme',
  themeConfig: {
    repo: 'feathersjs-ecosystem/feathers-vuex',
    docsDir: 'docs',
    editLinks: true,
    sidebar: [
      '/api-overview.md',
      '/3.0-major-release.md',
      '/getting-started.md',
      '/example-applications.md',
      '/vue-plugin.md',
      '/service-plugin.md',
      '/auth-plugin.md',
      '/model-classes.md',
      '/common-patterns.md',
      '/composition-api.md',
      '/mixins.md',
      '/data-components.md',
      '/feathers-vuex-forms.md',
      '/nuxt.md',
      '/2.0-major-release.md',
    ],
    serviceWorker: {
      updatePopup: true
    }
  }
}


================================================
FILE: docs/2.0-major-release.md
================================================
---
title: 2.0 Breaking Changes
sidebarDepth: 3
---

# 2.0 Breaking Changes

The biggest change in Feathers-Vuex 2.0 is that it has been refactored with TypeScript!  (It's mostly ES6, still)

Your project does NOT require to be written in TypeScript.  The `dist` is compiled to ES6.

## Fixing the build for older Vue-CLI Apps

As of October 2019, up-to-date Vue-CLI apps are able to properly build and use `feathers-vuex` after adding `transpileDependencies`.  For apps based on older modules, I've found the simplest solution to be to copy the `feathers-vuex` module into `src/libs` inside your project.  Create a `copy-deps.sh` file in the root of your project and setup the following:

```bash
rm -rf src/libs
mkdir src/libs

# feathers-vuex
cp -r node_modules/feathers-vuex/dist src/libs/feathers-vuex
```

Then in `package.json`, create a script that uses the `copy-deps.sh` file:

```json
{
  "copy": ". ./copy-deps.sh",
  "serve": "npm run copy && vue-cli-service serve",
  "build": "npm run copy && vue-cli-service build",
  "postinstall": "npm run copy"
}
```

It's not the prettiest solution, but it works well and is the simplest for older apps.

## Here's what's new in `feathers-vuex`

Check out the tests for the best documentation.  They've been reorganized.  This is still a Work in Progress.

## Changes to Initialization

1. To assist in connecting with multiple FeathersJS API servers, a new `serverAlias` option is now required.  This requires a simple addition to the initial options.
2. The exports have changed.
  - (a) A new `BaseModel` is available.  This is the base `FeathersVuexModel` which contains the model methods. Feel free to extend it and make it fit your awesome services!
  - (b) The `service` method has been renamed to `makeServicePlugin`.
  - (c) The `auth` method is now called `makeAuthPlugin`
  - (d) The `models` object is now exported, so you can access them from anywhere.  They are keyed by `serverAlias`.
  - (e) A new `clients` object is available. The intention is to allow working with multiple FeathersJS API servers.
3. You no longer pass a `servicePath` to create a service-plugin. Instead, pass the actual Feathers service.
4. Since you can customize the Model, you also pass the extended Model into the `makeServicePlugin` method.

Below is an all-in-one example of a the basic configuration steps.  See the next section for how to setup a project.

```js
// ./src/store/store.js
import feathers from './feathers-client'
import Vuex from 'vuex'
import feathersVuex from 'feathers-vuex'

const {
  BaseModel,         // (2a)
  makeServicePlugin, // (2b)
  makeAuthPlugin,    // (2c)
  models,            // (2d)
  clients            // (2e)
} = feathersVuex(feathers, {
  idField: '_id',
  serverAlias: 'myApi' // (1)
})

class Todo extends BaseModel {
  // required
  constructor (data, options) {
    super(data, options)
  }
  // required
  static modelName = 'Todo'

  // optional, but useful
  static instanceDefaults(data) {
    return {
      name: '',
      isComplete: false,
      userId: null,
      user: null // populated on the server
    }
  }

  // optional, but useful
  static setupInstance(data) {
    if (data.user) {
      data.user = new models.myApi.User(data.user)
    }
    return data
  }
  // customize the model as you see fit!
}

const todosPlugin = makeServicePlugin({
  Model: Todo, // (3)
  service: feathers.service('todos') // (4)
})

const store = new Vuex.Store({
  plugins: [
    todosPlugin
  ]
})
```

## Feathers-Vuex Vue plugin changes

The Vue plugin is registered in exactly the same way.  The difference comes when you try to find the Model classes in the `$FeathersVuex` object.  Instead of finding models directly on the `$FeathersVuex` object, they are namespaced by the `serverAlias` you provided.  This allows cleaner support for multiple APIs.  Supposing you had this code in a component, previously...

```js
created () {
  // The old way
  const { Todo } = this.$FeathersVuex
}
```

Modify it to include the new `serverAlias`.  Suppose you set a `serverAlias` of `myApi`, you'd put this in the new version:

```js
created () {
  // The new way includes the `serverAlias` of '.myApi'
  const { Todo } = this.$FeathersVuex.myApi
}
```

## Better default `idField` support

Since records are keyed by id, `feathers-vuex` needs to know what the `idField` is for each service.  In the last version, the default was `id`, and you had to specify something different.  This version supports `id` and `_id` with zero configuration.  You only need to set `idField` when you're using something other than `id` or `_id`.

There's still a warning message when records don't have a property matching the `idField`.  Just like in the last version, it only appears when you turn on `debug: true` in the options.

## Support for Temporary Records

Feathers-Vuex 2.0 supports tracking temporary items and automatically assigns a temporary id to new records. It also adds the records to `state.tempsById`.  This is customizable using the `tempIdField` option.

Because of the new ability to handle temporary records, a message is only logged when assigning a temporary id to a record.  The `checkId` utility function has been removed, since this was its main purpose.

## Getters Work with Temporary Records

The `find` getter has been updated to include records from `state.tempsById` when you pass `temps: true` in the params.

The `get` getter has also been updated to work with temp ids.  Pass the tempId the way you normally would pass the id:  `get(tempId)`

## The "currentItem" workflow is no longer supported

The `setCurrent` mutation and `currentId` state encouraged use of a very limiting API.  It's much more common for apps to require more than one current record.  The `createCopy`, `resetCopy` (formerly called `rejectCopy`), `commitCopy`, and `clearCopy` mutations (since v1.x) provide a more flexible solution for implementing the same functionality.  As a result of this, following have been removed from the modules:

- state: `currentID`, `copy`
- getters: `current`, `getCopy`
- mutations: `setCurrent`, `clearCurrent`, `clearList`, `commitCopy`, `clearCopy`, `resetCopy`

## The `diffOnPatch` option has been removed

(See the next section for its replacement.)

I have not been able to find a diffing algorithm that works equally well acroos all schemas.  It's especially difficult for nested schemas.  Because of this, `diffOnPatch` is no longer a global option.  It is being replaced by the `diffOnPatch` static Model method. See the next section.

## Model Classes: BYOD (Bring Your Own Diffing)

> Note: As of `feathers-vuex@3.9.0`, you can also pass `params.data` to the patch object to implement partial patching on objects.  You might choose to use `params.data` instead of `diffOnPatch`.

First, why do any diffing?  On the API server, an `update` request replaces an entire object, but a `patch` request only overwrites the attributes that are provided in the data.  For services with simple schemas, it doesn't really matter.  But if your schema grows really large, it can be supportive to only send the updates instead of the entire object.

A new `diffOnPatch` method is available to override in your extended models.  `diffOnPatch` gets called just before sending the data to the API server.  It gets called with the data and must return the diffed data.  By default, it is set to `diffOnPatch: data => data`.

Below is an example of how you might implement `diffOnPatch`.  You would only ever use this with a cloned instance, otherwise there's nothing to diff.

```js
import { diff } from 'deep-object-diff'
const { makeServicePlugin, BaseModel } = feathersVuex(feathers, { serverAlias: 'myApi' })

class Todo extends BaseModel {
  public constructor (data, options?) {
    super(data, options)
  }
  public static modelName = 'Todo'
  public static diffOnPatch (data) {
    const originalObject = Todo.store.state.keyedById[data._id]
    return diff(originalObject, data)
  }
}

const store = new Vuex.Store({
  plugins: [
    makeServicePlugin({
      Model: Todo,
      service: feathers.service(servicePath)
    })
  ]
})
```

## The `modelName` option has moved

While the original intent was to completely remove the `modelName` option, it's still required after transpiling to ES5.  This is because during transpilation, the class name gets stripped and can't be put back into place.  Since ES5 is the default target for most build environments, the `modelName` is still required to be specified, but it has been moved.  Instead of being an option, it's required as a static property of each class.

Note: Once ES6 is the default target for most build systems, modelName will become optional.  For future upgradability, it's recommended that you give your `modelName` the exact same name as your model class.

```js
const { makeServicePlugin, BaseModel } = feathersVuex(feathers, { serverAlias: 'myApi' })

class Todo extends BaseModel {
  public constructor (data, options?) {
    super(data, options)
  }
  public static modelName = 'Todo' // modelName is required on all Model classes.
  public static exampleProp: string = 'Hello, World! (notice the comma, folks!)'
}

const store = new Vuex.Store({
  plugins: [
    makeServicePlugin({
      Model: Todo,
      service: feathers.service(servicePath)
    })
  ]
})
```

## Options are no longer kept on the Model

The Model class no longer has an `options` property.  You can access the same information through the `Model.store.state[Model.namespace]`.

## The 'apiPrefix' option has been removed

Feathers-Vuex now includes full support for communicating with multiple FeathersJS APIs.  The `apiPrefix` option was a poorly-implemented, hacky, first attempt at this same feature.  Since it didn't work as intended, it has been removed.  See this example test for working with multiple APIs:

```js
import { assert } from 'chai'
import Vue from 'vue'
import Vuex from 'vuex'
import {
  feathersRestClient as feathers,
  makeFeathersRestClient
} from '../../test/fixtures/feathers-client'
import feathersVuex from './index'

it('works with multiple, independent Feathers servers', function() {
  // Connect to myApi, create a Todo Model & Plugin
  const feathersMyApi = makeFeathersRestClient('https://api.my-api.com')
  const myApi = feathersVuex(feathersMyApi, {
    idField: '_id',
    serverAlias: 'myApi'
  })
  class Todo extends myApi.BaseModel {
    public test: boolean = true
  }
  const todosPlugin = myApi.makeServicePlugin({
    Model: Todo,
    service: feathersMyApi.service('todos')
  })

  // Create a Task Model & Plugin on theirApi
  const feathersTheirApi = makeFeathersRestClient('https://api.their-api.com')
  const theirApi = feathersVuex(feathersTheirApi, {
    serverAlias: 'theirApi'
  })
  class Task extends theirApi.BaseModel {
    public test: boolean = true
  }
  const tasksPlugin = theirApi.makeServicePlugin({
    Model: Task,
    service: feathersTheirApi.service('tasks')
  })

  // Register the plugins
  new Vuex.Store({
    plugins: [todosPlugin, tasksPlugin]
  })
  const { models } = myApi

  assert(models.myApi.Todo === Todo)
  assert(!models.theirApi.Todo, `Todo stayed out of the 'theirApi' namespace`)
  assert(models.theirApi.Task === Task)
  assert(!models.myApi.Task, `Task stayed out of the 'myApi' namespace`)

  assert.equal(
    models.myApi.byServicePath[Todo.servicePath],
    Todo,
    'also registered in models.byServicePath'
  )
  assert.equal(
    models.theirApi.byServicePath[Task.servicePath],
    Task,
    'also registered in models.byServicePath'
  )
```

## Services are no longer set up, internally

You no longer just pass a servicePath.  Instead, create the service, then pass the returned service object.

## Simplified Pending Mutations

Previously, there was a mutation for every single variety of method and set/unset pending. (`setFindPending`, `unsetFindPending`, etc.). There were a total of twelve methods for this simple operation. They are now combined into two methods: `setPending(method)` and `unsetPending(method)`.  Here's the difference.

```js
// The old way
commit('setFindPending')
commit('unsetFindPending')

// The new way
commit('setPending', 'find')
commit('unsetPending', 'find')
```

## Simplified Error Mutations

The "error" mutations have been simplified similar to the "pending" mutations:

```js
// The old way
commit('setFindError', error)
commit('clearFindError')

// The new way
commit('setError', { method: 'find', error })
commit('clearError', 'find')
```

## `instanceDefaults` must be a function

In the previous version, you could specify instanceDefaults as an object.  It was buggy and limiting.  In this new version, `instanceDefaults` must always be a function.  See the next section for an example.

## Getter and Setter props go on the Model classes

One of the great features about using Model classes is data-level computed properties.  You get to specify computed properties directly on your data structures instead of inside components, which keeps a better separation of concerns.  In `feathers-vuex@2.x`, since we have direct access to the Model classes, it's the perfect place to define the computed properties:

```js
import feathersClient, {
  makeServicePlugin,
  BaseModel
} from '../../feathers-client'

class User extends BaseModel {
  constructor(data, options) {
    super(data, options)
  }
  static modelName = 'User' // required
  // Computed properties don't go on in the instanceDefaults, anymore.
  static instanceDefaults() {
    return {
      firstName: '',
      lastName: '',
      email: '',
      password: '',
      isAdmin: false,
    }
  }
  // Here's a computed getter
  get fullName() {
    return `${this.firstName} ${this.lastName}`
  }
  // Probably not something you'd do in real life, but it's an example of a setter.
  set fullName(fullName) {
    const [ firstName, lastName ] = fullName.split(' ')
    Object.assign(this, { firstName, lastName })
  }
}
const servicePath = 'users'
const servicePlugin = makeServicePlugin({
  Model: User,
  service: feathersClient.service(servicePath),
  servicePath
})
```

## Relationships have been separated from `instanceDefaults`

Feathers-Vuex 2.0 has a new API for establishing relationships between data.  Before we cover how it works, let's review the old API.

Feathers-Vuex 1.x allowed using the `instanceDefaults` API to both setup default values for Vue reactivity AND establishing relationships between services.  It supported passing a string name that matched a model name to setup a relationship, as shown in this next example.  This was a simple, but very limited API:

```js
// The old way
instanceDefaults: {
  _id: '',
  description: '',
  isCompleted: false,
  user: 'User'
}
```

Any instance data with a matching key would overwrite the same property in the instanceDefaults, which resulted in an inconsistent API.

In Feathers-Vuex 2.0, the `instanceDefaults` work the same for setting defaults with only one exception:  They no longer setup the relationships.  The new `setupInstance` function provides an API that is much more powerful.

As mentioned earlier, it MUST be provided as a function:

```js
// See the `model-instance-defaults.test.ts` file for example usage.
// This is a brief example.
instanceDefaults(data, { models, store}) {
  return {
    _id: '',
    description: '',
    isCompleted: false
    // No user props, here.
  }
}
```

Notice in the above example that we did not return `user`.  Relationships are now handled in the `setupInstance` method.

Where `instanceDefaults` props get overwritten with instance data, the props returned from `setupInstance` overwrite the instance data.  If it were using `Object.assign`, internally (it's not, but IF it were), it would look like the below example, where `data` is the original instance data passed to the constructor.

```js
Object.assign({}, instanceDefaults(data), data, setupInstance(data))
```

## Define Relationships and Modify Data with `setupInstance`

The new `setupInstance` method allows a lot of flexibility in creating new instances.  It has the exact same API as the `instanceDefaults` method.  The only difference is the order in which they are applied to the instance data.

Although it looks similar to `instanceDefaults`, it can't be used for default values.  This is because it overwrites instance data. Having separate methods allows a clean separation between setting up defaults and establishing relationships with other constructors.

```js
// See the `model-relationships.test.ts` file for example usage.
// This is a brief example.
function setupInstance(data, { models, store }) {
  const { User, Tag } = models.myServerAlias // Based on the serverAlias you provide, initially

  // A single User instance
  if (data.user) {
    data.user = new User(data.user)
  }
  // An array of Tag instances
  if (data.tags) {
    data.tags = data.tags.map(t => new Tag(t))
  }
  // A JavaScript Date Object
  if (data.createdAt) {
    data.createdAt = new Date(data.createdAt)
  }
  return data
}
```

Or below is an example that does the exact same thing with one line per attribute:

```js
function setupInstance(data, { models, store }) {
  const { User } = models.myServerAlias

  Object.assign(data, {
    ...(data.user && { user: new User(data.user) }), // A single User instance
    ...(data.tags && { tags: data.tags.map(t => new Tag(t)) }), // An array of Tag instances
    ...(data.createdAt && { createdAt: new Date(data.createdAt) }) // A JavaScript Date Object
  })
  return data
}
```

Where `instanceDefaults` props get replaced by instance data, the props returned from `setupInstance` overwrite the instance data.  If it were using `Object.assign`, internally (it's not, but IF it were), it would look like the below example, where `data` is the original instance data passed to the constructor.

```js
Object.assign({}, instanceDefaults(data), data, setupInstance(data))
```

## Preventing duplicate merge when extending BaseModel with a custom constructor

The BaseModel constructor calls `mergeWithAccessors(this, newData)`.  This utility function correctly copies data between both regular objects and Vue.observable instances.  If you create a class where you need to do your own merging, you probably don't want `mergeWithAccessors` to run twice.  In this case, you can use the `merge: false` BaseModel ___instance option___ to prevent the internal merge.  You can then access the `mergeWithAccessors` method by calling `MyModel.merge(this, newData)`.  Here's an example:

```ts
const { makeServicePlugin, BaseModel } = feathersVuex(feathersClient, {
  serverAlias: 'myApiServer'
})

class Todo extends BaseModel {
  public constructor(data, options?) {
    options.merge = false // Prevent the internal merge from occurring.
    super(data, options)

    // ... your custom constructor logic happens here.

    // Call the static merge method to do your own merging.
    Todo.merge(this, data)
  }
}
```

It's important to note that setting `merge: false` in the options will disable the `setupinstance` function.  You need to manually call it, like this:

```ts
class Todo extends BaseModel {
  public constructor(data, options?) {
    options = options || {}
    options.merge = false // Prevent the internal merge from occurring.
    super(data, options)

    // ... your custom construcor logic happens here.

    // Call setupInstance manually
    const { models, store } = Todo
    // JavaScript fundamentals: if you're using `this` in `setupInstance`, use .call(this, ...)
    const instanceData = Todo.setupInstance.call(this, data, { models, store })
    // If you're not using `this, just call it like normal
    const instanceData = Todo.setupInstance(data, { models, store })

    // Call the static merge method to do your own merging.
    Todo.merge(this, instanceData)
  }
}
```

## Customizing the BaseModel

Because we have access to the BaseModel, we can extend it to do whatever custom stuff we need in our application.  The `feathers-client.js` file is a great, centralized location for accomplishing this:

```js
// src/feathers-client.js
import feathers from '@feathersjs/feathers'
import socketio from '@feathersjs/socketio-client'
import authClient from '@feathersjs/authentication-client'
import io from 'socket.io-client'
import feathersVuex from 'feathers-vuex' // or '@/libs/feathers-vuex' if you're copying feathers-vuex as mentioned earlier.

// Setup the Feathers client
const host = process.env.VUE_APP_API_URL // or set a string here, directly
const socket = io(host, { transports: ['websocket'] })
const feathersClient = feathers()
  .configure(socketio(socket))
  .configure(authClient({ storage: window.localStorage }))

export default feathersClient

// Setup feathers-vuex
const {
  makeServicePlugin,
  makeAuthPlugin,
  BaseModel,
  models,
  clients,
  FeathersVuex
} = feathersVuex(feathersClient, {
  serverAlias: 'api', // or whatever that makes sense for your project
  idField: '_id' // `id` and `_id` are both supported, so this is only necessary if you're using something else.
})

// Note that if you want to
// extend the BaseClass for the rest of the app, this is a great place to do it.
// After you've extended the BaseClass with your CustomClass, export it, here.
class CustomBaseModel extends BaseModel {
  // Optionally add custom functionality for all services, here.
}

// Export all of the utilities for the rest of the app.
export {
  makeAuthPlugin,
  makeServicePlugin,
  BaseModel,
  models,
  clients,
  FeathersVuex,
  CustomBaseModel // Don't forget to export it for use in all other services.
}

```


## Auth plugin changes

With FeathersJS version 4, the user is returned in the authentication response, by default.  This means that it's no longer required to provide a `userService` option to populate the user. 👍

If you would like to enable backwards compatibility with the previous version of Feathers, pass the below code in the makeAuthPlugin.

```js
makeAuthPlugin({
  userService: 'users',
  actions: {
        responseHandler({ commit, state, dispatch }, response) {
      if (response.accessToken) {
        commit('setAccessToken', response.accessToken)
        // Decode the token and set the payload, but return the response
        return feathersClient.passport
          .verifyJWT(response.accessToken)
          .then(payload => {
            commit('setPayload', payload)
            let user = response[state.responseEntityField]
            // If a user was returned in the authenticate response, use that user.
            if (user) {
              if (state.serverAlias && state.userService) {
                const Model = Object.keys(models[state.serverAlias])
                  .map(modelName => models[state.serverAlias][modelName])
                  .find(model => model.servicePath === state.userService)
                if (Model) {
                  user = new Model(user)
                }
              }
              commit('setUser', user)
              // Populate the user if the userService was provided
            } else if (
              state.userService &&
              payload.hasOwnProperty(state.entityIdField)
            ) {
              return dispatch(
                'populateUser',
                payload[state.entityIdField]
              ).then(() => {
                commit('unsetAuthenticatePending')
                return response
              })
            } else {
              commit('unsetAuthenticatePending')
            }
            return response
          })
        // If there was not an accessToken in the response, allow the response to pass through to handle two-factor-auth
      } else {
        return response
      }
    }
  }
```

The above code will override the `responseHandler` auth action to work with the Passport-based version of Feathers Authentication.


## Gotchas


### Don't Perform Queries (Side Effects) in Getters

Don't try to perform a query from within a getter like the example, below.  It will result in an infinite loop:

```js
get user () {
  if (this.userId) {
    const user = Models.User.getFromStore(this.userId)

    // Fetch the User record if we don't already have it
    if (!user) {
      Models.User.get(this.userId)
    }

    return user
  } else {
    return null
  }
}
```

### Using custom query parameters

There are two places where the query operators have to be allowed.

- In the Feathers Client (for the actions): refer to the FeathersJS docs for `whitelist`ing operators.
- Inside feathers-vuex (for the getters): Check out the `paramsForServer` and  `whitelist` options for `feathers-vuex`. Both accept an array of strings representing prop names, but now I can't remember why I determined that I needed both. :)

For the Feathers Client, follow the FeathersJS docs for your database adapter.


================================================
FILE: docs/3.0-major-release.md
================================================
---
title: What's New in 3.0
sidebarDepth: 3
---

# What's new in Feathers-Vuex 3.0

## Vue Composition API Support

Version 3.0 of Feathers-Vuex is the Vue Composition API release!  There were quite a few disappointed (and misinformed:) developers in 2019 when the Vue.js team announced what is now called the Vue Composition API.  From my perspective:

- It is the most powerful feature added to Vue since its first release.
- It improves the ability to create dynamic functionality in components.
- It greatly enhances organization of code in components.
- It encourages code re-use. Check out the [vue-use-web](https://tarektouati.github.io/vue-use-web/) collection for some great examples.

And now it has become the best way to perform queries with Feathers-Vuex.  To find out how to take advantage of the new functionality in your apps, read the [Feather-Vuex Composition API docs](./composition-api.md).

## New `extend` option for `makeServicePlugin` <Badge text="3.9.0+" />

The `makeServicePlugin` now supports an `extend` method that allows customizing the store and gives access to the actual Vuex `store` object, as shown in this example:

```js
import { makeServicePlugin } from ‘feathers-vuex’
import { feathersClient } from ‘./feathers-client.js’

class Todo { /* truncated */ }

export default makeServicePlugin({
  Model: Todo,
  service: feathersClient.service(‘todos’),
  extend({ store, module }) {
    // Listen to other parts of the store
    store.watch(/* truncated */)

    return {
      state: {},
      getters: {},
      mutations: {},
      actions: {}
    }
  }
})
```

## Partial data on patch <Badge text="3.9.0+" />
As of version 3.9.0, you can provide an object as `params.data`, and Feathers-Vuex will use `params.data` as the patch data.  This change was made to the service-module, itself, so it will work for `patch` across all of feathers-vuex.  Here's an example of patching with partial data:

```js
import { models } from 'feathers-vuex'
const { Todo } = models.api

const todo = new Todo({ description: 'Do Something', isComplete: false })

todo.patch({ data: { isComplete: true } })

// also works for patching with instance.save
todo.save({ data: { isComplete: true } })
```

## FeathersVuexPagination Component <Badge text="3.8.0+" />

To assist with Server Side Pagination support, Feathers-Vuex now includes the `<FeathersVuexPagination>` component.  It's a renderless component that removes the boilerplate behind handling pagination in the UI.  Read about it in the [Composition API Docs](/composition-api.html#feathersvuexpagination).

## Custom Handling for Feathers Events <Badge text="3.1.0+" />

Version 3.1 of Feathers-Vuex enables ability to add custom handling for each of the FeathersJS realtime events.  You can read more about it in the [Service Plugin: Events](./service-plugin.md#service-events) docs.

## Breaking Changes

Feathers-Vuex follows semantic versioning.  There are two breaking changes in this release:

### Auth Plugin `user` Not Reactive <Badge text="New API in 3.2.0+" />

Due to changes in how reactivity is applied to service state (it's now using Vue.set under the hood), the `user` state of the `auth` module is no longer reactive.  To fix this issue, two getters have been added to the `auth` state.  They are available when a `userService` is provided to the `makeAuthPlugin` options.

- `user`: returns the reactive, logged-in user from the `userService` specified in the options.
- `isAuthenticated`: a easy to remember boolean attribute for if the user is logged in.

If you depend on a reactive, logged-in user in your apps, here is how to fix the reactivity:

- Replace any reference to `store.state.auth.user` with `store.getters['auth/user']`.

Because the `user` state is no longer reactive, it is logical for it to be removed in the next version.  It will likely be replaced by a `userId` attribute in Feathers-Vuex 4.0.


### Server-Side Pagination Support is Off by Default

The `makeFindMixin` (and the new `useFind` utility) now have server-side pagination support turned off, by default.  Real-time arrays of results are now the default setting.  This really improves the development experience, especially for new users.

To migrate your app to version 3.0, you need to update any `params` where you are using server-side pagination.  It will work as it has been in version 2.0 once you explicitly set `paginate: true` in the params, like this:

```js
import { makeFindMixin } from 'feathers-vuex'

export default {
  name: 'MyComponent',
  mixins: [ makeFindMixin({ service: 'users', watch: true })],
  computed: {
    usersParams() {
      return {
        query: {},
        paginate: true // explicitly enable pagination, now.
      }
    }
  }
}
```

This behavior exactly matches the new `useFind` utility.

## Deprecations

### The `keepCopiesInStore` Option <Badge text="deprecated" type="warning"/>

The `keepCopiesInStore` option is now deprecated.  This was a part of the "clone and commit" API which basically disabled the reason for creating the "clone and commit" API in the first place.

If you're not familiar with the Feathers-Vuex "clone and commit" API, you can learn more about the [built-in data modeling](./model-classes.md) API and the section about [Working with Forms](./feathers-vuex-forms.md#the-clone-and-commit-pattern).

The `keepCopiesInStore` feature is set to be removed in Feathers-Vuex 4.0.

### Auth Plugin State: `user` <Badge text="deprecated" type="warning"/>

As described, earlier on this page, since the Auth Plugin's `user` state is no longer reactive and has been replaced by a `user` getter that IS reactive, the `user` state will be removed in the Feathers-Vuex 4.0.

### Renderless Data Components: `query`, `fetchQuery` and `temps` <Badge text="deprecated type="warning">

To keep consistency with mixins and the composition API it's preferred to use `params` and `fetchParams` instead of the old `query` and `fetchQuery` for renderless data components. Also the `:temps="true"` is deprecated in favour of `:params="{ query: {}, temps: true }"`. This way additional params can be passed to the server if you need some more magic like `$populateParams`.

================================================
FILE: docs/api-overview.md
================================================
---
title: API Overview
sidebarDepth: 3
---

<!--- Usage ------------------------------------------------------------------------------------ -->
[![Build Status](https://travis-ci.org/feathersjs-ecosystem/feathers-vuex.png?branch=master)](https://travis-ci.org/feathersjs-ecosystem/feathers-vuex)
[![Dependency Status](https://img.shields.io/david/feathersjs-ecosystem/feathers-vuex.svg?style=flat-square)](https://david-dm.org/feathersjs-ecosystem/feathers-vuex)
[![Download Status](https://img.shields.io/npm/dm/feathers-vuex.svg?style=flat-square)](https://www.npmjs.com/package/feathers-vuex)

![feathers-vuex service logo](https://github.com/feathersjs-ecosystem/feathers-vuex/raw/master/service-logo.png)

> Integrate the Feathers Client into Vuex

`feathers-vuex` is a first class integration of the Feathers Client and Vuex.  It implements many Redux best practices under the hood, eliminates *a lot* of boilerplate code, and still allows you to easily customize the Vuex store.

These docs are for version 2.x.  For feathers-vuex@1.x, please go to [https://feathers-vuex-v1.netlify.com](https://feathers-vuex-v1.netlify.com).

## Features

- Fully powered by Vuex & Feathers
- Realtime By Default
- Actions With Reactive Data
- Local Queries
- Live Queries
- Feathers Query Syntax
- Vuex Strict Mode Support
- [Client-Side Pagination Support](./service-plugin.md#pagination-and-the-find-getter)
- Fall-Through Caching
- [`$FeathersVuex` Plugin for Vue](./vue-plugin.md)
- [Per-Service Data Modeling](./common-patterns.md#Basic-Data-Modeling-with-instanceDefaults)
- [Clone & Commit](./feathers-vuex-forms.md#the-clone-and-commit-pattern)
- Simplified Auth
- [Per-Record Defaults](./model-classes.md#instancedefaults)
- [Data Level Computed Properties](./2.0-major-release.md#getter-and-setter-props-go-on-the-model-classes)
- [Improved Relation Support](./2.0-major-release.md#define-relationships-and-modify-data-with-setupinstance)
- [Powerful Mixins](./mixins.md)
- [Renderless Data Components](./data-components.md)
- [Renderless Form Component](./feathers-vuex-forms.md#feathersvuexformwrapper) for Simplified Vuex Forms
- [Temporary (Local-only) Record Support](./2.0-major-release.md#support-for-temporary-records) *
- New `useFind` and `useGet` Vue Composition API super powers! <Badge text="3.0.0+" />
- [Server-Powered Pagination Support](./service-plugin.md#pagination-and-the-find-action) *
- [VuePress Dark Mode Support](https://tolking.github.io/vuepress-theme-default-prefers-color-scheme/) for the Docs

`** Improved in v3.0.0`

## License

Licensed under the [MIT license](LICENSE).

Feathers-Vuex is developed and maintained by [Marshall Thompson](https://www.github.com/marshallswain).



================================================
FILE: docs/auth-plugin.md
================================================
---
title: Auth Plugin
---

The Auth module assists setting up user login and logout.

## Setup

See the [Auth Setup](/getting-started.html#auth-plugin) section for an example of how to setup the Auth Plugin.

## Breaking Changes in 2.0

The following breaking changes were made between 1.x and 2.0:

- The `auth` method is now called `makeAuthPlugin`.

## Configuration

You can provide a `userService` in the auth plugin's options to automatically populate the user upon successful login.

## State

It includes the following state by default:

```js
{
  accessToken: undefined, // The JWT
  payload: undefined, // The JWT payload

  userService: null, // Specify the userService to automatically populate the user upon login.
  entityIdField: 'userId', // The property in the payload storing the user id
  responseEntityField: 'user', // The property in the payload storing the user
  user: null, // Deprecated: This is no longer reactive, so use the `user` getter. See below.

  isAuthenticatePending: false,
  isLogoutPending: false,

  errorOnAuthenticate: undefined,
  errorOnLogout: undefined
}
```

## Getters

Two getters are available when a `userService` is provided to the `makeAuthPlugin` options.

- `user`: returns the reactive, logged-in user from the `userService` specified in the options. Returns `null` if not logged in.
- `isAuthenticated`: a easy to remember boolean attribute for if the user is logged in.

## Actions

The following actions are included in the `auth` module.  Login is accomplished through the `authenticate` action.  For logout, use the `logout` action.  It's important to note that the records that were loaded for a user are NOT automatically cleared upon logout.  Because the business logic requirements for that feature would vary from app to app, it can't be baked into Feathers-Vuex.  It must be manually implemented.  The recommended solution is to simply refresh the browser, which clears the data from memory.

- `authenticate`: use instead of `feathersClient.authenticate()`
- `logout`: use instead of `feathersClient.logout()`

If you provided a `userService` and have correctly configured your `entityIdField` and `responseEntityField` (the defaults work with Feathers V4 out of the box), the `user` state will be updated with the logged-in user.  The record will also be reactive, which means when the user record updates (in the users service) the auth user will automatically update, as well.

> Note: The Vuex auth store will not update if you use the feathers client version of the above methods.

## Example

Here's a short example that implements the `authenticate` and `logout` actions.

```js
export default {
  // ...
  methods: {

    login() {
      this.$store.dispatch('auth/authenticate', {
        email: '...',
        password: '...'
      })
    }

    // ...

    logout() {
      this.$store.dispatch('auth/logout')
    }

  }
  // ...
}
```

Note that if you customize the auth plugin's `namespace` then the `auth/` prefix in the above example would change to the provided namespace.


================================================
FILE: docs/common-patterns.md
================================================
---
title: Common Patterns
---

## Set the `idField`

If you have a "WTF this isn't working" moment while setting up a new service, make sure you've set the `idField` property on your service.  In `feathers-vuex@1.x`, the `id` is the default `idField`.  You have to manually set `_id`.  Starting in `feathers-vuex@2.x`, both the `id` and `_id` fields are supported without any configuration, so you only set the `idField` when your service uses something else.

## Enable debugging

You can set `debug: true` in the options to enable some logging to assist with debugging.

## Use the `<FeathersVuexFind>` and `<FeathersVuexGet>` components

Using the new `<FeathersVuexFind>` and `<FeathersVuexGet>` components provides concise access to the best features of `feathers-vuex`, including live queries, reactive lists, custom pagination tracking per component, and fall-through cacheing of local data in the Vuex store.  Check out the [Renderless Data Components](./data-components.html) docs for more details.

## Use the `makeFindMixin` and `makeGetMixin` utilities

The mixin utilities provide the same functionality as the components, but with more power and flexibility.  Check out the [Mixin docs](./mixins.html) for more details.

## Working with TypeScript

As of version 2.0, Feathers-Vuex has been rewritten in TypeScript.

See [this issue](https://github.com/feathersjs-ecosystem/feathers-vuex/issues/114) for suggestions for with TypeScript helpers.

In version 3.0, support for the [Vue Composition API](https://github.com/vuejs/composition-api) was added in the form of the `useFind` and `useGet` utilities.  These new utilities provide the best experience for working with TypeScript.  This is due to two things:

1. Better general TypeScript support in the Vue Composition API.
1. Consistent object-key naming and types in the new utilities.

Read more about how to use them in the [Feathers-Vuex Composition API Docs](./composition-api.md)

## Clearing data upon user logout

The best solution is to simply refresh to clear memory.  The alternative to refreshing would be to perform manual cleanup of the service stores.  Refreshing is much simpler, so it's the officially supported solution.  Feel free to read [this issue](https://github.com/feathersjs-ecosystem/feathers-vuex/issues/10) for more suggestions.

## Accessing the store from hooks

Because the service's Model [is available](./service-plugin.html#The-FeathersClient-Service) at `service.FeathersVuexModel`, you can access the store inside hooks.  This is especially handy if you have some custom attributes in a paginated server response.

As an example, this `speeding-tickets` service has a `summary` attribute that comes back in the response.  We can

```js
import { makeServicePlugin, BaseModel } from '../feathers-client'

class SpeedingTicket extends BaseModel {
  constructor(data, options) {
    super(data, options)
  }
  // Required for $FeathersVuex plugin to work after production transpile.
  static modelName = 'SpeedingTicket'
  // Define default properties here
  static instanceDefaults() {
    return {
      vin: '',
      plateState: ''
    }
  }
}
const servicePath = 'speeding-tickets'
const servicePlugin = makeServicePlugin({
  Model: SpeedingTicket,
  service: feathersClient.service(servicePath),
  servicePath,
  mutations: {
    handleSummaryData (state, summaryData) {
      state.mostRecentSummary = summaryData
    }
  }
})

feathersClient.service(servicePath)
  .hooks({
    after: {
      find: [
        context => {
          const { service, result } = context

          if (result.summary) {
            service.FeathersVuexModel.store.commit('handleSummaryData', result.summary)
          }
        }
      ]
    }
  })
```

## Handling custom server responses

Sometimes your server response may contain more attributes than just database records and pagination data.  You could handle this directly in a component, if it's only needed in that one component,  But, if you need it in multiple components, there are better options.

Depending on what you need to do, you may be able to solve this by [accessing the store from hooks](#Accessing-the-store-from-hooks).  But that solution won't handle a scenario where you need the response data to be already populated in the store.

If you need the response data to already be in the store, you can use the [`afterFind` action](./service-plugin.html#afterFind-response).  Here's what this looks like:

```js
import { makeServicePlugin, BaseModel } from '../feathers-client'

class SpeedingTicket extends BaseModel {
  constructor(data, options) {
    super(data, options)
  }
  // Required for $FeathersVuex plugin to work after production transpile.
  static modelName = 'SpeedingTicket'
  // Define default properties here
  static instanceDefaults() {
    return {
      vin: '',
      plateState: ''
    }
  }
}
const servicePath = 'speeding-tickets'
const servicePlugin = makeServicePlugin({
  Model: SpeedingTicket,
  service: feathersClient.service(servicePath),
  servicePath,
  actions: {
    afterFind ({ commit, dispatch, getters, state }, response) {
      if (response.summary) {
        commit('handleSummaryData', response.summary)
      }
    }
  },
  mutations: {
    handleSummaryData (state, summaryData) {
      state.mostRecentSummary = summaryData
    }
  }
})
```

## Reactive Lists with Live Queries

Using Live Queries will greatly simplify app development.  The `find` getter enables this feature.  Here is how you might setup a component to take advantage of them.  The next example shows how to setup two live-query lists using two getters.

```js
import { mapState, mapGetters, mapActions } from 'vuex'

export default {
  name: 'some-component',
  computed: {
    ...mapState('appointments', { areAppointmentsLoading: 'isFindPending' }),
    ...mapGetters('appointments', { findAppointmentsInStore: 'find' } ),
    // Query for future appointments
    queryUpcoming () {
      return { date: { $gt: new Date() }}
    },
    // Query for past appointments
    queryPast () {
      return { date: { $lt: new Date() }}
    },
    // The list of upcoming appointments.
    upcomingAppointments () {
      return this.findAppointmentsInStore({ query: this.queryUpcoming }).data
    },
    // The list of past appointments
    pastAppointments () {
      return this.findAppointmentsInStore({ query: this.queryPast }).data
    }
  },
  methods: {
    ...mapActions('appointments', { findAppointments: 'find' })
  },
  created () {
    // Find all appointments. We'll use the getters to separate them.
    this.findAppointments({ query: {} })
  }
}
```

in the above example of component code, the `upcomingAppointments` and `pastAppointments` will automatically update.  If a new item is sent from the server, it will get added to one of the lists, automatically.  `feathers-vuex` listens to socket events automatically, so you don't have to manually wire any of this up!

## Organizing the services in your project

You can use the file system to organize each service into its own module. This is especially useful in organizing larger-sized projects.  Here's an example `store.js`.  It uses Webpack's require.context feature save repetitive imports.

See it [here](/getting-started.html#auth-plugin)

With the `store.js` file in place, we can start adding services to the `services` folder.

- [Learn how to setup the feathers-client.js file](/getting-started.html#feathers-client-feathers-vuex)
- [Learn how to setup a Vuex plugin for a Feathers service](/getting-started.html#service-plugins)
- [Learn how to setup the auth plugin](/getting-started.html#auth-plugin)

## Actions return reactive store records

Previously, when you directly used the response from an action, the individual records were not reactive.  This meant that these plain objects wouldn't update when you updated the matching record in the store.

```js
methods: {
  ...mapActions('todos', { findTodos: 'find' })
},
created () {
  this.findTodos({ query: {} })
    .then(response => {
      const todos = response.data || response
      // Suppose firstTodo has an id of 'todo-1'
      const firstTodo = todos[0]

      // Now, when you update the data in the store...
      this.$store.state.todos.keyedById['todo-1'].description = 'Updated description'

      // ... the instance in the `find` response also updates.  Yay!
      console.log(firstTodo.description) // --> 'Updated description'
    })
}
```

This is a super convenient feature, and it works with all actions (except remove, of course) But be aware that **only the individual records returned are reactive**.  The lists, themselves, are not reactive.  So if another record comes in from the server that matches the query, the list will not update.  For reactive lists, you must use the `find` getter, as shown in the following example.

```js
computed: {
  ...mapGetters('todos', { findTodosInStore: 'find' })
  todos () {
    return this.findTodosInStore({ query: {} }).data
  }
},
methods: {
  ...mapActions('todos', { findTodos: 'find' })
},
created () {
  this.findTodos({ query: {} })
    .then(response => {
      // In the find action, the 'todos' array is not a reactive list, but the individual records are.
      const todos = response.data || response
    })
}
```

In the above example, the computed `todos` will be a reactive list.  This means that when new records are added to the store, the list of todos will automatically update in the UI to include the new data.

In summary, you can plan on individual records in the action response data to be reactive, but if you need the actual arrays to be reactive to live queries, use the 'find' getter.

## Basic Data Modeling with `instanceDefaults`

See the [instanceDefaults API](./model-classes.html#instancedefaults)

## Handling Non-Reactive Data

If you are encountering a scenario where certain properties in your records are not reactive, it's probably because they

1. Are not defined in the `instanceDefaults`.
2. Are getting added to the record after it gets added to the Vuex store.

There are two ways to solve this:

1. Add the property to the `instanceDefaults` (see the previous section, above)  This tends to be the simplest solution.
2. Make sure the property is added in the responses from the API server.

## Model-Specific Computed Properties

You may find yourself in a position where model-specific computed properties would be very useful. [github issue](https://github.com/feathersjs-ecosystem/feathers-vuex/issues/163).  In Feathers-Vuex 1.7, these could be specified in the `instanceDefaults`.  As of 2.0, they are specified directly on each Model class:

```js
class Post extends BaseModel {
  // Required for $FeathersVuex plugin to work after production transpile.
  static modelName = 'Post'
  // Define default properties here
  static instanceDefaults() {
    return {
      description: '',
      isComplete: false,
      comments: [],
    }
  }

  // Specify computed properties as regular class properties
  get numberOfCommenters () {
      // Put your logic here.
  },
  set someOtherProp () {
      //  Setters also work
  }
}
```

## Relationships for Populated Data

If you're looking for a great solution for populating data to work with Feathers-Vuex, check out [feathers-graph-populate](https://feathers-graph-populate.netlify.app/).

A common task with almost any API is properly handling relationships between endpoints.  Imagine an API where you have `/todos` and `/users` services.  Each todo record can belong to a single user, so a todo has a `userId`.

```js
// GET todos/1
{
  id: 1,
  description: 'Learn about the health benefits of a low-carb diet.',
  isComplete: false,
  userId: 5
}
```

And a user response looks like this:

```js
// GET users/5
{
  id: 5,
  name: 'Marshall',
  username: 'marshallswain'
  email: 'marshall@ilovehealthy.com'
}
```

Suppose a requirement is put on the `/todos` service to populate the `user` in the response.  (As a super handy side note, this task is pretty easy when using [Matt Chaffe's](https://github.com/mattchewone) magical, efficient [feathers-shallow-populate hook](https://www.npmjs.com/package/feathers-shallow-populate))  So now the todo response looks like this:

```js
{
  id: 1,
  description: 'Learn about the health benefits of a low-carb diet.',
  isComplete: false,
  userId: 5,
  user: {
    id: 5,
    name: 'Marshall',
    username: 'marshallswain'
    email: 'marshall@ilovehealthy.com'
  }
}
```

Can you see the problem that will occur with this response?  When this record is put into the `/todos` store, it will contain a copy of the user record.  But we already have the user record in the `/users` store.  And what happens when the user data changes?  Now it's out of sync.  To keep it in sync, you might have to manually listen for `users updated` & `users patched` events.  Then you might have to write a custom mutation to update the user record attached to every applicable `todo` record.  This gets messy, fast!

There's an easier way to solve this problem. Use the new [`setupInstance` method on Model classes](/model-classes.html#setupinstance).

```js
import feathersClient, { makeServicePlugin, BaseModel } from '../feathers-client'

class Todo extends BaseModel {
  // Required for $FeathersVuex plugin to work after production transpile.
  static modelName = 'Todo'
  // Define default properties here
  static instanceDefaults() {
    return {
      email: '',
      password: ''
    }
  }
  // Updates `data.user` to be an instance of the `User` class.
  static setupInstance(data, { models }) {
    if (data.user) {
      data.user = new models.api.User(data.user)
    }
    return data
  }
}

const servicePath = 'todos'
const servicePlugin = makeServicePlugin({
  Model: Todo,
  service: feathersClient.service(servicePath),
  servicePath
})
```

When this record is instantiated, the `user` attribute will first be turned into a User [model instance](./model-classes.html), stored properly in the `/users` store. The `todo.user` attribute will be a reference to that user.  No more duplicate data!  Here's an example of how to set this up.

There's another amazing benefit from these relationships.  Because `feathers-vuex` listens to real-time events and keeps data up to date, when the user record changes, the `todo.user` automatically updates!

### Handling Sequelize Joins

See [this issue](https://github.com/feathersjs-ecosystem/feathers-vuex/issues/404) for a discussion on how to handle joins with Sequelize.  It's important to specify `raw: false`, as shown in [this comment](https://github.com/feathersjs-ecosystem/feathers-vuex/issues/404#issuecomment-571774598).

### Workflow for Saving Model Associations

A great issue was opened on GitHub about the [Workflow for clone and save Model with associations](https://github.com/feathersjs-ecosystem/feathers-vuex/issues/278).  That's a great issue to read to get familiar with the workflow.

## Form Binding

Use the Model classes to reduce the boilerplate required to work with forms and Vuex, even in strict mode!  Every model instance has a `.clone()` method which can be used to get a fully-reactive copy of the record in the store.  Here is a very simple version of how you could bind to a form and submit new data to the server.

```vue
<template>
  <div class="bg-white h-full p-6">
    <h1>Create Todo</h1>

    <form @submit.prevent="createTodo">
      <input v-model="clone.name" type="text" class="form-input" />
      <button
        type="submit"
        class="bg-blue-500 px-4 py-2 rounded text-white ml-2"
      >
        Create Todo
      </button>
    </form>
  </div>
</template>

<script>
export default {
  name: 'Todos',
  mixins: [makeFindMixin({ service: 'todos', watch: true })],
  data: () => ({
    todo: null,
    clone: null
  }),
  computed: {
    todosParams() {
      return {
        query: {},
        paginate: false
      }
    }
  },
  created() {
    const { Todo } = this.$FeathersVuex.myApi
    this.todo = new Todo({})
    this.clone = this.todo.clone()
  },
  methods: {
    async createTodo() {
      try {
        const todo = await this.clone.save()
        console.log(todo)
      } catch (error) {
        console.log(error)
      }
    },
    updateTodo(ev, todo) {
      todo.isComplete = ev.target.checked
      todo.save()
    }
  }
}
</script>

<style lang="postcss"></style>
```

## Multiple Copies

The previous version of `feathers-vuex` was hard-coded to allow for a single `current` record and one copy.  It was pretty easy to hit that limit.  This new release allows for keeping many more copies, one copy per stored record.  To make it easier to comply with Vuex's `strict` mode, copies are not kept in the store by default, but are instead kept on `Model.copiesById`.  You can make changes to the copies without having to make custom mutations, then you can commit them back into the store:

```js
const { Todo } = this.$FeathersVuex

// Create two records in the store (since they have ids, they get stored)
const todo = new Todo({ id: 1, description: 'Become more aware of others.'})
const todo2 = new Todo({ id: 2, description: 'Heal one ailments through healthy eating.'})

// Create a deep-cloned copies in Todo.copiesById
const todoCopy = todo.clone()
const todoCopy2 = todo2.clone()

// Try to clone a copy, and fail.
todoCopy.clone() // --> Error: You cannot clone a copy.
todoCopy2.clone() // --> Error: You cannot clone a copy.

// Modify the copies.
todoCopy.description.replace('others', 'self')
todoCopy2.description.replace('one', 'all')

// and update the original records
todoCopy.commit()
todoCopy2.commit()
```

You can use the `keepCopiesInStore`<Badge text="deprecated" type="warning"/> option to make this service keep all of its copies in `state.copiesById`.  Remember that to comply with Vuex `strict` mode (if that's a concern for you), you'll have to write custom mutations.  If it's not a concern (maybe you're the sole developer or whatever reason), you could technically turn off `strict` mode, enable `keepCopiesInStore`, and modify them however you desire, ignoring custom mutations.

```js
import Vue from 'vue'
import Vuex from 'vuex'
import feathersVuex from 'feathers-vuex'
import feathersClient from './feathers-client'

const { service, auth, FeathersVuex } = feathersVuex(feathersClient, { idField: '_id' })

Vue.use(FeathersVuex)
Vue.use(Vuex)

export default new Vuex.Store({
  plugins: [
    service('todos', {
      keepCopiesInStore: true,
      instanceDefaults: {
        description: '',
        complete: false
      }
    })
  ]
})
```

## Enable Debug Logging

If items aren't not getting added to the store properly, try setting the `debug` option on the `makeServicePlugin` to `true`.  It enables some additional logging that may be useful for troubleshooting.

## Full nuxt example

In this example we will create a nuxt configuration with all the features discribed in the [Nuxt Section](./nuxt.md).

Our application is hosted in 2 different endpoints, one for the feathers api and another with our nuxt SSR, and we will also implement a permission system that will prevent users without an `admin` permission to get into some pages. For that you will need to [customize your payload](https://docs.feathersjs.com/cookbook/authentication/stateless.html#customizing-the-payload) in your feathers api.

```js
// nuxt.config.js
export default {
  env: {
    API_URL: process.env.API_URL || 'http://localhost:3030'
  },
  router: {
    middleware: [
      'feathers'
    ]
  },
  plugins: [
    { src: '~/plugins/feathers-vuex.js' }
  ],
  modules: [
    'nuxt-client-init-module'
  ],
  build: {
    transpile: [
      'feathers-vuex'
    ]
  }
}
```

The `feathers` middleware will redirect any user in a non public page to the login, but will also redirect a loged user away from any public pages.

```js
// ~/middleware/feathers.js
export default function ({ store, redirect, route }) {
  const { auth } = store.state
  if (auth.publicPages.length > 0 && !auth.publicPages.includes(route.name) && !auth.payload) {
    return redirect('/login')
  } else if (auth.publicPages.length > 0 && auth.publicPages.includes(route.name) && auth.payload) {
    return redirect('/feed')
  }
}
```

The `admin` middleware will redirect any user that is not loged in or do not have the `admin` permission to a `not-permited` page.

```js
// ~/middleware/admin.js
export default function ({ store, redirect }) {
  const { auth } = store.state
  const permissions = auth.payload.permissions
  if (
    !auth.payload ||
    !permissions.includes('admin')
  ) {
    return redirect('/not-permited')
  }
}
```
Add the `admin` middleware to the administrative pages

```js
// ~/pages/**
export default {

  ...

  middleware: ['admin']

  ...

}
```

In the feathers client configuration we will use a different transport for the nuxt-server > api comunication and the nuxt-client > api. When we are making request on the server we do not need the socket io realtime messaging system so we can use an rest configuration for better performance.

```js
// ~/plugins/feathers.js
import feathers from '@feathersjs/feathers'
import rest from '@feathersjs/rest-client'
import axios from 'axios'
import socketio from '@feathersjs/socketio-client'
import auth from '@feathersjs/authentication-client'
import io from 'socket.io-client'
import { CookieStorage } from 'cookie-storage'
import { iff, discard } from 'feathers-hooks-common'
import feathersVuex, { initAuth, hydrateApi } from 'feathers-vuex'
// Get the api url from the environment variable
const apiUrl = process.env.API_URL
let socket
let restClient
// We won't use socket to comunicate from server to server
if (process.client) {
  socket = io(apiUrl, { transports: ['websocket'] })
} else {
  restClient = rest(apiUrl)
}
const transport = process.client ? socketio(socket) : restClient.axios(axios)
const storage = new CookieStorage()

const feathersClient = feathers()
  .configure(transport)
  .configure(auth({ storage }))
  .hooks({
    before: {
      all: [
        iff(
          context => ['create', 'update', 'patch'].includes(context.method),
          discard('__id', '__isTemp')
        )
      ]
    }
  })

export default feathersClient

// Setting up feathers-vuex
const { makeServicePlugin, makeAuthPlugin, BaseModel, models, FeathersVuex } = feathersVuex(
  feathersClient,
  {
    serverAlias: 'api', // optional for working with multiple APIs (this is the default value)
    idField: '_id', // Must match the id field in your database table/collection
    whitelist: ['$regex', '$options'],
    enableEvents: process.client // Prevent memory leak
  }
)

export { makeAuthPlugin, makeServicePlugin, BaseModel, models, FeathersVuex, initAuth, hydrateApi }
```

I prefere install the `FeathersVuex` plugin in a separate file, it's more consistent with nuxt patterns.

```js
// ~/plugins/feathers-vuex.js
import Vue from 'vue'
import { FeathersVuex } from './feathers'

Vue.use(FeathersVuex)
```

Configure any service you want on `~/store/services/*.js`.

```js
// ~/store/services/users.js
import feathersClient, { makeServicePlugin, BaseModel } from '~/plugins/feathers'

class User extends BaseModel {
  constructor(data, options) {
    super(data, options)
  }
  // Required for $FeathersVuex plugin to work after production transpile.
  static modelName = 'User'
  // Define default properties here
  static instanceDefaults() {
    return {
      email: '',
      password: '',
      permissions: []
    }
  }
}
const servicePath = 'users'
const servicePlugin = makeServicePlugin({
  Model: User,
  service: feathersClient.service(servicePath),
  servicePath
})

// Setup the client-side Feathers hooks.
feathersClient.service(servicePath).hooks({
  before: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
  },
  after: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
  },
  error: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
  }
})

export default servicePlugin
```

Create your nuxt store with the right nuxt pattern, exporting an Vuex store will be deprecated on nuxt 3.

```js
// ~/store/index.js
import { makeAuthPlugin, initAuth, hydrateApi, models } from '~/plugins/feathers'
const auth = makeAuthPlugin({
  userService: 'users',
  state: {
    publicPages: [
      'login',
      'signup'
    ]
  },
  actions: {
    onInitAuth ({ state, dispatch }, payload) {
      if (payload) {
        dispatch('authenticate', { strategy: 'jwt', accessToken: state.accessToken })
          .then((result) => {
            // handle success like a boss
            console.log('loged in')
          })
          .catch((error) => {
            // handle error like a boss
            console.log(error)
          })
      }
    }
  }
})

const requireModule = require.context(
  // The path where the service modules live
  './services',
  // Whether to look in subfolders
  false,
  // Only include .js files (prevents duplicate imports`)
  /.js$/
)
const servicePlugins = requireModule
  .keys()
  .map(modulePath => requireModule(modulePath).default)

export const modules = {
  // Custom modules
}

export const state = () => ({
  // Custom state
})

export const mutations = {
  // Custom mutations
}

export const actions = {
  // Custom actions
  nuxtServerInit ({ commit, dispatch }, { req }) {
    return initAuth({
      commit,
      dispatch,
      req,
      moduleName: 'auth',
      cookieName: 'feathers-jwt'
    })
  },
  nuxtClientInit ({ state, dispatch, commit }, context) {

    hydrateApi({ api: models.api })

    if (state.auth.accessToken) {
      return dispatch('auth/onInitAuth', state.auth.payload)
    }
  }
}

export const getters = {
  // Custom getters
}

export const plugins = [ ...servicePlugins, auth ]
```


================================================
FILE: docs/composition-api.md
================================================
---
title: Composition API
sidebarDepth: 3
---

# Feathers-Vuex Composition API <Badge text="3.0.0+" />

In addition to the Renderless Components and the Mixins, Feathers-Vuex includes utilities that let you take advantage of the [Vue Composition API](https://github.com/vuejs/composition-api).

It's important to note that the `@vue/composition-api` plugin must be registered BEFORE you import `App.vue`.  This means that you need to modify your `main.js` file to look like this:

```js
import Vue from 'vue'
import VueCompositionApi from '@vue/composition-api'

// Register the Composition API plugin BEFORE you import App.vue
Vue.use(VueCompositionApi)

import App from './App.vue'
import router from './router'
import store from './store/store'
import './plugins/plugins'
Vue.config.productionTip = true
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')
```

If you forget to register the plugin, first, you will see a console warning from Vue stating `[Vue warn]: Error in data(): "Error: [vue-composition-api] must call Vue.use(plugin) before using any function.".  To fix this, make sure to register the plugin BEFORE you call any Composition utility functions, as shown above.

## Setup

Before you can use the `useFind` and `useGet` composition functions, you'll need to [install the Vue Composition API](https://github.com/vuejs/composition-api#Installation) plugin.

## Detour: Reading a TypeScript interface

The next few sections show various TypeScript interfaces, which are basically shorthand descriptions of the types of data that make up a variable.  In this case, they're used to show the `options` object which can be passed to each of the composition api utilities.  If this is your first time with interfaces, here's a quick primer as an alternative to reading the [TypeScript interface docs](https://www.typescriptlang.org/docs/handbook/interfaces.html):

- In the [first interface example](#options), below, `UseFindOptions` is the name of the interface, similar to naming any other variable.  When using TypeScript, you can import and pass interfaces around like variables.
- Each line of the interface describes a property.
- The part before the `:` is the name of the property.
- The part after the `:` describes what type of variable it can be.
- You can look at any `|` after the `:` as a conditional "or"
- Any property followed by a `?` is optional.
- Any property not followed by a `?` is required.

## useFind <Badge text="3.0.0+" />

The `useFind` utility reduces boilerplate for querying with fall-through cache and realtime updates.  To get started with it you provide a `model` class and a computed `params` object.

Let's use the example of creating a User Guide, where we need to pull in the various `Tutorial` records from our `tutorials` service.  We'll keep it simple in the template and just show a list of the names.

```html
<template>
  <div>
    <li v-for="tutorial in tutorials" :key="tutorial._id">
      {{ tutorial.name }}
    </li>
  </div>
</template>

<script>
import { computed } from '@vue/composition-api'
import { useFind } from 'feathers-vuex'

export default {
  name: 'UserGuide',
  setup(props, context) {
    // 1. Get a reference to the model class
    const { Tutorial } = context.root.$FeathersVuex.api

    // 2. Create a computed property for the params
    const tutorialsParams = computed(() => {
      return {
        query: {}
      }
    })
    // 3. Provide the model and params in the options
    const tutorialsData = useFind({ model: Tutorial, params: tutorialsParams })

    // 4. Return the data, named as you prefer
    return {
      tutorials: tutorialsData.items
    }
  }
}
</script>
```

Let's review each of the numbered comments, above:

1. Get a reference to the model class.  With the Vue Composition API, there's no `this` object.  It has been replaced by the context object.  So, only when using the composition API, the `$FeathersVuex` object is found at `context.root.$FeathersVuex`
2. Create a computed property for the params. Return an object with a nested `query` object.

### Options

Since we learned earlier [how to read a TypeScript interface](#detour-reading-a-typescript-interface), let's look at the TypeScript definition for the `UseFindOptions` interface.

```ts
interface UseFindOptions {
  model: Function
  params: Params | Ref<Params>
  fetchParams?: Params | Ref<Params>
  queryWhen?: Ref<Function>
  qid?: string
  immediate?: boolean
}
```

And here's a look at each individual property:

- `model` must be a Feathers-Vuex Model class. The Model's `find` and `findInStore` methods are used to query data.
- `params` is a FeathersJS Params object OR a Composition API `ref` (or `computed`, since they return a `ref` instance) which returns a Params object.
  - When provided alone (without the optional `fetchParams`), this same query is used for both the local data store and the API requests.
  - Explicitly returning `null` will prevent an API request from being made.
  - You can use `params.qid` to dynamically specify the query identifier for any API request. The `qid` is used for tracking pagination data and enabling the fall-through cache across multiple queries.
  - Set `params.paginate` to `true` to turn off realtime updates for the results and defer pagination to the API server.  Pagination works the same as for the [makeFindMixin pagination](./mixins.html#pagination-with-fall-through-cacheing).
  - Set `params.debounce` to an integer and the API requests will automatically be debounced by that many milliseconds.  For example, setting `debounce: 1000` will assure that the API request will be made at most every 1 second.
  - Set `params.temps` to `true` to include temporary (local-only) items in the results. Temporary records are instances that have been created but not yet saved to the database.
  - Set `params.copies` to `true` to include cloned items in the results. The queried items get replaced with the corresponding copies from `copiesById`
- `fetchParams` This is a separate set of params that, when provided, will become the params sent to the API server.  The `params` will then only be used to query data from the local data store.
  - Explicitly returning `null` will prevent an API request from being made.
- `queryWhen` must be a `computed` property which returns a `boolean`. It provides a logical separation for preventing API requests *outside* of the `params`.
- `qid` allows you to specify a query identifier (used in the pagination data in the store).  This can also be set dynamically by returning a `qid` in the params.
- `immediate`, which is `true` by default, determines if the internal `watch` should fire immediately.  Set `immediate: false` and the query will not fire immediately.  It will only fire on subsequent changes to the params.

### Returned Attributes

Notice the `tutorialsData` in the previous example.  You can see that there's an `tutorialsData.items` property, which is returned at the bottom of the `setup` method as `tutorials`.  There are many more attributes available in the object returned from `useFind`. We can learn more about the return values by looking at its TypeScript interface, below.

```ts
interface UseFindData {
  items: Ref<any>
  paginationData: Ref<object>
  servicePath: Ref<string>
  qid: Ref<string>
  isPending: Ref<boolean>
  haveBeenRequested: Ref<boolean>
  haveLoaded: Ref<boolean>
  error: Ref<Error>
  debounceTime: Ref<number>
  latestQuery: Ref<object>
  isLocal: Ref<boolean>
  find: Function
}
```

Let's look at the functionality that each one provides:

- `items` is the list of results. By default, this list will be reactive, so if new items are created which match the query, they will show up in this list automagically.
- `servicePath` is the FeathersJS service path that is used by the current model. This is mostly only useful for debugging.
- `isPending` is a boolean that indicates if there is an active query.  It is set to `true` just before each outgoing request.  It is set to `false` after the response returns.  Bind to it in the UI to show an activity indicator to the user.
- `haveBeenRequested` is a boolean that is set to `true` immediately before the first query is sent out.  It remains true throughout the life of the component.  This comes in handy for first-load scenarios in the UI.
- `haveLoaded` is a boolean that is set to true after the first API response.  It remains `true` for the life of the component. This also comes in handy for first-load scenarios in the UI.
- `isLocal` is a boolean that is set to true if this data is local only.
- `qid` is currently the primary `qid` provided in params.  It might become more useful in the future.
- `debounceTime` is the current number of milliseconds used as the debounce interval.
- `latestQuery` is an object that holds the latest query information.  It populates after each successful API response. The information it contains can be used to pull data from the `paginationData`.
- `paginationData` is an object containing all of the pagination data for the current service.
- `error` is null until an API error occurs. The error object will be serialized into a plain object and available here.
- `find` is the find method used internally.  You can manually make API requests.  This is most useful for when you have `paginate: true` in the params.  You can manually query refreshed data from the server, when desired.

### Working with Refs

Pay special attention to the properties of type `Ref`, in the TypeScript interface, above.  Those properties are Vue Composition API `ref` instances.  This means that you need to reference their value by using `.value`.  In the next example the `completeTodos` and `incompleteTodos` are derived from the `todos`, using `todos.value`

```html
<template>
  <div>
    <li v-for="tutorial in tutorials" :key="tutorial._id">
      {{ tutorial.name }}
    </li>
  </div>
</template>

<script>
import { computed } from '@vue/composition-api'
import { useFind } from 'feathers-vuex'

export default {
  name: 'UserGuide',
  setup(props, context) {
    const { Todo } = context.root.$FeathersVuex.api

    const todosParams = computed(() => {
      return {
        query: {}
      }
    })
    const { items: todos } = useFind({ model: Todo, params: todosParams })
    // Notice the "todos.value"
    const completeTodos = computed(() => todos.value.filter(todo => todo.isComplete))
    const incompleteTodos = computed(() => todos.value.filter(todo => !todo.isComplete))

    return {
      todos,
      completeTodos,
      incompleteTodos
    }
  }
}
</script>
```

### Comparison to `makeFindMixin`
If you have already used the `makeFindMixin`, the `useFind` composition function will be very familiar, since it offers the same functionality in a more powerful way.  There are a few differences, though.

1. `useFind` is more TypeScript friendly. Since the mixins depended on adding dynamic attribute names that wouldn't overlap, TypeScript tooling and autocomplete weren't very effective.  The attributes returned from `useFind` are always consistent.
1. Instead of providing a service name, you provide a service Model from the `$FeathersVuex` Vue plugin.
1. The default behavior of `useFind` is to immediately query the API server. The `makeFindMixin`, by default, would wait until the watcher noticed the change.  This is to match the default behavior of `watch` in the Vue Composition API.  You can pass `{ immediate: false }` in the `useFind` options, which will be passed directly to the internal `watch` on the params.

Note that with the Vue Options API (aka the only way to write components in Vue 2.0) the models are found in `this.$FeathersVuex`.  With the Vue Composition API, this object is now at `context.root.$FeathersVuex`.

## useGet <Badge text="3.0.0+" />

The `useGet` Composition API utility provides the same fall-through cache functionality as `useFind`.  It has a slightly simpler API, only requiring a `model` and `id` instead of the `params` object.  Still, the `params` object can be used to send along additional query parameters in the request.  Below is an example of how you might use the `useGet` utility.

```html
<template>
  <div>
    <div v-if="post">{{ post.body }}</div>
    <div v-else-if="isPending">Loading</div>
    <div v-else>Post not found.</div>
  </div>
</template>

<script>
import { computed } from '@vue/composition-api'
import { useFind, useGet } from 'feathers-vuex'

export default {
  name: 'BlogPostView',
  props: {
    id: {
      type: String,
      required: true
    }
  },
  setup(props, context) {
    const { Post } = context.root.$FeathersVuex.api

    // Get the patient record
    const { item: post, isPending } = useGet({
      model: Post,
      id: props.id
    })

    return {
      post,
      isPending
    }
  }
}
<script>
```

See the [Routing with useGet](#routing-with-useget) portion of the patterns section, below, to see how to hook up the above component to vue-router.

### Options

We learned earlier [how to read a TypeScript interface](#detour-reading-a-typescript-interface), so let's look at the TypeScript interface for the `UseGetOptions`.

```ts
interface UseGetOptions {
  model: Function
  id: null | string | number | Ref<null> | Ref<string> | Ref<number>
  params?: Params | Ref<Params>
  queryWhen?: Ref<Function>
  local?: boolean
  immediate?: boolean
}
```

And here's a look at each individual property:

- `model` must be a Feathers-Vuex Model class. The Model's `get` and `getFromStore` methods are used to query data.
- `id` must be a record's unique identifier (`id` or `_id`, usually) or a ref or computed property which returns one.
  - When the `id` changes, the API will be queried for the new record (unless `queryWhen` evaluates to `false`).
  - If the `id` is `null`, no query will be made.
- `params` is a FeathersJS Params object OR a Composition API `ref` (or `computed`, since they return a `ref` instance) which returns a Params object.
  - Unlike the `useFind` utility, `useGet` does not currently have built-in debouncing.
- `queryWhen` must be a `computed` property which returns a `boolean`. It provides a logical separation for preventing API requests apart from `null` in the `id`.
- `immediate`, which is `true` by default, determines if the internal `watch` should fire immediately.  Set `immediate: false` and the query will not fire immediately.  It will only fire on subsequent changes to the `id` or `params`.

### Returned Attributes

```ts
interface UseGetData {
  item: Ref<any>
  servicePath: Ref<string>
  isPending: Ref<boolean>
  hasBeenRequested: Ref<boolean>
  hasLoaded: Ref<boolean>
  isLocal: Ref<boolean>
  error: Ref<Error>
  get: Function
}
```

## FeathersVuexPagination

As of version `3.8.0`, Feathers-Vuex includes the `FeathersVuexPagination` renderless component.  This component pairs with the [`useFind` utility](#usefind) to simplify handling server-side pagination.  If you use the FeathersVuex Vue plugin, the `FeathersVuexPagination` component is registered as a global component.  Since it's a renderless component, you'll need to supply your own UI to the default slot.

### Usage Steps

The steps to using the `FeathersVuexPagination` component include

1. Create a `pagination` ref containing an object with `$limit` and `$skip` properties.
2. Create a `params` computed property. Be sure to include a `query` object and `paginate: true` in the params.  It's also recommended that you use a `qid` to identify the component that you're using, otherwise pagination data could mix with other parts of the UI and create an inconsistent experience.
3. Merge the `pagination` into the `params.query`.
4. Pass the `params` object to the `useFind` utility.
5. Pull the `items` array and `latestQuery` object from `useFind`'s return value.
6. Make the `items`, `latestQuery`, and `pagination` available to the component's template by returning them in the setup method.
7. Provide the above two variables to the `FeathersVuexPagination` component as props.
8. Provide a UI inside the default slot, binding to variables and desired events.

### Props

The `FeathersVuexPagination` component only accepts two props.

- `v-model` (or `value`): Receives the `pagination` object, which must contain the `$limit` and `$skip` properties.
- `latest-query`, which receives the `latestQuery` object returned by the `useFind` utility.

### Default Slot Scope

The following variables and functions are provided by the default slot:

- `currentPage` {Number} The current page number, based on the current `$limit` and `$skip` values provided to the `v-model`.
- `pageCount` {Number} If the response from the API server includes a `total` attribute, the `pageCount` will be the total number of pages, based on the current value of `$limit`.
- `canPrev` {Boolean} Will be true if not on the first page (can go to a previous page).  This value is useful for enabling/disabling a button in the UI, if you desire to give that kind of feedback to the user.
- `canNext` {Boolean} Will be true if not on the last page (can go to a next page).  This value is useful for enabling/disabling a button in the UI, if you desire to give that kind of feedback to the user.
- `toStart` {Function} When called, will move to the first page.
- `toEnd` {Function} When called, will move to the last page.
- `toPage(n: number)` {Function} When called with a page number as its first argument, will move to that page number.  If the page number is greater than the total number of pages, will go to the last page.  If the page number is less than 0, will go to the first page.
- `prev` {Function} When called, moves to the previous page. Will not go below page 1.
- `next` {Function} When called, moves tot the next page.  Will not go past the last page.

### Example

Here is an example of how to use it.  It assumes that you have a `/listings` service with a `Listing` model.  The next code example below this one shows the `PaginationUi` component.  Note that not all slot scope variables and functions are required.  To implement basic pagination, only the `currentPage`, `pageCount`, `next`, and `prev` values are really necessary.  The other slot scope values allow providing a customized pagination experience.

```html
<template>
  <div>
    <!-- 7. ^ -->
    <FeathersVuexPagination v-model="pagination" :latest-query="latestQuery">
      <!-- 8. ^ -->
      <template #default="{ currentPage, pageCount, toStart, toEnd, toPage, next, prev, canNext, canPrev }">
        <PaginationUi
          :current-page="currentPage"
          :page-count="pageCount"
          :can-prev="canPrev"
          :can-next="canNext"
          @to-start="toStart"
          @to-end="toEnd"
          @to-page="toPage"
          @next="next"
          @prev="prev"
        />
      </template>
    </FeathersVuexPagination>

    <!-- Results -->
    <div>
      <div v-for="item in items" :key="item._id">
        {{ item }}
      </div>
    </div>
  </div>
</template>

<script>
import { ref, computed, watch } from '@vue/composition-api'
import { models, useFind, FeathersVuexPagination } from 'feathers-vuex'
import PaginationUi from './PaginationUi.vue'

export default {
  name: 'PaginationExample',
  components: {
    FeathersVuexPagination,
    PaginationUi
  },
  setup(props, context) {
    const { Listing } = models.api

    // 1.^
    const pagination = ref({
      $limit: 20,
      $skip: 0
    })
    // 2.^
    const params = computed(() => {
      const query = {}
      // 3.^
      Object.assign(query, pagination.value)

      return { query, qid: 'listingsPage', paginate: true }
    })
    // 4.^
    const data = useFind({ model: Listing, params: params })

    // 5.^  (can be merged into previous line)
    const { items, latestQuery } = data

    // 6.^
    return { items, pagination, latestQuery }
  }
}
</script>
```

As promised, here is the example code for the `PaginationUi` component used above.  It includes some TailwindCSS utility classes in the markup in order to show how one might use the `canPrev` and `canNext` properties.  Keep in mind that this is just an example.  You can provide whatever experience you want for your users by creating your own component.

```html
<template>
  <div class="flex flex-row items-center mt-2">
    <button
      type="button"
      class="rounded py-0.5 flex flex-row items-center justify-center w-24 mr-1"
      :class="[
        canPrev
          ? 'bg-gray-600 text-white'
          : 'bg-gray-400 text-gray-500 cursor-not-allowed'
      ]"
      :disabled="!canPrev"
      @click="e => $emit('prev', e)"
    >
      <ChevronLeftIcon />
      <p class="pr-2">Previous</p>
    </button>

    <button
      type="button"
      class="bg-gray-600 text-white rounded py-0.5 flex flex-row items-center justify-center w-24 mr-1"
      @click="e => $emit('to-start', e)"
    >
      <p class="pr-2">To Start</p>
    </button>

    <div class="flex flex-grow justify-center items-center">
      Page
      <input
        :value="currentPage"
        type="number"
        :min="1"
        :max="pageCount"
        class="w-12 rounded py-0.5 mx-1.5 dark:bg-gray-900 text-center"
        @input="event => $emit('to-page', event.target.value)"
      />
      of {{ pageCount }}
    </div>

    <button
      type="button"
      class="bg-gray-600 text-white rounded py-0.5 flex flex-row items-center justify-center w-24 mr-1"
      @click="e => $emit('to-end', e)"
    >
      <p class="pr-2">To End</p>
    </button>

    <button
      type="button"
      class="rounded py-0.5 flex flex-row items-center justify-center w-24"
      :class="[
        canNext
          ? 'bg-gray-600 text-white'
          : 'bg-gray-400 text-gray-500 cursor-not-allowed'
      ]"
      :disabled="!canNext"
      @click="e => $emit('next', e)"
    >
      <div class="w-12">Next</div>
      <ChevronRightIcon />
    </button>
  </div>
</template>

<script>
import { ChevronLeftIcon, ChevronRightIcon } from 'vue-feather-icons'

export default {
  name: 'SidebarPagination',
  components: {
    ChevronLeftIcon,
    ChevronRightIcon
  },
  props: {
    currentPage: {
      type: Number,
      required: true
    },
    pageCount: {
      type: Number,
      required: true
    },
    canPrev: {
      type: Boolean,
      required: true
    },
    canNext: {
      type: Boolean,
      required: true
    }
  }
}
</script>
```

## Patterns & Examples

### Server-Side Pagination

Similar to what was introduced with the `makeFindMixin` in Feathers-Vuex 2.0, the `useFind` API supports server-side pagination.  It is enabled by passing `paginate: true` in the `params` (or the `fetchParams` if you're using separate queries).  For an overview of how it works, refer to the [makeFindMixin pagination docs](./mixins.html#pagination-with-fall-through-cacheing).

### Simultaneous Queries

Let's look at an example where we have two separate tables and we want live-queried lists for both of them.  This example will show a component for a doctor's office that pulls up a patient by `id` using `useGet` then retrieves all of the patient's `appointments` using `useFind`.

```html
<template>
  <div>
    <div>{{ patient.name }}</div>

    <li v-for="appointment in appointments" :key="appointment._id">
      {{ appointment.date }}
    </li>
  </div>
</template>

<script>
import { computed } from '@vue/composition-api'
import { useFind, useGet } from 'feathers-vuex'

export default {
  name: 'PatientAppointments',
  props: {
    id: {
      type: String,
      required: true
    }
  },
  setup(props, context) {
    const { Patient, Appointment } = context.root.$FeathersVuex.api

    // Get the patient record
    const { item: patient } = useGet({ model: Patient, id: props.id })

    // Get all of the appointments belonging to the current patient
    const appointmentsParams = computed(() => {
      return {
        query: {
          userId: props.id,
          $sort: { date: -1 }
        }
      }
    })
    const { items: appointments } = useFind({
      model: Appointment,
      params: appointmentsParams
    })

    return {
      patient,
      appointments
    }
  }
}
</script>
```

### Deferring Queries

In the previous example, the requests for the `patient` and `appointments` are made at the same time because the user's `id` is available, already.  What if we were required to load `appointments` after the `patient` record finished loading?  We could change the `appointmentsParams` to return `null` until the `patient` record becomes available, as shown in the following example:

```html
<template>
  <div>
    <div>{{ patient.name }}</div>

    <li v-for="appointment in appointments" :key="appointment._id">
      {{ appointment.date }}
    </li>

    <div v-if="!appointments.length && haveLoaded">
      No appointments have been scheduled for this patient.
    </div>
  </div>
</template>

<script>
import { computed } from '@vue/composition-api'
import { useFind, useGet } from 'feathers-vuex'

export default {
  name: 'PatientAppointments',
  props: {
    id: {
      type: String,
      required: true
    }
  },
  setup(props, context) {
    const { Patient, Appointment } = context.root.$FeathersVuex.api

    // Get the patient record
    const { item: patient } = useGet({ model: Patient, id: props.id })

    // Get all of the appointments belonging to the current patient
    const appointmentsParams = computed(() => {
      // (1)
      if (!patient.value) {
        return null
      }
      // (2)
      return {
        query: {
          userId: patient.value._id,
          $sort: { date: -1 }
        }
      }
    })
    const { items: appointments, haveLoaded } = useFind({
      model: Appointment,
      params: appointmentsParams
    })

    return {
      patient,
      appointments,
      haveLoaded
    }
  }
}
</script>
```

Reviewing the above snippet, while there is no `patient` record, the `appointmentsParams` computed property returns `null` at comment `(1)`.  This will prevent any query from going out to the API server.

Once the `patient` has loaded, the full params object is returned at comment `(2)`.  This allows the `useFind` utility to make the request.

### Showing Loading State

This next example builds on the previous one and adds loading state for both the `patient` and the `appointments`.

```html
<template>
  <div>
    <div v-if="isPatientLoading">Loading</div>
    <div v-else>{{ patient.name }}</div>

    <li v-for="appointment in appointments" :key="appointment._id">
      {{ appointment.date }}
    </li>

    <div v-if="!appointments.length && haveLoaded">
      No appointments have been scheduled for this patient.
    </div>
  </div>
</template>

<script>
import { computed } from '@vue/composition-api'
import { useFind, useGet } from 'feathers-vuex'

export default {
  name: 'PatientAppointments',
  props: {
    id: {
      type: String,
      required: true
    }
  },
  setup(props, context) {
    const { Patient, Appointment } = context.root.$FeathersVuex.api

    const {
      item: patient,
      isPending: isPatientLoading
    } = useGet({ model: Patient, id: props.id })

    const appointmentsParams = computed(() => {
      if (!patient.value) {
        return null
      }
      return {
        query: {
          userId: patient.value._id,
          $sort: { date: -1 }
        }
      }
    })
    const { items: appointments, haveLoaded } = useFind({
      model: Appointment,
      params: appointmentsParams
    })

    return {
      patient,
      isPatientLoading,
      appointments,
      haveLoaded
    }
  }
}
</script>
```

### Using queryWhen

The `queryWhen` option for both `useFind` and `useGet` comes in handy when you want to conditional prevent API queries.  One use case for this is to prevent extra queries by checking if an item already exists in the vuex store.  This next example shows how to stop the `get` request if you already have a patient record with the current `id`.

```html
<template>
  <div>
    <div v-if="isPatientLoading">Loading</div>
    <div v-else>{{ patient.name }}</div>
  </div>
</template>

<script>
import { computed } from '@vue/composition-api'
import { useFind, useGet } from 'feathers-vuex'

export default {
  name: 'PatientInfo',
  props: {
    id: {
      type: String,
      required: true
    }
  },
  setup(props, context) {
    const { Patient } = context.root.$FeathersVuex.api

    const patientQueryWhen = computed(() => {
      return !Patient.getFromStore(props.id)
    })
    const { item: patient, isPending: isPatientLoading } = useGet({
      model: Patient,
      id: props.id,
      queryWhen: patientQueryWhen
    })

    return {
      patient,
      isPatientLoading
    }
  }
}
</script>
```

In the above example, the `patientQueryWhen` computed property will return `true` if we don't already have a `Patient` record in the store with the current `props.id`.  While you could also achieve similar results by performing this logic inside of a `params` computed property, the `queryWhen` option works great as a "master override" to prevent unneeded queries.

### Routing with useGet

Apps will commonly have one or more routes with an `:id` param.  This might be for viewing or editing data.  Vue Router has a feature that makes it easy to write reusable components without having to directly reference the `$route` object.  The key is to set the `props` attribute in a route definition to `true`.  Here's an example route:

```js
// router.js
import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
  routes: [
    {
      name: 'Post View',
      path: '/posts/:id',
      component: () =>
        import(/* webpackChunkName: "posts" */ './views/Post.vue'),
      props: true
    }
  ]
})
```

Now, the `Post.vue` file only requires to have a `prop` named `id`.  Vue Router will pass the params from the route as props to the component.  See the [first useGet example](#useget) for a component that would work with the above route.  The vue-router documentation has more information about [Passing Props to Route Components](https://router.vuejs.org/guide/essentials/passing-props.html#passing-props-to-route-components)

### Composing with Model types

Both `useGet` and `useFind` have an optional type parameter for the Model type which is used as the type for the returned item(s).

```ts
// Destructure Model class from global models object
const { User } = Vue.$FeathersVuex.api

// use useGet with User Model
useGet<typeof User.prototype>(/* ... */)

// use useFind with User Model
useFind<typeof User.prototype>(/* ... */)
```

## Conventions for Development

### Params are Computed

You might notice throughout these docs that the params are consistently shown as `computed` properties.  For long-term maintainability, this is the recommended practice.

Computed properties are read-only, so you can't push changes into them. This encourages declarative programming.  Think of a declarative query as having all of the instructions it needs to pull in data from whatever sources are required to build the query object. Writing declarative params will assist you in avoiding complex conditional conflicts as queries become more complex.

In contrast, an imperatively-written query would be a reactive object that you directly modify.  Think of imperative as pushing information into the query.  eg: `params.query.user = props.userId`.  When you have a lot of imperative code pushing parameters into the query, it's really easy to create conflicting logic.  So, keep in mind that while Feathers-Vuex will definitely handle an imperative-style query, your code will likely be less maintainable over the long run.

### Naming Variables

Having a variable naming convention can really assist the developer onboarding process and long run ease of use.  Here are some guidelines that could prove useful while using the composition API utilities:

- Params for `useFind` result in a list of records, and should therefore indicate plurality.
- When used, params for `useGet` result in a single record, and should indicate singularity.

```js
import { computed } from '@vue/composition-api'
import { useFind, useGet } from 'feathers-vuex'

export default {
  name: 'MyComponent',
  props: {
    id: {
      type: String,
      required: true
    }
  },
  setup(props, context) {
    const { Comment } = context.root.$FeathersVuex.api

    // Plural "comments" in the params for useFind
    const commentsParams = computed(() => {
      return { query: {} }
    })
    const commentsData = useFind({
      model: Comment,
      params: commentsParams
    })
    const { items: comments } = commentsData

    // Singular "comment" in the params for useGet
    const commentParams = computed(() => {
      return { query: {} }
    })
    const commentData = useGet({
      model: Comment,
      id: props.id,
      params: commentParams
    })
    const { item: comment } = commentData

    return {
      comments,
      comment
    }
  }
}
```

Variable naming becomes even more important when one service consumes the results of a previous service to make a query.

Note: the destructuring of `commentsData` and `commentData`, above, could happen on the same line as `useFind` and `useGet`, but it's a bit more clear in the example to split it into separate steps.  For users who are accustomed to destructuring, it makes perfect sense to do so:

```js
// Destructure and rename "item" to "comment" in the same line as the call to `useGet`
const { item: comment } = useGet({
  model: Comment,
  id: props.id,
  params: commentParams
})

return { comment }
```


================================================
FILE: docs/data-components.md
================================================
---
title: Renderless Data Components
sidebarDepth: 3
---

# Renderless Data Components

There are three renderless data provider components: `<FeathersVuexFind>`, `<FeathersVuexGet>` and `<FeathersVuexCount>`. They simplify performing queries against the store and/or the API server. They make the data available inside each component's default slot.

To see why you might want to use these components, below are two example components that are functionally equivalent.

Here's what it looks like to use the new component:

```html
<template>
  <FeathersVuexFind
    v-slot="{ items: categories }"
    service="categories"
    :params="{ query: {} }"
    watch="params"
  >
    <section class="admin-categories">
      {{categories}}
    </section>
  </FeathersVuexFind>
</template>

<script>
export default {
  name: 'admin-categories'
}
</script>
```

The above example is functionally equivalent to this much longer example which doesn't use the new component:

```html
<template>
  <section class="admin-categories">
    {{categories}}
  </section>
</template>

<script>
import { mapState, mapGetters, mapActions } from 'vuex'

export default {
  name: 'admin-categories',
  computed: {
    ...mapState('categories', { areCategoriesLoading: 'isFindPending' }),
    ...mapGetters('categories', { findCategoriesInStore: 'find' }),
    query () {
      return {}
    },
    categories () {
      return this.findCategoriesInStore({ query: this.query }).data
    }
  },
  methods: {
    ...mapActions('categories', { findCategories: 'find' })
  },
  created () {
    this.findCategories({ query: this.query })
  }
}
</script>
```

> To level up your skills, consider this content by Adam Wathan.  He wrote a terrific *free* article about [Renderless Components in Vue.js](https://adamwathan.me/renderless-components-in-vuejs/). I highly recommend you read it. He also created the *paid/premium* [Advanced Vue Component Design](https://adamwathan.me/advanced-vue-component-design/) course. His material influenced the creation of this component.

## FeathersVuexFind

The `FeathersVuexFind` component retrieves data from the API server, puts it in the Vuex store, then transparently retrieves the live, reactive data from the store and displays it to the user.

### Example

```vue
<FeathersVuexFind
  v-slot="{ items: users }"
  service="users"
  :params="{ query: {} }"
  watch="query"
>
  <section>
    {{users}}
  </section>
</FeathersVuexFind>
```

### Props

- `service {String}` - **required** the service path. This must match a service that has already been registered with FeathersVuex.
- `query {Object}` <Badge text="deprecated" type="warning"/> **use `params` instead** - the query object. If only the `query` attribute is provided, the same query will be used for both the `find` getter and the `find` action. See the `fetchQuery` attribute for more information. When using server-side pagination, use the `fetchQuery` prop and the `query` prop for querying data from the local store. If the query is `null` or `undefined`, the query against both the API and store will be skipped. The find getter will return an empty array.
- `watch {String|Array}` - specify the attributes of the `params` or `fetchParams` to watch. Pass 'params' to watch the entire params object. Pass 'params.query.name' to watch the 'name' property of the query. Watch is turned off by default, so the API server will only be queried once, by default. **Default: []**
- `fetchQuery {Object}` <Badge text="deprecated" type="warning"/> **use `fetchParams` instead** - when provided, the `fetchQuery` serves as the query for the API server. The `query` param will be used against the service's local Vuex store. **Default: undefined**
- `params {Object}` - the params object. If only the `params` attribute is provided, te same params will be used for both the `find` getter and the `find` action. See the `fetchParams` attribute for more information. <Badge text="3.12.0+" />
- `fetchParams {Object}` - when provided, the `fetchParams` servers as the params for the API server. The `params` will be used against the service's local Vuex store. <Badge text="3.12.0+" />
- `queryWhen {Boolean|Function}` - the query to the server will only be made when this evaluates to true.  **Default: true**
- `local {Boolean}` - when set to true, will only use the `query` prop to get data from the local Vuex store. It will disable queries to the API server. **Default:false**
- `editScope {Function}` - a utility function that allows you to modify the scope data, and even add attributes to it, before providing it to the default slot. You can also use it to pull data into the current component's data (though that may be less recommended, it can come in handy).  See the "Scope Data" section to learn more about what props are available in the scope object. **Default: scope => scope**
- `temps {Boolean}` <Badge text="deprecated" type="warning"/> **use `params: { query: {}, temps: true }` instead** - Enable `temps` to include temporary records (from `state.tempsById`) in the find getter results. **Default: false**
- `qid {String}` - The query identifier used for storing pagination data in the Vuex store. See the service module docs to see what you'll find inside. The default value is a random 10-character string. This means that by default, in theory, no two components will share the same pagination data, nor will they overwrite each other's pagination data. You can, of course, force them to use the same pagination data by giving them both the same `qid`, if there's a use case for that. **Default: randomString(10)**

### Scope Data

- `items {Array}` - The resulting array of records for find operations.
- `isFindPending {Boolean}` - When there's an active request to the API server, this will be `true`.  This is not the same as the `isFindPending` from the Vuex state.  The value in the Vuex state is `true` whenever **any** component is querying data from that same service.  This `isFindPending` attribute is specific to each component instance.
- `pagination {Object}` - pagination data from the Vuex store, keyed by the `qid` attribute.  By default, this will be specific to this component instance. (If you find a use case for sharing pagination between component instances, you can give both components the same `qid` string as a prop.)
- `queryInfo {Object}` - the queryInfo for the `pagination` object. Includes the `total` prop for server side pagination
- `pageInfo {Object}` - the pageInfo includes the queried ids and is necessary for server side pagination

## FeathersVuexGet

The `FeathersVuexGet` component allows fetching data from directly inside a template.  It makes the slot scope available to the child components.  Note that in `feathers-vuex@3.3.0` the component now includes support for `params` and `fetchParams` props.  These are meant to replace the `query` and `fetchQuery` props.  The `params` allow you, for example, to configure a project to pass custom params to the server.  This would require use of custom hooks.

### Example

```html
<template>
  <FeathersVuexGet
    v-slot="{ item: user }"
    service="users"
    :id="id"
    :params="params"
    :watch="[id, params]"
  >
      {{ user }}
  </FeathersVuexGet>
</template>

<script>
export default {
  name: 'UserProfile',
  computed: {
    id() {
      return this.$route.params.id
    },
    params() {
      return {
        $populateParams: {
          name: 'withFollowers'
        }
      }
    }
  }
}
</script>
```

### Props

- `service {String}` - **required** the service path. This must match a service that has already been registered with FeathersVuex.
- `id {Number|String}` - when performing a `get` request, serves as the id for the request. This is automatically watched, so if the `id` changes, an API request will be made and the data will be updated.  **Default: undefined**
- `query {Object}` <Badge text="deprecated" type="warning"/> **use `params` instead** - the query object. If only the `query` attribute is provided, the same query will be used for both the `get` getter and the `get` action. See the `fetchQuery` attribute for more information. When using server-side pagination, use the `fetchQuery` prop and the `query` prop for querying data from the local store. If the query is `null` or `undefined`, the query against both the API and store will be skipped. The find getter will return an empty array.
- `watch {String|Array}` - specify the attributes of the `params` or `fetchParams` to watch. Pass 'params' to watch the entire params object. Pass 'params.query.name' to watch the 'name' property of the query. Watch is turned off by default, so the API server will only be queried once, by default.  The only exception is for the `id` prop.  The `id` prop in the `FeathersVuexGet` component is always watched.  **Default: []**
- `fetchQuery {Object}` <Badge text="deprecated" type="warning"/> **use `fetchParams` instead** - when provided, the `fetchQuery` serves as the query for the API server. The `query` param will be used against the service's local Vuex store. **Default: undefined**
- `params {Object}` - the params object. If only the `params` attribute is provided, te same params will be used for both the `get` getter and the `get` action. See the `fetchParams` attribute for more information.
- `fetchParams {Object}` - when provided, the `fetchParams` servers as the params for the API server. The `params` will be used against the service's local Vuex store.
- `queryWhen {Boolean|Function}` - the query to the server will only be made when this evaluates to true.  **Default: true**
- `local {Boolean}`: when set to true, will only use the `params` prop to get data from the local Vuex store. It will disable queries to the API server. **Default:false**
- `editScope {Function}` - a utility function that allows you to modify the scope data, and even add attributes to it, before providing it to the default slot. You can also use it to pull data into the current component's data (though that may be less recommended, it can come in handy).  See the "Scope Data" section to learn more about what props are available in the scope object. **Default: scope => scope**

### Scope Data

- `item {Object}` - The resulting record for the get operation.
- `isGetPending {Boolean}` - When there's an active request to the API server, this will be `true`.  This is not the same as the `isGetPending` from the Vuex state.  The value in the Vuex state is `true` whenever **any** component is querying data from that same service.  This `isGetPending` attribute is specific to each component instance.

## FeathersVuexCount <Badge text="3.12.0+" />

The `FeathersVuexCount` component allows displaying a count of records. It makes the slot scope available to the child components. It adds `$limit: 0` to the passed params in the background. This will only run a (fast) counting query against the database.

> **Note:** it only works for services with enabled pagination!

```vue
<FeathersVuexCount v-slot="{ total }" service="users" :params="{ query: {} }">
  <span>
    {{ total }}
  </span>
</FeathersVuexCount>
```

### Props

- `service {String}` - The path of the service
- `params {Object}` - The params object passed to the `count` getter/action.
- `fetchParams {Object}` - A seperate params object for the `count` action
- `queryWhen {Boolean|Function(params)}` - the query to the server will only be made when this evaluates to true.  **Default: true**
- `watch {String|Array}` - specify the attributes of the `params` or `fetchParams` to watch. Pass 'params' to watch the entire params object. Pass 'params.query.name' to watch the 'name' property of the query. Watch is turned off by default, so the API server will only be queried once, by default. **Default: []**
- `local {Boolean}`: when set to true, will only use the `params` prop to get data from the local Vuex store. It will disable queries to the API server. **Default:false**

### Scope Data

- `total {Number}` - The number of found records.
- `isCountPending {Boolean}` - When there's an active request to the API server, this will be `true`.

## A note about the internal architecture

These components use Vuex getters (to query data from the local store) and actions (to query data from the API server).  When a `params` or `id` is provided, the components pull data from the API server and put it into the store. That same `params` or `id` is then used to pull data from the local Vuex store. Keep this in mind, especially when attempting to use server-side pagination. To use server-side pagination, use the `params` prop for pulling data from the local vuex store, then use the `fetchParams` prop to retrieve data from the API server.

## Registering the components

These components are automatically registered globally when using the Feathers-Vuex Vue plugin.

If you prefer to manually register the component, pass `{ components: false }` as options when using the FeathersVuex Vue plugin, then do the following:

```js
import { FeathersVuexFind, FeathersVuexGet, FeathersVuexCount } from 'feathers-vuex'

// in your component
components: {
  FeathersVuexFind,
  FeathersVuexGet,
  FeathersVuexCount
}

// or globally registered
Vue.component('FeathersVuexFind', FeathersVuexFind)
Vue.component('FeathersVuexGet', FeathersVuexGet)
Vue.component('FeathersVuexCount', FeathersVuexCount)
```

## Scope Data

When using these components, the scope data will become available to the `FeathersVuexFind`, `FeathersVuexGet` and `FeathersVuexCount` tags. It's accessible using the `v-slot="props"` attribute:

```html
<FeathersVuexFind v-slot="props" service="categories" :params="{ query: {} }">
  <div>
    {{props.items}}
  </div>
</FeathersVuexFind>
```

It's also possible to modify the scope data by passing a function as the `edit-scope` prop. See the example for [modifying scope data](#Modify-the-scope-data)

### Destructuring props

Use the object destructuring syntax to pull specific variables out of the `v-slot` object.  In the following example, instead of using `v-slot="props"`, it directly accesses the `items` prop through destructuring:

```html
<FeathersVuexFind v-slot="{ items }" service="categories" :params="{ query: {} }">
  <div>
    {{items}}
  </div>
</FeathersVuexFind>
```

### Renaming props with destructuring

You can also rename scope props through the Object destructuring syntax.  The  `v-slot` in the next example shows how to give the items a more-descriptive name:

```html
<FeathersVuexFind
  v-slot="{ items: categories }"
  service="categories"
  :params="{ query: {} }"
>
  <div>
    {{categories}}
  </div>
</FeathersVuexFind>
```

## Usage Examples

#### A basic find all

In this example, only the `service` attribute is provided. There is no `query` nor `id` provided, so no queries are made. So `props.items` in this example returns an empty array.

```html
<FeathersVuexFind v-slot="props" service="todos">
  <div>
    {{props.items}}
  </div>
</FeathersVuexFind>
```

#### Fetch data from the API and the same data from the Vuex store

This example fetches data from the API server because a query was provided.  Internally, this same `query` is used for both the `find` action and the `find` getter. Read other examples to see how to use distinct queries. Be aware that if you use pagination directives like `$skip` or `$limit`, you must use two queries to get the records you desire.

```html
<FeathersVuexFind v-slot="props" service="todos" :params="{ query: {} }">
  <div>
    {{props.items}}
  </div>
</FeathersVuexFind>
```

#### Only get data from the local Vuex store

If you've already pulled a bunch of data from the server, you can use the `local` prop to only query the local data:

```html
<FeathersVuexFind v-slot="props" service="todos" :params="{ query: {} }" local>
  <div>
    {{props.items}}
  </div>
</FeathersVuexFind>
```

#### Watch the query and re-fetch from the API

Sometimes you want to query new data from the server whenever the query changes.  Pass an array of attribute names to the `watch` attribute re-query whenever upon change.  This example watches the entire query object:

```html
<FeathersVuexFind
  v-slot="props"
  service="todos"
  :params="{ query: { isComplete: true } }"
  watch="params"
>
  <div>
    {{props.items}}
  </div>
</FeathersVuexFind>
```

This next example watches a single prop from the query:

```html
<FeathersVuexFind
  v-slot="props"
  service="todos"
  :params="{ query: { isComplete: true, dueDate: 'today' } }"
  watch="params.query.dueDate"
>
  <div>
    {{props.items}}
  </div>
</FeathersVuexFind>
```

You can also provide an array of strings to watch multiple properties:

```html
<FeathersVuexFind
  v-slot="props"
  service="dogs"
  :params="{ query: { breed: 'mixed', bites: true, hasWorms: false }}"
  :watch="['params.query.breed', 'params.query.bites']"
>
  <div>
    {{props.items}}
  </div>
</FeathersVuexFind>
```

#### Use a distinct `params` and `fetchParams`

In this scenario, the `fetchParams` is be used to grab a larger dataset from the API server (all todos with a matching `userId`). The `params` is used by the `find` getter to display a subset of this data from the store.  If the `isComplete` attribute gets set to `true`, only completed todos will be displayed.  Since a `fetchParams` is provided, the `watch` strings will be modified internally to watch the `fetchParams` object.  This means if you are watching `params.query.userId` and you add a `fetchParams`, the component is smart enough to know you meant `fetchParams.query.userId`. You don't have to rewrite your `watch` attribute after adding a `fetchParams` prop.

```html
<template>
  <FeathersVuexFind
    v-slot="{ items: todos }"
    service="todos"
    :params="{ query: { isComplete } }"
    :fetch-params="{ query: { userId } }"
    watch="params.query.userId"
  >
    <div>
      {{todos}}
    </div>
  </FeathersVuexFind>
</template>

<script>
export default {
  data: () => ({
    isComplete: false,
    userId: 1
  })
}
</script>
```

#### Modify the scope data

The `edit-scope` function allows you to modify the scope before passing it down to the default slot.  This feature can be super useful for preparing the data for the template.  The `prepareCategories` method in this next example adds two properties to the scope data, which are used to create a nested category structure:

```html
<template>
  <FeathersVuexFind
    v-slot="{ parentCategories, categoriesByParent }"
    service="categories"
    :params="{ query: {} }"
    :edit-scope="prepareCategories"
  >
    <ul>
      <li v-for="parent in parentCategories" :key="parent._id">
        <p>{{parent.name}}</p>
        <ul>
          <li v-for="child in categoriesByParent[parent.path]" :key="child._id">
            {{child.name}}
          </li>
        </ul>
      </li>
    </ul>
  </FeathersVuexFind>
</template>

<script>
export default {
  methods: {
    prepareCategories (scope) {
      scope.parentCategories = scope.items.filter(cat => !cat.path.includes('/'))
      scope.categoriesByParent = scope.parentCategories.reduce((acc, parentCat) => {
        acc[parentCat.path] = scope.items.filter(cat => {
          return cat.path.includes(parentCat.path) && cat.path !== parentCat.path
        })
        return acc
      }, {})
    }
  }
}
</script>
```

#### server-side pagination

When you want to use server-side pagination you need to pass the ids from the server to vuex. It can be done by a combination of `params`, `fetchParams` and `editScope` as described below. The `fetchParams`-prop is only computed after items from the server arrived. The ids for the `find` getter as well as the total amount of available values `total` are extracted by the `edit-scope` function and stored in `data`:

```html
<template>
  <FeathersVuexFind
    v-slot="{ items: todos }"
    :service="service"
    :params="internalParams"
    :fetch-params="fetchParams"
    :edit-scope="getPaginationInfo"
  >
    <div>
      {{todos}}
    </div>
  </FeathersVuexFind>
</template>

<script>
export default {
  data() {
    return {
      service: 'users',
      ids: [],
      params: {
        query: {
          isComplete: true
        },
      },
      total: 0,
      limit: 10,
      skip: 0
    };
  },
  computed: {
    internalParams() {
      const { idField } = this.$store.state[this.service];
      return {
        query: {
          [idField]: {
            $in: this.ids
          }
        }
      };
    },
    fetchParams() {
      const query = Object.assign({}, this.params.query, { $limit: this.limit, $skip: this.skip });

      return Object.assign({}, this.params, { query });
    }
  },
  methods: {
    getPaginationInfo (scope) {
      const { queryInfo, pageInfo } = scope;

      this.total = queryInfo.total;
      if (pageInfo && pageInfo.ids) {
        this.ids = pageInfo.ids;
      }
    }
  }
}
</script>
```

#### Query when certain conditions are met

Sometimes you only want to query the API server when certain conditions are met.  This example shows how to query the API server when the `userSearch` has as least three characters.  This property does not affect the internal `find` getter, so the `items` will still update when the `userSearch` property has fewer than three characters, just no API request will be made.  The `isFindPending` attribute is used to indicate when data is being loaded from the server.

```html
<template>
  <div>
    <input type="text" v-model="userSearch"/>

    <FeathersVuexFind
      v-slot="{ items: users, isFindPending: areUsersLoading }"
      service="users"
      :params="usersParams"
      watch="params"
      :queryWhen="userSearch.length > 2"
    >
      <ul :class="[ areUsersLoading && 'is-loading' ]">
        <li v-for="user in users" :key="user._id">
          {{user.email}}
        </li>
      </ul>
    </FeathersVuexFind>
  </div>
</template>

<script>
export default {
  data: () => ({
    userSearch: ''
  }),
  computed: {
    usersParams () {
      return {
        query: {
          email: { $regex: this.userSearch, $options: 'igm' },
          $sort: { email: 1 }
        }
      }
    }
  }
}
</script>
```

#### Use a get request

You can perform `get` requests with the `FeathersVuexGet` component and its `id` property.  In the next example, when the `selectedUserId` changes, a get request will automatically fetch and display the matching user record.  It also shows how to use the `isGetPending` prop to update the UI

```html
<FeathersVuexGet
  v-slot="{ item: currentUser, isGetPending }"
  service="todos"
  :id="selectedUserId"
>
  <div>
    <div v-if="isGetPending" class="loading"> loading... </div>
    {{currentUser}}
  </div>
</FeathersVuexGet>
```


================================================
FILE: docs/example-applications.md
================================================
---
title: Example Applications
sidebarDepth: 3
---

# Example Applications

On this page you will find any example applications using Feathers-Vuex that have been shared by the community.  If there's something you would like to see here, feel free to make a PR to add it to the [Community Examples list](#community-examples).

## Feathers Chat

The [Feathers Chat Example for Feathers Vuex](https://github.com/feathersjs-ecosystem/feathers-chat-vuex) has been updated to `feathers-vuex@3.x` and everything has been rewritten with the Vue composition API.  The old repo is now available at [https://github.com/feathersjs-ecosystem/feathers-chat-vuex-0.7](https://github.com/feathersjs-ecosystem/feathers-chat-vuex-0.7).  The following information will assist you in seeing the "before" and "after" of the refactor to feathers-vuex@3.x.

![Feathers Chat](https://camo.githubusercontent.com/14b6b2d6dd2475c3b83eb1ade6aedbcd8cf94139/68747470733a2f2f646f63732e66656174686572736a732e636f6d2f6173736574732f696d672f66656174686572732d636861742e39313936303738352e706e67)

### Before and After Comparisons

- The folder structure is similar, since this is a VueCLI application.  Some of the components in the old version have been moved into the `views` folder.
  - `/components/Home.vue` is now `/views/Home.vue`
  - `/components/Signup.vue` is now `/views/Signup.vue`
  - `/components/Login.vue` is now `/views/Login.vue`
  - `/components/Chat/Chat.vue` is now `/views/Chat.vue`
- The `/components` folder has been flattened. There are no more subfolders.
- Component refactors:
  - [Login.vue](https://github.com/feathersjs-ecosystem/feathers-chat-vuex/commit/eb9ba377c5705c1378bee72661a13dd0db48be05)
  - [Signup.vue](https://github.com/feathersjs-ecosystem/feathers-chat-vuex/commit/478710ed84869d33a9286078496c1e5974a95067)
  - [Users.vue](https://github.com/feathersjs-ecosystem/feathers-chat-vuex/commit/02b47149c80c27cdeb611c2f4438b4c62159c644)
  - [Messages.vue](https://github.com/feathersjs-ecosystem/feathers-chat-vuex/commit/930743c1679cc4ed9d691532a7dff1d6a34398e6)
  - [Compuser.vue](https://github.com/feathersjs-ecosystem/feathers-chat-vuex/commit/cd5c8898ede270d5e22f9c6ef1450d3f3c6278c9)
  - [Chat.vue](https://github.com/feathersjs-ecosystem/feathers-chat-vuex/commit/39eb3e13f6921b0d0524ae4ac7942b9ce78b222c)
  - [Messages.vue](https://github.com/feathersjs-ecosystem/feathers-chat-vuex/commit/e5cf7fb0cc8eab80ee3dc441afafb1399d69059e)

### More to Come

The Feathers Chat example is a pretty simple application.  Its primary purpose is to show off how easy it is to do realtime with FeathersJS.  (FeathersJS continues to be the only framework that treats real-time communication as a first-class citizen with the same API across multiple transports.)  But it doesn't properly showcase all of the great features in Feathers-Vuex 3.0.  This requires a solution that:

1. Still allows comparison of Feathers Chat applications made with other frameworks.
2. Allows the version of Feathers Chat built with Feathers-Vuex to add features and showcase things you might actually use in production.

If there are features which you would like to see implemented, please open an issue in the [feathers-chat-vuex Repo](https://github.com/feathersjs-ecosystem/feathers-chat-vuex) for your idea to be considered.

## Community Examples

If you have created or know of an example application, please add it, here.

- [Feathers-Chat-Vuex](https://github.com/feathersjs-ecosystem/feathers-chat-vuex)


================================================
FILE: docs/feathers-vuex-forms.md
================================================
---
title: Working with Forms
sidebarDepth: 4
---

# Working with Forms

The `FeathersVuexFormWrapper` and `FeathersVuexInputWrapper` are renderless components which assist in connecting your feathers-vuex data to a form.  The next two sections review why they exist by looking at a couple of common patterns.  Proceed to the [FeathersVuexFormWrapper](#feathersvuexformwrapper) or [FeathersVuexInputWrapper](#feathersvuexinputwrapper) sections to learn how to implement.

## The Mutation Multiplicity (anti) Pattern

When working with Vuex, it's considered an anti-pattern to modify store data directly.  Turn on Vuex strict mode, and it will throw an error every time you modify store data outside of a mutation.  In my experience, the most common (anti)pattern that beginners use to work around this "limitation" is to

1. Read data from the store and use it for display in the UI.
2. Create custom mutations intended to modify the data in specific ways.
3. Use the mutations wherever they apply (usually implemented as one mutation per form).

There are times when defining custom mutations is the most supportive pattern for the task, but I consider them to be more rare.  The above pattern can result in a huge number of mutations, extra lines of code, and increased long-term maintenance costs.

## The Clone and Commit Pattern

The "Clone and Commit" pattern provides an alternative to using a lot of mutations. This patterns looks more like this:

1. Read data from the store and use it for display in the UI.  (Same as above)
2. Create and modify a clone of the data.
3. Use a single mutation to commit the changes back to the original record in the store.

Sending most edits through a single mutation can really simplify the way you work with Vuex data.  The Feathers-Vuex `BaseModel` class has `clone` and `commit` instance methods.   These methods provide a clean API for working with items in the Vuex store and supporting Vuex strict mode:

```js
import { models } from 'feathers-vuex'

export default {
  name: 'MyComponent',
  created() {
    const { Todo } = models.api

    const todo = new Todo({
      description: 'Plant the garden',
      isComplete: false
    })

    const todoClone = todo.clone()
    todoClone.description = 'Plant half of the garden."
    todoClone.commit()
  }
}
```

In the example above, modifying the `todo` variable would directly modify part of the Vuex store outside of a mutation (also known as a reducer in Redux), which is a generally unsupportive practice.  Calling `todo.clone()` returns a reactive clone of the instance and keeps it outside the Vuex store.  This means you can make changes to it all you want without causing any trouble with Vuex.  You can then call `todoClone.commit()` to update the original record in the store.

The `clone` and `commit` methods are used inside the FeathersVuexFormWrapper component.

## FeathersVuexFormWrapper

The `FeathersVuexFormWrapper` component uses the "clone and commit" pattern to connect a single record to a child form within its default slot.

```vue
<template>
  <FeathersVuexFormWrapper :item="currentItem" watch>
    <template v-slot="{ clone, save, reset, remove }">
      <SomeEditor
        :item="clone"
        @save="save().then(handleSaveResponse)"
        @reset="reset"
        @remove="remove"
      ></SomeEditor>
    </template>
  </FeathersVuexFormWrapper>
</template>

<script>

import { FeathersVuexFormWrapper } from 'feathers-vuex'

export default {
  name: 'MyComponent',
  components: { FeathersVuexFormWrapper },
  props: {
    currentItem: {
      type: Object,
      required: true
    }
  },
  methods: {
    handleSaveReponse(savedItem) {
      console.log(savedItem) // The item returned from the API call
    }
  }
}
</script>
```

Here's another example of how you could use the form wrapper to both save the form and close a modal at the same time.  (The modal is not shown in the template markup.) Notice how the `@save` handler is an inline function that sets `isModalVisible` to false, then on a new line it calls save. This is handled perfectly by Vue.

```vue
<template>
  <FeathersVuexFormWrapper :item="currentItem" watch>
    <template v-slot="{ clone, save, reset, remove }">
      <SomeEditor
        :item="clone"
        @save="
          () => {
            isModalVisible = false
            save({ populateParams: {} })
          }
        "
        @reset="reset"
        @remove="remove"
      ></SomeEditor>
    </template>
  </FeathersVuexFormWrapper>
</template>

<script>

import { FeathersVuexFormWrapper } from 'feathers-vuex'

export default {
  name: 'MyComponent',
  components: { FeathersVuexFormWrapper },
  props: {
    currentItem: {
      type: Object,
      required: true
    }
  },
  data: () => ({
    isModalVisible: true
  }),
  methods: {
    handleSaveReponse(savedItem) {
      console.log(savedItem) // The item returned from the API call
    }
  }
}
</script>
```
### Props

- `item`: {Object} a model instance from the Vuex store.
- `watch`: {Boolean|Array} when enabled, if the original record is updated, the data will be re-cloned.  The newly-cloned data will overwrite the `clone` data (in the slot scope).  Default: `false`.
- `eager`: {Boolean} While this is enabled, using the `save` method will first commit the result to the store then it will send a network request.  The UI display will update immediately, without waiting for any response from the API server.  Default: `true`.

### Slot Scope

The default slot contains only four attributes.  The `clone` data can be passed to the child component.  The `save`, `reset`, and `remove` are meant to be bound to events emitted from the child component.

- `clone`: {Object} The cloned record.  Each record in the store can have a single clone.  The clones are stored on the service's model class, by default.
- `save`: {Function} When called, it commits the data and saves the record (with eager updating, by default.  See the `eager` prop.)  The save method calls `instance.save()`, internally, so you can pass a params object, if needed.
- `reset`: {Function} When called, the clone data will be reset back to the data that is currently found in the store for the same record.
- `remove`: {Function} When called, it removes the record from the API server and the Vuex store.

### Usage with `diffOnPatch`

If you plan to use the `diffOnPatch` static Model method together with the `FeathersVuexFormWrapper`, be sure to set the `eager` prop to `false`.  See [this GitHub issue](https://github.com/feathersjs-ecosystem/feathers-vuex/issues/520) for more details.

## FormWrapper Example: CRUD Form

### TodoView

It's a pretty common scenario to have the same form handle editing and creating data.  Below is a basic example of how you could use the FeathersVuexFormWrapper for this.  A few things to notice about the example:

1. It uses a `Todo` Model class to create and edit todos.  The `$FeathersVuex` object is available on `this` only when the [Feathers-Vuex Vue plugin](./vue-plugin.md) is used.
2. It assumes that you have a route setup with an `:id` parameter.
3. It assumes that the data has a MongoDB-style `_id` property, where an SQL-based service would probably use `id`.

```vue
<template>
  <FeathersVuexFormWrapper :item="item" watch>
    <template v-slot="{ clone, save, reset, remove }">
      <TodoEditor
        :item="clone"
        @save="save().then(handleSaveResponse)"
        @reset="reset"
        @remove="remove"
      ></TodoEditor>
    </template>
  </FeathersVuexFormWrapper>
</template>

<script>
import { FeathersVuexFormWrapper } from 'feathers-vuex'
import TodoEditor from './TodoEditor.vue'

export default {
  name: 'TodoView',
  components: {
    FeathersVuexFormWrapper,
    TodoEditor
  },
  props: {
    currentItem: {
      type: Object,
      required: true
    }
  },
  computed: {
    id() {
      return this.$route.params.id
    },
    // Returns a new Todo if the route `id` is 'new', or returns an existing Todo.
    item() {
      const { Todo } = this.$FeathersVuex.api

      return this.id === 'new' ? new Todo() : Todo.getFromStore(this.id)
    },
  },
  watch: {
    id: {
      handler(val) {
        // Early return if the route `:id` is 'new'
        if (val === 'new') {
          return
        }
        const { Todo } = this.$FeathersVuex.api
        const existingRecord = Todo.getFromStore(val)

        // If the record doesn't exist, fetch it from the API server
        // The `item` getter will automatically update after the data arrives.
        if (!existingRecord) {
          Todo.get(val)
        }
      },
      // We want the above handler handler to run immediately when the component is created.
      immediate: true
    }
  },
  methods: {
    handleSaveReponse(savedTodo) {
      // Redirect to the newly-saved item
      if (this.id === 'new') {
        this.$router.push({ params: { id: savedTodo._id } })
      }
    }
  }
}
</script>
```


### TodoEditor

Next let's look at a minimal example of a 'TodoEditor' component which is a child of the `FeathersVuexFormWrapper` in the above example.  A few things to notice about the below `TodoEditor` component:

1. It's minimal on purpose to show you the important parts of working with the `FeathersVuexFormWrapper`.
1. It emits the `save`, `reset`, and `remove` events, which are connected to the `FeathersVuexFormWrapper` in the above code snippet.
1. It's not styled to keep it simple.  You'll probably want to add some styles.  ;)
1. The Delete button immediately emits remove, so the instance will be deleted immediately.  You probably want, instead, to show a prompt or confirmation dialog to ask the user to confirm deletion.
1. This is HTML, so the button `type` is important.  If you forget to add `type="button"` to a button, it will default to `type="submit"`.  Clicking the button would submit the form and call the `@submit.prevent` handler on the `<form>` element.  This even applies to buttons inside child components of the form.  You definitely want to remember to put `type` attributes on all of your buttons.

```vue
<template>
  <form @submit.prevent="handleSubmit">
    <input type="checkbox" v-model="item.isComplete" />
    <input type="text" v-model="item.description" />

    <!-- Submits the form, see the @submit handler, above -->
    <button type="submit">Save</button>

    <!-- Emitting reset will restore the item back to the stored version. -->
    <button type="button" @click="$emit('reset')">Reset</button>

    <!-- Delete's the instance -->
    <button type="button" @click="$emit('remove')">Delete</button>
  </form>
</template>

<script>
export default {
  name: 'TodoEditor',
  props: {
    item: {
      type: Object,
      required: true
    }
  },
  setup(props, context) {
    function handleSubmit() {
      // This is a placeholder for checking form validity, (with Vuelidate, for example)
      const isValid = true || false

      if (formIsValid) {
        context.emit('save')
      } else {
        // Show any form errors in the UI.
      }
    }
    return { handleSubmit }
  }
}
</script>
```

### Vuelidate 2 Example

Here's an example of how you might use the upcoming Vuelidate 2 (which is being rewritten to work with the Vue Composition API) to do form validation.  Just to be clear, the validation library you use doesn't change how FeathersVuex will work.  Since Vuelidate is likely the most popular validation library, this is an example to get you started.  There may be some things to figure out to implement your use case.  First, you'll need to install these dependencies:

```json
{
  "dependencies": {
    "@vuelidate/core": "^2.0.0-alpha.0",
    "@vuelidate/validators": "^2.0.0-alpha.0"
  }
}
```

Here's the full example, complete with TailwindCSS styles.

```html
<template>
  <div class="permission-creator flex flex-row items-end">
    <!-- Org Selector -->
    <label class="block w-full">
      <span class="select-label text-gray-700">Add Organization</span>
      <XSelect
        v-model="selectedOrg"
        :items="filteredOrgs"
        :label="makeOrgLabel"
        clearable
        placeholder="Select an Organization"
        class="block"
        :input-class="[
          'x-select-button px-2 py-2 border rounded bg-white',
          $v.org.$dirty && $v.org.$invalid
            ? 'border-red-400'
            : 'border-gray-400'
        ]"
        @click="$v.org.$touch"
      />
    </label>

    <!-- Permission Selector -->
    <label class="block ml-0.5">
      <span class="select-label text-gray-700">Permission</span>
      <PermissionSelect v-model="selectedAccessType" />
    </label>

    <button
      class="form-button primary ml-0.5"
      :disabled="$v.$invalid"
      @click="validateAndCreate"
    >
      Add
    </button>
  </div>
</template>

<script>
import { XSelect } from '@rovit/x-select'
import PermissionSelect from '../PermissionSelect/PermissionSelect'
import { models, useFind } from 'feathers-vuex'
import { computed, ref } from '@vue/composition-api'
import keyBy from 'lodash/keyBy'
import capitalize from 'voca/capitalize'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'

export default {
  name: 'PermissionCreatorOrg',
  components: {
    XSelect,
    PermissionSelect
  },
  props: {
    excludeIds: {
      type: Array,
      default: () => []
    }
  },
  setup(props, context) {
    const { Org } = models.api

    const selectedOrg = ref(null)
    const selectedAccessType = ref('view')

    // Fetch orgs
    const orgsParams = computed(() => {
      return { query: {} }
    })
    const { items: orgs } = useFind({ model: Org, params: orgsParams })

    const filteredOrgs = computed(() => {
      const excludeIds = keyBy(props.excludeIds)
      return orgs.value.filter(org => {
        return !excludeIds[org._id]
      })
    })

    const $v = useVuelidate(
      {
        org: { required, $autoDirty: true },
        accessType: { required, $autoDirty: true }
      },
      { org: selectedOrg, accessType: selectedAccessType }
    )

    function validateAndCreate() {
      const org = selectedOrg.value
      const accessType = selectedAccessType.value

      if (!$v.$invalid) context.emit('create', { org, accessType })

      selectedOrg.value = null
      selectedAccessType.value = 'view'

      // Not currently working, so the org select turns red after removal
      $v.org.$reset()
    }

    function makeOrgLabel(org) {
      let label = `${org.name}`
      if (org.nameOfOwner) {
        label += ` (${org.nameOfOwner})`
      }
      return label
    }

    return {
      selectedOrg,
      selectedAccessType,
      filteredOrgs,
      validateAndCreate,
      capitalize,
      $v,
      makeOrgLabel
    }
  }
}
</script>

<style lang="postcss"></style>
```

## FeathersVuexInputWrapper

Building on the same ideas as the FeathersVuexFormWrapper, the FeathersVuexInputWrapper reduces boilerplate for working with the clone and commit pattern on a single input.  One use case for this component is implementing an "edit-in-place" workflow.  The following example shows how to use the FeathersVuexInputWrapper to automatically save a record upon `blur` on a text input:

```html
<template>
  <div class="p-3">
    <FeathersVuexInputWrapper :item="user" prop="email">
      <template #default="{ current, prop, createClone, handler }">
        <input
          v-model="current[prop]"
          type="text"
          @focus="createClone"
          @blur="e => handler(e, save)"
        />
      </template>
    </FeathersVuexInputWrapper>

    <!-- Simple readout to show that it's working. -->
    <pre class="bg-black text-white text-xs mt-2 p-1">{{user}}</pre>
  </div>
</template>

<script>
export default {
  name: 'InputWrapperExample',
  methods: {
    // Optionally make the event handler async.
    async save({ event, clone, prop, data }) {
      const user = clone.commit()
      return user.patch({ data })
    }
  }
}
</script>
```

Notice that in the `save` handler in the above example, the `.patch` method is called on the user, passing in the data.  Because the data contains only the user property which changed, the patch request will only send the data which has changed, saving precious bandwidth.

### Props

The `FeathersVuexInputWrapper` has two props, both of which are required:

- `item`: The original (non-cloned) model instance.
- `prop`: The property name on the model instance to be edited.

### Default Slot Scope

Only the default slot is used. The following props are available in the slot scope:

- `current {clone|instance}`: returns the clone if it exists, or the original record. `current = clone || item`
- `clone { clone }`: the internal clone. This is exposed for debugging purposes.
- `prop {String}`: the value of the `prop` prop. If you have the prop stored in a variable in the outer scope, this is redundant and not needed. You could just use this from the outer scope.  It mostly comes in handy when you are manually specifying the `prop` name on the component.
- `createClone {Function}`: sets up the internal clone. Meant to be used as an event handler.
- `handler {Function}`: has the signature `handler(event, callback)`.  It prepared data before calling the callback function that must be provided from the outer scope.

### The Callback Function

The `handler` function in the slot scope requires the use of a callback function as its second argument.  Here's an example callback function followed by an explanation of its properties:

```js
myCallback({ event, clone, prop, data }) {
  clone.commit()
}
```

- `event {Event}`: the event which triggered the `handler` function in the slot scope.
- `clone {clone}`: the cloned version of the `item` instance that was provided as a prop.
- `prop {String}`: the name of the `prop` that is being edited (will always match the `prop` prop.)
- `data {Object}`: An object containing the changes that were made to the object. Useful for calling `.patch({ data })` on the original instance.

This callback needs to be customized to fit your business logic.  You might patch the changes right away, as shown in this example callback function.

```js
async save({ event, clone, prop, data }) {
  const user = clone.commit()
  return user.patch({ data })
}
```

Notice in the example above that the `save` function is `async`.  This means that it returns a promise, which in this case is the `user.patch` request.  Internally, the `handler` method will automatically set the internal `clone` object to `null`, which will cause the `current` computed property to return the original instance.

Note that some types of HTML input elements will call `handler` repeatedly, so the handler needs to be debounced.  See an example, below.

## InputWrapper Examples

### Text Input

With a text input, you can use the `focus` and `blur` events

```html
<template>
  <div class="p-3">
    <FeathersVuexInputWrapper :item="user" prop="email">
      <template #default="{ current, prop, createClone, handler }">
        <input
          v-model="current[prop]"
          type="text"
          @focus="createClone"
          @blur="e => handler(e, save)"
        />
      </template>
    </FeathersVuexInputWrapper>

    <!-- Simple readout to show that it's working. -->
    <pre class="bg-black text-white text-xs mt-2 p-1">{{user}}</pre>
  </div>
</template>

<script>
export default {
  name: 'InputWrapperExample',
  props: {
    user: {
      type: Object,
      required: true
    }
  },
  methods: {
    // The callback can be async
    async save({ event, clone, prop, data }) {
      const user = clone.commit()
      return user.patch({ data })
    }
  }
}
</script>
```

### Color Input

Here is an example of using the FeathersVuexInputWrapper on a color input.  Color inputs emit a lot of `input` and `change` events, so you'll probably want to debounce the callback function if you are going to immediately save changes.  The example after this one shows how you might debounce.

```html
<template>
  <div class="p-3">
    <FeathersVuexInputWrapper :item="user" prop="email">
      <template #default="{ current, prop, createClone, handler }">
        <input
          v-model="current[prop]"
          type="text"
          @click="createClone"
          @change="e => handler(e, save)"
        />
      </template>
    </FeathersVuexInputWrapper>

    <!-- Simple readout to show that it's working. -->
    <pre class="bg-black text-white text-xs mt-2 p-1">{{user}}</pre>
  </div>
</template>

<script>
export default {
  name: 'InputWrapperExample',
  props: {
    user: {
      type: Object,
      required: true
    }
  },
  methods: {
    // The callback can be async
    async save({ event, clone, prop, data }) {
      const user = clone.commit()
      return user.patch({ data })
    }
  }
}
</script>
```

### Color Input with Debounce

Here is an example of using the FeathersVuexInputWrapper on a color input.  Notice how the debounced callback function is provided to the `handler`.  This is because color inputs trigger a `change` event every time their value changes.  To prevent sending thousands of patch requests as the user changes colors, we use the debounced function to only send a request after 100ms of inactivity.

Notice also that this example uses the Vue Composition API because creating a debounced function is much cleaner this way.

```vue
<template>
  <div class="p-3">
    <FeathersVuexInputWrapper :item="user" prop="email">
      <template #default="{ current, prop, createClone, handler }">
        <input
          v-model="current[prop]"
          type="text"
          @click="createClone"
          @change="e => handler(e, debouncedSave)"
        />
      </template>
    </FeathersVuexInputWrapper>

    <!-- Simple readout to show that it's working. -->
    <pre class="bg-black text-white text-xs mt-2 p-1">{{user}}</pre>
  </div>
</template>

<script>
import _debounce from 'lodash/debounce'

export default {
  name: 'InputWrapperExample',
  props: {
    user: {
      type: Object,
      required: true
    }
  },
  setup() {
    // The original, non-debounced save function
    async function save({ event, clone, prop, data }) {
      const user = clone.commit()
      return user.patch({ data })
    }
    // The debounced wrapper around the save function
    const debouncedSave = _debounce(save, 100)

    // We only really need to provide the debouncedSave to the template.
    return { debouncedSave }
  }
}
</script>
```


================================================
FILE: docs/feathervuex-in-vuejs3-setup.md
================================================
# Using Vuejs 3 setup()
Vuejs 3 introduced a new way of passing data from a parent to its child. This is valuable if the child is deep down the hierarchy chain. We want to include `FeathersVuex` in many child components. Through [Inject/Provide](https://v3.vuejs.org/guide/component-provide-inject.html#working-with-reactivity) we now have the ability to `inject` the `FeathersVuex`.`api` into our setup method.


## Setup() method
The context is no longer passed into the setup() as a parameter:

```
setup(props, context) {
    // old way
    const { User } = root.$FeathersVuex.api
}
```

We now must `inject` it into setup():

```
export default defineComponent({
    import { inject } from 'vue';

    setup() {
        // both $FeatherVuex and $fv work here
        const models: any = inject('$FeathersVuex')
        const newUser = new models.api.User()

        return {
            newUser
        }
    }
})
```

If an custom alias is desired, pass the `alias` into the module install as detailed [here](https://github.com/feathersjs-ecosystem/feathers-vuex/blob/vue-demi/packages/feathers-vuex-vue3/src/app-plugin.ts).

**Note:** You may auto import `inject` and other `vue` utilities using [unplugin-auto-import](https://github.com/antfu/unplugin-auto-import). Make sure to adjust the `auto-import.d.ts` file to match your `include[]` directory (`src` for vue-cli generated apps)



================================================
FILE: docs/getting-started.md
================================================
---
title: Getting Started
sidebarDepth: 3
---

# Getting Started with Feathers-Vuex

## Installation

```bash
npm install feathers-vuex @vue/composition-api --save
```

```bash
yarn add feathers-vuex @vue/composition-api
```

IMPORTANT: Feathers-Vuex is (and requires to be) published in ES6 format for full compatibility with JS classes.  If your project uses Babel, it must be configured properly.  See the [Project Configuration](#projectconfiguration) section for more information.

### With feathers-socketio

A realtime-transport like Socket.io or Primus is required in order to take advantage of the real-time socket events built into Feathers-Vuex. The `feathers-hooks-common` package, specified below, is not required to work with Feathers-Vuex.

```bash
npm i @feathersjs/feathers @feathersjs/socketio-client @feathersjs/authentication-client socket.io-client @vue/composition-api feathers-vuex feathers-hooks-common --save
```

```bash
yarn add @feathersjs/feathers @feathersjs/socketio-client @feathersjs/authentication-client socket.io-client @vue/composition-api feathers-vuex feathers-hooks-common
```

### With feathers-rest

Feathers-Vuex works with Feathers-Rest, but keep in mind that the `feathers-rest` client does not listen to socket events. The `feathers-hooks-common` package, specified below, is not required to work with Feathers-Vuex.

```bash
npm i @feathersjs/feathers @feathersjs/rest-client @feathersjs/authentication-client @vue/composition-api feathers-hooks-common feathers-vuex --save
```

```bash
yarn add @feathersjs/feathers @feathersjs/rest-client @feathersjs/authentication-client @vue/composition-api feathers-hooks-common feathers-vuex
```

## Project Configuration

### Vue-CLI

If your project runs on Vue-CLI, add the following to your `vue.config.js` file:

```js
module.exports = {
  transpileDependencies: ['feathers-vuex']
}
```

### Quasar

> In newer Quasar apps, the following `transpileDependencies` setup may not be necessary, anymore. See [this issue on GitHub](https://github.com/feathersjs-ecosystem/feathers-vuex/issues/450)

For Quasar apps, `transpileDependencies` can be updated in `quasar.conf.js` under build as

```
build: {
  transpileDependencies: ['feathers-vuex']
}
```

### Nuxt

If your project uses Nuxt, add the following to your `nuxt.config.js` file:

```
build: {
  transpile: ['feathers-vuex'],
}
```

### Resolving Build Issues

If you have issues with sub-dependencies not loading correctly, you may want to check out [this GitHub issue](https://github.com/feathersjs-ecosystem/feathers-vuex/issues/399).  One of the suggestions is likely to fix the issue.


Be sure to read the section of the docs dedicated to [Working With Nuxt](./nuxt.md).

## Vue DevTools

Since Feathers-Vuex extensively uses Vuex under the hood, you'll want to make sure your VueJS developer tools are up to date AND setup properly.  Specifically, the "New Vuex Backend" needs to be enabled.  To setup the devtools

1. Open the Vue tab of the developer tools while viewing your Vue project in the browser.
1. Go to the Settings panel.
1. Enable the new Vuex backend:

![New Vuex Backend in Vue DevTools](/img/devtools.jpg)

When the above setting is not enabled, the Vue Devtools will likely hang when you start working on a large project.

## Setup

Using Feathers-Vuex happens in these steps:

1. [Setup the Feathers client and Feathers-Vuex](#setup-the-feathers-client-and-feathers-vuex)
2. [Define a Model class and service plugin for each service](#setup-one-or-more-service-plugins)
3. [Setup the auth plugin](#setup-the-auth-plugin), if required.
4. Register the plugins with the Vuex store.

### Feathers Client & Feathers-Vuex

To setup `feathers-vuex`, we first need to setup the latest Feathers client.  We can also setup feathers-vuex in the same file.  Depending on your requirements, you'll need to install the feathers-client dependencies, as shown, above.

Note that this example includes an app-level hook that removes attributes for handling temporary (local-only) records.

```js
// src/feathers-client.js
import feathers from '@feathersjs/feathers'
import socketio from '@feathersjs/socketio-client'
import auth from '@feathersjs/authentication-client'
import io from 'socket.io-client'
import { iff, discard } from 'feathers-hooks-common'
import feathersVuex from 'feathers-vuex'

const socket = io('http://localhost:3030', {transports: ['websocket']})

const feathersClient = feathers()
  .configure(socketio(socket))
  .configure(auth({ storage: window.localStorage }))
  .hooks({
    before: {
      all: [
        iff(
          context => ['create', 'update', 'patch'].includes(context.method),
          discard('__id', '__isTemp')
        )
      ]
    }
  })

export default feathersClient

// Setting up feathers-vuex
const { makeServicePlugin, makeAuthPlugin, BaseModel, models, FeathersVuex } = feathersVuex(
  feathersClient,
  {
    serverAlias: 'api', // optional for working with multiple APIs (this is the default value)
    idField: '_id', // Must match the id field in your database table/collection
    whitelist: ['$regex', '$options']
  }
)

export { makeAuthPlugin, makeServicePlugin, BaseModel, models, FeathersVuex }
```

### Service Plugins

The following example creates a User class and registers it with the new `makeServicePlugin` utility function.  This same file is also a great place to add your service-level hooks, so they're shown, too.

```js
// src/store/services/users.js
import feathersClient, { makeServicePlugin, BaseModel } from '../../feathers-client'

class User extends BaseModel {
  constructor(data, options) {
    super(data, options)
  }
  // Required for $FeathersVuex plugin to work after production transpile.
  static modelName = 'User'
  // Define default properties here
  static instanceDefaults() {
    return {
      email: '',
      password: ''
    }
  }
}
const servicePath = 'users'
const servicePlugin = makeServicePlugin({
  Model: User,
  service: feathersClient.service(servicePath),
  servicePath
})

// Setup the client-side Feathers hooks.
feathersClient.service(servicePath).hooks({
  before: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
  },
  after: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
  },
  error: {
    all: [],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
  }
})

export default servicePlugin
```

### Auth Plugin

If your application uses authentication, the Auth Plugin will probably come in handy.  It's a couple of lines to setup:

```js
// src/store/store.auth.js
import { makeAuthPlugin } from '../feathers-client'

export default makeAuthPlugin({ userService: 'users' })
```

[Read more about the Auth Plugin](/auth-plugin.html).

### Vuex store

This example uses Webpack's `require.context` feature.  If you're not using Webpack, you'll need to manually import each module and list them in the `plugins` array.

```js
// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import { FeathersVuex } from '../feathers-client'
import auth from './store.auth'

Vue.use(Vuex)
Vue.use(FeathersVuex)

const requireModule = require.context(
  // The path where the service modules live
  './services',
  // Whether to look in subfolders
  false,
  // Only include .js files (prevents duplicate imports`)
  /\.js$/
)
const servicePlugins = requireModule
  .keys()
  .map(modulePath => requireModule(modulePath).default)

export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  plugins: [...servicePlugins, auth]
})
```

## Begin Using Feathers-Vuex

There are a couple of ways to use Feathers-Vuex.  Version 2.0 heavily focuses on abstracting away the Vuex syntax in favor of using [Model classes](/model-classes.html).  The Model classes are a layer on top of the Vuex getters, mutations, and actions. You can, of course, also directly use the [service plugin's getters, mutations, and actions](/service-plugin.html).

There are two plugins included:

1. The [Service Plugin](./service-plugin.md) adds a Vuex store for new services.
2. The [Auth Plugin](./auth-plugin.md) sets up the Vuex store for authentication / logout.

To see `feathers-vuex` in a working vue-cli application, check out [`feathers-chat-vuex`](https://github.com/feathersjs-ecosystem/feathers-chat-vuex).

### Global Configuration

The following default options are available for configuration:

```js
const defaultOptions = {
  // only configured globally
  serverAlias: 'api',
  keepCopiesInStore: false,

  // also configurable per service
  idField: 'id',
  tempIdField: '__id',
  nameStyle: 'short',

  debug: false,
  addOnUpsert: false,
  autoRemove: false,
  enableEvents: true,
  preferUpdate: false,
  replaceItems: false,
  skipRequestIfExists: false,

  paramsForServer: ['$populateParams'],
  whitelist: [],

  handleEvents: {
    created: (item, { model, models }) => options.enableEvents,
    patched: (item, { model, models }) => options.enableEvents,
    updated: (item, { model, models }) => options.enableEvents,
    removed: (item, { model, models }) => options.enableEvents
  },
}
```
- `serverAlias` - **Default:** `api` - Models are keyed by `serverAlias`. Access the `$FeathersVuex` Plugin and its models in your components by `this.$FeathersVuex.api.${Model}`
- `keepCopiesInStore` - **Default:** `false` - Set to true to store cloned copies in the store instead of on the Model. <Badge text="deprecated" type="warning" />

- `idField {String}` - **Default:** `'id'` - The field in each record that will contain the id
- `tempIdField {Boolean}` - **Default:** `'__id'` - The field in each temporary record that contains the id
- `nameStyle {'short'|'path'}` - **Default:** `'short'` - Use the full service path as the Vuex module name, instead of just the last section.
- `debug {Boolean}` - **Default:** `false` - Enable some logging for debugging
- `addOnUpsert {Boolean}` - **Default:** `false` - If `true` add new records pushed by 'updated/patched' socketio events into store, instead of discarding them.
- `autoRemove {Boolean}` - **Default:** `false` - If `true` automatically remove records missing from responses (only use with feathers-rest)
- `preferUpdate {Boolean}` - **Default:** `false` - If `true`, calling `model.save()` will do an `update` instead of a `patch`.
- `replaceItems {Boolean}` - **Default:** `false` - If `true`, updates & patches replace the record in the store. Default is false, which merges in changes.
- `skipRequestIfExists {Boolean}` - **Default:** `false` - For get action, if `true` the record already exists in store, skip the remote request.
- `paramsForServer {Array}` - **Default:** `['$populateParams']` - Custom query operators that are ignored in the find getter, but will pass through to the server. It is preconfigured to work with the `$populateParams` custom operator from [feathers-graph-populate](https://feathers-graph-populate.netlify.app/).
- `whitelist {Array}` - **Default:** `[]` - Custom query operators that will be allowed in the find getter.
- `enableEvents {Boolean}` - **Default:** `true` - If `false` socket event listeners will be turned off. See the services
- `handleEvents {Object}`: For this to work `enableEvents` must be `true`
  - `created {Function}` - **Default:** `(item, { model, models }) => options.enableEvents` - handle `created` events, return true to add to the store
  - `patched {Function}` - **Default:** `(item, { model, models }) => options.enableEvents` - handle `created` events, return true to update in the store
  - `updated {Function}` - **Default:** `(item, { model, models }) => options.enableEvents` - handle `created` events, return true to update in the store
  - `removed {Function}` - **Default:** `(item, { model, models }) => options.enableEvents` - handle `removed` events, return true to remove from the store

Also see the [Configs per Service](/service-plugin.html#configuration)

### Note about feathers-reactive

Previous versions of this plugin required both RxJS and `feathers-reactive` to receive realtime updates.  `feathers-vuex@1.0.0` has socket messaging support built in and takes advantage of Vuex reactivity, so RxJS and `feathers-reactive` are no longer required or supported.

Each service module can also be individually configured.


================================================
FILE: docs/index.md
================================================
---
home: true
heroImage: https://github.com/feathersjs-ecosystem/feathers-vuex/raw/master/service-logo.png
heroText: Feathers-Vuex 3.x
tagLine: Integration of FeathersJS, Vue, and Nuxt for the artisan developer
actionText: Get Started
actionLink: ./api-overview.md
features:
- title: Realtime by Default
  details: It's fully powered by Vuex and FeathersJS, lightweight, & realtime out of the box.
- title: Simplified Auth & Services
  details: Includes service and auth plugins powered by Vuex. All plugins can be easily customized to fit your app.  Fully flexible.
- title: Best Practices, Baked In
  details: Vue Composition API 😎 Common Redux patterns included. Fall-through cache by default. Query the Vuex store like a database.
footer: MIT Licensed | Copyright © 2017-present Marshall Thompson
---


================================================
FILE: docs/mixins.md
================================================
---
title: Mixins
sidebarDepth: 3
---

# Mixins

`Feathers-Vuex` mixins provide quick and easy best practices directly inside a component's viewModel.  They are similar to [Renderless Data Components](./components.md), but are more powerful for two reasons.

1. You can do lots of them together. Handle multiple queries against multiple services at the same time.  The Renderless Data Components aren't capable of handling more than one query without doing ugly nesting.
2. They bring the data directly into the component's actual viewModel.  The Renderless Data Components only pull the data into the template scope, so the only clean way to get access to the data was by passing it to a component as props.  This is a great solution until you run into number 1, above.

If you're not using the [Feathers-Vuex Composition API](./composition-api.md), the mixins are probably going to be your preferred solution for development.

## Usage

Here are the steps to using mixins:

1. Import the `makeFindMixin` utility from FeathersVuex.
2. Register it in a component's mixins once for each query to be made in the component.
3. Provide a set of params in a computed property (getter only)
4. Iterate over the computed "items" prop named after the service.

```vue
<script>
import { makeFindMixin } from 'feathers-vuex' // Step 1

export default {
  name: 'ServerTaskList',
  mixins: [ makeFindMixin({ service: 'server-tasks' })], // Step 2
  computed: {
    serverTasksParams() {
      return { query: {} } // Step 3
    }
  }
}
</script>

<template>
  <div>
    <ul>
      <!-- Step 4 -->
      <li v-for="task in serverTasks" :key="task._id">
        {{task.name}}
      </li>
    </ul>
  </div>
</template>
```

In the above example, any records returned from the server will automatically show up when they become available.  It also automatically responds to realtime events when you're using one of FeathersJS's realtime transports, like Socket.io.

Notice in the above example that using the mixin automatically makes the `serverTasks` available in the template.  The mixins automatically setup a few properties in the viewModel based on the camelCased name of the service.  You can also provide a `name` attribute to override the defaults:

## makeFindMixin

### Options

- `service {String|Function}` - **required** the service path. This must match a service that has already been registered with FeathersVuex.
  - **{String}** - The service namespace
  - **{Function}** - Any provided function will become a computed property in the component and will be used to determine its value.
- `name {String}` - The name to use in all of the dynamically-generated property names. See the section about Dynamically Generated Props
- `items {String}` - The attribute name to use for the records.
- `params {String|Function}` - One of two possible params attributes.  (The other is `fetchParams`)  When only `params` is provided, it will be used for both the `find` getter and the `find` action.  When using server-side pagination, use `fetchParams` for server communciation and the `params` prop for pulling data from the local store. If the params is `null` or `undefined`, the query against both the API will be skipped. The find getter will return an empty array. **Default {String}: `${camelCasedService}Params`** (So, by default, it will attempt to use the property on the component called serviceName + "Params")
  - **{String}** - The name of the attribute in the current component which holds or returns the query object.
  - **{Function}** - A provided function will become a computed property in the current component.
- `watch {String|Array<String>}` - specifies the attributes of the `params` or `fetchParams` to watch.  When a watched prop changes, a new request will be made to the API server. Pass 'params' to watch the entire params object.  Pass 'params.query.name' to watch the 'name' property of the query. Watch is turned off by default, meaning only one initial request is made. **Default {String}: `${camelCasedService}Params`**
  - **{Boolean}** - If `true`: `[${camelCasedService}Params]` will be watched, else `[]`
  - **{String}** - The name of the component's prop to use as the value. Transformed to an `Array<String>`
  - **{Array<String>}** - Names of the component's prop
- `fetchParams {String|Function}` - when provided, the `fetchParams` serves as the params for the API server request. When `fetchParams` is used, the `param` attribute will be used against the service's local Vuex store. **Default: undefined**
  - **{String}** - The name of the attribute in the current component which holds or returns the params object.
  - **{Function}** - A provided function will become a computed property in the current component.
- `queryWhen {Boolean|String|Function}` - the query to the server will only be made when this evaluates to true.  **Default: true**
  - **{Boolean}** - As a boolean, the value provided determines whether this is on or off.
  - **{String}** - The name of the component's prop to use as the value.
  - **{Function}** - Any provided function will become a method in the component and will receive the current params object as an argument.
- `local {Boolean|String|Function}` - when true, will only use the `params` prop to pull data from the local Vuex store. It will disable queries to the API server. The value of `local` will override `queryWhen`. **Default:false**
  - **{Boolean}** - As a boolean, the value provided determines whether this is on or off.
  - **{String}** - The name of the component's prop to use as the value.
  - **{Function}** - Any provided function will become a computed property in the component and will be used to determine its value.
- `qid {String}` - The "query identifier" ("qid", for short) is used for storing pagination data in the Vuex store. See the service module docs to see what you'll find inside.  The `qid` and its accompanying pagination data from the store will eventually be used for cacheing and preventing duplicate queries to the API.

### Injected Properties

With `makeFindMixin` the following properties will be injected into your component and can become handy to use manually. Since the names of the mixin are basically dynamically generated by the `service` and `name` props you pass. Here the general names to understand what's going on under the hood:

#### Dynamically Generated Props:
```vue
<script>
// general
export default {
  data: {
    [IS_FIND_PENDING]: false, // `isFind${capitalized}Pending`
    [HAVE_ITEMS_BEEN_REQUESTED_ONCE]: false, // `have${capitalized}BeenRequestedOnce`
    [HAVE_ITEMS_LOADED_ONCE]: false, // `have${capitalized}LoadedOnce`
    [MOST_RECENT_QUERY]: null, // `${prefix}LatestQuery`
    [ERROR]: null // ${prefix}Error
  },
  computed: {
    [PAGINATION]() {/* ... */} // `${prefix}PaginationData`
    [ITEMS]() {/* ... */}, // `${items}` || `${name}` || `${camelCasedPluralService}`
    [ITEMS_FETCHED]() {/* ... */} // `${items}Fetched` || `${name}Fetched` || `${camelCasedPluralService}Fetched`
    [FIND_GETTER]() {/* ... */} // `find${capitalized}InStore``
  },
  methods: {
    [`${FIND_ACTION}DebouncedProxy`](params) {/* ... */}  // `get${capitalized}`
    [FIND_ACTION](params) {/* ... */}
  }
}
```
#### Example with `service: 'server-tasks`
```vue
<script>
// example with 'server-tasks' service
export default {
  mixins: [
    makeGetMixin({
      service: 'server-tasks' // depending on service
    })
  ],
  data: {
    isFindServerTasksPending: false,
    haveServerTasksBeenRequestedOnce: false,
    haveServerTasksLoadedOnce: false,
    serverTasksError: null
  },
  computed: {
    serverTasksPaginationData() { /* ... */ }
    serverTasks() { /* ... */ },
    serverTasksFetched() { /* .. */ },
    findServerTasksInStore(params) { /* ... */ },
  },
  methods: {
    findServerTasksDebouncedProxy(params) { /* ... */ },
    findServerTasks(params) { /* ... */ }
  }
}
</script>

```

## makeGetMixin

### Options

- `id {String|Function}` - when performing a `get` request, serves as the id for the request. This is automatically watched, so if the `id` changes, an API request will be made and the data will be updated.  If `undefined` or `null`, no request will be made.  **Default: undefined**
  - **{String}** - The name of the component's prop to use as the value.
  - **{Function}** - Any provided function will become a computed property in the component and will be used to determine its value.
- `service {String|Function}` - **required** the service path. This must match a service that has already been registered with FeathersVuex.
  - **{String}** - The service namespace
  - **{Function}** - Any provided function will become a computed property in the component and will be used to determine its value.
- `name {String}` - The name to use in all of the dynamically-generated property names. See the section about Dynamically Generated Props
- `item {String}` - The attribute name to use for the record.
- `params {String|Function}` - One of two possible params attributes.  (The other is `fetchParams`)  When only `params` is provided, it will be used for both the `find` getter and the `find` action.  When using server-side pagination, use `fetchParams` for server communciation and the `params` prop for pulling data from the local store. If the params is `null` or `undefined`, the query against both the API will be skipped. The find getter will return an empty array. **Default {String}: `${camelCasedSingularizedService}Params`** (So, by default, it will attempt to use the property on the component called serviceName + "Params")
  - **{String}** - The name of the attribute in the current component which holds or returns the query object.
  - **{Function}** - A provided function will become a computed property in the current component.
- `watch {Boolean|String|Array<String>}` - specifies the attributes of the `params` or `fetchParams` to watch.  When a watched prop changes, a new request will be made to the API server. Pass 'params' to watch the entire params object.  Pass 'params.query.name' to watch the 'name' property of the query. Watch is turned off by default, meaning only one initial request is made. **Default {Array}: `[]`**
  - **{Boolean}** - If `true`: `[${camelCasedService}Params]` will be watched, else `[]`
  - **{String}** - The name of the component's prop to use as the value. Transformed to an `Array<String>`
  - **{Array<String>}** - Names of the component's prop
- `fetchParams {String|Function}` - when provided, the `fetchParams` serves as the params for the API server request. When `fetchParams` is used, the `param` attribute will be used against the service's local Vuex store. **Default: undefined**
  - **{String}** - The name of the attribute in the current component which holds or returns the params object.
  - **{Function}** - A provided function will become a computed property in the current component.

- `queryWhen {Boolean|String|Function}` - the query to the server will only be made when this evaluates to true.  **Default: true**
  - **{Boolean}** - As a boolean, the value provided determines whether this is on or off.
  - **{String}** - The name of the component's prop to use as the value.
  - **{Function}** - Any provided function will become a method in the component and will receive the current params object as an argument.

- `local {Boolean|String|Function}` - when true, will only use the `params` prop to pull data from the local Vuex store. It will disable queries to the API server. The value of `local` will override `queryWhen`. **Default:false**
  - **{Boolean}** - As a boolean, the value provided determines whether this is on or off.
  - **{String}** - The name of the component's prop to use as the value.
  - **{Function}** - Any provided function will become a computed property in the component and will be used to determine its value.

### Injected Properties

With `makeGetMixin` the following properties will be injected into your component and can become handy to use manually. Since the names of the mixin are basically dynamically generated by the `service` and `name` props you pass. Here the general names to understand what's going on under the hood:

#### Dynamically Generated Props:
```vue
<script>
export default {
  data: {
    [IS_GET_Pending]: false, // `isGet${capitalized}Pending`
    [HAS_ITEM_BEEN_REQUESTED_ONCE]: false, // `has${capitalized}BeenRequestedOnce`
    [HAS_ITEM_LOADED_ONCE]: false, // `has${capitalized}LoadedOnce`
    [ERROR]: null // `${prefix}Error`
  },
  computed: {
    [ITEM]() { /* ... */ }, // `${item}` || `${name}` || ${camelCasedSingularService}`
    [GET_GETTER]() { /* ... */ } // `get${capitalized}FromStore`
  },
  methods: {
    [GET_ACTI
Download .txt
gitextract_asa44tit/

├── .babelrc
├── .editorconfig
├── .github/
│   ├── FUNDING.yml
│   ├── contributing.md
│   ├── issue_template.md
│   └── pull_request_template.md
├── .gitignore
├── .istanbul.yml
├── .npmignore
├── .travis.yml
├── .vscode/
│   └── launch.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── docs/
│   ├── .vuepress/
│   │   └── config.js
│   ├── 2.0-major-release.md
│   ├── 3.0-major-release.md
│   ├── api-overview.md
│   ├── auth-plugin.md
│   ├── common-patterns.md
│   ├── composition-api.md
│   ├── data-components.md
│   ├── example-applications.md
│   ├── feathers-vuex-forms.md
│   ├── feathervuex-in-vuejs3-setup.md
│   ├── getting-started.md
│   ├── index.md
│   ├── mixins.md
│   ├── model-classes.md
│   ├── nuxt.md
│   ├── service-plugin.md
│   └── vue-plugin.md
├── mocha.opts
├── notes.old.md
├── package.json
├── src/
│   ├── FeathersVuexCount.ts
│   ├── FeathersVuexFind.ts
│   ├── FeathersVuexFormWrapper.ts
│   ├── FeathersVuexGet.ts
│   ├── FeathersVuexInputWrapper.ts
│   ├── FeathersVuexPagination.ts
│   ├── auth-module/
│   │   ├── auth-module.actions.ts
│   │   ├── auth-module.getters.ts
│   │   ├── auth-module.mutations.ts
│   │   ├── auth-module.state.ts
│   │   ├── make-auth-plugin.ts
│   │   └── types.ts
│   ├── index.ts
│   ├── make-find-mixin.ts
│   ├── make-get-mixin.ts
│   ├── service-module/
│   │   ├── global-clients.ts
│   │   ├── global-models.ts
│   │   ├── make-base-model.ts
│   │   ├── make-service-module.ts
│   │   ├── make-service-plugin.ts
│   │   ├── service-module.actions.ts
│   │   ├── service-module.events.ts
│   │   ├── service-module.getters.ts
│   │   ├── service-module.mutations.ts
│   │   ├── service-module.state.ts
│   │   └── types.ts
│   ├── useFind.ts
│   ├── useGet.ts
│   ├── utils.ts
│   └── vue-plugin/
│       └── vue-plugin.ts
├── stories/
│   ├── .npmignore
│   ├── FeathersVuexFormWrapper.stories.js
│   └── FeathersVuexInputWrapper.stories.js
├── test/
│   ├── auth-module/
│   │   ├── actions.test.js
│   │   └── auth-module.test.ts
│   ├── auth.test.js
│   ├── fixtures/
│   │   ├── fake-data.js
│   │   ├── feathers-client.js
│   │   ├── server.js
│   │   ├── store.js
│   │   └── todos.js
│   ├── index.test.ts
│   ├── make-find-mixin.test.ts
│   ├── service-module/
│   │   ├── make-service-plugin.test.ts
│   │   ├── misconfigured-client.test.ts
│   │   ├── model-base.test.ts
│   │   ├── model-instance-defaults.test.ts
│   │   ├── model-methods.test.ts
│   │   ├── model-relationships.test.ts
│   │   ├── model-serialize.test.ts
│   │   ├── model-temp-ids.test.ts
│   │   ├── model-tests.test.ts
│   │   ├── service-module.actions.test.ts
│   │   ├── service-module.getters.test.ts
│   │   ├── service-module.mutations.test.ts
│   │   ├── service-module.reinitialization.test.ts
│   │   ├── service-module.test.ts
│   │   └── types.ts
│   ├── test-utils.ts
│   ├── use/
│   │   ├── InstrumentComponent.js
│   │   ├── find.test.ts
│   │   └── get.test.ts
│   ├── utils.test.ts
│   └── vue-plugin.test.ts
├── tsconfig.json
└── tsconfig.test.json
Download .txt
SYMBOL INDEX (340 symbols across 58 files)

FILE: src/FeathersVuexCount.ts
  method total (line 40) | total() {
  method scope (line 48) | scope() {
  method findData (line 55) | findData() {
  method fetchData (line 75) | fetchData() {
  method created (line 89) | created() {
  method render (line 119) | render() {

FILE: src/FeathersVuexFind.ts
  method default (line 41) | default() {
  method default (line 51) | default(scope) {
  method default (line 57) | default() {
  method items (line 75) | items() {
  method pagination (line 85) | pagination() {
  method queryInfo (line 88) | queryInfo() {
  method pageInfo (line 92) | pageInfo() {
  method scope (line 101) | scope() {
  method findData (line 115) | findData() {
  method fetchData (line 144) | fetchData() {
  method created (line 158) | created() {
  method render (line 193) | render() {

FILE: src/FeathersVuexFormWrapper.ts
  method isNew (line 32) | isNew() {
  method setup (line 44) | setup() {
  method save (line 61) | save(params) {
  method reset (line 73) | reset() {
  method remove (line 78) | async remove() {
  method markAsDirty (line 83) | markAsDirty() {
  method render (line 89) | render() {

FILE: src/FeathersVuexGet.ts
  method default (line 66) | default() {
  method default (line 84) | default(scope) {
  method item (line 94) | item() {
  method scope (line 111) | scope() {
  method getArgs (line 119) | getArgs(queryToUse) {
  method getData (line 131) | getData() {
  method fetchData (line 154) | fetchData() {
  method created (line 170) | created() {
  method render (line 205) | render() {

FILE: src/FeathersVuexInputWrapper.ts
  method current (line 23) | current() {
  method handler (line 29) | handler(wait) {
  method createClone (line 36) | createClone(e) {
  method cleanup (line 39) | cleanup() {
  method handler (line 44) | handler(e, callback) {
  method render (line 61) | render() {

FILE: src/FeathersVuexPagination.ts
  method setup (line 28) | setup(props, context) {

FILE: src/auth-module/auth-module.actions.ts
  function makeAuthActions (line 10) | function makeAuthActions(feathersClient) {

FILE: src/auth-module/auth-module.getters.ts
  function makeAuthGetters (line 6) | function makeAuthGetters({ userService }) {

FILE: src/auth-module/auth-module.mutations.ts
  function makeAuthMutations (line 8) | function makeAuthMutations() {

FILE: src/auth-module/auth-module.state.ts
  function setupAuthState (line 8) | function setupAuthState({

FILE: src/auth-module/make-auth-plugin.ts
  function authPluginInit (line 23) | function authPluginInit(

FILE: src/auth-module/types.ts
  type AuthState (line 1) | interface AuthState {

FILE: src/index.ts
  function feathersVuex (line 56) | function feathersVuex(feathers, options: FeathersVuexOptions) {

FILE: src/make-find-mixin.ts
  function makeFindMixin (line 17) | function makeFindMixin(options) {

FILE: src/make-get-mixin.ts
  function makeFindMixin (line 9) | function makeFindMixin(options) {

FILE: src/service-module/global-clients.ts
  function addClient (line 20) | function addClient({ client, serverAlias }) {
  function clearClients (line 33) | function clearClients() {

FILE: src/service-module/global-models.ts
  function prepareAddModel (line 18) | function prepareAddModel(options: FeathersVuexOptions) {
  function clearModels (line 35) | function clearModels() {

FILE: src/service-module/make-base-model.ts
  function assertIsEventEmitter (line 33) | function assertIsEventEmitter(val: unknown): asserts val is EventEmitter {
  function makeBaseModel (line 47) | function makeBaseModel(options: FeathersVuexOptions) {

FILE: src/service-module/make-service-module.ts
  function makeServiceModule (line 16) | function makeServiceModule(

FILE: src/service-module/make-service-plugin.ts
  type ServiceOptionsDefaults (line 18) | interface ServiceOptionsDefaults {
  function prepareMakeServicePlugin (line 56) | function prepareMakeServicePlugin(

FILE: src/service-module/service-module.actions.ts
  type serviceAndOptions (line 11) | interface serviceAndOptions {
  function makeServiceActions (line 16) | function makeServiceActions({service, options}: serviceAndOptions) {

FILE: src/service-module/service-module.events.ts
  type ServiceEventsDebouncedQueue (line 5) | interface ServiceEventsDebouncedQueue {
  function enableServiceEvents (line 14) | function enableServiceEvents({

FILE: src/service-module/service-module.getters.ts
  constant FILTERS (line 14) | const FILTERS = ['$sort', '$limit', '$skip', '$select']
  function makeServiceGetters (line 32) | function makeServiceGetters() {
  type GetterName (line 134) | type GetterName = keyof ReturnType<typeof makeServiceGetters>

FILE: src/service-module/service-module.mutations.ts
  type PendingServiceMethodName (line 23) | type PendingServiceMethodName =
  type PendingIdServiceMethodName (line 30) | type PendingIdServiceMethodName = Exclude<
  function makeServiceMutations (line 35) | function makeServiceMutations() {

FILE: src/service-module/service-module.state.ts
  type ServiceStateExclusiveDefaults (line 12) | interface ServiceStateExclusiveDefaults {
  type ServiceState (line 47) | interface ServiceState<M extends Model = Model> {
  type PaginationState (line 94) | interface PaginationState {
  function makeDefaultState (line 103) | function makeDefaultState(options: MakeServicePluginOptions) {

FILE: src/service-module/types.ts
  type FeathersVuexOptions (line 13) | interface FeathersVuexOptions {
  type HandleEvents (line 33) | interface HandleEvents {
  type ServicePluginExtendOptions (line 40) | interface ServicePluginExtendOptions {
  type MakeServicePluginOptions (line 45) | interface MakeServicePluginOptions {
  type FeathersVuexStoreState (line 89) | interface FeathersVuexStoreState {
  type FeathersVuexGlobalModels (line 93) | interface FeathersVuexGlobalModels {
  type StoreState (line 98) | type StoreState = keyof FeathersVuexStoreState extends never
  type GlobalModels (line 101) | type GlobalModels = keyof FeathersVuexGlobalModels extends never
  type PatchParams (line 105) | interface PatchParams<D extends {} = AnyData> extends Params {
  type ModelSetupContext (line 109) | interface ModelSetupContext {
  type ModelInstanceOptions (line 120) | interface ModelInstanceOptions {
  type AnyData (line 141) | type AnyData = { [key: string]: any }
  type ModelStatic (line 144) | interface ModelStatic extends EventEmitter {
  type Model (line 300) | interface Model {

FILE: src/useFind.ts
  type UseFindOptions (line 17) | interface UseFindOptions {
  type UseFindState (line 26) | interface UseFindState {
  type UseFindData (line 36) | interface UseFindData<M> {
  function find (line 54) | function find<M extends Model = Model>(options: UseFindOptions): UseFind...

FILE: src/useGet.ts
  type UseGetOptions (line 16) | interface UseGetOptions {
  type UseGetState (line 24) | interface UseGetState {
  type UseGetData (line 31) | interface UseGetData<M> {
  function get (line 42) | function get<M extends Model = Model>(options: UseGetOptions): UseGetDat...

FILE: src/utils.ts
  type Query (line 18) | interface Query {
  type PaginationOptions (line 21) | interface PaginationOptions {
  type Params (line 25) | interface Params {
  type Paginated (line 36) | interface Paginated<T> {
  function stripSlashes (line 45) | function stripSlashes(location: string) {
  function setByDot (line 49) | function setByDot(obj, path, value, ifDelete?) {
  function upperCaseFirst (line 85) | function upperCaseFirst(string) {
  function getShortName (line 89) | function getShortName(service) {
  function getNameFromPath (line 99) | function getNameFromPath(service) {
  function readCookie (line 104) | function readCookie(cookies, name) {
  function payloadIsValid (line 123) | function payloadIsValid(payload) {
  function getValidPayloadFromToken (line 142) | function getValidPayloadFromToken(token) {
  function assignTempId (line 209) | function assignTempId(state, item) {
  function stringifyIfObject (line 220) | function stringifyIfObject(val): string | any {
  function getId (line 235) | function getId(item, idField?) {
  function getModelName (line 251) | function getModelName(Model) {
  function registerModel (line 266) | function registerModel(Model, globalModels, apiPrefix, servicePath) {
  function getServicePrefix (line 278) | function getServicePrefix(servicePath) {
  function getServiceCapitalization (line 287) | function getServiceCapitalization(servicePath) {
  function updateOriginal (line 296) | function updateOriginal(original, newData) {
  function getQueryInfo (line 339) | function getQueryInfo(
  function getItemsFromQueryInfo (line 371) | function getItemsFromQueryInfo(pagination, queryInfo, keyedById) {
  function makeNamespace (line 384) | function makeNamespace(namespace, servicePath, nameStyle) {
  function getServicePath (line 398) | function getServicePath(service: Service<any>, Model: any) {
  function randomString (line 408) | function randomString(length) {
  function createRelatedInstance (line 420) | function createRelatedInstance({ item, Model, idField, store }) {
  function isBaseModelInstance (line 429) | function isBaseModelInstance(item) {
  function mergeWithAccessors (line 436) | function mergeWithAccessors(
  function checkNamespace (line 522) | function checkNamespace(namespace, item, debug) {
  function assignIfNotPresent (line 534) | function assignIfNotPresent(Model, props): void {

FILE: src/vue-plugin/vue-plugin.ts
  type VueConstructor (line 17) | interface VueConstructor {
  type Vue (line 20) | interface Vue {
  method install (line 26) | install(Vue, options = { components: true }) {

FILE: stories/FeathersVuexInputWrapper.stories.js
  method save (line 26) | save({ clone, data }) {
  method save (line 57) | async save({ clone, data }) {
  method save (line 89) | async save({ event, clone, prop, data }) {
  method save (line 131) | async save({ clone, data }) {

FILE: test/auth-module/actions.test.js
  method create (line 23) | create(data) {
  method create (line 67) | create(data) {
  method create (line 91) | create(data) {

FILE: test/auth-module/auth-module.test.ts
  type CustomStore (line 15) | interface CustomStore {
  function makeContext (line 22) | function makeContext() {
  method setTestToFalse (line 101) | setTestToFalse(state) {
  method oneTwoThree (line 175) | oneTwoThree() {
  method setToTrue (line 195) | setToTrue(state) {
  method trigger (line 200) | trigger(context) {
  method create (line 218) | create(data, params) {
  method create (line 239) | create(data, params) {

FILE: test/auth.test.js
  method authenticate (line 28) | authenticate() {}
  method dispatch (line 46) | dispatch(action) {

FILE: test/fixtures/feathers-client.js
  function makeFeathersSocketClient (line 61) | function makeFeathersSocketClient(baseUrl) {
  function makeFeathersRestClient (line 68) | function makeFeathersRestClient(baseUrl) {

FILE: test/fixtures/store.js
  function makeStore (line 6) | function makeStore() {

FILE: test/fixtures/todos.js
  function makeTodos (line 1) | function makeTodos() {

FILE: test/make-find-mixin.test.ts
  function makeContext (line 17) | function makeContext() {
  type TodosComponent (line 47) | interface TodosComponent {
  method service (line 104) | service() {
  type TasksComponent (line 110) | interface TasksComponent {

FILE: test/service-module/make-service-plugin.test.ts
  type RootState (line 32) | interface RootState {
  class Todo (line 41) | class Todo extends BaseModel {
  class Todo (line 112) | class Todo extends BaseModel {
  class Todo (line 132) | class Todo extends BaseModel {
  class Todo (line 159) | class Todo extends BaseModel {
  method created (line 174) | created() {
  method updated (line 178) | updated() {
  method patched (line 182) | patched() {
  method removed (line 186) | removed() {
  method created (line 258) | created() {
  method updated (line 262) | updated() {
  method patched (line 266) | patched() {
  method removed (line 270) | removed() {
  class Todo (line 278) | class Todo extends BaseModel {
  method updated (line 291) | updated() {
  method created (line 359) | created(e) {
  method updated (line 362) | updated(e) {
  method patched (line 365) | patched(e) {
  method removed (line 368) | removed(e) {
  class Todo (line 375) | class Todo extends BaseModel {

FILE: test/service-module/misconfigured-client.test.ts
  class MisconfiguredTask (line 15) | class MisconfiguredTask extends BaseModel {

FILE: test/service-module/model-base.test.ts
  class Todo (line 167) | class Todo extends BaseModel {
  class Task (line 178) | class Task extends BaseModel {
  class Todo (line 205) | class Todo extends myApi.BaseModel {
  class Task (line 219) | class Task extends theirApi.BaseModel {

FILE: test/service-module/model-instance-defaults.test.ts
  type TodoState (line 19) | interface TodoState extends ServiceState {
  type RootState (line 26) | interface RootState {
  function makeContext (line 34) | function makeContext() {
  class NakedTodo (line 125) | class NakedTodo extends BaseModel {
  class Car (line 211) | class Car extends BaseModel {
    method combined (line 216) | public get combined(): string {
    method yearBeforeCurrent (line 219) | public set yearBeforeCurrent(year) {
    method constructor (line 225) | public constructor(data?, options?) {
    method constructor (line 253) | public constructor(data?, options?) {
  class Car (line 247) | class Car extends BaseModel {
    method combined (line 216) | public get combined(): string {
    method yearBeforeCurrent (line 219) | public set yearBeforeCurrent(year) {
    method constructor (line 225) | public constructor(data?, options?) {
    method constructor (line 253) | public constructor(data?, options?) {
  class Person (line 271) | class Person extends BaseModel {
    method constructor (line 278) | public constructor(data?, options?) {
    method constructor (line 322) | public constructor(data?, options?) {
    method constructor (line 354) | public constructor(data?, options?) {
    method constructor (line 425) | public constructor(data?, options?) {
  class Person (line 315) | class Person extends BaseModel {
    method constructor (line 278) | public constructor(data?, options?) {
    method constructor (line 322) | public constructor(data?, options?) {
    method constructor (line 354) | public constructor(data?, options?) {
    method constructor (line 425) | public constructor(data?, options?) {
  class Person (line 351) | class Person extends BaseModel {
    method constructor (line 278) | public constructor(data?, options?) {
    method constructor (line 322) | public constructor(data?, options?) {
    method constructor (line 354) | public constructor(data?, options?) {
    method constructor (line 425) | public constructor(data?, options?) {
  method fullName (line 372) | get fullName() {
  method fullName (line 375) | set fullName(val) {
  class Person (line 422) | class Person extends BaseModel {
    method constructor (line 278) | public constructor(data?, options?) {
    method constructor (line 322) | public constructor(data?, options?) {
    method constructor (line 354) | public constructor(data?, options?) {
    method constructor (line 425) | public constructor(data?, options?) {
  method fullName (line 443) | get fullName() {
  method fullName (line 446) | set fullName(val) {

FILE: test/service-module/model-methods.test.ts
  type TodoState (line 18) | interface TodoState extends ServiceState {
  type RootState (line 25) | interface RootState {
  function makeContext (line 34) | function makeContext() {
  method value (line 303) | value(params) {
  method value (line 321) | value(params) {
  method value (line 338) | value(params) {
  method value (line 357) | value(params) {
  method get (line 517) | get() {
  class PendingThing (line 534) | class PendingThing extends BaseModel {
    method constructor (line 536) | public constructor(data?, options?) {

FILE: test/service-module/model-relationships.test.ts
  class Todo (line 24) | class Todo extends BaseModel {
    method constructor (line 29) | public constructor(data, options?) {
    method constructor (line 72) | public constructor(data, options?) {
  function setupInstance (line 33) | function setupInstance(instance, { models, store }): Todo {
  class Todo (line 66) | class Todo extends BaseModel {
    method constructor (line 29) | public constructor(data, options?) {
    method constructor (line 72) | public constructor(data, options?) {
  class User (line 76) | class User extends BaseModel {
  function setupInstance (line 83) | function setupInstance(instance, { models, store }): Todo {
  function makeContext (line 138) | function makeContext() {

FILE: test/service-module/model-serialize.test.ts
  class Task (line 23) | class Task extends BaseModel {
    method instanceDefaults (line 25) | public static instanceDefaults() {
    method toJSON (line 32) | public toJSON() {
    method constructor (line 35) | public constructor(data, options?) {

FILE: test/service-module/model-temp-ids.test.ts
  type RootState (line 18) | interface RootState {
  class ComicService (line 23) | class ComicService extends MemoryService {
    method create (line 24) | public create(data, params) {
    method update (line 32) | public update(id, data, params) {
  function makeContext (line 38) | function makeContext() {
  class Transaction (line 83) | class Transaction extends BaseModel {
    method constructor (line 85) | public constructor(data?, options?) {
    method constructor (line 130) | public constructor(data?, options?) {
    method constructor (line 260) | public constructor(data?, options?) {
    method constructor (line 291) | public constructor(data?, options?) {
    method constructor (line 325) | public constructor(data?, options?) {
  class Transaction (line 128) | class Transaction extends BaseModel {
    method constructor (line 85) | public constructor(data?, options?) {
    method constructor (line 130) | public constructor(data?, options?) {
    method constructor (line 260) | public constructor(data?, options?) {
    method constructor (line 291) | public constructor(data?, options?) {
    method constructor (line 325) | public constructor(data?, options?) {
  class Thing (line 159) | class Thing extends BaseModel {
    method constructor (line 161) | public constructor(data?, options?) {
    method constructor (line 226) | public constructor(data?, options?) {
    method constructor (line 449) | public constructor(data?, options?) {
  class Thing (line 224) | class Thing extends BaseModel {
    method constructor (line 161) | public constructor(data?, options?) {
    method constructor (line 226) | public constructor(data?, options?) {
    method constructor (line 449) | public constructor(data?, options?) {
  class Transaction (line 258) | class Transaction extends BaseModel {
    method constructor (line 85) | public constructor(data?, options?) {
    method constructor (line 130) | public constructor(data?, options?) {
    method constructor (line 260) | public constructor(data?, options?) {
    method constructor (line 291) | public constructor(data?, options?) {
    method constructor (line 325) | public constructor(data?, options?) {
  class Transaction (line 289) | class Transaction extends BaseModel {
    method constructor (line 85) | public constructor(data?, options?) {
    method constructor (line 130) | public constructor(data?, options?) {
    method constructor (line 260) | public constructor(data?, options?) {
    method constructor (line 291) | public constructor(data?, options?) {
    method constructor (line 325) | public constructor(data?, options?) {
  class Transaction (line 323) | class Transaction extends BaseModel {
    method constructor (line 85) | public constructor(data?, options?) {
    method constructor (line 130) | public constructor(data?, options?) {
    method constructor (line 260) | public constructor(data?, options?) {
    method constructor (line 291) | public constructor(data?, options?) {
    method constructor (line 325) | public constructor(data?, options?) {
  class Thing (line 385) | class Thing extends BaseModel {
    method constructor (line 161) | public constructor(data?, options?) {
    method constructor (line 226) | public constructor(data?, options?) {
    method constructor (line 449) | public constructor(data?, options?) {
  class Thing (line 414) | class Thing extends BaseModel {
    method constructor (line 161) | public constructor(data?, options?) {
    method constructor (line 226) | public constructor(data?, options?) {
    method constructor (line 449) | public constructor(data?, options?) {
  class Thing (line 447) | class Thing extends BaseModel {
    method constructor (line 161) | public constructor(data?, options?) {
    method constructor (line 226) | public constructor(data?, options?) {
    method constructor (line 449) | public constructor(data?, options?) {
  class FooModel (line 518) | class FooModel extends BaseModel {
    method constructor (line 520) | public constructor(data?, options?) {
  method things (line 555) | things() {
  method things (line 563) | things(items) {
  class PendingThing (line 586) | class PendingThing extends BaseModel {
    method constructor (line 588) | public constructor(data?, options?) {

FILE: test/service-module/model-tests.test.ts
  type ModelOptions (line 8) | interface ModelOptions {
  method constructor (line 16) | public constructor(data, options?) {
  class Todo (line 26) | class Todo extends BaseModel {
    method constructor (line 34) | public constructor(data, options?) {
    method serialize (line 154) | public serialize() {
  method constructor (line 58) | public constructor(data, options?) {
  function makeServiceModel (line 69) | function makeServiceModel(options) {
  class Todo (line 82) | class Todo extends makeServiceModel({ servicePath: 'todos' }) {
    method constructor (line 34) | public constructor(data, options?) {
    method serialize (line 154) | public serialize() {
  method constructor (line 107) | public constructor(data, options?) {
  class Todo (line 121) | class Todo extends BaseModel {
    method constructor (line 34) | public constructor(data, options?) {
    method serialize (line 154) | public serialize() {
  class BaseModel (line 142) | class BaseModel {
    method clone (line 143) | public clone() {
    method constructor (line 147) | public constructor(data) {
  class Todo (line 152) | class Todo extends BaseModel {
    method constructor (line 34) | public constructor(data, options?) {
    method serialize (line 154) | public serialize() {

FILE: test/service-module/service-module.actions.test.ts
  type RootState (line 15) | interface RootState {
  type NumberedList (line 20) | interface NumberedList {
  function makeContext (line 25) | function makeContext() {
  method afterFind (line 563) | afterFind({}, response) {

FILE: test/service-module/service-module.mutations.test.ts
  class Todo (line 35) | class Todo extends BaseModel {
  class ComicService (line 70) | class ComicService extends MemoryService {
    method create (line 71) | public create(data, params) {
    method update (line 79) | public update(id, data, params) {
  function makeContext (line 85) | function makeContext() {
  method getter (line 484) | get getter() {
  method 'item.getter' (line 501) | 'item.getter'() {
  method 'item.users' (line 536) | 'item.users'() {
  method 'item.users' (line 567) | 'item.users'() {
  method 'item.obj' (line 598) | 'item.obj'() {
  method 'item.obj' (line 627) | 'item.obj'() {
  method 'item.isValid' (line 657) | 'item.isValid'() {
  method 'item.isValid' (line 686) | 'item.isValid'() {
  method 'item.name' (line 716) | 'item.name'() {
  method 'item.name' (line 745) | 'item.name'() {
  method 'item.name' (line 775) | 'item.name'() {
  method 'item.name' (line 805) | 'item.name'() {
  method 'item.age' (line 835) | 'item.age'() {
  method 'item.age' (line 864) | 'item.age'() {
  method getter (line 885) | get getter() {
  method setter (line 888) | set setter(val) {
  method handler (line 907) | handler() {
  method getter (line 932) | get getter() {
  method setter (line 935) | set setter(val) {
  method handler (line 956) | handler() {
  method getter (line 981) | get getter() {
  method setter (line 984) | set setter(val) {
  method getter (line 1042) | get getter() {
  method setter (line 1045) | set setter(val) {
  method getter (line 1146) | get getter() {
  method setter (line 1149) | set setter(val) {
  method getter (line 1200) | get getter() {
  method setter (line 1203) | set setter(val) {
  method getter (line 1232) | get getter() {
  method setter (line 1235) | set setter(val) {
  method makeResult (line 1325) | makeResult(props) {
  method makeResult (line 1372) | makeResult(props) {
  method makeResult (line 1419) | makeResult(props) {
  method makeResult (line 1479) | makeResult(props) {

FILE: test/service-module/service-module.reinitialization.test.ts
  type RootState (line 6) | interface RootState {
  function makeContext (line 10) | function makeContext() {

FILE: test/service-module/service-module.test.ts
  type Options (line 24) | interface Options {
  type TodoState (line 27) | interface TodoState extends ServiceState {
  type RootState (line 34) | interface RootState {
  function makeContext (line 42) | function makeContext() {
  function makeContextWithState (line 117) | function makeContextWithState() {
  function makeAutoRemoveContext (line 138) | function makeAutoRemoveContext() {
  function makeSocketIoContext (line 182) | function makeSocketIoContext() {
  class Todo (line 570) | class Todo extends BaseModel {
  method setTestToFalse (line 997) | setTestToFalse(state) {
  method oneTwoThree (line 1025) | oneTwoThree(state) {
  method setToTrue (line 1059) | setToTrue(state) {
  method trigger (line 1064) | trigger(context) {
  method setTestToFalse (line 1112) | setTestToFalse(state) {
  method oneTwoThree (line 1138) | oneTwoThree(state) {
  method setToTrue (line 1165) | setToTrue(state) {
  method trigger (line 1170) | trigger(context) {

FILE: test/service-module/types.ts
  type ServiceState (line 6) | interface ServiceState {
  type PaginationState (line 36) | interface PaginationState {
  type Location (line 45) | interface Location {

FILE: test/test-utils.ts
  function assertGetter (line 8) | function assertGetter(item, prop, value) {

FILE: test/use/InstrumentComponent.js
  method setup (line 12) | setup(props, context) {

FILE: test/use/find.test.ts
  function makeContext (line 25) | function makeContext() {

FILE: test/use/get.test.ts
  function makeContext (line 36) | function makeContext() {
  class Dohickey (line 161) | class Dohickey extends BaseModel {

FILE: test/utils.test.ts
  type RootState (line 21) | interface RootState {
  class User (line 67) | class User extends BaseModel {
  class User (line 124) | class User extends BaseModel {
  method addServerItem (line 136) | addServerItem(state) {

FILE: test/vue-plugin.test.ts
  type VueWithFeathers (line 17) | interface VueWithFeathers {
  function makeContext (line 21) | function makeContext() {
Condensed preview — 101 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (806K chars).
[
  {
    "path": ".babelrc",
    "chars": 127,
    "preview": "{\n  \"plugins\": [ \"add-module-exports\" ],\n  \"presets\": [\n    [ \"env\", { \"modules\": false } ],\n    \"es2015\",\n    \"stage-2\""
  },
  {
    "path": ".editorconfig",
    "chars": 214,
    "preview": "# http://editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_tr"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 69,
    "preview": "# These are supported funding model platforms\n\ngithub: marshallswain\n"
  },
  {
    "path": ".github/contributing.md",
    "chars": 6444,
    "preview": "# Contributing to Feathers\n\nThank you for contributing to Feathers! :heart: :tada:\n\nThis repo is the main core and where"
  },
  {
    "path": ".github/issue_template.md",
    "chars": 714,
    "preview": "### Steps to reproduce\n\n(First please check that this issue is not already solved as [described\nhere](https://github.com"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 1031,
    "preview": "### Summary\n\n(If you have not already please refer to the contributing guideline as [described\nhere](https://github.com/"
  },
  {
    "path": ".gitignore",
    "chars": 734,
    "preview": ".DS_Store\n\n# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverag"
  },
  {
    "path": ".istanbul.yml",
    "chars": 275,
    "preview": "verbose: false\ninstrumentation:\n  root: ./src/\n  excludes:\n    - lib/\n  include-all-sources: true\nreporting:\n  print: su"
  },
  {
    "path": ".npmignore",
    "chars": 78,
    "preview": ".editorconfig\n.jshintrc\n.travis.yml\n.istanbul.yml\n.babelrc\n.idea/\ntest/\n!lib/\n"
  },
  {
    "path": ".travis.yml",
    "chars": 168,
    "preview": "language: node_js\nnode_js: node\ncache: yarn\naddons:\n  code_climate:\n    repo_token: 'your repo token'\n  firefox: \"51.0\"\n"
  },
  {
    "path": ".vscode/launch.json",
    "chars": 1061,
    "preview": "{\n  // Use IntelliSense to learn about possible Node.js debug attributes.\n  // Hover to view descriptions of existing at"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 9084,
    "preview": "# Change Log\n\n## [v1.0.0-pre.3](https://github.com/feathersjs/feathers-vuex/tree/v1.0.0-pre.3) (2017-08-26)\n[Full Change"
  },
  {
    "path": "LICENSE",
    "chars": 1076,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016 Feathers\n\nPermission is hereby granted, free of charge, to any person obtainin"
  },
  {
    "path": "README.md",
    "chars": 1830,
    "preview": "# Feathers-Vuex\n\n[![Build Status](https://travis-ci.org/feathersjs-ecosystem/feathers-vuex.png?branch=master)](https://t"
  },
  {
    "path": "docs/.vuepress/config.js",
    "chars": 828,
    "preview": "module.exports = {\n  title: 'FeathersVuex',\n  description: 'Integration of FeathersJS, Vue, and Nuxt for the artisan dev"
  },
  {
    "path": "docs/2.0-major-release.md",
    "chars": 24910,
    "preview": "---\ntitle: 2.0 Breaking Changes\nsidebarDepth: 3\n---\n\n# 2.0 Breaking Changes\n\nThe biggest change in Feathers-Vuex 2.0 is "
  },
  {
    "path": "docs/3.0-major-release.md",
    "chars": 6203,
    "preview": "---\ntitle: What's New in 3.0\nsidebarDepth: 3\n---\n\n# What's new in Feathers-Vuex 3.0\n\n## Vue Composition API Support\n\nVer"
  },
  {
    "path": "docs/api-overview.md",
    "chars": 2716,
    "preview": "---\ntitle: API Overview\nsidebarDepth: 3\n---\n\n<!--- Usage ---------------------------------------------------------------"
  },
  {
    "path": "docs/auth-plugin.md",
    "chars": 3060,
    "preview": "---\ntitle: Auth Plugin\n---\n\nThe Auth module assists setting up user login and logout.\n\n## Setup\n\nSee the [Auth Setup](/g"
  },
  {
    "path": "docs/common-patterns.md",
    "chars": 25976,
    "preview": "---\ntitle: Common Patterns\n---\n\n## Set the `idField`\n\nIf you have a \"WTF this isn't working\" moment while setting up a n"
  },
  {
    "path": "docs/composition-api.md",
    "chars": 33713,
    "preview": "---\ntitle: Composition API\nsidebarDepth: 3\n---\n\n# Feathers-Vuex Composition API <Badge text=\"3.0.0+\" />\n\nIn addition to "
  },
  {
    "path": "docs/data-components.md",
    "chars": 22747,
    "preview": "---\ntitle: Renderless Data Components\nsidebarDepth: 3\n---\n\n# Renderless Data Components\n\nThere are three renderless data"
  },
  {
    "path": "docs/example-applications.md",
    "chars": 3496,
    "preview": "---\ntitle: Example Applications\nsidebarDepth: 3\n---\n\n# Example Applications\n\nOn this page you will find any example appl"
  },
  {
    "path": "docs/feathers-vuex-forms.md",
    "chars": 22549,
    "preview": "---\ntitle: Working with Forms\nsidebarDepth: 4\n---\n\n# Working with Forms\n\nThe `FeathersVuexFormWrapper` and `FeathersVuex"
  },
  {
    "path": "docs/feathervuex-in-vuejs3-setup.md",
    "chars": 1394,
    "preview": "# Using Vuejs 3 setup()\nVuejs 3 introduced a new way of passing data from a parent to its child. This is valuable if the"
  },
  {
    "path": "docs/getting-started.md",
    "chars": 12409,
    "preview": "---\ntitle: Getting Started\nsidebarDepth: 3\n---\n\n# Getting Started with Feathers-Vuex\n\n## Installation\n\n```bash\nnpm insta"
  },
  {
    "path": "docs/index.md",
    "chars": 806,
    "preview": "---\nhome: true\nheroImage: https://github.com/feathersjs-ecosystem/feathers-vuex/raw/master/service-logo.png\nheroText: Fe"
  },
  {
    "path": "docs/mixins.md",
    "chars": 28397,
    "preview": "---\ntitle: Mixins\nsidebarDepth: 3\n---\n\n# Mixins\n\n`Feathers-Vuex` mixins provide quick and easy best practices directly i"
  },
  {
    "path": "docs/model-classes.md",
    "chars": 20098,
    "preview": "---\ntitle: Data Modeling\nsidebarDepth: 3\n---\n\n# Data Modeling with Model Classes\n\nFeathers-Vuex 1.0 introduced some ligh"
  },
  {
    "path": "docs/nuxt.md",
    "chars": 9612,
    "preview": "---\ntitle: Nuxt\n---\n\n# Nuxt\n\n### Access `$FeathersVuex` models in Nuxt `asyncData`\n\nIn `feathers-vuex@2.x`, you can get "
  },
  {
    "path": "docs/service-plugin.md",
    "chars": 36431,
    "preview": "---\ntitle: Service Plugin\nsidebarDepth: 3\n---\n\n# Service Plugin\n\n<!-- markdownlint-disable MD002 MD033 MD041 -->\n\nThe `m"
  },
  {
    "path": "docs/vue-plugin.md",
    "chars": 3511,
    "preview": "---\ntitle: Vue Plugin\n---\n\n# The Vue Plugin\n\nThis `feathers-vuex` release includes a Vue plugin which gives all of your "
  },
  {
    "path": "mocha.opts",
    "chars": 52,
    "preview": "--compilers js:babel-core/register\ntest/node.test.js"
  },
  {
    "path": "notes.old.md",
    "chars": 2239,
    "preview": "## Extending the built-in Model classes\n\nIf you desire to extend the built-in Models\n\n**store/index.js:**\n```js\nimport V"
  },
  {
    "path": "package.json",
    "chars": 5604,
    "preview": "{\n  \"name\": \"feathers-vuex\",\n  \"description\": \"FeathersJS, Vue, and Nuxt for the artisan developer\",\n  \"version\": \"3.16."
  },
  {
    "path": "src/FeathersVuexCount.ts",
    "chars": 2921,
    "preview": "import { randomString } from './utils'\n\nexport default {\n  props: {\n    service: {\n      type: String,\n      required: t"
  },
  {
    "path": "src/FeathersVuexFind.ts",
    "chars": 4878,
    "preview": "import { randomString, getQueryInfo } from './utils'\nimport _get from 'lodash/get'\n\nexport default {\n  props: {\n    serv"
  },
  {
    "path": "src/FeathersVuexFormWrapper.ts",
    "chars": 2118,
    "preview": "export default {\n  name: 'FeathersVuexFormWrapper',\n  model: {\n    prop: 'item',\n    event: 'update:item'\n  },\n  props: "
  },
  {
    "path": "src/FeathersVuexGet.ts",
    "chars": 5372,
    "preview": "/* eslint-disable @typescript-eslint/explicit-function-return-type */\nexport default {\n  props: {\n    /**\n     * The pat"
  },
  {
    "path": "src/FeathersVuexInputWrapper.ts",
    "chars": 1344,
    "preview": "import _debounce from 'lodash/debounce'\n\nexport default {\n  name: 'FeathersVuexInputWrapper',\n  props: {\n    item: {\n   "
  },
  {
    "path": "src/FeathersVuexPagination.ts",
    "chars": 3189,
    "preview": "import {\n  h,\n  computed,\n  watch\n} from '@vue/composition-api'\n\nexport default {\n  name: 'FeathersVuexPagination',\n  pr"
  },
  {
    "path": "src/auth-module/auth-module.actions.ts",
    "chars": 2961,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport fastCopy "
  },
  {
    "path": "src/auth-module/auth-module.getters.ts",
    "chars": 642,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nexport default f"
  },
  {
    "path": "src/auth-module/auth-module.mutations.ts",
    "chars": 1278,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { seriali"
  },
  {
    "path": "src/auth-module/auth-module.state.ts",
    "chars": 800,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { AuthSta"
  },
  {
    "path": "src/auth-module/make-auth-plugin.ts",
    "chars": 2214,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { Feather"
  },
  {
    "path": "src/auth-module/types.ts",
    "chars": 290,
    "preview": "export interface AuthState {\n  accessToken: string\n  payload: {}\n  entityIdField: string\n  responseEntityField: string\n\n"
  },
  {
    "path": "src/index.ts",
    "chars": 4143,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport FeathersV"
  },
  {
    "path": "src/make-find-mixin.ts",
    "chars": 10531,
    "preview": "/*\neslint\nno-console: 0,\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\n\n"
  },
  {
    "path": "src/make-get-mixin.ts",
    "chars": 6058,
    "preview": "/*\neslint\nno-console: 0,\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\ni"
  },
  {
    "path": "src/service-module/global-clients.ts",
    "chars": 930,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport _get from"
  },
  {
    "path": "src/service-module/global-models.ts",
    "chars": 1228,
    "preview": "/*\neslint\nno-console: 0,\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\ni"
  },
  {
    "path": "src/service-module/make-base-model.ts",
    "chars": 14695,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport {\n  Feath"
  },
  {
    "path": "src/service-module/make-service-module.ts",
    "chars": 1118,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport _pick fro"
  },
  {
    "path": "src/service-module/make-service-plugin.ts",
    "chars": 4638,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport {\n  Feath"
  },
  {
    "path": "src/service-module/service-module.actions.ts",
    "chars": 10999,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport fastCopy "
  },
  {
    "path": "src/service-module/service-module.events.ts",
    "chars": 3242,
    "preview": "import { getId } from '../utils'\nimport _debounce from 'lodash/debounce'\nimport { globalModels } from './global-models'\n"
  },
  {
    "path": "src/service-module/service-module.getters.ts",
    "chars": 3937,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport sift from"
  },
  {
    "path": "src/service-module/service-module.mutations.ts",
    "chars": 14978,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0,\nno-var: 0\n*/\nimpor"
  },
  {
    "path": "src/service-module/service-module.state.ts",
    "chars": 3242,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\n\nimport _omit fr"
  },
  {
    "path": "src/service-module/types.ts",
    "chars": 10670,
    "preview": "import { Service, Id } from '@feathersjs/feathers'\nimport { Params, Paginated } from '../utils'\nimport { EventEmitter } "
  },
  {
    "path": "src/useFind.ts",
    "chars": 5071,
    "preview": "/*\neslint\n@typescript-eslint/no-explicit-any: 0\n*/\nimport {\n  computed,\n  isRef,\n  reactive,\n  Ref,\n  toRefs,\n  watch\n} "
  },
  {
    "path": "src/useGet.ts",
    "chars": 3215,
    "preview": "/*\neslint\n@typescript-eslint/no-explicit-any: 0\n*/\nimport {\n  reactive,\n  computed,\n  toRefs,\n  isRef,\n  watch,\n  Ref\n} "
  },
  {
    "path": "src/utils.ts",
    "chars": 14558,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport decode fr"
  },
  {
    "path": "src/vue-plugin/vue-plugin.ts",
    "chars": 1447,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport FeathersV"
  },
  {
    "path": "stories/.npmignore",
    "chars": 12,
    "preview": "*.stories.js"
  },
  {
    "path": "stories/FeathersVuexFormWrapper.stories.js",
    "chars": 1035,
    "preview": "/* eslint-disable @typescript-eslint/explicit-function-return-type */\nimport '../../assets/styles/tailwind.postcss'\n\nimp"
  },
  {
    "path": "stories/FeathersVuexInputWrapper.stories.js",
    "chars": 3201,
    "preview": "/* eslint-disable @typescript-eslint/explicit-function-return-type */\nimport FeathersVuexInputWrapper from '../src/Feath"
  },
  {
    "path": "test/auth-module/actions.test.js",
    "chars": 4080,
    "preview": "import assert from 'chai/chai'\nimport setupVuexAuth from '~/src/auth-module/auth-module'\nimport setupVuexService from '~"
  },
  {
    "path": "test/auth-module/auth-module.test.ts",
    "chars": 6979,
    "preview": "/* eslint-disable @typescript-eslint/explicit-function-return-type */\n/* eslint-disable @typescript-eslint/no-explicit-a"
  },
  {
    "path": "test/auth.test.js",
    "chars": 4693,
    "preview": "import { assert } from 'chai'\nimport feathersVuexAuth, { reducer } from '../src/auth'\nimport * as actionTypes from '../s"
  },
  {
    "path": "test/fixtures/fake-data.js",
    "chars": 40852,
    "preview": "export default {\n  users: [\n    {\n      email: 'Richie_Cartwright97@hotmail.com',\n      password: '$2a$13$7BBrmdiWTtm3Gb"
  },
  {
    "path": "test/fixtures/feathers-client.js",
    "chars": 2578,
    "preview": "import feathers from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio-client'\nimport rest from '@feathe"
  },
  {
    "path": "test/fixtures/server.js",
    "chars": 1096,
    "preview": "import feathers from '@feathersjs/feathers'\nimport rest from '@feathersjs/express/rest'\nimport socketio from '@feathersj"
  },
  {
    "path": "test/fixtures/store.js",
    "chars": 246,
    "preview": "import Vue from 'vue'\nimport Vuex from 'vuex'\n\nVue.use(Vuex)\n\nexport default function makeStore() {\n  return new Vuex.St"
  },
  {
    "path": "test/fixtures/todos.js",
    "chars": 230,
    "preview": "export function makeTodos() {\n  return {\n    1: { _id: 1, description: 'Dishes', isComplete: true },\n    2: { _id: 2, de"
  },
  {
    "path": "test/index.test.ts",
    "chars": 922,
    "preview": "import { assert } from 'chai'\nimport * as feathersVuex from '../src/index'\nimport Vue from 'vue'\nimport Vuex from 'vuex'"
  },
  {
    "path": "test/make-find-mixin.test.ts",
    "chars": 4935,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { assert "
  },
  {
    "path": "test/service-module/make-service-plugin.test.ts",
    "chars": 12747,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { assert "
  },
  {
    "path": "test/service-module/misconfigured-client.test.ts",
    "chars": 1155,
    "preview": "/* eslint @typescript-eslint/ban-ts-ignore:0 */\nimport { assert } from 'chai'\nimport feathersVuex from '../../src/index'"
  },
  {
    "path": "test/service-module/model-base.test.ts",
    "chars": 6936,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { assert "
  },
  {
    "path": "test/service-module/model-instance-defaults.test.ts",
    "chars": 14294,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { Service"
  },
  {
    "path": "test/service-module/model-methods.test.ts",
    "chars": 18928,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { Service"
  },
  {
    "path": "test/service-module/model-relationships.test.ts",
    "chars": 14817,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { assert "
  },
  {
    "path": "test/service-module/model-serialize.test.ts",
    "chars": 1431,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { assert "
  },
  {
    "path": "test/service-module/model-temp-ids.test.ts",
    "chars": 19050,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { Service"
  },
  {
    "path": "test/service-module/model-tests.test.ts",
    "chars": 4501,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { assert "
  },
  {
    "path": "test/service-module/service-module.actions.test.ts",
    "chars": 42977,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { Service"
  },
  {
    "path": "test/service-module/service-module.getters.test.ts",
    "chars": 20335,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { assert "
  },
  {
    "path": "test/service-module/service-module.mutations.test.ts",
    "chars": 43524,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { assert "
  },
  {
    "path": "test/service-module/service-module.reinitialization.test.ts",
    "chars": 4069,
    "preview": "import { assert } from 'chai'\nimport Vuex from 'vuex'\nimport { feathersRestClient as feathersClient } from '../fixtures/"
  },
  {
    "path": "test/service-module/service-module.test.ts",
    "chars": 43285,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { Service"
  },
  {
    "path": "test/service-module/types.ts",
    "chars": 927,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nexport interface"
  },
  {
    "path": "test/test-utils.ts",
    "chars": 1843,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { assert "
  },
  {
    "path": "test/use/InstrumentComponent.js",
    "chars": 428,
    "preview": "import useGet from '../../src/useGet'\n\nexport default {\n  name: 'InstrumentComponent',\n  template: '<div id=\"test\"> {{ i"
  },
  {
    "path": "test/use/find.test.ts",
    "chars": 5398,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0,\n@typescript-eslint"
  },
  {
    "path": "test/use/get.test.ts",
    "chars": 4842,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0,\n@typescript-eslint"
  },
  {
    "path": "test/utils.test.ts",
    "chars": 7623,
    "preview": "import { assert } from 'chai'\nimport { AuthState } from '../src/auth-module/types'\nimport { ServiceState } from './servi"
  },
  {
    "path": "test/vue-plugin.test.ts",
    "chars": 1264,
    "preview": "/*\neslint\n@typescript-eslint/explicit-function-return-type: 0,\n@typescript-eslint/no-explicit-any: 0\n*/\nimport { assert "
  },
  {
    "path": "tsconfig.json",
    "chars": 299,
    "preview": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"outDir\": \"dist\",\n  "
  },
  {
    "path": "tsconfig.test.json",
    "chars": 297,
    "preview": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"esModuleInterop\": true,\n    \"outDir\": \"dist\",\n  "
  }
]

About this extraction

This page contains the full source code of the feathersjs-ecosystem/feathers-vuex GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 101 files (756.0 KB), approximately 197.1k tokens, and a symbol index with 340 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!