[
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n    \"env\": {\n        \"browser\": true,\n        \"es6\": true,\n        \"mocha\": true,\n        \"node\": true\n    },\n    \"extends\": [\n        \"plugin:@typescript-eslint/recommended\"\n    ],\n    \"parser\": \"@typescript-eslint/parser\",\n    \"parserOptions\": {\n        \"project\": \"tsconfig.json\",\n        \"sourceType\": \"module\"\n    },\n    \"plugins\": [\n        \"@typescript-eslint\",\n        \"prettier\"\n    ],\n    \"ignorePatterns\": [\"**/lib/\", \"**/dist/\"],\n    \"rules\": {\n        \"prettier/prettier\": \"error\",\n        \"@typescript-eslint/no-explicit-any\": \"off\",\n        \"@typescript-eslint/no-unused-vars\": [\n            \"warn\", // or \"error\"\n            { \n                \"argsIgnorePattern\": \"^_\",\n                \"varsIgnorePattern\": \"^_\",\n                \"caughtErrorsIgnorePattern\": \"^_\",\n                \"ignoreRestSiblings\": true\n            }\n        ]\n    }\n};\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: [daffl, marshallswain]\npatreon: # Replace with a single Patreon username\nopen_collective: #\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\ncustom: # Replace with a single custom sponsorship URL\n"
  },
  {
    "path": ".github/contributing.md",
    "content": "# Contributing to Feathers\n\nThank you for contributing to Feathers! :heart: :tada:\n\nFeathers embraces modularity and is broken up across multiple modules. You can find them all in the `packages/` folder. Most reflect their name on npm. For example, the code for `@feathersjs/feathers` will be in `packages/feathers`, for `@feathersjs/authentication` in `packages/authenticaiton`.\n\n## Report a bug\n\nBefore 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.\n\nIf you haven't found your answer please feel free to join our [Discord server](https://discord.gg/qa8kez8QBx), create an issue on Github, or post on [Stackoverflow](http://stackoverflow.com) using the `feathersjs` tag. We try our best to monitor Stackoverflow but you're likely to get more immediate responses in Discord and Github.\n\nIssues 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**.\n\n## Report a Security Concern\n\nWe 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.\n\nIn 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 [Discord](https://discord.gg/qa8kez8QBx) or email us at <a href=\"mailto:\">hello@feathersjs.com</a> with details and we will respond ASAP.\n\nFor full details refer to our [Security docs](https://docs.feathersjs.com/SECURITY.html).\n\n## Pull Requests\n\nWe :heart: pull requests and we're continually working to make it as easy as possible for people to contribute.\n\nWe prefer small pull requests with minimal code changes. The smaller they are the easier they are to review and merge. A FeathersJS maintainer 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.\n\nAlthough 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, historical knowledge or information regarding the roadmap that the maintainers 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:\n\n**All PRs (except documentation) should be accompanied with tests and pass the linting rules.**\n\n### Code style\n\nBefore running the tests from the `test/` folder `npm test` will run ESlint. You can check your code changes individually by running `npm run lint`.\n\n### Tests\n\n[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.\n\n### Documentation\n\nFeathers documentation is contained in Markdown files in the [docs folder](https://github.com/feathersjs/feathers) of the main repository. To change the documentation submit a pull request to that repo, referencing any other PR if applicable, and the docs will be updated as soon as it is merged.\n\n## Community Contributions\n\nIf you've written something awesome about Feathers, for the Feathers ecosystem, or created an app using Feathers please add it to the [awesome-feathersjs](https://github.com/feathersjs-ecosystem/awesome-feathersjs).\n\nIf you think your module would be a good core `feathersjs` module or [featherjs-ecosystem](https://github.com/feathersjs-ecosystem) module then please contact one of the Feathers maintainers on [Discord](https://discord.gg/qa8kez8QBx) and we can discuss whether it belongs and how to get it there. :beers:\n\n## Contributor Code of Conduct\n\nAs 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.\n\nWe 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.\n\nExamples 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.\n\nProject 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.\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.\n\nThis 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/)\n"
  },
  {
    "path": ".github/issue_template.md",
    "content": "### Steps to reproduce\n\n(First please check that this issue is not already solved as [described\nhere](https://github.com/feathersjs/feathers/blob/dove/.github/contributing.md#report-a-bug) - if it is a general question or suggestion please start a [Discussion](https://github.com/feathersjs/feathers/discussions))\n\n- [ ] Tell us what broke. The more detailed the better.\n- [ ] If you can, please create a simple example that reproduces the issue and link to a gist, jrepo, etc. This makes it much easier for us to debug and issues that have a reproducible example will get higher priority.\n\n### Expected behavior\n\nTell us what should happen\n\n### Actual behavior\n\nTell us what happens instead\n\n### System configuration\n\nTell us about the applicable parts of your setup.\n\n**Module versions** (especially the part that's not working):\n\n**NodeJS version**:\n\n**Operating System**:\n\n**Browser Version**:\n\n**React Native Version**:\n\n**Module Loader**:\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "### Summary\n\n(If you have not already please refer to the contributing guideline as [described\nhere](https://github.com/feathersjs/feathers/blob/dove/.github/contributing.md#pull-requests))\n\n- [ ] Tell us about the problem your pull request is solving.\n- [ ] Are there any open issues that are related to this?\n- [ ] Is this PR dependent on PRs in other repos?\n\nIf so, please mention them to keep the conversations linked together.\n\n### Other Information\n\nIf there's anything else that's important and relevant to your pull\nrequest, mention that information here. This could include\nbenchmarks, or other information.\n\nYour 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.\n\nIf this is a new feature, please remember to add the appropriate documentation in their respective pages in the `docs` folder.\n\nThanks for contributing to Feathers! :heart:\n"
  },
  {
    "path": ".github/workflows/nodejs.yml",
    "content": "name: CI\n\non: [push, pull_request]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [20.x, 22.x]\n\n    services:\n      postgres:\n        image: postgres:latest\n        env:\n          POSTGRES_DB: feathers\n          POSTGRES_PASSWORD: postgres\n          POSTGRES_PORT: 5432\n          POSTGRES_USER: postgres\n        ports:\n          - 5432:5432\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n\n    steps:\n      - uses: actions/checkout@v2\n      - name: Use Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@v1\n        with:\n          node-version: ${{ matrix.node-version }}\n      - run: npm install\n      - run: npm test\n        env:\n          CI: true\n          TEST_DB: postgres\n"
  },
  {
    "path": ".github/workflows/update-dependencies.yml",
    "content": "name: Update dependencies\n\non:\n  schedule:\n    - cron: '0 0 1 * *'\n  workflow_dispatch:\njobs:\n  update-dependencies:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - name: Use Node.js\n        uses: actions/setup-node@v1\n        with:\n          node-version: '18.x'\n      - run: npm ci\n      - run: |\n          git config user.name \"GitHub Actions Bot\"\n          git config user.email \"hello@feathersjs.com\"\n          git checkout -b update-dependencies-$GITHUB_RUN_ID\n      - run: |\n          npm run update-dependencies\n          npm install\n      - run: |\n          git commit -am \"chore(dependencies): Update dependencies\"\n          git push origin update-dependencies-$GITHUB_RUN_ID\n      - run: |\n          gh pr create --title \"chore(dependencies): Update all dependencies\" --body \"\"\n        env:\n          GITHUB_TOKEN: ${{secrets.CI_ACCESS_TOKEN}}\n"
  },
  {
    "path": ".gitignore",
    "content": ".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 jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Compiled binary addons (http://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directory\n# Commenting this out is preferred by some people, see\n# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-\nnode_modules\n.nyc_output\n\n# Users Environment Variables\n.lock-wscript\n\n# IDEs\n.idea\n\n# Distributables\ndist/\n.nyc_output/\n.cache\n\n# TypeScript compiled files\npackages/**/lib\n**/build/*.tgz\n*.sqlite\ndocs/.vitepress/cache"
  },
  {
    "path": ".mocharc.json",
    "content": "{\n  \"timeout\": 30000,\n  \"require\": [\"ts-node/register\", \"source-map-support/register\"],\n  \"reporter\": \"Dot\",\n  \"extension\": \".test.ts\",\n  \"exit\": true\n}\n"
  },
  {
    "path": ".nycrc",
    "content": "{\n  \"verbose\": false,\n  \"tempDirectory\": \"./coverage/.tmp\",\n  \"semistandard\": {\n    \"env\": [\n      \"mocha\"\n    ]\n  },\n  \"extension\": [\n    \".ts\",\n    \".tsx\",\n    \".js\"\n  ],\n  \"exclude\": [\n    \"**/test/*\",\n    \"**/dist/*\",\n    \"**/*.dist.js\",\n    \"**/_templates/*\",\n    \"**/tests/*\",\n    \"**/adapter-tests/*\"\n  ],\n  \"print\": \"detail\",\n  \"reporter\": [\n    \"html\",\n    \"text\",\n    \"text-summary\",\n    \"lcov\"\n  ],\n  \"watermarks\": {\n    \"statements\": [\n      70,\n      90\n    ],\n    \"lines\": [\n      70,\n      90\n    ],\n    \"functions\": [\n      70,\n      90\n    ],\n    \"branches\": [\n      70,\n      90\n    ]\n  }\n}\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"tabWidth\": 2,\n  \"useTabs\": false,\n  \"printWidth\": 110,\n  \"semi\": false,\n  \"trailingComma\": \"none\",\n  \"singleQuote\": true\n}"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- **authentication-oauth:** Fix OAuth Callback Account Takeover ([#3663](https://github.com/feathersjs/feathers/issues/3663)) ([d6b0b5c](https://github.com/feathersjs/feathers/commit/d6b0b5cfbaf6f86a63662027c25616c28e54ede1))\n- **mongodb:** Ensure arbitrary objects can't be passed as MongoDB ids ([#3664](https://github.com/feathersjs/feathers/issues/3664)) ([163e664](https://github.com/feathersjs/feathers/commit/163e664f231a57041034c852b80525fc5c8cf68d))\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n### Bug Fixes\n\n- **client:** Ensure all client methods require valid ids ([#3661](https://github.com/feathersjs/feathers/issues/3661)) ([bc754d3](https://github.com/feathersjs/feathers/commit/bc754d3666b059b9d93799602dac427cb419ddc6))\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n### Bug Fixes\n\n- **oauth:** Patch open redirect and origin validation ([#3653](https://github.com/feathersjs/feathers/issues/3653)) ([ee19a0a](https://github.com/feathersjs/feathers/commit/ee19a0ae9bc2ebf23b1fe598a1f7361981b65401))\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n### Bug Fixes\n\n- Revert to compatible UUID package ([#3630](https://github.com/feathersjs/feathers/issues/3630)) ([5c8c9e3](https://github.com/feathersjs/feathers/commit/5c8c9e36efbbf695eccd6d8822e36e1ea75c1516))\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- @feathersjs/memory update with query ([#3617](https://github.com/feathersjs/feathers/issues/3617)) ([4c6caa2](https://github.com/feathersjs/feathers/commit/4c6caa27e9af1312718d0c233a0c35f7739ac553))\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n- **generators:** typebox generated schema resolver generic ([#3622](https://github.com/feathersjs/feathers/issues/3622)) ([55a4a9b](https://github.com/feathersjs/feathers/commit/55a4a9b6bb021c369fb65b50fa13869311587c3f))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- **knex:** Add support for extended operators in query builder ([#3578](https://github.com/feathersjs/feathers/issues/3578)) ([c355ae3](https://github.com/feathersjs/feathers/commit/c355ae3184f07b15b4a313aa64fb9e7fdd0524d5))\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n- **knex:** Add tableOptions parameter for inheritance on knex adapter options to pass on knex builder ([#3539](https://github.com/feathersjs/feathers/issues/3539)) ([ba5621b](https://github.com/feathersjs/feathers/commit/ba5621bfe5e7ab01189b6b7bccb00891bc2b14c7))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n### Bug Fixes\n\n- **generators:** Add FeathersGeneratorError ([#3556](https://github.com/feathersjs/feathers/issues/3556)) ([2a81a20](https://github.com/feathersjs/feathers/commit/2a81a204eb55c95d20fc45bf091c0131eff5a25d))\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n- **express:** Update express to version 4.21.1 ([#3543](https://github.com/feathersjs/feathers/issues/3543)) ([56d6151](https://github.com/feathersjs/feathers/commit/56d6151624f083d6604e76746cf555ed846b6d40))\n- **mongodb:** Fix mongo count ([#3541](https://github.com/feathersjs/feathers/issues/3541)) ([3e95c7d](https://github.com/feathersjs/feathers/commit/3e95c7df6ae7de6a3a406dfb61dd044ea905456f))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n### Bug Fixes\n\n- **knex:** use driver name to identify client ([#3527](https://github.com/feathersjs/feathers/issues/3527)) ([bb075ec](https://github.com/feathersjs/feathers/commit/bb075ec8beb3ac9b0a1a8aebc3c3756d970cc6a4))\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n### Bug Fixes\n\n- **generators:** Fix generating of gitignore ([#3514](https://github.com/feathersjs/feathers/issues/3514)) ([cabc397](https://github.com/feathersjs/feathers/commit/cabc397d2e4378c4bce79a60f2d196713cce4d8c))\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n### Bug Fixes\n\n- Fix update-dependencies task ([49b9f70](https://github.com/feathersjs/feathers/commit/49b9f70aba1084aa184d9b83c5a8249b793e6a1a))\n- **transport-commons:** Fix HTTP status precedence ([#3511](https://github.com/feathersjs/feathers/issues/3511)) ([5d999a0](https://github.com/feathersjs/feathers/commit/5d999a0acddc0cb7692058209dfbc62673ab5a69))\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n### Bug Fixes\n\n- **authentication-oauth:** Allow POST oauth callbacks ([#3497](https://github.com/feathersjs/feathers/issues/3497)) ([ffcc90b](https://github.com/feathersjs/feathers/commit/ffcc90bb95329cbb4b8f310e37024d417c216d8c))\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n### Bug Fixes\n\n- **adapter-commons:** Faster sorter ([#3495](https://github.com/feathersjs/feathers/issues/3495)) ([22243e4](https://github.com/feathersjs/feathers/commit/22243e4d92edc1a7343b4cf42be6dfb22e8b86d5))\n- **generators:** Fix migrate:make script in generated app ([#3490](https://github.com/feathersjs/feathers/issues/3490)) ([c7b0111](https://github.com/feathersjs/feathers/commit/c7b011150152e62a35f3f8ab04d6dde6d6727583))\n- **mongodb:** Added Update Method Prototype to MongoDBService Class ([#3494](https://github.com/feathersjs/feathers/issues/3494)) ([428f23a](https://github.com/feathersjs/feathers/commit/428f23a8c622cd8bc4d06253206aadd514267846))\n- **mongodb:** MongoDB Aggregation improvements ([#3366](https://github.com/feathersjs/feathers/issues/3366)) ([f2829b1](https://github.com/feathersjs/feathers/commit/f2829b1f8e33d13caae3557d37225d990467fb39))\n- **schema:** Allow regular functions in resolvers ([#3487](https://github.com/feathersjs/feathers/issues/3487)) ([187868e](https://github.com/feathersjs/feathers/commit/187868edd9c0c9d885c482b85be7a90655c86ca2))\n- **typebox:** Add TRecord to getValidator arg1 type ([#3488](https://github.com/feathersjs/feathers/issues/3488)) ([ffbcc0a](https://github.com/feathersjs/feathers/commit/ffbcc0ad0c361f77171f9ad6224006727644433a))\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n### Bug Fixes\n\n- **generators:** better types for enabled methods ([#3474](https://github.com/feathersjs/feathers/issues/3474)) ([bdb3d3a](https://github.com/feathersjs/feathers/commit/bdb3d3a308322bfed3caa4214e4b6a72f1a84944))\n- **knex:** Update committed to boolean type ([#3458](https://github.com/feathersjs/feathers/issues/3458)) ([5fa4dbc](https://github.com/feathersjs/feathers/commit/5fa4dbc06d0126ac18f5643562d0b74f03502caa))\n- **oauth:** Export OAuthService type ([#3479](https://github.com/feathersjs/feathers/issues/3479)) ([e7185cd](https://github.com/feathersjs/feathers/commit/e7185cde63990a0d24a7180c63b61dbc8ef6cd5b))\n- Reduce usage of lodash ([#3455](https://github.com/feathersjs/feathers/issues/3455)) ([8ce807a](https://github.com/feathersjs/feathers/commit/8ce807a5ca53ff5b8d5107a0656c6329404e6e6c))\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n### Bug Fixes\n\n- **generators:** Use module format for JS Knex migrations ([#3444](https://github.com/feathersjs/feathers/issues/3444)) ([3feaa71](https://github.com/feathersjs/feathers/commit/3feaa719443aa30b1121d928ba5b7b8f43837ffb))\n- **socketio:** Handle ackTimeout of socket.io ([#3437](https://github.com/feathersjs/feathers/issues/3437)) ([2642072](https://github.com/feathersjs/feathers/commit/26420721f3eb16f716a9e68ab3ed9f415bab7a9c))\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n- **transport-commons:** Properly delete route data ([#3433](https://github.com/feathersjs/feathers/issues/3433)) ([af01bdb](https://github.com/feathersjs/feathers/commit/af01bdbe050dd428d6fffefa1874e9a6e4182bad))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n### Bug Fixes\n\n- **knex:** Fix Knex adapter date comparison queries ([#3429](https://github.com/feathersjs/feathers/issues/3429)) ([23bafe1](https://github.com/feathersjs/feathers/commit/23bafe1204f79ce2ab0eaaa5544fab1a3ffb5f41))\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package feathers\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n### Bug Fixes\n\n- **generators:** Use cross-platform ES module \\_\\_dirname ([#3402](https://github.com/feathersjs/feathers/issues/3402)) ([0ac4882](https://github.com/feathersjs/feathers/commit/0ac4882663bb6a78622be0d903ae6508ecb516ad))\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n### Bug Fixes\n\n- **cli:** Add JS extension to binaries ([#3398](https://github.com/feathersjs/feathers/issues/3398)) ([aaf181d](https://github.com/feathersjs/feathers/commit/aaf181d924d0cb67c7792a54197082c59109264d))\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n### Bug Fixes\n\n- **cli:** Another fix for CLI ES module loading ([#3397](https://github.com/feathersjs/feathers/issues/3397)) ([3cb3bc9](https://github.com/feathersjs/feathers/commit/3cb3bc9a32602d82193b781b583ed0f37044e778))\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n### Bug Fixes\n\n- **cli:** Fix another ES module issue ([#3395](https://github.com/feathersjs/feathers/issues/3395)) ([8e39884](https://github.com/feathersjs/feathers/commit/8e39884a23d0e7868546dce4f7a3ee6e954c2b31))\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n### Bug Fixes\n\n- Update npm create feathers to ES module ([#3393](https://github.com/feathersjs/feathers/issues/3393)) ([314ce70](https://github.com/feathersjs/feathers/commit/314ce707332eadbea4505e5e7560397632da6205))\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n### Bug Fixes\n\n- **generators:** Move generators and CLI to featherscloud/pinion ([#3386](https://github.com/feathersjs/feathers/issues/3386)) ([eb87c99](https://github.com/feathersjs/feathers/commit/eb87c9922db56c5610e5b808f3ffe033c830e2b2))\n- **knex:** Add sqlite to returning clients ([#3389](https://github.com/feathersjs/feathers/issues/3389)) ([59fb40b](https://github.com/feathersjs/feathers/commit/59fb40b9eb34950ef2dd35b7de4762f224a171f1))\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n### Bug Fixes\n\n- **generators:** Harden mongodb.js to reliably extract database from any connection string ([#3264](https://github.com/feathersjs/feathers/issues/3264)) ([7b0f82c](https://github.com/feathersjs/feathers/commit/7b0f82c631ff5549cdc9a8e0ffcc705d067c2157))\n- **knex:** Add Error Handler to knex \\_update function ([#3371](https://github.com/feathersjs/feathers/issues/3371)) ([210f103](https://github.com/feathersjs/feathers/commit/210f1037bf69c641d4fd335cd4f084cbbac0a922))\n- **schema:** Fix setting dispatch on existing nested objects ([#3380](https://github.com/feathersjs/feathers/issues/3380)) ([04efd5a](https://github.com/feathersjs/feathers/commit/04efd5ab3339beafa0e1a9ef851483a387c6ec96))\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package feathers\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n### Bug Fixes\n\n- allow \\_patch to modify the entire base schema ([#3300](https://github.com/feathersjs/feathers/issues/3300)) ([0f41622](https://github.com/feathersjs/feathers/commit/0f41622307589b3a0b62ac411a73e6a601bda171))\n- **authentication-client:** Allow to abort fetch ([#3310](https://github.com/feathersjs/feathers/issues/3310)) ([ff3e104](https://github.com/feathersjs/feathers/commit/ff3e104b62d02d45261a293aff4e9491241f486f))\n- **express:** Re-export Router ([#3349](https://github.com/feathersjs/feathers/issues/3349)) ([0cbdb03](https://github.com/feathersjs/feathers/commit/0cbdb03a2d810f4855da9b21602c96e4fed7fce5))\n- **generators:** use `export type` vs `export` ([#3246](https://github.com/feathersjs/feathers/issues/3246)) ([82d30fd](https://github.com/feathersjs/feathers/commit/82d30fd37914e61935e068e89fc389f6bf47aaad))\n- **knex:** Add includeTriggerModifications for MSSQL support ([#3355](https://github.com/feathersjs/feathers/issues/3355)) ([cbe44b0](https://github.com/feathersjs/feathers/commit/cbe44b0e91506ab06c86355af67f83d5197bd896))\n- **schema:** Allow $in and $nin queries to work for arrays ([#3352](https://github.com/feathersjs/feathers/issues/3352)) ([677c214](https://github.com/feathersjs/feathers/commit/677c214a353a7f9a1f90649b9bbec4d0d6517a6f))\n- **schema:** Remove undefined $select when using resolveResult hook ([#3354](https://github.com/feathersjs/feathers/issues/3354)) ([c43e009](https://github.com/feathersjs/feathers/commit/c43e009188eb84f98e3f5f29ac4444e6967afc1f))\n- **transport-commons:** Allow case insensitive route lookups ([#3353](https://github.com/feathersjs/feathers/issues/3353)) ([a4a5ab6](https://github.com/feathersjs/feathers/commit/a4a5ab6cb59048176292cd71c04a32aa71ac4642))\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **client:** Replace placeholders in URL with route params ([#3270](https://github.com/feathersjs/feathers/issues/3270)) ([a0624eb](https://github.com/feathersjs/feathers/commit/a0624eb5a7919aa1b179a71beb1c1b9cab574525))\n- **core:** context.path is now typed correctly ([#3303](https://github.com/feathersjs/feathers/issues/3303)) ([ff18b3f](https://github.com/feathersjs/feathers/commit/ff18b3f8b7c8dbc97be588f699d539226785343a))\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n- **memory:** Ensure correct pagination totals ([#3307](https://github.com/feathersjs/feathers/issues/3307)) ([c59e1b8](https://github.com/feathersjs/feathers/commit/c59e1b80cb43571077b035ab2bf0b44f9daa5ab8))\n- **schema:** HookContext is now typed in schema ([#3306](https://github.com/feathersjs/feathers/issues/3306)) ([65fab86](https://github.com/feathersjs/feathers/commit/65fab86407b813122f24db928a59986c7286f270))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n### Bug Fixes\n\n- **authentication-oauth:** Move Grant error handling to the correct spot ([#3297](https://github.com/feathersjs/feathers/issues/3297)) ([e9c0828](https://github.com/feathersjs/feathers/commit/e9c0828937453c3f0a1bd16010089b825185eab6))\n- **schema:** Add typescript as peerDependency ([#3287](https://github.com/feathersjs/feathers/issues/3287)) ([cb562ee](https://github.com/feathersjs/feathers/commit/cb562eeddfa88e34fe5727d4000fa037746b0249))\n- **typebox:** Allow default value in StringEnum ([#3281](https://github.com/feathersjs/feathers/issues/3281)) ([25af09a](https://github.com/feathersjs/feathers/commit/25af09ad065e72768bf88bc8b529b68f2ca4da17))\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n### Bug Fixes\n\n- **authentication-oauth:** Properly handle all oAuth errors ([#3284](https://github.com/feathersjs/feathers/issues/3284)) ([148a9a3](https://github.com/feathersjs/feathers/commit/148a9a319b8e29138fda82d6c03bb489a7b4a6e1))\n- **client:** Add underscored methods to clients ([#3176](https://github.com/feathersjs/feathers/issues/3176)) ([f3c01f7](https://github.com/feathersjs/feathers/commit/f3c01f7b8266bfc642c55b77ba8e5bb333542630))\n- **generators:** Fix configure channels when not real-time app ([#3271](https://github.com/feathersjs/feathers/issues/3271)) ([c619ab2](https://github.com/feathersjs/feathers/commit/c619ab2c57f692c419fee610c269c1502b124852))\n- **typebox:** allow TUnion<TObject[]> inside getValidator ([#3262](https://github.com/feathersjs/feathers/issues/3262)) ([cf9df96](https://github.com/feathersjs/feathers/commit/cf9df96c1011fcf13e9c6d652b06036bb0aac1c3))\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n### Bug Fixes\n\n- add missing word ([#3237](https://github.com/feathersjs/feathers/issues/3237)) ([9a32184](https://github.com/feathersjs/feathers/commit/9a321848767e31176660d6937f8fa6d83ba215bd))\n- **transport-commons:** Handle invalid service paths on socket lookups ([#3241](https://github.com/feathersjs/feathers/issues/3241)) ([c397ab3](https://github.com/feathersjs/feathers/commit/c397ab3a0cd184044ae4f73540549b30a396821c))\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n### Bug Fixes\n\n- **core:** Ensure .service does not access Object properties ([#3235](https://github.com/feathersjs/feathers/issues/3235)) ([c0b670a](https://github.com/feathersjs/feathers/commit/c0b670ac4c7bf145e36b59ea89d1387b5514c237))\n- **generators:** Fix channel/service configuration order for Koa based apps ([580344e](https://github.com/feathersjs/feathers/commit/580344e96fe8a2f17fd53476af5a0c7ddefac0b6))\n- **koa:** Ensure .teardown works without a server ([#3234](https://github.com/feathersjs/feathers/issues/3234)) ([818572d](https://github.com/feathersjs/feathers/commit/818572df98456bc3e1a300e879329aa8f849be64))\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n### Bug Fixes\n\n- **authentication-client:** Do not trigger storage methods if storage not defined ([#3210](https://github.com/feathersjs/feathers/issues/3210)) ([261acbc](https://github.com/feathersjs/feathers/commit/261acbcde387db731e434cb106a27b49dcb64a9a))\n- **authentication-client:** removeAccessToken throws error if storage not defined ([#3195](https://github.com/feathersjs/feathers/issues/3195)) ([b8e2769](https://github.com/feathersjs/feathers/commit/b8e27698f7958a91fe9a4ee64ec5591d23194c44))\n- **authentication-local:** Local Auth - Nested username & Password fields ([#3091](https://github.com/feathersjs/feathers/issues/3091)) ([d135526](https://github.com/feathersjs/feathers/commit/d135526da18ecf2dc620b82820e1d09d8af5c0b5))\n- **authentication-oauth:** Update OAuth redirect to handle user requested redirect paths ([#3186](https://github.com/feathersjs/feathers/issues/3186)) ([3742028](https://github.com/feathersjs/feathers/commit/37420283c17bb8129c6ffdde841ce2034109cc6b))\n- **authentication:** Export JwtVerifyOptions ([#3214](https://github.com/feathersjs/feathers/issues/3214)) ([d59896e](https://github.com/feathersjs/feathers/commit/d59896eb0229f1490c712f19cf84eb2bcf123698))\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n### Bug Fixes\n\n- **generators:** Add sourceMap to tsconfig.json template ([#3166](https://github.com/feathersjs/feathers/issues/3166)) ([3049b7a](https://github.com/feathersjs/feathers/commit/3049b7a425d01cdd3058442c7183307a06cfc87a))\n- **mongodb:** Speed up multi create ([#3171](https://github.com/feathersjs/feathers/issues/3171)) ([e34f728](https://github.com/feathersjs/feathers/commit/e34f728139a1008503aa440f1b7cf6395719417b))\n- **schema:** Exclude json-schema-to-ts@2.8.0 ([#3180](https://github.com/feathersjs/feathers/issues/3180)) ([aee8531](https://github.com/feathersjs/feathers/commit/aee8531b5f0578f11e43b19a469b96e6f4b170ce))\n- **typebox:** Revert to TypeBox 0.25 ([#3183](https://github.com/feathersjs/feathers/issues/3183)) ([cacedf5](https://github.com/feathersjs/feathers/commit/cacedf59e3d2df836777f0cd06ab1b2484ed87c5))\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- **adapter-commons:** Support non-default import to ease use with ESM projects ([d06f2cf](https://github.com/feathersjs/feathers/commit/d06f2cfcadda7dc23f0e2bec44f64e6be8500d02))\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n- **memory:** Fix memory adapter readme ([#3153](https://github.com/feathersjs/feathers/issues/3153)) ([a9d826a](https://github.com/feathersjs/feathers/commit/a9d826a7dbe7df4501fbf82a47d2c3a77ca9e0c0))\n- **typebox:** Implement custom TypeBuilder for backwards compatibility ([#3150](https://github.com/feathersjs/feathers/issues/3150)) ([962bd87](https://github.com/feathersjs/feathers/commit/962bd87217212320b1a68f6556a16b8a6b8f757c))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **authentication:** Ensure authentication.entity configuration can be null ([#3136](https://github.com/feathersjs/feathers/issues/3136)) ([c47349b](https://github.com/feathersjs/feathers/commit/c47349b9dcf2067b7b572c5463b15b2a8fbda972))\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n- **generators:** Properly log unhandled rejection ([#3149](https://github.com/feathersjs/feathers/issues/3149)) ([eda8f78](https://github.com/feathersjs/feathers/commit/eda8f78fa5084c3247ad10b051610b3c51a13d24))\n- **knex:** Ensure that columns are selected unambigiously and avoid duplicate id selection ([#3144](https://github.com/feathersjs/feathers/issues/3144)) ([3eb7428](https://github.com/feathersjs/feathers/commit/3eb7428f888f0e8a0fbc09f5261bff3e68a0ed63))\n- **knex:** Get by id and transactions should work with params.knex ([#3146](https://github.com/feathersjs/feathers/issues/3146)) ([b172b5e](https://github.com/feathersjs/feathers/commit/b172b5ea9b461642874eb7d2ba01dc4cfc275155))\n- **knex:** Only apply default order for MSSQL ([#3145](https://github.com/feathersjs/feathers/issues/3145)) ([28c2627](https://github.com/feathersjs/feathers/commit/28c26279befea6cf43cedd3af628234b170b8c91))\n- **mongodb:** Add MongoDB as peerDependency ([#3148](https://github.com/feathersjs/feathers/issues/3148)) ([0137b40](https://github.com/feathersjs/feathers/commit/0137b40fb694fa95e3b7b7ad41504831b894d977))\n- **typebox:** Upgrade to TypeBox 0.26.0 ([#3113](https://github.com/feathersjs/feathers/issues/3113)) ([d1d9598](https://github.com/feathersjs/feathers/commit/d1d95984dd94d2b9305e7338421f84f9c4f733fd))\n\n## [5.0.2](https://github.com/feathersjs/feathers/compare/v5.0.1...v5.0.2) (2023-03-23)\n\n### Bug Fixes\n\n- **generators:** Make sure TypeScript version in generated app matches ([#3122](https://github.com/feathersjs/feathers/issues/3122)) ([f0acfdf](https://github.com/feathersjs/feathers/commit/f0acfdf9d33337bf40ca12126c2550f56e31fa3b))\n- **socketio-client:** Move core dependency to the right spot ([#3117](https://github.com/feathersjs/feathers/issues/3117)) ([6cd66f1](https://github.com/feathersjs/feathers/commit/6cd66f13e4e668defb57074413846550b147a51d))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n### Bug Fixes\n\n- **core:** Add PaginationParams to general find method ([#3095](https://github.com/feathersjs/feathers/issues/3095)) ([8ebdcf5](https://github.com/feathersjs/feathers/commit/8ebdcf5107fae5fa23920390052b871033de3a0a))\n- **core:** Use Symbol.for to instantiate shared symbols ([#3087](https://github.com/feathersjs/feathers/issues/3087)) ([7f3fc21](https://github.com/feathersjs/feathers/commit/7f3fc2167576f228f8183568eb52b077160e8d65))\n- **generators:** Conditionally import channels in Express app ([#3106](https://github.com/feathersjs/feathers/issues/3106)) ([c2dbaaa](https://github.com/feathersjs/feathers/commit/c2dbaaa4d1d5a5675b5812a7ed2317076ac414fe))\n- **koa:** Replace koa-bodyparser with koa-body ([#3093](https://github.com/feathersjs/feathers/issues/3093)) ([2456bf8](https://github.com/feathersjs/feathers/commit/2456bf882c99ae2cddd1a39bffba7e61217fc055))\n- **memory/mongodb:** $select as only property & force 'id' in '$select' ([#3081](https://github.com/feathersjs/feathers/issues/3081)) ([fbe3cf5](https://github.com/feathersjs/feathers/commit/fbe3cf5199e102b5aeda2ae33828d5034df3d105))\n- **transport-commons:** Fix dispatching of arrays ([#3075](https://github.com/feathersjs/feathers/issues/3075)) ([98fdda5](https://github.com/feathersjs/feathers/commit/98fdda53187acee88137b39662c766cc62cd7b55))\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n### Bug Fixes\n\n- **generators:** Fix typo in service client generator ([#3068](https://github.com/feathersjs/feathers/issues/3068)) ([612032e](https://github.com/feathersjs/feathers/commit/612032eced24ecbcf255d51ff0d537d74227cfd7))\n- **koa:** Make Koa app inspectable ([#3069](https://github.com/feathersjs/feathers/issues/3069)) ([4fbbfff](https://github.com/feathersjs/feathers/commit/4fbbfff2a3c625f8e6929e5a09e2cf7b739ffe11))\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n### Bug Fixes\n\n- **koa:** Fix missing dependency on feathers ([#3061](https://github.com/feathersjs/feathers/issues/3061)) ([80dc95f](https://github.com/feathersjs/feathers/commit/80dc95ff85c9074b8f70e3ff71562f18863ef2be))\n- **schema:** validateQuery - move next function outside of try-catch ([#3053](https://github.com/feathersjs/feathers/issues/3053)) ([37fe5c4](https://github.com/feathersjs/feathers/commit/37fe5c4a4d813867f6d02098b7c77d08786248c7))\n\n### Features\n\n- **generators:** Final tweaks to the generators ([#3060](https://github.com/feathersjs/feathers/issues/3060)) ([1bf1544](https://github.com/feathersjs/feathers/commit/1bf1544fa8deeaa44ba354fb539dc3f1fd187767))\n- **schema:** Add schema helper for handling Object ids ([#3058](https://github.com/feathersjs/feathers/issues/3058)) ([1393bed](https://github.com/feathersjs/feathers/commit/1393bed81a9ee814de6aab0e537af83e667591a2))\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n### Bug Fixes\n\n- **generators:** Add schema selection to CI test matrix ([#3035](https://github.com/feathersjs/feathers/issues/3035)) ([7484b16](https://github.com/feathersjs/feathers/commit/7484b164fba4ac2ee379dc5c6363f964f45e94d3))\n- **generators:** Fix Knex migration generated filename ([#3033](https://github.com/feathersjs/feathers/issues/3033)) ([1ac18a7](https://github.com/feathersjs/feathers/commit/1ac18a7143173d973af982772678834f7a7334f7))\n- **generators:** Generated app does not start when choosing JSON schema ([#3034](https://github.com/feathersjs/feathers/issues/3034)) ([7b8250b](https://github.com/feathersjs/feathers/commit/7b8250bd535c3c5ec7429a65139335ad43616ae0))\n- **knex:** The method getModel in the knex adapter ([#3043](https://github.com/feathersjs/feathers/issues/3043)) ([77e14dd](https://github.com/feathersjs/feathers/commit/77e14dd3f4a29adff8beb805d0e6186ead59e4fe))\n- **schema:** Do not change the hook context in resolvers ([#3048](https://github.com/feathersjs/feathers/issues/3048)) ([bfd8c04](https://github.com/feathersjs/feathers/commit/bfd8c04c15279063a0d4b70771715c656dda5f7c))\n- **schema:** Ensure that resolveResult and resolveExternal are run as around hooks ([#3032](https://github.com/feathersjs/feathers/issues/3032)) ([71942f4](https://github.com/feathersjs/feathers/commit/71942f418e3afe167aef4f98b1a97356dae7625c))\n- **typebox:** Allow nested or in and queries ([#3029](https://github.com/feathersjs/feathers/issues/3029)) ([39e0b78](https://github.com/feathersjs/feathers/commit/39e0b785238b809aa9b4dea9b95efc3c188c9baa))\n\n### Features\n\n- **mongodb:** Add Object ID keyword converter and update MongoDB CLI & docs ([#3041](https://github.com/feathersjs/feathers/issues/3041)) ([ca0994e](https://github.com/feathersjs/feathers/commit/ca0994eaecb5a31f310bc980d106834e11f24f41))\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- **authentication-oauth:** Use original headers in oauth flow ([#3025](https://github.com/feathersjs/feathers/issues/3025)) ([fb3d8cc](https://github.com/feathersjs/feathers/commit/fb3d8cca123d68a77b096bc92e49baa55424afe0))\n- **configuration:** Add pool and connection object to SQL database default configuration ([#3023](https://github.com/feathersjs/feathers/issues/3023)) ([092c749](https://github.com/feathersjs/feathers/commit/092c749d43f7da4d019576d1210fe7d3719a44a2))\n- **databases:** Ensure that query sanitization is not necessary when using query schemas ([#3022](https://github.com/feathersjs/feathers/issues/3022)) ([dbf514e](https://github.com/feathersjs/feathers/commit/dbf514e85d1508b95c007462a39b3cadd4ff391d))\n- **databases:** Improve documentation for adapters and allow dynamic Knex adapter options ([#3019](https://github.com/feathersjs/feathers/issues/3019)) ([66c4b5e](https://github.com/feathersjs/feathers/commit/66c4b5e72000dd03acb57fca1cad4737c85c9c9e))\n- **feathers:** Run after all hooks first, and then after method hooks ([#3004](https://github.com/feathersjs/feathers/issues/3004)) ([3692fd5](https://github.com/feathersjs/feathers/commit/3692fd57f70564492cef8bbaf78d264627a9bf0a))\n- **generators:** Add main schema to all validators ([#2997](https://github.com/feathersjs/feathers/issues/2997)) ([5854dea](https://github.com/feathersjs/feathers/commit/5854dea7f610262121a49623ec5bbd474dcd3ef3))\n- **generators:** Add TypeScript as normal instead of dev dependency ([#3011](https://github.com/feathersjs/feathers/issues/3011)) ([2f67398](https://github.com/feathersjs/feathers/commit/2f673987f38b199e75aff629b7cdfcaebfd69c4c))\n- **generators:** Do not removeAdditional in queries ([#3000](https://github.com/feathersjs/feathers/issues/3000)) ([ef501bc](https://github.com/feathersjs/feathers/commit/ef501bcfa528119168787e9d857f1bb90e0c3114))\n- **schema:** Allow any type in resolver hooks ([#3006](https://github.com/feathersjs/feathers/issues/3006)) ([f01281f](https://github.com/feathersjs/feathers/commit/f01281f7d83262738459585fc3f53f56c0a0deb8))\n- **schema:** Ensure all types of nested data are securely dispatched ([#3005](https://github.com/feathersjs/feathers/issues/3005)) ([e4a9da5](https://github.com/feathersjs/feathers/commit/e4a9da5f3288e8e9f02087754473c7a9dfda6cb1))\n- **schema:** Fix TypeBox extension value query syntax inference ([#3010](https://github.com/feathersjs/feathers/issues/3010)) ([f1c7a76](https://github.com/feathersjs/feathers/commit/f1c7a76586bbb8aed66ef866c3dcd666d79f3a24))\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n### Features\n\n- **database:** Add and to the query syntax ([#3021](https://github.com/feathersjs/feathers/issues/3021)) ([00cb0d9](https://github.com/feathersjs/feathers/commit/00cb0d9c302ae951ae007d3d6ceba33e254edd9c))\n- **generators:** Add service file for shared information ([#3008](https://github.com/feathersjs/feathers/issues/3008)) ([0a1665d](https://github.com/feathersjs/feathers/commit/0a1665d23e002afadb40ed99bf0168f0fceb0054))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Bug Fixes\n\n- **cli:** Add unhandledRejection handler to generated index file ([#2932](https://github.com/feathersjs/feathers/issues/2932)) ([e3cedc8](https://github.com/feathersjs/feathers/commit/e3cedc8e00f52d892f21fd6a3eb4ca4fe40a903c))\n- **cli:** Minor generated app improvements ([#2936](https://github.com/feathersjs/feathers/issues/2936)) ([ba1a550](https://github.com/feathersjs/feathers/commit/ba1a5500a8a5ea4ab44da44ac509e48c723d7efd))\n- **cli:** Properly log validation errors in log-error hook ([54c883c](https://github.com/feathersjs/feathers/commit/54c883c2bb5c35c02b1a2081b2f17554550aa1d4))\n- **cli:** Use correct package manager when installing an app ([#2973](https://github.com/feathersjs/feathers/issues/2973)) ([99c2a70](https://github.com/feathersjs/feathers/commit/99c2a70b77f0b68698a66180b69a56cb20c2ca0d))\n- **databases:** Make sure adapter method signatures are exported properly ([#2943](https://github.com/feathersjs/feathers/issues/2943)) ([458d668](https://github.com/feathersjs/feathers/commit/458d66859e256c5854e7590f0b4a11b233fe0374))\n- **knex:** Ensure custom ids are returned on create ([#2934](https://github.com/feathersjs/feathers/issues/2934)) ([c4fa3cf](https://github.com/feathersjs/feathers/commit/c4fa3cf812d59e6e8e3831ab098bb8768c92e8f4))\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n- **schema:** Allow to add additional operators to the query syntax ([#2941](https://github.com/feathersjs/feathers/issues/2941)) ([f324940](https://github.com/feathersjs/feathers/commit/f324940d5795b41e8c6fc113defb0beb7ab03a0a))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **adapter-commons:** multiple type definition issues ([#2876](https://github.com/feathersjs/feathers/issues/2876)) ([4ff1ed0](https://github.com/feathersjs/feathers/commit/4ff1ed084eb2b2cb687de27a28c96a0dad4530b7))\n- **authentication-client:** Do not cache authentication errors ([#2892](https://github.com/feathersjs/feathers/issues/2892)) ([cc4e767](https://github.com/feathersjs/feathers/commit/cc4e76726fce1ac73252cfd92e22570d4bdeca20))\n- **authentication-client:** Improve socket reauthentication handling ([#2895](https://github.com/feathersjs/feathers/issues/2895)) ([9db5e7a](https://github.com/feathersjs/feathers/commit/9db5e7adb0f6aea43d607f530d8258ade98b7362))\n- **authentication-client:** Remove access token for fatal 400 errors ([#2894](https://github.com/feathersjs/feathers/issues/2894)) ([cfc6c7a](https://github.com/feathersjs/feathers/commit/cfc6c7a6b9dbc7fb60816e2b7f15897c38deb98d))\n- **authentication:** Fix order of connection and login event handling ([#2909](https://github.com/feathersjs/feathers/issues/2909)) ([801a503](https://github.com/feathersjs/feathers/commit/801a503425062e27f2a32b91493b6ffae3822626))\n- **cli:** mongodb connection string for node 17+ ([#2875](https://github.com/feathersjs/feathers/issues/2875)) ([7fa2012](https://github.com/feathersjs/feathers/commit/7fa2012897d8429b522fbca72211fc9be1c25f7e))\n- **core:** `context.type` for around hooks ([#2890](https://github.com/feathersjs/feathers/issues/2890)) ([d606ac6](https://github.com/feathersjs/feathers/commit/d606ac660fd5335c95206784fea36530dd2e851a))\n- **core:** Allow services with no external methods ([#2921](https://github.com/feathersjs/feathers/issues/2921)) ([df56918](https://github.com/feathersjs/feathers/commit/df569183d1a9ed0a9e0ea5bf8d7dab52d326a33d))\n- **core:** Improve service option usage and method option typings ([#2902](https://github.com/feathersjs/feathers/issues/2902)) ([164d75c](https://github.com/feathersjs/feathers/commit/164d75c0f11139a316baa91f1762de8f8eb7da2d))\n- **schema:** Allow query schemas with no properties, error on unsupported types ([#2904](https://github.com/feathersjs/feathers/issues/2904)) ([b66c734](https://github.com/feathersjs/feathers/commit/b66c734357478f51b2d38fa7f3eee08640cea26e))\n- **schema:** Check for undefined value in resolveQueryObjectId resolver ([#2914](https://github.com/feathersjs/feathers/issues/2914)) ([d9449fa](https://github.com/feathersjs/feathers/commit/d9449fa835f58fc9cec5f7254c50219494129140))\n- **socketio:** Disconnect socket on app disconnect event ([#2896](https://github.com/feathersjs/feathers/issues/2896)) ([4ba0039](https://github.com/feathersjs/feathers/commit/4ba003907843cfc2655798a568b16f07ff8adb1b))\n- **typebox:** Improve query syntax defaults ([#2888](https://github.com/feathersjs/feathers/issues/2888)) ([59f3cdc](https://github.com/feathersjs/feathers/commit/59f3cdca6376e34fe39a7b91db837d0325aeb5db))\n\n### Features\n\n- **adapter:** Add patch data type to adapters and refactor AdapterBase usage ([#2906](https://github.com/feathersjs/feathers/issues/2906)) ([9ddc2e6](https://github.com/feathersjs/feathers/commit/9ddc2e6b028f026f939d6af68125847e5c6734b4))\n- **cli:** Use separate patch schema and types ([#2916](https://github.com/feathersjs/feathers/issues/2916)) ([7088af6](https://github.com/feathersjs/feathers/commit/7088af64a539dc7f1a016d832b77b98aaaf92603))\n- **docs:** CLI and application structure guide ([#2818](https://github.com/feathersjs/feathers/issues/2818)) ([142914f](https://github.com/feathersjs/feathers/commit/142914fc001a8420056dd56db992c1c4f1bd312c))\n- **schema:** Split resolver options and property resolvers ([#2889](https://github.com/feathersjs/feathers/issues/2889)) ([4822c94](https://github.com/feathersjs/feathers/commit/4822c949812e5a1dceff3c62b2f9de4781b4d601))\n- **schema:** Virtual property resolvers ([#2900](https://github.com/feathersjs/feathers/issues/2900)) ([7d03b57](https://github.com/feathersjs/feathers/commit/7d03b57ae2f633bdd4a368e0d5955011fbd6c329))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n### Bug Fixes\n\n- **cli:** Fix MongoDB connection database name parsing ([#2845](https://github.com/feathersjs/feathers/issues/2845)) ([50e7463](https://github.com/feathersjs/feathers/commit/50e7463971ef95cb98358b70a721e67554d92eb5))\n- **cli:** Use proper MSSQL client ([#2853](https://github.com/feathersjs/feathers/issues/2853)) ([bae5176](https://github.com/feathersjs/feathers/commit/bae5176488b46fc377e53719d20e0036e087aa16))\n- **docs:** Add JavaScript web app frontend guide ([#2834](https://github.com/feathersjs/feathers/issues/2834)) ([68cf03f](https://github.com/feathersjs/feathers/commit/68cf03f092da38ccbec5e9fd42b95d00f5a0a9f2))\n- **memory:** Use for loop in \\_find() for better performance ([#2844](https://github.com/feathersjs/feathers/issues/2844)) ([d6ee5f1](https://github.com/feathersjs/feathers/commit/d6ee5f1c869f0c65cb470130f35956a52356e5c3))\n\n### Features\n\n- **docs:** Add Awesome Ecosystem page ([f66177d](https://github.com/feathersjs/feathers/commit/f66177ded1f48ac45a7105f73c5c3cda7084c7b1))\n- **mongodb:** Add ObjectId resolvers and MongoDB option in the guide ([#2847](https://github.com/feathersjs/feathers/issues/2847)) ([c5c1fba](https://github.com/feathersjs/feathers/commit/c5c1fba5718a63412075cd3838b86b889eb0bd48))\n- **schema:** Add StringEnum to TypeBox module ([#2827](https://github.com/feathersjs/feathers/issues/2827)) ([65d3665](https://github.com/feathersjs/feathers/commit/65d36656f50a48f633fa3fcabaea10521d04bf1c))\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n### Bug Fixes\n\n- **authentication:** Improve logout and disconnect connection handling ([#2813](https://github.com/feathersjs/feathers/issues/2813)) ([dd77379](https://github.com/feathersjs/feathers/commit/dd77379d8bdcd32d529bef912e672639e4899823))\n- **cli:** Ensure code injection points are not code style dependent ([#2832](https://github.com/feathersjs/feathers/issues/2832)) ([0776e26](https://github.com/feathersjs/feathers/commit/0776e26bfe4c1df9d2786499941bd3faba1715c0))\n- **cli:** Only generate authentication setup when selected ([#2823](https://github.com/feathersjs/feathers/issues/2823)) ([7d219d9](https://github.com/feathersjs/feathers/commit/7d219d9c5269267b50f3ce99a5653d645f9927c1))\n- **docs:** Review transport API docs and update Express middleware setup ([#2811](https://github.com/feathersjs/feathers/issues/2811)) ([1b97f14](https://github.com/feathersjs/feathers/commit/1b97f14d474f5613482f259eeaa585c24fcfab43))\n- **schema:** Improve resolver performance ([#2822](https://github.com/feathersjs/feathers/issues/2822)) ([5fa900f](https://github.com/feathersjs/feathers/commit/5fa900f90d55859332c90283dddddab26ae3759c))\n- **schema:** Use the same options for resolveData hook ([#2833](https://github.com/feathersjs/feathers/issues/2833)) ([ed3b050](https://github.com/feathersjs/feathers/commit/ed3b05051db6886729d4824825ca8f00c2459af7))\n- **transports:** Add remaining middleware for generated apps to Koa and Express ([#2796](https://github.com/feathersjs/feathers/issues/2796)) ([0d5781a](https://github.com/feathersjs/feathers/commit/0d5781a5c72a0cbb2ec8211bfa099f0aefe115a2))\n\n### Features\n\n- **cli:** Add authentication client to generated client ([#2801](https://github.com/feathersjs/feathers/issues/2801)) ([bd59f91](https://github.com/feathersjs/feathers/commit/bd59f91b45a01c2eea0c4386e567f4de5aa6ad99))\n- **docs:** New website and documentation pages ([#2802](https://github.com/feathersjs/feathers/issues/2802)) ([ae85fa2](https://github.com/feathersjs/feathers/commit/ae85fa216f12f7ff5d15e7039640e27a09989ea4))\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n### Bug Fixes\n\n- **errors:** Allows to pass no error message ([#2794](https://github.com/feathersjs/feathers/issues/2794)) ([f3ddab6](https://github.com/feathersjs/feathers/commit/f3ddab637e269e67e852ffce07b060bab2b085c0))\n- **koa:** Only set error code for Feathers errors ([#2793](https://github.com/feathersjs/feathers/issues/2793)) ([d3ee41e](https://github.com/feathersjs/feathers/commit/d3ee41e27b0ea5d29b344d6584ab03e48d16e2b4))\n\n### Features\n\n- **cli:** Generate full client test suite and improve typed client ([#2788](https://github.com/feathersjs/feathers/issues/2788)) ([57119b6](https://github.com/feathersjs/feathers/commit/57119b6bb2797f7297cf054268a248c093ecd538))\n- **cli:** Improve generated schema definitions ([#2783](https://github.com/feathersjs/feathers/issues/2783)) ([474a9fd](https://github.com/feathersjs/feathers/commit/474a9fda2107e9bcf357746320a8e00cda8182b6))\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Bug Fixes\n\n- **authentication-oauth:** Fix regression with prefix handling in OAuth ([#2773](https://github.com/feathersjs/feathers/issues/2773)) ([b1844b1](https://github.com/feathersjs/feathers/commit/b1844b1f27feeb7e66920ec9e318872857711834))\n- **core:** Ensure setup and teardown can be overriden and maintain hook functionality ([#2779](https://github.com/feathersjs/feathers/issues/2779)) ([ab580cb](https://github.com/feathersjs/feathers/commit/ab580cbcaa68d19144d86798c13bf564f9d424a6))\n\n### Features\n\n- **cli:** Add ability to `npm init feathers` ([#2755](https://github.com/feathersjs/feathers/issues/2755)) ([d734931](https://github.com/feathersjs/feathers/commit/d734931ffd4f983a05d9e771ce0e43b696c2bc0e))\n- **cli:** Improve CLI interface ([#2753](https://github.com/feathersjs/feathers/issues/2753)) ([c7e1b7e](https://github.com/feathersjs/feathers/commit/c7e1b7e80aacb84441908c3d73512d9cf7557f7e))\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n- **schema:** Make schemas validation library independent and add TypeBox support ([#2772](https://github.com/feathersjs/feathers/issues/2772)) ([44172d9](https://github.com/feathersjs/feathers/commit/44172d99b566d11d9ceda04f1d0bf72b6d05ce76))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n### Bug Fixes\n\n- **authentication-oauth:** Fix oAuth origin and error handling ([#2752](https://github.com/feathersjs/feathers/issues/2752)) ([f7e1c33](https://github.com/feathersjs/feathers/commit/f7e1c33de1b7af0672a302d2ba6e15d997f0aa83))\n- **schema:** Fix for Ajv global collision bug [#2681](https://github.com/feathersjs/feathers/issues/2681) ([#2702](https://github.com/feathersjs/feathers/issues/2702)) ([0b2def6](https://github.com/feathersjs/feathers/commit/0b2def6ca483fad6ca22fcc4ea9873bc027925d8))\n- **socketio:** Reinitialize hooks on overriden setup method ([#2722](https://github.com/feathersjs/feathers/issues/2722)) ([5e8e7c4](https://github.com/feathersjs/feathers/commit/5e8e7c442238fdc929a0a36b8b8ca2b230ce761f))\n\n### Features\n\n- Add CORS support to oAuth, Express, Koa and generated application ([#2744](https://github.com/feathersjs/feathers/issues/2744)) ([fd218f2](https://github.com/feathersjs/feathers/commit/fd218f289f8ca4c101e9938e8683e2efef6e8131))\n- **authentication-oauth:** Koa and transport independent oAuth authentication ([#2737](https://github.com/feathersjs/feathers/issues/2737)) ([9231525](https://github.com/feathersjs/feathers/commit/9231525a24bb790ba9c5d940f2867a9c727691c9))\n- **cli:** Add custom environment variable support to generated application ([#2751](https://github.com/feathersjs/feathers/issues/2751)) ([c7bf80d](https://github.com/feathersjs/feathers/commit/c7bf80d82c28c190e3f0136d51af5b7de1bc4868))\n- **cli:** Adding ClientService to CLI ([#2750](https://github.com/feathersjs/feathers/issues/2750)) ([1d45427](https://github.com/feathersjs/feathers/commit/1d45427988521ac028755cbe128685fcdf34f636))\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **authentication-client:** Properly handle missing token error ([#2700](https://github.com/feathersjs/feathers/issues/2700)) ([160746e](https://github.com/feathersjs/feathers/commit/160746e2bceb465fd1b6a003415f8ab38daba521))\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n- **core:** Get hooks to work reliably with custom methods ([#2714](https://github.com/feathersjs/feathers/issues/2714)) ([8d7e04a](https://github.com/feathersjs/feathers/commit/8d7e04acd0f0e2af9f4c13efee652d296dd3bc51))\n- **knex:** Fix PostgreSQL integration issues and run CI tests against pg ([#2698](https://github.com/feathersjs/feathers/issues/2698)) ([1f71d78](https://github.com/feathersjs/feathers/commit/1f71d7884656c1494004931f4979ad59d23e4ee6))\n- **mongodb:** Ensure transactions are used properly in create ([#2699](https://github.com/feathersjs/feathers/issues/2699)) ([fe22615](https://github.com/feathersjs/feathers/commit/fe22615b7fa17d3c20ac26d6f82097917c9b63f6))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n### Bug Fixes\n\n- **authentication-client:** Ensure reAuthenticate works in parallel with other requests ([#2690](https://github.com/feathersjs/feathers/issues/2690)) ([41b3761](https://github.com/feathersjs/feathers/commit/41b376106b47e2f40a8914db7a5ed2935e070c08))\n- **cli:** Fix flaky authentication migration and SQL id schema types ([#2676](https://github.com/feathersjs/feathers/issues/2676)) ([04ce9a5](https://github.com/feathersjs/feathers/commit/04ce9a53f4226cd6283f9dc241876e90ddf48618))\n- Freeze the resolver context ([#2685](https://github.com/feathersjs/feathers/issues/2685)) ([247dccb](https://github.com/feathersjs/feathers/commit/247dccb2eb72551962030321cb1c0ecb11b0181e))\n- **socketio-client:** Make Socket.io client event target compatible ([#2686](https://github.com/feathersjs/feathers/issues/2686)) ([716c49a](https://github.com/feathersjs/feathers/commit/716c49a270e4be5e5276192092c292f72ffcfa19))\n\n### Features\n\n- **cli:** Add support for Prettier ([#2684](https://github.com/feathersjs/feathers/issues/2684)) ([83aa8f9](https://github.com/feathersjs/feathers/commit/83aa8f9f212cb122d831dca8858852b0ac9b4da8))\n- **cli:** Improve generated application folder structure ([#2678](https://github.com/feathersjs/feathers/issues/2678)) ([d114557](https://github.com/feathersjs/feathers/commit/d114557721e73d6302aa88c11e3726dbcbd5c92b))\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n### Bug Fixes\n\n- **cli:** Fix compilation folders that got mixed up ([fc4cb74](https://github.com/feathersjs/feathers/commit/fc4cb742f7f9164096d9319b13dfaaa5f54686a6))\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n### Bug Fixes\n\n- **cli:** Generator fixes to work with the new guide ([#2674](https://github.com/feathersjs/feathers/issues/2674)) ([b773fa5](https://github.com/feathersjs/feathers/commit/b773fa5dbd7ff450cfb2f7b93e64882592262712))\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Bug Fixes\n\n- **authentication-oauth:** Fix bug and properly set Grant defaults ([#2659](https://github.com/feathersjs/feathers/issues/2659)) ([cb93bb9](https://github.com/feathersjs/feathers/commit/cb93bb911fd92282424da2db805cd685b7e4a45b))\n- **authentication:** Add safe dispatch data for authentication requests ([#2662](https://github.com/feathersjs/feathers/issues/2662)) ([d8104a1](https://github.com/feathersjs/feathers/commit/d8104a19ee9181e6a5ea81014af29ff9a3c28a8a))\n- **schema:** Fix dispatch resolver hook to convert actually resolved data ([#2663](https://github.com/feathersjs/feathers/issues/2663)) ([f7e87db](https://github.com/feathersjs/feathers/commit/f7e87dbb9a0bc8d89aee47318dddbaa4d6ba5b91))\n\n### Features\n\n- **authentication-local:** Add passwordHash property resolver ([#2660](https://github.com/feathersjs/feathers/issues/2660)) ([b41279b](https://github.com/feathersjs/feathers/commit/b41279b55eea3771a6fa4983a37be2413287bbc6))\n- **cli:** Add generators for new Knex SQL database adapter ([#2673](https://github.com/feathersjs/feathers/issues/2673)) ([0fb2c0f](https://github.com/feathersjs/feathers/commit/0fb2c0f629116f71184b8698c383af8cfd149688))\n- **cli:** Add hook generator ([#2667](https://github.com/feathersjs/feathers/issues/2667)) ([24e4bc0](https://github.com/feathersjs/feathers/commit/24e4bc04a67fadee0e6a96a8389d788faba5c305))\n- **cli:** Add support for JavaScript to the new CLI ([#2668](https://github.com/feathersjs/feathers/issues/2668)) ([ebac587](https://github.com/feathersjs/feathers/commit/ebac587f7d00dc7607c3f546352d79f79b89a5d4))\n- **cli:** Add typed client to a generated app ([#2669](https://github.com/feathersjs/feathers/issues/2669)) ([5b801b5](https://github.com/feathersjs/feathers/commit/5b801b5017ddc3eaa95622b539f51d605916bc86))\n- **cli:** Initial Feathers v5 CLI and Pinion generator ([#2578](https://github.com/feathersjs/feathers/issues/2578)) ([7f59ae7](https://github.com/feathersjs/feathers/commit/7f59ae7f1471895ba8a82aa4702f1a23f71b7682))\n- **knex:** Add KnexJS SQL database adapter to core ([#2671](https://github.com/feathersjs/feathers/issues/2671)) ([9380fff](https://github.com/feathersjs/feathers/commit/9380fff58596e8bb90b8bb098d2795b7eadfec20))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n### Bug Fixes\n\n- **express:** Ensure Express options can be set before configuring REST transport ([#2655](https://github.com/feathersjs/feathers/issues/2655)) ([c9b8f74](https://github.com/feathersjs/feathers/commit/c9b8f74a0196acb99be44ac5e0fff3f1128288cd))\n- **schema:** Always resolve dispatch in resolveAll and add getDispatch method ([#2645](https://github.com/feathersjs/feathers/issues/2645)) ([145b366](https://github.com/feathersjs/feathers/commit/145b366435695438fbc8db9fdb161162ca9049ad))\n- **schema:** remove `default` from queryProperty schemas ([#2646](https://github.com/feathersjs/feathers/issues/2646)) ([940a2b6](https://github.com/feathersjs/feathers/commit/940a2b6868d2f77f81edb1661f6417ec2ea6e372))\n\n### Features\n\n- **client:** Improve client side custom method support ([#2654](https://github.com/feathersjs/feathers/issues/2654)) ([c138acf](https://github.com/feathersjs/feathers/commit/c138acf50affbe6b66177d084d3c7a3e9220f09f))\n- **core:** Rename async hooks to around hooks, allow usual registration format ([#2652](https://github.com/feathersjs/feathers/issues/2652)) ([2a485a0](https://github.com/feathersjs/feathers/commit/2a485a07929184261f27437fc0fdfe5a44694834))\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n### Bug Fixes\n\n- **schema:** Allows resolveData with different resolvers based on method ([#2644](https://github.com/feathersjs/feathers/issues/2644)) ([be71fa2](https://github.com/feathersjs/feathers/commit/be71fa2fe260e05b7dcc0d5f439e33f2e9ec2434))\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n### Bug Fixes\n\n- **authentication-oauth:** Fix regression using incorrect callback and redirect_uri ([#2631](https://github.com/feathersjs/feathers/issues/2631)) ([43d8a08](https://github.com/feathersjs/feathers/commit/43d8a082d7e1807f8a431c44a1dbd9b04c3af0d2))\n- **core:** Do not throw missing method error for regular hook methods ([#2636](https://github.com/feathersjs/feathers/issues/2636)) ([afe9a3b](https://github.com/feathersjs/feathers/commit/afe9a3b3d49897eff045ee237ca2937a6b975291))\n- **schema:** Add Combine helper to allow merging schema types that use ([#2637](https://github.com/feathersjs/feathers/issues/2637)) ([06d03e9](https://github.com/feathersjs/feathers/commit/06d03e91abb1347576c2351c12322d01c58473e5))\n- **typescript:** Make additional types generic to work with extended types ([#2625](https://github.com/feathersjs/feathers/issues/2625)) ([269fdec](https://github.com/feathersjs/feathers/commit/269fdecc5961092dc8608b3cbe16f433c80bfa96))\n\n### Features\n\n- **schema:** Add resolveAll hook ([#2643](https://github.com/feathersjs/feathers/issues/2643)) ([85527d7](https://github.com/feathersjs/feathers/commit/85527d71cb78852880696e5d96abdcdf24593934))\n- **schema:** Add resolver for safe external data dispatching ([#2641](https://github.com/feathersjs/feathers/issues/2641)) ([72b980e](https://github.com/feathersjs/feathers/commit/72b980e05631136d30c8f1468dee45ec6a8d2503))\n- **schema:** Add schema resolver converter functionality ([#2640](https://github.com/feathersjs/feathers/issues/2640)) ([26d9e05](https://github.com/feathersjs/feathers/commit/26d9e05327d6e0144466cd57d6fcc11ac7ecb06a))\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **authentication-oauth:** Don't send origins in Grant's config, as it will be considered another provider ([#2617](https://github.com/feathersjs/feathers/issues/2617)) ([ae3dddd](https://github.com/feathersjs/feathers/commit/ae3dddd8a654924465512d56b4651413912c6932))\n- **configuration:** Only validate the initial configuration against the schema ([#2622](https://github.com/feathersjs/feathers/issues/2622)) ([386c5e2](https://github.com/feathersjs/feathers/commit/386c5e2e67bfad4fb4333f2e3e17f7d7e09ac27e))\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n### Features\n\n- **schema:** Add querySyntax helper to create full query schemas ([#2621](https://github.com/feathersjs/feathers/issues/2621)) ([2bbb103](https://github.com/feathersjs/feathers/commit/2bbb103b2f3e30fb0fff935f92ad3276a1a67e41))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Bug Fixes\n\n- **adapter-commons:** Clarify adapter query filtering ([#2607](https://github.com/feathersjs/feathers/issues/2607)) ([2dac771](https://github.com/feathersjs/feathers/commit/2dac771b0a3298d6dd25994d05186701b0617718))\n- **adapter-tests:** Ensure multi tests can run standalone ([#2608](https://github.com/feathersjs/feathers/issues/2608)) ([d7243f2](https://github.com/feathersjs/feathers/commit/d7243f20e84d9dde428ad8dfc7f48388ca569e6e))\n- **authentication-oauth:** Fix issue with overriding the default Grant configuration ([#2615](https://github.com/feathersjs/feathers/issues/2615)) ([b345857](https://github.com/feathersjs/feathers/commit/b3458578532f9750de2940aeb8afdc75cb0b46f2))\n- **authentication-oauth:** Make oAuth authentication work with cookie-session ([#2614](https://github.com/feathersjs/feathers/issues/2614)) ([9f10bfc](https://github.com/feathersjs/feathers/commit/9f10bfc75083d5bcabea77cfb385aa3965cdf6d6))\n- **client:** Fix @feathersjs/client types field ([#2596](https://github.com/feathersjs/feathers/issues/2596)) ([d719f54](https://github.com/feathersjs/feathers/commit/d719f54daee63daf9ed5cc762626ca15131086de))\n- **express:** Fix typo in types reference in package.json ([#2613](https://github.com/feathersjs/feathers/issues/2613)) ([eacf1b3](https://github.com/feathersjs/feathers/commit/eacf1b3474e6d9da69b8671244c23a75cff87d95))\n- **transport-commons:** Ensure socket queries are always plain objects ([#2597](https://github.com/feathersjs/feathers/issues/2597)) ([97313e1](https://github.com/feathersjs/feathers/commit/97313e121cfee4199f10012e95b8507557aa507e))\n\n### Features\n\n- **mongodb:** Add feathers-mongodb adapter as @feathersjs/mongodb ([#2610](https://github.com/feathersjs/feathers/issues/2610)) ([6d43734](https://github.com/feathersjs/feathers/commit/6d43734a53db02c435cafc52a22dca414e5d0940))\n- **schema:** Allow hooks to run resolvers in sequence ([#2609](https://github.com/feathersjs/feathers/issues/2609)) ([d85c507](https://github.com/feathersjs/feathers/commit/d85c507c76d07e48fc8e7e28ff7de0ef435e0ef8))\n- **typescript:** Improve adapter typings ([#2605](https://github.com/feathersjs/feathers/issues/2605)) ([3b2ca0a](https://github.com/feathersjs/feathers/commit/3b2ca0a6a8e03e8390272c4d7e930b4bffdaacf5))\n- **typescript:** Improve params and query typeability ([#2600](https://github.com/feathersjs/feathers/issues/2600)) ([df28b76](https://github.com/feathersjs/feathers/commit/df28b7619161f1df5e700326f52cca1a92dc5d28))\n\n### BREAKING CHANGES\n\n- **adapter-commons:** Changes the common adapter base class to use `sanitizeQuery` and `sanitizeData`\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n### Bug Fixes\n\n- **adapter-tests:** Add tests for pagination in multi updates ([#2472](https://github.com/feathersjs/feathers/issues/2472)) ([98a811a](https://github.com/feathersjs/feathers/commit/98a811ac605575ff812a08d0504729a5efe7a69c))\n- **core:** Ensure that dynamically registered services are always set up ([#2593](https://github.com/feathersjs/feathers/issues/2593)) ([27cc7d0](https://github.com/feathersjs/feathers/commit/27cc7d08321861cd69e6b66e1fdfa43c50664820))\n- **schema:** result resolver correctly resolves paginated find result ([#2594](https://github.com/feathersjs/feathers/issues/2594)) ([6511e45](https://github.com/feathersjs/feathers/commit/6511e45bd0624f1a629530719709f4b27fecbe0b))\n\n### Features\n\n- **authentication:** Add setup method for auth strategies ([#1611](https://github.com/feathersjs/feathers/issues/1611)) ([a3c3581](https://github.com/feathersjs/feathers/commit/a3c35814dccdbbf6de96f04f60b226ce206c6dbe))\n- **configuration:** Allow app configuration to be validated against a schema ([#2590](https://github.com/feathersjs/feathers/issues/2590)) ([a268f86](https://github.com/feathersjs/feathers/commit/a268f86da92a8ada14ed11ab456aac0a4bba5bb0))\n- **core:** Add app.setup and app.teardown hook support ([#2585](https://github.com/feathersjs/feathers/issues/2585)) ([ae4ebee](https://github.com/feathersjs/feathers/commit/ae4ebee5d39957651473007c4d3adb210160e040))\n- **core:** Add app.teardown functionality ([#2570](https://github.com/feathersjs/feathers/issues/2570)) ([fcdf524](https://github.com/feathersjs/feathers/commit/fcdf524ae1995bb59265d39f12e98b7794bed023))\n- **core:** Finalize app.teardown() functionality ([#2584](https://github.com/feathersjs/feathers/issues/2584)) ([1a166f3](https://github.com/feathersjs/feathers/commit/1a166f3ded811ecacf0ae8cb67880bc9fa2eeafa))\n- **transport-commons:** add `context.http.response` ([#2524](https://github.com/feathersjs/feathers/issues/2524)) ([5bc9d44](https://github.com/feathersjs/feathers/commit/5bc9d447043c2e2b742c73ed28ecf3b3264dd9e5))\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n### Bug Fixes\n\n- **express:** Fix application typings to work with typed configuration ([#2539](https://github.com/feathersjs/feathers/issues/2539)) ([b9dfaee](https://github.com/feathersjs/feathers/commit/b9dfaee834b13864c1ed4f2f6a244eb5bb70395b))\n- **hooks:** Allow all built-in hooks to be used the async and regular way ([#2559](https://github.com/feathersjs/feathers/issues/2559)) ([8f9f631](https://github.com/feathersjs/feathers/commit/8f9f631e0ce89de349207db72def84e7ab496a4a))\n- **queryProperty:** allow compound oneOf ([#2545](https://github.com/feathersjs/feathers/issues/2545)) ([3077d2d](https://github.com/feathersjs/feathers/commit/3077d2d896a38d579ce4d5b530e21ad332bcf221))\n- **schema:** Properly handle resolver errors ([#2540](https://github.com/feathersjs/feathers/issues/2540)) ([31fbdff](https://github.com/feathersjs/feathers/commit/31fbdff8bd848ac7e0eda56e307ac34b1bfcf17f))\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n### Bug Fixes\n\n- **authentication-oauth:** OAuth redirect lost sometimes due to session store race ([#2514](https://github.com/feathersjs/feathers/issues/2514)) ([#2515](https://github.com/feathersjs/feathers/issues/2515)) ([6109c44](https://github.com/feathersjs/feathers/commit/6109c44428c6b8f6bb4e089be760ea1a4ef3d01e))\n- **schema:** Do not error for schemas without properties ([#2519](https://github.com/feathersjs/feathers/issues/2519)) ([96fdb47](https://github.com/feathersjs/feathers/commit/96fdb47d45fd88a8039aa9cc9ec8aebd98672b95))\n- **schema:** Fix resolver data type and use new validation feature in test fixture ([#2523](https://github.com/feathersjs/feathers/issues/2523)) ([1093f12](https://github.com/feathersjs/feathers/commit/1093f124b60524cbd9050fcf07ddaf1d558973da))\n\n### Features\n\n- **express, koa:** make transports similar ([#2486](https://github.com/feathersjs/feathers/issues/2486)) ([26aa937](https://github.com/feathersjs/feathers/commit/26aa937c114fb8596dfefc599b1f53cead69c159))\n- **schema:** Allow to use custom AJV and test with ajv-formats ([#2513](https://github.com/feathersjs/feathers/issues/2513)) ([ecfa4df](https://github.com/feathersjs/feathers/commit/ecfa4df29f029f6ca8517cacf518c14b46ffeb4e))\n- **schema:** Improve schema typing, validation and extensibility ([#2521](https://github.com/feathersjs/feathers/issues/2521)) ([8c1b350](https://github.com/feathersjs/feathers/commit/8c1b35052792e82d13be03c06583534284fbae82))\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **adapter-commons:** clean up in sort.ts and select function ([#2492](https://github.com/feathersjs/feathers/issues/2492)) ([c3ec8a4](https://github.com/feathersjs/feathers/commit/c3ec8a418bdc85506e3c5100015720a45454d8d3))\n- **adapter-commons:** Fix sorting for embedded objects ([#2488](https://github.com/feathersjs/feathers/issues/2488)) ([9c22f70](https://github.com/feathersjs/feathers/commit/9c22f70a838cb6341775d91705a7527c8fc5590e))\n- missing express types for Request, Response ([#2498](https://github.com/feathersjs/feathers/issues/2498)) ([ee67131](https://github.com/feathersjs/feathers/commit/ee67131bbaa24c54d3d781bdf8820015759ac488))\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n### Features\n\n- **authentication-oauth:** Allow dynamic oAuth redirect ([#2469](https://github.com/feathersjs/feathers/issues/2469)) ([b7143d4](https://github.com/feathersjs/feathers/commit/b7143d4c0fbe961e714f79512be04449b9bbd7d9))\n- **core:** add `context.http` and move `statusCode` there ([#2496](https://github.com/feathersjs/feathers/issues/2496)) ([b701bf7](https://github.com/feathersjs/feathers/commit/b701bf77fb83048aa1dffa492b3d77dd53f7b72b))\n- **core:** Improve legacy hooks integration ([08c8b40](https://github.com/feathersjs/feathers/commit/08c8b40999bf3889c61a4d4fad97a2c4f78bafc9))\n- **transport-commons:** Ability to register routes with custom params ([#2482](https://github.com/feathersjs/feathers/issues/2482)) ([497990a](https://github.com/feathersjs/feathers/commit/497990ae4a980e5a52a1f0f932db12cd0e6e254a))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package feathers\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package feathers\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package feathers\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n### Bug Fixes\n\n- **core:** Allow to return a new hook context in basic hooks ([#2462](https://github.com/feathersjs/feathers/issues/2462)) ([422b6fc](https://github.com/feathersjs/feathers/commit/422b6fc11cf9e42f4234f0823a0b06a4df50982d))\n\n### Features\n\n- **schema:** Allow resolvers to validate a schema ([#2465](https://github.com/feathersjs/feathers/issues/2465)) ([7d9590b](https://github.com/feathersjs/feathers/commit/7d9590bbe12b94b8b5a7987684f5d4968e426481))\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n### Bug Fixes\n\n- **authentication-local:** adds error handling for undefined/null password field ([#2444](https://github.com/feathersjs/feathers/issues/2444)) ([4323f98](https://github.com/feathersjs/feathers/commit/4323f9859a66a7fe3f7f15d81476bd81b735c226))\n\n### Features\n\n- **schema:** Initial version of schema definitions and resolvers ([#2441](https://github.com/feathersjs/feathers/issues/2441)) ([c57a5cd](https://github.com/feathersjs/feathers/commit/c57a5cd56699a121647be4506d8f967e6d72ecae))\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package feathers\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package feathers\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n### Bug Fixes\n\n- **core:** Clean up readme ([eb3b4f2](https://github.com/feathersjs/feathers/commit/eb3b4f248c0816c92a2300cceed18a6f2518508a))\n- **core:** Set version back to development ([b328767](https://github.com/feathersjs/feathers/commit/b3287676cd773e164fd646ba4cffbf81983a9157))\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n### Bug Fixes\n\n- **koa:** Throw a NotFound Feathers error on missing paths ([#2415](https://github.com/feathersjs/feathers/issues/2415)) ([e013f98](https://github.com/feathersjs/feathers/commit/e013f98315d550ced6eacffd615c61bb0912b4ba))\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- **authentication-oauth:** Omit query from internal calls ([#2398](https://github.com/feathersjs/feathers/issues/2398)) ([04c7c83](https://github.com/feathersjs/feathers/commit/04c7c83eeaa6a7466c84b958071b468ed42f0b0f))\n- **core:** Add list of protected methods that can not be used for custom methods ([#2390](https://github.com/feathersjs/feathers/issues/2390)) ([6584a21](https://github.com/feathersjs/feathers/commit/6584a216e5a7d5f2a45822be6bfcb91c35cc2252))\n- **hooks:** Migrate built-in hooks and allow backwards compatibility ([#2358](https://github.com/feathersjs/feathers/issues/2358)) ([759c5a1](https://github.com/feathersjs/feathers/commit/759c5a19327a731af965c3604119393b3d09a406))\n- **koa:** Use extended query parser for compatibility ([#2397](https://github.com/feathersjs/feathers/issues/2397)) ([b2944ba](https://github.com/feathersjs/feathers/commit/b2944bac3ec6d5ecc80dc518cd4e58093692db74))\n- Update database adapter common repository urls ([#2380](https://github.com/feathersjs/feathers/issues/2380)) ([3f4db68](https://github.com/feathersjs/feathers/commit/3f4db68d6700c7d9023ecd17d0d39893f75a19fd))\n\n### Features\n\n- **typescript:** Allow to pass generic service options to adapter services ([#2392](https://github.com/feathersjs/feathers/issues/2392)) ([f9431f2](https://github.com/feathersjs/feathers/commit/f9431f242354f804cafb835519f98dd405ac4f0b))\n- Support being a built-in CodeSandbox sandbox ([#2381](https://github.com/feathersjs/feathers/issues/2381)) ([a2ac25a](https://github.com/feathersjs/feathers/commit/a2ac25a26e80530f7c50b88ef15eef46ee2b0634))\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n### Bug Fixes\n\n- **transport-commons:** Fix route placeholder registration and improve radix router performance ([#2336](https://github.com/feathersjs/feathers/issues/2336)) ([4d84dfd](https://github.com/feathersjs/feathers/commit/4d84dfd092ce0510312e975d5cd57e04973fb311))\n- **typescript:** Move Paginated type back for better compatibility ([#2350](https://github.com/feathersjs/feathers/issues/2350)) ([2917d05](https://github.com/feathersjs/feathers/commit/2917d05fffb4716d3c4cdaa5ac6a1aee0972e8a6))\n\n### Features\n\n- **koa:** KoaJS transport adapter ([#2315](https://github.com/feathersjs/feathers/issues/2315)) ([2554b57](https://github.com/feathersjs/feathers/commit/2554b57cf05731df58feeba9c12faab18e442107))\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n### Features\n\n- **deno:** Feathers core build for Deno ([#2299](https://github.com/feathersjs/feathers/issues/2299)) ([dece8fb](https://github.com/feathersjs/feathers/commit/dece8fbc0e7601f1505ce8bbb1e4e69cc26e8f98))\n- **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package feathers\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n### Bug Fixes\n\n- **adapter-tests:** Add test that verified paginated total ([#2273](https://github.com/feathersjs/feathers/issues/2273)) ([879bd6b](https://github.com/feathersjs/feathers/commit/879bd6b24f42e04eeeeba110ddddda3e1e1dea34))\n- **dependencies:** Fix transport-commons dependency and update other dependencies ([#2284](https://github.com/feathersjs/feathers/issues/2284)) ([05b03b2](https://github.com/feathersjs/feathers/commit/05b03b27b40604d956047e3021d8053c3a137616))\n- **feathers:** Always enable hooks on default service methods ([#2275](https://github.com/feathersjs/feathers/issues/2275)) ([827cc9b](https://github.com/feathersjs/feathers/commit/827cc9b752eecdaf63605d7dffd86f531b7e4af3))\n\n### Features\n\n- **adapter-commons:** Added mongoDB like search in embedded objects ([687e3c7](https://github.com/feathersjs/feathers/commit/687e3c7c36904221b2707d0220c0893e3cb1faa9))\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- **adapter-commons:** Always respect paginate.max ([#2267](https://github.com/feathersjs/feathers/issues/2267)) ([f588257](https://github.com/feathersjs/feathers/commit/f5882575536624ed3a32bb6e3ff1919fa17e366d))\n- **transport-commons:** Do not error when adding an undefined connection to a channel ([#2268](https://github.com/feathersjs/feathers/issues/2268)) ([28114c4](https://github.com/feathersjs/feathers/commit/28114c495d6564868bb3ffbf619bf80b774dce4b))\n- Resolve some type problems ([#2260](https://github.com/feathersjs/feathers/issues/2260)) ([a3d75fa](https://github.com/feathersjs/feathers/commit/a3d75fa29490e8a19412a12bc993ee7bb573068f))\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n- **adapter-commons:** Return missing overloads ([#2203](https://github.com/feathersjs/feathers/issues/2203)) ([bbe7e2a](https://github.com/feathersjs/feathers/commit/bbe7e2a131633e9a6e7aac7f7fa02a312bca63c7))\n- **socketio-client:** Fix client transport-commons reference ([#2164](https://github.com/feathersjs/feathers/issues/2164)) ([3a42c54](https://github.com/feathersjs/feathers/commit/3a42c544058456b19c7e21827226541bfa6ad621))\n\n### Features\n\n- **core:** Public custom service methods ([#2270](https://github.com/feathersjs/feathers/issues/2270)) ([e65abfb](https://github.com/feathersjs/feathers/commit/e65abfb5388df6c19a11c565cf1076a29f32668d))\n- Application service types default to any ([#1566](https://github.com/feathersjs/feathers/issues/1566)) ([d93ba9a](https://github.com/feathersjs/feathers/commit/d93ba9a17edd20d3397bb00f4f6e82e804e42ed6))\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n- **authentication-client:** Throw separate OauthError in authentication client ([#2189](https://github.com/feathersjs/feathers/issues/2189)) ([fa45ec5](https://github.com/feathersjs/feathers/commit/fa45ec520b21834e103e6fe4200b06dced56c0e6))\n- **core:** Remove Uberproto ([#2178](https://github.com/feathersjs/feathers/issues/2178)) ([ddf8821](https://github.com/feathersjs/feathers/commit/ddf8821f53317e6a378657f7d66acb03a037ee47))\n- **transport-commons:** New built-in high performance radix router ([#2177](https://github.com/feathersjs/feathers/issues/2177)) ([6d18065](https://github.com/feathersjs/feathers/commit/6d180651b4eb40289ecea3df3575f207aa6c5d1f))\n\n### BREAKING CHANGES\n\n- **core:** Services no longer extend Uberproto objects and\n  `service.mixin()` is no longer available.\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n### Features\n\n- **memory:** Move feathers-memory into @feathersjs/memory ([#2153](https://github.com/feathersjs/feathers/issues/2153)) ([dd61fe3](https://github.com/feathersjs/feathers/commit/dd61fe371fb0502f78b8ccbe1f45a030e31ecff6))\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Bug Fixes\n\n- **errors:** Format package.json with spaces ([cbd31c1](https://github.com/feathersjs/feathers/commit/cbd31c10c2c574de63d6ca5e55dbfb73a5fdd758))\n\n### chore\n\n- **configuration:** Remove environment variable substitution ([#1942](https://github.com/feathersjs/feathers/issues/1942)) ([caaa21f](https://github.com/feathersjs/feathers/commit/caaa21ffdc6a8dcac82fb403c91d9d4b781a6c0a))\n- **package:** Remove @feathersjs/primus packages from core ([#1919](https://github.com/feathersjs/feathers/issues/1919)) ([d20b7d5](https://github.com/feathersjs/feathers/commit/d20b7d5a70f4d3306e294696156e8aa0337c35e9)), closes [#1899](https://github.com/feathersjs/feathers/issues/1899)\n\n### Features\n\n- **core:** Migrate @feathersjs/feathers to TypeScript ([#1963](https://github.com/feathersjs/feathers/issues/1963)) ([7812529](https://github.com/feathersjs/feathers/commit/7812529ff0f1008e21211f1d01efbc49795dbe55))\n- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))\n- **transport-commons:** Remove legacy message format and unnecessary client timeouts ([#1939](https://github.com/feathersjs/feathers/issues/1939)) ([5538881](https://github.com/feathersjs/feathers/commit/5538881a08bc130de42c5984055729d8336f8615))\n\n### BREAKING CHANGES\n\n- **configuration:** Falls back to node-config instead of adding additional\n  functionality like path replacements and automatic environment variable insertion.\n- **transport-commons:** Removes the old message format and client service timeout\n- **package:** Remove primus packages to be moved into the ecosystem.\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Bug Fixes\n\n- **authentication-oauth:** Updated typings for projects with strictNullChecks ([#1941](https://github.com/feathersjs/feathers/issues/1941)) ([be91206](https://github.com/feathersjs/feathers/commit/be91206e3dba1e65a81412b7aa636bece3ab4aa2))\n- **errors:** Format package.json with spaces ([cbd31c1](https://github.com/feathersjs/feathers/commit/cbd31c10c2c574de63d6ca5e55dbfb73a5fdd758))\n\n### chore\n\n- **configuration:** Remove environment variable substitution ([#1942](https://github.com/feathersjs/feathers/issues/1942)) ([caaa21f](https://github.com/feathersjs/feathers/commit/caaa21ffdc6a8dcac82fb403c91d9d4b781a6c0a))\n- **package:** Remove @feathersjs/primus packages from core ([#1919](https://github.com/feathersjs/feathers/issues/1919)) ([d20b7d5](https://github.com/feathersjs/feathers/commit/d20b7d5a70f4d3306e294696156e8aa0337c35e9)), closes [#1899](https://github.com/feathersjs/feathers/issues/1899)\n\n### Features\n\n- **core:** Migrate @feathersjs/feathers to TypeScript ([#1963](https://github.com/feathersjs/feathers/issues/1963)) ([7812529](https://github.com/feathersjs/feathers/commit/7812529ff0f1008e21211f1d01efbc49795dbe55))\n- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))\n- **transport-commons:** Remove legacy message format and unnecessary client timeouts ([#1939](https://github.com/feathersjs/feathers/issues/1939)) ([5538881](https://github.com/feathersjs/feathers/commit/5538881a08bc130de42c5984055729d8336f8615))\n\n### BREAKING CHANGES\n\n- **configuration:** Falls back to node-config instead of adding additional\n  functionality like path replacements and automatic environment variable insertion.\n- **transport-commons:** Removes the old message format and client service timeout\n- **package:** Remove primus packages to be moved into the ecosystem.\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n### Bug Fixes\n\n- **authentication-client:** Allow reAuthentication using specific strategy ([#2140](https://github.com/feathersjs/feathers/issues/2140)) ([2a2bbf7](https://github.com/feathersjs/feathers/commit/2a2bbf7f8ee6d32b9fac8afab3421286b06e6443))\n- **socketio-client:** Throw an error and show a warning if someone tries to use socket.io-client v3 ([#2135](https://github.com/feathersjs/feathers/issues/2135)) ([cc3521c](https://github.com/feathersjs/feathers/commit/cc3521c935a1cbd690e29b7057998e3898f282db))\n- **typescript:** Fix `data` property definition in @feathersjs/errors ([#2018](https://github.com/feathersjs/feathers/issues/2018)) ([ef1398c](https://github.com/feathersjs/feathers/commit/ef1398cd5b19efa50929e8c9511ca5684a18997f))\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n### Bug Fixes\n\n- **authentication:** consistent response return between local and jwt strategy ([#2042](https://github.com/feathersjs/feathers/issues/2042)) ([8d25be1](https://github.com/feathersjs/feathers/commit/8d25be101a2593a9e789375c928a07780b9e28cf))\n- **authentication-oauth:** session.destroy is undefined when use cookie-session package ([#2100](https://github.com/feathersjs/feathers/issues/2100)) ([46e84b8](https://github.com/feathersjs/feathers/commit/46e84b83f2acce985380243fc6d08c64e96f0068))\n- **package:** Fix clean script in non Unix environments ([#2110](https://github.com/feathersjs/feathers/issues/2110)) ([09b62c0](https://github.com/feathersjs/feathers/commit/09b62c0c7e636caf620904ba87d61f168a020f05))\n- **typescript:** Add user property to the Params. ([#2090](https://github.com/feathersjs/feathers/issues/2090)) ([1e94265](https://github.com/feathersjs/feathers/commit/1e942651fbaaf07fc66c159225fbc992a0174bf4))\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n### Bug Fixes\n\n- **authentication-local:** Keep non-objects in protect hook ([#2085](https://github.com/feathersjs/feathers/issues/2085)) ([5a65e2e](https://github.com/feathersjs/feathers/commit/5a65e2e6cee0a15614f23ee2e0d3c25d3365027d))\n- **authentication-oauth:** Always end session after oAuth flows are finished ([#2087](https://github.com/feathersjs/feathers/issues/2087)) ([d219d0d](https://github.com/feathersjs/feathers/commit/d219d0d89c5e45aa289dd67cb0c8bdc05044c846))\n- **configuration:** Fix handling of config values that start with . or .. but are not actually relative paths; e.g. \".foo\" or \"..bar\" ([#2065](https://github.com/feathersjs/feathers/issues/2065)) ([d07bf59](https://github.com/feathersjs/feathers/commit/d07bf5902e9c8c606f16b9523472972d3d2e9b49))\n- **rest-client:** Handle non-JSON errors with fetch adapter ([#2086](https://github.com/feathersjs/feathers/issues/2086)) ([e24217a](https://github.com/feathersjs/feathers/commit/e24217ad1e784ad71cd9d64fe1727dd02f039991))\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n- **authentication-client:** Fix storage type so it works with all supported interfaces ([#2041](https://github.com/feathersjs/feathers/issues/2041)) ([6ee0e78](https://github.com/feathersjs/feathers/commit/6ee0e78d55cf1214f61458f386b94c350eec32af))\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n### Bug Fixes\n\n- **authentication:** Add JWT getEntityQuery ([#2013](https://github.com/feathersjs/feathers/issues/2013)) ([e0e7fb5](https://github.com/feathersjs/feathers/commit/e0e7fb5162940fe776731283b40026c61d9c8a33))\n- **typescript:** Revert add overload types for `find` service methods ([#1972](https://github.com/feathersjs/feathers/issues/1972))\" ([#2025](https://github.com/feathersjs/feathers/issues/2025)) ([a9501ac](https://github.com/feathersjs/feathers/commit/a9501acb4d3ef58dfb87d62c57a9bf76569da281))\n\n## [4.5.6](https://github.com/feathersjs/feathers/compare/v4.5.5...v4.5.6) (2020-07-12)\n\n### Bug Fixes\n\n- **authentication:** Omit query in JWT strategy ([#2011](https://github.com/feathersjs/feathers/issues/2011)) ([04ce7e9](https://github.com/feathersjs/feathers/commit/04ce7e98515fe9d495cd0e83e0da097e9bcd7382))\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n### Bug Fixes\n\n- **authentication:** Include query params when authenticating via authenticate hook [#2009](https://github.com/feathersjs/feathers/issues/2009) ([4cdb7bf](https://github.com/feathersjs/feathers/commit/4cdb7bf2898385ddac7a1692bc9ac2f6cf5ad446))\n- **authentication-oauth:** Updated typings for projects with strictNullChecks ([#1941](https://github.com/feathersjs/feathers/issues/1941)) ([be91206](https://github.com/feathersjs/feathers/commit/be91206e3dba1e65a81412b7aa636bece3ab4aa2))\n- **typescript:** add overload types for `find` service methods ([#1972](https://github.com/feathersjs/feathers/issues/1972)) ([ef55af0](https://github.com/feathersjs/feathers/commit/ef55af088d05d9d36aba9d9f8d6c2c908a4f20dd))\n\n## [4.5.4](https://github.com/feathersjs/feathers/compare/v4.5.3...v4.5.4) (2020-04-29)\n\n### Bug Fixes\n\n- **authentication-local:** Allow to hash passwords in array data ([#1936](https://github.com/feathersjs/feathers/issues/1936)) ([64705f5](https://github.com/feathersjs/feathers/commit/64705f5d9d4dc27f799da3a074efaf74379a3398))\n- **authentication-oauth:** Add getEntity method to oAuth authentication and remove provider field for other calls ([#1935](https://github.com/feathersjs/feathers/issues/1935)) ([d925c1b](https://github.com/feathersjs/feathers/commit/d925c1bd193b5c19cb23a246f04fc46d0429fc75))\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n### Bug Fixes\n\n- **authentication:** Remove entity from connection information on logout ([#1889](https://github.com/feathersjs/feathers/issues/1889)) ([b062753](https://github.com/feathersjs/feathers/commit/b0627530d61babe15dd84369d3093ccae4b780ca))\n- **authentication-oauth:** Allow req.feathers to be used in oAuth authentication requests ([#1886](https://github.com/feathersjs/feathers/issues/1886)) ([854c9ca](https://github.com/feathersjs/feathers/commit/854c9cac9a9a5f8f89054a90feb24ab5c4766f5f))\n- **errors:** Add 410 Gone to errors ([#1849](https://github.com/feathersjs/feathers/issues/1849)) ([6801428](https://github.com/feathersjs/feathers/commit/6801428f8fd17dbfebcdb6f1b0cd01433a4033dc))\n- **typescript:** Add type keys to service pagination options. ([#1888](https://github.com/feathersjs/feathers/issues/1888)) ([859c601](https://github.com/feathersjs/feathers/commit/859c601519c7cb399e8b1667bb50073466812d5c))\n- **typescript:** Use stricter type for HookContext 'method' prop ([#1896](https://github.com/feathersjs/feathers/issues/1896)) ([24a41b7](https://github.com/feathersjs/feathers/commit/24a41b74486ddadccad18f3ae63afdac5bd373c7))\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n### Bug Fixes\n\n- Updated typings for express middleware ([#1839](https://github.com/feathersjs/feathers/issues/1839)) ([6b8e897](https://github.com/feathersjs/feathers/commit/6b8e8971a9dbb08913edd1be48826624645d9dc1))\n- **authentication:** Improve JWT strategy configuration error message ([#1844](https://github.com/feathersjs/feathers/issues/1844)) ([2c771db](https://github.com/feathersjs/feathers/commit/2c771dbb22d53d4f7de3c3f514e57afa1a186322))\n- **package:** update grant-profile to version 0.0.11 ([#1841](https://github.com/feathersjs/feathers/issues/1841)) ([5dcd2aa](https://github.com/feathersjs/feathers/commit/5dcd2aa3483059cc7a2546b145dd72b4705fe2fe))\n- **test:** typo in password ([#1797](https://github.com/feathersjs/feathers/issues/1797)) ([dfba6ec](https://github.com/feathersjs/feathers/commit/dfba6ec2f21adf3aa739218cf870eaaaa5df6e9c))\n- **typescript:** Make HookMap and HookObject generics. ([#1815](https://github.com/feathersjs/feathers/issues/1815)) ([d10145d](https://github.com/feathersjs/feathers/commit/d10145d91a09aef7bce5af80805a3c0fa9d94f26))\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package feathers\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n### Bug Fixes\n\n- Add `params.authentication` type, remove `hook.connection` type ([#1732](https://github.com/feathersjs/feathers/issues/1732)) ([d46b7b2](https://github.com/feathersjs/feathers/commit/d46b7b2abac8862c0e4dbfce20d71b8b8a96692f))\n\n### Features\n\n- **authentication-oauth:** Set oAuth redirect URL dynamically and pass query the service ([#1737](https://github.com/feathersjs/feathers/issues/1737)) ([0b05f0b](https://github.com/feathersjs/feathers/commit/0b05f0b58a257820fa61d695a36f36455209f6a1))\n- **rest-client:** Allow for customising rest clients ([#1780](https://github.com/feathersjs/feathers/issues/1780)) ([c5cfec7](https://github.com/feathersjs/feathers/commit/c5cfec7a4aafcaffaab0cdacb9b5d297ff20320f))\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n### Bug Fixes\n\n- **adapter-commons:** Filter arrays in queries ([#1724](https://github.com/feathersjs/feathers/issues/1724)) ([872b669](https://github.com/feathersjs/feathers/commit/872b66906a806ab92ca41b5f6f504ff0af1ce79e))\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n### Bug Fixes\n\n- Gracefully handle errors in publishers ([#1710](https://github.com/feathersjs/feathers/issues/1710)) ([0616306](https://github.com/feathersjs/feathers/commit/061630696762e9dbf1dc4e738094992ba16989fc))\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n### Bug Fixes\n\n- **authentication-client:** Reset authentication promise on socket disconnect ([#1696](https://github.com/feathersjs/feathers/issues/1696)) ([3951626](https://github.com/feathersjs/feathers/commit/395162633ff22e95833a3c2900cb9464bb5b056f))\n- **core:** Improve hook missing parameter message by adding the service name ([#1703](https://github.com/feathersjs/feathers/issues/1703)) ([2331c2a](https://github.com/feathersjs/feathers/commit/2331c2a3dd70d432db7d62a76ed805d359cbbba5))\n- **rest-client:** Allow to customize getting the query ([#1594](https://github.com/feathersjs/feathers/issues/1594)) ([5f21272](https://github.com/feathersjs/feathers/commit/5f212729849414c4da6f0d51edd1986feca992ee))\n- **transport-commons:** Allow to properly chain SocketIo client.off ([#1706](https://github.com/feathersjs/feathers/issues/1706)) ([a4aecbc](https://github.com/feathersjs/feathers/commit/a4aecbcd3578c1cf4ecffb3a58fb6d26e15ee513))\n- **typescript:** Allow specific service typings for `Hook` and `HookContext` ([#1688](https://github.com/feathersjs/feathers/issues/1688)) ([f5d0ddd](https://github.com/feathersjs/feathers/commit/f5d0ddd9724bf5778355535d2103d59daaad6294))\n\n### Features\n\n- **authentication:** Add parseStrategies to allow separate strategies for creating JWTs and parsing headers ([#1708](https://github.com/feathersjs/feathers/issues/1708)) ([5e65629](https://github.com/feathersjs/feathers/commit/5e65629b924724c3e81d7c81df047e123d1c8bd7))\n- **authentication-oauth:** Set oAuth redirect URL dynamically ([#1608](https://github.com/feathersjs/feathers/issues/1608)) ([1293e08](https://github.com/feathersjs/feathers/commit/1293e088abbb3d23f4a44680836645a8049ceaae))\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n### Bug Fixes\n\n- **authentication:** Retain object references in authenticate hook ([#1675](https://github.com/feathersjs/feathers/issues/1675)) ([e1939be](https://github.com/feathersjs/feathers/commit/e1939be19d4e79d3f5e2fe69ba894a11c627ae99))\n- **authentication-oauth:** Allow hash based redirects ([#1676](https://github.com/feathersjs/feathers/issues/1676)) ([ffe7cf3](https://github.com/feathersjs/feathers/commit/ffe7cf3fbb4e62d7689065cf7b61f25f602ce8cf))\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package feathers\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n### Bug Fixes\n\n- Add jsonwebtoken TypeScript type dependency ([317c80a](https://github.com/feathersjs/feathers/commit/317c80a9205e8853bb830a12c3aa1a19e95f9abc))\n- Only initialize default Express session if oAuth is actually used ([#1648](https://github.com/feathersjs/feathers/issues/1648)) ([9b9b43f](https://github.com/feathersjs/feathers/commit/9b9b43ff09af1080e4aaa537064bac37b881c9a2))\n- Small type improvements ([#1624](https://github.com/feathersjs/feathers/issues/1624)) ([50162c6](https://github.com/feathersjs/feathers/commit/50162c6e562f0a47c6a280c4f01fff7c3afee293))\n\n## [4.3.8](https://github.com/feathersjs/feathers/compare/v4.3.7...v4.3.8) (2019-10-14)\n\n### Bug Fixes\n\n- Remove adapter commons type alternatives ([#1620](https://github.com/feathersjs/feathers/issues/1620)) ([c9f3086](https://github.com/feathersjs/feathers/commit/c9f3086344420b57dbce7c4169cf550c97509f0d))\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n### Bug Fixes\n\n- Improve authentication client default storage initialization ([#1613](https://github.com/feathersjs/feathers/issues/1613)) ([d7f5107](https://github.com/feathersjs/feathers/commit/d7f5107ef76297b4ca6db580afc5e2b372f5ee4d))\n- improve Service and AdapterService types ([#1567](https://github.com/feathersjs/feathers/issues/1567)) ([baad6a2](https://github.com/feathersjs/feathers/commit/baad6a26f0f543b712ccb40359b3933ad3a21392))\n- make \\_\\_hooks writable and configurable ([#1520](https://github.com/feathersjs/feathers/issues/1520)) ([1c6c374](https://github.com/feathersjs/feathers/commit/1c6c3742ecf1cb813be56074da89e6736d03ffe8))\n- Typings for express request and response properties ([#1609](https://github.com/feathersjs/feathers/issues/1609)) ([38cf8c9](https://github.com/feathersjs/feathers/commit/38cf8c950c1a4fb4a6d78d68d70e7fdd63b71c3c))\n\n## [4.3.6](https://github.com/feathersjs/feathers/compare/v4.3.5...v4.3.6) (2019-10-07)\n\n### Bug Fixes\n\n- Check query for NaN ([#1607](https://github.com/feathersjs/feathers/issues/1607)) ([f1a781f](https://github.com/feathersjs/feathers/commit/f1a781f))\n\n## [4.3.5](https://github.com/feathersjs/feathers/compare/v4.3.4...v4.3.5) (2019-10-07)\n\n### Bug Fixes\n\n- Authentication type improvements and timeout fix ([#1605](https://github.com/feathersjs/feathers/issues/1605)) ([19854d3](https://github.com/feathersjs/feathers/commit/19854d3))\n- Change this reference in client libraries to explicitly passed app ([#1597](https://github.com/feathersjs/feathers/issues/1597)) ([4e4d10a](https://github.com/feathersjs/feathers/commit/4e4d10a))\n- Improve error message when authentication strategy is not allowed ([#1600](https://github.com/feathersjs/feathers/issues/1600)) ([317a312](https://github.com/feathersjs/feathers/commit/317a312))\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n### Bug Fixes\n\n- Reset version number after every publish ([#1596](https://github.com/feathersjs/feathers/issues/1596)) ([f24f82f](https://github.com/feathersjs/feathers/commit/f24f82f))\n- Typing improvements ([#1580](https://github.com/feathersjs/feathers/issues/1580)) ([7818aec](https://github.com/feathersjs/feathers/commit/7818aec))\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n### Bug Fixes\n\n- check for undefined access token ([#1571](https://github.com/feathersjs/feathers/issues/1571)) ([976369d](https://github.com/feathersjs/feathers/commit/976369d))\n- Small improvements in dependencies and code structure ([#1562](https://github.com/feathersjs/feathers/issues/1562)) ([42c13e2](https://github.com/feathersjs/feathers/commit/42c13e2))\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n### Bug Fixes\n\n- Add info to express error handler logger type ([#1557](https://github.com/feathersjs/feathers/issues/1557)) ([3e1d26c](https://github.com/feathersjs/feathers/commit/3e1d26c))\n- LocalStrategy authenticates without username ([#1560](https://github.com/feathersjs/feathers/issues/1560)) ([2b258fd](https://github.com/feathersjs/feathers/commit/2b258fd)), closes [#1559](https://github.com/feathersjs/feathers/issues/1559)\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n### Bug Fixes\n\n- Fix regression in transport commons ([#1551](https://github.com/feathersjs/feathers/issues/1551)) ([ed9e934](https://github.com/feathersjs/feathers/commit/ed9e934))\n- Omit standard protocol ports from the default hostname ([#1543](https://github.com/feathersjs/feathers/issues/1543)) ([ef16d29](https://github.com/feathersjs/feathers/commit/ef16d29))\n- Use long-timeout for JWT expiration timers ([#1552](https://github.com/feathersjs/feathers/issues/1552)) ([65637ec](https://github.com/feathersjs/feathers/commit/65637ec))\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n### Bug Fixes\n\n- Only remove token on NotAuthenticated error in authentication client and handle error better ([#1525](https://github.com/feathersjs/feathers/issues/1525)) ([13a8758](https://github.com/feathersjs/feathers/commit/13a8758))\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n### Bug Fixes\n\n- Fix auth publisher mistake ([08bad61](https://github.com/feathersjs/feathers/commit/08bad61))\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Expire and remove authenticated real-time connections ([#1512](https://github.com/feathersjs/feathers/issues/1512)) ([2707c33](https://github.com/feathersjs/feathers/commit/2707c33))\n- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))\n- Use WeakMap to connect socket to connection ([#1509](https://github.com/feathersjs/feathers/issues/1509)) ([64807e3](https://github.com/feathersjs/feathers/commit/64807e3))\n\n### Features\n\n- Let strategies handle the connection ([#1510](https://github.com/feathersjs/feathers/issues/1510)) ([4329feb](https://github.com/feathersjs/feathers/commit/4329feb))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n### Bug Fixes\n\n- @feathersjs/adapter-commons: `update` id is non-nullable ([#1468](https://github.com/feathersjs/feathers/issues/1468)) ([43ec802](https://github.com/feathersjs/feathers/commit/43ec802))\n- Add getEntityId to JWT strategy and fix legacy Socket authentication ([#1488](https://github.com/feathersjs/feathers/issues/1488)) ([9a3b324](https://github.com/feathersjs/feathers/commit/9a3b324))\n- Add method to reliably get default authentication service ([#1470](https://github.com/feathersjs/feathers/issues/1470)) ([e542cb3](https://github.com/feathersjs/feathers/commit/e542cb3))\n- Do not error in authentication client on logout ([#1473](https://github.com/feathersjs/feathers/issues/1473)) ([8211b98](https://github.com/feathersjs/feathers/commit/8211b98))\n- Improve Params typing ([#1474](https://github.com/feathersjs/feathers/issues/1474)) ([54a3aa7](https://github.com/feathersjs/feathers/commit/54a3aa7))\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package feathers\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n### Bug Fixes\n\n- Fix feathers-memory dependency that did not get updated ([9422b13](https://github.com/feathersjs/feathers/commit/9422b13))\n- Remove unnecessary top level export files in @feathersjs/express ([#1442](https://github.com/feathersjs/feathers/issues/1442)) ([73c3fb2](https://github.com/feathersjs/feathers/commit/73c3fb2))\n\n### Features\n\n- @feathersjs/express allow to pass an existing Express application instance ([#1446](https://github.com/feathersjs/feathers/issues/1446)) ([853a6b0](https://github.com/feathersjs/feathers/commit/853a6b0))\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n### Bug Fixes\n\n- @feathersjs/adapter-commons: remove data from `remove` arguments ([#1426](https://github.com/feathersjs/feathers/issues/1426)) ([fd54ae9](https://github.com/feathersjs/feathers/commit/fd54ae9))\n- @feathersjs/express: allow middleware arrays ([#1421](https://github.com/feathersjs/feathers/issues/1421)) ([b605ab8](https://github.com/feathersjs/feathers/commit/b605ab8))\n- @feathersjs/express: replace `reduce` with `map` ([#1429](https://github.com/feathersjs/feathers/issues/1429)) ([44542e9](https://github.com/feathersjs/feathers/commit/44542e9))\n- Clean up hooks code ([#1407](https://github.com/feathersjs/feathers/issues/1407)) ([f25c88b](https://github.com/feathersjs/feathers/commit/f25c88b))\n- Fix @feathersjs/feathers typings http import ([abbc07b](https://github.com/feathersjs/feathers/commit/abbc07b))\n- Fix OpenCollective link ([28888a1](https://github.com/feathersjs/feathers/commit/28888a1))\n- Improve transport-commons types ([#1396](https://github.com/feathersjs/feathers/issues/1396)) ([f9d8536](https://github.com/feathersjs/feathers/commit/f9d8536))\n- Updated typings for ServiceMethods ([#1409](https://github.com/feathersjs/feathers/issues/1409)) ([b5ee7e2](https://github.com/feathersjs/feathers/commit/b5ee7e2))\n\n### Features\n\n- adapter-commons: add `allowsMulti(method)` to AdapterService ([#1431](https://github.com/feathersjs/feathers/issues/1431)) ([e688851](https://github.com/feathersjs/feathers/commit/e688851))\n- Add hook-less methods and service option types to adapter-commons ([#1433](https://github.com/feathersjs/feathers/issues/1433)) ([857f54a](https://github.com/feathersjs/feathers/commit/857f54a))\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Make oAuth paths more consistent and improve authentication client ([#1377](https://github.com/feathersjs/feathers/issues/1377)) ([adb2543](https://github.com/feathersjs/feathers/commit/adb2543))\n- Set authenticated: true after successful authentication ([#1367](https://github.com/feathersjs/feathers/issues/1367)) ([9918cff](https://github.com/feathersjs/feathers/commit/9918cff))\n- Typings fix and improvements. ([#1364](https://github.com/feathersjs/feathers/issues/1364)) ([515b916](https://github.com/feathersjs/feathers/commit/515b916))\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n### Bug Fixes\n\n- Throw NotAuthenticated on token verification errors ([#1357](https://github.com/feathersjs/feathers/issues/1357)) ([e0120df](https://github.com/feathersjs/feathers/commit/e0120df))\n- **typescript:** finally should be optional ([#1350](https://github.com/feathersjs/feathers/issues/1350)) ([f439a9e](https://github.com/feathersjs/feathers/commit/f439a9e))\n- Add fallback for legacy socket authenticate event ([#1356](https://github.com/feathersjs/feathers/issues/1356)) ([61b1056](https://github.com/feathersjs/feathers/commit/61b1056))\n- Correctly read the oauth strategy config ([#1349](https://github.com/feathersjs/feathers/issues/1349)) ([9abf314](https://github.com/feathersjs/feathers/commit/9abf314))\n- Fix versioning tests. Closes [#1346](https://github.com/feathersjs/feathers/issues/1346) ([dd519f6](https://github.com/feathersjs/feathers/commit/dd519f6))\n- Use `export =` in TypeScript definitions ([#1285](https://github.com/feathersjs/feathers/issues/1285)) ([12d0f4b](https://github.com/feathersjs/feathers/commit/12d0f4b))\n\n### Features\n\n- Add global disconnect event ([#1355](https://github.com/feathersjs/feathers/issues/1355)) ([85afcca](https://github.com/feathersjs/feathers/commit/85afcca))\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n### Bug Fixes\n\n- Add registerPublisher alias for .publish ([#1302](https://github.com/feathersjs/feathers/issues/1302)) ([98fe8f8](https://github.com/feathersjs/feathers/commit/98fe8f8))\n- Always require strategy parameter in authentication ([#1327](https://github.com/feathersjs/feathers/issues/1327)) ([d4a8021](https://github.com/feathersjs/feathers/commit/d4a8021))\n- Bring back params.authenticated ([#1317](https://github.com/feathersjs/feathers/issues/1317)) ([a0ffd5e](https://github.com/feathersjs/feathers/commit/a0ffd5e))\n- Do not log as errors below a 500 response ([#1256](https://github.com/feathersjs/feathers/issues/1256)) ([33fd0e4](https://github.com/feathersjs/feathers/commit/33fd0e4))\n- Guard against null in client side logout function ([#1319](https://github.com/feathersjs/feathers/issues/1319)) ([fa7f057](https://github.com/feathersjs/feathers/commit/fa7f057))\n- Handle error oAuth redirect in authentication client ([#1307](https://github.com/feathersjs/feathers/issues/1307)) ([12d48ee](https://github.com/feathersjs/feathers/commit/12d48ee))\n- Improve authentication parameter handling ([#1333](https://github.com/feathersjs/feathers/issues/1333)) ([6e77204](https://github.com/feathersjs/feathers/commit/6e77204))\n- Improve oAuth option handling and usability ([#1335](https://github.com/feathersjs/feathers/issues/1335)) ([adb137d](https://github.com/feathersjs/feathers/commit/adb137d))\n- Merge httpStrategies and authStrategies option ([#1308](https://github.com/feathersjs/feathers/issues/1308)) ([afa4d55](https://github.com/feathersjs/feathers/commit/afa4d55))\n- Rename jwtStrategies option to authStrategies ([#1305](https://github.com/feathersjs/feathers/issues/1305)) ([4aee151](https://github.com/feathersjs/feathers/commit/4aee151))\n- Update version number check ([53575c5](https://github.com/feathersjs/feathers/commit/53575c5))\n- Updated HooksObject typings ([#1300](https://github.com/feathersjs/feathers/issues/1300)) ([b28058c](https://github.com/feathersjs/feathers/commit/b28058c))\n\n### Features\n\n- Add params.headers to all transports when available ([#1303](https://github.com/feathersjs/feathers/issues/1303)) ([ebce79b](https://github.com/feathersjs/feathers/commit/ebce79b))\n- Change and *JWT methods to *accessToken ([#1304](https://github.com/feathersjs/feathers/issues/1304)) ([5ac826b](https://github.com/feathersjs/feathers/commit/5ac826b))\n- express use service.methods ([#945](https://github.com/feathersjs/feathers/issues/945)) ([3f0b1c3](https://github.com/feathersjs/feathers/commit/3f0b1c3))\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Add test to make sure different id in adapter query works ([#1165](https://github.com/feathersjs/feathers/issues/1165)) ([0ba4580](https://github.com/feathersjs/feathers/commit/0ba4580))\n- Add whitelist and filter support to common adapter service ([#1132](https://github.com/feathersjs/feathers/issues/1132)) ([df1daaa](https://github.com/feathersjs/feathers/commit/df1daaa))\n- Added path and method in to express request for passport ([#1112](https://github.com/feathersjs/feathers/issues/1112)) ([afa1cb4](https://github.com/feathersjs/feathers/commit/afa1cb4))\n- Authentication core improvements ([#1260](https://github.com/feathersjs/feathers/issues/1260)) ([c5dc7a2](https://github.com/feathersjs/feathers/commit/c5dc7a2))\n- Catch connection initialization errors ([#1043](https://github.com/feathersjs/feathers/issues/1043)) ([4f9acd6](https://github.com/feathersjs/feathers/commit/4f9acd6))\n- Compare socket event data using lodash's isEqual instead of indexOf ([#1061](https://github.com/feathersjs/feathers/issues/1061)) ([f706db3](https://github.com/feathersjs/feathers/commit/f706db3))\n- Do not inherit app object from Object prototype ([#1153](https://github.com/feathersjs/feathers/issues/1153)) ([ed8c2e4](https://github.com/feathersjs/feathers/commit/ed8c2e4))\n- Fix AdapterService multi option when set to true ([#1134](https://github.com/feathersjs/feathers/issues/1134)) ([40402fc](https://github.com/feathersjs/feathers/commit/40402fc))\n- Improve JWT authentication option handling ([#1261](https://github.com/feathersjs/feathers/issues/1261)) ([31b956b](https://github.com/feathersjs/feathers/commit/31b956b))\n- make codeclimate conform to rule of three ([#1076](https://github.com/feathersjs/feathers/issues/1076)) ([0a2ce87](https://github.com/feathersjs/feathers/commit/0a2ce87))\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- More robust parsing of mongodb connection string. Use new url parser. ([#1002](https://github.com/feathersjs/feathers/issues/1002)) ([74b31df](https://github.com/feathersjs/feathers/commit/74b31df))\n- Normalize params to object even when it is falsy ([#1012](https://github.com/feathersjs/feathers/issues/1012)) ([af97818](https://github.com/feathersjs/feathers/commit/af97818))\n- Only merge authenticated property on update ([8a564f7](https://github.com/feathersjs/feathers/commit/8a564f7))\n- reduce authentication connection hook complexity and remove unnecessary checks ([fa94b2f](https://github.com/feathersjs/feathers/commit/fa94b2f))\n- support a secretProvider ([#1063](https://github.com/feathersjs/feathers/issues/1063)) ([9da26ad](https://github.com/feathersjs/feathers/commit/9da26ad))\n- Support Logger swallowing ([#995](https://github.com/feathersjs/feathers/issues/995)) ([5b3b37e](https://github.com/feathersjs/feathers/commit/5b3b37e)), closes [/github.com/feathersjs/generator-feathers/pull/392#issuecomment-420408312](https://github.com//github.com/feathersjs/generator-feathers/pull/392/issues/issuecomment-420408312)\n- Throw error in `filterQuery` when query parameter is unknown ([#1131](https://github.com/feathersjs/feathers/issues/1131)) ([cd1a183](https://github.com/feathersjs/feathers/commit/cd1a183))\n- Update 401.html ([#983](https://github.com/feathersjs/feathers/issues/983)) ([cec6bae](https://github.com/feathersjs/feathers/commit/cec6bae))\n- Update 404.html ([#984](https://github.com/feathersjs/feathers/issues/984)) ([72132d1](https://github.com/feathersjs/feathers/commit/72132d1))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n- Update adapter common tests to check for falsy ([#1140](https://github.com/feathersjs/feathers/issues/1140)) ([2856722](https://github.com/feathersjs/feathers/commit/2856722))\n- Update adapter tests to not rely on error instance ([#1202](https://github.com/feathersjs/feathers/issues/1202)) ([6885e0e](https://github.com/feathersjs/feathers/commit/6885e0e))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n- **adapter-commons:** Keep Symbols when filtering a query ([#1141](https://github.com/feathersjs/feathers/issues/1141)) ([c9f55d8](https://github.com/feathersjs/feathers/commit/c9f55d8))\n- **authentication:** Fall back when req.app is not the application when emitting events ([#1185](https://github.com/feathersjs/feathers/issues/1185)) ([6a534f0](https://github.com/feathersjs/feathers/commit/6a534f0))\n- **chore:** Add .npmignore to adapter-commons ([8e129d8](https://github.com/feathersjs/feathers/commit/8e129d8))\n- **chore:** Properly configure and run code linter ([#1092](https://github.com/feathersjs/feathers/issues/1092)) ([fd3fc34](https://github.com/feathersjs/feathers/commit/fd3fc34))\n- **chore:** Remove CLI and generators that belong in their own repositories ([#1091](https://github.com/feathersjs/feathers/issues/1091)) ([e894ac8](https://github.com/feathersjs/feathers/commit/e894ac8))\n- **compile-task:** on windows machine ([#60](https://github.com/feathersjs/feathers/issues/60)) ([617e0a4](https://github.com/feathersjs/feathers/commit/617e0a4))\n- **docs/new-features:** syntax highlighting ([#347](https://github.com/feathersjs/feathers/issues/347)) ([4ab7c95](https://github.com/feathersjs/feathers/commit/4ab7c95))\n- **knex:** Fix knex + sql server issues when using authentication generator ([#257](https://github.com/feathersjs/feathers/issues/257)) ([8f8f75f](https://github.com/feathersjs/feathers/commit/8f8f75f))\n- **package:** update @feathersjs/commons to version 2.0.0 ([#31](https://github.com/feathersjs/feathers/issues/31)) ([c1ef5b1](https://github.com/feathersjs/feathers/commit/c1ef5b1))\n- **package:** update @feathersjs/commons to version 2.0.0 ([#692](https://github.com/feathersjs/feathers/issues/692)) ([ca665ab](https://github.com/feathersjs/feathers/commit/ca665ab))\n- **package:** update config to version 3.0.0 ([#1100](https://github.com/feathersjs/feathers/issues/1100)) ([c9f4b42](https://github.com/feathersjs/feathers/commit/c9f4b42))\n- use minimal RegExp matching for better performance ([#977](https://github.com/feathersjs/feathers/issues/977)) ([3ca7e97](https://github.com/feathersjs/feathers/commit/3ca7e97))\n- **package:** update @feathersjs/commons to version 2.0.0 ([#45](https://github.com/feathersjs/feathers/issues/45)) ([9e82595](https://github.com/feathersjs/feathers/commit/9e82595))\n- **package:** update @feathersjs/commons to version 2.0.0 ([#84](https://github.com/feathersjs/feathers/issues/84)) ([78ed39c](https://github.com/feathersjs/feathers/commit/78ed39c))\n- **package:** update debug to version 3.0.0 ([#2](https://github.com/feathersjs/feathers/issues/2)) ([7e19603](https://github.com/feathersjs/feathers/commit/7e19603))\n- **package:** update debug to version 3.0.0 ([#22](https://github.com/feathersjs/feathers/issues/22)) ([0b62606](https://github.com/feathersjs/feathers/commit/0b62606))\n- **package:** update debug to version 3.0.0 ([#30](https://github.com/feathersjs/feathers/issues/30)) ([baf7a00](https://github.com/feathersjs/feathers/commit/baf7a00))\n- **package:** update debug to version 3.0.0 ([#31](https://github.com/feathersjs/feathers/issues/31)) ([902ddf5](https://github.com/feathersjs/feathers/commit/902ddf5))\n- **package:** update debug to version 3.0.0 ([#31](https://github.com/feathersjs/feathers/issues/31)) ([f23d617](https://github.com/feathersjs/feathers/commit/f23d617))\n- **package:** update debug to version 3.0.0 ([#45](https://github.com/feathersjs/feathers/issues/45)) ([2391434](https://github.com/feathersjs/feathers/commit/2391434))\n- **package:** update debug to version 3.0.0 ([#45](https://github.com/feathersjs/feathers/issues/45)) ([9b9bde5](https://github.com/feathersjs/feathers/commit/9b9bde5))\n- **package:** update debug to version 3.0.0 ([#555](https://github.com/feathersjs/feathers/issues/555)) ([f788804](https://github.com/feathersjs/feathers/commit/f788804))\n- **package:** update debug to version 3.0.0 ([#59](https://github.com/feathersjs/feathers/issues/59)) ([fedcf06](https://github.com/feathersjs/feathers/commit/fedcf06))\n- **package:** update debug to version 3.0.0 ([#61](https://github.com/feathersjs/feathers/issues/61)) ([6f5009c](https://github.com/feathersjs/feathers/commit/6f5009c))\n- **package:** update debug to version 3.0.0 ([#83](https://github.com/feathersjs/feathers/issues/83)) ([49f1de9](https://github.com/feathersjs/feathers/commit/49f1de9))\n- **package:** update debug to version 3.0.0 ([#86](https://github.com/feathersjs/feathers/issues/86)) ([fd1bb6b](https://github.com/feathersjs/feathers/commit/fd1bb6b))\n- **package:** update debug to version 3.0.1 ([#46](https://github.com/feathersjs/feathers/issues/46)) ([f8ada69](https://github.com/feathersjs/feathers/commit/f8ada69))\n- **package:** update generator-feathers to version 1.0.3 ([#81](https://github.com/feathersjs/feathers/issues/81)) ([0c66bc5](https://github.com/feathersjs/feathers/commit/0c66bc5))\n- **package:** update generator-feathers to version 1.0.5 ([#83](https://github.com/feathersjs/feathers/issues/83)) ([229caba](https://github.com/feathersjs/feathers/commit/229caba))\n- **package:** update generator-feathers to version 1.0.6 ([#86](https://github.com/feathersjs/feathers/issues/86)) ([7ae8e56](https://github.com/feathersjs/feathers/commit/7ae8e56))\n- **package:** update generator-feathers to version 1.1.0 ([#93](https://github.com/feathersjs/feathers/issues/93)) ([f393e4c](https://github.com/feathersjs/feathers/commit/f393e4c))\n- **package:** update generator-feathers to version 1.1.1 ([#95](https://github.com/feathersjs/feathers/issues/95)) ([3279ba9](https://github.com/feathersjs/feathers/commit/3279ba9))\n- **package:** update generator-feathers to version 1.2.0 ([#96](https://github.com/feathersjs/feathers/issues/96)) ([8eb5674](https://github.com/feathersjs/feathers/commit/8eb5674))\n- **package:** update generator-feathers to version 1.2.10 ([#115](https://github.com/feathersjs/feathers/issues/115)) ([c1db2b2](https://github.com/feathersjs/feathers/commit/c1db2b2))\n- **package:** update generator-feathers to version 1.2.11 ([#116](https://github.com/feathersjs/feathers/issues/116)) ([bba6550](https://github.com/feathersjs/feathers/commit/bba6550))\n- **package:** update generator-feathers to version 1.2.12 ([#119](https://github.com/feathersjs/feathers/issues/119)) ([e5c737d](https://github.com/feathersjs/feathers/commit/e5c737d))\n- **package:** update generator-feathers to version 1.2.2 ([#98](https://github.com/feathersjs/feathers/issues/98)) ([ee629e3](https://github.com/feathersjs/feathers/commit/ee629e3)), closes [#97](https://github.com/feathersjs/feathers/issues/97)\n- **package:** update generator-feathers to version 1.2.3 ([#99](https://github.com/feathersjs/feathers/issues/99)) ([b6cf361](https://github.com/feathersjs/feathers/commit/b6cf361))\n- **package:** update generator-feathers to version 1.2.4 ([#101](https://github.com/feathersjs/feathers/issues/101)) ([2182fef](https://github.com/feathersjs/feathers/commit/2182fef))\n- **package:** update generator-feathers to version 1.2.5 ([#104](https://github.com/feathersjs/feathers/issues/104)) ([295f6aa](https://github.com/feathersjs/feathers/commit/295f6aa))\n- **package:** update generator-feathers to version 1.2.6 ([#106](https://github.com/feathersjs/feathers/issues/106)) ([66125dc](https://github.com/feathersjs/feathers/commit/66125dc))\n- **package:** update generator-feathers to version 1.2.9 ([#110](https://github.com/feathersjs/feathers/issues/110)) ([17e55dc](https://github.com/feathersjs/feathers/commit/17e55dc))\n- **package:** update generator-feathers to version 2.0.0 ([#126](https://github.com/feathersjs/feathers/issues/126)) ([eff6627](https://github.com/feathersjs/feathers/commit/eff6627))\n- **package:** update generator-feathers to version 2.1.0 ([#128](https://github.com/feathersjs/feathers/issues/128)) ([b712355](https://github.com/feathersjs/feathers/commit/b712355))\n- **package:** update generator-feathers to version 2.1.1 ([#129](https://github.com/feathersjs/feathers/issues/129)) ([1f91c0b](https://github.com/feathersjs/feathers/commit/1f91c0b))\n- **package:** update generator-feathers to version 2.2.0 ([#130](https://github.com/feathersjs/feathers/issues/130)) ([308ad0b](https://github.com/feathersjs/feathers/commit/308ad0b))\n- **package:** update generator-feathers to version 2.3.0 ([#131](https://github.com/feathersjs/feathers/issues/131)) ([7894807](https://github.com/feathersjs/feathers/commit/7894807))\n- **package:** update generator-feathers to version 2.3.1 ([#132](https://github.com/feathersjs/feathers/issues/132)) ([c3e3187](https://github.com/feathersjs/feathers/commit/c3e3187))\n- **package:** update generator-feathers to version 2.4.0 ([#137](https://github.com/feathersjs/feathers/issues/137)) ([1645d2e](https://github.com/feathersjs/feathers/commit/1645d2e))\n- **package:** update generator-feathers to version 2.4.1 ([#140](https://github.com/feathersjs/feathers/issues/140)) ([e5a5f7c](https://github.com/feathersjs/feathers/commit/e5a5f7c))\n- **package:** update generator-feathers to version 2.4.4 ([#151](https://github.com/feathersjs/feathers/issues/151)) ([3dcd480](https://github.com/feathersjs/feathers/commit/3dcd480))\n- **package:** update generator-feathers to version 2.5.2 ([#155](https://github.com/feathersjs/feathers/issues/155)) ([493ca4b](https://github.com/feathersjs/feathers/commit/493ca4b))\n- **package:** update generator-feathers to version 2.5.3 ([#156](https://github.com/feathersjs/feathers/issues/156)) ([ef570a8](https://github.com/feathersjs/feathers/commit/ef570a8))\n- **package:** update generator-feathers to version 2.5.4 ([#158](https://github.com/feathersjs/feathers/issues/158)) ([787f30c](https://github.com/feathersjs/feathers/commit/787f30c))\n- **package:** update generator-feathers to version 2.5.5 ([#159](https://github.com/feathersjs/feathers/issues/159)) ([bbd1b29](https://github.com/feathersjs/feathers/commit/bbd1b29))\n- **package:** update generator-feathers to version 2.5.6 ([#161](https://github.com/feathersjs/feathers/issues/161)) ([cb72a5c](https://github.com/feathersjs/feathers/commit/cb72a5c))\n- **package:** update generator-feathers to version 2.6.0 ([#164](https://github.com/feathersjs/feathers/issues/164)) ([6212ec9](https://github.com/feathersjs/feathers/commit/6212ec9))\n- **package:** update generator-feathers-plugin to version 0.11.0 ([#105](https://github.com/feathersjs/feathers/issues/105)) ([d40bb75](https://github.com/feathersjs/feathers/commit/d40bb75))\n- **package:** update generator-feathers-plugin to version 0.12.1 ([#112](https://github.com/feathersjs/feathers/issues/112)) ([f374e01](https://github.com/feathersjs/feathers/commit/f374e01))\n- **package:** update generator-feathers-plugin to version 1.0.0 ([#134](https://github.com/feathersjs/feathers/issues/134)) ([ee905b0](https://github.com/feathersjs/feathers/commit/ee905b0))\n- **package:** update jsonwebtoken to version 8.0.0 ([#567](https://github.com/feathersjs/feathers/issues/567)) ([6811626](https://github.com/feathersjs/feathers/commit/6811626))\n- **package:** update ms to version 2.0.0 ([#509](https://github.com/feathersjs/feathers/issues/509)) ([7e4b0b6](https://github.com/feathersjs/feathers/commit/7e4b0b6))\n- **package:** update passport to version 0.4.0 ([#558](https://github.com/feathersjs/feathers/issues/558)) ([dcb14a5](https://github.com/feathersjs/feathers/commit/dcb14a5))\n- **package:** update passport-jwt to version 4.0.0 ([#58](https://github.com/feathersjs/feathers/issues/58)) ([77a3800](https://github.com/feathersjs/feathers/commit/77a3800))\n- **package:** update socket.io to version 2.0.0 ([#75](https://github.com/feathersjs/feathers/issues/75)) ([d4a4b71](https://github.com/feathersjs/feathers/commit/d4a4b71))\n- **package:** update yeoman-environment to version 2.0.0 ([#89](https://github.com/feathersjs/feathers/issues/89)) ([2355652](https://github.com/feathersjs/feathers/commit/2355652))\n- **package:** update yeoman-generator to version 2.0.0 ([#279](https://github.com/feathersjs/feathers/issues/279)) ([4f38e8b](https://github.com/feathersjs/feathers/commit/4f38e8b))\n- **package:** update yeoman-generator to version 2.0.0 ([#46](https://github.com/feathersjs/feathers/issues/46)) ([7071095](https://github.com/feathersjs/feathers/commit/7071095))\n- **package:** update yeoman-generator to version 3.0.0 ([#374](https://github.com/feathersjs/feathers/issues/374)) ([acdbbca](https://github.com/feathersjs/feathers/commit/acdbbca))\n\n### chore\n\n- **package:** Move adapter tests into their own module ([#1164](https://github.com/feathersjs/feathers/issues/1164)) ([dcc1e6b](https://github.com/feathersjs/feathers/commit/dcc1e6b))\n- drop support for Node.js 0.10 ([#48](https://github.com/feathersjs/feathers/issues/48)) ([3f7555a](https://github.com/feathersjs/feathers/commit/3f7555a))\n\n### Features\n\n- @feathers/cli: introduce option to choose jest for tests instead of mocha ([#1057](https://github.com/feathersjs/feathers/issues/1057)) ([1356a1c](https://github.com/feathersjs/feathers/commit/1356a1c))\n- @feathersjs/authentication-oauth ([#1299](https://github.com/feathersjs/feathers/issues/1299)) ([656bae7](https://github.com/feathersjs/feathers/commit/656bae7))\n- Add authentication through oAuth redirect to authentication client ([#1301](https://github.com/feathersjs/feathers/issues/1301)) ([35d8043](https://github.com/feathersjs/feathers/commit/35d8043))\n- Add AuthenticationBaseStrategy and make authentication option handling more explicit ([#1284](https://github.com/feathersjs/feathers/issues/1284)) ([2667d92](https://github.com/feathersjs/feathers/commit/2667d92))\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Added generators for feathers-objection & feathers-cassandra ([#1010](https://github.com/feathersjs/feathers/issues/1010)) ([c8b27d0](https://github.com/feathersjs/feathers/commit/c8b27d0))\n- Allow registering a service at the root level ([#1115](https://github.com/feathersjs/feathers/issues/1115)) ([c73d322](https://github.com/feathersjs/feathers/commit/c73d322))\n- Allow to skip sending service events ([#1270](https://github.com/feathersjs/feathers/issues/1270)) ([b487bbd](https://github.com/feathersjs/feathers/commit/b487bbd))\n- Authentication v3 client ([#1240](https://github.com/feathersjs/feathers/issues/1240)) ([65b43bd](https://github.com/feathersjs/feathers/commit/65b43bd))\n- Authentication v3 core server implementation ([#1205](https://github.com/feathersjs/feathers/issues/1205)) ([1bd7591](https://github.com/feathersjs/feathers/commit/1bd7591))\n- Authentication v3 Express integration ([#1218](https://github.com/feathersjs/feathers/issues/1218)) ([82bcfbe](https://github.com/feathersjs/feathers/commit/82bcfbe))\n- Authentication v3 local authentication ([#1211](https://github.com/feathersjs/feathers/issues/1211)) ([0fa5f7c](https://github.com/feathersjs/feathers/commit/0fa5f7c))\n- Common database adapter utilities and test suite ([#1130](https://github.com/feathersjs/feathers/issues/1130)) ([17b3dc8](https://github.com/feathersjs/feathers/commit/17b3dc8))\n- Make custom query for oAuth authentication ([#1124](https://github.com/feathersjs/feathers/issues/1124)) ([5d43e3c](https://github.com/feathersjs/feathers/commit/5d43e3c))\n- Remove (hook, next) signature and SKIP support ([#1269](https://github.com/feathersjs/feathers/issues/1269)) ([211c0f8](https://github.com/feathersjs/feathers/commit/211c0f8))\n- Support params symbol to skip authenticate hook ([#1296](https://github.com/feathersjs/feathers/issues/1296)) ([d16cf4d](https://github.com/feathersjs/feathers/commit/d16cf4d))\n\n### BREAKING CHANGES\n\n- Rewrite for authentication v3\n- Update authentication strategies for @feathersjs/authentication v3\n- **package:** Removes adapter tests from @feathersjs/adapter-commons\n- Move database adapter utilities from @feathersjs/commons into its own module\n- This module no longer supports Node.js 0.10\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "<a href=\"https://feathersjs.com\" title=\"FeathersJS\">\n  <img src=\"https://feathersjs.com/og.png\" alt=\"Feathers - The API and real-time application framework\">\n</a>\n\n---\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/feathers.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/feathers)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\nFeathers is a full-stack framework for creating web APIs and real-time applications with TypeScript or JavaScript.\n\nFeathers can interact with any backend technology, supports many databases out of the box and works with any frontend like React, VueJS, Angular, React Native, Android or iOS.\n\n# Getting started\n\nGet started with just three commands:\n\n```bash\n$ npm create feathers my-new-app\n$ cd my-new-app\n$ npm run dev\n```\n\nTo learn more about Feathers visit the website at [feathersjs.com](http://feathersjs.com) or jump right into [the Feathers guides](https://feathersjs.com/guides/).\n\n# Contributing\n\nTo start developing, clone this repository, then run:\n\n```\ncd feathers\nnpm install\n```\n\nTo run all tests run\n\n```\nnpm test\n```\n\nIndividual tests can be run in the module you are working on:\n\n```\ncd packages/feathers\nnpm test\n```\n\n# License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "docs/.vitepress/components/Badges.vue",
    "content": "<script setup lang=\"ts\">\n// A style wrapper to make npm badges do flex-row.\n</script>\n\n<template>\n  <div class=\"badges\"><slot /></div>\n</template>\n\n<style lang=\"postcss\">\n/* For npm and changelog badges */\n.badges p {\n  @apply flex flex-row;\n}\n.badges img {\n  margin-right: .5em\n}\n</style>\n"
  },
  {
    "path": "docs/.vitepress/components/BlockQuote.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nconst props = defineProps({\n  // Can be tip, info, warning, danger, or details\n  type: { type: String, default: 'tip' },\n  label: { type: String },\n})\nconst outerTag = computed(() => (props.type === 'details' ? 'details' : 'div'))\nconst labelTag = computed(() => (props.type === 'details' ? 'summary' : 'p'))\n</script>\n\n<template>\n  <component :is=\"outerTag\" class=\"custom-block\" :class=\"type\">\n    <component\n      :is=\"labelTag\"\n      class=\"custom-block-title\"\n      :class=\"type === 'details' ? 'capitalize' : 'uppercase'\"\n    >\n      {{ label || type }}\n    </component>\n    <slot />\n  </component>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/components/Contributors.vue",
    "content": "<script setup lang=\"ts\">\nimport { contributors } from '../contributors'\n</script>\n\n<template>\n  <div flex=\"~ wrap gap2\" justify-center>\n    <a v-for=\"{ name, avatar } of contributors\" :key=\"name\" :href=\"`https://github.com/${name}`\" m-0 rel=\"noopener noreferrer\" :aria-label=\"`${name} on GitHub`\">\n      <img loading=\"lazy\" :src=\"avatar\" width=\"50\" height=\"50\" rounded-full h-12 w-12 :alt=\"`${name}'s avatar`\">\n    </a>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/components/DatabaseBlock.vue",
    "content": "<script setup lang=\"ts\">\nimport { useGlobalDb } from '../theme/store'\n\ndefineProps({\n  globalId: String,\n  inline: String\n})\n\nconst activeGlobalDb = useGlobalDb()\n</script>\n\n<template>\n  <component :is=\"inline ? 'span' : 'div'\" :class=\"{ hidden: globalId !== activeGlobalDb }\">\n    <slot />\n  </component>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/components/DatabaseSelect.vue",
    "content": "<script setup lang=\"ts\">\nimport { useGlobalDb } from '../theme/store'\nimport Select from './Select.vue'\n\nconst activeGlobalDb = useGlobalDb()\n\nconst handleGlobalDbUpdate = (val: string) => {\n  if (activeGlobalDb.value !== val) {\n    activeGlobalDb.value = val\n    document.body.setAttribute('data-db', val)\n  }\n}\n</script>\n\n<template>\n  <Select\n    id=\"GlobalDbSelect\"\n    :value=\"activeGlobalDb\"\n    label=\"Database\"\n    :options=\"[\n      { value: 'sql', text: 'SQL' },\n      { value: 'mongodb', text: 'MongoDB' }\n    ]\"\n    @update-value=\"handleGlobalDbUpdate\"\n  />\n</template>\n"
  },
  {
    "path": "docs/.vitepress/components/FeaturesList.vue",
    "content": "<template>\n  <ul\n    class=\"features-list\"\n    dir=\"auto\"\n    flex=\"~ col gap2 md:gap-3\"\n  >\n    <ListItem><a target=\"_blank\" href=\"https://vitejs.dev\" rel=\"noopener noreferrer\">Vite</a>'s config, transformers, resolvers, and plugins.</ListItem>\n    <ListItem>Use the same setup from your app to run the tests!</ListItem>\n    <ListItem><a target=\"_blank\" href=\"https://twitter.com/antfu7/status/1468233216939245579\" rel=\"noopener noreferrer\">Smart & instant watch mode, like HMR for tests!</a></ListItem>\n    <ListItem>Components testing for Vue, React, Svelte, Lit and more</ListItem>\n    <ListItem>Out-of-box TypeScript / JSX support</ListItem>\n    <ListItem>ESM first, top level await</ListItem>\n    <ListItem>Workers multi-threading via <a target=\"_blank\" href=\"https://github.com/Aslemammad/tinypool\" rel=\"noopener noreferrer\">tinypool</a></ListItem>\n    <ListItem>Filtering, timeouts, concurrent for suite and tests</ListItem>\n    <ListItem><a target=\"_blank\" href=\"https://jestjs.io/docs/snapshot-testing\" rel=\"noopener noreferrer\">Jest Snapshot</a></ListItem>\n    <ListItem><a target=\"_blank\" href=\"https://www.chaijs.com/\" rel=\"noopener noreferrer\">Chai</a> built-in for assertions + <a target=\"_blank\" href=\"https://jestjs.io/docs/expect\" rel=\"noopener noreferrer\">Jest expect</a> compatible APIs</ListItem>\n    <ListItem><a target=\"_blank\" href=\"https://github.com/Aslemammad/tinyspy\" rel=\"noopener noreferrer\">Tinyspy</a> built-in for mocking</ListItem>\n    <ListItem><a target=\"_blank\" href=\"https://github.com/capricorn86/happy-dom\" rel=\"noopener noreferrer\">happy-dom</a> or <a target=\"_blank\" href=\"https://github.com/jsdom/jsdom\" rel=\"noopener noreferrer\">jsdom</a> for DOM mocking</ListItem>\n    <ListItem>Native code coverage via <a target=\"_blank\" href=\"https://github.com/bcoe/c8\" rel=\"noopener noreferrer\">c8</a></ListItem>\n    <ListItem>Rust like <a href=\"/guide/in-source\">in-source testing</a></ListItem>\n  </ul>\n</template>\n\n<style scoped>\n.features-list li {\n  list-style: none;\n  display: flex;\n  gap: 0.4rem;\n  margin: 0;\n}\n\n.features-list {\n  padding: 0;\n}\n</style>\n"
  },
  {
    "path": "docs/.vitepress/components/LanguageBlock.vue",
    "content": "<script setup lang=\"ts\">\nimport { useGlobalLanguage } from '../theme/store'\n\ndefineProps({\n  globalId: String,\n  inline: String\n})\n\nconst activeGlobalId = useGlobalLanguage()\n</script>\n\n<template>\n  <component :is=\"inline ? 'span' : 'div'\" :class=\"{ hidden: globalId !== activeGlobalId }\">\n    <slot />\n  </component>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/components/LanguageSelect.vue",
    "content": "<script setup lang=\"ts\">\nimport { useGlobalLanguage } from '../theme/store'\nimport Select from './Select.vue'\n\nconst activeGlobalLanguage = useGlobalLanguage()\n\nconst handleGlobalLanguageUpdate = (val: string) => {\n  activeGlobalLanguage.value = val\n  document.body.setAttribute('data-language', val)\n}\n</script>\n\n<template>\n  <Select\n    id=\"GlobalLanguageSelect\"\n    :value=\"activeGlobalLanguage\"\n    label=\"Code Language\"\n    :options=\"[\n      { value: 'ts', text: 'TypeScript' },\n      { value: 'js', text: 'JavaScript' }\n    ]\"\n    @update-value=\"handleGlobalLanguageUpdate\"\n  />\n</template>\n"
  },
  {
    "path": "docs/.vitepress/components/ListItem.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed, effectScope, onMounted, ref } from 'vue'\nimport { until, useElementVisibility } from '@vueuse/core'\n\nconst el = ref()\nconst state = ref(0)\n\nfunction reset() {\n  state.value = 0\n  setTimeout(() => {\n    state.value = Math.random() > 0.9 ? 2 : 1\n    if (state.value === 2)\n      setTimeout(reset, 1000)\n  }, Math.round(Math.random() * 3000) + 400)\n}\n\nconst color = computed(() => {\n  return {\n    '--c-brand': state.value === 1\n      ? 'rgba(74,222,128,1)'\n      : state.value === 2\n        ? 'rgba(248, 113, 113)'\n        : 'rgba(250, 204, 21)',\n  } as any\n})\n\nconst scope = effectScope()\n\nconst visibility = scope.run(() => useElementVisibility(el))\n\nonMounted(async () => {\n  await until(visibility).toBe(true)\n\n  scope.stop()\n  reset()\n})\n</script>\n\n<template>\n  <li :style=\"color\">\n    <div\n      ref=\"el\"\n      relative\n      m=\"ya r-1\"\n      w-5\n      h-5\n      flex-none\n      align-mid\n    >\n      <div absolute transition duration-300 :class=\"state ? 'flip' : ''\">\n        <div i-carbon:circle-dash animate-spin animate-2s text-yellow4 />\n      </div>\n      <div absolute transition duration-300 :class=\"state === 1 ? '' : 'flip'\">\n        <div i-carbon:checkmark-outline class=\"text-$vp-c-brand\" />\n      </div>\n      <div absolute transition duration-300 :class=\"state === 2 ? '' : 'flip'\">\n        <div i-carbon:close-outline text-red4 />\n      </div>\n    </div>\n    <div>\n      <slot />\n    </div>\n  </li>\n</template>\n\n<style>\n.flip {\n  transform: rotateY(90deg);\n}\n</style>\n"
  },
  {
    "path": "docs/.vitepress/components/Logo.vue",
    "content": "<template>\n  <svg\n    class=\"feathers-logo\"\n    viewBox=\"0 0 256 256\"\n    version=\"1.1\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n    preserveAspectRatio=\"xMidYMid\"\n  >\n    <g>\n      <path\n        d=\"M128,9.102 C193.665,9.102 246.898,62.335 246.898,128 C246.898,193.665 193.665,246.898 128,246.898 C62.335,246.898 9.102,193.665 9.102,128 C9.102,62.335 62.335,9.102 128,9.102 M128,0 C57.421,0 0,57.421 0,128 C0,198.579 57.421,256 128,256 C198.579,256 256,198.579 256,128 C256,57.421 198.579,0 128,0 M148.83,25.524 C138.4,23.628 113.179,61.933 104.836,85.258 C104.202,87.027 102.75,93.507 102.75,95.213 C102.75,95.213 109.281,109.268 111.093,112.564 C108.059,110.984 101.77,98.808 101.77,98.808 C98.736,104.592 95.828,131.148 96.776,136.079 C96.776,136.079 103.538,146.141 106.163,148.657 C102.56,147.456 96.492,139.302 96.492,139.302 C95.354,142.81 95.576,150.109 96.113,152.576 C100.664,159.213 106.732,159.972 106.732,159.972 C106.732,159.972 100.095,226.153 110.145,231.083 C116.403,229.756 117.92,157.127 117.92,157.127 C117.92,157.127 125.505,157.696 127.212,155.8 C131.068,153.145 140.038,125.576 140.17,121.598 C140.17,121.598 129.76,123.55 124.683,125.522 C128.509,121.722 140.732,119.17 140.732,119.17 C144.047,115.191 151.023,88.123 151.726,79.779 C151.902,77.686 152.309,75.122 151.994,71.381 C151.994,71.381 142.053,73.558 139.98,72.805 C142.084,72.568 152.243,68.665 152.243,68.665 C154.044,52.452 154.601,26.574 148.83,25.524 L148.83,25.524 Z M112.45,197.215 C111.655,216.711 111.156,222.219 110.335,226.816 C109.956,227.673 109.577,227.813 109.197,226.721 C105.72,210.729 105.973,90.283 145.606,35.48 C122.556,77.572 112.071,158.341 112.45,197.215 L112.45,197.215 Z\"\n        fill=\"currentColor\"\n      ></path>\n    </g>\n  </svg>\n</template>\n\n<style lang=\"postcss\">\n.dark .feathers-logo {\n  @apply invert-1;\n}\n</style>\n"
  },
  {
    "path": "docs/.vitepress/components/Select.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed, onMounted, watch, ref } from 'vue'\nimport { useRoute } from 'vitepress'\n\ninterface Props {\n  value: string\n  label: string\n  options: Array<{ value: string; text: string }>\n  showOnRoutePrefix?: string[]\n  hideOnMobile?: boolean\n  hideLabel?: boolean\n}\nconst props = defineProps<Props>()\nconst emit = defineEmits(['updateValue'])\n\nconst route = useRoute()\nconst isVisible = ref(true)\n\nconst updateAttribute = (value: string) => {\n  emit('updateValue', value)\n}\n\nconst valueProxy = computed({\n  get: () => props.value,\n  set: (val: string) => {\n    updateAttribute(val)\n  }\n})\n\nonMounted(() => {\n  updateAttribute(props.value)\n  watch(\n    () => route.path,\n    (val) => {\n      const prefixes = props.showOnRoutePrefix\n      if (prefixes?.length) {\n        const shouldShow = !!prefixes.find((p: string) => route.path.includes(p))\n        isVisible.value = shouldShow\n      }\n    },\n    { immediate: true }\n  )\n})\n</script>\n\n<template>\n  <div\n    class=\"transition-all duration-400 overflow-hidden\"\n    :class=\"{ 'hidden lg:block': hideOnMobile, 'max-h-20': isVisible, 'max-h-0': !isVisible }\"\n  >\n    <label>\n      <span v-if=\"!hideLabel\" class=\"language-select-label text-sm font-bold block pt-2\">{{ label }}</span>\n      <div class=\"relative\">\n        <select\n          v-model=\"valueProxy\"\n          class=\"language-select w-full border border-black/10 pl-3 py-1.5 bg-base-100 pr-10 font-semibold transition duration-200 ease-in-out rounded-md\"\n        >\n          <option v-for=\"option in options\" :key=\"option.value\" :value=\"option.value\">\n            {{ option.text }}\n          </option>\n        </select>\n        <div class=\"i-carbon-chevron-down absolute right-1.5 top-2.5\" />\n      </div>\n    </label>\n  </div>\n</template>\n\n<style lang=\"postcss\">\n.language-select-label {\n  color: var(--vp-c-text-1);\n}\n</style>\n"
  },
  {
    "path": "docs/.vitepress/components/Tab.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed, inject } from 'vue'\n\nconst props = defineProps({\n  name: String,\n  globalId: String,\n})\n\nconst { addTab, activeIndex, showTabs }: any = inject('tab-state')\n\nconst index = addTab({\n  name: props.name,\n  globalId: props.globalId,\n})\n\nconst isActive = computed(() => {\n  return index === activeIndex.value\n})\n</script>\n\n<template>\n  <div v-if=\"isActive\" class=\"tab relative\">\n    <div\n      v-if=\"!showTabs && !hideLabel\"\n      class=\"tab-label bg-neutral text-neutral-content inline-block text-xs px-2.5 py-1 rounded-t-md\"\n    >\n      {{ name }}\n    </div>\n    <div class=\"z-0\">\n      <slot></slot>\n    </div>\n  </div>\n</template>\n\n<style>\n.tab {\n  @apply pt-6;\n}\n.tab-label {\n  @apply absolute z-10 top-0;\n}\n.tab div[class*='language-']:first-child {\n  @apply -mt-0.25;\n}\n</style>\n"
  },
  {
    "path": "docs/.vitepress/components/Tabs.vue",
    "content": "<script setup lang=\"ts\">\nimport { ref, watch, provide } from \"vue\"\nimport { useStorage } from \"@vueuse/core\"\nimport { useGlobalLanguage } from \"../theme/store\"\n\nconst props = defineProps({\n  groupName: String,\n  showTabs: Boolean,\n})\n\n// Tabs\nconst tabs = ref<any[]>([])\nconst addTab = (tabData: any) => {\n  const existingIndex = tabs.value.findIndex((t) => t.name === tabData.name)\n  return existingIndex !== -1 ? existingIndex : tabs.value.push(tabData) - 1\n}\n\n// Active Tab\nconst activeIndex: any = useStorage(props.groupName as string, 0)\nconst setActiveTab = (index: number) => {\n  const tab = tabs.value[index]\n  activeIndex.value = index\n  // Update the globalId to sync tabs.\n  // if (tab.globalId) activeGlobalId.value = tab.globalId\n}\n\nprovide(\"tab-state\", { addTab, activeIndex, showTabs: props.showTabs })\n\n// Global ID\nconst activeGlobalId = useGlobalLanguage()\nwatch(activeGlobalId, (id) => {\n  const matchingTabIndex = tabs.value.findIndex((t) => t.globalId === id)\n  if (matchingTabIndex != -1) activeIndex.value = matchingTabIndex\n})\n</script>\n\n<template>\n  <div class=\"tabs mt-10 mb-8\">\n    <div v-if=\"showTabs\" class=\"flex flex-row\">\n      <button\n        type=\"button\"\n        v-for=\"(tab, index) in tabs\"\n        :key=\"tab.name\"\n        class=\"py-1.5 px-3\"\n        :class=\"{\n          'active text-white bg-neutral': index === activeIndex,\n          'bg-neutral/20': index !== activeIndex,\n          'rounded-l-lg': index === 0,\n          'rounded-r-lg': index === tabs.length - 1,\n        }\"\n        @click=\"() => setActiveTab(index)\"\n      >\n        {{ tab.name }}\n      </button>\n    </div>\n\n    <slot />\n  </div>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/components/TeamMember.vue",
    "content": "<script setup lang=\"ts\">\nimport type { CoreTeam } from '../contributors'\n\ndefineProps<{\n  avatar: CoreTeam['avatar']\n  name: CoreTeam['name']\n  github: CoreTeam['github']\n  twitter: CoreTeam['twitter']\n  sponsors: CoreTeam['sponsors']\n  description: CoreTeam['description']\n}>()\n</script>\n\n<template>\n  <div text-left flex=\"~ row gap6\" relative>\n    <img\n      loading=\"lazy\"\n      width=\"100\" height=\"100\"\n      rounded-full min-w-25 min-h-25 h-25 w-25\n      inline-block\n      :src=\"avatar\"\n      :alt=\"`${name}'s avatar`\"\n    >\n    <div flex=\"~ col gap2\">\n      <div text-2xl>\n        {{ name }}\n      </div>\n      <div op60 v-html=\"description\" />\n      <div flex=\"~ inline gap-2\" text-2xl>\n        <a\n          class=\"i-carbon-logo-github inline-block !text-current op30 hover:op100 mya transition duration-200\"\n          :href=\"`https://github.com/${github}`\"\n          target=\"_blank\"\n          rel=\"noopener noreferrer\"\n          :aria-label=\"`${name} on GitHub`\"\n        />\n        <a\n          v-if=\"twitter\"\n          class=\"i-carbon-logo-twitter inline-block text-1.3em mya !text-current op30 hover:op100 transition duration-200\"\n          :href=\"`https://twitter.com/${twitter}`\"\n          target=\"_blank\"\n          rel=\"noopener noreferrer\"\n          :aria-label=\"`${name} on Twitter`\"\n        />\n      </div>\n    </div>\n    <a\n      v-if=\"sponsors\"\n      class=\"btn bg-pink-500 hover:bg-pink-600 text-sm !text-white px3 absolute bottom-2 right-1\"\n      flex=\"~ row gap-2\"\n      target=\"_blank\"\n      rel=\"noopener noreferrer\"\n      :href=\"`https://github.com/sponsors/${github}`\"\n    >\n      <span class=\"i-carbon-favorite-filled\" />\n      Sponsor\n    </a>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/.vitepress/components.d.ts",
    "content": "/* eslint-disable */\n// @ts-nocheck\n// biome-ignore lint: disable\n// oxlint-disable\n// ------\n// Generated by unplugin-vue-components\n// Read more: https://github.com/vuejs/core/pull/3399\n\nexport {}\n\n/* prettier-ignore */\ndeclare module 'vue' {\n  export interface GlobalComponents {\n    Badges: typeof import('./components/Badges.vue')['default']\n    BlockQuote: typeof import('./components/BlockQuote.vue')['default']\n    Contributors: typeof import('./components/Contributors.vue')['default']\n    DatabaseBlock: typeof import('./components/DatabaseBlock.vue')['default']\n    DatabaseSelect: typeof import('./components/DatabaseSelect.vue')['default']\n    ElCheckbox: typeof import('element-plus/es')['ElCheckbox']\n    ElInput: typeof import('element-plus/es')['ElInput']\n    ElOption: typeof import('element-plus/es')['ElOption']\n    ElRadio: typeof import('element-plus/es')['ElRadio']\n    ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']\n    ElSelect: typeof import('element-plus/es')['ElSelect']\n    FeaturesList: typeof import('./components/FeaturesList.vue')['default']\n    LanguageBlock: typeof import('./components/LanguageBlock.vue')['default']\n    LanguageSelect: typeof import('./components/LanguageSelect.vue')['default']\n    ListItem: typeof import('./components/ListItem.vue')['default']\n    Logo: typeof import('./components/Logo.vue')['default']\n    Select: typeof import('./components/Select.vue')['default']\n    Tab: typeof import('./components/Tab.vue')['default']\n    Tabs: typeof import('./components/Tabs.vue')['default']\n    TeamMember: typeof import('./components/TeamMember.vue')['default']\n  }\n}\n"
  },
  {
    "path": "docs/.vitepress/config.nav.ts",
    "content": "import { releases } from './meta'\n// import { version } from '../package.json'\n\nconst version = 5\n\nexport default [\n  { text: 'Guides', link: '/guides/' },\n  { text: 'API', link: '/api/' },\n  { text: 'Help', link: '/help/' },\n  {\n    text: `v${version}`,\n    items: [\n      {\n        text: 'Release Notes ',\n        link: releases\n      },\n      {\n        text: 'Crow v4 ',\n        link: 'https://crow.docs.feathersjs.com'\n      },\n      {\n        text: 'Buzzard v3 ',\n        link: 'https://buzzard.docs.feathersjs.com'\n      }\n    ]\n  },\n  {\n    text: 'Ecosystem',\n    link: '/ecosystem/'\n  }\n]\n"
  },
  {
    "path": "docs/.vitepress/config.sidebar.ts",
    "content": "const comparisonSidebar = [\n  {\n    text: 'Compare Feathers',\n    items: [\n      {\n        text: 'Overview',\n        link: '/comparison'\n      },\n      {\n        text: 'Feathers vs Firebase',\n        link: '/feathers-vs-firebase'\n      },\n      {\n        text: 'Feathers vs Meteor',\n        link: '/feathers-vs-meteor'\n      },\n      {\n        text: 'Feathers vs Sails',\n        link: '/feathers-vs-sails'\n      },\n      {\n        text: 'Feathers vs Loopback',\n        link: '/feathers-vs-loopback'\n      }\n    ]\n  }\n]\n\nexport default {\n  '/guides': [\n    {\n      text: 'Getting Started',\n      collapsible: true,\n      items: [\n        {\n          text: 'Quick start',\n          link: '/guides/basics/starting.md'\n        },\n        {\n          text: 'Creating an app',\n          link: '/guides/basics/generator.md'\n        },\n        {\n          text: 'Authentication',\n          link: '/guides/basics/authentication.md'\n        },\n        {\n          text: 'Services',\n          link: '/guides/basics/services.md'\n        },\n        {\n          text: 'Hooks',\n          link: '/guides/basics/hooks.md'\n        },\n        {\n          text: 'Schemas',\n          link: '/guides/basics/schemas.md'\n        },\n        {\n          text: 'Logging in',\n          link: '/guides/basics/login.md'\n        }\n        // {\n        //   text: 'Writing Tests',\n        //   link: '/guides/basics/testing.md'\n        // }\n      ]\n    },\n    {\n      text: 'Frontend',\n      collapsible: true,\n      collapsed: false,\n      items: [\n        {\n          text: 'JavaScript',\n          link: '/guides/frontend/javascript.md'\n        }\n        // {\n        //   text: 'Frontend Frameworks',\n        //   link: '/guides/frameworks.md'\n        // }\n      ]\n    },\n    {\n      text: 'CLI',\n      collapsible: true,\n      collapsed: true,\n      items: [\n        {\n          text: '📖 Readme',\n          link: '/guides/cli/index.md'\n        },\n        {\n          text: '📂 config',\n          items: [\n            {\n              text: '📄 default.json',\n              link: '/guides/cli/default.json.md'\n            },\n            {\n              text: '📄 custom-environment-variables.json',\n              link: '/guides/cli/custom-environment-variables.md'\n            }\n          ]\n        },\n        {\n          text: '📂 src',\n          items: [\n            {\n              text: '📂 hooks',\n              items: [\n                {\n                  text: '📄 &lt;hook&gt;',\n                  link: '/guides/cli/hook.md'\n                },\n                {\n                  text: '📄 log-error',\n                  link: '/guides/cli/log-error.md'\n                }\n              ]\n            },\n            {\n              text: '📂 services',\n              items: [\n                {\n                  text: '📂 &lt;service&gt;',\n                  items: [\n                    {\n                      text: '📄 &lt;service&gt;',\n                      link: '/guides/cli/service.md'\n                    },\n                    {\n                      text: '📄 &lt;service&gt;.class',\n                      link: '/guides/cli/service.class.md'\n                    },\n                    {\n                      text: '📄 &lt;service&gt;.schemas',\n                      link: '/guides/cli/service.schemas.md'\n                    },\n                    {\n                      text: '📄 &lt;service&gt;.shared',\n                      link: '/guides/cli/service.shared.md'\n                    }\n                  ]\n                }\n              ]\n            },\n            {\n              text: '📄 app',\n              link: '/guides/cli/app.md'\n            },\n            {\n              text: '📄 authentication',\n              link: '/guides/cli/authentication.md'\n            },\n            {\n              text: '📄 channels',\n              link: '/guides/cli/channels.md'\n            },\n            {\n              text: '📄 client',\n              link: '/guides/cli/client.md'\n            },\n            {\n              text: '📄 configuration',\n              link: '/guides/cli/configuration.md'\n            },\n            {\n              text: '📄 declarations',\n              link: '/guides/cli/declarations.md'\n            },\n            {\n              text: '📄 logger',\n              link: '/guides/cli/logger.md'\n            },\n            {\n              text: '📄 validators',\n              link: '/guides/cli/validators.md'\n            },\n            {\n              text: '📄 &lt;database&gt;',\n              link: '/guides/cli/databases.md'\n            }\n          ]\n        },\n        {\n          text: '📂 test',\n          items: [\n            {\n              text: '📄 client.test',\n              link: '/guides/cli/client.test.md'\n            },\n            {\n              text: '📄 app.test',\n              link: '/guides/cli/app.test.md'\n            },\n            {\n              text: '📄 &lt;service&gt;.test',\n              link: '/guides/cli/service.test.md'\n            }\n          ]\n        },\n        {\n          text: '📄 .prettierrc',\n          link: '/guides/cli/prettierrc.md'\n        },\n        {\n          text: '📄 knexfile',\n          link: '/guides/cli/knexfile.md'\n        },\n        {\n          text: '📄 package.json',\n          link: '/guides/cli/package.md'\n        },\n        {\n          text: '📄 tsconfig.json',\n          link: '/guides/cli/tsconfig.md'\n        }\n      ]\n    },\n    {\n      text: 'Migrating',\n      // collapsible: true,\n      items: [\n        {\n          text: \"What's new?\",\n          link: '/guides/whats-new.md'\n        },\n        {\n          text: 'Migration guide',\n          link: '/guides/migrating.md'\n        }\n      ]\n    }\n  ],\n  '/api': [\n    {\n      text: 'Core',\n      collapsible: true,\n      items: [\n        {\n          text: 'Application',\n          link: '/api/application'\n        },\n        {\n          text: 'Services',\n          link: '/api/services'\n        },\n        {\n          text: 'Hooks',\n          link: '/api/hooks'\n        },\n        {\n          text: 'Events',\n          link: '/api/events'\n        },\n        {\n          text: 'Errors',\n          link: '/api/errors'\n        }\n      ]\n    },\n    {\n      text: 'Transports',\n      collapsible: true,\n      collapsed: true,\n      items: [\n        {\n          text: 'Configuration',\n          link: '/api/configuration'\n        },\n        {\n          text: 'Koa',\n          link: '/api/koa'\n        },\n        {\n          text: 'Express',\n          link: '/api/express'\n        },\n        {\n          text: 'Socket.io',\n          link: '/api/socketio'\n        },\n        {\n          text: 'Channels',\n          link: '/api/channels'\n        }\n      ]\n    },\n    {\n      text: 'Authentication',\n      collapsible: true,\n      collapsed: true,\n      items: [\n        {\n          text: 'Overview',\n          link: '/api/authentication/'\n        },\n        {\n          text: 'Service',\n          link: '/api/authentication/service'\n        },\n        {\n          text: 'Hook',\n          link: '/api/authentication/hook'\n        },\n        {\n          text: 'Strategies',\n          link: '/api/authentication/strategy'\n        },\n        {\n          text: 'JWT',\n          link: '/api/authentication/jwt'\n        },\n        {\n          text: 'Local',\n          link: '/api/authentication/local'\n        },\n        {\n          text: 'OAuth',\n          link: '/api/authentication/oauth'\n        }\n      ]\n    },\n    {\n      text: 'Client',\n      collapsible: true,\n      collapsed: true,\n      items: [\n        {\n          text: 'Feathers Client',\n          link: '/api/client'\n        },\n        {\n          text: 'REST Client',\n          link: '/api/client/rest'\n        },\n        {\n          text: 'Socket.io Client',\n          link: '/api/client/socketio'\n        },\n        {\n          text: 'Authentication',\n          link: '/api/authentication/client'\n        }\n      ]\n    },\n    {\n      text: 'Schema',\n      collapsible: true,\n      collapsed: true,\n      items: [\n        {\n          text: 'Overview',\n          link: '/api/schema/'\n        },\n        {\n          text: 'TypeBox',\n          link: '/api/schema/typebox'\n        },\n        {\n          text: 'JSON schema',\n          link: '/api/schema/schema'\n        },\n        {\n          text: 'Validators',\n          link: '/api/schema/validators'\n        },\n        {\n          text: 'Resolvers',\n          link: '/api/schema/resolvers'\n        }\n      ]\n    },\n    {\n      text: 'Databases',\n      collapsible: true,\n      collapsed: true,\n      items: [\n        {\n          text: 'Adapters',\n          link: '/api/databases/adapters'\n        },\n        {\n          text: 'Common API',\n          link: '/api/databases/common'\n        },\n        {\n          text: 'Querying',\n          link: '/api/databases/querying'\n        },\n        {\n          text: 'MongoDB',\n          link: '/api/databases/mongodb'\n        },\n        {\n          text: 'SQL',\n          link: '/api/databases/knex'\n        },\n        {\n          text: 'Memory',\n          link: '/api/databases/memory'\n        }\n      ]\n    }\n  ],\n  '/help': [\n    {\n      text: 'Help',\n      items: [\n        {\n          text: 'Getting Help',\n          link: '/help/'\n        },\n        {\n          text: 'FAQ',\n          link: '/help/faq'\n        }\n      ]\n    }\n  ],\n  '/cookbook': [\n    {\n      text: 'General',\n      items: [\n        {\n          text: 'Scaling',\n          link: '/cookbook/general/scaling'\n        }\n      ]\n    },\n    {\n      text: 'Authentication',\n      items: [\n        {\n          text: 'Anonymous',\n          link: '/cookbook/authentication/anonymous'\n        },\n        {\n          text: 'API Key',\n          link: '/cookbook/authentication/apiKey'\n        },\n        {\n          text: 'Auth0',\n          link: '/cookbook/authentication/auth0'\n        },\n        {\n          text: 'Facebook',\n          link: '/cookbook/authentication/facebook'\n        },\n        {\n          text: 'Google',\n          link: '/cookbook/authentication/google'\n        },\n        {\n          text: 'Firebase',\n          link: '/cookbook/authentication/firebase'\n        },\n        {\n          text: 'Discord',\n          link: '/cookbook/authentication/_discord'\n        },\n        {\n          text: 'Stateless JWT',\n          link: '/cookbook/authentication/stateless'\n        },\n        {\n          text: 'Revoking JWTs',\n          link: '/cookbook/authentication/revoke-jwt'\n        }\n      ]\n    },\n    {\n      text: 'Express',\n      items: [\n        {\n          text: 'File Uploads',\n          link: '/cookbook/express/file-uploading'\n        },\n        {\n          text: 'View Engine SSR',\n          link: '/cookbook/express/view-engine'\n        }\n      ]\n    },\n    {\n      text: 'Deployment',\n      items: [\n        {\n          text: 'Dockerize a Feathers App',\n          link: '/cookbook/deploy/docker'\n        }\n      ]\n    }\n  ],\n  '/comparison': comparisonSidebar,\n  '/feathers-vs-firebase': comparisonSidebar,\n  '/feathers-vs-meteor': comparisonSidebar,\n  '/feathers-vs-sails': comparisonSidebar,\n  '/feathers-vs-loopback': comparisonSidebar\n}\n"
  },
  {
    "path": "docs/.vitepress/config.ts",
    "content": "import { defineConfig } from 'vitepress'\nimport { discord, font, github, ogImage, ogUrl, twitter, feathersDescription, feathersName } from './meta'\nimport sidebar from './config.sidebar'\nimport nav from './config.nav'\n\n// For sitemap/search\nimport { createWriteStream } from 'node:fs'\nimport { SitemapStream } from 'sitemap'\nimport { resolve } from 'node:path'\nconst links: any[] = []\n\nexport default defineConfig({\n  lang: 'en-US',\n  title: feathersName,\n  description: feathersDescription,\n  head: [\n    ['meta', { name: 'theme-color', content: '#ffffff' }],\n    ['link', { rel: 'icon', href: '/logo.svg', type: 'image/svg+xml' }],\n    ['link', { rel: 'alternate icon', href: '/favicon.ico', type: 'image/png', sizes: '16x16' }],\n    [\n      'meta',\n      {\n        name: 'author',\n        content: `daffl, marshallswain, and FeathersJS contributors`\n      }\n    ],\n    [\n      'meta',\n      {\n        name: 'keywords',\n        content:\n          'feathersjs, feathers, react, vue, preact, svelte, solid, typescript, esm, node, deno, cloudflare, workers'\n      }\n    ],\n    ['meta', { property: 'og:title', content: feathersName }],\n    ['meta', { property: 'og:description', content: feathersDescription }],\n    ['meta', { property: 'og:url', content: ogUrl }],\n    ['meta', { property: 'og:image', content: ogImage }],\n    ['meta', { name: 'twitter:title', content: feathersName }],\n    ['meta', { name: 'twitter:description', content: feathersDescription }],\n    ['meta', { name: 'twitter:image', content: ogImage }],\n    ['meta', { name: 'twitter:card', content: 'summary_large_image' }],\n    ['link', { href: font, rel: 'stylesheet' }],\n    ['link', { rel: 'mask-icon', href: '/logo.svg', color: '#ffffff' }],\n    ['link', { rel: 'apple-touch-icon', href: '/apple-touch-icon.png', sizes: '180x180' }]\n  ],\n  lastUpdated: true,\n  markdown: {\n    theme: {\n      light: 'vitesse-light',\n      dark: 'vitesse-dark'\n    }\n  },\n  themeConfig: {\n    logo: '/logo.svg',\n\n    editLink: {\n      pattern: 'https://github.com/feathersjs/feathers/edit/dove/docs/:path',\n      text: 'Suggest changes to this page'\n    },\n\n    socialLinks: [\n      { icon: 'discord', link: discord },\n      { icon: 'github', link: github }\n    ],\n\n    footer: {\n      message: 'Released under the MIT License.',\n      copyright: `Copyright © 2012-${new Date().getFullYear()} FeathersJS contributors`\n    },\n\n    nav,\n    sidebar\n  },\n  // for sitemap/search\n  transformHtml: (_: any, id: any, { pageData }: any) => {\n    if (!/[\\\\/]404\\.html$/.test(id))\n      links.push({\n        // you might need to change this if not using clean urls mode\n        url: pageData.relativePath.replace(/((^|\\/)index)?\\.md$/, '$2'),\n        lastmod: pageData.lastUpdated\n      })\n  },\n  // for sitemap/search\n  buildEnd: async ({ outDir }) => {\n    const sitemap = new SitemapStream({\n      hostname: 'https://dove.feathersjs.com/'\n    })\n    const writeStream = createWriteStream(resolve(outDir, 'sitemap.xml'))\n    sitemap.pipe(writeStream)\n    links.forEach((link) => sitemap.write(link))\n    sitemap.end()\n    await new Promise((r) => writeStream.on('finish', r))\n  }\n})\n"
  },
  {
    "path": "docs/.vitepress/meta.ts",
    "content": "// noinspection ES6PreferShortImport: IntelliJ IDE hint to avoid warning to use `~/contributors`, will fail on build if changed\n\n/* Texts */\nexport const feathersName = 'feathers'\nexport const feathersShortName = 'feathers'\nexport const feathersDescription = 'The API & Real-time Application Framework'\n\n/* CDN fonts and styles */\nexport const googleapis = 'https://fonts.googleapis.com'\nexport const gstatic = 'https://fonts.gstatic.com'\nexport const font = `${googleapis}/css2?family=Readex+Pro:wght@200;400;600&display=swap`\n\n/* vitepress head */\nexport const ogUrl = 'https://feathersjs.com/'\nexport const ogImage = `${ogUrl}og.png`\n\n/* GitHub and social links */\nexport const github = 'https://github.com/feathersjs/feathers'\nexport const releases = 'https://github.com/feathersjs/feathers/releases'\nexport const contributing = 'https://github.com/feathersjs/feathers/blob/master/.github/contributing.md'\nexport const discord = 'https://discord.gg/qa8kez8QBx'\nexport const twitter = null;\n\n/* Avatar/Image/Sponsors servers */\nexport const preconnectLinks = [googleapis, gstatic]\nexport const preconnectHomeLinks = [googleapis, gstatic]\n\n/* PWA runtime caching urlPattern regular expressions */\nexport const pwaFontsRegex = new RegExp(`^${googleapis}/.*`, 'i')\nexport const pwaFontStylesRegex = new RegExp(`^${gstatic}/.*`, 'i')\n"
  },
  {
    "path": "docs/.vitepress/scripts/assets.ts",
    "content": "import { promises as fs } from 'fs'\nimport fg from 'fast-glob'\nimport { font, preconnectHomeLinks, preconnectLinks } from '../meta'\n\nconst preconnect = `\n  ${preconnectLinks.map(l => `<link rel=\"dns-prefetch\" href=\"${l}\">`).join('\\n')}\n  ${preconnectLinks.map(l => `<link rel=\"preconnect\" crossorigin=\"anonymous\" href=\"${l}\">`).join('\\n')}\n`\n\nconst preconnectHome = `\n  ${preconnectHomeLinks.map(l => `<link rel=\"dns-prefetch\" href=\"${l}\">`).join('\\n')}\n  ${preconnectHomeLinks.map(l => `<link rel=\"preconnect\" crossorigin=\"anonymous\" href=\"${l}\">`).join('\\n')}\n`\n\nexport const optimizePages = async (pwa: boolean) => {\n  const names = await fg('./.vitepress/dist/**/*.html', { onlyFiles: true })\n\n  await Promise.all(names.map(async (i) => {\n    let html = await fs.readFile(i, 'utf-8')\n\n    let prefetchImg = '\\n\\t<link rel=\"prefetch\" href=\"/logo.svg\">'\n\n    let usePreconnect = preconnect\n\n    if (i.endsWith('/dist/index.html')) {\n      usePreconnect = preconnectHome\n      prefetchImg = `\n${prefetchImg}\n\\t<link rel=\"prefetch\" href=\"/netlify.svg\">\n\\t<link rel=\"prefetch\" href=\"/bg.png\">\n`\n    }\n\n    // we need the font on development, so the font entry is added in vitepress head\n    html = html.replace(`<link href=\"${font.replace('&', '&amp;')}\" rel=\"stylesheet\">`, '')\n\n    html = html.replace(\n      /<link rel=\"stylesheet\" href=\"(.*)\">/g,\n      `\n    ${usePreconnect}\n    <link rel=\"preload\" as=\"style\" href=\"$1\" />\n    <link rel=\"stylesheet\" href=\"$1\" />\n    <link\n      rel=\"preload\"\n      as=\"style\"\n      onload=\"this.onload=null;this.rel='stylesheet'\"\n      href=\"${font}\"\n    />\n    <noscript>\n      <link rel=\"stylesheet\" crossorigin=\"anonymous\" href=\"${font}\" />\n    </noscript>`).trim()\n\n    if (pwa) {\n      html = html.replace(\n        '</head>',\n        `\n\\t<link rel=\"prefetch\" href=\"/manifest.webmanifest\">${prefetchImg}\n\\t<link rel=\"manifest\" href=\"/manifest.webmanifest\">\\n</head>`,\n      )\n    }\n    else {\n      html = html.replace(\n        '</head>',\n        `\n${prefetchImg}\n</head>`,\n      )\n    }\n\n    // TODO: dark/light theme, don't remove yet\n    // html = html.replace(\n    //   '</head>',\n    //   '\\t<link rel=\"manifest\" href=\"/manifest.webmanifest\">\\n<script>\\n'\n    //     + '    (function() {\\n'\n    //     + '      const prefersDark = window.matchMedia && window.matchMedia(\\'(prefers-color-scheme: dark)\\').matches\\n'\n    //     + '      const setting = localStorage.getItem(\\'color-schema\\') || \\'auto\\'\\n'\n    //     + '      if (setting === \\'dark\\' || (prefersDark && setting !== \\'light\\'))\\n'\n    //     + '        document.documentElement.classList.toggle(\\'dark\\', true)\\n'\n    //     + '    })()\\n'\n    //     + '  </script></head>',\n    // )\n\n    html = html.replace(\n      /aria-hidden=\"true\"/gi,\n      'tabindex=\"-1\" aria-hidden=\"true\"',\n    ).replace(\n      /<img class=\"logo\"/gi,\n      '<img class=\"logo\" width=\"31\" height=\"31\"',\n    )\n\n    await fs.writeFile(i, html, 'utf-8')\n  }))\n}\n"
  },
  {
    "path": "docs/.vitepress/style/element-plus.scss",
    "content": "@forward 'element-plus/theme-chalk/src/common/var.scss' with (\n  $colors: (\n    'primary': (\n      'base': #745847\n    )\n  )\n);\n\n@use 'element-plus/theme-chalk/src/index.scss';\n"
  },
  {
    "path": "docs/.vitepress/style/main.postcss",
    "content": "@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap');\n\n:root body {\n  font-family:\n    'Poppins',\n    -apple-system,\n    BlinkMacSystemFont,\n    'Segoe UI',\n    Roboto,\n    Oxygen,\n    Ubuntu,\n    Cantarell,\n    'Open Sans',\n    'Helvetica Neue',\n    sans-serif !important;\n}\nhtml {\n  -webkit-tap-highlight-color: transparent;\n}\n\n/* Home Page Toolbar Overrides */\n.home-page .VPNavBar {\n  border-bottom: none;\n}\n\n.home-page .VPNav {\n  --vp-nav-bg-color: transparent;\n  --vp-c-gutter: transparent;\n}\n\n/* Remove the search button from the home page. Keyboard shortcut still works. */\n.home-page #docsearch {\n  /* display: none; */\n}\n/* Hide the default footer because FeathersLayout.vue uses a custom footer */\n.home-page .VPFooter {\n  display: none;\n}\n/* Hide the white gradient at the bottom of the page */\n.aside-curtain {\n  display: none;\n}\n\n/* TODO: Move to UnoCSS Rules */\nbody .bg-primary {\n  background: var(--primary);\n}\nbody .text-primary-content {\n  background: var(--primary-content);\n}\nbody .bg-secondary {\n  background: var(--secondary);\n}\nbody .text-secondary-content {\n  background: var(--secondary-content);\n}\n/* For secondary colors, switch the cloud color to charcoal in dark mode */\n.dark body .bg-secondary {\n  background: var(--accent);\n}\n.dark body .text-secondary-content {\n  background: var(--accent-content);\n}\n\nbody .bg-neutral {\n  background: var(--neutral);\n}\nbody .text-neutral-content {\n  color: var(--neutral-content);\n}\nbody .bg-base-100 {\n  background: var(--vp-c-bg);\n}\n\n.VPNav .logo,\n.VPNav .title {\n  transition: all 300ms;\n}\n.VPNav .logo,\n.VPNav .title {\n  text-transform: lowercase;\n}\n.home-page .title,\n.feathers-footer .title {\n  font-size: 32px;\n}\n.home-page .logo,\n.feathers-footer .logo {\n  height: 48px;\n  fill: blue;\n}\n.dark .logo {\n  filter: invert(1);\n}\n\n/* Style the Global Language Select in the left nav */\n#app #GlobalLanguageSelect {\n  /* @apply pt-2 pb-3;\n  border-bottom: 1px solid transparent;\n  border-bottom-color: var(--vp-c-divider-light); */\n}\n\n#VPSidebarNav:not(:first-child) {\n  @apply mt-3;\n  border-top-color: var(--vp-c-divider-light);\n}\n\n@media (min-width: 960px) {\n  .home-page .VPNav,\n  .home-page .VPNav.no-sidebar {\n    position: static;\n    background: none;\n  }\n  #app.home-page .VPNav {\n    backdrop-filter: none;\n    -webkit-backdrop-filter: none;\n  }\n}\n\n/* Overrides */\n\n.VPSocialLink {\n  transform: scale(0.9);\n}\n\n.vp-doc th,\n.vp-doc td {\n  padding: 6px 10px;\n  border: 1px solid #8882;\n}\n\n/* h3 breaks SEO => replaced with h2 with the same size */\n.home-content h2 {\n  margin-top: 2rem;\n  font-size: 1.35rem;\n  border-bottom: none;\n  margin-bottom: 0;\n}\n\nimg.resizable-img {\n  width: unset;\n  height: unset;\n}\n\nbody[data-language='js'] pre.language-selectable[data-language='ts'] {\n  display: none;\n}\n\nbody[data-language='ts'] pre.language-selectable[data-language='js'] {\n  display: none;\n}\n"
  },
  {
    "path": "docs/.vitepress/style/vars.postcss",
    "content": "/**\n * Colors\n * -------------------------------------------------------------------------- */\n\n:root {\n  --primary: #ed8a80;                /* congo pink */\n  --primary-content: #3C3C3B;        /* charcoal */\n  --neutral: #27464F;                /* midnight green */\n  --neutral-content: #EDEDED;        /* cloud */\n  --secondary: #EDEDED;              /* charcoal */\n  --secondary-content: #3C3C3B;      /* cloud */\n  --accent: #3C3C3B;                 /* charcoal */\n  --accent-content: #EDEDED;         /* cloud */\n  --btn-focus-scale: 1.05;\n\n  --vp-c-accent: rgb(218, 180, 11);\n  --vp-c-brand: var(--primary);\n  --vp-c-brand-light: #FFA69D;\n  --vp-c-brand-lighter: #FA978D;\n  --vp-c-brand-dark: #e47f75;\n  --vp-c-brand-darker: #db6d62;\n  --vp-code-block-bg: rgba(125,125,125,0.04);\n  --vp-c-green-light: rgb(18, 181, 157);\n  --vp-custom-block-tip-border: rgba(18, 181, 157, 0.5);\n  --vp-custom-block-tip-bg: rgba(18, 181, 157, 0.1);\n  --vp-code-line-highlight-color: rgba(18, 181, 157, 0.2);\n  /* --vp-code-line-highlight-color: #eea74b22; */\n  /* --vp-code-line-highlight-color: #db6d6232; */\n  /* --vp-code-line-highlight-color: #db6d6232; */\n  /* --vp-code-line-highlight-color: rgba(0, 0, 0, 0.1); */\n}\n\n.dark {\n  --vp-code-block-bg: rgba(0,0,0,0.2);\n  --vp-code-line-highlight-color: rgba(18, 181, 157, 0.15);\n}\n\n/**\n * Component: Button\n * -------------------------------------------------------------------------- */\n\n:root {\n  --vp-button-brand-border: var(--vp-c-brand-light);\n  --vp-button-brand-text: var(--vp-c-text-dark-1);\n  --vp-button-brand-bg: var(--vp-c-brand);\n  --vp-button-brand-hover-border: var(--vp-c-brand-light);\n  --vp-button-brand-hover-text: var(--vp-c-text-dark-1);\n  --vp-button-brand-hover-bg: var(--vp-c-brand-light);\n  --vp-button-brand-active-border: var(--vp-c-brand-light);\n  --vp-button-brand-active-text: var(--vp-c-text-dark-1);\n  --vp-button-brand-active-bg: var(--vp-button-brand-bg);\n}\n\n/**\n * Component: Home\n * -------------------------------------------------------------------------- */\n\n :root {\n  --vp-home-hero-name-color: transparent;\n  --vp-home-hero-name-background: -webkit-linear-gradient(\n    120deg,\n    #f850ce 30%,\n    #c10893\n  );\n  --vp-home-hero-image-background-image: linear-gradient(\n    -45deg,\n    #ffffff8f 30%,\n    #ff85f75e\n  );\n  --vp-home-hero-image-filter: blur(30px);\n}\n\n@media (min-width: 640px) {\n  :root {\n    --vp-home-hero-image-filter: blur(56px);\n  }\n}\n\n@media (min-width: 960px) {\n  :root {\n    --vp-home-hero-image-filter: blur(72px);\n  }\n}\n\n\n/**\n * Component: Algolia\n * -------------------------------------------------------------------------- */\n\n.DocSearch {\n  --docsearch-primary-color: var(--vp-c-brand) !important;\n}\n"
  },
  {
    "path": "docs/.vitepress/theme/FeathersLayout.vue",
    "content": "<script setup lang=\"ts\">\nimport DefaultTheme from 'vitepress/theme'\nimport Footer from '../../components/Footer.vue'\nimport DatabaseSelect from '../components/DatabaseSelect.vue'\n\nconst { Layout } = DefaultTheme\n</script>\n\n<template>\n  <Layout>\n    <template #sidebar-nav-before>\n      <DatabaseSelect />\n    </template>\n  </Layout>\n  <Footer />\n</template>\n"
  },
  {
    "path": "docs/.vitepress/theme/index.ts",
    "content": "import googleAnalytics from 'vitepress-plugin-google-analytics'\nimport 'element-plus/theme-chalk/dark/css-vars.css'\n\nimport '../vite-env.d'\nimport Theme from 'vitepress/theme'\nimport { inBrowser } from 'vitepress'\nimport '../style/main.postcss'\nimport '../style/vars.postcss'\nimport 'uno.css'\nimport FeathersLayout from './FeathersLayout.vue'\nimport Tab from '../components/Tab.vue'\nimport Tabs from '../components/Tabs.vue'\nimport Select from '../components/Select.vue'\nimport Badges from '../components/Badges.vue'\nimport Logo from '../components/Logo.vue'\nimport BlockQuote from '../components/BlockQuote.vue'\nimport LanguageBlock from '../components/LanguageBlock.vue'\nimport DatabaseBlock from '../components/DatabaseBlock.vue'\n\nimport '../style/element-plus.scss'\n// import 'element-plus/dist/index.css'\n\nif (inBrowser) import('./pwa')\n\nexport default {\n  ...Theme,\n  Layout: FeathersLayout,\n  enhanceApp({ app }) {\n    googleAnalytics({\n      id: 'G-XQ8CKCD9L6'\n    }),\n      // Globally register components so they don't have to be imported in the template.\n      app.component('Tabs', Tabs)\n    app.component('Tab', Tab)\n    app.component('Select', Select)\n    app.component('Badges', Badges)\n    app.component('Logo', Logo)\n    app.component('BlockQuote', BlockQuote)\n    app.component('LanguageBlock', LanguageBlock)\n    app.component('DatabaseBlock', DatabaseBlock)\n  }\n}\n"
  },
  {
    "path": "docs/.vitepress/theme/pwa.ts",
    "content": "import { registerSW } from 'virtual:pwa-register'\n\nregisterSW({ immediate: true })\n"
  },
  {
    "path": "docs/.vitepress/theme/store.ts",
    "content": "import { createGlobalState, useStorage } from '@vueuse/core'\n\nexport const useGlobalLanguage = createGlobalState(() => useStorage('global-language', 'ts'))\nexport const useGlobalDb = createGlobalState(() => useStorage('global-db', 'sql'))\n"
  },
  {
    "path": "docs/.vitepress/vite-env.d.ts",
    "content": "/// <reference types=\"vite/client\" />\n\ndeclare module '*.vue' {\n  import type { DefineComponent } from 'vue'\n  const component: DefineComponent<{}, {}, any>\n  export default component\n}\n"
  },
  {
    "path": "docs/api/application.md",
    "content": "---\noutline: deep\n---\n\n# Application\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/authentication-client.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/feathers)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/feathers/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/feathers --save\n```\n\nThe core `@feathersjs/feathers` module provides the ability to initialize a new Feathers application instance. It works in Node, React Native and the browser (see the [client](./client.md) chapter for more information). Each instance allows for registration and retrieval of [services](./services.md), [hooks](./hooks.md), plugin configuration, and getting and setting configuration options. An initialized Feathers application is referred to as the **app object**.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\n\ntype ServiceTypes = {\n  // Add registered services here\n}\n\n// Types for `app.set(name, value)` and `app.get(name)`\ntype Configuration = {\n  port: number\n}\n\nconst app = feathers<ServiceTypes, Configuration>()\n```\n\n## .use(path, service [, options])\n\n`app.use(path, service [, options]) -> app` allows registering a [service object](./services.md) on a given `path`.\n\n```ts\nimport { feathers, type Id } from '@feathersjs/feathers'\n\nclass MessageService {\n  async get(id: Id) {\n    return {\n      id,\n      text: `This is the ${id} message!`\n    }\n  }\n}\n\ntype ServiceTypes = {\n  // Add services path to type mapping here\n  messages: MessageService\n}\n\nconst app = feathers<ServiceTypes>()\n\n// Register a service instance on the app\napp.use('messages', new MessageService())\n\n// Get the service and call the service method with the correct types\nconst message = await app.service('messages').get('test')\n```\n\n### path\n\nThe `path` is a string that should be URL friendly and may contain `/` as a separator. `path` can also be `/` to register a service at the root level. A path may contain placeholders in the form of `:userId/messages` which will be included in `params.route` by a transport.\n\n### options\n\nThe following options are available:\n\n- `methods` (default: `['find', 'get', 'create', 'patch', 'update','remove']`) - A list of official and [custom service methods](services.md#custom-methods) that should be available to clients. When using this option **all** method names that should be available externally must be passed. Those methods will automatically be available for use with [hooks](./hooks).\n- `events` - A list of [public custom events sent by this service](./events.md#custom-events)\n\n```ts\nimport { EventEmitter } from 'events'\nimport { feathers, type Id } from '@feathersjs/feathers'\n\n// Feathers services will always be event emitters\n// but we can also extend it for better type consistency\nclass MessageService extends EventEmitter {\n  async doSomething(data: { message: string }, params: Params) {\n    this.emit('something', 'I did something')\n    return data\n  }\n\n  async get(id: Id) {\n    return {\n      id,\n      text: `This is the ${id} message!`\n    }\n  }\n}\n\ntype ServiceTypes = {\n  // Add services path to type mapping here\n  messages: MessageService\n}\n\nconst app = feathers<ServiceTypes>()\n\n// Register a service with options\napp.use('messages', new MessageService(), {\n  methods: ['get', 'doSomething'],\n  events: ['something']\n})\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nIf the `methods` property is `undefined`, all standard methods will be enabled and accessible externally.\n\n</BlockQuote>\n\n## .unuse(path)\n\n`app.unuse(path)` unregisters an existing service on `path` and calls the services [.teardown method](./services.md#teardownapp-path) if it is implemented.\n\n## .service(path)\n\n`app.service(path) -> service` returns the [service object](./services.md) for the given path. Feathers internally creates a new object from each registered service. This means that the object returned by `app.service(path)` will provide the same methods and functionality as your original service object but also functionality added by Feathers and its plugins like [service events](./events.md) and [additional methods](./services.md#feathers-functionality).\n\n```ts\nconst messageService = app.service('messages')\n\nconst message = await messageService.get('test')\n\nconsole.log(message)\n\nmessageService.on('created', (message: Message) => {\n  console.log('Created a todo')\n})\n```\n\n<BlockQuote type=\"info\" label=\"Note\">\n\nNote that a server side `app.service(path)` only allows the original service name (e.g. `app.service(':userId/messages')`) and does not parse placeholders. To get a service with route paramters use [.lookup](#lookuppath)\n\n</BlockQuote>\n\n## .lookup(path)\n\n`app.lookup(path)` allows to look up a full path and will return the `data` (route parameters) and `service` **on the server**.\n\n```ts\nconst lookup = app.lookup('messages/4321')\n\n// lookup.service -> app.service('messages')\n// lookup.data -> { __id: '4321' }\n\n// `lookup.dta` needs to be passed as `params.route`\nlookup.service.find({\n  route: lookup.data\n})\n```\n\nCase insensitive lookups can be enabled in the `app` file like this:\n\n```ts\napp.routes.caseSensitive = false\n```\n\n## .hooks(hooks)\n\n`app.hooks(hooks) -> app` allows registration of application-level hooks. For more information see the [application hooks section in the hooks chapter](./hooks.md#application-hooks).\n\n## .publish([event, ] publisher)\n\n`app.publish([event, ] publisher) -> app` registers a global event publisher. For more information see the [channels publishing](./channels.md#publishing) chapter.\n\n## .configure(callback)\n\n`app.configure(callback) -> app` runs a `callback` function that gets passed the application object. It is used to initialize plugins and can be used to separate your application into different files.\n\n```ts\nconst setupService = (app: Application) => {\n  app.use('/todos', todoService)\n}\n\napp.configure(setupService)\n```\n\n## .setup([server])\n\n`app.setup([server]) -> Promise<app>` is used to initialize all services by calling each [services .setup(app, path)](services.md#setupapp-path) method (if available).\nIt will also use the `server` instance passed (e.g. through `http.createServer`) to set up SocketIO (if enabled) and any other provider that might require the server instance. You can register [application setup hooks](./hooks.md#setup-and-teardown) to e.g. set up database connections and other things required to be initialized on startup in a certain order.\n\nNormally `app.setup` will be called automatically when starting the application via [app.listen([port])](#listen-port) but there are cases (like in tests) when it can be called explicitly.\n\n## .teardown([server])\n\n`app.teardown([server]) -> Promise<app>` can be called to gracefully shut down the application. When the app has been set up with a server (e.g. by calling `app.listen()`) the server will be closed automatically when calling `app.teardown()`. You can also register [application hooks](./hooks.md#setup-and-teardown) on teardown to e.g. close database connection etc.\n\n## .listen(port)\n\n`app.listen([port]) -> Promise<HTTPServer>` starts the application on the given port. It will set up all configured transports (if any) and then run [app.setup(server)](#setup-server) with the server object and then return the server object.\n\n`listen` will only be available if a server side transport (REST or websocket) has been configured.\n\n## .set(name, value)\n\n`app.set(name, value) -> app` assigns setting `name` to `value`.\n\n<BlockQuote type=\"danger\">\n\n`app.set` is global to the application. It is used for storing application wide information like database connection strings etc. **Do not use it for storing request or service specific data.** This can be done by adding data to the [hook context](./hooks.md#hook-context).\n\n</BlockQuote>\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\n\ntype ServiceTypes = {\n  // Add services path to type mapping here\n}\n\n// app.get and app.set can be typed when initializing the app\ntype Configuration = {\n  port: number\n}\n\nconst app = feathers<ServiceTypes, Configuration>()\n\napp.set('port', 3030)\n\napp.listen(app.get('port'))\n```\n\n<BlockQuote type=\"info\" label=\"Note\">\n\nOn the server, settings are usually initialized using [Feathers configuration](configuration.md).\n\n</BlockQuote>\n\n## .get(name)\n\n`app.get(name) -> value` retrieves the setting `name`.\n\n## .on(eventname, listener)\n\nProvided by the core [NodeJS EventEmitter .on](https://nodejs.org/api/events.html#events_emitter_on_eventname_listener). Registers a `listener` method (`function(data) {}`) for the given `eventname`.\n\n```js\napp.on('login', (user) => console.log('Logged in', user))\n```\n\n## .emit(eventname, data)\n\nProvided by the core [NodeJS EventEmitter .emit](https://nodejs.org/api/events.html#events_emitter_emit_eventname_args).\n\n```ts\ntype MyEventData = { message: string }\n\napp.emit('myevent', {\n  message: 'Something happened'\n})\n\napp.on('myevent', (data: MyEventData) => console.log('myevent happened', data))\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\n`app` can not receive or send events to or from clients. A [custom service](./services.md) should be used for that.\n\n</BlockQuote>\n\n## .removeListener(eventname)\n\nProvided by the core [NodeJS EventEmitter .removeListener](https://nodejs.org/api/events.html#events_emitter_removelistener_eventname_listener). Removes all or the given listener for `eventname`.\n\n## .mixins\n\n`app.mixins` contains a list of service mixins. A mixin is a callback (`(service, path, options) => {}`) that gets run for every service that is being registered. Adding your own mixins allows to add functionality to every registered service.\n\n```ts\nimport type { Id } from '@feathersjs/feathers'\n\n// Mixins have to be added before registering any services\napp.mixins.push((service: any, path: string) => {\n  service.sayHello = function () {\n    return `Hello from service at '${path}'`\n  }\n})\n\napp.use('/todos', {\n  async get(id: Id) {\n    return { id }\n  }\n})\n\napp.service('todos').sayHello()\n// -> Hello from service at 'todos'\n```\n\n## .services\n\n`app.services` contains an object of all [services](./services.md) keyed by the path they have been registered via `app.use(path, service)`. This allows to return a list of all available service names:\n\n```ts\nconst servicePaths = Object.keys(app.services)\n\nservicePaths.forEach((path) => {\n  const service = app.service(path)\n})\n```\n\n<BlockQuote type=\"danger\">\n\nTo retrieve services use [app.service(path)](#service-path), not `app.services[path]` directly.\n\n</BlockQuote>\n\nA Feathers [client](client.md) does not know anything about the server it is connected to. This means that `app.services` will _not_ automatically contain all services available on the server. Instead, the server has to provide the list of its services, e.g. through a [custom service](./services.md):\n\n```ts\nclass InfoService {\n  constructor(public app: Application) {}\n\n  async find() {\n    return {\n      service: Object.keys(this.app.services)\n    }\n  }\n}\n\napp.use('info', new InfoService(app))\n```\n\n## .defaultService\n\n`app.defaultService` can be a function that returns an instance of a new standard service for `app.service(path)` if there isn't one registered yet. By default it throws a `NotFound` error when you are trying to access a service that doesn't exist.\n\n```ts\nimport { MemoryService } from '@feathersjs/memory'\n\n// For every `path` that doesn't have a service\n// Automatically return a new in-memory service\napp.defaultService = function (path: string) {\n  return new MemoryService()\n}\n```\n\nThis is used by the [client transport adapters](./client.md) to automatically register client side services that talk to a Feathers server.\n"
  },
  {
    "path": "docs/api/authentication/client.md",
    "content": "---\noutline: deep\n---\n\n# Authentication Client\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/authentication-client.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/authentication-client)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/authentication-client/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/authentication-client --save\n```\n\nThe `@feathersjs/authentication-client` module allows you to easily authenticate a Feathers client against a Feathers server. It is not required, but makes it easier to implement authentication in your client by automatically storing and sending the access token and handling re-authenticating when a websocket disconnects.\n\n## Usage\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio-client'\nimport io from 'socket.io-client'\nimport authentication from '@feathersjs/authentication-client'\n\nconst socket = io('http://api.feathersjs.com')\nconst app = feathers()\n\n// Setup the transport (Rest, Socket, etc.) here\napp.configure(socketio(socket))\n\n// Available options are listed in the \"Options\" section\napp.configure(authentication())\n```\n\n## Options\n\nThe following options are available for `app.configure(authentication(options))`:\n\n- `storage` (default: `localStorage` if available, `MemoryStorage` otherwise) - The storage to store the access token. For React Native use `import { AsyncStorage } from 'react-native'`\n- `path` (default: '/authentication') - The path of the authentication service\n- `locationKey` (default: `'access_token'`) - The name of the window hash parameter to parse for an access token from the `window.location`. Usually used by the OAuth flow.\n- `locationErrorKey` (default: `'error') - The name of the window hash parameter to parse for authentication errors. Usually used by the OAuth flow.\n- `jwtStrategy` (default: `'jwt'`) - The access token authentication strategy\n- `storageKey` (default: `'feathers-jwt'`) - Key for storing the token in `storage`\n- `header` (default: `'Authorization'`) - Name of the accessToken header\n- `scheme` (default: `'Bearer'`) - The HTTP header scheme\n- Authentication (default: `AuthenticationClient`) - Allows to provide a [customized authentication client class](#customization)\n\n<BlockQuote type=\"info\">\n\nVerifying or parsing the token on the client usually isn't necessary since the server does that on JWT authentication and returns with the token information but it can still be done manually with the [jwt-decode](https://www.npmjs.com/package/jwt-decode) package.\n\n</BlockQuote>\n\n## app.reAuthenticate([force])\n\n`app.reAuthenticate() -> Promise` will try to authenticate using the access token from the storage or the window location (e.g. after a successful [OAuth](./oauth.md) login). This is normally called to either show your application (when successful) or showing a login page or redirecting to the appropriate OAuth link.\n\n```js\ntry {\n  await app.reAuthenticate()\n  showDashboard()\n} catch (error) {\n  showLoginPage()\n}\n```\n\n<BlockQuote type=\"danger\">\n\n`app.reAuthenticate()` has to be called when you want to use the token from storage. **There is no need to call it more than once**, so you’d typically only do it once when the application initializes. When successful, all subsequent requests will send their authentication information automatically.\n\n</BlockQuote>\n\nIn some rare cases, for example making sure the user object returned by `app.get('authentication')` is up-to-date after it was changed on the server, you may force reauthentication via `app.reAuthenticate(true)`.\n\n## app.authenticate(data)\n\n`app.authenticate(data) -> Promise` will try to authenticate with a Feathers server by passing a `strategy` and other properties as credentials.\n\n```ts\ntry {\n  // Authenticate with the local email/password strategy\n  await app.authenticate({\n    strategy: 'local',\n    email: 'my@email.com',\n    password: 'my-password'\n  })\n  // Show e.g. logged in dashboard page\n} catch (error: any) {\n  // Show login page (potentially with `e.message`)\n  console.error('Authentication error', e)\n}\n```\n\n- `data {Object}` - of the format `{strategy [, ...otherProps]}`\n  - `strategy {String}` - the name of the strategy to be used to authenticate. Required.\n  - `...otherProps {Properties} ` vary depending on the chosen strategy. Above is an example of using the `local` strategy.\n\n## app.logout()\n\nRemoves the access token from storage on the client. It also calls the `remove` method of the [authentication service](./service.md).\n\n## app.get('authentication')\n\n`app.get('authentication') -> Promise` is a Promise that resolves with the current authentication information. For most strategies this is the best place to **get the currently authenticated user**:\n\n```js\n// Returns the authenticated user\nconst { user } = await app.get('authentication')\n// Gets the authenticated accessToken (JWT)\nconst { accessToken } = await app.get('authentication')\n```\n\n## app.authentication\n\nReturns the instance of the [AuthenticationClient](#authenticationclient).\n\n## AuthenticationClient\n\n### service\n\n`app.authentication.service` returns an instance of the authentication client service, normally `app.service('authentication')`.\n\n### storage\n\n`app.authentication.storage` returns the storage instance (e.g. window.LocalStorage, React Native AsyncStorage or an in-memory store).\n\n### handleSocket(socket)\n\n`app.authentication.handleSocket(socket) -> void` makes sure that a websocket real-time connection is always re-authenticated before making any other request.\n\n### getFromLocation(location)\n\n`app.authentication.getFromLocation(location) -> Promise` tries to retrieve an access token from `window.location`. This usually means the `access_token` in the hash set by the [OAuth authentication strategy](./oauth.md).\n\n### setAccessToken(token)\n\n`app.authentication.setAccessToken(token) -> Promise` sets the access token in the storage (normally `feathers-jwt` in `window.localStorage`).\n\n### getAccessToken()\n\n`app.authentication.getAccessToken() -> Promise` returns the access token from `storage`. If not found it will try to get the access token via [getFromLocation()]() or return `null` if neither was successful.\n\n### removeAccessToken()\n\n`app.authentication.removeAccessToken() -> Promise` removes the access token from the storage.\n\n### reset()\n\n`app.authentication.reset()` resets the authentication state without explicitly logging out. Should not be called directly.\n\n### handleError()\n\n`app.authentication.handleError(error, type: 'authenticate'|'logout') -> Promise` handles any error happening in the `authenticate` or `logout` method. By default it removes the access token if the error is a `NotAuthenticate` error. Otherwise it does nothing.\n\n### reAuthenticate(force, strategy?)\n\n`app.authentication.reAuthenticate(force = false, strategy) -> Promise` will re-authenticate with the current access token from [app.authentication.getAccessToken()](). If `force` is set to `true` it will always re-authenticate, with the default `false` only when not already authenticated.\n\n`strategy` is an optional parameter which defaults to the configured `jwtStrategy`.\n\n### authenticate()\n\nThe internal method called when using [app.authenticate()](#app-authenticate-data).\n\n### logout()\n\nThe internal method called when using [app.logout()](#app-logout).\n\n## Customization\n\nThe [AuthenticationClient]() can be extended to provide custom functionality and then passed during initialization:\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio-client'\nimport io from 'socket.io-client'\nimport authentication, { AuthenticationClient } from '@feathersjs/authentication-client'\n\nconst socket = io('http://api.feathersjs.com')\nconst app = feathers()\n\nclass MyAuthenticationClient extends AuthenticationClient {\n  getFromLocation(location) {\n    // Do custom location things here\n    return super.getFromLocation(location)\n  }\n}\n\n// Setup the transport (Rest, Socket, etc.) here\napp.configure(socketio(socket))\n\n// Pass the custom authentication client class as the `Authentication` option\napp.configure(\n  authentication({\n    Authentication: MyAuthenticationClient\n  })\n)\n```\n\n## Hooks\n\nThe following hooks are added to the client side application automatically (when calling `app.configure(authentication())`).\n\n### authentication\n\nHook that ensures for every request that authentication is completed and successful. It also makes the authentication information available in the client side `params` (e.g. `params.user`).\n\n### populateHeader\n\nAdds the appropriate `Authorization` header for any REST request.\n"
  },
  {
    "path": "docs/api/authentication/hook.md",
    "content": "---\noutline: deep\n---\n\n# Authenticate Hook\n\nThe `authenticate` hook will use `params.authentication` of the service method call and run [authenticationService.authenticate()](./service.md#authenticate-data-params-strategies).\n\nThe hook will\n\n- Throw an error if the strategy fails\n- Throw an error if no authentication information is set and it is an external call (`params.provider` is set) or do nothing if it is an internal call (`params.provider` is `undefined`)\n- If successful, merge `params` with the return value of the authentication strategy\n\nFor example, a successful [JWT strategy](./jwt.md) authentication will set:\n\n```js\nparams.authentication.payload // The decoded payload\nparams.authentication.strategy === 'jwt' // The strategy name\nparams.user // or params[entity] if entity is not `null`\n```\n\nIn the following hooks and for the service method call. It can be used as a `before` or `around` [hook](../hooks.md).\n\n## authenticate(...strategies)\n\nCheck `params.authentication` against a list of authentication strategy names.\n\n```ts\nimport { authenticate } from '@feathersjs/authentication'\n\n// Authenticate with `jwt` and `api-key` strategy\n// using app.service('authentication') as the authentication service\napp.service('messages').hooks({\n  around: {\n    all: [authenticate('jwt', 'api-key')]\n  }\n})\n```\n\n## authenticate(options)\n\nCheck `params.authentication` against a list of strategies and specific authentication service. Available `options` are:\n\n- `service` - The path to the authentication service\n- `strategies` - A list of strategy names\n\n```js\nimport { authenticate } from '@feathersjs/authentication'\n\n// Authenticate with `jwt` and `api-key` strategy\n// using app.service('v1/authentication') as the authentication service\napp.service('messages').hooks({\n  before: {\n    all: [\n      authenticate({\n        service: 'v1/authentication',\n        strategies: ['jwt', 'api-key']\n      })\n    ]\n  }\n})\n```\n"
  },
  {
    "path": "docs/api/authentication/index.md",
    "content": "---\noutline: deep\n---\n\n# Authentication Overview\n\nThe `@feathersjs/authentication` plugins provide a collection of tools for username/password, JWT and OAuth (GitHub, Facebook etc.) authentication as well as custom authentication mechanisms.\n\nIt consists of the following core modules:\n\n- `@feathersjs/authentication` which includes\n  - The [AuthenticationService](./service.md) that allows to register [authentication strategies](./strategy.md) and create and manage access tokens\n  - The [JWTStrategy](./jwt.md) to use JWTs to make authenticated requests\n  - The [authenticate hook](./hook.md) to limit service calls to an authentication strategy.\n- [Local authentication](./local.md) for local username/password authentication\n- [OAuth authentication](./oauth.md) for Google, GitHub, Facebook etc. authentication\n- [The authentication client](./client.md) to use Feathers authentication on the client.\n\n<BlockQuote type=\"warning\">\n\n`@feathersjs/authentication` is an abstraction for different authentication mechanisms. It does not handle things like user verification or password reset functionality etc. This can be implemented manually, with the help of libraries like [feathers-authentication-management](https://github.com/feathers-plus/feathers-authentication-management) or a platform like [Auth0](https://auth0.com/).\n\n</BlockQuote>\n"
  },
  {
    "path": "docs/api/authentication/jwt.md",
    "content": "---\noutline: deep\n---\n\n# JWT Authentication\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/authentication.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/authentication)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/authentication/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/authentication --save\n```\n\nThe `JWTStrategy` is an [authentication strategy](./strategy.md) included in `@feathersjs/authentication` for authenticating [JSON web tokens (JWT)](https://jwt.io/):\n\n```json\n{\n  \"strategy\": \"jwt\",\n  \"accessToken\": \"<your JWT>\"\n}\n```\n\n## Usage\n\n```ts\nimport { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'\nimport type { Application } from './declarations'\n\ndeclare module './declarations' {\n  interface ServiceTypes {\n    authentication: AuthenticationService\n  }\n}\n\nexport const authentication = (app: Application) => {\n  const authentication = new AuthenticationService(app)\n\n  authentication.register('jwt', new JWTStrategy())\n\n  app.use('authentication', authentication)\n}\n```\n\n## Options\n\nOptions are set in the [authentication configuration](./service.md#configuration) under the strategy name. Available options are:\n\n- `header` (default: `'Authorization'`): The HTTP header containing the JWT\n- `schemes` (default: `[ 'Bearer', 'JWT' ]`): An array of schemes to support\n\nThe default settings support passing the JWT through the following HTTP headers:\n\n```\nAuthorization: <your JWT>\nAuthorization: Bearer <your JWT>\nAuthorization: JWT <your JWT>\n```\n\nOptions are usually set under the registered name via [Feathers configuration](../configuration.md) in `config/default.json` or `config/<environment>.json`:\n\n```json\n{\n  \"authentication\": {\n    \"jwt\": {\n      \"header\": \"X-Auth\"\n    }\n  }\n}\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nSince the default options are what most clients expect for JWT authentication they usually don't need to be customized.\n\n</BlockQuote>\n\nTo change the settings for generating and validating a JWT see the [authentication service configuration](./service.md#configuration)\n\n## JwtStrategy\n\n### getEntity(id, params)\n\n`jwtStrategy.getEntity(id, params)` returns the entity instance for `id`, usually `entityService.get(id, params)`. It will _not_ be called if `entity` in the [authentication configuration](./service.md#configuration) is set to `null`.\n\n### authenticate(data, params)\n\n`jwtStrategy.authenticate(data, params)` will try to verify `data.accessToken` by calling the strategies [authenticationService.verifyAccessToken](./service.md).\n\nReturns a promise that resolves with the following format:\n\n```js\n{\n  [entity],\n  accessToken,\n  authentication: {\n    strategy: 'jwt',\n    payload\n  }\n}\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nSince the JWT strategy returns an `accessToken` property (the same as the token sent to this strategy), that access token will also be returned by [authenticationService.create](./service.md#create-data-params) instead of creating a new one.\n\n</BlockQuote>\n\n### getEntityQuery(params)\n\nReturns the `query` to use when calling `entityService.get` (default: `{}`).\n\n### parse(req, res)\n\nParse the HTTP request headers for JWT authentication information. By default in the `Authorization` header. Returns a promise that resolves with either `null` or data in the form of:\n\n```js\n{\n  strategy: '<strategy name>',\n  accessToken: '<access token from HTTP header>'\n}\n```\n\n## Customization\n\n```ts\nimport { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'\nimport { LocalStrategy } from '@feathersjs/authentication-local'\nimport type { Application } from './declarations'\n\ndeclare module './declarations' {\n  interface ServiceTypes {\n    authentication: AuthenticationService\n  }\n}\n\nclass MyJwtStrategy extends JWTStrategy {\n  // Only allow authenticating activated users\n  async getEntityQuery(params: Params) {\n    return {\n      active: true\n    }\n  }\n}\n\nexport default (app: Application) => {\n  const authentication = new AuthenticationService(app)\n\n  authentication.register('jwt', new MyJwtStrategy())\n\n  // ...\n  app.use('authentication', authentication)\n}\n```\n"
  },
  {
    "path": "docs/api/authentication/local.md",
    "content": "---\noutline: deep\n---\n\n# Local Authentication\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/authentication-local.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/authentication-local)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/authentication-local/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/authentication-local --save\n```\n\n`@feathersjs/authentication-local` provides a `LocalStrategy` for authenticating with a username/email and password combination, e.g.\n\n```json\n{\n  \"strategy\": \"local\",\n  \"email\": \"hello@feathersjs.com\",\n  \"password\": \"supersecret\"\n}\n```\n\n## Usage\n\n```ts\nimport { AuthenticationService } from '@feathersjs/authentication'\nimport { LocalStrategy } from '@feathersjs/authentication-local'\nimport type { Application } from './declarations'\n\ndeclare module './declarations' {\n  interface ServiceTypes {\n    authentication: AuthenticationService\n  }\n}\n\nexport const authentication = (app: Application) => {\n  const authentication = new AuthenticationService(app)\n\n  authentication.register('local', new LocalStrategy())\n\n  app.use('authentication', authentication)\n}\n```\n\n## Options\n\nOptions are set in the [authentication configuration](./service.md#configuration) under the strategy name. Available options are:\n\n- `usernameField`: Name of the username field (e.g. `'email'`), may be a nested property (e.g. `'auth.email'`)\n- `passwordField`: Name of the password field (e.g. `'password'`), may be a nested property (e.g. `'auth.password'`)\n- `hashSize` (default: `10`): The BCrypt salt length\n- `errorMessage` (default: `'Invalid login'`): The error message to return on errors\n- `entityUsernameField` (default: `usernameField`): Name of the username field on the entity if authentication request data and entity field names are different\n- `entityPasswordField` (default: `passwordField`): Name of the password field on the entity if authentication request data and entity field names are different\n\nOptions are usually set under the registered name via [Feathers configuration](../configuration.md) in `config/default.json` or `config/<environment>.json`:\n\n```json\n{\n  \"authentication\": {\n    \"local\": {\n      \"usernameField\": \"email\",\n      \"passwordField\": \"password\"\n    }\n  }\n}\n```\n\n## LocalStrategy\n\n<BlockQuote type=\"info\" label=\"Note\">\n\nThe methods described in this section are intended for [customization](#customization) purposes and internal calls. They usually do not need to be called directly.\n\n</BlockQuote>\n\n### getEntityQuery(query, params)\n\n`localStrategy.getEntityQuery(query, params) -> Promise` returns the query for finding the entity. `query` includes the `usernameField` or `entityUsernameField` as `{ [field]: username }` and by default returns a promise that resolves with `{ $limit: 1 }` combined with `query`.\n\n### findEntity(username, params)\n\n`localStrategy.findEntity(username, params) -> Promise` return the entity for a given username and service call parameters. It will use the query returned by `getEntityQuery` and call `.find` on the entity (usually `/users`) service. It will return a promise that resolves with the first result of the `.find` call or throw an error if nothing was found.\n\n### getEntity(entity, params)\n\n`localStrategy.getEntity(authResult, params) -> Promise` returns the external representation for `entity` that will be sent back to the client.\n\n### hashPassword(password)\n\n`localStrategy.hashPassword(password) -> Promise` creates a safe one-way hash of the given plain `password` string. By default [bCryptJS](https://www.npmjs.com/package/bcryptjs) is used.\n\n### comparePassword(entity, password)\n\n`localStrategy.comparePassword(entity, password) -> Promise` compares a plain text `password` with the hashed password of the `entity` returned by `findEntity`. Returns the `entity` or throws an error if the passwords don't match.\n\n### authenticate(authentication, params)\n\n`localStrategy.authenticate(authentication, params)` is the main endpoint implemented by any [authentication strategy](./strategy.md). It is usually called for authentication requests for this strategy by the [AuthenticationService](./service.md).\n\n## Customization\n\nThe `LocalStrategy` can be customized like any ES6 class and then registered on the [AuthenticationService](./service.md):\n\n```ts\nimport type { Application, Params, Query } from '@feathersjs/feathers'\nimport { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'\nimport { LocalStrategy } from '@feathersjs/authentication-local'\n\nclass MyLocalStrategy extends LocalStrategy {\n  async getEntityQuery(query: Query, params: Params) {\n    // Query for use but only include `active` users\n    return {\n      ...query,\n      active: true,\n      $limit: 1\n    }\n  }\n}\n\nexport default (app: Application) => {\n  const authService = new AuthenticationService(app)\n\n  authService.register('local', new MyLocalStrategy())\n\n  // ...\n  app.use('/authentication', authService)\n}\n```\n\n## Helpers\n\n### Protecting fields\n\nAs of Feathers v5, external [resolvers](../schema/resolvers.md) using the `schemaHooks.resolveExternal` hook are the preferred method to hide or change fields for external requests. The following will always hide the user password for external responses and events:\n\n```ts\nimport { resolve, schemaHooks } from '@feathersjs/schema'\n\nexport const userExternalResolver = resolve<User, HookContext>({\n  properties: {\n    // The password should never be visible externally\n    password: async () => undefined\n  }\n})\n\napp.service('users').hooks({\n  after: {\n    all: [schemaHooks.resolveExternal(userExternalResolver)]\n  }\n})\n```\n\n### passwordHash\n\nThe `passwordHash` utility provides a [property resolver function](../schema/resolvers.md#property-resolvers) that uses a local strategy to securely [hash the password](#hashpassword-password) before storing it in the database. The following options are available:\n\n- `strategy` - The name of the local strategy (usually `'local'`)\n- `service` - The path of the authentication service (will use `app.get('defaultAuthentication')` by default)\n\n```ts\nexport const userDataResolver = resolve<User, HookContext>({\n  properties: {\n    password: passwordHash({ strategy: 'local' })\n  }\n})\n```\n\n### hashPassword(field)\n\nThe `hashPassword` hook is provided for Feathers v4 backwards compatibility but **has been deprecated** in favour of the [passwordHash resolver](#passwordhash).\n\n### protect(...fields)\n\nThe `protect` hook is provided for Feathers v4 backwards compatibility but **has been deprecated** in favour of [external data resolvers](../schema/resolvers.md).\n"
  },
  {
    "path": "docs/api/authentication/oauth.md",
    "content": "---\noutline: deep\n---\n\n# OAuth\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/authentication-oauth.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/authentication-oauth)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/authentication-oauth/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/authentication-oauth --save\n```\n\n`@feathersjs/authentication-oauth` allows to authenticate with over 180 OAuth providers (Google, Facebook, GitHub etc.) using [grant](https://github.com/simov/grant), an OAuth middleware module for NodeJS.\n\n## Usage\n\nThe following section covers oAuth authentication strategy [setup](#setup) and a more detailed description of the possible oAuth [flows](#flow) and [oAuth URLs](#oauth-urls).\n\n### Setup\n\nThe following is a standard oAuth setup. The `OAuthStrategy` often needs to be [customized](#customization) to include additional fields (like the avatar, email address or username) from the oAuth provider.\n\n```ts\nimport { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'\nimport { LocalStrategy } from '@feathersjs/authentication-local'\nimport { OAuthStrategy, oauth } from '@feathersjs/authentication-oauth'\nimport type { Application } from './declarations'\n\ndeclare module './declarations' {\n  interface ServiceTypes {\n    authentication: AuthenticationService\n  }\n}\n\nexport const authentication = (app: Application) => {\n  const authentication = new AuthenticationService(app)\n\n  authentication.register('jwt', new JWTStrategy())\n  authentication.register('github', new OAuthStrategy())\n  authentication.register('google', new OAuthStrategy())\n\n  app.use('authentication', authentication)\n  app.configure(oauth({}))\n}\n```\n\nThe following settings for `app.configure(oauth())` are available:\n\n- `linkStrategy` (default: `'jwt'`) - The name of the stratagy to use for [account linking](#account-linking)\n- `authService` (default: `app.get('defaultAuthentication')`) - The path of the authentication service to use\n- `expressSession` - An Express middleware for handling sessions. By default will use an HTTP cookie that is only available for the oAuth flow. **This normally does not need to be changed.**\n- `koaSession` - A Koa middleware for handling sessions. By default will use an HTTP cookie that is only available for the oAuth flow. **This normally does not need to be changed.**\n\n### Providers\n\nFor specific OAuth provider setup see the following [cookbook](../../cookbook/) guides:\n\n- [Auth0](../../cookbook/authentication/auth0.md)\n- [Facebook](../../cookbook/authentication/facebook.md)\n- [Google](../../cookbook/authentication/google.md)\n\n### Flow\n\nThere are two ways to initiate OAuth authentication:\n\n1. Through the browser (most common)\n\n   - User clicks on link to OAuth URL (`oauth/<provider>`)\n   - Gets redirected to provider and authorizes the application\n   - Callback to the [OauthStrategy](#oauthstrategy) which\n     - Gets the users profile\n     - Finds or creates the user (entity) for that profile\n   - The [AuthenticationService](./service.md) creates an access token for that entity\n   - Redirects back to the origin URL including the generated access token\n   - The frontend (e.g. the Feathers [authentication client](./client.md)) uses the returned access token to authenticate\n\n2. With an existing access token, e.g. obtained through the Facebook mobile SDK\n   - Authenticate normally through the [authentication service](./service.md) with `{ strategy: '<name>', accessToken: 'oauth access token' }`.\n   - Calls the [OauthStrategy](#oauthstrategy) which\n     - Gets the users profile\n     - Finds or creates the entity for that profile\n   - Returns the authentication result\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nIf you are attempting to authenticate using an existing oAuth access token, ensure that you have added the strategy (e.g. 'facebook') to the allowed [authStrategies](./service.md#configuration) configuration.\n\n</BlockQuote>\n\n### OAuth URLs\n\nThere are two URLs and redirects that are important for OAuth authentication:\n\n- `http(s)://<host>/oauth/<provider>`: The main URL to initiate the OAuth flow. **Link to this from the browser.**\n- `http(s)://<host>/oauth/<provider>/callback`: The callback path that should be **set in the OAuth provider application settings.**\n\nIn the browser any OAuth flow can be initiated with a link like this:\n\n```html\n<a href=\"/oauth/github\">Login with GitHub</a>\n```\n\n### Account linking\n\nTo **link an existing user** the current access token can be added to the OAuth flow query using the `feathers_token` query parameter:\n\n```html\n<a href=\"/oauth/github?feathers_token=<your access token>\"> Login with GitHub </a>\n```\n\nThis will use the user (entity) of that access token to link the OAuth account to. Using the [authentication client](./client.md) you can get the current access token via `app.get('authentication')`:\n\n```ts\nconst { accessToken } = await app.get('authentication')\n```\n\n### Redirects\n\nThe recommended way to enable redirects is to set a list of allowed `origins` in your [application configuration](../configuration.md) (e.g. `config/default.json`). This will ensure cross origin restrictions across your application and allow oAuth authentication from different frontend applications.\n\n```js\n{\n  \"origins\": [\n    // Allow redirect to a local development frontend\n    // (e.g. a create-react-app server) and our production URL\n    \"http://localhost:500\", \"https://myapp.feathersjs.com\"\n  ]\n}\n```\n\n**Alternatively**, the `redirect` configuration can be used to redirect back to the frontend application after OAuth authentication was successful and an access token for the user has been created by the [authentication service](./service.md) or if authentication failed. It works cross domain and by default includes the access token or error message in the window location hash. The following configuration\n\n```js\n{\n  \"authentication\": {\n    \"oauth\": {\n      \"redirect\": \"https://app.mydomain.com/\"\n    }\n  }\n}\n```\n\nA successful oAuth flow will redirect to the origin or redirect URL in the form of `https://app.mydomain.com/#access_token=<user jwt>` or `https://app.mydomain.com/#error=<some error message>`. Redirects can be customized with the [getRedirect()](#getredirect-data) method of the OAuth strategy. The [authentication client](./client.md) handles the default redirects automatically already.\n\n<BlockQuote type=\"info\" label=\"Note\">\n\nThe redirect is using a hash instead of a query string by default because it is not logged server side and can be easily read on the client. You can force query based redirect by adding a `?` to the end of the `redirect` option.\n\n</BlockQuote>\n\nIf the `redirect` option is not set and no origin is available the authentication result data will be sent as JSON instead.\n\nDynamic redirects to the same URL are possible by setting the `redirect` query parameter in the OAuth flow. For example, the following OAuth link:\n\n```html\n<a href=\"/oauth/github?redirect=dashboard\"> Login with GitHub </a>\n```\n\nWith the above configuration will redirect to `https://app.mydomain.com/dashboard` after the OAuth flow.\n\n## Options\n\nOptions are usually set under the registered name via [Feathers configuration](../configuration.md) in `config/default.json` or `config/<environment>.json` under the `authentication.oauth` section. Available options are:\n\n- `origins` (default: `app.get('origins')`): A list of URLs from which oAuth authentication should be allowed. For example setting this option to`[ \"https://feathersjs.com\", \"https://feathers.cloud\" ]` would allow requests from those domains and redirect back to where the request came from. This can be used **instead of** the `redirect` option for a more consisten cross origin configuration via the `app.get('origins')` configuration value and to allow oAuth logins from multiple domains.\n- `redirect`: The URL of the frontend to redirect to with the access token (or error message). The [authentication client](./client.md) handles those redirects automatically. If not set, the authentication result will be sent as JSON instead.\n- `defaults`: Default [Grant configuration](https://github.com/simov/grant#configuration) used for all strategies. The following default options are set automatically:\n  - `prefix` (default: `'/oauth'`) - The OAuth base path\n  - `origin` (default: `http(s)://host[:port]`) - The server path for the oAuth flow to redirect back to. Set this if you are e.g. running your local server on HTTPS\n- `<strategy-name>` (e.g. `twitter`): The [Grant configuration](https://github.com/simov/grant#configuration) used for a specific strategy.\n\n<BlockQuote type=\"tip\">\n\nRemoving the `redirect` option allows to troubleshoot troubleshoot OAuth authentication errors as a JSON response by opening the oAuth URL directly in the browser.\n\n</BlockQuote>\n\n```json\n{\n  \"authentication\": {\n    \"origins\": [\"localhost:3030\"],\n    \"oauth\": {\n      \"redirect\": \"/frontend\",\n      \"google\": {\n        \"key\": \"...\",\n        \"secret\": \"...\",\n        \"custom_params\": { \"access_type\": \"offline\" }\n      },\n      \"twitter\": {\n        \"key\": \"...\",\n        \"secret\": \"...\"\n      }\n    }\n  }\n}\n```\n\n<BlockQuote type=\"info\" label=\"Note\">\n\nAll OAuth strategies will by default always look for configuration under `authentication.oauth.<name>`. If `authentication.oauth` is not set in the configuration, OAuth authentication will be disabled.\n\n</BlockQuote>\n\nHere is a [list of all Grant configuration options](https://github.com/simov/grant#all-available-options) that are available:\n\n| Key                        | Location                                                                   | Description                                                                                              |\n| :------------------------- | :------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------- |\n| request_url                | [oauth.json](https://github.com/simov/grant/blob/master/config/oauth.json) | OAuth1/step1                                                                                             |\n| authorize_url              | [oauth.json](https://github.com/simov/grant/blob/master/config/oauth.json) | OAuth1/step2 or OAuth2/step1                                                                             |\n| access_url                 | [oauth.json](https://github.com/simov/grant/blob/master/config/oauth.json) | OAuth1/step3 or OAuth2/step2                                                                             |\n| oauth                      | [oauth.json](https://github.com/simov/grant/blob/master/config/oauth.json) | OAuth version number                                                                                     |\n| scope_delimiter            | [oauth.json](https://github.com/simov/grant/blob/master/config/oauth.json) | string delimiter used for concatenating multiple scopes                                                  |\n| protocol, host, path       | `defaults`                                                                 | used to generate `redirect_uri`                                                                          |\n| transport                  | `defaults`                                                                 | [transport](#response-data-transport) to use to deliver the response data in your final `callback` route |\n| state                      | `defaults`                                                                 | toggle random `state` string generation for OAuth2                                                       |\n| key                        | `[provider]`                                                               | OAuth app key, reserved aliases: `consumer_key` and `client_id`                                          |\n| secret                     | `[provider]`                                                               | OAuth app secret, reserved aliases: `consumer_secret` and `client_secret`                                |\n| scope                      | `[provider]`                                                               | list of scopes to request                                                                                |\n| custom_params              | `[provider]`                                                               | custom authorization [parameters](#custom-parameters) and their values                                   |\n| subdomain                  | `[provider]`                                                               | string to be [embedded](#subdomain-urls) in `request_url`, `authorize_url` and `access_url`              |\n| nonce                      | `[provider]`                                                               | toggle random `nonce` string generation for [OpenID Connect](#openid-connect) providers                  |\n| callback                   | `[provider]`                                                               | final callback route on your server to receive the [response data](#response-data)                       |\n| dynamic                    | `[provider]`                                                               | allow [dynamic override](#dynamic-override) of configuration                                             |\n| overrides                  | `[provider]`                                                               | [static overrides](#static-overrides) for a provider                                                     |\n| response                   | `[provider]`                                                               | [limit](#limit-response-data) the response data                                                          |\n| token_endpoint_auth_method | `[provider]`                                                               | authentication method for the [token endpoint](#token-endpoint-auth-method)                              |\n| name                       | generated                                                                  | provider's [name](#grant), used to generate `redirect_uri`                                               |\n| profile_url                | [grant-profile](https://github.com/simov/grant-profile)                    | The URL to retrieve the user profile from                                                                |\n| [provider]                 | generated                                                                  | provider's [name](#grant) as key                                                                         |\n| redirect_uri               | generated                                                                  | OAuth app [redirect URI](#redirect-uri), generated using `protocol`, `host`, `path` and `name`           |\n\n## OAuthStrategy\n\n### entityId\n\n`oauthStrategy.entityId -> string` returns the name of the id property of the entity.\n\n### getEntityQuery(profile, params)\n\n`oauthStrategy.getEntityQuery(profile, params) -> Promise` returns the entity lookup query to find the entity for a profile. By default returns\n\n```js\n{\n  [`${this.name}Id`]: profile.sub || profile.id\n}\n```\n\n### getEntityData(profile, entity, params)\n\n`oauthStrategy.getEntityData(profile, existing, params) -> Promise` returns the data to either create a new or update an existing entity. `entity` is either the existing entity or `null` when creating a new entity.\n\n### getProfile(data, params)\n\n`oauthStrategy.getProfile(data, params) -> Promise` returns the user profile information from the OAuth provider that was used for the login. `data` is the OAuth callback information which normally contains e.g. the OAuth access token.\n\n### getRedirect (data)\n\n`oauthStrategy.getRedirect(data) -> Promise` returns the URL to redirect to after a successful OAuth login and entity lookup or creation. By default it redirects to `authentication.oauth.redirect` from the configuration with `#access_token=<access token for entity>` added to the end of the URL. The `access_token` hash is e.g. used by the [authentication client](./client.md) to log the user in after a successful OAuth login. The default redirects do work cross domain.\n\n### getAllowedOrigin (params)\n\n`oauthStrategy.getAllowedOrigin(params) -> Promise` returns the redirect base URL or throws an error if it is not allowed.\n\n### getCurrentEntity(params)\n\n`oauthStrategy.getCurrentEntity(params) -> Promise` returns the currently linked entity for the given `params`. It will either use the entity authenticated by `params.authentication` or return `null`.\n\n### findEntity(profile, params)\n\n`oauthStrategy.findEntity(profile, params) -> Promise` finds an entity for a given OAuth profile. Uses `{ [${this.name}Id]: profile.id }` by default.\n\n### createEntity(profile, params)\n\n`oauthStrategy.createEntity(profile, params) -> Promise` creates a new entity for the given OAuth profile. Uses `{ [${this.name}Id]: profile.id }` by default.\n\n### updateEntity(entity, profile, params)\n\n`oauthStrategy.updateEntity(entity, profile, params) -> Promise` updates an existing entity with the given profile. Uses `{ [${this.name}Id]: profile.id }` by default.\n\n### authenticate(authentication, params)\n\n`oauthStrategy.authenticate(authentication, params)` is the main endpoint implemented by any [authentication strategy](./strategy.md). It is usually called for authentication requests for this strategy by the [AuthenticationService](./service.md).\n\n## Customization\n\nNormally, any OAuth provider set up in the [configuration](#configuration) will be initialized with the default [OAuthStrategy](#oauthstrategy). The flow for a specific provider can be customized by extending `OAuthStrategy` class and registering it under that name on the [AuthenticationService](./service.md):\n\n```ts\nimport { Application } from '@feathersjs/feathers'\nimport { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'\nimport type { OAuthProfile } from '@feathersjs/authentication'\nimport { OAuthStrategy } from '@feathersjs/authentication-oauth'\n\ndeclare module './declarations' {\n  interface ServiceTypes {\n    authentication: AuthenticationService\n  }\n}\n\nclass MyGithubStrategy extends OAuthStrategy {\n  async getEntityData(profile: OAuthProfile) {\n    // Include the `email` from the GitHub profile when creating\n    // or updating a user that logged in with GitHub\n    const baseData = await super.getEntityData(profile)\n\n    return {\n      ...baseData,\n      email: profile.email\n    }\n  }\n}\n\nexport default (app: Application) => {\n  const authentication = new AuthenticationService(app)\n\n  authentication.register('github', new MyGithubStrategy())\n\n  // ...\n  app.use('authentication', authentication)\n}\n```\n"
  },
  {
    "path": "docs/api/authentication/service.md",
    "content": "---\noutline: deep\n---\n\n# Authentication Service\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/authentication.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/authentication)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/authentication/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/authentication --save\n```\n\nThe `AuthenticationService` is a [Feathers service](../services.md) that allows to register different [authentication strategies](./strategy.md) and manage access tokens (using [JSON web tokens (JWT)](https://jwt.io/) by default). This section describes\n\n- The [standard setup](#setup) used by the generator\n- How to [configure](#configuration) authentication and where the configuration should go\n- The different [authentication flows](#authentication-flows)\n- The methods available on the authentication service\n- How to [customize](#customization) the authentication service\n- The [Events](#events) sent by the authentication service\n\n## Setup\n\nThe standard setup initializes an [AuthenticationService](#authenticationservice) at the `/authentication` path with a [JWT strategy](./jwt.md), [Local strategy](./local.md) and [OAuth authentication](./oauth.md) (if selected).\n\n```ts\nimport { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'\nimport { LocalStrategy } from '@feathersjs/authentication-local'\nimport type { Application } from './declarations'\n\ndeclare module './declarations' {\n  interface ServiceTypes {\n    authentication: AuthenticationService\n  }\n}\n\nexport const authentication = (app: Application) => {\n  const authentication = new AuthenticationService(app)\n\n  authentication.register('jwt', new JWTStrategy())\n  authentication.register('local', new LocalStrategy())\n\n  app.use('authentication', authentication)\n}\n```\n\n## Configuration\n\nThe standard authentication service configuration is normally located in the `authentication` section of a [configuration file](../configuration.md) (default: `config/default.json`).\n\n<BlockQuote type=\"info\" label=\"Note\">\n\nThe authentication service can also be configured dynamically or without Feathers configuration by using [app.set](../application.md#set-name-value), e.g. `app.set('authentication', config)`.\n\n</BlockQuote>\n\nThe following options are available:\n\n- `secret`: The JWT signing secret.\n- `service`: The path of the entity service\n- `authStrategies`: A list of authentication strategy names to allow on this authentication service to create access tokens.\n- `parseStrategies`: A list of authentication strategies that should be used to parse HTTP requests. Defaults to the same as `authStrategies`.\n- `entity`: The name of the field that will contain the entity after successful authentication. Will also be used to set `params[entity]` (usually `params.user`) when using the [authenticate hook](./hook). Can be `null` if no entity is used (see [stateless tokens](../../cookbook/authentication/stateless.md)).\n- `entityId`: The id property of an entity object. Only necessary if the entity service does not have an `id` property (e.g. when using a custom entity service).\n- `jwtOptions`: All options available for the [node-jsonwebtoken package](https://github.com/auth0/node-jsonwebtoken).\n\nAn authentication service configuration in `config/default.json` can look like this:\n\n```json\n{\n  \"authentication\": {\n    \"secret\": \"CHANGE_ME\",\n    \"entity\": \"user\",\n    \"service\": \"users\",\n    \"authStrategies\": [\"jwt\", \"local\"],\n    \"jwtOptions\": {\n      \"header\": { \"typ\": \"access\" },\n      \"audience\": \"https://yourdomain.com\",\n      \"issuer\": \"feathers\",\n      \"algorithm\": \"HS256\",\n      \"expiresIn\": \"1d\"\n    }\n  }\n}\n```\n\n<BlockQuote type=\"info\">\n\n`typ` in the `header` options is not a typo, it is part of the [JWT JOSE header specification](https://tools.ietf.org/html/rfc7519#section-5).\n\n</BlockQuote>\n\nAdditionally to the above configuration, most [strategies](./strategy.md) will look for their own configuration under the name it was registered. An example can be found in the [local strategy configuration](./local.md#configuration).\n\n## Authentication flows\n\nBelow are the flows how the authentication service can be used.\n\n### To _create a new JWT_\n\nFor any strategy allowed in `authStrategies`, a user can call `app.service('/authentication').create(data)` or `POST /authentication` with `data` as `{ strategy: name, ...loginData }`. Internally authentication will then\n\n- Call the strategy `.authenticate` method with `data`\n- Create a JWT for the entity returned by the strategy\n- Return the JWT (`accessToken`) and the additional information from the strategy\n\nFor `local` strategy, the user has to be created before doing auth, otherwise, a 401 `NotAuthenticated` error will be sent.\n\n### To _authenticate an external request_\n\nFor any HTTP request and strategy allowed in `parseStrategies` or - if not set - `authStrategies` authentication will:\n\n- Call [strategy.parse](./strategy.md#parse-req-res) and set the return value of the first strategy that does not return `null` as `params.authentication`\n- Verify `params.authentication` using the [authenticate hook](./hook.md) which calls the strategy `.authenticate` method with `params.authentication` as the data\n- Merge the return value of the strategy with `params` (e.g. setting `params.user`)\n\n### To authenticate _your own service request_\n\nFor any service that uses the [authenticate hook](./hook.md) called internally you can set `params.authentication` in the service call which will then:\n\n- Verify `params.authentication` using the [authenticate hook](./hook.md) which calls the strategy `.authenticate` method with `params.authentication` as the data\n- Merge the return value of the strategy with `params` (e.g. setting `params.user`)\n\n<BlockQuote type=\"warning\">\n\nYou can set `params.authentication` for internal requests on the server but usually setting the entity (`params.user` in most cases) if you already have it available should be preferred. This will avoid the overhead of running authentication again if it has already been done.\n\n</BlockQuote>\n\n## AuthenticationService\n\n### constructor(app [, configKey])\n\n`const authService = new AuthenticationService(app, configKey = 'authentication')` initializes a new authentication service with the [Feathers application](../application.md) instance and a `configKey` which is the name of the configuration property to use via [app.get()](../application.md#get-name) (default: `app.get('authentication')`). Upon initialization it will also update the configuration with the [default settings](#configuration).\n\n### authenticate(data, params, ...strategies)\n\n`authService.authenticate(data, params, ...strategies) -> Promise` is the main authentication method and authenticates `data` and `params` against a list of strategies in `strategies`.\n\n`data` _must_ always contain a `strategy` property indicating the name of the strategy. If `data.strategy` is not available or not allowed (included in the `strategies` list) a `NotAuthenticated` error will be thrown. Otherwise the result of [strategy.authenticate()](./strategy.md#authenticate-authentication-params) will be returned.\n\n### create(data, params)\n\n`authService.create(data, params) -> Promise` runs `authService.authenticate` with `data`, `params` and the list of `strategies` from `authStrategies` in the [configuration](#configuration). As with any other [Feathers service](../services.md), this method will be available to clients, e.g. running a `POST /authentication`.\n\nIf successful it will create a JWT with the payload taken from [authService.getPayload](#getpayload-authresult-params) and the options from [authService.getTokenOptions](#gettokenoptions-authresult-params). `data` _must_ always contain a valid and allowed `strategy` name. Will emit the [`login` event](#app-on-login).\n\n### remove(id, params)\n\n`authService.remove(id, params) -> Promise` should be called with `id` set to `null` or to the authenticated access token. Will verify `params.authentication` and emit the [`logout` event](#app-on-logout) if successful.\n\n### configuration\n\n`authService.configuration` returns a copy of current value of `app.get(configKey)` (default: `app.get('authentication')`). This is a deep copy of the configuration and is not intended to be modified. In order to change the configuration, [app.set(configKey)](../application.md#set-name-value) should be used:\n\n```ts\nconst config = app.get('authentication')\n\n// Update configuration with a new entity\napp.set('authentication', {\n  ...config,\n  entity: 'some other entity name'\n})\n```\n\n### register(name, strategy)\n\n`authService.register(name, strategy)` registers an [authentication strategy](./strategy.md) under `name` and calls the strategy methods `setName`, `setApplication`, `setAuthentication` and `verifyConfiguration` if they are implemented.\n\n### getStrategy(name)\n\n`service.getStrategy(name)` returns the authentication strategy registered under `name`. Usually authentication strategies do not need to be used directly.\n\n### getStrategies(...names)\n\n`service.getStrategies(...names) -> AuthenticationStrategy[]` returns the [authentication strategies](./strategy.md) that exist for a list of names. The returned array may include `undefined` values if the strategy does not exist. Usually authentication strategies do not need to be used directly.\n\n```js\nconst [localStrategy] = authService.getStrategies('local')\n```\n\n### createAccessToken(payload)\n\n`authService.createAccessToken(payload, [options, secret]) -> Promise` creates a new access token. By default it is a [JWT](https://jwt.io/) with `payload`, using [configuration.jwtOptions](#configuration) merged with `options` (optional). It will either use `authService.configuration.secret` or the optional `secret` to sign the JWT. Throws an error if the access token can not be created.\n\n```ts\nconst token = await app.service('authentication').createAccessToken({\n  permission: 'admin'\n})\n```\n\n<BlockQuote type=\"warning\">\n\nNormally, it is not necessary to call this method directly. Calling [authService.create(data, params)](#create-data-params) using an authentication strategy will take care of creating the correct access token.\n\n</BlockQuote>\n\n### verifyAccessToken(accessToken)\n\n`authService.verifyAccessToken(accessToken, [options, secret]) -> Promise` verifies the access token. By default it will try to verify a JWT using `configuration.jwtOptions` merged with `options` (optional). Will either use `configuration.secret` or the optional `secret` to verify the JWT. Returns the encoded payload or throws an error.\n\n### getTokenOptions(authResult, params)\n\n`authService.getTokenOptions(authResult, params) -> Promise` returns the options for creating a new access token based on the return value from calling [authService.authenticate()](#authenticate-data-params-strategies). Called internally on [authService.create()](#create-data-params). It will try to set the JWT `subject` to the entity (user) id if it is available which will then be used by the [JWT strategy](./jwt.md) to populate `params[entity]` (usually `params.user`).\n\n### getPayload(authResult, params)\n\n`authService.getPayload(authResult, params) -> Promise` returns the access token payload for an authentication result (the return value of [authService.create()](#create-data-params)) and [service call parameters](../services.md#params). Called internally on [.create](#create-data-params). Returns either `params.payload` or an empty object (`{}`).\n\n### parse(req, res, ...strategies)\n\n`authService.parse(req, res, ...strategies) -> Promise` parses a [NodeJS HTTP request](https://nodejs.org/api/http.html#http_class_http_incomingmessage) and [HTTP response](https://nodejs.org/api/http.html#http_class_http_serverresponse) for authentication information using `strategies` calling [each strategies `.parse()` method](./strategy.md#parse-req-res) if it is implemented. Will return the value of the first strategy that didn't return `null`. This does _not_ authenticate the request, it will only return authentication information that can be used by `authService.authenticate` or `authService.create`.\n\n### setup(path, app)\n\n`authService.setup(path, app)` verifies the [configuration](#configuration) and makes sure that\n\n- A `secret` has been set\n- If `entity` is not `null`, check if the entity service is available and make sure that either the `entityId` configuration or the `entityService.id` property is set.\n- Register internal hooks to send events and keep real-time connections up to date. All custom hooks should be registered at this time.\n\n## app.get('defaultAuthentication')\n\nAfter registering an authentication service, it will set the `defaultAuthentication` property on the application to its configuration name (`configKey` set in the constructor) if it does not exist. `app.get('defaultAuthentication')` will be used by other parts of Feathers authentication to access the authentication service if it is not otherwise specified. Usually this will be `'authentication'`.\n\n## Customization\n\nThe `AuthenticationService` can be customized like any other class:\n\n```ts\nimport type { Params } from '@feathersjs/feathers'\nimport type { AuthenticationResult } from '@feathersjs/authentication'\nimport { AuthenticationService } from '@feathersjs/authentication'\n\nclass MyAuthService extends AuthenticationService {\n  async getPayload(authResult: AuthenticationResult, params: Params) {\n    // Call original `getPayload` first\n    const payload = await super.getPayload(authResult, params)\n    const { user } = authResult\n\n    if (user && user.permissions) {\n      payload.permissions = user.permissions\n    }\n\n    return payload\n  }\n}\n\napp.use('/authentication', new MyAuthService(app))\n```\n\nThings to be aware of when extending the authentication service:\n\n- When implementing your own `constructor`, always call `super(app, configKey)`\n- When overriding a method, calling `super.method` and working with its return value is recommended unless you are certain your custom method behaves exactly the same way, otherwise things may no longer work as expected.\n- When extending `setup`, `super.setup(path, app)` should always be called, otherwise events and real-time connection authentication will no longer work.\n\n## Events\n\nFor both, `login` and `logout` the event data is `(authenticationResult, params, context) => {}` as follows:\n\n- `authResult` is the return value of the `authService.create` or `authService.remove` call. It usually contains the user and access token.\n- `params` is the service call parameters\n- `context` is the service methods [hook context](../hooks.md#hook-context)\n\n### app.on('login')\n\n`app.on('login', (authenticationResult, params, context) => {})` will be sent after a user logs in. This means, after any successful external call to [authService.create](#create-data-params).\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nThe `login` event is also sent for e.g. reconnections of websockets and may not always have a corresponding `logout` event. Use the [`disconnect` event](../channels.md#app-on-disconnect) for handling disconnection.\n\n</BlockQuote>\n\n### app.on('logout')\n\n`app.on('logout', (authenticationResult, params, context) => {})` will be sent after a user explicitly logs out. This means after any successful external call to [authService.remove](#remove-id-params).\n"
  },
  {
    "path": "docs/api/authentication/strategy.md",
    "content": "---\noutline: deep\n---\n\n# Authentication Strategies\n\nAn authentication strategy is any object or class that implements at least an [authenticate(data, params)]() method. They can be registered with the AuthenticationService to authenticate service calls and other requests. The following strategies already come with Feathers:\n\n- [JWTStrategy](./jwt.md) in `@feathersjs/authentication`\n- [LocalStrategy](./local.md) in `@feathersjs/authentication-local`\n- [OAuthStrategy](./oauth.md) in `@feathersjs/authentication-oauth`\n\nMore details on how to customize existing strategies can be found in their API documentation. This section describes the common methods for all authentication strategies and how a custom authentication strategy can be implemented.\n\n## setName(name)\n\nWill be called with the `name` under which the strategy has been [registered on the authentication service](./service.md#register-name-strategy). Does not have to be implemented.\n\n## setApplication(app)\n\nWill be called with the [Feathers application](../application.md) instance. Does not have to be implemented.\n\n## setAuthentication(service)\n\nWill be called with the [Authentication service](./service.md) this strategy has been registered on. Does not have to be implemented.\n\n## verifyConfiguration()\n\nSynchronously verify the configuration for this strategy and throw an error if e.g. required fields are not set. Does not have to be implemented.\n\n## authenticate(authentication, params)\n\nAuthenticate `authentication` data with additional `params`. `authenticate` should throw a `NotAuthenticated` if it failed or return an authentication result object.\n\n## parse(req, res)\n\nParse a given plain Node HTTP request and response and return `null` or the authentication information it provides. Does not have to be implemented.\n\nThis is called by the authentication service. See [AuthService.parse](https://dove.feathersjs.com/api/authentication/service.html#parse-req-res-strategies)\n\n## AuthenticationBaseStrategy\n\nThe `AuthenticationBaseStrategy` class provides a base class that already implements some of the strategy methods below with some common functionality:\n\n- [setName](#setname-name) sets `this.name`\n- [setApplication](#setapplication-app) sets `this.app`\n- [setAuthentication](#setauthentication-service) sets `this.authentication`\n- `configuration` getter returns `this.authentication.configuration[this.name]`\n- `entityService` getter returns the entity (usually `/users`) service from `this.app`\n\n## Examples\n\nExamples for authentication strategies can be found in the [Cookbook](../../cookbook/):\n\n- [Anonymous strategy](../../cookbook/authentication/anonymous.md)\n"
  },
  {
    "path": "docs/api/channels.md",
    "content": "---\noutline: deep\n---\n\n# Channels\n\nOn a Feathers server with a real-time transport (like [Socket.io](./socketio.md)) configured, event channels determine which connected clients to send [real-time events](./events.md) to and how the sent data should look.\n\nThis chapter describes:\n\n- [Concepts](#concepts) of real-time communication\n- [An example](#example) channels.js file\n- [Real-time Connections](#connections) and how to access them\n- [Channel usage](#channels) and how to retrieve, join and leave channels\n- [Publishing events](#publishing) to channels\n\n<BlockQuote label=\"Important\">\n\nChannels functionality will not be available in the following two scenarios:\n\n- When you're making a rest-only API, not using a real-time adapter.\n- When you're using Feathers on the client. Only server-side Feathers has channel management.\n\n</BlockQuote>\n\nHere are some example logic conditions where channels are useful:\n\n- Real-time events should only be sent to authenticated users\n- Users should only get updates about messages from chat rooms they joined\n- Only users in the same organization should receive real-time updates about their data changes\n- Only admins should be notified when new users are created\n- When a user is created, modified or removed, non-admins should only receive a \"safe\" version of the user object (e.g. only `email`, `id` and `avatar`)\n\n## Concepts\n\nA **_channel_** is basically an array of **_connection_** objects. Each array is explicitly given a name. When using a real-time server transport and a new client connects, you can tell the server to explicitly add that client's connection object to any relevant channels. Any connection in a channel will receive all events that are sent to that channel. This allows clients to receive only their intended messages.\n\nWhen using a real-time transport, the server pushes events (such as \"created\", \"removed\" etc. for a particular service) down to its clients. Using channels allows customizing which clients should receive each event. The client doesn’t subscribe to individual channels, directly, but rather subscribes to specific events like `created`, `patched`, custom events, etc, in which they are interested. Those events will only fire for a client if the server pushes data to one a channel to which the client has been added.\n\nYou can have any number of channels. This helps to organise how data is sent and to control the volume of data, by not sending things that aren't relevant.\n\nThe server can also change connection channel membership from time to time, eg. before vs after login.\n\nThe server needs to explicitly **publish** channels it is interested in sharing with clients before they become available.\n\n## Example\n\nThe example below shows a `channels.js` file illustrating how the different parts fit together:\n\n```ts\nimport type { RealTimeConnection, Params } from '@feathersjs/feathers'\nimport type { Application, HookContext } from './declarations'\n\nexport default function (app: any) {\n  if (typeof app.channel !== 'function') {\n    // If no real-time functionality has been configured just return\n    return\n  }\n\n  app.on('connection', (connection: RealTimeConnection) => {\n    // On a new real-time connection, add it to the anonymous channel\n    app.channel('anonymous').join(connection)\n  })\n\n  app.on('login', (AuthenticationResult: any, { connection }: Params) => {\n    // connection can be undefined if there is no\n    // real-time connection, e.g. when logging in via REST\n    if (connection) {\n      // The connection is no longer anonymous, remove it\n      app.channel('anonymous').leave(connection)\n\n      // Add it to the authenticated user channel\n      app.channel('authenticated').join(connection)\n    }\n  })\n\n  // eslint-disable-next-line no-unused-vars\n  app.publish((data: any, context: HookContext) => {\n    // Here you can add event publishers to channels set up in `channels.js`\n    // To publish only for a specific event use `app.publish(eventname, () => {})`\n    console.log(\n      'Publishing all events to all authenticated users. See `channels.js` and https://docs.feathersjs.com/api/channels.html for more information.'\n    )\n\n    // e.g. to publish all service events to all authenticated users use\n    return app.channel('authenticated')\n  })\n}\n```\n\n## Connections\n\nA connection is an object that represents a real-time connection. It is the same object as `socket.feathers` in a [Socket.io](./socketio.md#params) middleware. You can add any kind of information to it but most notably, when using [authentication](./authentication/service.md), it will contain the authenticated user. By default it is located in `connection.user` once the client has authenticated on the socket (usually by calling `app.authenticate()` on the [client](./client.md)).\n\nWe can get access to the `connection` object by listening to `app.on('connection', connection => {})` or `app.on('login', (payload, { connection }) => {})`.\n\n<BlockQuote type=\"info\" label=\"Note\">\n\nWhen a connection is terminated it will be automatically removed from all channels.\n\n</BlockQuote>\n\n### app.on('connection')\n\n`app.on('connection', connection => {})` is fired every time a new real-time connection is established. This is a good place to add the connection to a channel for anonymous users (in case we want to send any real-time updates to them):\n\n```ts\nimport type { RealTimeConnection } from '@feathersjs/feathers'\n\napp.on('connection', (connection: RealTimeConnection) => {\n  // On a new real-time connection, add it to the\n  // anonymous channel\n  app.channel('anonymous').join(connection)\n})\n```\n\n### app.on('disconnect')\n\n`app.on('disconnect', connection => {})` is fired every time real-time connection is disconnected. This is a good place to to handle disconnections outside of a logout. A connection that is disconnected will always leave all its channels automatically.\n\n### app.on('login')\n\n`app.on('login', (authenticationResult, params, context) => {})` is sent by the [AuthenticationService](./authentication/service.md#app-on-login) on successful login.\n\nThis is a good place to add the connection to channels related to the user (e.g. chat rooms, admin status etc.)\n\n```ts\nimport type { Params } from '@feathersjs/feathers'\nimport type { AuthenticationResult } from '@feathersjs/authentication'\n\napp.on('login', (payload: AuthenticationResult, { connection }: Params) => {\n  // connection can be undefined if there is no\n  // real-time connection, e.g. when logging in via REST\n  if (connection) {\n    // The user attached to this connection\n    const { user } = connection\n\n    // The connection is no longer anonymous, remove it\n    app.channel('anonymous').leave(connection)\n\n    // Add it to the authenticated user channel\n    app.channel('authenticated').join(connection)\n\n    // Channels can be named anything and joined on any condition `\n    // E.g. to send real-time events only to admins use\n    if (user.isAdmin) {\n      app.channel('admins').join(connection)\n    }\n\n    // If the user has joined e.g. chat rooms\n    user.rooms.forEach((room) => {\n      app.channel(`rooms/${room.id}`).join(connection)\n    })\n  }\n})\n```\n\n### app.on('logout')\n\n`app.on('logout', (AuthenticationResult, params, context) => {})` is sent by the [AuthenticationService](./authentication/service.md) on successful logout:\n\n```ts\nimport type { Params } from '@feathersjs/feathers'\nimport type { AuthenticationResult } from '@feathersjs/authentication'\n\napp.on('logout', (payload: AuthenticationResult, { connection }: Params) => {\n  if (connection) {\n    // Join the channels a logged out connection should be in\n    app.channel('anonymous').join(connection)\n  }\n})\n```\n\n<BlockQuote type=\"info\" label=\"note\">\n\nOn `logout` the connection will be removed from all existing channels automatically.\n\n</BlockQuote>\n\n## Channels\n\nA channel is an object that contains a number of connections. It can be created via `app.channel` and allows a connection to join or leave it.\n\n### app.channel(...names)\n\n`app.channel(name) -> Channel`, when given a single name, returns an existing or new named channel:\n\n```ts\napp.channel('admins') // the admin channel\napp.channel('authenticated') // the authenticated channel\n```\n\n`app.channel(name1, name2, ... nameN) -> Channel`, when given multiples names, will return a combined channel. A combined channel contains a list of all connections (without duplicates) and re-directs `channel.join` and `channel.leave` calls to all its child channels.\n\n```ts\n// Combine the anonymous and authenticated channel\nconst combinedChannel = app.channel('anonymous', 'authenticated')\n\n// Join the `anonymous` and `authenticated` channel\ncombinedChannel.join(connection)\n\n// Join the `admins` and `chat` channel\napp.channel('admins', 'chat').join(connection)\n\n// Leave the `admins` and `chat` channel\napp.channel('admins', 'chat').leave(connection)\n\n// Make user with `_id` 5 leave the admins and chat channel\napp.channel('admins', 'chat').leave((connection) => {\n  return connection.user._id === 5\n})\n```\n\n### app.channels\n\n`app.channels -> [string]` returns a list of all existing channel names.\n\n```ts\napp.channel('authenticated')\napp.channel('admins', 'users')\n\napp.channels // [ 'authenticated', 'admins', 'users' ]\n\napp.channel(app.channels) // will return a channel with all connections\n```\n\nThis is useful to e.g. remove a connection from all channels:\n\n```ts\nimport type { RealTimeConnection } from '@feathersjs/feathers'\n\n// When a user is removed, make all their connections leave every channel\napp.service('users').on('removed', (user: User) => {\n  app.channel(app.channels).leave((connection: RealTimeConnection) => {\n    return user._id === connection.user._id\n  })\n})\n```\n\n### channel.join(connection)\n\n`channel.join(connection) -> Channel` adds a connection to this channel. If the channel is a combined channel, add the connection to all its child channels. If the connection is already in the channel it does nothing. Returns the channel object.\n\n```ts\nimport type { Params } from '@feathersjs/feathers'\nimport type { AuthenticationResult } from '@feathersjs/authentication'\n\napp.on('login', (payload: AuthenticationResult, { connection }: Params) => {\n  if (connection && connection.user.isAdmin) {\n    // Join the admins channel\n    app.channel('admins').join(connection)\n\n    // Calling a second time will do nothing\n    app.channel('admins').join(connection)\n  }\n})\n```\n\n### channel.leave(connection|fn)\n\n`channel.leave(connection|fn) -> Channel` removes a connection from this channel. If the channel is a combined channel, remove the connection from all its child channels. Also allows to pass a callback that is run for every connection and returns if the connection should be removed or not. Returns the channel object.\n\n```ts\nimport type { RealTimeConnection } from '@feathersjs/feathers'\n\n// Make the user with `_id` 5 leave the `admins` channel\napp.channel('admins').leave((connection: RealTimeConnection) => {\n  return connection.user._id === 5\n})\n```\n\n### channel.filter(fn)\n\n`channel.filter(fn) -> Channel` returns a new channel filtered by a given function which gets passed the connection.\n\n```ts\nimport type { RealTimeConnection } from '@feathersjs/feathers'\n\n// Returns a new channel with all connections of the user with `_id` 5\nconst userFive = app\n  .channel(app.channels)\n  .filter((connection: RealTimeConnection) => connection.user._id === 5)\n```\n\n### channel.send(data)\n\n`channel.send(data) -> Channel` returns a copy of this channel with customized data that should be sent for this event. Usually this should be handled by modifying either the service method result or setting client \"safe\" data in `context.dispatch` but in some cases it might make sense to still change the event data for certain channels.\n\nWhat data will be sent as the event data will be determined by the first available in the following order:\n\n1. `data` from `channel.send(data)`\n2. `context.dispatch`\n3. `context.result`\n\n```ts\nimport type { RealTimeConnection } from '@feathersjs/feathers'\n\napp.on('connection', (connection: RealTimeConnection) => {\n  // On a new real-time connection, add it to the\n  // anonymous channel\n  app.channel('anonymous').join(connection)\n})\n\n// Send the `users` `created` event to all anonymous\n// users but use only the name as the payload\napp.service('users').publish('created', (data: User) => {\n  return app.channel('anonymous').send({\n    name: data.name\n  })\n})\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nIf a connection is in multiple channels (e.g. `users` and `admins`) it will get the data from the _first_ channel that it is in.\n\n</BlockQuote>\n\n### channel.connections\n\n`channel.connections -> [ object ]` contains a list of all connections in this channel.\n\n### channel.length\n\n`channel.length -> integer` returns the total number of connections in this channel.\n\n## Publishing\n\nPublishers are callback functions that return which channel(s) to send an event to. They can be registered at the application and the service level and for all or specific events. A publishing function gets the event data and context object (`(data, context) => {}`) and returns a named or combined channel, an array of channels or `null`. Only one publisher can be registered for one type. Besides the standard [service event names](./events.md#service-events) an event name can also be a [custom event](./events.md#custom-events). `context` is the [hook context object](./hooks.md) from the service call or an object containing `{ path, service, app, result }` for custom events.\n\n### service.publish([event,] fn)\n\n`service.publish([event,] fn) -> service` registers a publishing function for a specific service for a specific event or all events if no event name was given.\n\n```ts\nimport { HookContext } from './declarations'\nimport type { Params } from '@feathersjs/feathers'\nimport type { AuthenticationResult } from '@feathersjs/authentication'\n\napp.on('login', (payload: AuthenticationResult, { connection }: Params) => {\n  // connection can be undefined if there is no\n  // real-time connection, e.g. when logging in via REST\n  if (connection && connection.user.isAdmin) {\n    app.channel('admins').join(connection)\n  }\n})\n\n// Publish all messages service events only to its room channel\napp.service('messages').publish((data: Message, context: HookContext) => {\n  return app.channel(`rooms/${data.roomId}`)\n})\n\n// Publish the `created` event to admins and the user that sent it\napp.service('users').publish('created', (data: User, context: HookContext) => {\n  return [\n    app.channel('admins'),\n    app.channel(app.channels).filter((connection) => connection.user._id === context.params.user._id)\n  ]\n})\n\n// Prevent all events in the `password-reset` service from being published\napp.service('password-reset').publish(() => null)\n```\n\n### app.publish([event,] fn)\n\n`app.publish([event,] fn) -> app` registers a publishing function for all services for a specific event or all events if no event name was given.\n\n```ts\nimport type { Params } from '@feathersjs/feathers'\nimport type { AuthenticationResult } from '@feathersjs/authentication'\n\napp.on('login', (payload: AuthenticationResult, { connection }: Params) => {\n  // connection can be undefined if there is no\n  // real-time connection, e.g. when logging in via REST\n  if (connection) {\n    app.channel('authenticated').join(connection)\n  }\n})\n\n// Publish all events to all authenticated users\napp.publish((data: any, context: HookContext) => {\n  return app.channel('authenticated')\n})\n\n// Publish the `log` custom event to all connections\napp.publish('log', (data: any, context: HookContext) => {\n  return app.channel(app.channels)\n})\n```\n\n### Publisher precedence\n\nThe first publisher callback found in the following order will be used:\n\n1. Service publisher for a specific event\n2. Service publisher for all events\n3. App publishers for a specific event\n4. App publishers for all events\n\n## Keeping channels updated\n\nSince every application will be different, keeping the connections assigned to channels up to date (e.g. if a user joins/leaves a room) is up to you.\n\nIn general, channels should reflect your persistent application data. This means that it normally isn't necessary for e.g. a user to request to directly join a channel. This is especially important when running multiple instances of an application since channels are only _local_ to the current instance.\n\nInstead, the relevant information (e.g. what rooms a user is currently in) should be stored in the database and then the active connections can be re-distributed into the appropriate channels listening to the proper [service events](./events.md).\n\nThe following example updates all active connections for a given user when the user object (which is assumed to have a `rooms` array being a list of room ids the user has joined) is updated or removed:\n\n```ts\nimport type { RealTimeConnection } from '@feathersjs/feathers'\nimport type { Params } from '@feathersjs/feathers'\nimport type { AuthenticationResult } from '@feathersjs/authentication'\n\n// Join a channel given a user and connection\nconst joinChannels = (user: User, connection: RealTimeConnection) => {\n  app.channel('authenticated').join(connection)\n  // Assuming that the chat room/user assignment is stored\n  // on an array of the user\n  user.rooms.forEach((room) => app.channel(`rooms/${roomId}`).join(connection))\n}\n\n// Get a user to leave all channels\nconst leaveChannels = (user: User) => {\n  app.channel(app.channels).leave((connection) => connection.user._id === user._id)\n}\n\n// Leave and re-join all channels with new user information\nconst updateChannels = (user: User) => {\n  // Find all connections for this user\n  const { connections } = app.channel(app.channels).filter((connection) => connection.user._id === user._id)\n\n  // Leave all channels\n  leaveChannels(user)\n\n  // Re-join all channels with the updated user information\n  connections.forEach((connection) => joinChannels(user, connection))\n}\n\napp.on('login', (payload: AuthenticationResult, { connection }: Params) => {\n  if (connection) {\n    // Join all channels on login\n    joinChannels(connection.user, connection)\n  }\n})\n\n// On `updated` and `patched`, leave and re-join with new room assignments\napp.service('users').on('updated', updateChannels)\napp.service('users').on('patched', updateChannels)\n// On `removed`, remove the connection from all channels\napp.service('users').on('removed', leaveChannels)\n```\n\n<BlockQuote type=\"info\" label=\"Note\">\n\nThe number active connections is usually one (or none) but unless you prevent it explicitly Feathers is not preventing multiple logins of the same user (e.g. with two open browser windows or on a mobile device).\n\n</BlockQuote>\n"
  },
  {
    "path": "docs/api/client/rest.md",
    "content": "---\noutline: deep\n---\n\n# REST Client\n\nThe following chapter describes the use of\n\n- [@feathersjs/rest-client](#feathersjsrest-client) as a client side Feathers HTTP API integration\n- [Direct connection](#http-api) with any other HTTP client\n\n## rest-client\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/client.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/rest-client)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/rest-client/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/rest-client --save\n```\n\n`@feathersjs/rest-client` allows to connect to a service exposed through a REST HTTP transport (e.g. with [Koa](../koa.md#rest) or [Express](../express.md#rest)) using [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), [Superagent](https://github.com/ladjs/superagent) or [Axios](https://github.com/mzabriskie/axios).\n\n<BlockQuote type=\"info\">\n\nFor directly using a Feathers REST API (via HTTP) without using Feathers on the client see the [HTTP API](#http-api) section.\n\n</BlockQuote>\n\n<BlockQuote type=\"tip\">\n\nREST client services do emit `created`, `updated`, `patched` and `removed` events but only _locally for their own instance_. Real-time events from other clients can only be received by using a real-time transport like [Socket.io](./socketio.md).\n\n</BlockQuote>\n\n<BlockQuote type=\"warning\">\n\nA client application can only use **a single transport** (e.g. either REST or Socket.io). Using two transports in the same client application is not necessary.\n\n</BlockQuote>\n\n### rest([baseUrl])\n\nREST client services can be initialized by loading `@feathersjs/rest-client` and initializing a client object with a base URL.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport rest from '@feathersjs/rest-client'\n\nconst app = feathers()\n\n// Connect to the same as the browser URL (only in the browser)\nconst restClient = rest()\n\n// Connect to a different URL\nconst restClient = rest('http://feathers-api.com')\n\n// Configure an AJAX library (see below) with that client\napp.configure(restClient.fetch(window.fetch.bind(window)))\n\n// Connect to the `http://feathers-api.com/messages` service\nconst messages = app.service('messages')\n```\n\nThe base URL is relative from where services are registered. That means that\n\n- A service at `http://api.feathersjs.com/api/v1/messages` with a base URL of `http://api.feathersjs.com` would be available as `app.service('api/v1/messages')`\n- A base URL of `http://api.feathersjs.com/api/v1` would be `app.service('messages')`.\n\n<BlockQuote type=\"warning\" label=\"important\">\n\nIn the browser `window.fetch` (which the same as the global `fetch`) has to be passed as `window.fetch.bind(window)` otherwise it will be called with an incorrect context, causing a JavaScript error: `Failed to execute 'fetch' on 'Window': Illegal invocation`.\n\n</BlockQuote>\n\n### params.headers\n\nRequest specific headers can be through `params.headers` in a service call:\n\n```js\napp.service('messages').create(\n  {\n    text: 'A message from a REST client'\n  },\n  {\n    headers: { 'X-Requested-With': 'FeathersJS' }\n  }\n)\n```\n\n### params.connection\n\nAllows to pass additional options specific to the AJAX library. `params.connection.headers` will be merged with `params.headers`:\n\n```js\napp.configure(restClient.axios(axios))\n\napp.service('messages').get(1, {\n  connection: {\n    // Axios specific options here\n  }\n})\n```\n\n### app.rest\n\n`app.rest` contains a reference to the `connection` object passed to `rest().<name>(connection)`.\n\n### Request libraries\n\nThe Feathers REST client can be used with several HTTP request libraries.\n\n#### Fetch\n\nThe [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) is the recommended way to make client connections since it does not require a third party library on most platforms:\n\n```js\n// In Node\napp.configure(restClient.fetch(fetch))\n\n// In modern browsers\napp.configure(restClient.fetch(window.fetch.bind(window)))\n```\n\nWhere supported, an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) can be used to abort fetch requests:\n\n```js\nconst controller = new AbortController()\n\napp.configure(restClient.fetch(fetch))\n\napp.service('messages').get(1, {\n  connection: {\n    signal: controller.signal\n  }\n})\n\ncontroller.abort()\n```\n\n#### Superagent\n\n[Superagent](http://visionmedia.github.io/superagent/) currently works with a default configuration:\n\n```ts\nimport superagent from 'superagent'\n\napp.configure(restClient.superagent(superagent))\n```\n\n#### Axios\n\n[Axios](http://github.com/mzabriskie/axios) currently works with a default configuration:\n\n```js\nimport axios from 'axios'\n\napp.configure(restClient.axios(axios))\n```\n\nTo use default values for all requests, `axios.create` with [the axios configuration](https://axios-http.com/docs/req_config) can be used:\n\n```js\nimport axios from 'axios'\n\napp.configure(\n  restClient.axios(\n    axios.create({\n      headers: { 'X-Requested-With': 'My-Feathers-Frontend' }\n    })\n  )\n)\n```\n\n### Custom Methods\n\nOn the client, [custom service methods](../services.md#custom-methods) registered using the `methods` option when registering the service via `restClient.service()`:\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport type { Params } from '@feathersjs/feathers'\nimport rest from '@feathersjs/rest-client'\nimport type { RestService } from '@feathersjs/rest-client'\n\n// `data` and return type of custom method\ntype CustomMethodData = { name: string }\ntype CustomMethodResponse = { acknowledged: boolean }\n\ntype ServiceTypes = {\n  // The type is a RestService extended with custom methods\n  myservice: RestService & {\n    myCustomMethod(data: CustomMethodData, params: Params): Promise<CustomMethodResponse>\n  }\n}\n\nconst client = feathers<ServiceTypes>()\n\n// Connect to the same as the browser URL (only in the browser)\nconst restClient = rest().fetch(window.fetch.bind(window))\n\n// Connect to a different URL\nconst restClient = rest('http://feathers-api.com').fetch(window.fetch.bind(window))\n\n// Configure an AJAX library (see below) with that client\nclient.configure(restClient)\n\n// Register a REST client service with all methods listed\nclient.use('myservice', restClient.service('myservice'), {\n  methods: ['find', 'get', 'create', 'update', 'patch', 'remove', 'myCustomMethod']\n})\n\n// Then it can be used like other service methods\nclient.service('myservice').myCustomMethod(data, params)\n```\n\n<BlockQuote type=\"info\">\n\nJust like on the server _all_ methods you want to use have to be listed in the `methods` option.\n\n</BlockQuote>\n\n### Connecting to multiple servers\n\nIt is possible to instantiate and use individual services pointing to different servers by calling `rest('server').<library>().service(name)`:\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport rest from '@feathersjs/rest-client'\n\nconst app = feathers()\n\nconst client1 = rest('http://feathers-api.com').fetch(window.fetch.bind(window))\nconst client2 = rest('http://other-feathers-api.com').fetch(window.fetch.bind(window))\n\n// With additional options to e.g. set authentication information\nconst client2 = rest('http://other-feathers-api.com').fetch(window.fetch.bind(window), {\n  headers: {\n    Authorization: 'Bearer <Token for other-feathers-api.com>'\n  }\n})\n\n// Configuring this will initialize default services for http://feathers-api.com\napp.configure(client1)\n\n// Connect to the `http://feathers-api.com/messages` service\nconst messages = app.service('messages')\n\n// Register /users service that points to http://other-feathers-api.com/users\napp.use('users', client2.service('users'))\n\nconst users = app.service('users')\n```\n\n<BlockQuote type=\"info\" label=\"note\">\n\nIf the authentication information is different, it needs to be set as an option as shown above or via `params.headers` when making the request.\n\n</BlockQuote>\n\n### Extending rest clients\n\nThis can be useful if you e.g. wish to override how the query is transformed before it is sent to the API.\n\n```ts\nimport type { Query } from '@feathersjs/feathers'\nimport { FetchClient } from '@feathersjs/rest-client'\nimport qs from 'qs'\n\nclass CustomFetch extends FetchClient {\n  getQuery(query: Query) {\n    if (Object.keys(query).length !== 0) {\n      const queryString = qs.stringify(query, {\n        strictNullHandling: true\n      })\n\n      return `?${queryString}`\n    }\n\n    return ''\n  }\n}\n\napp.configure(restClient.fetch(fetch, CustomFetch))\n```\n\n## HTTP API\n\nYou can communicate with a Feathers REST API using any other HTTP REST client. The following section describes what HTTP method, body and query parameters belong to which service method call.\n\nAll query parameters in a URL will be set as `params.query` on the server. Other service parameters can be set through [hooks](../hooks.md) and [Express middleware](../express.md). URL query parameter values will always be strings. Conversion (e.g. the string `'true'` to boolean `true`) on the server is done via [schemas](../schema/index.md) or [hooks](../hooks.md).\n\nThe body type for `POST`, `PUT` and `PATCH` requests is determined by the request type. You should also make sure you are setting your `Accept` header to `application/json`. Here is the mapping of service methods to REST API calls:\n\n| Service method | HTTP method | Path        |\n| -------------- | ----------- | ----------- |\n| .find()        | GET         | /messages   |\n| .get()         | GET         | /messages/1 |\n| .create()      | POST        | /messages   |\n| .update()      | PUT         | /messages/1 |\n| .patch()       | PATCH       | /messages/1 |\n| .remove()      | DELETE      | /messages/1 |\n\n### Authentication\n\nAuthenticating HTTP (REST) requests is a two step process. First you have to obtain a JWT from the [authentication service](../authentication/service.md) by POSTing the strategy you want to use:\n\n```json\n// POST /authentication the Content-Type header set to application/json\n{\n  \"strategy\": \"local\",\n  \"email\": \"your email\",\n  \"password\": \"your password\"\n}\n```\n\nHere is what that looks like with curl:\n\n```bash\ncurl -H \"Content-Type: application/json\" -X POST -d '{\"strategy\":\"local\",\"email\":\"your email\",\"password\":\"your password\"}' http://localhost:3030/authentication\n```\n\nThen to authenticate subsequent requests, add the returned `accessToken` to the `Authorization` header as `Bearer <your access token>`:\n\n```bash\ncurl -H \"Content-Type: application/json\" -H \"Authorization: Bearer <your access token>\" http://localhost:3030/messages\n```\n\nFor more information see the [authentication API documentation](../).\n\n### find\n\nRetrieves a list of all matching resources from the service\n\n```\nGET /messages?status=read&user=10\n```\n\nWill call `messages.find({ query: { status: 'read', userId: '10' } })` on the server.\n\nIf you want to use any of the built-in find operands ($le, $lt, $ne, $eq, $in, etc.) the general format is as follows:\n\n```\nGET /messages?field[$operand]=value&field[$operand]=value2\n```\n\nFor example, to find the records where field _status_ is not equal to **active** you could do\n\n```\nGET /messages?status[$ne]=active\n```\n\nThe find API allows the use of $limit, $skip, $sort, and $select in the query. These special parameters can be passed directly inside the query object:\n\n```\n// Find all messages that are read, limit to 10, only include text field.\n{\"status\": \"read\", \"$limit\":10, \"$select\": [\"name\"] } } // JSON\n\nGET /messages?status=read&$limit=10&$select[]=text // HTTP\n```\n\nMore information about the possible parameters for official database adapters can be found [in the database querying section](../databases/querying.md).\n\n### get\n\nRetrieve a single resource from the service.\n\n```\nGET /messages/1\n```\n\nWill call `messages.get(1, {})` on the server.\n\n```\nGET /messages/1?status=read\n```\n\nWill call `messages.get(1, { query: { status: 'read' } })` on the server.\n\n### create\n\nCreate a new resource with `data` which may also be an array.\n\n```\nPOST /messages\n{ \"text\": \"I really have to iron\" }\n```\n\nWill call `messages.create({ \"text\": \"I really have to iron\" }, {})` on the server.\n\n```\nPOST /messages\n[\n  { \"text\": \"I really have to iron\" },\n  { \"text\": \"Do laundry\" }\n]\n```\n\n<BlockQuote type=\"info\" label=\"note\">\n\nWith a [database adapters](../databases/adapters.md) the [`multi` option](../databases/common.md) has to be set explicitly to support creating multiple entries.\n\n</BlockQuote>\n\n### update\n\nCompletely replace a single or multiple resources.\n\n```\nPUT /messages/2\n{ \"text\": \"I really have to do laundry\" }\n```\n\nWill call `messages.update(2, { text: 'I really have to do laundry' }, {})` on the server. When no `id` is given by sending the request directly to the endpoint something like:\n\n```\nPUT /messages?status=unread\n{ \"status\": \"read\" }\n```\n\nWill call `messages.update(null, { status: 'read' }, { query: { status: 'unread' } })` on the server.\n\n### patch\n\nMerge the existing data of a single or multiple resources with the new `data`.\n\n```\nPATCH /messages/2\n{ \"status\": \"read\" }\n```\n\nWill call `messages.patch(2, { status: 'read' }, {})` on the server. When no `id` is given by sending the request directly to the endpoint something like:\n\n```\nPATCH /messages?status=unread\n{ \"status\": \"read\" }\n```\n\nWill call `messages.patch(null, { status: 'read' }, { query: { status: 'unread' } })` on the server to change the status for all read messages.\n\n<BlockQuote type=\"info\" label=\"note\">\n\nWith a [database adapters](../databases/adapters.md) the [`multi` option](../databases/common.md) has to be set to support patching multiple entries.\n\n</BlockQuote>\n\nThis is supported out of the box by the Feathers [database adapters](../databases/adapters.md)\n\n### remove\n\nRemove a single or multiple resources:\n\n```\nDELETE /messages/2\n```\n\nWill call `messages.remove(2, {} })`.\n\nWhen no `id` is given by sending the request directly to the endpoint something like:\n\n```\nDELETE /messages?status=archived\n```\n\nWill call `messages.remove(null, { query: { status: 'archived' } })` to delete all read messages.\n\n<BlockQuote type=\"info\" label=\"note\">\n\nWith a [database adapters](../databases/adapters.md) the [`multi` option](../databases/common.md) has to be set to support patching multiple entries.\n\n</BlockQuote>\n\n### Custom methods\n\n[Custom service methods](../services.md#custom-methods) can be called directly via HTTP by sending a POST request and setting the `X-Service-Method` header to the method you want to call:\n\n```\nPOST /messages\n\nX-Service-Method: myCustomMethod\n\n{\n  \"message\": \"Hello world\"\n}\n```\n\nVia CURL:\n\n```bash\ncurl -H \"Content-Type: application/json\" -H \"X-Service-Method: myCustomMethod\" -X POST -d '{\"message\": \"Hello world\"}' http://localhost:3030/myservice\n```\n\nThis will call `messages.myCustomMethod({ message: 'Hello world' }, {})`.\n\n### Route placeholders\n\nService URLs can have placeholders, e.g. `users/:userId/messages`. (see in [express](../express.md#params.route) or [koa](../koa.md#params.route))\n\nYou can call the client with route placeholders in the `params.route` property:\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport rest from '@feathersjs/rest-client'\n\nconst app = feathers()\n\n// Connect to the same as the browser URL (only in the browser)\nconst restClient = rest()\n\n// Connect to a different URL\nconst restClient = rest('http://feathers-api.com')\n\n// Configure an AJAX library (see below) with that client\napp.configure(restClient.fetch(window.fetch.bind(window)))\n\n// Connect to the `http://feathers-api.com/messages` service\nconst messages = app.service('users/:userId/messages')\n\n// Call the `http://feathers-api.com/users/2/messages` URL\nmessages.find({\n  route: {\n    userId: 2\n  }\n})\n```\n\nThis can also be achieved by using the client bundled,\nsharing several `servicePath` variable exported in the [service shared file](../../guides/cli/service.shared.md#Variables) file.\n\n```ts\nimport rest from '@feathersjs/rest-client'\n// usersMessagesPath contains 'users/:userId/messages'\nimport { createClient, usersMessagesPath } from 'my-app'\n\nconst connection = rest('https://myapp.com').fetch(window.fetch.bind(window))\n\nconst client = createClient(connection)\n\n// Call the `https://myapp.com/users/2/messages` URL\nclient.service(usersMessagesPath).find({\n  route: {\n    userId: 2\n  }\n})\n```\n"
  },
  {
    "path": "docs/api/client/socketio.md",
    "content": "---\noutline: deep\n---\n\n# Socket.io Client\n\n## socketio-client\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/client.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/socketio-client)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/socketio-client/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/socketio-client socket.io-client --save\n```\n\nThe `@feathersjs/socketio-client` module allows to connect to services exposed through the [Socket.io transport](../socketio.md) via a Socket.io socket. We recommend using Feathers and the `@feathersjs/socketio-client` module on the client if possible since it can also handle reconnection and reauthentication. If however, you want to use a direct Socket.io connection without using Feathers on the client, see the [Direct connection](#direct-connection) section.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nSocket.io is also used to _call_ service methods. Using sockets for both calling methods and receiving real-time events is generally faster than using [REST](./rest.md). There is therefore no need to use both REST and Socket.io in the same client application.\n\n</BlockQuote>\n\n### socketio(socket)\n\nInitialize the Socket.io client using a given socket and the default options.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio-client'\nimport io from 'socket.io-client'\n\nconst socket = io('http://api.feathersjs.com')\nconst app = feathers()\n\n// Set up Socket.io client with the socket\napp.configure(socketio(socket))\n\n// Receive real-time events through Socket.io\napp.service('messages').on('created', (message) => console.log('New message created', message))\n\n// Call the `messages` service\napp.service('messages').create({\n  text: 'A message from a REST client'\n})\n```\n\n### `app.io`\n\n`app.io` contains a reference to the `socket` object passed to `socketio(socket [, options])`\n\n```ts\napp.io.on('disconnect', (reason: any) => {\n  // Show offline message\n})\n```\n\n### Custom Methods\n\nOn the client, [custom service methods](../services.md#custom-methods) are also registered using the `methods` option when registering the service via `socketClient.service()`:\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport type { Params } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio-client'\nimport type { SocketService } from '@feathersjs/socketio-client'\nimport io from 'socket.io-client'\n\n// `data` and return type of custom method\ntype CustomMethodData = { name: string }\ntype CustomMethodResponse = { acknowledged: boolean }\n\ntype ServiceTypes = {\n  // The type is a Socket service extended with custom methods\n  myservice: SocketService & {\n    myCustomMethod(data: CustomMethodData, params: Params): Promise<CustomMethodResponse>\n  }\n}\n\nconst socket = io('http://api.feathersjs.com')\nconst client = feathers<ServiceTypes>()\nconst socketClient = socketio(socket)\n\n// Set up Socket.io client with the socket\nclient.configure(socketClient)\n\n// Register a socket client service with all methods listed\nclient.use('myservice', socketClient.service('myservice'), {\n  methods: ['find', 'get', 'create', 'update', 'patch', 'remove', 'myCustomMethod']\n})\n\n// Then it can be used like other service methods\nclient.service('myservice').myCustomMethod(data, params)\n```\n\n<BlockQuote type=\"info\">\n\nJust like on the server _all_ methods you want to use have to be listed in the `methods` option.\n\n</BlockQuote>\n\n### Route placeholders\n\nService URLs can have placeholders, e.g. `users/:userId/messages`. (see in [express](../express.md#params.route) or [koa](../koa.md#params.route))\n\nYou can call the client with route placeholders in the `params.route` property:\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio-client'\nimport io from 'socket.io-client'\n\nconst socket = io('http://api.feathersjs.com')\nconst app = feathers()\n\n// Set up Socket.io client with the socket\napp.configure(socketio(socket))\n\n// Call `users/2/messages`\napp.service('users/:userId/messages').find({\n  route: {\n    userId: 2\n  }\n})\n```\n\nThis can also be achieved by using the client bundled,\nsharing several `servicePath` variable exported in the [service shared file](../../guides/cli/service.shared.md#Variables) file.\n\n```ts\nimport rest from '@feathersjs/rest-client'\n\nconst connection = rest('https://myapp.com').fetch(window.fetch.bind(window))\n\nconst client = createClient(connection)\n\n// Call the `https://myapp.com/users/2/messages` URL\nclient.service(usersMyMessagesPath).find({\n  route: {\n    userId: 2\n  }\n})\n\nimport io from 'socket.io-client'\nimport socketio from '@feathersjs/socketio-client'\nimport { createClient, usersMessagesPath } from 'my-app'\n\nconst socket = io('http://api.my-feathers-server.com')\nconst connection = socketio(socket)\n\nconst client = createClient(connection)\n\nconst messageService = client.service('users/:userId/messages')\n\n// Call `users/2/messages`\napp.service('users/:userId/messages').find({\n  route: {\n    userId: 2\n  }\n})\n```\n\n## Direct connection\n\nFeathers sets up a normal Socket.io server that you can connect to with any Socket.io compatible client, usually the [Socket.io client](http://socket.io/docs/client-api/) either by loading the `socket.io-client` module or `/socket.io/socket.io.js` from the server. Query parameter types do not have to be converted from strings as they do for REST requests.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nThe socket connection URL has to point to the server root which is where Feathers will set up Socket.io.\n\n</BlockQuote>\n\n```html\n<!-- Connecting to the same URL -->\n<script src=\"/socket.io/socket.io.js\"></script>\n<script>\n  var socket = io()\n</script>\n\n<!-- Connecting to a different server -->\n<script src=\"http://localhost:3030/socket.io/socket.io.js\"></script>\n<script>\n  var socket = io('http://localhost:3030/')\n</script>\n```\n\nService methods can be called by emitting a `<methodname>` event followed by the service path and method parameters. The service path is the name the service has been registered with (in `app.use`), without leading or trailing slashes. An optional callback following the `function(error, data)` Node convention will be called with the result of the method call or any errors that might have occurred.\n\n`params` will be set as `params.query` in the service method call. Other service parameters can be set through a [Socket.io middleware](../socketio.md).\n\nIf the service path or method does not exist, an appropriate Feathers error will be returned.\n\n### Authentication\n\nThere are two ways to establish an authenticated Socket.io connection. Either by calling the authentication service or by sending authentication headers.\n\n#### Via authentication service\n\nSockets will be authenticated automatically by calling [.create](#create) on the [authentication service](../authentication/service.md):\n\n```ts\nimport io from 'socket.io-client'\n\nconst socket = io('http://localhost:3030')\n\nsocket.emit(\n  'create',\n  'authentication',\n  {\n    strategy: 'local',\n    email: 'hello@feathersjs.com',\n    password: 'supersecret'\n  },\n  function (error, authResult) {\n    console.log(authResult)\n    // authResult will be {\"accessToken\": \"your token\", \"user\": user }\n    // You can now send authenticated messages to the server\n  }\n)\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nWhen a socket disconnects and then reconnects, it has to be authenticated again before making any other request that requires authentication. This is usually done with the [jwt strategy](../authentication/jwt.md) using the `accessToken` from the `authResult`. The [authentication client](../authentication/client.md) handles this already automatically.\n\n</BlockQuote>\n\n```js\nsocket.on('connect', () => {\n  socket.emit(\n    'create',\n    'authentication',\n    {\n      strategy: 'jwt',\n      accessToken: authResult.accessToken\n    },\n    function (error, newAuthResult) {\n      console.log(newAuthResult)\n    }\n  )\n})\n```\n\n#### Via handshake headers\n\nIf the authentication strategy (e.g. JWT or API key) supports parsing headers, an authenticated websocket connection can be established by adding the information in the [extraHeaders option](https://socket.io/docs/client-api/#With-extraHeaders):\n\n```ts\nimport io from 'socket.io-client'\n\nconst socket = io('http://localhost:3030', {\n  extraHeaders: {\n    Authorization: `Bearer <accessToken here>`\n  }\n})\n```\n\n<BlockQuote type=\"info\" label=\"Note\">\n\nThe authentication strategy needs to be included in the [`authStrategies` configuration](../authentication/service.md#configuration).\n\n</BlockQuote>\n\n### find\n\nRetrieves a list of all matching resources from the service\n\n```js\nsocket.emit('find', 'messages', { status: 'read', user: 10 }, (error, data) => {\n  console.log('Found all messages', data)\n})\n```\n\nWill call `app.service('messages').find({ query: { status: 'read', user: 10 } })` on the server.\n\n### get\n\nRetrieve a single resource from the service.\n\n```js\nsocket.emit('get', 'messages', 1, (error, message) => {\n  console.log('Found message', message)\n})\n```\n\nWill call `app.service('messages').get(1, {})` on the server.\n\n```js\nsocket.emit('get', 'messages', 1, { status: 'read' }, (error, message) => {\n  console.log('Found message', message)\n})\n```\n\nWill call `app.service('messages').get(1, { query: { status: 'read' } })` on the server.\n\n### create\n\nCreate a new resource with `data` which may also be an array.\n\n```js\nsocket.emit(\n  'create',\n  'messages',\n  {\n    text: 'I really have to iron'\n  },\n  (error, message) => {\n    console.log('Todo created', message)\n  }\n)\n```\n\nWill call `app.service('messages').create({ text: 'I really have to iron' }, {})` on the server.\n\n```js\nsocket.emit('create', 'messages', [{ text: 'I really have to iron' }, { text: 'Do laundry' }])\n```\n\nWill call `app.service('messages').create` with the array.\n\n### update\n\nCompletely replace a single or multiple resources.\n\n```js\nsocket.emit(\n  'update',\n  'messages',\n  2,\n  {\n    text: 'I really have to do laundry'\n  },\n  (error, message) => {\n    console.log('Todo updated', message)\n  }\n)\n```\n\nWill call `app.service('messages').update(2, { text: 'I really have to do laundry' }, {})` on the server. The `id` can also be `null` to update multiple resources:\n\n```js\nsocket.emit(\n  'update',\n  'messages',\n  null,\n  {\n    status: 'unread'\n  },\n  { status: 'read' }\n)\n```\n\nWill call `app.service('messages').update(null, { status: 'read' }, { query: { satus: 'unread' } })` on the server.\n\n### patch\n\nMerge the existing data of a single or multiple resources with the new `data`.\n\n```js\nsocket.emit(\n  'patch',\n  'messages',\n  2,\n  {\n    read: true\n  },\n  (error, message) => {\n    console.log('Patched message', message)\n  }\n)\n```\n\nWill call `app.service('messages').patch(2, { read: true }, {})` on the server. The `id` can also be `null` to update multiple resources:\n\n```js\nsocket.emit(\n  'patch',\n  'messages',\n  null,\n  {\n    status: 'read'\n  },\n  {\n    status: 'unread'\n  },\n  (error, message) => {\n    console.log('Patched message', message)\n  }\n)\n```\n\nWill call `app.service('messages').patch(null, { status: 'read' }, { query: { status: 'unread' } })` on the server, to change the status for all read app.service('messages').\n\n### remove\n\nRemove a single or multiple resources:\n\n```js\nsocket.emit('remove', 'messages', 2, {}, (error, message) => {\n  console.log('Removed a message', message)\n})\n```\n\nWill call `app.service('messages').remove(2, {})` on the server. The `id` can also be `null` to remove multiple resources:\n\n```js\nsocket.emit('remove', 'messages', null, { status: 'archived' })\n```\n\nWill call `app.service('messages').remove(null, { query: { status: 'archived' } })` on the server to delete all messages with status `archived`.\n\n### Custom methods\n\n[Custom service methods](../services.md#custom-methods) can be called directly via Socket.io by sending a `socket.emit(methodName, serviceName, data, query)` message:\n\n```js\nsocket.emit('myCustomMethod', 'myservice', { message: 'Hello world' }, {}, (error, data) => {\n  console.log('Called myCustomMethod', data)\n})\n```\n\n### Listening to events\n\nListening to service events allows real-time behaviour in an application. [Service events](../events.md) are sent to the socket in the form of `servicepath eventname`.\n\n#### created\n\nThe `created` event will be published with the callback data, when a service `create` returns successfully.\n\n```ts\nconst socket = io('http://localhost:3030/')\n\nsocket.on('messages created', (message: Message) => {\n  console.log('Got a new Todo!', message)\n})\n```\n\n#### updated, patched\n\nThe `updated` and `patched` events will be published with the callback data, when a service `update` or `patch` method calls back successfully.\n\n```ts\nconst socket = io('http://localhost:3030/')\n\nsocket.on('my/messages updated', (message: Message) => {\n  console.log('Got an updated Todo!', message)\n})\n\nsocket.emit(\n  'update',\n  'my/messages',\n  1,\n  {\n    text: 'Updated text'\n  },\n  {},\n  (error, callback) => {\n    // Do something here\n  }\n)\n```\n\n#### removed\n\nThe `removed` event will be published with the callback data, when a service `remove` calls back successfully.\n\n```js\nconst socket = io('http://localhost:3030/')\n\nsocket.on('messages removed', (message: Message) => {\n  // Remove element showing the Todo from the page\n  $('#message-' + message.id).remove()\n})\n```\n\n#### Custom events\n\n[Custom events](../events.md#custom-events) can be listened to accordingly:\n\n```ts\nconst socket = io('http://localhost:3030/')\n\nsocket.on('messages myevent', function (data: any) {\n  console.log('Got myevent event', data)\n})\n```\n"
  },
  {
    "path": "docs/api/client.md",
    "content": "---\noutline: deep\n---\n\n# Feathers Client\n\nOne of the most notable features of Feathers is that it can also be used as the client. In contrast with most other frameworks, it isn't a separate library; instead you get the exact same functionality with a client and on a server. This means you can use [services](./services.md) and [hooks](./hooks.md) and configure plugins. By default, a Feathers client automatically creates services that talk to a Feathers server.\n\nIn order to connect to a Feathers server, a client creates [Services](./services.md) that use a REST or websocket connection to relay method calls and - for a real-time transport like Socket.io - allow listening to [events](./events.md) on the server. This means the [Feathers application instance](./application.md) is usable the exact same way as on the server.\n\nModules most relevant on the client are:\n\n- `@feathersjs/feathers` to initialize a new Feathers [application](./application.md)\n- [@feathersjs/rest-client](./client/rest.md) to connect to services through REST HTTP provided by [Koa](./koa.md) or [Express](./express.md).\n- [@feathersjs/socketio-client](./client/socketio.md) to connect to services through [Socket.io](./socketio.md).\n- [@feathersjs/authentication-client](./authentication/client.md) to authenticate a client\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nYou do not have to use Feathers on the client to connect to a Feathers server. The client [REST client](./client/rest.md) and [Socket.io client](./client/socketio.md) chapters also describe how to use the connection directly without Feathers on the client side.\n\n</BlockQuote>\n\nThis chapter describes how to set up Feathers as the client in Node, React Native and in the browser with a module loader like Webpack or Parcel or through a `<script>` tag. The examples are using [the Socket.io client](./client/socketio.md). For other connection methods see the chapters linked above.\n\n## Typed client\n\nA Feathers application generated with Feathers v5 or later now exports a client file, including the types you defined in [schemas](./schema/index.md) on the server. For more information see the [CLI guide](../guides/cli/client.md)\n\n## Node\n\nTo connect to a Feathers server in NodeJS, install the desired client connection library (here, `socket.io-client`), alongside the Feathers core library, and the connection-specific library:\n\n```\nnpm install @feathersjs/feathers @feathersjs/socketio-client socket.io-client --save\n```\n\nThen initialize like this:\n\n```ts\nimport io from 'socket.io-client'\nimport { feathers } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio-client'\n\nconst socket = io('http://api.my-feathers-server.com')\nconst client = feathers()\n\nclient.configure(socketio(socket))\n\nconst messageService = client.service('messages')\n\nmessageService.on('created', (message: Message) => console.log('Created a message', message))\n\n// Use the messages service from the server\nmessageService.create({\n  text: 'Message from client'\n})\n```\n\n## React Native\n\nReact Native usage is the same as for the [Node client](#node). Install the required packages into your [React Native](https://facebook.github.io/react-native/) project.\n\n```bash\nnpm install @feathersjs/feathers @feathersjs/socketio-client socket.io-client\n```\n\nThen in the main application file:\n\n```ts\nimport io from 'socket.io-client'\nimport { AsyncStorage } from 'react-native'\nimport { feathers } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio-client'\nimport authentication from '@feathersjs/authentication-client'\n\nconst socket = io('http://api.my-feathers-server.com', {\n  transports: ['websocket'],\n  forceNew: true\n})\nconst client = feathers()\n\nclient.configure(socketio(socket))\nclient.configure(\n  authentication({\n    storage: AsyncStorage\n  })\n)\n\nconst messageService = client.service('messages')\n\nmessageService.on('created', (message: Message) => console.log('Created a message', message))\n\n// Use the messages service from the server\nmessageService.create({\n  text: 'Message from client'\n})\n```\n\nSince React Native for Android doesn't handle timeouts exceeding one minute, consider setting lower values for `pingInterval` and `pingTimeout` of [Socket.io](./socketio.md) **on your server**. This will stop warnings related to this [issue](https://github.com/facebook/react-native/issues/12981). For example:\n\n```js\nimport socketio from '@feathersjs/socketio'\n\nconst app = feathers()\n\napp.configure(\n  socketio({\n    pingInterval: 10000,\n    pingTimeout: 50000\n  })\n)\n```\n\n## Module loaders\n\nFeathers client libraries work with the out-of-the-box configuration of all modern module loaders like Webpack, Parcel, Vite etc.\n\n### Webpack\n\nNo additional setup should be necessary to use the Feathers client modules in a standard configuration with Webpack.\n\n### create-react-app\n\n[create-react-app](https://github.com/facebookincubator/create-react-app) uses [Webpack](#webpack) and also no longer requires additional setup to load the individual Feathers client modules.\n\n### Others\n\nFor non-CommonJS formats (like AMD) version of Feathers and its client modules the [@feathersjs/client module](#feathers-client) can be used.\n\n## @feathersjs/client\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/client.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/client)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/client/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/client --save\n```\n\n`@feathersjs/client` is a module that bundles the separate Feathers client-side modules into one file which can be loaded directly in the browser through a `<script>` tag and in most other JavaScript runtimes.\n\n<BlockQuote type=\"danger\" label=\"Important\">\n\nIf you are using a module loader like Webpack, Parcel etc., create-react-app and in React Native and Node you **should not use** `@feathersjs/client`. Use the individual client modules instead. This will give you the most modern builds and reduce bundle size and build/load time. See the [REST client](./client/rest.md) and [Socket.io client](./client/socketio.md) chapters for invidual module use.\n\n</BlockQuote>\n\nHere is a table of which Feathers client module is included:\n\n| Feathers module                   | @feathersjs/client      |\n| --------------------------------- | ----------------------- |\n| @feathersjs/feathers              | feathers (default)      |\n| @feathersjs/errors                | feathers.errors         |\n| @feathersjs/rest-client           | feathers.rest           |\n| @feathersjs/socketio-client       | feathers.socketio       |\n| @feathersjs/authentication-client | feathers.authentication |\n\nWhen you are loading `@feathersjs/client` you do not have to install or load any of the other modules listed in the table above.\n\n### When to use\n\n`@feathersjs/client` can be used directly in the browser using a `<script>` tag without a module loader as well as module loaders that do not support CommonJS (like RequireJS).\n\n### Load from CDN with `<script>`\n\nBelow is an example of the scripts you would use to load `@feathersjs/client` from [unpkg.com](https://unpkg.com).\n\n```html\n<script src=\"//unpkg.com/@feathersjs/client@^5.0.0/dist/feathers.js\"></script>\n<script src=\"//unpkg.com/socket.io-client@^4.0.0/dist/socket.io.js\"></script>\n<script>\n  // Socket.io is exposed as the `io` global.\n  const socket = io('http://localhost:3030')\n  // @feathersjs/client is exposed as the `feathers` global.\n  const app = feathers()\n\n  app.configure(feathers.socketio(socket))\n  app.configure(feathers.authentication())\n\n  app.service('messages').create({\n    text: 'A new message'\n  })\n\n  // feathers.errors is an object with all of the custom error types.\n</script>\n```\n"
  },
  {
    "path": "docs/api/configuration.md",
    "content": "---\noutline: deep\n---\n\n# Configuration\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/configuration.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/configuration)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/configuration/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/configuration --save\n```\n\n`@feathersjs/configuration` is a wrapper for [node-config](https://github.com/lorenwest/node-config) to make configuration values available via [app.get](./application.md#get-name) which can then be used to configure an application.\n\nBy default it will look in `config/*` for `default.json`. It will be merged with other configuration files in the `config/` folder using the `NODE_ENV` environment variable. So setting `NODE_ENV=production` will merge `config/default.json` with `config/production.json`.\n\nFor more information also see the [node-config docs](https://github.com/lorenwest/node-config/wiki/Configuration-Files).\n\n## Usage\n\n`app.configure(configuration())` loads the configuration from `node-config` and makes it available via `app.get()`.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport configuration from '@feathersjs/configuration'\n\n// Use the application root and `config/` as the configuration folder\nconst app = feathers().configure(configuration())\n\n// Will return 3030 with  `{ \"port\": 3030 }` in config/default.json\napp.get('port')\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nDirect access to nested config properties is not supported via `app.get()`. To access a nested config property (e.g. `Customer.dbConfig.host`, use `app.get('Customer').dbConfig.host`.\n\n</BlockQuote>\n\n## Configuration validation\n\n`app.configure(configuration(validator))` loads the configuration from `node-config`, makes it available via `app.get()` and validates the original configuration against a [Feathers schema](./schema/) validator when [app.setup](./application.md#setup-server) (or [app.listen](./application.md#listen-port)) is called.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport { Ajv } from '@feathersjs/schema'\nimport { Type, getValidator } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\nimport configuration from '@feathersjs/configuration'\n\nconst configurationSchema = Type.Object(\n  {\n    port: Type.Number(),\n    host: Type.String()\n  },\n  { $id: 'Configuration', additionalProperties: false }\n)\n\nconst configurationValidator = getValidator(configurationSchema, new Ajv())\n\ntype ServiceTypes = {}\n// Use the schema type for typed `app.get` and `app.set` calls\ntype Configuration = Static<typeof configurationSchema>\n\n// Use the application root and `config/` as the configuration folder\nconst app = feathers<ServiceTypes, Configuration>().configure(configuration(configurationValidator))\n\n// Configuration will only be validated now\napp\n  .listen()\n  .then(() => console.log('Server started'))\n  .catch((error) => {\n    // Configuration validation errors will show up here\n    console.log(error.data)\n  })\n```\n\n## Environment variables\n\nAs recommended by node-config, it is possible to override the configuration with custom variables by passing a JSON object in the [`NODE_CONFIG` environment variable](https://github.com/lorenwest/node-config/wiki/Environment-Variables#node_config):\n\n```\n$ export NODE_CONFIG='{ \"port\":  8080, \"host\": \"production.app\" }'\n$ node myapp.js\n```\n\nIndividual environment variables can be used through [Custom Environment Variables](https://github.com/lorenwest/node-config/wiki/Environment-Variables#custom-environment-variables) by creating a `config/custom-environment-variables.json` like this:\n\n```js\n{\n  \"port\": \"PORT\",\n  \"mongodb\": \"MONGOHQ_URL\"\n}\n```\n\n## Configuration directory\n\nBy default, Feathers will use the `config/` directory in the root of your project’s source directory. To change this, e.g., if you have Feathers installed under the `server/` directory and you want your configuration at `server/config/`, you have to set the `NODE_CONFIG_DIR` environment variable in `app.js` _before_ importing `@feathersjs/configuration`:\n\n```\n$ export NODE_CONFIG_DIR=server/config\n$ node myapp.js\n```\n\n<BlockQuote type=\"info\" label=\"Note\">\n\nThe NODE_CONFIG_DIR environment variable isn’t used directly by @feathersjs/configuration but by the [node-config](https://github.com/lorenwest/node-config) module that it uses. For more information on configuring node-config settings, see the [Configuration Files Wiki page](https://github.com/lorenwest/node-config/wiki/Configuration-Files).\n\n</BlockQuote>\n"
  },
  {
    "path": "docs/api/databases/adapters.md",
    "content": "---\noutline: deep\n---\n\n# Overview\n\nFeathers database adapters are modules that provide [services](../services.md) that implement standard [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) functionality for a specific database. They use a [common API](./common.md) for initialization and settings, and they provide a [common query syntax](./querying.md).\n\n<BlockQuote>\n\n[Services](../services.md) allow to implement access to _any_ database or API. The database adapters listed here are just convenience wrappers with a common API. See the community adapters section for support for other datastores.\n\n</BlockQuote>\n\n## Core Adapters\n\nThe following data storage adapters are available in Feathers core\n\n| Core Package         | Supported Data Stores                                                                                          |\n| -------------------- | -------------------------------------------------------------------------------------------------------------- |\n| [Memory](./memory)   | Memory                                                                                                         |\n| [MongoDB](./mongodb) | MongoDB                                                                                                        |\n| [SQL (Knex)](./knex) | MySQL<br/> MariaDB <br/> PostgreSQL<br/> CockroachDB<br/> SQLite<br/> Amazon Redshift<br/> OracleDB<br/> MSSQL |\n\n## Community Adapters\n\nThere are also many community maintained adapters for other databases and ORMs which can be found on the [Ecosystem page](/ecosystem/?cat=Database&sort=lastPublish).\n"
  },
  {
    "path": "docs/api/databases/common.md",
    "content": "---\noutline: deep\n---\n\n# Common API\n\nThe Feathers database adapters implement a common interface for initialization, pagination, extending and querying. This chapter describes the common adapter initialization and options, how to enable and use pagination, the details on how specific service methods behave and how to extend an adapter with custom functionality.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nEvery database adapter is an implementation of the [Feathers service interface](../services.md). If there is no adapter available for your database of choice, you can still use it directly in a [custom service](../services.md). We recommend being familiar with Feathers services, service events and hooks and the database before using a database adapter.\n\n</BlockQuote>\n\n## Initialization\n\n### `new <Name>Service(options)`\n\nEach adapter exports a `<Name>Service` class that can be exported and extended.\n\n```ts\nimport { NameService } from 'feathers-<name>'\n\napp.use('/messages', new NameService())\napp.use('/messages', new NameService({ id, events, paginate }))\n```\n\n### Options\n\nThe following options are available for all database adapters:\n\n- `id {string}` (_optional_) - The name of the id field property (usually set by default to `id` or `_id`).\n- `paginate {Object}` (_optional_) - A [pagination object](#pagination) containing a `default` and `max` page size\n- `multi {string[]|boolean}` (_optional_, default: `false`) - Allow `create` with arrays and `patch` and `remove` with id `null` to change multiple items. Can be `true` for all methods or an array of allowed methods (e.g. `[ 'remove', 'create' ]`)\n\nThe following legacy options are still available but should be avoided:\n\n- `events {string[]}` (_optional_, **deprecated**) - A list of [custom service events](../events.md#custom-events) sent by this service. Use the `events` option when [registering the service with app.use](../application.md#usepath-service--options) instead.\n- `operators {string[]}` (_optional_, **deprecated**) - A list of additional non-standard query parameters to allow (e.g `[ '$regex' ]`). Not necessary when using a [query schema](../schema/validators.md#validatequery)\n- `filters {Object}` (_optional_, **deprecated**) - An object of additional top level query filters, e.g. `{ $populate: true }`. Can also be a converter function like `{ $ignoreCase: (value) => value === 'true' ? true : false }`. Not necessary when using a [query schema](../schema/validators.md#validatequery)\n\nFor database specific options see the adapter documentation.\n\n## Pagination\n\nWhen initializing an adapter you can set the following pagination options in the `paginate` object:\n\n- `default` - Sets the default number of items when `$limit` is not set\n- `max` - Sets the maximum allowed number of items per page (even if the `$limit` query parameter is set higher)\n\nWhen `paginate.default` is set, `find` will return a _page object_ (instead of the normal array) in the following form:\n\n```\n{\n  \"total\": \"<total number of records>\",\n  \"limit\": \"<max number of items per page>\",\n  \"skip\": \"<number of skipped items (offset)>\",\n  \"data\": [/* data */]\n}\n```\n\nThe pagination options can be set as follows:\n\n```js\nconst service = require('feathers-<db-name>')\n\n// Set the `paginate` option during initialization\napp.use(\n  '/todos',\n  service({\n    paginate: {\n      default: 5,\n      max: 25\n    }\n  })\n)\n\n// override pagination in `params.paginate` for this call\napp.service('todos').find({\n  paginate: {\n    default: 100,\n    max: 200\n  }\n})\n\n// disable pagination for this call\napp.service('todos').find({\n  paginate: false\n})\n```\n\n<BlockQuote type=\"info\" label=\"note\">\n\nDisabling or changing the default pagination is not available in the client. Only `params.query` is passed to the server (also see a [workaround here](https://github.com/feathersjs/feathers/issues/382#issuecomment-288125825))\n\n</BlockQuote>\n\n## params.adapter\n\nSetting the `adapter` in the [service method `params`](../services.md#params) allows do dynamically modify the database adapter options based on the request. This e.g. allows to temporarily allow multiple entry creation/changes or the pagination settings.\n\n```ts\nconst messages = [\n  {\n    text: 'message 1'\n  },\n  {\n    text: 'message 2'\n  }\n]\n\n// Enable multiple entry insertion for this request\napp.service('messages').create(messages, {\n  adapter: {\n    multi: true\n  }\n})\n```\n\n<BlockQuote type=\"tip\">\n\nIf the adapter has a `Model` option, `params.adapter.Model` can be used to point to different databases based on the request to e.g. allow multi-tenant systems. This is usually done by setting `context.params.adapter` in a [hook](../hooks.md).\n\n</BlockQuote>\n\n## params.paginate\n\nSetting `paginate` in the [service method `params`](../services.md#params) allows to change or disable the default pagination for a single request:\n\n```ts\n// Get all messages as an array\nconst allMessages = await app.service('messages').find({\n  paginate: false\n})\n```\n\n## Extending Adapters\n\nThere are two ways to extend existing database adapters. Either by extending the base class or by adding functionality through hooks.\n\n### Classes\n\nAll modules also export an [ES6 class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes) as `<Name>Service` that can be directly extended. See the [Service CLI guide](../../guides/cli/service.class.md) on how to override existing and implement new methods.\n\n## Service methods\n\nThis section describes specifics on how the [service methods](../services.md) are implemented for all adapters.\n\n### constructor(options)\n\nInitializes a new service. Should call `super(options)` when overwritten.\n\n### Methods without hooks\n\nThe database adapters support calling their service methods without any hooks by adding a `_` in front of the method name as `_find`, `_get`, `_create`, `_patch`, `_update` and `_remove`. This can be useful if you need the raw data from the service and don't want to trigger any of its hooks.\n\n```js\n// Call `get` without running any hooks\nconst message = await app.service('/messages')._get('<message id>')\n```\n\n<BlockQuote type=\"warning\" label=\"note\">\n\nThese methods are only available internally on the server, not on the client side and only for the Feathers database adapters. They do _not_ send any events.\n\n</BlockQuote>\n\n### adapter.find(params)\n\n`adapter.find(params) -> Promise` returns a list of all records matching the query in `params.query` using the [common querying mechanism](./querying.md). Will either return an array with the results or a page object if [pagination is enabled](#pagination).\n\n```ts\n// Find all messages for user with id 1\nconst messages = await app.service('messages').find({\n  query: {\n    userId: 1\n  }\n})\n\nconsole.log(messages)\n\n// Find all messages belonging to room 1 or 3\nconst roomMessages = await app.service('messages').find({\n  query: {\n    roomId: {\n      $in: [1, 3]\n    }\n  }\n})\n\nconsole.log(roomMessages)\n```\n\nFind all messages for user with id 1\n\n```\nGET /messages?userId=1\n```\n\nFind all messages belonging to room 1 or 3\n\n```\nGET /messages?roomId[$in]=1&roomId[$in]=3\n```\n\n### adapter.get(id, params)\n\n`adapter.get(id, params) -> Promise` retrieves a single record by its unique identifier (the field set in the `id` option during initialization).\n\n```ts\nconst message = await app.service('messages').get(1)\n\nconsole.log(message)\n```\n\n```\nGET /messages/1\n```\n\n### adapter.create(data, params)\n\n`adapter.create(data, params) -> Promise` creates a new record with `data`. `data` can also be an array to create multiple records.\n\n```ts\nconst message = await app.service('messages').create({\n  text: 'A test message'\n})\n\nconsole.log(message)\n\nconst messages = await app.service('messages').create([\n  {\n    text: 'Hi'\n  },\n  {\n    text: 'How are you'\n  }\n])\n\nconsole.log(messages)\n```\n\n```\nPOST /messages\n{\n  \"text\": \"A test message\"\n}\n```\n\n### adapter.update(id, data, params)\n\n`adapter.update(id, data, params) -> Promise` completely replaces a single record identified by `id` with `data`. Does not allow replacing multiple records (`id` can't be `null`). `id` can not be changed.\n\n```ts\nconst updatedMessage = await app.service('messages').update(1, {\n  text: 'Updates message'\n})\n\nconsole.log(updatedMessage)\n```\n\n```\nPUT /messages/1\n{ \"text\": \"Updated message\" }\n```\n\n### adapter.patch(id, data, params)\n\n`adapter.patch(id, data, params) -> Promise` merges a record identified by `id` with `data`. `id` can be `null` to allow replacing multiple records (all records that match `params.query` the same as in `.find`). `id` can not be changed.\n\n```ts\nconst patchedMessage = await app.service('messages').patch(1, {\n  text: 'A patched message'\n})\n\nconsole.log(patchedMessage)\n\nconst params = {\n  query: { read: false }\n}\n\n// Mark all unread messages as read\nconst multiPatchedMessages = await app.service('messages').patch(\n  null,\n  {\n    read: true\n  },\n  params\n)\n```\n\n```\nPATCH /messages/1\n{ \"text\": \"A patched message\" }\n```\n\nMark all unread messages as read\n\n```\nPATCH /messages?read=false\n{ \"read\": true }\n```\n\n### adapter.remove(id, params)\n\n`adapter.remove(id, params) -> Promise` removes a record identified by `id`. `id` can be `null` to allow removing multiple records (all records that match `params.query` the same as in `.find`).\n\n```ts\nconst removedMessage = await app.service('messages').remove(1)\n\nconsole.log(removedMessage)\n\nconst params = {\n  query: { read: true }\n}\n\n// Remove all read messages\nconst removedMessages = await app.service('messages').remove(null, params)\n```\n\n```\nDELETE /messages/1\n```\n\nRemove all read messages\n\n```\nDELETE /messages?read=true\n```\n"
  },
  {
    "path": "docs/api/databases/knex.md",
    "content": "---\noutline: deep\n---\n\n# SQL Databases\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/knex.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/knex)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/knex/CHANGELOG.md)\n\n</Badges>\n\nSupport for SQL databases like PostgreSQL, MySQL, MariaDB, SQLite or MSSQL is provided in Feathers via the `@feathersjs/knex` database adapter which uses [KnexJS](https://knexjs.org/). Knex is a fast and flexible query builder for SQL and supports many databases without the overhead of a full blown ORM like Sequelize. It still provides an intuitive syntax and more advanced tooling like migration support.\n\n```bash\n$ npm install --save @feathersjs/knex\n```\n\n<BlockQuote>\n\nThe Knex adapter implements the [common database adapter API](./common) and [querying syntax](./querying).\n\n</BlockQuote>\n\n## API\n\n### KnexService(options)\n\n`new KnexService(options)` returns a new service instance initialized with the given options. The following example extends the `KnexService` and then uses the `sqliteClient` (or relevant client for your SQL database type) from the app configuration and provides it to the `Model` option, which is passed to the new `MessagesService`.\n\n```ts\nimport type { Params } from '@feathersjs/feathers'\nimport { KnexService } from '@feathersjs/knex'\nimport type { KnexAdapterParams, KnexAdapterOptions } from '@feathersjs/knex'\n\nimport type { Application } from '../../declarations'\nimport type { Messages, MessagesData, MessagesQuery } from './messages.schema'\n\nexport interface MessagesParams extends KnexAdapterParams<MessagesQuery> {}\n\nexport class MessagesService<ServiceParams extends Params = MessagesParams> extends KnexService<\n  Messages,\n  MessagesData,\n  ServiceParams\n> {}\n\nexport const messages = (app: Application) => {\n  const options: KnexAdapterOptions = {\n    paginate: app.get('paginate'),\n    Model: app.get('sqliteClient'),\n    name: 'messages'\n  }\n  app.use('messages', new MessagesService(options))\n}\n```\n\n### Options\n\nThe Knex specific adapter options are:\n\n- `Model {Knex}` (**required**) - The KnexJS database instance\n- `name {string}` (**required**) - The name of the table\n- `schema {string}` (_optional_) - The name of the schema table prefix (example: `schema.table`)\n- `tableOptions {only: boolean` (_optional_) - For PostgreSQL only. Argument for passing options to knex db builder. ONLY keyword is used before the tableName to discard inheriting tables' data. (https://knexjs.org/guide/query-builder.html#common)\n- `extendedOperators {[string]: string}` (_optional_) - A map defining additional operators for the query builder. Example: `{ $fulltext: '@@' }` for PostgreSQL full text search. See [Knex source](https://github.com/knex/knex/blob/master/lib/formatter/wrappingFormatter.js#L10) for operators supported by Knex.\n\nThe [common API options](./common.md#options) are:\n\n- `id {string}` (_optional_, default: `'id'`) - The name of the id field property. By design, Knex will always add an `id` property.\n- `paginate {Object}` (_optional_) - A [pagination object](#pagination) containing a `default` and `max` page size\n- `multi {string[]|boolean}` (_optional_, default: `false`) - Allow `create` with arrays and `patch` and `remove` with id `null` to change multiple items. Can be `true` for all methods or an array of allowed methods (e.g. `[ 'remove', 'create' ]`)\n\nThere are additionally several legacy options in the [common API options](./common.md#options)\n\n### getModel([params])\n\n`service.getModel([params])` returns the [Knex](https://knexjs.org/guide/query-builder.html) client for this table.\n\n### db(params)\n\n`service.db([params])` returns the Knex database instance for a request. This will include the `schema` table prefix and use a transaction if passed in `params`.\n\n### createQuery(params)\n\n`service.createQuery(params)` returns a query builder for a service request, including all conditions matching the query syntax. This method can be overriden to e.g. [include associations](#associations) or used in a hook customize the query and then passing it to the service call as [params.knex](#paramsknex).\n\n```ts\napp.service('messages').hooks({\n  before: {\n    find: [\n      async (context: HookContext) => {\n        const query = context.service.createQuery(context.params)\n\n        // do something with query here\n        query.orderBy('name', 'desc')\n\n        context.params.knex = query\n      }\n    ]\n  }\n})\n```\n\n### params.knex\n\nWhen making a [service method](https://docs.feathersjs.com/api/services.html) call, `params` can contain an `knex` property which allows to modify the options used to run the KnexJS query. See [createQuery](#createqueryparams) for an example.\n\n## Querying\n\nIn addition to the [common querying mechanism](./querying.md), this adapter also supports the following operators. Note that these operators need to be added for each query-able property to the [TypeBox query schema](../schema/typebox.md#query-schemas) or [JSON query schema](../schema/schema.md#querysyntax) like this:\n\n```ts\nconst messageQuerySchema = Type.Intersect(\n  [\n    // This will additionally allow querying for `{ name: { $ilike: 'Dav%' } }`\n    querySyntax(messageQueryProperties, {\n      name: {\n        $ilike: Type.String()\n      }\n    }),\n    // Add additional query properties here\n    Type.Object({})\n  ],\n  { additionalProperties: false }\n)\n```\n\n### $like\n\nFind all records where the value matches the given string pattern. The following query retrieves all messages that start with `Hello`:\n\n```ts\napp.service('messages').find({\n  query: {\n    text: {\n      $like: 'Hello%'\n    }\n  }\n})\n```\n\nThrough the REST API:\n\n```\n/messages?text[$like]=Hello%\n```\n\n### $notlike\n\nThe opposite of `$like`; resulting in an SQL condition similar to this: `WHERE some_field NOT LIKE 'X'`\n\n```ts\napp.service('messages').find({\n  query: {\n    text: {\n      $notlike: '%bar'\n    }\n  }\n})\n```\n\nThrough the REST API:\n\n```\n/messages?text[$notlike]=%bar\n```\n\n### $ilike\n\nFor PostgreSQL only, the keywork $ilike can be used instead of $like to make the match case insensitive. The following query retrieves all messages that start with `hello` (case insensitive):\n\n```ts\napp.service('messages').find({\n  query: {\n    text: {\n      $ilike: 'hello%'\n    }\n  }\n})\n```\n\nThrough the REST API:\n\n```\n/messages?text[$ilike]=hello%\n```\n\n## Search\n\nBasic search can be implemented with the [query operators](#querying).\n\n## Associations\n\nWhile [resolvers](../schema/resolvers.md) offer a reasonably performant way to fetch associated entities, it is also possible to join tables to populate and query related data. This can be done by overriding the [createQuery](#createqueryparams) method and using the [Knex join methods](https://knexjs.org/guide/query-builder.html#join) to join the tables of related services.\n\n### Querying\n\nConsidering a table like this:\n\n```ts\nawait db.schema.createTable('todos', (table) => {\n  table.increments('id')\n  table.string('text')\n  table.bigInteger('personId').references('id').inTable('people').notNullable()\n  return table\n})\n```\n\nTo query based on properties from the `people` table, join the tables you need in `createQuery` like this:\n\n```ts\nclass TodoService<ServiceParams = KnexAdapterParams<TodoQuery>> extends KnexService<Todo> {\n  createQuery(params: KnexAdapterParams<AdapterQuery>) {\n    const query = super.createQuery(params)\n\n    query.join('people as person', 'todos.personId', 'person.id')\n\n    return query\n  }\n}\n```\n\nThis will alias the table name from `people` to `person` (since our Todo only has a single person) and then allow to query all related properties as dot separated properties like `person.name`, including the [Feathers query syntax](./querying.md):\n\n```ts\n// Find the Todos for all Daves older than 100\napp.service('todos').find({\n  query: {\n    'person.name': 'Dave',\n    'person.age': { $gt: 100 }\n  }\n})\n```\n\nNote that in most applications, the query-able properties have to explicitly be added to the [TypeBox query schema](../schema/typebox.md#query-schemas) or [JSON query schema](../schema/schema.md#querysyntax). Support for the query syntax for a single property can be added with the `queryProperty` helper:\n\n```ts\nimport { queryProperty } from '@feathersjs/typebox'\n\nexport const todoQueryProperties = Type.Pick(userSchema, ['text'])\nexport const todoQuerySchema = Type.Intersect(\n  [\n    querySyntax(userQueryProperties),\n    // Add additional query properties here\n    Type.Object(\n      {\n        // Only query the name for strings\n        'person.name': Type.String(),\n        // Support the query syntax for the age\n        'person.age': queryProperty(Type.Number())\n      },\n      { additionalProperties: false }\n    )\n  ],\n  { additionalProperties: false }\n)\n```\n\n### Populating\n\nRelated properties from the joined table can be added as aliased properties with [query.select](https://knexjs.org/guide/query-builder.html#select):\n\n```ts\nclass TodoService<ServiceParams = KnexAdapterParams<TodoQuery>> extends KnexService<Todo> {\n  createQuery(params: KnexAdapterParams<AdapterQuery>) {\n    const query = super.createQuery(params)\n\n    query\n      .join('people as person', 'todos.personId', 'person.id')\n      // This will add a `personName` property\n      .select('person.name as personName')\n      // This will add a `person.age' property\n      .select('person.age')\n\n    return query\n  }\n}\n```\n\n<BlockQuote type=\"warning\" label=\"important\">\n\nSince SQL does not have a concept of nested objects, joined properties will be dot separated strings, **not nested objects**. Conversion can be done by e.g. using Lodash `_.set` in a [resolver converter](../schema/resolvers.md#options).\n\n</BlockQuote>\n\nThis works well for individual properties, however if you require the complete (and safe) representation of the entire related data, use a [resolver](../schema/resolvers.md) instead.\n\n## Transactions\n\nThe Knex adapter comes with three hooks that allows to run service method calls in a transaction. They can be used as application wide hooks or per service.\n\nTo use the transactions feature, you must ensure that the three hooks (start, end and rollback) are being used.\n\nAt the start of any request, a new transaction will be started. All the changes made during the request to the services that are using knex will use the transaction. At the end of the request, if successful, the changes will be commited. If an error occurs, the changes will be forfeit, all the `creates`, `patches`, `updates` and `deletes` are not going to be commited.\n\nThe object that contains `transaction` is stored in the `params.transaction` of each request.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nIf you call another Knex service within a hook and want to share the transaction you will have to pass `context.params.transaction` in the parameters of the service call.\n\n</BlockQuote>\n\nSometimes it can be important to know when the transaction has been completed (committed or rolled back). For example, we might want to wait for transaction to complete before we send out any realtime events. This can be done by awaiting on the `transaction.committed` promise which will always resolve to either `true` in case the transaction has been committed, or `false` in case the transaction has been rejected.\n\n```ts\napp.service('messages').publish(async (data, context) => {\n  const { transaction } = context.params\n\n  if (transaction) {\n    const success = await transaction.committed\n\n    if (!success) {\n      return []\n    }\n  }\n\n  return app.channel(`rooms/${data.roomId}`)\n})\n```\n\nThis also works with nested service calls and nested transactions. For example, if a service calls `transaction.start()` and passes the transaction param to a nested service call, which also calls `transaction.start()` in it's own hooks, they will share the top most `committed` promise that will resolve once all of the transactions have successfully committed.\n\n\n### Example Transaction Setup\n\nWe will be using TypeBox schemas throughout, but that is not a requirement.\n\nWe will have two services `Order` and `ShippingOrder`\n\nWhen we create an `Order` we want to automatically create a `ShippingOrder`, but if `Order` or `ShippingOrder` fail to be created we want to roll everything back and not save either.\n\n#### Order Schema\n\n```ts\nexport const orderSchema = Type.Object(\n  {\n    id: Type.String({ format: 'uuid' }),\n    item: Type.String(),\n    address: Type.String(),\n    quantity: Type.Number()\n  },\n  { $id: 'Order', additionalProperties: false }\n)\n```\n\n#### Shipping Order Schema\n\n```ts\nexport const shippingOrderSchema = Type.Object(\n  {\n    id: Type.String({ format: 'uuid' }),\n    order_id: Type.String({ format: 'uuid', $schema: 'Order' }),\n    expedited: Type.Boolean(),\n    shipped: Type.Boolean()\n  },\n  { $id: 'ShippingOrder', additionalProperties: false }\n)\n```\n\n#### After hook\n\nLet's start by adding our logic to automatically create our `ShippingOrder`.\n\nIn our `order.ts` file we can add this hook\n\n```ts\nafter: {\n  create: [\n    async (context: HookContext<OrderService>) => {\n      const ourOrder = context.result as Order //Let's not deal with arrays or pagination for now\n\n      await context.app\n        .service(shippingOrderPath)\n        .create({ expedited: true, shipped: false, order_id: ourOrder.id })\n    }\n  ]\n}\n```\n\n#### The problem\n\nNow that we have our logic in, `Order` will automatically create `ShippingOrder`. But what if something goes wrong and the `Order` is created but `ShippingOrder` isn't. This could cause an order to never be shipped.\n\nWe can solve this problem in two ways outlined below.\n\n<BlockQuote>\n\nYou can emulate an error by throwing an error in the before create hook of your `shipping-order.ts` file\n\n```ts\ncreate: [\n  async () => {\n    throw new Error('Fail')\n  },\n  schemaHooks.validateData(shippingOrderDataValidator),\n  schemaHooks.resolveData(shippingOrderDataResolver)\n]\n```\n\n</BlockQuote>\n\n#### Application wide wrapping transaction\n\nUsing the global hooks in `src/app.ts` we are able to wrap all of our `create`, `update`, and `patch` hooks.\n\n```ts\nimport { transaction } from '@feathersjs/knex'\n\nconst transactionHandler = async (context: HookContext<any>, next: NextFunction) => {\n  try {\n    console.log('Start our work')\n    await transaction.start()(context)\n    await next()\n    await transaction.end()(context)\n    console.log('Work done')\n  } catch (err) {\n    console.log('Rollback')\n    await transaction.rollback()(context)\n    throw err\n  }\n}\n\n// Register hooks that run on all service methods\napp.hooks({\n  around: {\n    create: [transactionHandler],\n    patch: [transactionHandler],\n    update: [transactionHandler],\n    delete: [transactionHandler]\n  }\n})\n```\n\nWhat this does is for any `create`/`update`/`patch`/`delete` request, we are starting a transaction that will be available in `context.params.transaction`.\n\nNote this does not mean we are done, when a `create` request is made to `Order`, it will have `context.params.transaction` available to it but we have to pass that along to `ShippingOrder` create request.\n\nLet's revisit our hook that automatically creates `ShippingOrder` and modify it to pass our transaction with the request.\n\n```ts\nafter: {\n  create: [\n    async (context: HookContext<OrderService>) => {\n      const ourOrder = context.result as Order\n\n      await context.app.service(shippingOrderPath).create(\n        { expedited: true, shipped: false, order_id: ourOrder.id },\n        { transaction: context.params.transaction } // <--\n      )\n    }\n  ]\n}\n```\n\n<BlockQuote>\nWe have to use await here otherwise the transaction will close before the creation is finished. For something like sending an email, you can opt to not await.\n\n```ts\ncontext.params.transaction?.committed.then((success: any) => {\n  if (!success) return\n  //Send Email\n})\n```\n\n</BlockQuote>\n\n### Service wide wrapping transaction\n\nThe simplest way of doing this is\n\n- Add `transaction.start()` in the before create hook.\n- Add `transaction.end()` in the after create hook.\n- Add `transaction.rollback()` in the error all hook.\n\n```ts\napp.service(orderPath).hooks({\n  around: {\n    // ...\n  },\n  before: {\n    // ...\n    create: [\n      schemaHooks.validateData(orderDataValidator),\n      schemaHooks.resolveData(orderDataResolver),\n      transaction.start()\n    ]\n  },\n  after: {\n    create: [\n      async (context: HookContext<OrderService>) => {\n        const ourOrder = context.result as Order //Let's not deal with arrays or pagination for now\n\n        await context.app\n          .service(shippingOrderPath)\n          .create(\n            { expedited: true, shipped: false, order_id: ourOrder.id },\n            { transaction: context.params.transaction }\n          )\n      },\n      transaction.end()\n    ]\n  },\n  error: {\n    all: [transaction.rollback()]\n  }\n})\n```\n\n#### Example with around hook\n\nWhen utilizing the around hook, you must pass the context manually. Remember to handle your errors as well, since `around` hooks will not throw into the `error` hook\n\n```ts\n{\n  around: {\n    create: [\n      async (context: HookContext<OrderService>, next: NextFunction) => {\n        console.log('Start Work')\n        await transaction.start()(context)\n        try {\n          //We can do any work here, similar to a before hook\n          await next()\n          const ourOrder = context.result as Order\n\n          await context.app\n            .service(shippingOrderPath)\n            .create(\n              { expedited: true, shipped: false, order_id: ourOrder.id },\n              { transaction: context.params.transaction }\n            )\n          console.log('End Work')\n          transaction.end()(context)\n        } catch (err) {\n          console.log('Rollback')\n          transaction.rollback()(context)\n          throw err\n        }\n      }\n    ]\n  }\n}\n```\n\n\n## Error handling\n\nThe adapter only throws [Feathers Errors](https://docs.feathersjs.com/api/errors.html) with the message to not leak sensitive information to a client. On the server, the original error can be retrieved through a secure symbol via `import { ERROR } from '@feathersjs/knex'`\n\n```ts\nimport { ERROR } from 'feathers-knex'\n\ntry {\n  await knexService.doSomething()\n} catch (error: any) {\n  // error is a FeathersError with just the message\n  // Safely retrieve the Knex error\n  const knexError = error[ERROR]\n}\n```\n\n## Migrations\n\nIn a generated application, migrations are already set up. See the [CLI guide](../../guides/cli/knexfile.md) and the [KnexJS migrations documentation](https://knexjs.org/guide/migrations.html) for more information.\n"
  },
  {
    "path": "docs/api/databases/memory.md",
    "content": "---\noutline: deep\n---\n\n# Memory Adapter\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/memory.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/memory)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/memory/CHANGELOG.md)\n\n</Badges>\n\n`@feathersjs/memory` is a service adatper for in-memory data storage that works on all platforms. It is normally not used to store data on a production server but can be useful for data that isn't persistent and to e.g. cache data in browser or React Native applications.\n\n```bash\n$ npm install --save @feathersjs/memory\n```\n\n<BlockQuote>\n\nThe memory adapter implements the [common database adapter API](./common) and [querying syntax](./querying).\n\n</BlockQuote>\n\n## API\n\n### Usage\n\n```ts\nimport { MemoryService } from '@feathersjs/memory'\n\ntype Message = {\n  id: number\n  text: string\n}\n\ntype MessageData = Pick<Message, 'text'>\n\nclass MyMessageService extends MemoryService<Message, MessageData> {}\n\napp.use('messages', new MyMessageService({}))\n```\n\n### Options\n\nThe following options are available:\n\n- `id` (_optional_, default: `'id'`) - The name of the id field property.\n- `startId` (_optional_, default: `0`) - An id number to start with that will be incremented for every new record (unless it is already set).\n- `store` (_optional_) - An object with id to item assignments to pre-initialize the data store\n- `events` (_optional_) - A list of [custom service events](https://docs.feathersjs.com/api/events.html#custom-events) sent by this service\n- `paginate` (_optional_) - A [pagination object](https://docs.feathersjs.com/api/databases/common.html#pagination) containing a `default` and `max` page size\n- `allow` (_optional_) - A list of additional query parameters to allow\n- `multi` (_optional_) - Allow `create` with arrays and `update` and `remove` with `id` `null` to change multiple items. Can be `true` for all methods or an array of allowed methods (e.g. `[ 'remove', 'create' ]`)\n"
  },
  {
    "path": "docs/api/databases/mongodb.md",
    "content": "---\noutline: deep\n---\n\n# MongoDB\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/mongodb.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/mongodb)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/mongodb/CHANGELOG.md)\n\n</Badges>\n\nSupport for MongoDB is provided in Feathers via the `@feathersjs/mongodb` database adapter which uses the [MongoDB Client for Node.js](https://www.npmjs.com/package/mongodb). The adapter uses the [MongoDB Aggregation Framework](https://www.mongodb.com/docs/manual/aggregation/), internally, and enables using Feathers' friendly syntax with the full power of [aggregation operators](https://www.mongodb.com/docs/manual/meta/aggregation-quick-reference/). The adapter automatically uses the [MongoDB Query API](https://www.mongodb.com/docs/drivers/node/current/quick-reference/) when you need features like [Collation](https://www.mongodb.com/docs/drivers/node/current/fundamentals/collations/).\n\n```bash\n$ npm install --save @feathersjs/mongodb\n```\n\n<BlockQuote>\n\nThe MongoDB adapter implements the [common database adapter API](./common) and [querying syntax](./querying).\n\n</BlockQuote>\n\n## API\n\n### `MongoDBService(options)`\n\n`new MongoDBService(options)` returns a new service instance initialized with the given options. The following example extends the `MongoDBService` and then uses the `mongodbClient` from the app configuration and provides it to the `Model` option, which is passed to the new `MessagesService`.\n\n```ts\nimport type { Params } from '@feathersjs/feathers'\nimport { MongoDBService } from '@feathersjs/mongodb'\nimport type { MongoDBAdapterParams, MongoDBAdapterOptions } from '@feathersjs/mongodb'\n\nimport type { Application } from '../../declarations'\nimport type { Messages, MessagesData, MessagesQuery } from './messages.schema'\n\nexport interface MessagesParams extends MongoDBAdapterParams<MessagesQuery> {}\n\nexport class MessagesService<ServiceParams extends Params = MessagesParams> extends MongoDBService<\n  Messages,\n  MessagesData,\n  ServiceParams\n> {}\n\nexport const messages = (app: Application) => {\n  const options: MongoDBAdapterOptions = {\n    paginate: app.get('paginate'),\n    Model: app.get('mongodbClient').then((db) => db.collection('messages'))\n  }\n  app.use('messages', new MessagesService(options))\n}\n```\n\nHere's an overview of the `options` object:\n\n### Options\n\nMongoDB adapter specific options are:\n\n- `Model {Promise<MongoDBCollection>}` (**required**) - A Promise that resolves with the MongoDB collection instance. This can also be the return value of an `async` function without `await`\n- `disableObjectify {boolean}` (_optional_, default `false`) - This will disable conversion of the id field to a MongoDB ObjectID if you want to e.g. use normal strings\n- `useEstimatedDocumentCount {boolean}` (_optional_, default `false`) - If `true` document counting will rely on `estimatedDocumentCount` instead of `countDocuments`\n- `disabledOperators {string[]}` (_optional_, default `['$rename']`) - A list of [MongoDB update operators](https://www.mongodb.com/docs/manual/reference/operator/update/) to block in `patch` data. See [Securing update operators](#securing-update-operators) for details.\n\nThe [common API options](./common.md#options) are:\n\n- `id {string}` (_optional_, default: `'_id'`) - The name of the id field property. By design, MongoDB will always add an `_id` property. But you can choose to use a different property as your primary key.\n- `paginate {Object}` (_optional_) - A [pagination object](#pagination) containing a `default` and `max` page size\n- `multi {string[]|boolean}` (_optional_, default: `false`) - Allow `create` with arrays and `patch` and `remove` with id `null` to change multiple items. Can be `true` for all methods or an array of allowed methods (e.g. `[ 'remove', 'create' ]`)\n\nThere are additionally several legacy options in the [common API options](./common.md#options)\n\n### getModel()\n\n`getModel([params])` returns a Promise that resolves with the MongoDB collection object. The optional `params` is the service parameters which may allow to override the collection via [params.adapter](./common.md#paramsadapter).\n\n### aggregateRaw(params)\n\nThe `find` method has been split into separate utilities for converting params into different types of MongoDB requests. When using `params.pipeline`, the `aggregateRaw` method is used to convert the Feathers params into a MongoDB aggregation pipeline with the `model.aggregate` method. This method returns a raw MongoDB Cursor object, which can be used to perform custom pagination or in custom server scripts, if desired.\n\n### findRaw(params)\n\n`findRaw(params)` This method is used when there is no `params.pipeline` and uses the common `model.find` method. It returns a raw MongoDB Cursor object, which can be used to perform custom pagination or in custom server scripts, if desired.\n\n### makeFeathersPipeline(params)\n\n`makeFeathersPipeline(params)` takes a set of Feathers params and converts them to a pipeline array, ready to pass to `model.aggregate`. This utility comprises the bulk of the `aggregateRaw` functionality, but does not use `params.pipeline`.\n\n### Custom Params\n\nThe `@feathersjs/mongodb` adapter utilizes three custom params which control adapter-specific features: `params.pipeline`, `params.mongodb`, and `params.adapter`. As mentioned [here](/api/services#params), these custom params are not intended to be used directly from the client. Directly exposing `params.pipeline` or `params.mongodb` to the client directly would expose the entire database to the client through powerful pipeline queries.\n\n#### params.adapter\n\nAllows to dynamically set the [adapter options](#options) (like the `Model` collection) for a service method call.\n\n#### params.pipeline\n\nUsed for [aggregation pipelines](#aggregation-pipeline). Whenever this property is set, the adapter will use the `model.aggregate` method instead of the `model.find` method. The `pipeline` property should be an array of [aggregation stages](https://www.mongodb.com/docs/manual/reference/operator/aggregation-pipeline/).\n\n#### params.mongodb\n\nWhen making a [service method](/api/services.md) call, `params` can contain an`mongodb` property (for example, `{ upsert: true }`) which allows modifying the options used to run the MongoDB query. This param can be used for both find and aggregation queries.\n\n## Transactions\n\n[MongoDB Transactions](https://docs.mongodb.com/manual/core/transactions/) can be used by passing a `session` in [params.mongodb](#paramsmongodb). For example in a [hook](../hooks.md):\n\n```ts\nimport { ObjectId } from 'mongodb'\nimport { HookContext } from '../declarations'\n\nexport const myHook = async (context: HookContext) => {\n  const { app } = context\n  const session = app.get('mongoClient').startSession()\n\n  try {\n    await session.withTransaction(async () => {\n      const fooData = { message: 'Data for foo' }\n      const barData = { text: 'Data for bar' }\n\n      await app.service('fooService').create(fooData, {\n        mongodb: { session }\n      })\n      await app.service('barService').create(barData, {\n        mongodb: { session }\n      })\n    })\n  } finally {\n    await session.endSession()\n  }\n}\n```\n\n## Indexes\n\nIndexes and unique constraints can be added to the `Model` Promise, usually in the `getOptions` in `<service>.class`:\n\n```ts\nexport const getOptions = (app: Application): MongoDBAdapterOptions => {\n  return {\n    paginate: app.get('paginate'),\n    Model: app\n      .get('mongodbClient')\n      .then((db) => db.collection('myservice'))\n      .then((collection) => {\n        collection.createIndex({ email: 1 }, { unique: true })\n\n        return collection\n      })\n  }\n}\n```\n\n<BlockQuote type=\"info\">\n\nNote that creating indexes for an existing collection with many entries should be done as a separate operation instead. See the [MongoDB createIndex documentation](https://www.mongodb.com/docs/manual/reference/method/db.collection.createIndex/) for more information.\n\n</BlockQuote>\n\n## Querying\n\nAdditionally to the [common querying mechanism](./querying.md) this adapter also supports [MongoDB's query syntax](https://www.mongodb.com/docs/manual/tutorial/query-documents/) and the `update` method also supports MongoDB [update operators](https://www.mongodb.com/docs/manual/reference/operator/update/).\n\n## Securing update operators\n\nThe `patch` method supports MongoDB [update operators](https://www.mongodb.com/docs/manual/reference/operator/update/) like `$push`, `$inc`, and `$unset` in the data payload. While this is powerful, it can be a security risk if patch data from the client is not properly validated. For example, an authenticated user who can patch their own profile could send:\n\n```ts\n// Escalate privileges by pushing to a roles array\nawait app.service('users').patch(userId, { $push: { roles: 'admin' } })\n\n// Expose internal fields by renaming them\nawait app.service('users').patch(userId, { $rename: { secretField: 'public' } })\n```\n\n### Schema validation\n\nThe primary defense is to use [schema validation](../schema/validators.md) on your patch data. When your schema only allows known fields with known types, unexpected operators will be rejected before they reach the database.\n\n### The `disabledOperators` option\n\nAs an additional layer of defense, the `disabledOperators` option blocks specific update operators from being passed through to MongoDB. By default, `$rename` is blocked.\n\nTo block additional operators on a service:\n\n```ts\nnew MongoDBService({\n  Model: app.get('mongodbClient').then((db) => db.collection('users')),\n  disabledOperators: ['$rename', '$unset', '$inc']\n})\n```\n\nTo override per-call via `params.adapter`:\n\n```ts\nservice.patch(id, data, {\n  adapter: { disabledOperators: ['$rename', '$unset'] }\n})\n```\n\nTo allow all operators (not recommended without schema validation):\n\n```ts\nnew MongoDBService({\n  Model: app.get('mongodbClient').then((db) => db.collection('messages')),\n  disabledOperators: []\n})\n```\n\n## Search\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nNote that in a normal application all MongoDB specific operators have to explicitly be added to the [TypeBox query schema](../schema/typebox.md#query-schemas) or [JSON query schema](../schema/schema.md#querysyntax).\n\n</BlockQuote>\n\nThere are two ways to perform search queries with MongoDB:\n\n- Perform basic Regular Expression matches using the `$regex` filter.\n- Perform full-text search using the `$search` filter.\n\n### Basic Regex Search\n\nYou can perform basic search using regular expressions with the `$regex` operator. Here's an example query.\n\n```js\n{\n  text: { $regex: 'feathersjs', $options: 'igm' },\n}\n```\n\n### Full-Text Search\n\nSee the MongoDB documentation for instructions on performing full-text search using the `$search` operator:\n\n- Perform [full-text queries on self-hosted MongoDB](https://www.mongodb.com/docs/manual/core/link-text-indexes/).\n- Perform [full-text queries on MongoDB Atlas](https://www.mongodb.com/docs/atlas/atlas-search/) (MongoDB's first-party hosted database).\n- Perform [full-text queries with the MongoDB Pipeline](https://www.mongodb.com/docs/manual/tutorial/text-search-in-aggregation/)\n\n## Aggregation Pipeline\n\nIn Feathers v5 Dove, we added support for the full power of MongoDB's Aggregation Framework and blends it seamlessly with the familiar Feathers Query syntax. The `find` method automatically uses the aggregation pipeline when `params.pipeline` is set.\n\nThe Aggregation Framework is accessed through the mongoClient's `model.aggregate` method, which accepts an array of \"stages\". Each stage contains an operator which describes an operation to apply to the previous step's data. Each stage applies the operation to the results of the previous step. It’s now possible to perform any of the [Aggregation Stages](https://www.mongodb.com/docs/upcoming/reference/operator/aggregation-pipeline/) like `$lookup` and `$unwind`, integration with the normal Feathers queries.\n\nHere's how it works with the operators that match the Feathers Query syntax. Let's convert the following Feathers query:\n\n```ts\nconst query = {\n  text: { $regex: 'feathersjs', $options: 'igm' },\n  $sort: { createdAt: -1 },\n  $skip: 20,\n  $limit: 10\n}\n```\n\nThe above query looks like this when converted to aggregation pipeline stages:\n\n```ts\n;[\n  // returns the set of records containing the word \"feathersjs\"\n  { $match: { text: { $regex: 'feathersjs', $options: 'igm' } } },\n  // Sorts the results of the previous step by newest messages, first.\n  { $sort: { createdAt: -1 } },\n  // Skips the first 20 records of the previous step\n  { $skip: 20 },\n  // returns the next 10 records\n  { $limit: 10 }\n]\n```\n\n### Pipeline Queries\n\nYou can use the `params.pipeline` array to append additional stages to the query. This next example uses the `$lookup` operator together with the `$unwind` operator to populate a `user` attribute onto each message based on the message's `userId` property.\n\n```ts\nconst result = await app.service('messages').find({\n  query: { $sort: { name: 1 } },\n  pipeline: [\n    {\n      $lookup: {\n        from: 'users',\n        localField: 'userId',\n        foreignField: '_id',\n        as: 'user'\n      }\n    },\n    { $unwind: { path: '$user' } }\n  ],\n  paginate: false\n})\n```\n\n### Aggregation Stages\n\nIn the example, above, the `query` is added to the pipeline, first. Then additional stages are added in the `pipeline` option:\n\n- The `$lookup` stage creates an array called `user` which contains any matches in `message.userId`, so if `userId` were an array of ids, any matches would be in the `users` array. However, in this example, the `userId` is a single id, so...\n- The `$unwind` stage turns the array into a single `user` object.\n\nThe above is like doing a join, but without the data transforming overhead like you'd get with an SQL JOIN. If you have properly applied index to your MongoDB collections, the operation will typically execute extremely fast for a reasonable amount of data.\n\nA couple of other notable query stages:\n\n- `$graphLookup` lets you recursively pull in a tree of data from a single collection.\n- `$search` lets you do full-text search on fields\n\nAll stages of the pipeline happen directly on the MongoDB server.\n\nRead through the full list of supported stages [in the MongoDB documentation](https://www.mongodb.com/docs/upcoming/reference/operator/aggregation-pipeline/).\n\n### The `$feathers` Stage\n\nThe previous section showed how to append stages to a query using `params.pipeline`. Well, `params.pipeline` also supports a custom `$feathers` operator/stage which allows you to specify exactly where in the pipeline the Feathers Query gets injected.\n\n### Example: Proxy Permissions\n\nImagine a scenario where you want to query the `pages` a user can edit by referencing a `permissions` collection to find out which pages the user can actually edit. Each record in the `permissions` record has a `userId` and a `pageId`. So we need to find and return only the pages to which the user has access by calling `GET /pages` from the client.\n\nWe could put the following query in a hook to pull the correct `pages` from the database in a single query THROUGH the permissions collection. Remember, the request is coming in on the `pages` service, but we're going to query for pages `through` the permissions collection. Assume we've already authenticated the user, so the user will be found at `context.params.user`.\n\n```ts\n// Assume this query on the client\nconst pages = await app.service('pages').find({ query: {} })\n\n// And put this query in a hook to populate pages \"through\" the permissions collection\nconst result = await app.service('permissions').find({\n  query: {},\n  pipeline: [\n    // query all permissions records which apply to the current user\n    {\n      $match: { userId: context.params.user._id }\n    },\n    // populate the pageId onto each `permission` record, as an array containing one page\n    {\n      $lookup: {\n        from: 'pages',\n        localField: 'pageId',\n        foreignField: '_id',\n        as: 'page'\n      }\n    },\n    // convert the `page` array into an object, so now we have an array of permissions with permission.page on each.\n    {\n      $unwind: { path: '$page' }\n    },\n    // Add a permissionId to each page\n    {\n      $addFields: {\n        'page.permissionId': '$_id'\n      }\n    },\n    // discard the permission and only keep the populated `page`, and bring it top level in the array\n    {\n      $replaceRoot: { newRoot: '$page' }\n    },\n    // apply the feathers query stages to the aggregation pipeline.\n    // now the query will apply to the pages, since we made the pages top level in the previous step.\n    {\n      $feathers: {}\n    }\n  ],\n  paginate: false\n})\n```\n\nNotice the `$feathers` stage in the above example. It will apply the query to that stage in the pipeline, which allows the query to apply to pages even though we had to make the query through the `permissions` service.\n\nIf we were to express the above query with JavaScript, the final result would the same as with the following example:\n\n```ts\n// perform a db query to get the permissions\nconst permissions = await context.app.service('permissions').find({\n  query: {\n    userId: context.params.user._id\n  },\n  paginate: false\n})\n// make a list of pageIds\nconst pageIds = permissions.map((permission) => permission.pageId)\n// perform a db query to get the pages with matching `_id`\nconst pages = await context.app.service('pages').find({\n  query: {\n    _id: {\n      $in: pageIds\n    }\n  },\n  paginate: false\n})\n// key the permissions by pageId for easy lookup\nconst permissionsByPageId = permissions.reduce((byId, current) => {\n  byId[current.pageId] = current\n  return byId\n}, {})\n// Add the permissionId to each `page` record.\nconst pagesWithPermissionId = pages.map((page) => {\n  page.permissionId = permissionByPageId[page._id]._id\n  return page\n})\n// And now apply the original query, whatever the client may have sent, to the pages.\n// It might require another database query\n```\n\nBoth examples look a bit complex, but te one using aggregation stages will be much quicker because all stages run in the database server. It will also be quicker because it all happens in a single database query!\n\nOne more obstacle for using JavaScript this way is that if the user's query changed (from the front end), we would likely be required to edit multiple different parts of the JS logic in order to correctly display results. With the pipeline example, above, the query is very cleanly applied.\n\n## Collation\n\nThis adapter includes support for [collation and case insensitive indexes available in MongoDB v3.4](https://docs.mongodb.com/manual/release-notes/3.4/#collation-and-case-insensitive-indexes). Collation parameters may be passed using the special `collation` parameter to the `find()`, `remove()` and `patch()` methods.\n\n**Example: Patch records with case-insensitive alphabetical ordering**\n\nThe example below would patch all student records with grades of `'c'` or `'C'` and above (a natural language ordering). Without collations this would not be as simple, since the comparison `{ $gt: 'c' }` would not include uppercase grades of `'C'` because the code point of `'C'` is less than that of `'c'`.\n\n```ts\nconst patch = { shouldStudyMore: true }\nconst query = { grade: { $gte: 'c' } }\nconst collation = { locale: 'en', strength: 1 }\nconst patchedStudent = await students.patch(null, patch, { query, collation })\n```\n\n**Example: Find records with a case-insensitive search**\n\nSimilar to the above example, this would find students with a grade of `'c'` or greater, in a case-insensitive manner.\n\n```ts\nconst query = { grade: { $gte: 'c' } }\nconst collation = { locale: 'en', strength: 1 }\n\nconst collatedStudents = await students.find({ query, collation })\n```\n\nFor more information on MongoDB's collation feature, visit the [collation reference page](https://docs.mongodb.com/manual/reference/collation/).\n\n## ObjectIds\n\nMongoDB uses [ObjectId](https://www.mongodb.com/docs/manual/reference/method/ObjectId/) object as primary keys. To store them in the right format they have to be converted from and to strings.\n\n### AJV keyword\n\nTo validate and convert strings to an object id using AJV, the `keywordObjectId` [AJV keyword](https://ajv.js.org/api.html#ajv-addkeyword-definition-string-object-ajv) helper can be used. It is set up automatically in a generated application using MongoDB.\n\n```ts\nimport { keywordObjectId } from '@feathersjs/mongodb'\n\nconst validator = new Ajv()\n\nvalidator.addKeyword(keywordObjectId)\n```\n\n### ObjectIdSchema\n\nBoth, `@feathersjs/typebox` and `@feathersjs/schema` export an `ObjectIdSchema` helper that creates a schema which can be both, a MongoDB ObjectId or a string that will be converted with the `objectid` keyword:\n\n```ts\nimport { ObjectIdSchema } from '@feathersjs/typebox' // or '@feathersjs/schema'\n\nconst typeboxSchema = Type.Object({\n  userId: ObjectIdSchema()\n})\n\nconst jsonSchema = {\n  type: 'object',\n  properties: {\n    userId: ObjectIdSchema()\n  }\n}\n```\n\n<BlockQuote label=\"Important\" type=\"warning\">\n\nThe `ObjectIdSchema` helper will only work when the [`objectid` AJV keyword](#ajv-keyword) is registered.\n\n</BlockQuote>\n\n### ObjectId resolvers\n\nWhile the AJV format checks if an object id is valid, it still needs to be converted to the right type. An alternative the the [AJV converter](#ajv-converter) is to use [Feathers resolvers](../schema/resolvers.md). The following [property resolver](../schema/resolvers.md) helpers can be used.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nObjectId resolvers do not need to be used when using the [AJV keyword](#ajv-keyword). They are useful however when using another JSON schema validation library.\n\n</BlockQuote>\n\n#### resolveObjectId\n\n`resolveObjectId` resolves a property as an object id. It can be used as a direct property resolver or called with the original value.\n\n```ts\nimport { resolveObjectId } from '@feathersjs/mongodb'\n\nexport const messageDataResolver = resolve<Message, HookContext>({\n  properties: {\n    userId: resolveObjectId\n  }\n})\n\nexport const messageDataResolver = resolve<Message, HookContext>({\n  properties: {\n    userId: async (value, _message, context) => {\n      // If the user is an admin, allow them to create messages for other users\n      if (context.params.user.isAdmin && value !== undefined) {\n        return resolveObjectId(value)\n      }\n      // Otherwise associate the record with the id of the authenticated user\n      return context.params.user._id\n    }\n  }\n})\n```\n\n#### resolveQueryObjectId\n\n`resolveQueryObjectId` allows to query for object ids. It supports conversion from a string to an object id as well as conversion for values from the [$in, $nin and $ne query syntax](./querying.md).\n\n```ts\nimport { resolveQueryObjectId } from '@feathersjs/mongodb'\n\nexport const messageQueryResolver = resolve<MessageQuery, HookContext>({\n  properties: {\n    userId: resolveQueryObjectId\n  }\n})\n```\n\n## Dates\n\nWhile MongoDB has a native `Date` type, the most reliable way to deal with dates is to send and store them as UTC millisecond timestamps e.g. returned by [Date.now()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now) or [new Date().getTime()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime) which is also used in the [Feathers getting started guide](../../guides/basics/generator.md). This has a few advantages:\n\n- No conversion between different string types\n- No timezone and winter/summer time issues\n- Easier calculations and query-ability\n"
  },
  {
    "path": "docs/api/databases/querying.md",
    "content": "---\noutline: deep\n---\n\n# Querying\n\nAll official database adapters support a common way for querying, sorting, limiting and selecting `find` and `get` method calls as part of `params.query`. Querying also applies `update`, `patch` and `remove` method calls.\n\n<BlockQuote label=\"Note\">\n\nWhen used via REST URLs all query values are strings and may need to be converted to the correct type. In a v5 application this is done automatically using [schemas](../schema/index.md).\n\n</BlockQuote>\n\n## Filters\n\nFilters are special properties (starting with a `$`) added at the top level of a query. They can determine page settings, the properties to select and more.\n\n### $limit\n\n`$limit` will return only the number of results you specify:\n\n```js\n// Retrieves the first two unread messages\napp.service('messages').find({\n  query: {\n    $limit: 2,\n    read: false\n  }\n})\n```\n\n```\nGET /messages?$limit=2&read=false\n```\n\n<BlockQuote>\n\nWith [pagination enabled](common.md#pagination), to just get the number of available records set `$limit` to `0`. This will only run a (fast) counting query against the database and return a page object with the `total` and an empty `data` array.\n\n</BlockQuote>\n\n### $skip\n\n`$skip` will skip the specified number of results:\n\n```js\n// Retrieves the next two unread messages\napp.service('messages').find({\n  query: {\n    $limit: 2,\n    $skip: 2,\n    read: false\n  }\n})\n```\n\n```\nGET /messages?$limit=2&$skip=2&read=false\n```\n\n### $sort\n\n`$sort` will sort based on the object you provide. It can contain a list of properties by which to sort mapped to the order (`1` ascending, `-1` descending).\n\n```js\n// Find the 10 newest messages\napp.service('messages').find({\n  query: {\n    $limit: 10,\n    $sort: {\n      createdAt: -1\n    }\n  }\n})\n```\n\n```\n/messages?$limit=10&$sort[createdAt]=-1\n```\n\n### $select\n\n`$select` allows to pick which fields to include in the result. This will work for any service method.\n\n```js\n// Only return the `text` and `userId` field in a message\napp.service('messages').find({\n  query: {\n    $select: ['text', 'userId']\n  }\n})\n\napp.service('messages').get(1, {\n  query: {\n    $select: ['text']\n  }\n})\n```\n\n```\nGET /messages?$select[]=text&$select[]=userId\nGET /messages/1?$select[]=text\n```\n\n### $or\n\nFind all records that match any of the given criteria.\n\n```js\n// Find all messages that are not marked as archived\n// or any message from room 2\napp.service('messages').find({\n  query: {\n    $or: [{ archived: { $ne: true } }, { roomId: 2 }]\n  }\n})\n```\n\n```\nGET /messages?$or[0][archived][$ne]=true&$or[1][roomId]=2\n```\n\n### $and\n\nFind all records that match all of the given criteria.\n\n```js\n// Find all messages that are not marked as archived and in room 2\napp.service('messages').find({\n  query: {\n    $and: [{ archived: { $ne: true } }, { roomId: 2 }]\n  }\n})\n```\n\n```\nGET /messages?$and[0][archived][$ne]=true&$and[1][roomId]=2\n```\n\n## Operators\n\nOperators either query a property for a specific value or determine nested special properties (starting with a `$`) that allow querying the property for certain conditions. When multiple operators are set, all conditions have to apply for a property to match.\n\n### Equality\n\nAll fields that do not contain special query parameters are compared directly for equality.\n\n```js\n// Find all unread messages in room #2\napp.service('messages').find({\n  query: {\n    read: false,\n    roomId: 2\n  }\n})\n```\n\n```\nGET /messages?read=false&roomId=2\n```\n\n### $in, $nin\n\nFind all records where the property does (`$in`) or does not (`$nin`) match any of the given values.\n\n```js\n// Find all messages in room 2 or 5\napp.service('messages').find({\n  query: {\n    roomId: {\n      $in: [2, 5]\n    }\n  }\n})\n```\n\n```\nGET /messages?roomId[$in][]=2&roomId[$in][]=5\n```\n\n### $lt, $lte\n\nFind all records where the value is less (`$lt`) or less and equal (`$lte`) to a given value.\n\n```js\n// Find all messages older than a day\nconst DAY_MS = 24 * 60 * 60 * 1000\n\napp.service('messages').find({\n  query: {\n    createdAt: {\n      $lt: new Date().getTime() - DAY_MS\n    }\n  }\n})\n```\n\n```\nGET /messages?createdAt[$lt]=1479664146607\n```\n\n### $gt, $gte\n\nFind all records where the value is more (`$gt`) or more and equal (`$gte`) to a given value.\n\n```js\n// Find all messages within the last day\nconst DAY_MS = 24 * 60 * 60 * 1000\n\napp.service('messages').find({\n  query: {\n    createdAt: {\n      $gt: new Date().getTime() - DAY_MS\n    }\n  }\n})\n```\n\n```\nGET /messages?createdAt[$gt]=1479664146607\n```\n\n### $ne\n\nFind all records that do not equal the given property value.\n\n```js\n// Find all messages that are not marked as archived\napp.service('messages').find({\n  query: {\n    archived: {\n      $ne: true\n    }\n  }\n})\n```\n\n```\nGET /messages?archived[$ne]=true\n```\n\n## Search\n\nSearching is not part of the common querying syntax since it is very specific to the database you are using. For built in databases, see the [SQL search](./knex.md#search) and [MongoDb search](./mongodb.md#search) documentation. If you are using [a community supported adapter](/ecosystem/?cat=Database&sort=lastPublish) their documentation may contain additional information on how to implement search functionality.\n"
  },
  {
    "path": "docs/api/errors.md",
    "content": "---\noutline: deep\n---\n\n# Errors\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/errors.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/errors)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/errors/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/errors --save\n```\n\nThe `@feathersjs/errors` module contains a set of standard error classes used by all other Feathers modules.\n\n## Examples\n\nHere are a few ways that you can use them:\n\n```ts\nimport { NotFound, GeneralError, BadRequest } from '@feathersjs/errors'\n\n// If you were to create an error yourself.\nconst notFound = new NotFound('User does not exist')\n\n// You can wrap existing errors\nconst existing = new GeneralError(new Error('I exist'))\n\n// You can also pass additional data\nconst data = new BadRequest('Invalid email', {\n  email: 'sergey@google.com'\n})\n\n// You can also pass additional data without a message\nconst dataWithoutMessage = new BadRequest({\n  email: 'sergey@google.com'\n})\n\n// If you need to pass multiple errors\nconst validationErrors = new BadRequest('Invalid Parameters', {\n  errors: { email: 'Email already taken' }\n})\n\n// You can also omit the error message and we'll put in a default one for you\nconst validationErrors = new BadRequest({\n  errors: {\n    email: 'Invalid Email'\n  }\n})\n```\n\n## Feathers errors\n\nThe following error types, all of which are instances of `FeathersError`, are available:\n\n- 400: `BadRequest`\n- 401: `NotAuthenticated`\n- 402: `PaymentError`\n- 403: `Forbidden`\n- 404: `NotFound`\n- 405: `MethodNotAllowed`\n- 406: `NotAcceptable`\n- 408: `Timeout`\n- 409: `Conflict`\n- 411: `LengthRequired`\n- 422: `Unprocessable`\n- 429: `TooManyRequests`\n- 500: `GeneralError`\n- 501: `NotImplemented`\n- 502: `BadGateway`\n- 503: `Unavailable`\n\n<BlockQuote type=\"tip\">\n\nAll of the Feathers core modules and most plugins and database adapters automatically emit the appropriate Feathers errors for you. For example, most of the database adapters will already send `Conflict` or `Unprocessable` errors on validation errors.\n\n</BlockQuote>\n\nFeathers errors contain the following fields:\n\n- `name` - The error name (e.g. \"BadRequest\", \"ValidationError\", etc.)\n- `message` - The error message string\n- `code` - The HTTP status code\n- `className` - A CSS class name that can be handy for styling errors based on the error type. (e.g. \"bad-request\" , etc.)\n- `data` - An object containing anything you passed to a Feathers error except for the `errors` object and `message`.\n- `errors` - An object containing whatever was passed to a Feathers error inside `errors`. This is typically validation errors or if you want to group multiple errors together.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nTo convert a Feathers error back to an object call `error.toJSON()`. A normal `console.log` of a JavaScript Error object will not automatically show those additional properties described above (even though they can be accessed directly).\n\n</BlockQuote>\n\n## Custom errors\n\nYou can create custom errors by extending from the `FeathersError` class and calling its constructor with `(message, name, code, className, data)`:\n\n- `message` - The error message\n- `name` - The error name (e.g. `MyError`)\n- `code` - An [HTTP error code](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)\n- `className` - The full name of the error class (e.g. `my-error`)\n- `data` - Additional data to include in the error\n\n```ts\nimport { FeathersError } from '@feathersjs/errors'\n\nclass UnsupportedMediaType extends FeathersError {\n  constructor(message: string, data: any) {\n    super(message, 'UnsupportedMediaType', 415, 'unsupported-media-type', data)\n  }\n}\n\nconst error = new UnsupportedMediaType('Not supported')\n\nconsole.log(error.toJSON())\n```\n\n## Error Handling\n\nIt is important to make sure that errors get cleaned up before they go back to the client. [Express error handling middleware](https://docs.feathersjs.com/api/express.html#expresserrorhandler) works only for REST calls. If you want to make sure that ws errors are handled as well, you need to use [application error hooks](hooks.md#application-hooks) which are called on any service call error.\n\nHere is an example error handler you can add to app.hooks errors.\n\n```js\nconst errors = require('@feathersjs/errors')\nconst errorHandler = (ctx) => {\n  if (ctx.error) {\n    const error = ctx.error\n    if (!error.code) {\n      const newError = new errors.GeneralError('server error')\n      ctx.error = newError\n      return ctx\n    }\n    if (error.code === 404 || process.env.NODE_ENV === 'production') {\n      error.stack = null\n    }\n    return ctx\n  }\n}\n```\n\nthen add it as an [application level](./application.md#hooks-hooks) error hook\n\n```ts\napp.hooks({\n  //...\n  error: {\n    all: [errorHandler]\n  }\n})\n```\n"
  },
  {
    "path": "docs/api/events.md",
    "content": "---\noutline: deep\n---\n\n# Events\n\nEvents are the key part of Feathers real-time functionality. All events in Feathers are provided through the [NodeJS EventEmitter](https://nodejs.org/api/events.html) interface. This section describes\n\n- A quick overview of the [NodeJS EventEmitter interface](#eventemitters)\n- The standard [service events](#service-events)\n- How to allow sending [custom events](#custom-events) from the server to the client\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nFor more information on how to safely send real-time events to clients, see the [Channels chapter](./channels.md).\n\n</BlockQuote>\n\n## EventEmitters\n\nOnce registered, any [service](./services.md) gets turned into a standard [NodeJS EventEmitter](https://nodejs.org/api/events.html) and can be used accordingly.\n\n```ts\nconst messages = app.service('messages')\n\n// Listen to a normal service event\nmessages.on('patched', (message: Message) => console.log('message patched', message))\n\n// Only listen to an event once\nmesssages.once('removed', (message: Message) => console.log('First time a message has been removed', message))\n\n// A reference to a handler\nconst onCreatedListener = (message: Message) => console.log('New message created', message)\n\n// Listen `created` with a handler reference\nmessages.on('created', onCreatedListener)\n\n// Unbind the `created` event listener\nmessages.removeListener('created', onCreatedListener)\n\n// Send a custom event\nmessages.emit('customEvent', {\n  anything: 'Data can be anything'\n})\n```\n\n## Service Events\n\nAny service automatically emits `created`, `updated`, `patched` and `removed` events when the respective service method returns successfully. This works on the client as well as on the server. Events are not fired until all [hooks](./hooks.md) have executed. When the client is using [Socket.io](socketio.md), events will be pushed automatically from the server to all connected clients. This is how Feathers does real-time.\n\n<BlockQuote type=\"tip\">\n\nTo disable sending of events e.g. when updating a large amount of data, set [context.event](./hooks.md#context-event) to `null` in a hook.\n\n</BlockQuote>\n\nAdditionally to the event `data`, all events also get the [hook context](./hooks.md) from their method call passed as the second parameter.\n\n### created\n\nThe `created` event will fire with the result data when a service `create` returns successfully.\n\n```ts\nimport { feathers, type Params, type HookContext } from '@feathersjs/feathers'\n\ntype Message = { text: string }\n\nclass MessageService {\n  async create(data: Message) {\n    return data\n  }\n}\n\nconst app = feathers<{ messages: MessageService }>()\n\napp.use('messages', new MessageService())\n\n// Retrieve the wrapped service object which is also an EventEmitter\nconst messages = app.service('messages')\n\nmessages.on('created', (message: Message, contexHookContext) => console.log('created', message))\n\nmessages.create({\n  text: 'We have to do something!'\n})\n```\n\n### updated, patched\n\nThe `updated` and `patched` events will fire with the callback data when a service `update` or `patch` method calls back successfully.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport type { Id, Params, HookContext } from '@feathersjs/feathers'\n\ntype Message = { text: string }\n\nclass MessageService {\n  async update(id: Id, data: Message) {\n    return data\n  }\n\n  async patch(id: Id, data: Message) {\n    return data\n  }\n}\n\nconst app = feathers<{ messages: MessageService }>()\n\napp.use('messages', new MessageService())\n\nconst messages = app.service('my/messages')\n\nmessages.on('updated', (message: Message, context: HookContext) => console.log('updated', message))\nmessages.on('patched', (message: Message) => console.log('patched', message))\n\nmessages.update(0, {\n  text: 'updated message'\n})\n\nmessages.patch(0, {\n  text: 'patched message'\n})\n```\n\n### removed\n\nThe `removed` event will fire with the callback data when a service `remove` calls back successfully.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport type { Id, Params, HookContext } from '@feathersjs/feathers'\n\ntype Message = { text: string }\n\nclass MessageService {\n  async remove(id: Id, params: Params) {\n    return { id }\n  }\n}\n\nconst app = feathers<{ messages: MessageService }>()\n\napp.use('messages', new MessageService())\n\nconst messages = app.service('messages')\n\nmessages.on('removed', (message: Message, context: HookContext) => console.log('removed', message))\nmessages.remove(1)\n```\n\n## Custom events\n\nBy default, real-time clients will only receive the [standard events](#service-events). However, it is possible to define a list of custom events that should also be sent to the client when registering the service with [app.use](./application.md##use-path-service-options), when `service.emit('customevent', data)` is called on the server. The `context` for custom events won't be a full hook context but just an object containing `{ app, service, path, result }`.\n\n<BlockQuote type=\"warning\" label=\"important\">\n\nCustom events can only be sent from the server to the client, not the other way (client to server). A [custom service](./services.md) should be used for those cases.\n\n</BlockQuote>\n\nFor example, a payment service that sends status events to the client while processing a payment could look like this:\n\n```ts\nclass PaymentService {\n  async create(data: any, params: Params) {\n    const customer = await createStripeCustomer(params.user)\n    this.emit('status', { status: 'created' })\n\n    const payment = await createPayment(data)\n    this.emit('status', { status: 'completed' })\n\n    return payment\n  }\n}\n\n// Then register it like this:\napp.use('payments', new PaymentService(), {\n  events: ['status']\n})\n```\n\nUsing `service.emit` custom events can also be sent in a hook:\n\n```js\napp.service('payments').hooks({\n  after: {\n    create(context: HookContext) {\n      context.service.emit('status', { status: 'completed' })\n    }\n  }\n})\n```\n\nCustom events can be [published through channels](./channels.md#publishing) just like standard events and listened to it in a [Feathers client](./client.md) or [directly on the socket connection](./client/socketio.md#listening-to-events):\n\n```js\nclient.service('payments').on('status', (data) => {})\n\n// or\nsocket.on('payments status', (data) => {})\n```\n"
  },
  {
    "path": "docs/api/express.md",
    "content": "---\noutline: deep\n---\n\n# Express\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/express.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/express)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/express/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/express --save\n```\n\nThe `@feathersjs/express` module contains [Express](http://expressjs.com/) framework integrations for Feathers:\n\n- The [Express framework bindings](#expressapp) to make a Feathers application Express compatible\n- An Express based transport to expose services through a [REST API](#expressrest)\n- An [Express error handler](#expresserrorhandler) for [Feathers errors](./errors.md)\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport express from '@feathersjs/express'\n\nconst app = express(feathers())\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nAs of Feathers v5, [Koa](./koa.md) is the recommended framework integration since it is more modern, faster and easier to use. When chosen explicitly, you should already be familiar with [Express](http://expressjs.com/en/guide/routing.html).\n\n</BlockQuote>\n\n## express(app)\n\n`express(app) -> app` is a function that turns a [Feathers application](./application.md) into a fully Express (4+) compatible application that additionally to Feathers functionality also lets you use the [Express API](http://expressjs.com/en/4x/api.html).\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport express from '@feathersjs/express'\n\nconst app = express(feathers())\n```\n\nNote that `@feathersjs/express` also exposes the Express [built-in middleware](#built-ins)\n\n## express(app, expressApp)\n\n`express(app, expressApp) -> app` allows to extend an existing Express application with the Feathers application `app`.\n\n## express()\n\nIf no Feathers application is passed, `express() -> app` returns a plain Express application just like a normal call to Express would.\n\n## app.use(path, service|mw|\\[mw\\])\n\n`app.use(path, service|mw|[mw]) -> app` registers either a [service object](./services.md), an [Express middleware](http://expressjs.com/en/guide/writing-middleware.html) or an array of [Express middleware](http://expressjs.com/en/guide/writing-middleware.html) on the given path. If [a service object](./services.md) is passed it will use Feathers registration mechanism, for a middleware function Express.\n\n```ts\n// Register a service\napp.use('todos', {\n  async get(id) {\n    return { id }\n  }\n})\n\n// Register an Express middleware\napp.use('/test', (req, res) => {\n  res.json({\n    message: 'Hello world from Express middleware'\n  })\n})\n\n// Register multiple Express middleware functions\napp.use(\n  '/test',\n  (req, res, next) => {\n    res.data = 'Step 1 worked'\n    next()\n  },\n  (req, res) => {\n    res.json({\n      message: `Hello world from Express middleware ${res.data}`\n    })\n  }\n)\n```\n\n## app.listen(port)\n\n`app.listen(port) -> Promise<HttpServer>` will first call Express [app.listen](http://expressjs.com/en/4x/api.html#app.listen) and then internally also call the [app.setup(server)](./application.md#setup-server).\n\n```ts\n// Listen on port 3030\nconst server = await app.listen(3030)\n```\n\n## app.setup(server)\n\n`app.setup(server) -> app` is usually called internally by `app.listen` but in the cases described below needs to be called explicitly.\n\n### Sub-Apps\n\nWhen registering an application as a sub-app, `app.setup(server)` has to be called to initialize the sub-apps services.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport express from '@feathersjs/express'\n\nconst api = feathers()\n\napi.use('service', myService)\n\nconst mainApp = express(feathers()).use('/api/v1', api)\n\nconst server = await mainApp.listen(3030)\n\n// Now call setup on the Feathers app with the server\nawait api.setup(server)\n```\n\n### HTTPS\n\nHTTPS requires creating a separate server in which case `app.setup(server)` also has to be called explicitly. In a generated application `src/index.js` should look like this:\n\n```ts\nimport https from 'https'\nimport { app } from './app'\n\nconst port = app.get('port')\nconst server = https\n  .createServer(\n    {\n      key: fs.readFileSync('privatekey.pem'),\n      cert: fs.readFileSync('certificate.pem')\n    },\n    app\n  )\n  .listen(443)\n\n// Call app.setup to initialize all services and SocketIO\napp.setup(server)\n\nserver.on('listening', () => logger.info('Feathers application started'))\n```\n\n### Virtual Hosts\n\nThe [vhost](https://github.com/expressjs/vhost) Express middleware can be used to run a Feathers application on a virtual host but again requires `app.setup(server)` to be called explicitly.\n\n```ts\nimport vhost from 'vhost'\nimport { feathers } from '@feathersjs/feathers'\nimport express from '@feathersjs/express'\n\nconst app = express(feathers())\n\napp.use('/todos', todoService)\n\nconst host = express().use(vhost('foo.com', app))\nconst server = await host.listen(8080)\n\n// Here we need to call app.setup because .listen on our virtual hosted\n// app is never called\napp.setup(server)\n```\n\n## rest()\n\nRegisters a Feathers transport mechanism that allows you to expose and consume [services](./services.md) through a [RESTful API](https://en.wikipedia.org/wiki/Representational_state_transfer). This means that you can call a service method through the `GET`, `POST`, `PUT`, `PATCH` and `DELETE` [HTTP methods](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol):\n\n| Service method | HTTP method | Path        |\n| -------------- | ----------- | ----------- |\n| .find()        | GET         | /messages   |\n| .get()         | GET         | /messages/1 |\n| .create()      | POST        | /messages   |\n| .update()      | PUT         | /messages/1 |\n| .patch()       | PATCH       | /messages/1 |\n| .remove()      | DELETE      | /messages/1 |\n\n### app.configure(rest())\n\nConfigures the transport provider with a standard formatter sending JSON response via [res.json](http://expressjs.com/en/4x/api.html#res.json).\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport express, { json, urlencoded, rest } from '@feathersjs/express'\n\n// Create an Express compatible Feathers application\nconst app = express(feathers())\n\n// Turn on JSON parser for REST services\napp.use(json())\n// Turn on URL-encoded parser for REST services\napp.use(urlencoded({ extended: true }))\n// Set up REST transport\napp.configure(rest())\n```\n\n<BlockQuote type=\"danger\" label=\"Important\">\n\nThe `json` and `urlencoded` body parser and [params middleware](#params) has to be registered **before** any service.\n\n</BlockQuote>\n\n### app.configure(rest(formatter))\n\nThe default REST response formatter is a middleware that formats the data retrieved by the service as JSON. If you would like to configure your own `formatter` middleware pass a `formatter(req, res)` function. This middleware will have access to `res.data` which is the data returned by the service. [res.format](http://expressjs.com/en/4x/api.html#res.format) can be used for content negotiation.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport express, { json, urlencoded, rest } from '@feathersjs/express'\n\nconst app = express(feathers())\n\n// Turn on JSON parser for REST services\napp.use(json())\n// Turn on URL-encoded parser for REST services\napp.use(urlencoded({ extended: true }))\n// Set up REST transport\napp.configure(\n  rest(function (req, res) {\n    // Format the message as text/plain\n    res.format({\n      'text/plain': function () {\n        res.end(`The Message is: \"${res.data.text}\"`)\n      }\n    })\n  })\n)\n```\n\n## Custom service middleware\n\nCustom Express middleware that only should run before or after a specific service can be passed to `app.use` in the order it should run:\n\n```ts\nconst todoService = {\n  async get(id: Id) {\n    return {\n      id,\n      description: `You have to do ${id}!`\n    }\n  }\n}\n\napp.use('todos', logRequest, todoService, updateData)\n```\n\n<BlockQuote type=\"danger\">\n\nCustom middleware will only run for REST requests and not when used with other transports (like Socket.io). If possible try to avoid custom middleware and use [hooks](hooks.md) or customized services instead which will work for all transports.\n\n</BlockQuote>\n\nMiddleware that runs after the service has the service call information available as\n\n- `res.data` - The data that will be sent\n- `res.hook` - The [hook](./hooks.md) context of the service method call\n\nFor example `updateData` could look like this:\n\n```js\nfunction updateData(req, res, next) {\n  res.data.updateData = true\n  next()\n}\n```\n\nIf you run `res.send` in a custom middleware after the service and don't call `next`, other middleware (like the REST formatter) will be skipped. This can be used to e.g. render different views for certain service method calls, for example to export a file as CSV:\n\n```ts\nimport json2csv from 'json2csv'\n\nconst fields = ['done', 'description']\n\napp.use('todos', todoService, function (req, res) {\n  const result = res.data\n  const data = result.data // will be either `result` as an array or `data` if it is paginated\n  const csv = json2csv({ data, fields })\n\n  res.type('csv')\n  res.end(csv)\n})\n```\n\n## params\n\nAll Express middleware will have access to the `req.feathers` object to set properties on the service method `params`:\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport type { Id, Params } from '@feathersjs/feathers'\nimport express, { json, urlencoded, rest } from '@feathersjs/express'\n\nconst app = express(feathers())\n\napp.use(json())\napp.use(urlencoded({ extended: true }))\napp.use(function (req, res, next) {\n  req.feathers.fromMiddleware = 'Hello world'\n  next()\n})\napp.configure(rest())\n\napp.use('todos', {\n  async get(id: Id, params: Params) {\n    console.log(params.provider) // -> 'rest'\n    console.log(params.fromMiddleware) // -> 'Hello world'\n\n    return {\n      id,\n      params,\n      description: `You have to do ${id}!`\n    }\n  }\n})\n\napp.listen(3030)\n```\n\nAvoid setting `req.feathers = something` directly since it may already contain information that other Feathers plugins rely on. Adding individual properties or using `{ ...req.feathers, something }` is the more reliable option.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nSince the order of Express middleware matters, any middleware that sets service parameters has to be registered **before** `app.configure(rest())` or as a [custom service middleware](#custom-service-middleware)\n\n</BlockQuote>\n\n<BlockQuote type=\"tip\">\n\nAlthough it may be convenient to set `req.feathers.req = req` to have access to the request object in the service, we recommend keeping your services as provider independent as possible. There usually is a way to pre-process your data in a middleware so that the service does not need to know about the HTTP request or response.\n\n</BlockQuote>\n\n### params.query\n\n`params.query` will contain the URL query parameters sent from the client. For the REST transport the query string is parsed using the [qs](https://github.com/ljharb/qs) module. For some query string examples see the [database querying](./databases/querying.md) chapter.\n\n<BlockQuote type=\"warning\">\n\nOnly `params.query` is passed between the server and the client, other parts of `params` are not. This is for security reasons so that a client can't set things like `params.user` or the database options. You can always map from `params.query` to other `params` properties in a [hook](./hooks.md).\n\n</BlockQuote>\n\nFor example:\n\n```\nGET /messages?read=true&$sort[createdAt]=-1\n```\n\nWill set `params.query` to\n\n```json\n{\n  \"read\": \"true\",\n  \"$sort\": { \"createdAt\": \"-1\" }\n}\n```\n\n<BlockQuote type=\"tip\">\n\nNote that the URL is a string so type conversion may be necessary. This is usually done with [query schemas and resolvers](./schema/index.md).\n\n</BlockQuote>\n\n<BlockQuote type=\"danger\">\n\nIf an array in your request consists of more than 20 items, the [qs](https://www.npmjs.com/package/qs) parser implicitly [converts](https://github.com/ljharb/qs#parsing-arrays) it to an object with indices as keys. To extend this limit, you can set a custom query parser: `app.set('query parser', str => qs.parse(str, {arrayLimit: 1000}))`\n\n</BlockQuote>\n\n### params.provider\n\nFor any [service method call](./services.md) made through REST `params.provider` will be set to `rest`. In a [hook](./hooks.md) this can for example be used to prevent external users from making a service method call:\n\n```ts\nimport { HookContext } from 'declarations'\n\napp.service('users').hooks({\n  before: {\n    remove: [\n      async (context: HookContext) => {\n        // check for if(context.params.provider) to prevent any external call\n        if (context.params.provider === 'rest') {\n          throw new Error('You can not delete a user via REST')\n        }\n      }\n    ]\n  }\n})\n```\n\n### params.headers\n\n`params.headers` will contain the original service request headers.\n\n### params.route\n\nExpress route placeholders in a service URL will be added to the services `params.route`. See the [FAQ entry on nested routes](../help/faq.md#how-do-i-do-nested-or-custom-routes) for more details on when and when not to use nested routes.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport express, { rest } from '@feathersjs/express'\n\nconst app = express(feathers())\n\napp.configure(rest())\napp.use(function (req, res, next) {\n  req.feathers.fromMiddleware = 'Hello world'\n  next()\n})\n\napp.use('users/:userId/messages', {\n  async get(id, params) {\n    console.log(params.query) // -> ?query\n    console.log(params.provider) // -> 'rest'\n    console.log(params.fromMiddleware) // -> 'Hello world'\n    console.log(params.route.userId) // will be `1` for GET /users/1/messages\n\n    return {\n      id,\n      params,\n      read: false,\n      text: `Feathers is great!`,\n      createdAt: new Date().getTime()\n    }\n  }\n})\n\napp.listen(3030)\n```\n\n## Middleware\n\n`@feathersjs/express` comes with the following middleware\n\n### notFound(options)\n\n`notFound()` returns middleware that returns a `NotFound` (404) [Feathers error](./errors.md). It should be used as the last middleware **before** the error handler. The following options are available:\n\n- `verbose`: Set to `true` if the URL should be included in the error message (default: `false`)\n\n```ts\nimport { notFound, errorHandler } from '@feathersjs/express'\n\n// Return errors that include the URL\napp.use(notFound({ verbose: true }))\napp.use(errorHandler())\n```\n\n### errorHandler()\n\n`errorHandler` is an [Express error handler](https://expressjs.com/en/guide/error-handling.html) middleware that formats any error response to a REST call as JSON (or HTML if e.g. someone hits our API directly in the browser) and sets the appropriate error code.\n\n<BlockQuote type=\"tip\">\n\nYou can still use any other Express compatible [error middleware](http://expressjs.com/en/guide/error-handling.html) with Feathers.\n\n</BlockQuote>\n\n<BlockQuote type=\"danger\" label=\"Important\">\n\nJust like in Express, the error handler has to be registered _after_ all middleware and services.\n\n</BlockQuote>\n\n#### app.use(errorHandler())\n\nSet up the error handler with the default configuration.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport express from '@feathersjs/express'\n\nconst app = express(feathers())\n\n// before starting the app\napp.use(express.errorHandler())\n```\n\n#### app.use(errorHandler(options))\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport express from '@feathersjs/express'\n\nconst app = express(feathers())\n\n// Just like Express your error middleware needs to be\n// set up last in your middleware chain.\napp.use(\n  express.errorHandler({\n    html: function (error, req, res, next) {\n      // render your error view with the error object\n      res.render('error', error)\n    }\n  })\n)\n\napp.use(\n  errorHandler({\n    html: {\n      404: 'path/to/notFound.html',\n      500: 'there/will/be/robots.html'\n    }\n  })\n)\n```\n\n<BlockQuote type=\"warning\" label=\"important\">\n\nIf you want to have the response in json format be sure to set the `Accept` header in your request to `application/json` otherwise the default error handler will return HTML.\n\n</BlockQuote>\n\nThe following options can be passed when creating a new error handler:\n\n- `html` (Function|Object) [optional] - A custom formatter function or an object that contains the path to your custom html error pages. Can also be set to `false` to disable html error pages altogether so that only JSON is returned.\n- `logger` (Function|false) (default: `console`) - Set a logger object to log the error (it will be logger with `logger.error(error)`\n\n### authenticate()\n\n`express.authenticate(...strategies)` allows to protect an Express middleware with an [authentication service](./authentication/service.md) that has [strategies](./authentication/strategy.md) registered that can parse HTTP headers. It will set the authentication information on the `req.feathers` object (e.g. `req.feathers.user`). The following example protects the `/hello` endpoint with the JWT strategy (so the `Authorization: Bearer <JWT>` header needs to be set) and uses the user email to render the message:\n\n```ts\nimport { authenticate } from '@feathersjs/express'\n\napp.use('/hello', authenticate('jwt'), (req, res) => {\n  const { user } = req.feathers\n\n  res.render(`Hello ${user.email}`)\n})\n\n// When using with the non-default authentication service\napp.use(\n  '/hello',\n  authenticate({\n    service: 'v2/auth',\n    strategies: ['jwt', 'api-key']\n  }),\n  (req, res) => {\n    const { user } = req.feathers\n\n    res.render(`Hello ${user.email}`)\n  }\n)\n```\n\nWhen clicking a normal link, web browsers do _not_ send the appropriate header. In order to initate an authenticated request to a middleware from a browser link, there are two options. One is using a session which is described in the [Server Side rendering guide](../cookbook/express/view-engine.md), another is to add the JWT access token to the query string and mapping it to an authentication request:\n\n```ts\nimport { authenticate } from '@feathersjs/express'\n\nconst setQueryAuthentication = (req, res, next) => {\n  const { access_token } = req.query\n\n  if (access_token) {\n    req.authentication = {\n      strategy: 'jwt',\n      accessToken: access_token\n    }\n  }\n\n  next()\n}\n\n// Request this with `hello?access_token=<your jwt>`\napp.use('/hello', setQueryAuthentication, authenticate('jwt'), (req, res) => {\n  const { user } = req.feathers\n\n  res.render(`Hello ${user.email}`)\n})\n```\n\nHow to get the access token from the authentication client is described in the [authentication client documentation](../api/authentication/client.md#app-get-authentication).\n\n<BlockQuote type=\"warning\">\n\nWhen using HTTPS URLs are safely encrypted but when using this method you have to make sure that access tokens are not logged through any of your logging mechanisms.\n\n</BlockQuote>\n\n### parseAuthentication\n\nThe `parseAuthentication` middleware is registered automatically and will use the strategies of the default [authentication service](./authentication/service.md) to parse headers for authentication information. If you want to additionally parse authentication with a different authentication service this middleware can be registered again with that service configured.\n\n```ts\nimport { parseAuthentication } from '@feathersjs/express'\n\napp.use(\n  parseAuthentication({\n    service: 'api/v1/authentication',\n    strategies: ['jwt', 'local']\n  })\n)\n```\n\n### cors\n\nA reference to the [cors](https://github.com/expressjs/cors) module.\n\n### compression\n\nA reference to the [compression](https://github.com/expressjs/compression) module.\n\n### Built ins\n\nNote that `@feathersjs/express` also exposes the standard [Express middleware](http://expressjs.com/en/4x/api.html#express):\n\n- `json` - A JSON body parser\n- `urlencoded` - A URL encoded form body parser\n- `serveStatic` - To statically host files in a folder\n- `Router` - Creates an Express router object\n"
  },
  {
    "path": "docs/api/hooks.md",
    "content": "---\noutline: deep\n---\n\n# Hooks\n\nHooks are pluggable middleware functions that can be registered **around**, **before**, **after** or on **error**(s) of a [service method](./services.md). Multiple hook functions can be chained to create complex work-flows. A hook is **transport independent**, which means it does not matter if it has been called internally on the server, through HTTP(S) (REST), websockets or any other transport Feathers supports. They are also service agnostic, meaning they can be used with ​**any**​ service regardless of whether they use a database or not.\n\nHooks are commonly used to handle things like permissions, validation, logging, [authentication](./authentication/hook.md), [data schemas and resolvers](./schema/index.md), sending notifications and more. This pattern keeps your application logic flexible, composable, and easier to trace through and debug. For more information about the design patterns behind hooks see [this blog post](https://blog.feathersjs.com/api-service-composition-with-hooks-47af13aa6c01).\n\n## Quick Example\n\nThe following example logs the runtime of any service method on the `messages` service and adds `createdAt` property before saving the data to the database:\n\n```ts\nimport { feathers, type HookContext, type NextFunction } from '@feathersjs/feathers'\n\nconst app = feathers()\n\napp.service('messages').hooks({\n  around: {\n    all: [\n      // A hook that wraps around all other hooks and the service method\n      // logging the total runtime of a successful call\n      async (context: HookContext, next: NextFunction) => {\n        const startTime = Date.now()\n\n        await next()\n\n        console.log(`Method ${context.method} on ${context.path} took ${Date.now() - startTime}ms`)\n      }\n    ]\n  },\n  before: {\n    create: [\n      async (context: HookContext) => {\n        context.data = {\n          ...context.data,\n          createdAt: Date.now()\n        }\n      }\n    ]\n  }\n})\n```\n\n<BlockQuote type=\"info\">\n\nWhile it is always possible to add properties like `createdAt` in the above example via hooks, the preferred way to make data modifications like this in Feathers 5 is via [schemas and resolvers](./schema/index.md).\n\n</BlockQuote>\n\n## Hook functions\n\n### before, after and error\n\n`before`, `after` and `error` hook functions are functions that are `async` or return a promise and take the [hook context](#hook-context) as the parameter and return nothing or throw an error.\n\n```ts\nimport { HookContext } from '../declarations'\n\nexport const hookFunction = async (context: HookContext) => {\n  // Do things here\n}\n```\n\nFor more information see the [hook flow](#hook-flow) section.\n\n### around\n\n`around` hooks are a special kind of hook that allow to control the entire `before`, `after` and `error` flow in a single function. They are a Feathers specific version of the generic [@feathersjs/hooks](https://github.com/feathersjs/hooks). An `around` hook is an `async` function that accepts two arguments:\n\n- The [hook context](#hook-context)\n- An asynchronous `next` function. Somewhere in the body of the hook function, there is a call to `await next()`, which calls the `next` hooks OR the original function if all other hooks have run.\n\nIn its simplest form, an around hook looks like this:\n\n```js\nimport { HookContext, NextFunction } from '../declarations'\n\nexport const myAfoundHook = async (context: HookContext, next: NextFunction) => {\n  try {\n    // Code before `await next()` runs before the main function\n    await next()\n    // Code after `await next()` runs after the main function.\n  } catch (error) {\n    // Do things on error\n  } finally {\n    // Do things always\n  }\n}\n```\n\nAny around hook can be wrapped around another function. Calling `await next()` will either call the next hook in the chain or the service method if all other hooks have run.\n\n## Hook flow\n\nIn general, hooks are executed in the order [they are registered](#registering-hooks) with `around` hooks running first:\n\n- `around` hooks (before `await next()`)\n- `before` hooks\n- service method\n- `after` hooks\n- `around` hooks (after `await next()`)\n\nNote that since `around` hooks wrap **around** everything, the first hook to run will be the last to execute its code after `await next()`. This is reverse of the order `after` hooks execute.\n\nThe hook flow can be affected as follows.\n\n### Throwing an error\n\nWhen an error is thrown (or the promise is rejected), all subsequent hooks - and the service method call if it didn't run already - will be skipped and only the error hooks will run.\n\nThe following example throws an error when the text for creating a new message is empty. You can also create very similar hooks to use your Node validation library of choice.\n\n```ts\napp.service('messages').hooks({\n  before: {\n    create: [\n      async (context: HookContext) => {\n        if (context.data.text.trim() === '') {\n          throw new Error('Message text can not be empty')\n        }\n      }\n    ]\n  }\n})\n```\n\n### Setting `context.result`\n\nWhen `context.result` is set in an `around` hook before calling `await next()` or in a `before` hook, the original [service method](./services.md) call will be skipped. All other hooks will still execute in their normal order. The following example always returns the currently [authenticated user](./authentication/service.md) instead of the actual user for all `get` method calls:\n\n```js\napp.service('users').hooks({\n  before: {\n    get: [\n      async (context: HookContext) => {\n        // Never call the actual users service\n        // just use the authenticated user\n        context.result = context.params.user\n      }\n    ]\n  }\n})\n```\n\n## Hook context\n\nThe hook `context` is passed to a hook function and contains information about the service method call. It has **read only** properties that should not be modified and **_writeable_** properties that can be changed for subsequent hooks.\n\n<BlockQuote type=\"tip\">\n\nThe `context` object is the same throughout a service method call so it is possible to add properties and use them in other hooks at a later time.\n\n</BlockQuote>\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nIf you want to inspect the hook context, e.g. via `console.log`, the object returned by [context.toJSON()](#contexttojson) should be used, otherwise you won't see all properties that are available.\n\n</BlockQuote>\n\n### `context.app`\n\n`context.app` is a _read only_ property that contains the [Feathers application object](./application.md). This can be used to retrieve other services (via `context.app.service('name')`) or configuration values.\n\n### `context.service`\n\n`context.service` is a _read only_ property and contains the service this hook currently runs on.\n\n### `context.path`\n\n`context.path` is a _read only_ property and contains the service name (or path) without leading or trailing slashes.\n\n### `context.method`\n\n`context.method` is a _read only_ property with the name of the [service method](./services.md) (`find`, `get`, `create`, `update`, `patch`, `remove`).\n\n### `context.type`\n\n`context.type` is a _read only_ property with the hook type (one of `around`, `before`, `after` or `error`).\n\n### `context.params`\n\n`context.params` is a **writeable** property that contains the [service method](./services.md) parameters (including `params.query`). For more information see the [service params documentation](./services.md#params).\n\n### `context.id`\n\n`context.id` is a **writeable** property and the `id` for a `get`, `remove`, `update` and `patch` service method call. For `remove`, `update` and `patch`, `context.id` can also be `null` when modifying multiple entries. In all other cases it will be `undefined`.\n\n### `context.data`\n\n`context.data` is a **writeable** property containing the data of a `create`, `update` and `patch` service method call.\n\n<BlockQuote type=\"info\">\n\n`context.data` will only be available for `create`, `update`, `patch` and [custom methods](./services.md#custom-methods).\n\n</BlockQuote>\n\n### `context.error`\n\n`context.error` is a **writeable** property with the error object that was thrown in a failed method call. It can be modified to change the error that is returned at the end.\n\n<BlockQuote type=\"info\">\n\n`context.error` will only be available if `context.type` is `error`.\n\n</BlockQuote>\n\n### `context.result`\n\n`context.result` is a **writeable** property containing the result of the successful service method call. It is only available in `after` hooks. `context.result` can also be set in\n\n- An `around` or `before` hook to skip the actual service method (database) call\n- An `error` hook to swallow the error and return a result instead\n\n<BlockQuote type=\"info\">\n\n`context.result` will only be available if `context.type` is `after` or if `context.result` has been set.\n\n</BlockQuote>\n\n### `context.dispatch`\n\n`context.dispatch` is a **writeable, optional** property and contains a \"safe\" version of the data that should be sent to any client. If `context.dispatch` has not been set `context.result` will be sent to the client instead. `context.dispatch` only affects the data sent through a Feathers Transport like [REST](./express.md) or [Socket.io](./socketio.md). An internal method call will still get the data set in `context.result`.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\n`context.dispatch` is used by the `schemaHooks.resolveDispatch` [resolver](./schema/resolvers.md). Use dispatch resolvers whenever possible to get safe representations external data.\n\n</BlockQuote>\n\n### `context.http`\n\n`context.http` is a **writeable, optional** property that allows customizing HTTP response specific properties. The following properties can be set:\n\n- `context.http.status` - Sets the [HTTP status code](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) that should be returned. Usually the most appropriate status code will be picked automatically but there are cases where it needs to be customized.\n- `context.http.headers` - An object with additional HTTP response headers\n- `context.http.location` - Setting this property will trigger a redirect for HTTP requests.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nSetting `context.http` properties will have no effect when using a websocket real-time connection.\n\n</BlockQuote>\n\n### `context.event`\n\n`context.event` is a **writeable, optional** property that allows service events to be skipped by setting it to `null`\n\n### `context.toJSON()`\n\n`context.toJSON()` returns a full object representation of the hook context and all its properties.\n\n## Registering hooks\n\nHook functions are registered on a service through the `app.service(<servicename>).hooks(hooks)` method. The most commonly used registration format is\n\n```js\n{\n  [type]: { // around, before, after or error\n    all: [\n      // list of hooks that should run for every method here\n    ],\n    [methodName]: [\n      // list of method hooks here\n    ]\n  }\n}\n```\n\nThis means usual hook registration looks like this:\n\n```ts\n// The standard all at once way (also used by the generator)\n// an array of functions per service method name (and for `all` methods)\napp.service('servicename').hooks({\n  around: {\n    all: [\n      async (context: HookContext, next: NextFunction) => {\n        console.log('around all hook ran')\n        await next()\n      }\n    ],\n    find: [\n      /* other hook functions here */\n    ],\n    get: [],\n    create: [],\n    update: [],\n    patch: [],\n    remove: [],\n    // Custom methods use hooks as well\n    myCustomMethod: []\n  },\n  before: {\n    all: [async (context: HookContext) => console.log('before all hook ran')],\n    find: [\n      /* other hook functions here */\n    ],\n    get: []\n    // ...etc\n  },\n  after: {\n    find: [async (context: HookContext) => console.log('after find hook ran')]\n  },\n  error: {}\n})\n```\n\n<BlockQuote type=\"warning\">\n\nHooks will only be available for the standard service methods or methods passed in `options.methods` to [app.use](application.md#usepath-service--options). See the [documentation for @feathersjs/hooks](https://github.com/feathersjs/hooks) how to use hooks on other methods.\n\n</BlockQuote>\n\nSince around hooks offer the same functionality as `before`, `after` and `error` hooks at the same time they can also be registered without a nested object:\n\n```ts\nimport { HookContext, NextFunction } from './declarations'\n\n// Passing an array of around hooks that run for every method\napp.service('servicename').hooks([\n  async (context: HookContext, next: NextFunction) => {\n    console.log('around all hook ran')\n    await next()\n  }\n])\n\n// Passing an object with method names and a list of around hooks\napp.service('servicename').hooks({\n  get: [\n    async (context: HookContext, next: NextFunction) => {\n      console.log('around get hook ran')\n      await next()\n    }\n  ],\n  create: [],\n  update: [],\n  patch: [],\n  remove: [],\n  myCustomMethod: []\n})\n```\n\n## Application hooks\n\n### Service hooks\n\nTo add hooks to every service `app.hooks(hooks)` can be used. Application hooks are [registered in the same format as service hooks](#registering-hooks) and also work exactly the same. Note when application hooks will be executed:\n\n- `around` application hook will run around all other hooks\n- `before` application hooks will always run _before_ all service `before` hooks\n- `after` application hooks will always run _after_ all service `after` hooks\n- `error` application hooks will always run _after_ all service `error` hooks\n\nHere is an example for a very useful application hook that logs every service method error with the service and method name as well as the error stack.\n\n```ts\nimport { HookContext } from './declarations'\n\napp.hooks({\n  error: {\n    all: [\n      async (context: HookContext) => {\n        console.error(`Error in '${context.path}' service method '${context.method}'`, context.error.stack)\n      }\n    ]\n  }\n})\n```\n\n### Setup and teardown\n\nA special kind of application hooks are [app.setup](./application.md#setupserver) and [app.teardown](./application.md#teardownserver) hooks. They are around hooks that can be used to initialize database connections etc. and only run once when the application starts or shuts down. Setup and teardown hooks only have `context.app` and `context.server` available in the hook context.\n\n```ts\nimport { MongoClient } from 'mongodb'\n\napp.hooks({\n  setup: [\n    async (context: HookContext, next: NextFunction) => {\n      // E.g. wait for MongoDB connection to complete\n      await context.app.get('mongoClient').connect()\n      await next()\n    }\n  ],\n  teardown: [\n    async (context: HookContext, next: NextFunction) => {\n      // Close MongoDB connection\n      await context.app.get('mongoClient').close()\n      await next()\n    }\n  ]\n})\n```\n"
  },
  {
    "path": "docs/api/index.md",
    "content": "---\noutline: deep\n---\n\n# API\n\nThis section describes all the individual modules and APIs of Feathers.\n\n## Core\n\nFeathers core functionality that works on the client and the server\n\n- [Application](./application.md) - The main Feathers application API\n- [Services](./services.md) - Service objects and their methods and Feathers specific functionality\n- [Hooks](./hooks.md) - Pluggable middleware for service methods\n- [Events](./events.md) - Events sent by Feathers service methods\n- [Errors](./errors.md) - A collection of error classes used throughout Feathers\n\n## Transports\n\nExpose a Feathers application as an API server\n\n- [Configuration](./configuration.md) - A node-config wrapper to initialize configuration of a server side application.\n- [Koa](./koa.md) - Feathers KoaJS framework bindings, REST API provider and error middleware.\n- [Express](./express.md) - Feathers Express framework bindings, REST API provider and error middleware.\n- [Socket.io](./socketio.md) - The Socket.io real-time transport provider\n- [Channels](./channels.md) - Channels are used to send real-time events to clients\n\n## Authentication\n\nFeathers authentication mechanism\n\n- [Service](./authentication/service.md) - The main authentication service configuration\n- [Hook](./authentication/hook.md) - The hook used to authenticate service method calls\n- [Strategies](./authentication/strategy.md) - More about authentication strategies\n- [Local](./authentication/local.md) - Local email/password authentication\n- [JWT](./authentication/jwt.md) - JWT authentication\n- [OAuth](./authentication/oauth.md) - Using OAuth logins (Facebook, Twitter etc.)\n\n## Client\n\nMore details on how to use Feathers on the client\n\n- [Usage](./client.md) - Feathers client usage in Node, React Native and the browser (also with Webpack and Browserify)\n- [REST](./client/rest.md) - Feathers client and direct REST API server usage\n- [Socket.io](./client/socketio.md) - Feathers client and direct Socket.io API server usage\n- [Authentication](authentication/client) - A client for Feathers authentication\n\n## Schema\n\nModel definitions for validating and resolving data.\n\n- [TypeBox](./schema/typebox.md) - Integration for TypeBox, a JSON schema type builder\n- [JSON schema](./schema/schema.md) - JSON schema integration\n- [Validators](./schema/validators.md) - Schema validators and validation hooks\n- [Resolvers](./schema/resolvers.md) - Dynamic data resolvers\n\n## Databases\n\nFeathers common database adapter API and querying mechanism\n\n- [Adapters](./databases/adapters.md) - A list of supported database adapters\n- [Common API](./databases/common.md) - Database adapter common initialization and configuration API\n- [Querying](./databases/querying.md) - The common querying mechanism\n- [MongoDB](./databases/querying.md) - The adapter for MongoDB databases\n- [SQL](./databases/knex.md) - The adapter for SQL databases using KnexJS\n- [Memory](./databases/memory.md) - The adapter for in-memory data storage\n"
  },
  {
    "path": "docs/api/koa.md",
    "content": "---\noutline: deep\n---\n\n# Koa\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/koa.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/koa)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/koa/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/koa --save\n```\n\nThe `@feathersjs/koa` module contains the [KoaJS](https://koajs.com/) framework integrations for Feathers. It will turn the Feathers app into a fully compatible KoaJS application.\n\n## koa(app)\n\n`koa(app) -> app` is a function that turns a [Feathers application](./application.md) into a fully KoaJS compatible application that additionally to Feathers functionality also lets you use the [KoaJS API](https://koajs.com/).\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport { koa, errorHandler, bodyParser, rest } from '@feathersjs/koa'\n\nconst app = koa(feathers())\n\napp.use(errorHandler())\napp.use(authentication())\napp.use(bodyParser())\napp.configure(rest())\n```\n\nAlso see the [additional middleware](#middleware) that `@feathersjs/koa` exposes.\n\n## koa(app, koaApp)\n\n`koa(app, koaApp) -> app` allows to extend an existing Koa application with the Feathers application `app`.\n\n## koa()\n\nIf no Feathers application is passed, `koa() -> app` returns a plain Koa application (`new Koa()`).\n\n## app.use(location|mw[, service])\n\n`app.use(location|mw[, service]) -> app` registers either a [service object](./services.md), or a Koa middleware. If a path and [service object](./services.md) is passed it will use Feathers registration mechanism, for a middleware function Koa.\n\n## app.listen(port)\n\n`app.listen(port) -> HttpServer` will first call Koa [app.listen](https://github.com/koajs/koa/blob/master/docs/api/index.md#applisten) and then internally also call the [Feathers app.setup(server)](./application.md#setupserver).\n\n```js\n// Listen on port 3030\nconst server = await app.listen(3030)\n```\n\n## app.setup(server)\n\n`app.setup(server) -> app` is usually called internally by `app.listen` but in the cases described below needs to be called explicitly.\n\n### HTTPS\n\nHTTPS requires creating a separate server in which case `app.setup(server)` also has to be called explicitly. In a generated application `src/index.js` should look like this:\n\n```ts\nimport https from 'https'\nimport { app } from './app'\n\nconst port = app.get('port')\nconst server = https\n  .createServer(\n    {\n      key: fs.readFileSync('privatekey.pem'),\n      cert: fs.readFileSync('certificate.pem')\n    },\n    app.callback()\n  )\n  .listen(443)\n\n// Call app.setup to initialize all services and SocketIO\napp.setup(server)\n\nserver.on('listening', () => logger.info('Feathers application started'))\n```\n\n## params\n\nIn a Koa middleware, `ctx.feathers` is an object which will be extended as `params` in a service method call.\n\n```ts\nimport { rest } from '@feathersjs/koa'\nimport type { NextFunction } from '@feathersjs/koa'\nimport type { Id, Params } from '@feathersjs/feathers'\n\nclass TodoService {\n  async get(id: Id, params: Params & { fromMiddleware: string }) {\n    const { fromMiddleware } = params\n\n    return { id, fromMiddleware }\n  }\n}\n\n// Register Koa middleware\napp.use(async (ctx: any, next: NextFunction) => {\n  ctx.feathers = {\n    ...ctx.feathers,\n    fromMiddleware: 'Hello from Koa middleware'\n  }\n\n  await next()\n})\napp.configure(rest())\n\n// Register a service\napp.use('todos', new TodoService())\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nNote that `app.configure(rest())` has to happen **after** any custom middleware.\n\n</BlockQuote>\n\n### params.query\n\n`params.query` will contain the URL query parameters sent from the client parsed using [koa-qs](https://github.com/koajs/qs).\n\n<BlockQuote type=\"warning\" label=\"important\">\n\nOnly `params.query` is passed between the server and the client, other parts of `params` are not. This is for security reasons so that a client can't set things like `params.user` or the database options. You can always map from `params.query` to other `params` properties in a [hook](./hooks.md).\n\n</BlockQuote>\n\nTo increase the array limit in query strings, `koa-qs` can be reinitalized with the options for the [qs](https://www.npmjs.com/package/qs) module:\n\n```ts\n// app.ts\nimport koaQs from 'koa-qs'\n\n// ...\nkoaQs(app, 'extended', {\n  arrayLimit: 200\n})\n```\n\n### params.provider\n\nFor any [service method call](./services.md) made through REST `params.provider` will be set to `rest`.\n\n### params.route\n\nRoute placeholders in a service URL will be added to the services `params.route`. See the [FAQ entry on nested routes](../help/faq.md#how-do-i-do-nested-or-custom-routes) for more details on when and when not to use nested routes.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport { koa, errorHandler, bodyParser, rest } from '@feathersjs/koa'\n\nconst app = koa(feathers())\n\napp.use('users/:userId/messages', {\n  async get(id, params) {\n    console.log(params.query) // -> ?query\n    console.log(params.provider) // -> 'rest'\n    console.log(params.fromMiddleware) // -> 'Hello world'\n    console.log(params.route) // will be `{ userId: '1' }` for GET /users/1/messages\n\n    return {\n      id,\n      params,\n      read: false,\n      text: `Feathers is great!`,\n      createdAt: new Date().getTime()\n    }\n  }\n})\n\napp.listen(3030)\n```\n\n## Service middleware\n\nWhen registering a service, it is also possible to pass custom Koa middleware that should run `before` the specific service method in the `koa` [service option](./application.md#usepath-service--options):\n\n```ts\napp.use('/todos', new TodoService(), {\n  koa: {\n    before: [\n      async (ctx, next) => {\n        ctx.feathers // data that will be merged into sevice `params`\n\n        // This will run all subsequent middleware and the service call\n        await next()\n\n        // Then we have additional properties available on the context\n        ctx.hook // the hook context from the method call\n        ctx.body // the return value\n      }\n    ]\n  }\n})\n```\n\nNote that the order of middleware will be `[...before, serviceMethod]`.\n\n## Middleware\n\n### rest\n\n```ts\nimport { rest } from '@feathersjs/koa'\n\napp.configure(rest())\n```\n\nConfigures the middleware for handling service calls via HTTP. It will also register authentication header parsing. The following (optional) options are available:\n\n- `formatter` - A middleware that formats the response body\n- `authentication` - The authentication `service` and `strategies` to use for parsing authentication information\n\n### errorHandler\n\n```ts\nimport { errorHandler } from '@feathersjs/koa'\n\napp.use(errorHandler())\n```\n\nA middleware that formats errors as a Feathers error and sets the proper status code. Needs to be the first middleware registered in order to catch all other errors.\n\n### authenticate\n\nA middleware that allows to authenticate a user (or other authentication entity) using the [authentication service](./authentication/service.md) setting `ctx.feathers.user`. Not necessary for use with services but can be used in custom middleware.\n\n```ts\nimport { authenticate } from '@feathersjs/koa'\n\n// Authenticate other middleware with the JWT strategy\napp.use(authenticate('jwt'))\n\n// Authenticate a non default service\napp.use(\n  authenticate({\n    service: 'api/v1',\n    strategies: ['jwt']\n  })\n)\n```\n\n### parseAuthentication\n\nThe `parseAuthentication` middleware is registered automatically and will use the strategies of the default [authentication service](./authentication/service.md) to parse headers for authentication information. If you want to additionally parse authentication with a different authentication service this middleware can be registered again with that service configured.\n\n```ts\nimport { parseAuthentication } from '@feathersjs/koa'\n\napp.use(\n  parseAuthentication({\n    service: 'api/v1/authentication',\n    strategies: ['jwt', 'local']\n  })\n)\n```\n\n### bodyParser\n\nA reference to the [koa-body](https://github.com/koajs/koa-body) module.\n\n### cors\n\nA reference to the [@koa/cors](https://github.com/koajs/cors) module.\n\n### serveStatic\n\nA reference to the [koa-static](https://github.com/koajs/static) module.\n"
  },
  {
    "path": "docs/api/schema/index.md",
    "content": "---\noutline: deep\n---\n\n# Schema Overview\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/schema.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/schema)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/schema/CHANGELOG.md)\n\n</Badges>\n\n`@feathersjs/schema` provides a way to define data models and to dynamically resolve them. It comes in in the following main parts:\n\n- [JSON schema](https://json-schema.org/) using [TypeBox](./typebox.md) or [plain JSON schema](./schema.md) to define a data model with TypeScript types and validations. This allows us to:\n  - Automatically get TypeScript types from schema definitions\n  - Automatically generate API documentation\n  - Create [database adapter](../databases/common.md) models without duplicating the data format\n- [Validators](./validators.md) take a [TypeBox](./typebox.md) or [JSON](./schema.md) schema to validate data to\n  - Ensure data is valid and always in the right format\n  - Validate query string queries and convert them to the right type\n- [Resolvers](./resolvers.md) - Resolve properties based on a context (usually the [hook context](../hooks.md)). This can be used for many different things like:\n  - Adding default and computed values\n  - Populating associations\n  - Securing queries and e.g. limiting requests to a user\n  - Removing protected properties for external requests\n  - Ability to add read- and write permissions on the property level\n  - Hashing passwords and validating dynamic password policies\n"
  },
  {
    "path": "docs/api/schema/resolvers.md",
    "content": "---\noutline: deep\n---\n\n# Resolvers\n\nResolvers dynamically resolve individual properties based on a context, in a Feathers application usually the [hook context](../hooks.md#hook-context).\n\nThis provide a flexible way to do things like:\n\n- Populating associations\n- Returning computed properties\n- Securing queries and e.g. limiting requests for a user\n- Setting context (e.g. logged in user or organization) specific default values\n- Removing protected properties for external requests\n- Add read- and write permissions on the property level\n- Hashing passwords and validating dynamic password policies\n\nYou can create a resolver for any data type and resolvers can also be used outside of Feathers.\n\n## Example\n\nHere is an example for a standalone resolver using a custom context:\n\n```ts\nimport { resolve } from '@feathersjs/schema'\n\ntype User = {\n  id: number\n  name: string\n}\n\ntype Message = {\n  id: number\n  userId: number\n  likes: number\n  text: string\n  user: User\n}\n\nclass MyContext {\n  getUser(id) {\n    return {\n      id,\n      name: 'David'\n    }\n  }\n\n  getLikes(messageId) {\n    return 10\n  }\n}\n\nconst messageResolver = resolve<Message, MyContext>({\n  likes: (value, message, context) => {\n    return context.getLikes(message.id)\n  },\n  user: (value, message, context) => {\n    return context.getUser(message.userId)\n  }\n})\n\nconst resolvedMessage = await messageResolver.resolve(\n  {\n    id: 1,\n    userId: 23,\n    text: 'Hello!'\n  },\n  new MyContext()\n)\n```\n\n## Property resolvers\n\nProperty resolvers are a map of property names to resolver functions. A resolver function is an `async` or regular function that resolves a property on a data object. If it returns `undefined` the property will not be included. It gets passed the following parameters:\n\n- `value` - The current value which can also be `undefined`\n- `data` - The initial data object\n- `context` - The context for this resolver\n- `status` - Additional status information like current property resolver path, the properties that should be resolved or a reference to the initial context.\n\n```ts\nconst userResolver = resolve<User, MyContext>({\n  isDrinkingAge: async (value, user, context) => {\n    const drinkingAge = await context.getDrinkingAge(user.country)\n\n    return user.age >= drinkingAge\n  },\n  fullName: (value, user, context) => {\n    return `${user.firstName} ${user.lastName}`\n  }\n})\n```\n\n<BlockQuote type=\"danger\">\n\nProperty resolver functions should only return a value and not have side effects. This means a property resolver **should not** do things like create new data or modify the `data` or `context` object. [Hooks](../hooks.md) should be used for side effects.\n\n</BlockQuote>\n\n## Virtual property resolvers\n\nVirtual resolvers are property resolvers that do not use the `value` but instead always return a value of their own. The parameters are (`(data, context, status)`). The above example can be written like this:\n\n```ts\nimport { resolve, virtual } from '@feathersjs/schema'\n\nconst userResolver = resolve<User, MyContext>({\n  isDrinkingAge: virtual(async (user, context) => {\n    const drinkingAge = await context.getDrinkingAge(user.country)\n\n    return user.age >= drinkingAge\n  }),\n  fullName: virtual((user, context) => {\n    return `${user.firstName} ${user.lastName}`\n  })\n})\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nVirtual resolvers should always be used when combined with a [database adapter](../databases/adapters.md) in order to make valid [$select queries](../databases/querying.md#select). Otherwise queries could try to select fields that do not exist in the database which will throw an error.\n\n</BlockQuote>\n\n## Options\n\nA resolver takes the following options as the second parameter:\n\n- `converter` (optional): A `(data, context) => {}` or `async (data, context) => {}` function that can return a completely new representation of the data. A `converter` runs before `properties` resolvers.\n\n```ts\nconst userResolver = resolve<User, MyContext>(\n  {\n    isDrinkingAge: async (value, user, context) => {\n      const drinkingAge = await context.getDrinkingAge(user.country)\n\n      return user.age >= drinkingAge\n    },\n    fullName: async (value, user, context) => {\n      return `${user.firstName} ${user.lastName}`\n    }\n  },\n  {\n    // Convert the raw data into a new structure before running property resolvers\n    converter: async (rawData, context) => {\n      return {\n        firstName: rawData.data.first_name,\n        lastName: rawData.data.last_name\n      }\n    }\n  }\n)\n```\n\n## Hooks\n\nIn a Feathers application, resolvers are used through [hooks](../hooks.md) to convert service `query`, `data` and `response`. The context for these resolvers is always the [hook context](../hooks.md#hook-context).\n\n### resolveData\n\nData resolvers use the `hooks.resolveData(...resolvers)` hook and convert the `data` from a `create`, `update` or `patch` [service method](../services.md) or a [custom method](../services.md#custom-methods). This can be used to validate against the schema and e.g. hash a password before storing it in the database or to remove properties the user is not allowed to write. It is possible to pass multiple objects containing resolvers which will run in the order they are passed. Subsequent resolver objects will receive the output from previous resolvers. `schemaHooks.resolveData` can be used as an `around` and `before` hook.\n\n```ts\nimport { hooks as schemaHooks, resolve } from '@feathersjs/schema'\nimport { Type } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\nimport type { HookContext } from '../declarations'\n\nconst messageSchema = Type.Object(\n  {\n    id: Type.Number(),\n    text: Type.String(),\n    createdAt: Type.Number(),\n    updatedAt: Type.Number(),\n    userId: Type.Number()\n  },\n  { $id: 'Message', additionalProperties: false }\n)\n\ntype Message = Static<typeof messageSchema>\n\n// Pick the data for creating a new message\nconst messageDataSchema = Type.Pick(messageSchema, ['text'])\ntype MessageData = Static<typeof messageDataSchema>\n\n// Resolver that automatically set `userId` and `createdAt`\nconst messageDataResolver = resolve<Message, HookContext>({\n  // Associate the currently authenticated user\n  userId: (value, message, context) => context.params?.user.id,\n  // Return the current date\n  createdAt: () => Date.now()\n})\n\n// Resolver that automatically sets `updatedAt`\nconst messagePatchResolver = resolve<Message, HookContext>({\n  // Return the current date\n  updatedAt: () => Date.now()\n})\n\napp.service('users').hooks({\n  before: {\n    create: [schemaHooks.resolveData(messageDataResolver)],\n    patch: [schemaHooks.resolveData(messagePatchResolver)]\n  }\n})\n```\n\nNote that as an `all` hook `resolveData` will run for any method that has `data`, including [custom methods](../services.md#custom-methods). If you want to validate custom methods differently the hook should be registered on each service method it is used:\n\n```ts\napp.service('users').hooks({\n  before: {\n    create: [schemaHooks.resolveData(messageDataResolver)],\n    update: [schemaHooks.resolveData(messageDataResolver)],\n    patch: [schemaHooks.resolveData(messageDataResolver)],\n    customMethod: [schemaHooks.resolveData(customMethodDataResolver)]\n  }\n})\n```\n\n### resolveResult\n\nResult resolvers use the `hooks.resolveResult(...resolvers)` hook and resolve the data that is returned by a service call ([context.result](../hooks.md#context-result) in a hook). This can be used to populate associations or add other computed properties etc. It is possible to pass multiple resolvers which will run in the order they are passed, using the previous data.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\n`schemaHooks.resolveResult` must be used as an `around` hook. This is to ensure that the database adapters will be able to handle [$select queries](../databases/querying.md#select) properly when using [virtual properties](#virtual-property-resolvers).\n\n</BlockQuote>\n\n```ts\nimport { hooks as schemaHooks, resolve, virtual } from '@feathersjs/schema'\nimport { Type } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\nimport type { HookContext } from '../declarations'\n\nconst userSchema = Type.Object(\n  {\n    id: Type.Number(),\n    email: Type.String(),\n    password: Type.String(),\n    avatar: Type.Optional(Type.String())\n  },\n  { $id: 'User', additionalProperties: false }\n)\ntype User = Static<typeof userSchema>\n\nconst messageSchema = Type.Object(\n  {\n    id: Type.Number(),\n    text: Type.String(),\n    createdAt: Type.Number(),\n    userId: Type.Number(),\n    user: Type.Ref(userSchema)\n  },\n  { $id: 'Message', additionalProperties: false }\n)\n\ntype Message = Static<typeof messageSchema>\n\nexport const messageResolver = resolve<Message, HookContext>({\n  user: virtual(async (message, context) => {\n    // Populate the user associated via `userId`\n    const user = await context.app.service('users').get(message.userId)\n    return user\n  })\n})\n\napp.service('messages').hooks({\n  around: {\n    all: [schemaHooks.resolveResult(messageResolver)]\n  }\n})\n```\n\n### resolveExternal\n\nExternal (or dispatch) resolver use the `hooks.resolveDispatch(...resolvers)` hook to return a safe version of the data that will be sent to external clients. It is possible to pass multiple resolvers which will run in the order they are passed, using the previous data. Returning `undefined` for a property resolver will exclude the property which can be used to hide sensitive data like the user password. This includes nested associations and real-time events. `schemaHooks.resolveExternal` can be used as an `around` or `after` hook.\n\n```ts\nimport { hooks as schemaHooks, resolve } from '@feathersjs/schema'\nimport { Type } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\nimport type { HookContext } from '../declarations'\n\nconst userSchema = Type.Object(\n  {\n    id: Type.Number(),\n    email: Type.String(),\n    password: Type.String(),\n    avatar: Type.Optional(Type.String())\n  },\n  { $id: 'User', additionalProperties: false }\n)\ntype User = Static<typeof userSchema>\n\nexport const userExternalResolver = resolve<User, HookContext>({\n  // Always hide the password for external responses\n  password: () => undefined\n})\n\n// Dispatch should be resolved on every method\napp.service('users').hooks({\n  around: {\n    all: [schemaHooks.resolveExternal(userExternalResolver)]\n  }\n})\n```\n\n<BlockQuote type=\"warning\" label=\"important\">\n\nIn order to get the safe data from resolved associations **all services** involved need the `schemaHooks.resolveExternal` hook registered even if it does not need a resolver (`schemaHooks.resolveExternal()`).\n\n`schemaHooks.resolveExternal` should be registered first when used as an `around` hook or last when used as an `after` hook so that it gets the final result data.\n\n</BlockQuote>\n\n### resolveQuery\n\nQuery resolvers use the `hooks.resolveQuery(...resolvers)` hook to modify `params.query`. This is often used to set default values or limit the query so a user can only request data they are allowed to see. It is possible to pass multiple resolvers which will run in the order they are passed, using the previous data. `schemaHooks.resolveQuery` can be used as an `around` or `before` hook.\n\nIn this example for a `User` schema we are first checking if a user is available in our request. In the case a user is available we are returning the user's ID. Otherwise we return whatever value was provided for `id`.\n\n`context.params.user` would only be set if the request contains a user. This is usually the case when an external request is made. In the case of an internal request we may not have a specific user we are dealing with, and we will just return `value`.\n\nIf we were to receive an internal request, such as `app.service('users').get(123)`, `context.params.user` would be `undefined` and we would just return the `value` which is `123`.\n\n```ts\nimport { hooks as schemaHooks, resolve } from '@feathersjs/schema'\nimport { Type } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\nimport type { HookContext } from '../declarations'\n\nconst userSchema = Type.Object(\n  {\n    id: Type.Number(),\n    email: Type.String(),\n    password: Type.String(),\n    avatar: Type.Optional(Type.String())\n  },\n  { $id: 'User', additionalProperties: false }\n)\ntype User = Static<typeof userSchema>\n\nexport const userQueryProperties = Type.Pick(userSchema, ['id', 'email'])\nexport const userQuerySchema = querySyntax(userQueryProperties)\nexport type UserQuery = Static<typeof userQuerySchema>\n\nexport const userQueryResolver = resolve<UserQuery, HookContext>({\n  // If there is an authenticated user, they can only see their own data\n  id: (value, query, context) => {\n    if (context.params.user) {\n      return context.params.user.id\n    }\n\n    return value\n  }\n})\n\n// The query can be resolved on every method\napp.service('users').hooks({\n  before: {\n    all: [resolveQuery(userQueryResolver)]\n  }\n})\n```\n\nFor a more complicated example. We will make a separate `queryResolver`, called `companyFilterQueryResolver`, that will act as a ownership filter. We will have a `Company` service that is owned by a `User`. We will assume our app has two registered users and two companies. Each user owning one company. For simplicity, `User1` owns `Company1`, and `User2` owns `Company2`\n\nWe want to make sure only the user that owns the company can make any requests related to it. Our schema contains a `ownerUser` field, this is the owner of the company. When a request is made to the company schema, we are effectivly filtering our search for companies to be only those whose `ownerUser` matches the requesting user's id.\n\nSo if a `GET /company` request is made by `User1`, our resolver will convert our query to `GET /company?name=Company1&ownerUser={User1.id}`. The result will only return an array of 1 company to `User1`\n\nSimilarily, if a patch request was made by `User1` to modify `Company2`. A `404` would occur, as resulting query would search the database for a `Company2` that is owned by `User1` which does not exist.\n\n```ts\n// Main data model schema\nexport const companySchema = Type.Object(\n  {\n    id: Type.String({ format: 'uuid' }),\n    name: Type.String(),\n    ownerUser: Type.Ref(userSchema)\n  },\n  { $id: 'Company', additionalProperties: false }\n)\n\n// Schema for allowed query properties\nexport const companyQueryProperties = Type.Pick(companySchema, ['id'])\nexport const companyQuerySchema = Type.Intersect(\n  [\n    querySyntax(companyQueryProperties),\n    // Add additional query properties here\n    Type.Object({}, { additionalProperties: false })\n  ],\n  { additionalProperties: false }\n)\nexport type CompanyQuery = Static<typeof companyQuerySchema>\nexport const companyQueryValidator = getValidator(companyQuerySchema, queryValidator)\nexport const companyQueryResolver = resolve<CompanyQuery, HookContext>({})\n\nexport const companyFilterQueryResolver = resolve<Company, HookContext>({\n  ownerUser: (value, obj, context) => {\n    if (context.params.user) {\n      return context.params.user.id\n    }\n    return value\n  }\n})\n```\n"
  },
  {
    "path": "docs/api/schema/schema.md",
    "content": "---\noutline: deep\n---\n\n# JSON Schema\n\nAs an alternative to [TypeBox](./typebox.md), `@feathersjs/schema` also provides the ability to define plain JSON schemas as objects. It uses [json-schema-to-ts](https://github.com/thomasaribart/json-schema-to-ts) to turn those schemas into TypeScript types.\n\n<BlockQuote label=\"Need JSON Schema help?\">\n\nYou can find an introduction in the [JSON schema official getting started guide](https://json-schema.org/learn/getting-started-step-by-step) and a lot of type-specific JSON Schema examples in the [json-schema-to-ts docs](https://github.com/ThomasAribart/json-schema-to-ts).\n\n</BlockQuote>\n\n## Creating Schemas\n\n### Definitions\n\nIf you are not familiar with JSON schema have a look at the [official getting started guide](https://json-schema.org/learn/getting-started-step-by-step). Here is an example for a possible user schema:\n\n```ts\nimport type { FromSchema } from '@feathersjs/schema'\n\nexport const userSchema = {\n  $id: 'User',\n  type: 'object',\n  additionalProperties: false,\n  required: ['email', 'password'],\n  properties: {\n    id: { type: 'number' },\n    email: { type: 'string' },\n    password: { type: 'string' }\n  }\n} as const\n\nexport type User = FromSchema<typeof userSchema>\n```\n\n<LanguageBlock global-id=\"ts\">\n\n### Generating Correct Types\n\nFor correct TypeScript types, the definition always **needs to be declared `as const`**. This first example will not produce correct types because the definition is not immediately followed by `as const`:\n\n```ts\n// Will not produce correct types.\nconst definition = { type: 'object' } // `as const` is missing, here.\n```\n\nThis next example does declare `as const` after the `definition`, so the types will be generated correctly:\n\n```ts\n// Produces correct types.\nconst definition = { type: 'object' } as const\n```\n\n</LanguageBlock>\n\n## Extending Schemas\n\nTo create a new schema that extends an existing one, combine the schema properties (and `schema.required`, if used) with the new properties:\n\n```ts\nimport type { FromSchema } from '@feathersjs/schema'\n\nexport const userDataSchema = {\n  $id: 'User',\n  type: 'object',\n  additionalProperties: false,\n  required: ['email', 'password'],\n  properties: {\n    email: { type: 'string' },\n    password: { type: 'string' }\n  }\n} as const\n\nexport type UserData = FromSchema<typeof userDataSchema>\n\nexport const userSchema = {\n  $id: 'UserResult',\n  type: 'object',\n  additionalProperties: false,\n  required: [...userDataSchema.required, 'id'],\n  properties: {\n    ...userDataSchema.properties,\n    id: { type: 'number' }\n  }\n} as const\n\nexport type User = FromSchema<typeof userSchema>\n```\n\n## References\n\nAssociated schemas can be initialized via the `$ref` keyword referencing the `$id` set during schema definition.\n\n<LanguageBlock global-id=\"ts\">\n\nIn TypeScript, the referenced type needs to be added explicitly.\n\n</LanguageBlock>\n\n```ts\nimport type { FromSchema } from '@feathersjs/schema'\n\nexport const userSchema = {\n  $id: 'User',\n  type: 'object',\n  additionalProperties: false,\n  required: ['email', 'password'],\n  properties: {\n    id: { type: 'number' },\n    email: { type: 'string' },\n    password: { type: 'string' }\n  }\n} as const\n\nexport type User = FromSchema<typeof userSchema>\n\nexport const messageSchema = {\n  $id: 'Message',\n  type: 'object',\n  additionalProperties: false,\n  required: ['text'],\n  properties: {\n    text: { type: 'string' },\n    user: { $ref: 'User' }\n  }\n} as const\n\nexport type Message = FromSchema<\n  typeof messageSchema,\n  {\n    // All schema references need to be passed to get the correct type\n    references: [typeof userSchema]\n  }\n>\n```\n\n## Query Helpers\n\nSchema ships with a few helpers to automatically create schemas that comply with the [Feathers query syntax](../databases/querying.md) (like `$gt`, `$ne` etc.):\n\n### querySyntax\n\n`querySyntax(schema.properties, extensions)` initializes all properties the additional query syntax properties `$limit`, `$skip`, `$select` and `$sort`. `$select` and `$sort` will be typed so they only allow existing schema properties.\n\n```ts\nimport { querySyntax } from '@feathersjs/schema'\nimport type { FromSchema } from '@feathersjs/schema'\n\nexport const userQuerySchema = {\n  $id: 'UserQuery',\n  type: 'object',\n  additionalProperties: false,\n  properties: {\n    ...querySyntax(userSchema.properties)\n  }\n} as const\n\nexport type UserQuery = FromSchema<typeof userQuerySchema>\n\nconst userQuery: UserQuery = {\n  $limit: 10,\n  $select: ['email', 'id'],\n  $sort: {\n    email: 1\n  }\n}\n```\n\nAdditional special query properties [that are not already included in the query syntax](../databases/querying.md) like `$ilike` can be added like this:\n\n```ts\nimport { querySyntax } from '@feathersjs/schema'\nimport type { FromSchema } from '@feathersjs/schema'\n\nexport const userQuerySchema = {\n  $id: 'UserQuery',\n  type: 'object',\n  additionalProperties: false,\n  properties: {\n    ...querySyntax(userSchema.properties, {\n      email: {\n        $ilike: {\n          type: 'string'\n        }\n      }\n    } as const)\n  }\n} as const\n\nexport type UserQuery = FromSchema<typeof userQuerySchema>\n\nconst userQuery: UserQuery = {\n  $limit: 10,\n  $select: ['email', 'id'],\n  $sort: {\n    email: 1\n  },\n  email: {\n    $ilike: '%@example.com'\n  }\n}\n```\n\n### queryProperty\n\n`queryProperty` helper takes a definition for a single property and returns a schema that allows the default query operators. This helper supports the operators listed, below. Learn what each one means in the [common query operator](/api/databases/querying#operators) documentation.\n\n- `$gt`\n- `$gte`\n- `$lt`\n- `$lte`\n- `$ne`\n- `$in`\n- `$nin`\n\nThe `name` property in the example, below, shows how `queryProperty` wraps a single property's definition.\n\n```ts\nimport { queryProperty } from '@feathersjs/schema'\n\nexport const userQuerySchema = {\n  $id: 'UserQuery',\n  type: 'object',\n  additionalProperties: false,\n  properties: {\n    name: queryProperty({ type: 'string' })\n  }\n} as const\n```\n\nWith the `queryProperty` utility in place, the schema will allow querying on `name` using any of the above-listed operators. With it in place, the query in the following example will not throw an error:\n\n```ts\nconst query = { name: { $in: ['Marco', 'Polo'] } }\n\napp.service('users').find({ query })\n```\n\nYou can learn how it works, [here](https://github.com/feathersjs/feathers/blob/dove/packages/schema/src/query.ts#L29-L55).\n\n### queryProperties\n\n`queryProperties(schema.properties)` takes the all properties of a schema and converts them into query schema properties (using `queryProperty`)\n\n## Validators\n\nThe following functions are available to get a [validator function](./validators.md) from a JSON schema definition.\n\n<BlockQuote type=\"info\" label=\"note\">\n\nSee the [validators](./validators.md) chapter for more information on validators and validator functions.\n\n</BlockQuote>\n\n### getDataValidator\n\n`getDataValidator(definition, validator)` returns validators for the data of `create`, `update` and `patch` service methods. You can either pass a single definition in which case all properties of the `patch` schema will be optional or individual validators for `create`, `update` and `patch`.\n\n```ts\nimport { getDataValidator, Ajv } from '@feathersjs/schema'\nimport type { FromSchema } from '@feathersjs/schema'\n\nconst userDataSchema = {\n  $id: 'User',\n  type: 'object',\n  additionalProperties: false,\n  required: ['email', 'password'],\n  properties: {\n    email: { type: 'string' },\n    password: { type: 'string' }\n  }\n} as const\n\ntype UserData = FromSchema<typeof userDataSchema>\n\nconst dataValidator = new Ajv()\n\nconst dataValidator = getDataValidator(userDataSchema, dataValidator)\n```\n\n### getValidator\n\n`getValidator(definition, validator)` returns a single validator function for a JSON schema.\n\n```ts\nimport { querySyntax, Ajv, getValidator } from '@feathersjs/schema'\nimport type { FromSchema } from '@feathersjs/schema'\n\nexport const userQuerySchema = {\n  $id: 'UserQuery',\n  type: 'object',\n  additionalProperties: false,\n  properties: {\n    ...querySyntax(userSchema.properties)\n  }\n} as const\n\nexport type UserQuery = FromSchema<typeof userQuerySchema>\n\n// Since queries can be only strings we can to coerce them\nconst queryValidator = new Ajv({\n  coerceTypes: true\n})\n\nconst messageValidator = getValidator(userQuerySchema, queryValidator)\n```\n"
  },
  {
    "path": "docs/api/schema/typebox.md",
    "content": "---\noutline: deep\n---\n\n# TypeBox\n\n`@feathersjs/typebox` allows to define JSON schemas with [TypeBox](https://github.com/sinclairzx81/typebox), a JSON schema type builder with static type resolution for TypeScript.\n\n[[toc]]\n\n<BlockQuote type=\"info\" label=\"Note\">\n\nFor additional information also see the [TypeBox documentation](https://github.com/sinclairzx81/typebox/blob/master/readme.md#contents).\n\n</BlockQuote>\n\n## Usage\n\nThe module exports all of TypeBox functionality with additional support for [query schemas](#query-schemas) and [validators](#validators). The following is an example for defining the message schema [from the guide](../../guides/basics/schemas.md#handling-messages) using TypeBox:\n\n```ts\nimport { Type } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\n\nconst messageSchema = Type.Object(\n  {\n    id: Type.Number(),\n    text: Type.String(),\n    createdAt: Type.Number(),\n    userId: Type.Number()\n  },\n  { $id: 'Message', additionalProperties: false }\n)\n\ntype Message = Static<typeof messageSchema>\n```\n\n## Result and data schemas\n\nA good approach to define schemas in a Feathers application is to create the main schema first. This is usually the properties that are in the database and things like associated entries. Then we can get the data schema by e.g. picking the properties a client submits using `Type.Pick`\n\n```ts\nimport { Type } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\n\nconst userSchema = Type.Object(\n  {\n    id: Type.Number(),\n    email: Type.String(),\n    password: Type.String(),\n    avatar: Type.Optional(Type.String())\n  },\n  { $id: 'User', additionalProperties: false }\n)\ntype User = Static<typeof userSchema>\n\n// Pick the data for creating a new user\nconst userDataSchema = Type.Pick(userSchema, ['email', 'password'])\n\ntype UserData = Static<typeof userDataSchema>\n\nconst messageSchema = Type.Object(\n  {\n    id: Type.Number(),\n    text: Type.String(),\n    createdAt: Type.Number(),\n    userId: Type.Number(),\n    // Reference the user\n    user: Type.Ref(userSchema)\n  },\n  { $id: 'Message', additionalProperties: false }\n)\n\ntype Message = Static<typeof messageSchema>\n\n// Pick the data for creating a new message\nconst messageDataSchema = Type.Pick(messageSchema, ['text'])\n\ntype MessageData = Static<typeof messageDataSchema>\n```\n\n## Query schemas\n\n### querySyntax\n\n`querySyntax(definition, extensions, options)` returns a schema to validate the [Feathers query syntax](../databases/querying.md) for all properties in a TypeBox definition.\n\n```ts\nimport { querySyntax } from '@feathersjs/typebox'\n\n// Schema for allowed query properties\nconst messageQueryProperties = Type.Pick(messageSchema, ['id', 'text', 'createdAt', 'userId'], {\n  additionalProperties: false\n})\nconst messageQuerySchema = querySyntax(messageQueryProperties)\n\ntype MessageQuery = Static<typeof messageQuerySchema>\n```\n\nAdditional special query properties [that are not already included in the query syntax](../databases/querying.md) like `$ilike` can be added like this:\n\n```ts\nimport { querySyntax } from '@feathersjs/typebox'\n\n// Schema for allowed query properties\nconst messageQueryProperties = Type.Pick(messageSchema, ['id', 'text', 'createdAt', 'userId'], {\n  additionalProperties: false\n})\nconst messageQuerySchema = Type.Intersect(\n  [\n    // This will additionally allow querying for `{ name: { $ilike: 'Dav%' } }`\n    querySyntax(messageQueryProperties, {\n      name: {\n        $ilike: Type.String()\n      }\n    }),\n    // Add additional query properties here\n    Type.Object({})\n  ],\n  { additionalProperties: false }\n)\n```\n\nTo allow additional query properties outside of the query syntax use the intersection type:\n\n```ts\nimport { querySyntax } from '@feathersjs/typebox'\n\n// Schema for allowed query properties\nconst messageQueryProperties = Type.Pick(messageSchema, ['id', 'text', 'createdAt', 'userId'], {\n  additionalProperties: false\n})\nconst messageQuerySchema = Type.Intersect(\n  [\n    querySyntax(messageQueryProperties),\n    Type.Object({\n      isActive: Type.Boolean()\n    })\n  ],\n  { additionalProperties: false }\n)\n\ntype MessageQuery = Static<typeof messageQuerySchema>\n```\n\n### queryProperty\n\n`queryProperty(definition)` returns a schema for the [Feathers query syntax](../databases/querying.md) for a single property.\n\n## Validators\n\nThe following functions are available to get a [validator function](./validators.md) from a TypeBox schema.\n\n<BlockQuote type=\"info\" label=\"note\">\n\nSee the [validators](./validators.md) chapter for more information on validators and validator functions.\n\n</BlockQuote>\n\n### getDataValidator\n\n`getDataValidator(definition, validator)` returns validators for the data of `create`, `update` and `patch` service methods. You can either pass a single definition in which case all properties of the `patch` schema will be optional or individual validators for `create`, `update` and `patch`.\n\n```ts\nimport { Ajv } from '@feathersjs/schema'\nimport { Type, getDataValidator } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\n\nconst userSchema = Type.Object(\n  {\n    id: Type.Number(),\n    email: Type.String(),\n    password: Type.String(),\n    avatar: Type.Optional(Type.String())\n  },\n  { $id: 'User', additionalProperties: false }\n)\ntype User = Static<typeof userSchema>\n\n// Pick the data for creating a new user\nconst userDataSchema = Type.Pick(userSchema, ['email', 'password'])\n\nconst dataValidator = new Ajv()\n\nconst userDataValidator = getDataValidator(userDataSchema, dataValidator)\n\n// For more granular control\nconst userDataValidator = getDataValidator(\n  {\n    create: userDataSchema,\n    update: userDataSchema,\n    patch: Type.Partial(userDataSchema)\n  },\n  dataValidator\n)\n```\n\n### getValidator\n\n`getValidator(definition, validator)` returns a single validator function for a TypeBox schema.\n\n```ts\nimport { Ajv } from '@feathersjs/schema'\nimport { Type, getValidator } from '@feathersjs/typebox'\n\n// Schema for allowed query properties\nconst messageQueryProperties = Type.Pick(messageSchema, ['id', 'text', 'createdAt', 'userId'], {\n  additionalProperties: false\n})\nconst messageQuerySchema = querySyntax(messageQueryProperties)\ntype MessageQuery = Static<typeof messageQuerySchema>\n\n// Since queries can be only strings we can to coerce them\nconst queryValidator = new Ajv({\n  coerceTypes: true\n})\n\nconst messageQueryValidator = getValidator(messageQuerySchema, queryValidator)\n```\n\n## Validating Dates\n\nWhen validating dates sent from the client, the most spec-compliant solution is to use the [ISO8601 format](https://www.rfc-editor.org/rfc/rfc3339#section-5.6). For example, SQLite date values are strings in the [ISO8601 format](https://www.rfc-editor.org/rfc/rfc3339#section-5.6), which is `YYYY-MM-DDTHH:MM:SS.SSS`. The character between the date and time formats is generally specified as the letter `T`, as in `2016-01-01T10:20:05.123`. For date values, you implement this spec with `Type.String` and not `Type.Date`.\n\nWhen using AJV you can validate this format with the `ajv-formats` package, which the Feathers CLI installs for you. Using it with `@feathersjs/typebox` looks like this:\n\n```ts\nconst userSchema = Type.Object(\n  {\n    createdAt: Type.String({ format: 'date-time' })\n  },\n  { $id: 'User', additionalProperties: false }\n)\n```\n\nSee the `@feathersjs/mongodb` docs for more information on [validating dates with MongoDB](/api/databases/mongodb#dates).\n\n## Types\n\nTypeBox provides a set of functions that allow you to compose JSON Schema similar to how you would compose static types with TypeScript. Each function creates a JSON schema fragment which can compose into more complex types. The schemas produced by TypeBox can be passed directly to any JSON Schema-compliant validator, or used to reflect runtime metadata for a type.\n\n### Standard\n\nThese are the standard TypeBox types. Each section shows equivalent code in three formats:\n\n- TypeBox\n- TypeScript type\n- JSON Schema\n\nThe following information comes from the TypeBox documentation. It has been formatted to make it easier to copy/paste examples.\n\n#### Primitive Types\n\nPrimitive type utilities create schemas for individual values.\n\n##### Any\n\nCreates a schema that will always pass validation. It's the equivalent of TypeScript's [any](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any) type.\n\n```js\nconst T = Type.Any()\n```\n\n```js\ntype T = any\n```\n\n```js\nconst T = {}\n```\n\n##### Unknown\n\nSimilar to [any](#any), it creates a schema that will always pass validation. It's the equivalent of TypeScript's [unknown](https://www.typescriptlang.org/docs/handbook/2/functions.html#unknown) type.\n\n```js\nconst T = Type.Unknown()\n```\n\n```js\ntype T = unknown\n```\n\n```js\nconst T = {}\n```\n\n##### String\n\nCreates a string schema and type. `Type.String` will generally be used for validating dates sent from clients, as well. See [Validating Dates](#validating-dates).\n\n```js\nconst T = Type.String()\n```\n\n```js\ntype T = string\n```\n\n```js\nconst T = {\n  type: 'string'\n}\n```\n\n###### String Formats Bundled\n\nStrings are the most versatile, serializable type which can be transmitted from clients. Because of their versatility, several custom string formatters are supported, by default, in Feathers CLI-generated applications. [Additional formats](#additional-formats) can be manually enabled.\n\n<hr/>\n\n###### `date-time`\n\n```ts\nType.String({ format: 'date-time' })\n```\n\nValidates against the [date-time](https://www.rfc-editor.org/rfc/rfc3339#section-5.6) described in RFC3339/ISO8601, which is the following format:\n\n```\nYYYY-MM-DDTHH:MM:SS.SSS+HH:MM\n2022-11-30T11:21:44.000-08:00\n```\n\nThe sections of this format are described as follows:\n\n- **full-date**: `YYYY-MM-DD`\n- **partial-time**: `HH:MM:SS.SSS` (where `.SSS` represents optional milliseconds)\n- **time-offset**: `+HH:MM` (where `+` can be `-` and which value represents UTC offset or \"time zone\") **required**\n\n<hr/>\n\n###### `time`\n\n```ts\nType.String({ format: 'time' })\n```\n\nValidates against the following format:\n\n```\nHH:MM:SS.SSS+HH:MM\n11:21:44.000-08:00\n```\n\nThe sections of this format are described as follows:\n\n- **partial-time**: `HH:MM:SS.SSS` (where `.SSS` represents optional milliseconds)\n- **time-offset**: `+HH:MM` (where `+` can be `-` and which value represents UTC offset or \"time zone\") **optional**\n\n<hr/>\n\n###### `date`\n\n```ts\nType.String({ format: 'date' })\n```\n\nValidates against the [full date](https://www.rfc-editor.org/rfc/rfc3339#section-5.6) described in RFC3339/ISO8601, which is the following format:\n\n```\nYYYY-MM-DD\n2022-11-30\n```\n\n<hr/>\n\n###### `email`\n\n```ts\nType.String({ format: 'email' })\n```\n\nValidates email addresses against the format specified by [RFC 1034](https://rumkin.com/software/email/rules/).\n\n<hr/>\n\n###### `hostname`\n\n```ts\nType.String({ format: 'hostname' })\n```\n\nValidates hostnames against the format specified by [RFC 1034](https://rumkin.com/software/email/rules/).\n\n<hr/>\n\n###### `ipv4`\n\n```ts\nType.String({ format: 'ipv4' })\n```\n\nValidates an IPV4-formatted IP Address.\n\n```\n0.0.0.0 to 255.255.255.255\n```\n\n<hr/>\n\n###### `ipv6`\n\n```ts\nType.String({ format: 'ipv6' })\n```\n\nValidates an IPV6-formatted IP Address.\n\n<hr/>\n\n###### `uri`\n\n```ts\nType.String({ format: 'uri' })\n```\n\nValidates a full URI.\n\n<hr/>\n\n###### `uri-reference`\n\n```ts\nType.String({ format: 'uri-reference' })\n```\n\n<hr/>\n\n###### `uuid`\n\n```ts\nType.String({ format: 'uuid' })\n```\n\nValidates a Universally Unique Identifier according to [rfc4122](https://www.rfc-editor.org/rfc/rfc4122).\n\n<hr/>\n\n###### `uri-template`\n\n```ts\nType.String({ format: 'uri-template' })\n```\n\nValidates a URI Template according to [rfc6570](https://www.rfc-editor.org/rfc/rfc6570).\n\n<hr/>\n\n###### `json-pointer`\n\n```ts\nType.String({ format: 'json-pointer' })\n```\n\nValidates a JSON Pointer, according to [RFC6901](https://www.rfc-editor.org/rfc/rfc6901).\n\n<hr/>\n\n###### `relative-json-pointer`\n\n```ts\nType.String({ format: 'relative-json-pointer' })\n```\n\nValidates a Relative JSON Pointer, according to [this draft](https://datatracker.ietf.org/doc/html/draft-luff-relative-json-pointer-00).\n\n<hr/>\n\n###### `regex`\n\n```ts\nType.String({ format: 'regex' })\n```\n\nTests whether a string is a valid regular expression by passing it to RegExp constructor.\n\n<hr/>\n\n###### Additional Formats\n\nThe `ajv-formats` package bundled with CLI-generated apps includes additional utilities, listed below, which can be manually enabled by modifying the array of formats in `src/schema/validators.ts`. The additional formats are highlighted in this code example:\n\n```ts{16-25}\nconst formats: FormatsPluginOptions = [\n  'date-time',\n  'time',\n  'date',\n  'email',\n  'hostname',\n  'ipv4',\n  'ipv6',\n  'uri',\n  'uri-reference',\n  'uuid',\n  'uri-template',\n  'json-pointer',\n  'relative-json-pointer',\n  'regex',\n  'iso-time',\n  'iso-date-time',\n  'duration',\n  'byte',\n  'int32',\n  'int64',\n  'float',\n  'double',\n  'password',\n  'binary',\n]\n```\n\nBe aware that there is also an [ajv-formats-draft2019 package](https://github.com/luzlab/ajv-formats-draft2019) which can be manually installed. The package allows use of several international formats for urls, domains, and emails. The formats are included in [JSON Schema draft-07](https://json-schema.org/draft-07/json-schema-release-notes.html).\n\n<hr/>\n\n###### iso-time\n\nMust be manually enabled. See [Additional Formats](#additional-formats).\n\n```ts\nType.String({ format: 'iso-time' })\n```\n\nValidates against UTC-based time format:\n\n```\nHH:MM:SS.SSSZ\n11:21:44.000Z\n\nHH:MM:SSZ\n11:21:44Z\n```\n\nThe sections of this format are described as follows:\n\n- **partial-time**: `HH:MM:SS.SSS` (where `.SSS` represents optional milliseconds)\n- **Z**: `Z` (where Z represents UTC time zone, or time offset 00:00)\n\n<hr/>\n\n###### `iso-date-time`\n\n```ts\nType.String({ format: 'iso-date-time' })\n```\n\nValidates against the [date-time](https://www.rfc-editor.org/rfc/rfc3339#section-5.6) described in RFC3339/ISO8601, which is the following format:\n\n```\nYYYY-MM-DDTHH:MM:SS.SSSZ\n2022-11-30T11:21:44.000Z\n\nYYYY-MM-DDTHH:MM:SSZ\n2022-11-30T11:21:44Z\n```\n\nThe sections of this format are described as follows:\n\n- **full-date**: `YYYY-MM-DD`\n- **partial-time**: `HH:MM:SS.SSS` (where `.SSS` represents optional milliseconds)\n- **Z**: `Z` (where Z represents UTC time zone, or time offset 00:00)\n\n<hr/>\n\n###### Duration\n\nMust be manually enabled. See [Additional Formats](#additional-formats).\n\n```ts\nType.String({ format: 'duration' })\n```\n\nA duration string representing a period of time, as specified in [rfc3339 appendix-A](https://www.rfc-editor.org/rfc/rfc3339#appendix-A) undder the \"Durations\" heading. Here's an excerpt of the spec.\n\n```\nDurations:\n\ndur-second        = 1*DIGIT \"S\"\ndur-minute        = 1*DIGIT \"M\" [dur-second]\ndur-hour          = 1*DIGIT \"H\" [dur-minute]\ndur-time          = \"T\" (dur-hour / dur-minute / dur-second)\ndur-day           = 1*DIGIT \"D\"\ndur-week          = 1*DIGIT \"W\"\ndur-month         = 1*DIGIT \"M\" [dur-day]\ndur-year          = 1*DIGIT \"Y\" [dur-month]\ndur-date          = (dur-day / dur-month / dur-year) [dur-time]\n\nduration          = \"P\" (dur-date / dur-time / dur-week)\n```\n\n<hr/>\n\n###### Byte\n\nMust be manually enabled. See [Additional Formats](#additional-formats).\n\n```ts\nType.String({ format: 'byte' })\n```\n\nValidates base64-encoded data according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types).\n\n<hr/>\n\n###### int32\n\nMust be manually enabled. See [Additional Formats](#additional-formats).\n\n```ts\nType.String({ format: 'int32' })\n```\n\nValidates signed (+/-), 32-bit integers according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types).\n\n<hr/>\n\n###### int64\n\nMust be manually enabled. See [Additional Formats](#additional-formats).\n\n```ts\nType.String({ format: 'int64' })\n```\n\nValidates signed (+/-), 64-bit integers according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types).\n\n<hr/>\n\n###### float\n\nMust be manually enabled. See [Additional Formats](#additional-formats).\n\n```ts\nType.String({ format: 'float' })\n```\n\nValidates floats according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types).\n\n<hr/>\n\n###### double\n\nMust be manually enabled. See [Additional Formats](#additional-formats).\n\n```ts\nType.String({ format: 'double' })\n```\n\nValidates doubles according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types).\n\n<hr/>\n\n###### password\n\nMust be manually enabled. See [Additional Formats](#additional-formats).\n\n```ts\nType.String({ format: 'password' })\n```\n\nValidates passwords according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types).\n\n<hr/>\n\n###### binary\n\nMust be manually enabled. See [Additional Formats](#additional-formats).\n\n```ts\nType.String({ format: 'binary' })\n```\n\nValidates a binary string according to the [openApi 3.0.0 specification](https://spec.openapis.org/oas/v3.0.0#data-types).\n\n<hr/>\n\n##### Number\n\nCreates a number schema and type.\n\n```js\nconst T = Type.Number()\n```\n\n```js\ntype T = number\n```\n\n```js\nconst T = {\n  type: 'number'\n}\n```\n\n##### Integer\n\nCreates a number schema and type. The number has to be an integer (not a float).\n\n```js\nconst T = Type.Integer()\n```\n\n```js\ntype T = number\n```\n\n```js\nconst T = {\n  type: 'integer'\n}\n```\n\n##### Boolean\n\nCreates a boolean schema and type.\n\n```js\nconst T = Type.Boolean()\n```\n\n```js\ntype T = boolean\n```\n\n```js\nconst T = {\n  type: 'boolean'\n}\n```\n\n##### Null\n\nCreates a schema and type only allowing `null`.\n\n```js\nconst T = Type.Null()\n```\n\n```js\ntype T = null\n```\n\n```js\nconst T = {\n  type: 'null'\n}\n```\n\n##### Literal\n\nCreates a schema and type that must match the provided value.\n\n```js\nconst T = Type.Literal(42)\n```\n\n```js\ntype T = 42\n```\n\n```js\nconst T = {\n  const: 42,\n  type: 'number'\n}\n```\n\n#### Object & Array Types\n\nThese utilities creates schemas and types for objects and arrays.\n\n##### RegEx\n\nCreates a string schema that validates against a regular expression object. The TypeScript type will be `string`.\n\n```js\nconst T = Type.RegEx(/foo/)\n```\n\n```js\ntype T = string\n```\n\n```js\nconst T = {\n  type: 'string',\n  pattern: 'foo'\n}\n```\n\n##### Array\n\nCreates an array of the provided type. You can use any of the utility types to specify what can go in the array, even complex types using [union](#union) and [intersect](#intersect).\n\n```js\nconst T = Type.Array(Type.Number())\n```\n\n```js\ntype T = number[]\n```\n\n```js\nconst T = {\n  type: 'array',\n  items: {\n    type: 'number'\n  }\n}\n```\n\n##### Object\n\nCreates an object schema where all properties are required by default. You can use the [Type.Optional](#optional) utility to mark a key as optional.\n\n```js\nconst T = Type.Object({\n  x: Type.Number(),\n  y: Type.Number()\n})\n```\n\n```js\ntype T = {\n  x: number,\n  y: number\n}\n```\n\n```js\nconst T = {\n  type: 'object',\n  properties: {\n    x: {\n      type: 'number'\n    },\n    y: {\n      type: 'number'\n    }\n  },\n  required: ['x', 'y']\n}\n```\n\n##### Tuple\n\nCreates an array type with exactly two items matching the specified types.\n\n```js\nconst T = Type.Tuple([Type.Number(), Type.Number()])\n```\n\n```js\ntype T = [number, number]\n```\n\n```js\nconst T = {\n  type: 'array',\n  items: [{ type: 'number' }, { type: 'number' }],\n  additionalItems: false,\n  minItems: 2,\n  maxItems: 2\n}\n```\n\n##### StringEnum\n\n`StringEnum` is a standalone utility to for specifying an array of allowed string values on a property. It is directly exported from `@feathersjs/typebox`:\n\n```js\n// import the module, first\nimport { StringEnum } from '@feathersjs/typebox'\n\nconst T = StringEnum(['crow', 'dove', 'eagle'])\n// Add additional options\nconst T = StringEnum(['crow', 'dove', 'eagle'], {\n    default: 'crow'\n})\n```\n\nTo obtain the TypeScript type, use the `Static` utility:\n\n```js\nimport { Static } from '@feathersjs/typebox'\n\ntype T = Static<typeof T>\n```\n\n```js\nconst T = {\n  enum: ['crow', 'dove', 'eagle']\n}\n```\n\n##### Enum\n\n<BlockQuote>\n\nFor string values, use [StringEnum](#stringenum).\n\n</BlockQuote>\n\n```js\nenum Foo {\n  A,\n  B,\n}\nconst T = Type.Enum(Foo)\n```\n\n```js\nenum Foo {\n  A,\n  B,\n}\ntype T = Foo\n```\n\n```js\nconst T = {\n  anyOf: [\n    { type: 'number', const: 0 },\n    { type: 'number', const: 1 }\n  ]\n}\n```\n\n#### Utility Types\n\nThe utility types create types which are derived from other types.\n\n##### KeyOf\n\nCreates a schema for a string that can be any of the keys of a provided `Type.Object`. It's similar to TypeScript's [KeyOf](https://www.typescriptlang.org/docs/handbook/2/keyof-types.html#handbook-content) operator.\n\n```js\nconst T = Type.KeyOf(\n  Type.Object({\n    x: Type.Number(),\n    y: Type.Number()\n  })\n)\n```\n\n```js\ntype T = keyof {\n  x: number,\n  y: number,\n}\n```\n\n```js\nconst T = {\n  anyOf: [\n    { type: 'string', const: 'x' },\n    { type: 'string', const: 'y' }\n  ]\n}\n```\n\n##### Union\n\nCreates a type which can be one of the types in the provided array. It's the equivalent to using `|` to form a TypeScript [Union](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#unions).\n\n```js\nconst T = Type.Union([Type.String(), Type.Number()])\n```\n\n```js\ntype T = string | number\n```\n\n```js\nconst T = {\n  anyOf: [{ type: 'string' }, { type: 'number' }]\n}\n```\n\n##### Intersect\n\nCreates an object type by combining two or more other object types.\n\n```js\nconst T = Type.Intersect([\n  Type.Object({\n    x: Type.Number()\n  }),\n  Type.Object({\n    y: Type.Number()\n  })\n])\n```\n\n```js\ntype T = { x: number } & { y: number }\n```\n\n```js\nconst T = {\n  type: 'object',\n  properties: {\n    x: { type: 'number' },\n    y: { type: 'number' }\n  },\n  required: ['x', 'y']\n}\n```\n\n##### Never\n\nCreates a type that will never validate if the attribute is present. This is useful if you are allowing [additionalProperties](#additionalproperties) but need to prevent using specific keys.\n\n```js\nconst T = Type.Never()\n```\n\n```js\ntype T = never\n```\n\n```js\nconst T = {\n  allOf: [\n    { type: 'boolean', const: false },\n    { type: 'boolean', const: true }\n  ]\n}\n```\n\n##### Record\n\nCreates the JSON Schema equivalent of TypeScript's [Record](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type) utility type.\n\n```js\nconst T = Type.Record(Type.String(), Type.Number())\n```\n\n```js\ntype T = Record<string, number>\n```\n\n```js\nconst T = {\n  type: 'object',\n  patternProperties: {\n    '^.*$': {\n      type: 'number'\n    }\n  }\n}\n```\n\n##### Partial\n\nCreates a schema for an object where all keys are optional. It's the opposite of [Required](#required), and the JSON Schema equivalent of TypeScript's [Partial](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype) utility type.\n\n```js\nconst T = Type.Partial(\n  Type.Object({\n    x: Type.Number(),\n    y: Type.Number()\n  })\n)\n```\n\n```js\ntype T = Partial<{\n  x: number,\n  y: number\n}>\n```\n\n```js\nconst T = {\n  type: 'object',\n  properties: {\n    x: { type: 'number' },\n    y: { type: 'number' }\n  }\n}\n```\n\n##### Required\n\nCreates a schema for an object where all keys are required, even ignoring if keys are marked with `Type.Optional`. It's the opposite of [Partial](#partial), and the JSON Schema equivalent of TypeScript's [Required](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype) utility type.\n\n```js\nconst T = Type.Required(\n  Type.Object({\n    x: Type.Optional(Type.Number()),\n    y: Type.Optional(Type.Number())\n  })\n)\n```\n\n```js\ntype T = Required<{\n  x?: number,\n  y?: number\n}>\n```\n\n```js\nconst T = {\n  type: 'object',\n  properties: {\n    x: { type: 'number' },\n    y: { type: 'number' }\n  },\n  required: ['x', 'y']\n}\n```\n\n##### Pick\n\nForms a new object containing only the array of keys provided in the second argument. It's the JSON Schema equivalent of TypeScript's [Pick](https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys) utility type.\n\n```js\nconst T = Type.Pick(\n  Type.Object({\n    x: Type.Number(),\n    y: Type.Number()\n  }),\n  ['x']\n)\n```\n\n```js\ntype T = Pick<\n  {\n    x: number,\n    y: number\n  },\n  'x'\n>\n```\n\n```js\nconst T = {\n  type: 'object',\n  properties: {\n    x: { type: 'number' }\n  },\n  required: ['x']\n}\n```\n\n##### Omit\n\nForms a new object containing all keys except those provided in the second argument. It's the JSON Schema equivalent of TypeScript's [Omit](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys) utility type.\n\n```js\nconst T = Type.Omit(\n  Type.Object({\n    x: Type.Number(),\n    y: Type.Number()\n  }),\n  ['x']\n)\n```\n\n```js\ntype T = Omit<\n  {\n    x: number,\n    y: number\n  },\n  'x'\n>\n```\n\n```js\nconst T = {\n  type: 'object',\n  properties: {\n    y: { type: 'number' }\n  },\n  required: ['y']\n}\n```\n\n### Modifiers\n\nTypeBox provides modifiers that can be applied to an objects properties. This allows for `optional` and `readonly` to be applied to that property. The following table illustrates how they map between TypeScript and JSON Schema.\n\n#### Optional\n\nAllows marking a key in [Type.Object](#object) as optional.\n\n```js\nconst T = Type.Object({\n  name: Type.Optional(Type.String())\n})\n```\n\n```js\ntype T = {\n  name?: string\n}\n```\n\n```js\nconst T = {\n  type: 'object',\n  properties: {\n    name: {\n      type: 'string'\n    }\n  }\n}\n```\n\n#### Readonly\n\nAllows marking a key in [Type.Object](#object) as readonly. It's the equivalent of TypeScript's [Readonly](https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype) utility type.\n\n```js\nconst T = Type.Object({\n  name: Type.Readonly(Type.String())\n})\n```\n\n```js\ntype T = {\n  readonly name: string\n}\n```\n\n```js\nconst T = {\n  type: 'object',\n  properties: {\n    name: {\n      type: 'string'\n    }\n  },\n  required: ['name']\n}\n```\n\n#### ReadonlyOptional\n\nAllows marking a key in [Type.Object](#object) as both [readonly](#readonly) and [optional](#optional).\n\n```js\nconst T = Type.Object({\n  name: Type.ReadonlyOptional(Type.String())\n})\n```\n\n```js\ntype T = {\n  readonly name?: string\n}\n```\n\n```js\nconst T = {\n  type: 'object',\n  properties: {\n    name: {\n      type: 'string'\n    }\n  }\n}\n```\n\n### Options by Type\n\nYou can pass additional JSON schema options on the last argument of any given type. The [JSON Schema specification](https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural) describes options for each data type. Descriptions from the specification are copied here for easy reference.\n\n#### For Numbers\n\nNumber types support the following options, which can be used simultaneously.\n\n##### `multipleOf`\n\nThe value of \"multipleOf\" MUST be a number, strictly greater than 0. Values are valid only if division by this keyword's value results in an integer.\n\n```ts\nconst T = Type.Number({ multipleOf: 2 })\n```\n\n##### `maximum`\n\nThe value of \"maximum\" MUST be a number, representing an inclusive upper limit for a numeric instance. If the instance is a number, then this keyword validates only if the instance is less than or exactly equal to \"maximum\".\n\n```ts\nconst T = Type.Number({ maximum: 20 })\n```\n\n##### `exclusiveMaximum`\n\nThe value of \"exclusiveMaximum\" MUST be a number, representing an exclusive upper limit for a numeric instance. If the instance is a number, then the instance is valid only if it has a value strictly less than (not equal to) \"exclusiveMaximum\".\n\n```ts\nconst T = Type.Number({ exclusiveMaximum: 20 })\n```\n\n##### `minimum`\n\nThe value of \"minimum\" MUST be a number, representing an inclusive lower limit for a numeric instance. If the instance is a number, then this keyword validates only if the instance is greater than or exactly equal to \"minimum\".\n\n```ts\nconst T = Type.Number({ minimum: 20 })\n```\n\n##### `exclusiveMinimum`\n\nThe value of \"exclusiveMinimum\" MUST be a number, representing an exclusive lower limit for a numeric instance. If the instance is a number, then the instance is valid only if it has a value strictly greater than (not equal to) \"exclusiveMinimum\".\n\n```ts\nconst T = Type.Number({ exclusiveMinimum: 20 })\n```\n\n#### For Strings\n\nString types support the following options, which can be used simultaneously.\n\n##### `maxLength`\n\nThe value of this keyword MUST be a non-negative integer. A string instance is valid against this keyword if its length is less than, or equal to, the value of this keyword. The length of a string instance is defined as the number of its characters as defined by RFC 8259 [RFC8259].\n\n##### `minLength`\n\nThe value of this keyword MUST be a non-negative integer. A string instance is valid against this keyword if its length is greater than, or equal to, the value of this keyword. The length of a string instance is defined as the number of its characters as defined by RFC 8259 [RFC8259]. Omitting this keyword has the same behavior as a value of 0.\n\n##### `pattern`\n\nUse `Type.Regex`, instead of this option.\n\n##### With AJV Formats\n\nThere are four custom options which are only available for certain formats when using the `ajv-formats` package:\n\n- [formatMinimum](#formatminimum)\n- [formatMaximum](#formatmaximum)\n- [formatExclusiveMinimum](#formatexclusiveminimum)\n- [formatExclusiveMaximum](#formatexclusivemaximum)\n\nThe above-listed options are only available when using the following [string formats](#string-formats).\n\n- [date](#date)\n- [time](#time)\n- [date-time](#date-time)\n- [iso-time](#iso-time)\n- [iso-date-time](#iso-date-time)\n\n##### `formatMinimum`\n\nAllows defining minimum constraints when the `format` keyword defines ordering (using the compare function in format definition). Available when using [ajv-formats](#with-ajv-formats).\n\nThe following example validates that the provided date is on or after November 13, 2022.\n\n```ts\nType.String({ format: 'date', formatMinimum: '2022-11-13' })\n```\n\n##### `formatMaximum`\n\nAllows defining maximum constraints when the `format` keyword defines ordering (using the compare function in format definition). Available when using [ajv-formats](#with-ajv-formats).\n\nThe following example validates that the provided date is on or before November 13, 2022.\n\n```ts\nType.String({ format: 'date', formatMaximum: '2022-11-13' })\n```\n\n##### `formatExclusiveMinimum`\n\nAllows defining exclusive minimum constraints when the `format` keyword defines ordering (using the compare function in format definition). Available when using [ajv-formats](#with-ajv-formats).\n\nThe following example validates that the provided date is after (and not on) November 13, 2022.\n\n```ts\nType.String({ format: 'date', formatExclusiveMinimum: '2022-11-13' })\n```\n\n##### `formatExclusiveMaximum`\n\nAllows defining exclusive maximum constraints when the `format` keyword defines ordering (using the compare function in format definition). Available when using [ajv-formats](#with-ajv-formats).\n\nThe following example validates that the provided date is before (and not on) November 13, 2022.\n\n```ts\nType.String({ format: 'date', formatExclusiveMaximum: '2022-11-13' })\n```\n\n#### For Arrays\n\nArray types support the following options, which can be used simultaneously.\n\n##### `maxItems`\n\nThe value of this keyword MUST be a non-negative integer. An array instance is valid against \"maxItems\" if its size is less than, or equal to, the value of this keyword.\n\n##### `minItems`\n\nThe value of this keyword MUST be a non-negative integer. An array instance is valid against \"minItems\" if its size is greater than, or equal to, the value of this keyword. Omitting this keyword has the same behavior as a value of 0.\n\n##### `uniqueItems`\n\nThe value of this keyword MUST be a boolean. If this keyword has boolean value false, the instance validates successfully. If it has boolean value true, the instance validates successfully if all of its elements are unique. Omitting this keyword has the same behavior as a value of false.\n\n##### `maxContains`\n\nThe value of this keyword MUST be a non-negative integer.\n\nIf \"contains\" is not present within the same schema object, then this keyword has no effect.\n\nAn instance array is valid against \"maxContains\" in two ways, depending on the form of the annotation result of an adjacent \"contains\" [json-schema] keyword. The first way is if the annotation result is an array and the length of that array is less than or equal to the \"maxContains\" value. The second way is if the annotation result is a boolean \"true\" and the instance array length is less than or equal to the \"maxContains\" value.\n\n##### `minContains`\n\nThe value of this keyword MUST be a non-negative integer.\n\nIf \"contains\" is not present within the same schema object, then this keyword has no effect.\n\nAn instance array is valid against \"minContains\" in two ways, depending on the form of the annotation result of an adjacent \"contains\" [json-schema] keyword. The first way is if the annotation result is an array and the length of that array is greater than or equal to the \"minContains\" value. The second way is if the annotation result is a boolean \"true\" and the instance array length is greater than or equal to the \"minContains\" value.\n\nA value of 0 is allowed, but is only useful for setting a range of occurrences from 0 to the value of \"maxContains\". A value of 0 causes \"minContains\" and \"contains\" to always pass validation (but validation can still fail against a \"maxContains\" keyword).\n\nOmitting this keyword has the same behavior as a value of 1.\n\n#### For Objects\n\nArray types support the following options, which can be used simultaneously.\n\n##### `additionalProperties`\n\nSpecifies if keys other than the ones specified in the schema are allowed to be present in the object.\n\n##### `maxProperties`\n\nThe value of this keyword MUST be a non-negative integer. An object instance is valid against \"maxProperties\" if its number of properties is less than, or equal to, the value of this keyword.\n\n##### `minProperties`\n\nThe value of this keyword MUST be a non-negative integer. An object instance is valid against \"minProperties\" if its number of properties is greater than, or equal to, the value of this keyword. Omitting this keyword has the same behavior as a value of 0.\n\n##### `required`\n\nAll TypeBox types are required unless you wrap them in [Type.Optional](#optional), so you don't need to use this option, manually.\n\n##### `dependentRequired`\n\nThe value of this keyword MUST be an object. Properties in this object, if any, MUST be arrays. Elements in each array, if any, MUST be strings, and MUST be unique.\n\nThis keyword specifies properties that are required if a specific other property is present. Their requirement is dependent on the presence of the other property.\n\nValidation succeeds if, for each name that appears in both the instance and as a name within this keyword's value, every item in the corresponding array is also the name of a property in the instance.\n\nOmitting this keyword has the same behavior as an empty object.\n\n### Extended\n\nIn addition to JSON schema types, TypeBox provides several extended types that allow for the composition of `function` and `constructor` types. These additional types are not valid JSON Schema and will not validate using typical JSON Schema validation. However, these types can be used to frame JSON schema and describe callable interfaces that may receive JSON validated data. Since these are nonstandard types, most applications will not need them. Consider using the [Standard Types](#standard), instead, as using these types may make it difficult to upgrade your application in the future.\n\n#### Extended Configuration\n\nUtilities in this section require updating `src/schemas/validators.ts` to the Extended Ajv Configuration, as shown here: \n\n```ts\nimport { TypeGuard } from '@sinclair/typebox'\nimport { Value } from '@sinclair/typebox/value'\nimport addFormats from 'ajv-formats'\nimport type { Options } from 'ajv'\nimport Ajv from 'ajv'\n\nfunction schemaOf(schemaOf: string, value: unknown, schema: unknown) {\n  switch (schemaOf) {\n    case 'Constructor':\n      return TypeGuard.IsConstructor(schema) && Value.Check(schema, value) // not supported\n    case 'Function':\n      return TypeGuard.IsFunction(schema) && Value.Check(schema, value) // not supported\n    case 'Date':\n      return TypeGuard.IsDate(schema) && Value.Check(schema, value)\n    case 'Promise':\n      return TypeGuard.IsPromise(schema) && Value.Check(schema, value) // not supported\n    case 'Uint8Array':\n      return TypeGuard.IsUint8Array(schema) && Value.Check(schema, value)\n    case 'Undefined':\n      return TypeGuard.IsUndefined(schema) && Value.Check(schema, value) // not supported\n    case 'Void':\n      return TypeGuard.IsVoid(schema) && Value.Check(schema, value)\n    default:\n      return false\n  }\n}\n\nexport function createAjv(options: Options = {}) {\n  return addFormats(new Ajv(options), [\n    'date-time',\n    'time',\n    'date',\n    'email',\n    'hostname',\n    'ipv4',\n    'ipv6',\n    'uri',\n    'uri-reference',\n    'uuid',\n    'uri-template',\n    'json-pointer',\n    'relative-json-pointer',\n    'regex',\n  ])\n  .addKeyword({ type: 'object', keyword: 'instanceOf', validate: schemaOf })\n  .addKeyword({ type: 'null', keyword: 'typeOf', validate: schemaOf })\n  .addKeyword('exclusiveMinimumTimestamp')\n  .addKeyword('exclusiveMaximumTimestamp')\n  .addKeyword('minimumTimestamp')\n  .addKeyword('maximumTimestamp')\n  .addKeyword('minByteLength')\n  .addKeyword('maxByteLength')\n}\n\nexport const dataValidator: Ajv = createAjv({})\nexport const queryValidator: Ajv = createAjv({ coerceTypes: true })\n```\n\nIf you see an error stating `Error: strict mode: unknown keyword: \"instanceOf\"`, it's likely because you need to extend your configuration, as shown above.\n\n#### Constructor\n\nVerifies that the value is a constructor with typed arguments and return value. Requires [Extended Ajv Configuration](#extended-configuration).\n\n```js\nconst T = Type.Constructor([Type.String(), Type.Number()], Type.Boolean())\n```\n\n```js\ntype T = new (\n  arg0: string,\n  arg1: number,\n) => boolean\n```\n\n```js\nconst T = {\n  type: 'constructor',\n  parameters: [\n    { type: 'string' },\n    { type: 'number' },\n  ],\n  return {\n    type: 'boolean',\n  },\n}\n```\n\n#### Function\n\nVerifies that the value is a function with typed arguments and return value. Requires [Extended Ajv Configuration](#extended-configuration).\n\n```js\nconst T = Type.Function([Type.String(), Type.Number()], Type.Boolean())\n```\n\n```js\ntype T = ({\n  arg0: string,\n  arg1: number\n}) => boolean\n```\n\n```js\nconst T = {\n  type: 'function',\n  parameters: [\n    { type: 'string' },\n    { type: 'number' },\n  ],\n  return {\n    type: 'boolean',\n  },\n}\n```\n\n#### Promise\n\nVerifies that the value is an instanceof Promise which resolves to the provided type. Requires [Extended Ajv Configuration](#extended-configuration).\n\n```js\nconst T = Type.Promise(Type.String())\n```\n\n```js\ntype T = Promise<string>\n```\n\n```js\nconst T = {\n  type: 'promise',\n  item: { type: 'string' }\n}\n```\n\n#### Uint8Array\n\nVerifies that the value is an instanceof Uint8Array. Requires [Extended Ajv Configuration](#extended-configuration).\n\n```js\nconst T = Type.Uint8Array()\n```\n\n```js\ntype T = Uint8Array\n```\n\n```js\nconst T = {\n  type: 'object',\n  instanceOf: 'Uint8Array'\n}\n```\n\n#### Date\n\nVerifies that the value is an instanceof Date. This is likely not the validator to use for storing dates in a database. See [Validating Dates](#validating-dates). Requires [Extended Ajv Configuration](#extended-configuration).\n\n```js\nconst T = Type.Date()\n```\n\n```js\ntype T = Date\n```\n\n```js\nconst T = {\n  type: 'object',\n  instanceOf: 'Date'\n}\n```\n\n#### Undefined\n\nVerifies that the value is `undefined`. Requires [Extended Ajv Configuration](#extended-configuration).\n\n```js\nconst T = Type.Undefined()\n```\n\n```js\ntype T = undefined\n```\n\n```js\nconst T = {\n  type: 'object',\n  specialized: 'Undefined'\n}\n```\n\n\n#### Symbol\n\nVerifies that the value is of type `Symbol`. Requires [Extended Ajv Configuration](#extended-configuration).\n\n```js\nconst T = Type.Symbol()\n```\n\n```js\ntype T = symbol\n```\n\n```js\nconst T = {\n  type: 'null',\n  typeOf: 'Symbol'\n}\n```\n\n#### BigInt\n\nVerifies that the value is of type `BigInt`. Requires [Extended Ajv Configuration](#extended-configuration).\n\n```js\nconst T = Type.BigInt()\n```\n\n```js\ntype T = bigint\n```\n\n```js\nconst T = {\n  type: 'null',\n  typeOf: 'BigInt'\n}\n```\n\n#### Void\n\nVerifies that the value is `null`. Requires [Extended Ajv Configuration](#extended-configuration).\n\n```js\nconst T = Type.Void()\n```\n\n```js\ntype T = void\n```\n\n```js\nconst T = {\n  type: 'null'\n}\n```\n\n### Reference\n\nUse `Type.Ref(...)` to create referenced types. The target type must specify an `$id`.\n\n```ts\nconst T = Type.String({ $id: 'T' })\nconst R = Type.Ref(T)\n```\n\nFor a more detailed example see the [result and data schema](#result-and-data-schemas) section.\n"
  },
  {
    "path": "docs/api/schema/validators.md",
    "content": "---\noutline: deep\n---\n\n# Validators\n\n[Ajv](https://ajv.js.org/) is the default JSON Schema validator used by `@feathersjs/schema`. We chose it because it's fully compliant with the JSON Schema spec and it's the fastest JSON Schema validator because it has its own compiler. It pre-compiles code for each validator, instead of dynamically creating validators from schemas during runtime.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nAjv and most other validation libraries are only used for ensuring data is valid and are not designed to convert data to different types. Type conversions and populating data can be done using [resolvers](./resolvers.md). This ensures a clean separation of concern between validating and populating data.\n\n</BlockQuote>\n\n## Usage\n\nThe following is the standard `validators.ts` file that sets up a validator for data and queries (for which string types will be coerced automatically). It also sets up a collection of additional formats using [ajv-formats](https://ajv.js.org/packages/ajv-formats.html). The validators in this file can be customized according to the [Ajv documentation](https://ajv.js.org/) and [its plugins](https://ajv.js.org/packages/). You can find the available Ajv options in the [Ajv class API docs](https://ajv.js.org/options.html).\n\n```ts\nimport { Ajv, addFormats } from '@feathersjs/schema'\nimport type { FormatsPluginOptions } from '@feathersjs/schema'\n\nconst formats: FormatsPluginOptions = [\n  'date-time',\n  'time',\n  'date',\n  'email',\n  'hostname',\n  'ipv4',\n  'ipv6',\n  'uri',\n  'uri-reference',\n  'uuid',\n  'uri-template',\n  'json-pointer',\n  'relative-json-pointer',\n  'regex'\n]\n\nexport const dataValidator = addFormats(new Ajv({}), formats)\n\nexport const queryValidator = addFormats(\n  new Ajv({\n    coerceTypes: true\n  }),\n  formats\n)\n```\n\n## Validation functions\n\nA validation function takes data and validates them against a schema using a validator. They can be used with any validation library. Currently the `getValidator` functions are available for:\n\n- [TypeBox schema](./typebox.md#validators) to validate a TypeBox definition using an Ajv validator instance\n- [JSON schema](./schema.md#validators) to validate a JSON schema object using an Ajv validator instance\n\n## Hooks\n\nThe following hooks take a [validation function](#validation-functions) and validate parts of the [hook context](../hooks.md#hook-context).\n\n### validateData\n\n`schemaHooks.validateData` takes a [validation function](#validation-functions) and allows to validate the `data` in a `create`, `update` and `patch` request as well as [custom service methods](../services.md#custom-methods). It can be used as an `around` or `before` hook.\n\n```ts\nimport { Ajv, hooks as schemaHooks } from '@feathersjs/schema'\nimport { Type, getValidator } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\nimport { dataValidator } from '../validators'\n\nconst userSchema = Type.Object(\n  {\n    id: Type.Number(),\n    email: Type.String(),\n    password: Type.String(),\n    avatar: Type.Optional(Type.String())\n  },\n  { $id: 'User', additionalProperties: false }\n)\ntype User = Static<typeof userSchema>\n\nconst userDataSchema = Type.Pick(userSchema, ['email', 'password'])\n\n// Returns validation functions for `create`, `update` and `patch`\nconst userDataValidator = getValidator(userDataSchema, dataValidator)\n\napp.service('users').hooks({\n  before: {\n    all: [schemaHooks.validateData(userDataValidator)]\n  }\n})\n```\n\n### validateQuery\n\n`schemaHooks.validateQuery` takes a [validation function](#validation-functions) and validates the `query` of a request. It can be used as an `around` or `before` hook. When using the `queryValidator` from the [usage](#usage) section, strings will automatically be converted to the right type using [Ajv's type coercion rules](https://ajv.js.org/coercion.html).\n\n```ts\nimport { Ajv, schemaHooks } from '@feathersjs/schema'\nimport { Type, getValidator } from '@feathersjs/typebox'\nimport { queryValidator } from '../validators'\n\n// Schema for allowed query properties\nconst messageQueryProperties = Type.Pick(messageSchema, ['id', 'text', 'createdAt', 'userId'], {\n  additionalProperties: false\n})\nconst messageQuerySchema = querySyntax(messageQueryProperties)\ntype MessageQuery = Static<typeof messageQuerySchema>\n\nconst messageQueryValidator = getValidator(messageQuerySchema, queryValidator)\n\napp.service('messages').hooks({\n  around: {\n    all: [schemaHooks.validateQuery(messageQueryValidator)]\n  }\n})\n```\n\n### Using validators with custom methods\n\nYou can optionally create validators for your custom methods. For example we will create a custom method in our `user` service that simply says \"Hello ${name}\" to the requestor.\n\nFor the example we can use this TypeBox schema\n\n```ts\n//Our request object, we expect something like {name: \"Bob\"}\nexport const sayHelloRequest = Type.Object(\n  {\n    name: Type.String({\n      description: \"Who are we saying hello to!\",\n      examples: [\"Bob\"],\n      minLength: 2,\n    }),\n  },\n  { $id: \"sayHelloRequest\", additionalProperties: false },\n);\n\n//We intend on returning an object with a string response property\nexport const sayHelloResponse = Type.Object(\n  { response: Type.String() },\n  { $id: \"sayHelloResponse\", additionalProperties: false },\n);\n\nexport const sayHelloValidator = getValidator(sayHelloRequest, dataValidator);\n```\n\nIn our user class file, we can define our custom method\n\n```ts\nasync sayHello(data: Static<typeof sayHelloRequest>): Promise<Static<typeof sayHelloResponse>> {  \n  const { name } = data  \n  return { response: `Hello ${name}` }  \n}\n```\n\nFinally, we can add our validator in our service hooks\n\n```ts\nsayHello: [schemaHooks.validateData(sayHelloValidator)]\n```\n"
  },
  {
    "path": "docs/api/services.md",
    "content": "---\noutline: deep\n---\n\n# Services\n\nServices are the heart of every Feathers application. Services are objects or instances of [classes](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes) that implement [certain methods](#service-methods). Feathers itself will also add some [additional methods and functionality](#feathers-functionality) to its services.\n\n## Service methods\n\nService methods are pre-defined [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) and [custom methods](#custom-methods) that your service provides or that have already been implemented by one of the [database adapters](./databases/common.md). Below is an example of a Feathers service as a class or object.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport type { Params, Id, NullableId } from '@feathersjs/feathers'\n\nclass MyServiceClass {\n  async find(params: Params) {\n    return []\n  }\n  async get(id: Id, params: Params) {}\n  async create(data: any, params: Params) {}\n  async update(id: NullableId, data: any, params: Params) {}\n  async patch(id: NullableId, data: any, params: Params) {}\n  async remove(id: NullableId, params: Params) {}\n  async setup(app: Application, path: string) {}\n  async teardown(app: Application, path: string) {}\n}\n\nconst myServiceObject = {\n  async find(params: Params) {\n    return []\n  },\n  async get(id: Id, params: Params) {},\n  async create(data: any, params: Params) {},\n  async update(id: NullableId, data: any, params: Params) {},\n  async patch(id: NullableId, data: any, params: Params) {},\n  async remove(id: NullableId, params: Params) {},\n  async setup(app: Application, path: string) {},\n  async teardown(app: Application, path: string) {}\n}\n\ntype ServiceTypes = {\n  'my-service': MyServiceClass\n  'my-service-object': typeof myServiceObject\n}\n\nconst app = feathers<ServiceTypes>()\n\napp.use('my-service', new MyServiceClass())\napp.use('my-service-object', myServiceObject)\n```\n\n<BlockQuote type=\"danger\">\n\nAlways use the service returned by `app.service(path)` not the service object or class directly or you will not get any of the [Feathers service functionality](services.md#feathers-functionality)\n\n</BlockQuote>\n\n<BlockQuote type=\"tip\">\n\nMethods are optional and if a method is not implemented Feathers will automatically emit a `NotImplemented` error. At least one standard service method must be implemented to be considered a service. If you used `methods` option when registering the service via [app.use](./application.md#usepath-service--options), all methods listed must be available.\n\n</BlockQuote>\n\nService methods must use [async/await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) or return a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) and have the following parameters:\n\n- `id` — The identifier for the resource. A resource is the data identified by a unique id.\n- `data` — The resource data.\n- `params` - Additional parameters for the method call (see [params](#params))\n\nOnce registered, the service can be retrieved and used via [app.service()](./application.md#servicepath):\n\n```js\nconst myService = app.service('my-service')\n\nconst items = await myService.find()\n\nconst item = await app.service('my-service').get(1)\n\nconsole.log('.get(1)', item)\n```\n\n<BlockQuote type=\"info\">\n\nAlthough probably the most common use case, a service does not necessarily have to connect to a database. A custom service can implement any functionality like talking to another API or send an email etc.\n\n</BlockQuote>\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nThis section describes the general usage of service methods and how to implement them. They are already implemented by the official Feathers database adapters. For specifics on how to use the database adapters, see the [database adapters documentation](./databases/common.md).\n\n</BlockQuote>\n\n### params\n\n`params` contain additional information for the service method call. Some properties in `params` can be set by Feathers already. Commonly used are:\n\n- `params.query` - the query parameters from the client, either passed as URL query parameters (see the [REST](./express.md) chapter) or through websockets (see [Socket.io](./socketio.md)).\n- `params.provider` - The transport (`rest` or `socketio`) used for this service call. Will be `undefined` for internal calls from the server (unless passed explicitly).\n- `params.authentication` - The authentication information to use for the [authentication service](./authentication/service.md)\n- `params.user` - The authenticated user, either set by [Feathers authentication](./authentication/) or passed explicitly.\n- `params.connection` - If the service call has been made by a real-time transport (e.g. through websockets), `params.connection` is the connection object that can be used with [channels](./channels.md).\n- `params.headers` - The HTTP headers connected to this service call if available. This is either the headers of the REST call or the headers passed when initializing a websocket connection.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nFor external calls only `params.query` will be sent between the client and server. This is because other parameters in `params` on the server often contain security critical information (like `params.user` or `params.authentication`).\n\n</BlockQuote>\n\n### .find(params)\n\n`service.find(params) -> Promise` - Retrieves a list of all resources from the service. `params.query` can be used to filter and limit the returned data.\n\n```ts\nclass MessageService {\n  async find(params: Params) {\n    return [\n      {\n        id: 1,\n        text: 'Message 1'\n      },\n      {\n        id: 2,\n        text: 'Message 2'\n      }\n    ]\n  }\n}\n\napp.use('messages', new MessageService())\n```\n\n<BlockQuote type=\"info\">\n\n`find` does not have to return an array. It can also return an object. The database adapters already do this for [pagination](./databases/common.md#pagination).\n\n</BlockQuote>\n\n### .get(id, params)\n\n`service.get(id, params) -> Promise` - Retrieves a single resource with the given `id` from the service.\n\n```ts\nimport type { Id, Params } from '@feathersjs/feathers'\n\nclass TodoService {\n  async get(id: Id, params: Params) {\n    return {\n      id,\n      text: `You have to do ${id}!`\n    }\n  }\n}\n\napp.use('todos', new TodoService())\n```\n\n### .create(data, params)\n\n`service.create(data, params) -> Promise` - Creates a new resource with `data`. The method should return with the newly created data. `data` may also be an array.\n\nA successful `create` method call emits the [`created` service event](./events.md#created) with the returned data or a separate event for every item if the returned data is an array.\n\n```ts\nimport type { Id, Params } from '@feathersjs/feathers'\n\ntype Message = { text: string }\n\nclass MessageService {\n  messages: Message[] = []\n\n  async create(data: Message, params: Params) {\n    this.messages.push(data)\n\n    return data\n  }\n}\n\napp.use('messages', new MessageService())\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nNote that `data` may also be an array. When using a [database adapters](./databases/adapters.md) the [`multi` option](./databases/common.md) has to be set to allow arrays.\n\n</BlockQuote>\n\n### .update(id, data, params)\n\n`service.update(id, data, params) -> Promise` - Replaces the resource identified by `id` with `data`. The method should return with the complete, updated resource data. `id` can also be `null` when updating multiple records.\n\nA successful `update` method call emits the [`updated` service event](./events.md#updated-patched). If an array is returned, it will send an individual `updated` event for every item.\n\n<BlockQuote type=\"info\">\n\nThe [database adapters](./databases/adapters.md) do not support completely replacing multiple entries.\n\n</BlockQuote>\n\n### .patch(id, data, params)\n\n`patch(id, data, params) -> Promise` - Merges the existing data of the resource identified by `id` with the new `data`. `id` can also be `null` indicating that multiple resources should be patched with `params.query` containing the query criteria.\n\nA successful `patch` method call emits the [`patched` service event](./events.md#updated-patched) with the returned data. When an array is returned when patching mutiple items, it will send an individual `patched` event for every item in the array.\n\nThe method should return with the complete, updated resource data. Implement `patch` additionally (or instead of) `update` if you want to distinguish between partial and full updates and support the `PATCH` HTTP method.\n\n<BlockQuote type=\"info\">\n\nWith [database adapters](./databases/adapters.md) the [`multi` option](./databases/common.md) has to be set explicitly to support patching multiple entries.\n\n</BlockQuote>\n\n### .remove(id, params)\n\n`service.remove(id, params) -> Promise` - Removes the resource with `id`. The method should return with the removed data. `id` can also be `null`, which indicates the deletion of multiple resources, with `params.query` containing the query criteria.\n\nA successful `remove` method call emits the [`removed` service event](./events.md#removed) with the returned data or a separate event for every item if the returned data is an array.\n\n<BlockQuote type=\"info\">\n\nWith [database adapters](./databases/adapters.md) the [`multi` option](./databases/common.md) has to be set explicitly to support removing multiple entries.\n\n</BlockQuote>\n\n### .setup(app, path)\n\n`service.setup(app, path) -> Promise` is a special method that initializes the service, passing an instance of the Feathers application and the path it has been registered on.\n\nWhen calling [app.listen](application.md#listenport) or [app.setup](application.md#setupserver) all registered services `setup` methods will be called. If a service is registered afterwards, the `setup` method will be called immediately.\n\n### .teardown(app, path)\n\n`service.teardown(app, path) -> Promise` is a special method that shuts down the service, passing an instance of the Feathers application and the path it has been registered on. If a service implements a `teardown` method, it will be called during [app.teardown()](application.md#teardownserver) or when unregistering the service via [app.unuse](./application.md#unusepath).\n\n## Custom Methods\n\nA custom method is any other service method you want to expose publicly. A custom method **must have** the signature of `(data, params)` with the same semantics as standard service methods (`data` is the payload, `params` is the service [params](#params)). They can be used with [hooks](./hooks.md) (including authentication) and must be `async` or return a Promise.\n\nIn order to register a public custom method, the names of _all methods_ have to be passed as the `methods` option when registering the service with [app.use()](./application.md#usepath-service--options)\n\n```ts\nimport type { Id, Params } from '@feathersjs/feathers'\n\ntype CustomData = {\n  name: string\n}\n\nclass MyService {\n  async get(id: Id, params: Params) {\n    return {\n      id,\n      message: `You have to do ${id}`\n    }\n  }\n\n  async myCustomMethod(data: CustomData, params: Params) {\n    return data\n  }\n}\n\ntype ServiceTypes = {\n  'my-service': MyService\n}\n\nconst app = feathers<ServiceTypes>()\n  .configure(rest())\n  .use('my-service', new MyService(), {\n    // Pass all methods you want to expose\n    methods: ['get', 'myCustomMethod']\n  })\n```\n\nSee the [REST client](./client/rest.md) and [Socket.io client](./client/socketio.md) chapters on how to use those custom methods on the client.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nWhen passing the `methods` option **all methods** you want to expose, including standard service methods, must be listed. This allows to completely disable standard service method you might not want to expose. The `methods` option only applies to external access (via a transport like HTTP or websockets). All methods continue to be available internally on the server.\n\n</BlockQuote>\n\n## Feathers functionality\n\nWhen registering a service, Feathers (or its plugins) can also add its own methods to a service. Most notably, every service will automatically become an instance of a [NodeJS EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter).\n\n### .hooks(hooks)\n\nRegister [hooks](./hooks.md) for this service.\n\n### .publish([event, ] publisher)\n\nRegister an event publishing callback. For more information, see the [channels chapter](./channels.md).\n\n### .on(eventname, listener)\n\nProvided by the core [NodeJS EventEmitter .on](https://nodejs.org/api/events.html#events_emitter_on_eventname_listener). Registers a `listener` method (`function(data) {}`) for the given `eventname`.\n\n<BlockQuote type=\"info\">\n\nFor more information about service events, see the [Events chapter](./events.md).\n\n</BlockQuote>\n\n### .emit(eventname, data)\n\nProvided by the core [NodeJS EventEmitter .emit](https://nodejs.org/api/events.html#events_emitter_emit_eventname_args). Emits the event `eventname` to all event listeners.\n\n### .removeListener(eventname)\n\nProvided by the core [NodeJS EventEmitter .removeListener](https://nodejs.org/api/events.html#events_emitter_removelistener_eventname_listener). Removes all listeners, or the given listener, for `eventname`.\n"
  },
  {
    "path": "docs/api/socketio.md",
    "content": "---\noutline: deep\n---\n\n# Socket.io\n\n<Badges>\n\n[![npm version](https://img.shields.io/npm/v/@feathersjs/socketio.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/socketio)\n[![Changelog](https://img.shields.io/badge/changelog-.md-blue.svg?style=flat-square)](https://github.com/feathersjs/feathers/blob/dove/packages/socketio/CHANGELOG.md)\n\n</Badges>\n\n```\nnpm install @feathersjs/socketio --save\n```\n\nThe [@feathersjs/socketio](https://github.com/feathersjs/socketio) module allows to call [service methods](./services.md) and receive [real-time events](./events.md) via [Socket.io](http://socket.io/), a NodeJS library which enables real-time bi-directional, event-based communication.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nThis page describes how to set up a Socket.io server. The [Socket.io client chapter](./client/socketio.md) shows how to connect to this server on the client and the message format for service calls and real-time events.\n\n</BlockQuote>\n\n## Configuration\n\n`@feathersjs/socketio` can be used standalone or together with a Feathers framework integration like [Express](./express.md).\n\n### socketio()\n\n`app.configure(socketio())` sets up the Socket.io transport with the default configuration using either the server provided by [app.listen](./application.md#listenport) or passed in [app.setup(server)](./application.md#setupserver).\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio'\n\nconst app = feathers()\n\napp.configure(socketio())\n\napp.listen(3030)\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nOnce the server has been started with `app.listen()` or `app.setup(server)` the Socket.io object is available as `app.io`. Usually you should not have to send or listen to events on `app.io` directly.\n\n</BlockQuote>\n\n### socketio(callback)\n\n`app.configure(socketio(callback))` sets up the Socket.io transport with the default configuration and call `callback` with the [Socket.io server object](http://socket.io/docs/server-api/).\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio'\n\nconst app = feathers()\n\napp.configure(\n  socketio((io) => {\n    io.on('connection', (socket) => {\n      // Do something here\n    })\n\n    // Registering Socket.io middleware\n    io.use(function (socket, next) {\n      // Exposing a request property to services and hooks\n      socket.feathers.referrer = socket.request.referrer\n      next()\n    })\n  })\n)\n\napp.listen(3030)\n```\n\n<BlockQuote type=\"danger\">\n\nTry to avoid listening and sending events on the `socket` directly since it circumvents Feathers secure dispatch mechanisms available through [channels](./channels.md) and [hooks](./hooks.md).\n\n</BlockQuote>\n\n#### Using uWebSockets.js\n\nuWS can be used as a drop in replacement for socket handling.  \nAs a result you'll see lower latencies, a better memory footprint and even slightly less overall resource usage.  \nYou will on the other hand need to install the following extra package to get things working.\n\n```\nnpm install uNetworking/uWebSockets.js#20.31.0 --save\n```\n\nNow you can use the `io.attachApp` function to attach uWS as a replacement.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio'\nimport { App } from 'uWebSockets.js'\n\nconst app = feathers()\n\napp.configure(\n  socketio((io) => {\n    io.attachApp(App())\n  })\n)\n\napp.listen(3030)\n```\n\n### socketio(options [, callback])\n\n`app.configure(socketio(options [, callback]))` sets up the Socket.io transport with the given [Socket.io options object](https://github.com/socketio/engine.io#methods-1) and optionally calls the callback described above.\n\nThis can be used to e.g. configure the path where Socket.io is initialize (`socket.io/` by default). The following changes the path to `ws/`:\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio'\n\nconst app = feathers()\n\napp.configure(\n  socketio(\n    {\n      path: '/ws/'\n    },\n    (io) => {\n      // Do something here\n      // This function is optional\n    }\n  )\n)\n\napp.listen(3030)\n```\n\n### socketio(port, [options], [callback])\n\n`app.configure(socketio(port, [options], [callback]))` creates a new Socket.io server on a separate port. Options and a callback are optional and work as described above.\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio'\n\nconst app = feathers()\n\napp.configure(socketio(3031))\napp.listen(3030)\n```\n\n## params\n\n[Socket.io middleware](https://socket.io/docs/v4/middlewares/) can modify the `feathers` property on the `socket` which will then be used as the service call `params`:\n\n```ts\napp.configure(\n  socketio((io) => {\n    io.use((socket, next) => {\n      socket.feathers.user = { name: 'David' }\n      next()\n    })\n  })\n)\n\napp.use('messages', {\n  async create(data, params, callback) {\n    // When called via SocketIO:\n    params.provider // -> socketio\n    params.user // -> { name: 'David' }\n    return data\n  }\n})\n```\n\n<BlockQuote type=\"info\">\n\n`socket.feathers` is the same object as the `connection` in a [channel](./channels.md). `socket.request` and `socket.handshake` contains information the HTTP request that initiated the connection (see the [Socket.io documentation](https://socket.io/docs/server-api/#socket-request)).\n\n</BlockQuote>\n\n### params.provider\n\nFor any [service method call](./services.md) made through Socket.io `params.provider` will be set to `socketio`. In a [hook](./hooks.md) this can for example be used to prevent external users from making a service method call:\n\n```js\napp.service('users').hooks({\n  before: {\n    remove(context) {\n      // check for if(context.params.provider) to prevent any external call\n      if (context.params.provider === 'socketio') {\n        throw new Error('You can not delete a user via Socket.io')\n      }\n    }\n  }\n})\n```\n\n### params.query\n\n`params.query` will contain the query parameters sent from the client.\n\n<BlockQuote type=\"warning\">\n\nOnly `params.query` is passed between the server and the client, other parts of `params` are not. This is for security reasons so that a client can't set things like `params.user` or the database options. You can always map from `params.query` to `params` in a before [hook](./hooks.md).\n\n</BlockQuote>\n\n### params.connection\n\n`params.connection` is the connection object that can be used with [channels](./channels.md). It is the same object as `socket.feathers` in a Socket.io middleware as [shown in the `params` section](#params).\n\n### params.headers\n\n`params.headers` contains the headers from the original handshake. This is usually sent with the `extraHeaders` option when initialising the connection on the client:\n\n```ts\nconst socket = io('http://localhost:9777', {\n  extraHeaders: {\n    MyHeader: 'somevalue'\n  }\n})\n```\n"
  },
  {
    "path": "docs/auto-imports.d.ts",
    "content": "/* eslint-disable */\n/* prettier-ignore */\n// @ts-nocheck\n// noinspection JSUnusedGlobalSymbols\n// Generated by unplugin-auto-import\n// biome-ignore lint: disable\nexport {}\ndeclare global {\n\n}\n"
  },
  {
    "path": "docs/comparison.md",
    "content": "# Feathers vs others\n\nThe following sections compare Feathers to other software choices that seem similar or may overlap with the use cases of Feathers. Due to the bias of these comparisons being on the Feathers website, we attempt to only use facts. Below you can find a feature comparison table and in each section you can get more detailed comparisons. If you find something invalid or out of date in the comparisons, please create an issue and we'll address it as soon as possible.\n\n- [Feathers vs Firebase](/feathers-vs-firebase)\n- [Feathers vs Meteor](/feathers-vs-meteor)\n- [Feathers vs Sails](/feathers-vs-sails)\n- [Feathers vs Loopback](/feathers-vs-loopback)\n- [Feathers vs Nest](/feathers-vs-nest)\n"
  },
  {
    "path": "docs/components/CTAButton.vue",
    "content": "<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nconst props = defineProps({\n  primary: Boolean,\n  href: String\n})\n\nconst classes = computed(() => {\n  return { 'btn-primary': props.primary }\n})\n</script>\n\n<template>\n  <a\n    :href=\"href || '/guides/'\"\n    class=\"btn text-md font-bold uppercase px-6 py-0.5 rounded-full\"\n    md=\"text-lg px-8 py-1.6\"\n    lg=\"py-2.8 px-12\"\n    :class=\"classes\"\n  >\n    <slot />\n  </a>\n</template>\n\n<style lang=\"postcss\">\n.btn {\n  animation: button-pop var(--animation-btn, 0.25s) ease-out;\n}\n.btn:active:hover,\n.btn:active:focus {\n  animation: none;\n}\n.btn:active:hover,\n.btn:active:focus {\n  transform: scale(var(--btn-focus-scale, 0.95));\n}\n\n.btn-primary {\n  background-color: var(--vp-c-brand);\n  transition: all 300ms;\n}\n.btn-primary:hover {\n  background-color: var(--vp-c-brand-darker);\n}\n\n@keyframes button-pop {\n  0% {\n    transform: scale(var(--btn-focus-scale, 0.95));\n  }\n  40% {\n    transform: scale(1.02);\n  }\n  100% {\n    transform: scale(1);\n  }\n}\n</style>\n"
  },
  {
    "path": "docs/components/Footer.vue",
    "content": "<script setup lang=\"ts\">\nimport FooterList from './FooterList.vue'\nimport { useData, useRoute } from 'vitepress'\nimport { useWindowSize } from '@vueuse/core'\nimport { computed } from 'vue'\n\nconst route = useRoute()\nconst { theme, frontmatter } = useData()\n\nfunction ensureStartingSlash(path: any) {\n  return /^\\//.test(path) ? path : `/${path}`\n}\nfunction getSidebar(sidebar: any, path: any) {\n  if (Array.isArray(sidebar)) {\n    return sidebar\n  }\n  if (sidebar == null) {\n    return []\n  }\n  path = ensureStartingSlash(path)\n  const dir = Object.keys(sidebar)\n    .sort((a, b) => {\n      return b.split('/').length - a.split('/').length\n    })\n    .find((dir) => {\n      // make sure the multi sidebar key starts with slash too\n      return path.startsWith(ensureStartingSlash(dir))\n    })\n  return dir ? sidebar[dir] : []\n}\n\nconst sidebar = computed(() => {\n  const sidebarConfig = theme.value.sidebar\n  const relativePath = route.data.relativePath\n  return sidebarConfig ? getSidebar(sidebarConfig, relativePath) : []\n})\nconst hasSidebar = computed(() => {\n  return (\n    frontmatter.value.sidebar !== false && sidebar.value.length > 0 && frontmatter.value.layout !== 'home'\n  )\n})\n\n// Adjust width based on sidebar\nconst { width } = useWindowSize()\nconst addLeftMargin = computed(() => {\n  return width.value > 960\n})\n\nconst aboutList = [\n  {\n    label: 'Philosophy',\n    link: 'https://blog.feathersjs.com/why-we-built-the-best-web-framework-you-ve-probably-never-heard-of-until-now-176afc5c6aac'\n  },\n  { label: 'Comparison', link: '/comparison' },\n  { label: 'Ecosystem', link: 'https://github.com/feathersjs/awesome-feathersjs' }\n]\nconst learnList = [\n  { label: 'Guides', link: '/guides/' },\n  { label: 'API', link: '/api/' },\n  { label: 'Blog', link: 'https://blog.feathersjs.com' }\n]\nconst ecosystemList = [\n  { label: 'Become a Backer', link: 'https://github.com/sponsors/daffl' },\n  { label: 'Find Help', link: '/help/' },\n  { label: 'Github Issues', link: 'https://github.com/feathersjs/feathers/issues' }\n]\n</script>\n\n<template>\n  <footer\n    class=\"VPContent has-sidebar feathers-footer bg-neutral text-neutral-content\"\n    :class=\"{\n      'has-sidebar': hasSidebar,\n      'is-home': frontmatter.layout === 'home'\n    }\"\n  >\n    <div class=\"max-w-6xl w-full mx-auto px-4\">\n      <div class=\"sidebar-adjust\">\n        <div class=\"title flex flex-row items-center ml-2\">\n          <img class=\"logo invert mr-2\" src=\"/logo.svg\" />\n          feathers\n        </div>\n\n        <div class=\"flex flex-col sm:flex-row gap-12 sm:gap-0 flex-wrap mt-6 ml-10\">\n          <FooterList title=\"About\" :items=\"aboutList\" class=\"w-1/3\" />\n          <FooterList title=\"Learn\" :items=\"learnList\" class=\"w-1/3\" />\n          <FooterList title=\"Ecosystem\" :items=\"ecosystemList\" class=\"w-1/3\" />\n        </div>\n\n        <div class=\"h-1 bg-primary rounded-full mt-16\"></div>\n\n        <div class=\"py-6 text-sm text-center\">\n          <p class=\"message\">{{ theme.footer.message }}</p>\n          <p class=\"copyright\">{{ theme.footer.copyright }}</p>\n        </div>\n      </div>\n    </div>\n  </footer>\n</template>\n\n<style scoped>\n#app.home-page .feathers-footer {\n  padding-top: 64px;\n}\n\n@media (min-width: 960px) {\n  #app:not(.home-page) .VPContent {\n    padding-top: var(--vp-nav-height);\n  }\n\n  #app:not(.home-page) .VPContent.has-sidebar {\n    margin: var(--vp-layout-top-height, 0px) 0 0;\n    padding-left: var(--vp-sidebar-width);\n  }\n}\n\n@media (min-width: 1440px) {\n  #app:not(.home-page) .VPContent.has-sidebar {\n    padding-right: calc((100vw - var(--vp-layout-max-width)) / 2);\n    padding-left: calc((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width));\n  }\n}\n</style>\n"
  },
  {
    "path": "docs/components/FooterList.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps({\n  title: String,\n  items: Array,\n})\n</script>\n\n<template>\n  <ul class=\"text-lg\">\n    <li class=\"list-title font-bold text-2xl mb-4\">{{ title }}</li>\n    <li v-for=\"item in items\" :key=\"item.title\">\n      <a :href=\"item.link\">{{ item.label }}</a>\n    </li>\n  </ul>\n</template>\n"
  },
  {
    "path": "docs/components/HomeCTATextSection.vue",
    "content": "<script setup lang=\"ts\">\nimport CTAButton from './CTAButton.vue'\n\ndefineProps({\n  text: String,\n})\n</script>\n\n<template>\n  <div class=\"py-24 text-center\">\n    <h2 class=\"text-lg font-bold mb-10 md:text-2xl lg:text-3xl\">{{ text }}</h2>\n    <CTAButton primary>Get Started</CTAButton>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/components/HomeCreateFirstApp.vue",
    "content": "<template>\n  <div class=\"py-16 xl:py-24 bg-secondary text-center lg:text-lg\">\n    <h2 class=\"md:text-xl lg:text-2xl font-bold\">Create your first Feathers API in minutes</h2>\n    <div class=\"py-8\">\n      <img src=\"/img/coding-bird.svg\" alt=\"\" class=\"w-3/4 max-w-4xl mx-auto\" />\n    </div>\n    <p class=\"vp-doc pb-2\"><a href=\"/guides/\">Check out the docs</a> to learn more about Feathers.</p>\n    <p class=\"vp-doc\">\n      Feel free say hello on <a href=\"https://discord.gg/qa8kez8QBx\" target=\"_blank\">Discord</a>.\n    </p>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/components/HomeFeature1.vue",
    "content": "<script setup lang=\"ts\">\nimport HomeFeature1Content from \"./HomeFeature1Content.vue\"\n</script>\n\n<template>\n  <div>\n    <HomeFeature1Content class=\"block md:hidden\" />\n    <div class=\"flex flex-row\">\n      <div class=\"w-1/2 ml-6 flex items-end\">\n        <img src=\"/img/client-bird.svg\" class=\"relative left-4 w-full\" />\n      </div>\n      <div class=\"w-1/2 grid place-content-center\">\n        <HomeFeature1Content class=\"hidden md:block\" />\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/components/HomeFeature1Content.vue",
    "content": "<template>\n  <div class=\"py-6 md:py-0 px-6 md:text-sm prose text-center md:text-left xl:text-xl\">\n    <p>\n      Feathers is a full-stack web-framework for creating APIs and real-time applications with TypeScript or JavaScript.\n    </p>\n    <p>\n      Feathers can interact with any backend technology, supports many databases out of the box\n      and works with any frontend technology like React, VueJS, Angular, React Native,\n      Android or iOS.\n    </p>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/components/HomeFeature2.vue",
    "content": "<script setup lang=\"ts\">\nimport HomeFeature2Content from \"./HomeFeature2Content.vue\"\n</script>\n\n<template>\n  <div class=\"pb-16\">\n    <div class=\"flex flex-row\">\n      <div class=\"w-1/2 grid place-content-center\">\n        <HomeFeature2Content class=\"hidden md:block\" />\n      </div>\n      <div class=\"w-1/2 flex-none pl-12 pt-1 md:pt-3\">\n        <img\n          src=\"/img/server-bird.svg\"\n          class=\"w-full md:pr-4 xl:pr-22 relative right-4\"\n        />\n      </div>\n    </div>\n    <HomeFeature2Content class=\"block md:hidden\" />\n  </div>\n</template>\n"
  },
  {
    "path": "docs/components/HomeFeature2Content.vue",
    "content": "<script setup lang=\"ts\">\nimport CTAButton from './CTAButton.vue'\n</script>\n\n<template>\n  <div class=\"py-6 md:py-0 px-12 text-center\">\n    <div class=\"md:text-sm prose text-center md:text-left xl:text-xl\">\n      <p>Build prototypes in minutes and production-ready apps in days.</p>\n      <p>Seriously.</p>\n    </div>\n    <CTAButton href=\"/guides/basics/generator.html\" class=\"mt-6\" primary>Build a chat app</CTAButton>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/components/HomeFeatureGrid.vue",
    "content": "<script setup lang=\"ts\">\nimport HomeFeatureCard from './HomeFeatureGridCard.vue'\n\nconst cards = [\n  {\n    title: 'Fast',\n    imgSrc: '/img/feature-icons/Fast_Icon.svg',\n    description:\n      'Leveraging a unique architecture, Feathers lets you focus on building your APIs and real-time applications quickly. You automatically get scalable HTTP and real-time APIs and stay prepared for whatever else the future might bring.'\n  },\n  {\n    title: 'Universal',\n    imgSrc: '/img/feature-icons/Universal_Icon.svg',\n    description:\n      'Feathers can be used with NodeJS, in the browser, with React Native or with any other API client. You can use any database with <a href=\"/api/databases/adapters.html\">many supported out of the box</a> and connect your API seamlessly to any frontend framework.'\n  },\n  {\n    title: 'Flexible',\n    imgSrc: '/img/feature-icons/Flexible_Icon.svg',\n    description:\n      'Built for TypeScript, Feathers provides the structure to create complex applications but is flexible enough to not be in the way. With <a href=\"/ecosystem/\">a large ecosystem of plugins</a> you can include exactly what you need. No more, no less.'\n  }\n]\n</script>\n\n<template>\n  <div class=\"bg-secondary text-center pt-18 overflow-hidden\">\n    <h2 class=\"text-xl lg:text-2xl font-bold\">See what makes Feathers special</h2>\n\n    <div class=\"feature-grid flex md:flex-row flex-wrap justify-center relative mt-12\">\n      <HomeFeatureCard\n        v-for=\"card in cards\"\n        class=\"w-72 m-6\"\n        :key=\"card.title\"\n        :title=\"card.title\"\n        :img-src=\"card.imgSrc\"\n        :description=\"card.description\"\n      />\n    </div>\n\n    <div class=\"bg-base-100 h-64 relative -mt-64\"></div>\n  </div>\n</template>\n\n<style lang=\"postcss\">\n/* Adds the white arc behind the cards */\n.feature-grid::before {\n  background-color: var(--vp-c-bg);\n  border-radius: 50%;\n  bottom: 0;\n  content: '';\n  height: 300px;\n  position: absolute;\n  width: 150%;\n  z-index: 2;\n}\n</style>\n"
  },
  {
    "path": "docs/components/HomeFeatureGridCard.vue",
    "content": "<script setup lang=\"ts\">\ndefineProps({\n  title: String,\n  imgSrc: String,\n  description: String\n})\n</script>\n\n<template>\n  <div class=\"home-feature-card bg-base-100 bg-white shadow-xl p-8 space-y-4 z-10\">\n    <div class=\"flex items-center justify-center\">\n      <img :src=\"imgSrc\" alt=\"\" class=\"mx-auto w-42 h-42\" />\n    </div>\n    <p class=\"font-bold text-xl\">{{ title }}</p>\n    <p class=\"vp-doc\" v-html=\"description\"></p>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/components/HomeHero.vue",
    "content": "<script setup lang=\"ts\">\nimport { onMounted, onBeforeUnmount } from 'vue'\nimport CTAButton from './CTAButton.vue'\nimport { useData } from 'vitepress'\n\nconst { isDark } = useData()\n\nconst toggleHomeClass = () => document.getElementById('app')?.classList.toggle('home-page')\n\nonMounted(toggleHomeClass)\nonBeforeUnmount(toggleHomeClass)\n</script>\n\n<template>\n  <div class=\"home-hero\">\n    <div class=\"illustration\">\n      <div class=\"feathers-home-hero relative\">\n        <div class=\"relative aspect-15/9 overflow-hidden\">\n          <img\n            id=\"hero-day-bg\"\n            class=\"hero-bg-light w-screen transition-opacity duration-1000 pointer-events-none\"\n            src=\"/img/illustration/hero-day-bg.svg\"\n            alt=\"A sunny daytime background looking over FeathersJS Valley.\"\n            width=\"1504\"\n            height=\"902\"\n          />\n          <img\n            id=\"hero-night-bg\"\n            class=\"hero-bg-dark w-screen absolute inset-0 transition-opacity duration-1000 pointer-events-none\"\n            src=\"/img/illustration/hero-night-bg.svg\"\n            alt=\"A chill nighttime background overlooking FeathersJS Valley\"\n            width=\"1504\"\n            height=\"902\"\n          />\n          <img\n            id=\"hero-day-sun-solo\"\n            class=\"hero-bg-dark w-screen absolute inset-0 transition-all duration-1000 pointer-events-none\"\n            src=\"/img/illustration/hero-day-sun-solo.svg\"\n            alt=\"The FeathersJS Birds enjoying a cool night in the valley of Feathers where a lovely treehouse sits next to the river running between the mountains.\"\n            width=\"1583\"\n            height=\"1580\"\n          />\n          <img\n            id=\"hero-night-moon-solo\"\n            class=\"hero-bg-dark w-screen absolute inset-0 transition-all duration-1000 pointer-events-none\"\n            :class=\"[isDark ? '-top-[69%] opacity-100' : 'top-[300%] opacity-0']\"\n            src=\"/img/illustration/hero-night-moon-solo.svg\"\n            alt=\"The FeathersJS Birds enjoying a cool night in the valley of Feathers where a lovely treehouse sits next to the river running between the mountains.\"\n            width=\"1583\"\n            height=\"1580\"\n          />\n          <img\n            id=\"hero-day-foreground\"\n            class=\"w-screen absolute inset-0 transition-opacity duration-1000 pointer-events-none\"\n            src=\"/img/illustration/hero-day-foreground.svg\"\n            alt=\"The FeathersJS Birds enjoying a cool night in the valley of Feathers where a lovely treehouse sits next to the river running between the mountains.\"\n            width=\"1504\"\n            height=\"902\"\n          />\n          <img\n            class=\"hero-bg-dark w-screen absolute inset-0 transition-opacity duration-1000 pointer-events-none\"\n            src=\"/img/illustration/hero-night-foreground.svg\"\n            alt=\"The FeathersJS Birds enjoying a cool night in the valley of Feathers where a lovely treehouse sits next to the river running between the mountains.\"\n            width=\"1504\"\n            height=\"902\"\n          />\n          <div class=\"absolute inset-0 flex flex-col pt-13.5vw md:pt-14.5vw\">\n            <div\n              class=\"transition-all duration-400 text-center text-lg xl:text-6xl leading-tight font-bold\"\n              sm=\"text-2xl\"\n              md=\"text-3xl\"\n              lg=\"text-5xl\"\n              xl=\"text-6xl\"\n            >\n              The API and Real-time <br />\n              Application Framework\n            </div>\n            <div class=\"mx-auto mt-4 lg:mt-12 hidden md:block\">\n              <CTAButton primary>Get Started</CTAButton>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <div class=\"illustration-roundb text-center text-neutral-content pt-4 font-bold\">\n        <p class=\"text-xs md:text-base lg:text-lg xl:text-2xl\">\n          For TypeScript and JavaScript in Node.js, React Native and the browser\n        </p>\n        <div class=\"scale-80\">\n          <CTAButton href=\"/guides/basics/starting.html\" primary class=\"mt-3 mb-6 md:mb-10\"\n            >Quick Start</CTAButton\n          >\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n\n<style lang=\"postcss\">\n@media (min-width: 768px) {\n  .home-hero {\n    margin-top: -56px;\n    margin-bottom: 40px;\n  }\n}\n@media (min-width: 960px) {\n  .home-hero {\n    margin-top: -144px;\n    margin-bottom: 40px;\n  }\n}\n\n#hero-day-sun-solo,\n.dark #hero-night-moon-solo {\n  @apply -top-[69%] opacity-100;\n}\n.dark #hero-day-sun-solo,\n#hero-night-moon-solo {\n  @apply top-[300%] opacity-0;\n}\n\n.hero-bg-dark {\n  opacity: 0;\n}\n.dark .hero-bg-dark {\n  opacity: 1;\n}\n\n.illustration {\n  /* height: 69vw; */\n  justify-content: center;\n  position: relative;\n  overflow: hidden;\n}\n\n.illustration-roundb::before {\n  background: var(--neutral);\n  border-radius: 50%;\n  bottom: 0;\n  content: '';\n  height: 300px;\n  position: absolute;\n  width: 150%;\n  margin-left: -75%;\n  z-index: -1;\n}\n</style>\n"
  },
  {
    "path": "docs/components/HomeIndustryPartners.vue",
    "content": "<template>\n  <div class=\"home-industry-partners text-center py-16\">\n    <div class=\"max-w-7xl mx-auto\">\n      <h2 class=\"text-xl mb-8 font-bold\">Our Industry Partners</h2>\n\n      <p class=\"text-sm mb-12\" md=\"text-lg px-32\">\n        Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh\n        euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.\n      </p>\n\n      <div class=\"grid grid-cols-3 lg:grid-cols-5 px-12 gap-4\">\n        <div\n          v-for=\"id in 5\"\n          :key=\"id\"\n          class=\"max-h-16 flex flex-row items-center justify-center\"\n        >\n          <img :src=\"`/img/partners/${id}.jpg`\" alt=\"\" class=\"h-full\" />\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/components/HomeQuickStart.vue",
    "content": "<script setup lang=\"ts\">\nimport CTAButton from './CTAButton.vue'\n</script>\n\n<template>\n  <div class=\"bg-neutral text-neutral-content flex flex-col items-center py-24\" xl=\"py-32\">\n    <h2 class=\"text-center pb-8 font-bold\" md=\"text-xl px-16\" lg=\"px-32 text-2xl\">\n      Learn the basics and create your first real-time API in 15 minutes.\n    </h2>\n    <CTAButton href=\"/guides/basics/starting.html\" primary>Quick Start</CTAButton>\n  </div>\n</template>\n"
  },
  {
    "path": "docs/cookbook/authentication/_discord.md",
    "content": "---\noutline: deep\n---\n\n# Discord\n\nDiscord login can be initialized like any other [OAuth provider](../../api/authentication/oauth.md) by adding the app id and secret to `config/default.json`:\n\n```js\n{\n  \"authentication\": {\n    \"oauth\": {\n      \"discord\": {\n        \"key\": \"<App ID>\",\n        \"secret\": \"<App Secret>\",\n        \"scope\": [\"identify email\"]\n      }\n    }\n  }\n}\n```\n\n> __Protip:__ A list of all available Discord scopes can be found [here](https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes)\n\n## Application client and secret\n\nThe client id (App ID) and secret can be found [here](https://discord.com/developers/applications/):\n![Discord App](https://cdn.discordapp.com/attachments/468897350807453706/722369856317423656/unknown.png)\n\nNow add this to your src/authentication.ts:\n\n```ts\nimport {OAuthProfile, OAuthStrategy} from \"@feathersjs/authentication-oauth\";\nimport {AuthenticationRequest} from \"@feathersjs/authentication\";\nimport axios, {AxiosRequestConfig} from 'axios'\nimport {ServiceAddons} from '@feathersjs/feathers';\nimport {AuthenticationService, JWTStrategy} from '@feathersjs/authentication';\nimport {LocalStrategy} from '@feathersjs/authentication-local';\nimport {oauth} from '@feathersjs/authentication-oauth';\nimport {Application} from './declarations';\n\n\nexport default function (app: Application) {\n  const authentication = new AuthenticationService(app);\n\n  authentication.register('jwt', new JWTStrategy());\n  authentication.register('local', new LocalStrategy());\n  authentication.register('discord', new DiscordStrategy());\n\n  app.use('/authentication', authentication);\n  app.configure(oauth());\n}\n\nexport class DiscordStrategy extends OAuthStrategy {\n  async getProfile(authResult: AuthenticationRequest) {\n    // This is the OAuth access token that can be used\n    // for Discord API requests as the Bearer token\n    const accessToken = authResult.access_token;\n    const userOptions: AxiosRequestConfig = {\n      method: 'GET',\n      headers: {'Authorization': `Bearer ${accessToken}`},\n      url: `https://discord.com/api/users/@me`,\n    };\n    const {data} = await axios(userOptions);\n    return data;\n  }\n\n  async getEntityData(profile: OAuthProfile) {\n    // `profile` is the data returned by getProfile\n    const baseData = await super.getEntityData(profile);\n\n    if (profile.avatar == null) {\n      profile.avatar = 'https://cdn.discordapp.com/embed/avatars/0.png'\n    } else {\n      const isGif = profile.avatar.startsWith('a_');\n      profile.avatar = `https://cdn.discordapp.com/avatars/${profile['id']}/${profile['avatar']}.${isGif ? 'gif' : 'png'}`\n    }\n\n    return {\n      ...baseData,\n      username: profile.username,\n      email: profile.email,\n      avatar: profile.avatar,\n    };\n  }\n}\n```\n\nIf you don't need the avatar then you can simply remove the lines of code.\nIf the user doesn't have an avatar then we will set it to Discord's default avatar.\n\n\n"
  },
  {
    "path": "docs/cookbook/authentication/anonymous.md",
    "content": "---\noutline: deep\n---\n\n# Anonymous authentication\n\nAnonymous authentication can be allowed by creating a [custom strategy](../../api/authentication/strategy.md) that returns the `params` that you would like to use to identify an authenticated user.\n\n\n\n<LanguageBlock global-id=\"ts\">\n\n```ts\nimport { Params } from '@feathersjs/feathers';\nimport { AuthenticationBaseStrategy, AuthenticationResult, AuthenticationService } from '@feathersjs/authentication';\n\nclass AnonymousStrategy extends AuthenticationBaseStrategy {\n  async authenticate(authentication: AuthenticationResult, params: Params) {\n    return {\n      anonymous: true\n    }\n  }\n}\n\nexport default function(app: Application) {\n  const authentication = new AuthenticationService(app);\n  // ... authentication service setup\n  authentication.register('anonymous', new AnonymousStrategy());\n}\n```\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\nIn `src/authentication.js`:\n\n```js\nconst { AuthenticationBaseStrategy, AuthenticationService } = require('@feathersjs/authentication');\n\nclass AnonymousStrategy extends AuthenticationBaseStrategy {\n  async authenticate(authentication, params) {\n    return {\n      anonymous: true\n    }\n  }\n}\n\nmodule.exports = app => {\n  const authentication = new AuthenticationService(app);\n  // ... authentication service setup\n  authentication.register('anonymous', new AnonymousStrategy());\n}\n```\n\n</LanguageBlock>\n\n\n\n\nNext, we create a hook called `allow-anonymous` that sets `params.authentication` if it does not exist and if `params.provider` exists (which means it is an external call) to use that `anonymous` strategy:\n\n\n\n<LanguageBlock global-id=\"ts\">\n\n```ts\nimport { Hook, HookContext } from '@feathersjs/feathers';\n\nexport default (): Hook => {\n  return async (context: HookContext, next?: NextFunction) => {\n    const { params } = context;\n\n    if (params.provider && !params.authentication) {\n      context.params = {\n        ...params,\n        authentication: {\n          strategy: 'anonymous'\n        }\n      }\n    }\n\n    if (next) {\n      await next();\n    }\n\n    return context;\n  }\n}\n```\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\n```js\n/* eslint-disable require-atomic-updates */\nmodule.exports = function (options = {}) { // eslint-disable-line no-unused-vars\n  return async context => {\n    const { params } = context;\n\n    if(params.provider && !params.authentication) {\n      context.params = {\n        ...params,\n        authentication: {\n          strategy: 'anonymous'\n        }\n      }\n    }\n\n    return context;\n  };\n};\n```\n\n</LanguageBlock>\n\n\n\nThis hook should be added __before__ the [authenticate hook](../../api/authentication/hook.md) wherever anonymous authentication should be allowed:\n\n```js\nall: [ allowAnonymous(), authenticate('jwt', 'anonymous') ],\n```\n\nIf an anonymous user now accesses the service externally, the service call will succeed and have `params.anonymous` set to `true`.\n"
  },
  {
    "path": "docs/cookbook/authentication/apiKey.md",
    "content": "# API Key Authentication\n\nWe will start by providing the required configuration for this strategy. You should change all of these values as per your requirement.\n\n```js\n{\n  \"authentication\": {\n    ...otherConfig,\n    \"authStrategies\": [ ...otherStrategies, \"apiKey\" ],\n    \"apiKey\": {\n      \"allowedKeys\": [ \"API_KEY_1\", \"API_KEY_2\" ],\n      \"header\": \"x-access-token\"\n    }\n  }\n}\n```\n\nNote: if all you want is api key authentication, it is still necessary to register a secret, service and entity. Since no other authentication method is used, entity can be `null`.\n\nA fully working example with just API key authentication:\n```json\n{\n  \"host\": \"localhost\",\n  \"port\": 3030,\n  \"public\": \"../public/\",\n  \"paginate\": {\n    \"default\": 10,\n    \"max\": 50\n  },\n  \"authentication\": {\n    \"secret\": \"some-secret\",\n    \"service\": \"users\",\n    \"entity\": null,\n    \"authStrategies\": [\"apiKey\"],\n    \"apiKey\": {\n      \"allowedKeys\": [ \"API_KEY_1\", \"API_KEY_2\" ],\n      \"header\": \"x-access-token\"\n    }\n  }\n}\n```\n\nNext we will be creating a [custom strategy](../../api/authentication/strategy.md) that returns the `params` that you would like to use to identify an authenticated user/request.\n\n\n\n<LanguageBlock global-id=\"ts\">\n\n```ts\nimport { AuthenticationBaseStrategy, AuthenticationResult, AuthenticationService } from '@feathersjs/authentication';\nimport { NotAuthenticated } from '@feathersjs/errors';\nimport { ServiceAddons } from '@feathersjs/feathers';\nimport { Application } from './declarations';\n\n\ndeclare module './declarations' {\n  interface ServiceTypes {\n    'authentication': AuthenticationService & ServiceAddons<any>;\n  }\n}\n\nclass ApiKeyStrategy extends AuthenticationBaseStrategy {\n  app: Application;\n\n  constructor(app: Application) {\n    super();\n    this.app = app;\n  }\n\n  async authenticate(authentication: AuthenticationResult) {\n    const { token } = authentication;\n\n    const config = this.app.get('authentication').apiKey;\n\n    const match = config.allowedKeys.includes(token);\n    if (!match) throw new NotAuthenticated('Incorrect API Key');\n\n    return {\n      apiKey: true\n    }\n  }\n}\n\nexport default function (app: Application) {\n  const authentication = new AuthenticationService(app);\n\n  // This can have multiple .register calls if multiple strategies have been added\n  authentication.register('apiKey', new ApiKeyStrategy(app));\n\n  app.use('/authentication', authentication);\n}\n```\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\nIn `src/authentication.js`:\n\n```js\nconst { AuthenticationBaseStrategy, AuthenticationService } = require('@feathersjs/authentication');\nconst { NotAuthenticated } = require('@feathersjs/errors');\n\nclass ApiKeyStrategy extends AuthenticationBaseStrategy {\n  async authenticate(authentication) {\n    const { token } = authentication;\n\n    const config = this.authentication.configuration[this.name];\n\n    const match = config.allowedKeys.includes(token);\n    if (!match) throw new NotAuthenticated('Incorrect API Key');\n\n    return {\n      apiKey: true\n    }\n  }\n}\n\nmodule.exports = app => {\n  const authentication = new AuthenticationService(app);\n  // ... authentication service setup\n  authentication.register('apiKey', new ApiKeyStrategy());\n}\n```\n\n</LanguageBlock>\n\n\n\nNext, we create a hook called `allow-apiKey` that sets `params.authentication` if it does not exist and if `params.provider` exists (which means it is an external call) to use that `apiKey` strategy. We will also provide the capability for the apiKey to be read from the request header: (you could also read the token as a query parameter but you will have to filter it out before it's passed to Feathers calls like `get` and `find`.\n\n\n\n<LanguageBlock global-id=\"ts\">\n\n```ts\nimport { HookContext, NextFunction } from '@feathersjs/feathers';\n\nexport default () => async (context: HookContext, next: NextFunction) => {\n  const { params, app } = context;\n\n  const headerField = app.get('authentication').apiKey.header;\n  const token = params.headers ? params.headers[headerField] : null;\n\n  if (token && params.provider && !params.authentication) {\n    context.params = {\n      ...params,\n      authentication: {\n        strategy: 'apiKey',\n        token\n      }\n    };\n  }\n\n  return next();\n}\n```\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\n```js\n/* eslint-disable require-atomic-updates */\nmodule.exports = function (options = {}) { // eslint-disable-line no-unused-vars\n  return async context => {\n    const { params, app } = context;\n\n    const headerField = app.get('authentication').apiKey.header;\n    const token = params.headers[headerField];\n\n    if (token && params.provider && !params.authentication) {\n      context.params = {\n        ...params,\n        authentication: {\n          strategy: 'apiKey',\n          token\n        }\n      };\n    }\n\n    return context;\n  };\n};\n```\n\n</LanguageBlock>\n\n\n\nThis hook should be added __before__ the [authenticate hook](../../api/authentication/hook.md) wherever API Key authentication should be allowed:\n\n```js\nimport { authenticate } from '@feathersjs/authentication/lib/hooks';\nimport allowApiKey from './hooks/allow-api-key';\n\nall: [ allowApiKey(), authenticate('jwt', 'apiKey') ],\n```\n\nIf a user now accesses the service externally with the correct apiKey, the service call will succeed and have `params.apiKey` set to `true`.\n"
  },
  {
    "path": "docs/cookbook/authentication/auth0.md",
    "content": "---\noutline: deep\n---\n\n# Auth0\n\nTo enable OAuth logins with [Auth0](http://auth0.com), we need the following settings after creating an application:\n\n![Auth0 application](../assets/auth0-app.png)\n\nThis should be added in your configuration (usually `config/default.json`) as follows:\n\n```json\n\"authentication\": {\n  \"oauth\": {\n    \"redirect\": \"/\",\n    \"auth0\": {\n      \"key\": \"<Client ID>\",\n      \"secret\": \"<Client Secret>\",\n      \"subdomain\": \"<Domain without auth0.com\",\n      \"scope\": [\"openid\", \"profile\", \"email\"]\n    }\n  }\n}\n```\n\n> __Important:__ `subdomain` should be the \"Domain\" from the application settings __without__ the `auth0.com` part. So, in the screenshot above, the subdomain for `dev-6gqkmpt6.auth0.com` would be `dev-6gqkmpt6`. If the subdomain includes a region, it needs to be included as well so the subdomain for `dev-6gqkmpt6.us.auth0.com` would be `dev-6gqkmpt6.us`\n\n## Strategy\n\nTo use Auth0 in the chat application from the [Feathers guide](../../guides/) we have to do the same modifications as already shown [for the GitHub login in the authentication guide](../../guides/basics/authentication.md).\n\n\n\n<LanguageBlock global-id=\"ts\">\n\nIn `src/authentication.ts` like this:\n\n```ts\nimport { ServiceAddons, Params } from '@feathersjs/feathers';\nimport { AuthenticationService, JWTStrategy } from '@feathersjs/authentication';\nimport { LocalStrategy } from '@feathersjs/authentication-local';\nimport { oauth, OAuthStrategy, OAuthProfile } from '@feathersjs/authentication-oauth';\n\nimport { Application } from './declarations';\n\ndeclare module './declarations' {\n  interface ServiceTypes {\n    'authentication': AuthenticationService & ServiceAddons<any>;\n  }\n}\n\nclass Auth0Strategy extends OAuthStrategy {\n  async getEntityData(profile: OAuthProfile, existing: any, params: Params) {\n    const baseData = await super.getEntityData(profile, existing, params);\n\n    return {\n      ...baseData,\n      email: profile.email\n    };\n  }\n}\n\nexport default function(app: Application) {\n  const authentication = new AuthenticationService(app);\n\n  authentication.register('jwt', new JWTStrategy());\n  authentication.register('local', new LocalStrategy());\n  authentication.register('auth0', new Auth0Strategy());\n\n  app.use('/authentication', authentication);\n  app.configure(oauth());\n}\n```\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\nIn `src/authentication.js` like this:\n\n```js\nconst { AuthenticationService, JWTStrategy } = require('@feathersjs/authentication');\nconst { LocalStrategy } = require('@feathersjs/authentication-local');\nconst { expressOauth, OAuthStrategy } = require('@feathersjs/authentication-oauth');\n\nclass Auth0Strategy extends OAuthStrategy {\n  async getEntityData(profile) {\n    const baseData = await super.getEntityData(profile);\n\n    return {\n      ...baseData,\n      email: profile.email\n    };\n  }\n}\n\nmodule.exports = app => {\n  const authentication = new AuthenticationService(app);\n\n  authentication.register('jwt', new JWTStrategy());\n  authentication.register('local', new LocalStrategy());\n  authentication.register('auth0', new Auth0Strategy());\n\n  app.use('/authentication', authentication);\n  app.configure(expressOauth());\n};\n```\n\n</LanguageBlock>\n\n\n\nAdditionally, `auth0Id` needs to be included in the data in the users service class.\n"
  },
  {
    "path": "docs/cookbook/authentication/facebook.md",
    "content": "---\noutline: deep\n---\n\n# Facebook\n\nFacebook login can be initialized like any other [OAuth provider](../../api/authentication/oauth.md) by adding the app id and secret to `config/default.json`:\n\n```js\n{\n  \"authentication\": {\n    \"oauth\": {\n      \"facebook\": {\n        \"key\": \"<App ID>\",\n        \"secret\": \"<App Secret>\"\n      }\n    }\n  }\n}\n```\n\nRequesting the email property requires adding additional `scope` to the oauth configuration:\n```js\n{\n  \"authentication\": {\n    \"oauth\": {\n      \"facebook\": {\n        \"key\": \"<App ID>\",\n        \"secret\": \"<App Secret>\",\n        \"scope\": [\"email, public_profile\"]\n      }\n    }\n  }\n}\n```\n\n## Application client and secret\n\nThe client id (App ID) and secret can be found in the Settings of the [Facebook app](https://developers.facebook.com/apps):\n\n![Facebook app settings](../assets/facebook-app.png)\n\n## Getting profile data\n\nThe standard OAuth strategy only returns the default profile fields (`id` and `name`). To get other fields, like the email or profile picture, the [getProfile](../../api/authentication/oauth.md#getprofile-data-params) method of the [OAuth strategy needs to be customized](../../api/authentication/oauth.md#customization) to call the Graph API profile endpoint `https://graph.facebook.com/me` with an HTTP request library like [Axios](https://developers.facebook.com/tools/explorer/) requesting the additional fields.\n\n> __Pro tip:__ Facebook API requests can be tested via the [Graph API explorer](https://developers.facebook.com/tools/explorer/).\n\nThe following example allows to log in with Facebook in the [chat application from the guide](../../guides/index.md):\n\n\n\n<LanguageBlock global-id=\"ts\">\n\n```ts\nimport { Params } from '@feathersjs/feathers';\nimport { AuthenticationService, JWTStrategy, AuthenticationRequest } from '@feathersjs/authentication';\nimport { LocalStrategy } from '@feathersjs/authentication-local';\nimport { expressOauth, OAuthStrategy, OAuthProfile } from '@feathersjs/authentication-oauth';\nimport axios from 'axios';\nimport { Application } from './declarations';\n\ndeclare module './declarations' {\n  interface ServiceTypes {\n    'authentication': AuthenticationService & ServiceAddons<any>;\n  }\n}\n\nclass FacebookStrategy extends OAuthStrategy {\n  async getProfile (authResult: AuthenticationRequest, _params: Params) {\n    // This is the OAuth access token that can be used\n    // for Facebook API requests as the Bearer token\n    const accessToken = authResult.access_token;\n\n    const { data } = await axios.get('https://graph.facebook.com/me', {\n      headers: {\n        authorization: `Bearer ${accessToken}`\n      },\n      params: {\n        // There are\n        fields: 'id,name,email'\n      }\n    });\n\n    return data;\n  }\n\n  async getEntityData(profile: OAuthProfile, existing: any, params: Params) {\n    // `profile` is the data returned by getProfile\n    const baseData = await super.getEntityData(profile, existing, params);\n\n    return {\n      ...baseData,\n      email: profile.email\n    };\n  }\n}\n\nexport default function(app: Application) {\n  const authentication = new AuthenticationService(app);\n\n  authentication.register('jwt', new JWTStrategy());\n  authentication.register('local', new LocalStrategy());\n  authentication.register('facebook', new FacebookStrategy());\n\n  app.use('/authentication', authentication);\n  app.configure(expressOauth());\n}\n```\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\nIn `src/authentication.js`:\n\n```js\nconst axios = require('axios');\nconst { AuthenticationService, JWTStrategy } = require('@feathersjs/authentication');\nconst { LocalStrategy } = require('@feathersjs/authentication-local');\nconst { expressOauth, OAuthStrategy } = require('@feathersjs/authentication-oauth');\n\nclass FacebookStrategy extends OAuthStrategy {\n  async getProfile (authResult) {\n    // This is the OAuth access token that can be used\n    // for Facebook API requests as the Bearer token\n    const accessToken = authResult.access_token;\n\n    const { data } = await axios.get('https://graph.facebook.com/me', {\n      headers: {\n        authorization: `Bearer ${accessToken}`\n      },\n      params: {\n        // There are\n        fields: 'id,name,email,picture'\n      }\n    });\n\n    return data;\n  }\n\n  async getEntityData(profile) {\n    // `profile` is the data returned by getProfile\n    const baseData = await super.getEntityData(profile);\n\n    return {\n      ...baseData,\n      name:  profile.name,\n      email: profile.email\n    };\n  }\n}\n\nmodule.exports = app => {\n  const authentication = new AuthenticationService(app);\n\n  authentication.register('jwt', new JWTStrategy());\n  authentication.register('local', new LocalStrategy());\n  authentication.register('facebook', new FacebookStrategy());\n\n  app.use('/authentication', authentication);\n  app.configure(expressOauth());\n};\n```\n\n</LanguageBlock>\n\n\n\n> __Pro tip:__ [See all available Facebook user options here](https://developers.facebook.com/docs/graph-api/reference/user/).\n"
  },
  {
    "path": "docs/cookbook/authentication/firebase.md",
    "content": "---\noutline: deep\n---\n\n# Firebase\n\n[Firebase](https://firebase.google.com/docs/auth) requires a custom [OAuth Authentication Strategy](../../api/authentication/oauth.html#oauthstrategy). This is because one is not provided to us, by the default [Grant](https://github.com/simov/grant) configuration Feathers uses for [OAuth](https://docs.feathersjs.com/api/authentication/oauth.html#oauth).\n\nSince Firebase does not provide a UI for us to redirect to, we use flow #2 outlined in [OAuth Flow](../../api/authentication/oauth.html#flow).\n\n\n## Authentation Setup\n\nUpdate `config/default.json`:\n\n```json\n{\n  \"authentication\": {\n    \"oauth\": {}\n  },\n  \"firebase\": {\n    \"type\": \"THIS SHOULD BE YOUR SERVICE ACCOUNT\",\n    \"project_id\": \"GENERATED UNDER FIREBASE CONSOLE\",\n    \"...\": \"...\"\n  }\n}\n\n```\n> Note: Since Firebase can be used for more than just authentication, we'll store our service account in the root of our config. Otherwise, if preferred, you can store under `authentication.oauth`.\n\n## Authentication Strategy\n\nCreate a file under `src/firebase.js`:\n\n```js\nconst firebase = require('firebase-admin');\nconst { OAuthStrategy } = require('@feathersjs/authentication-oauth');\nconst { NotAuthenticated } = require('@feathersjs/errors');\n\nconst logger = require('./logger');\n\nfunction initialize(app){\n  const firebaseConfig = app.get('firebase');\n\n  // Initialize app\n  try {\n    firebase.initializeApp({\n      credential: firebase.credential.cert(firebaseConfig)\n    });\n  } catch (e) {\n    console.log('erorr initializing firebase', e);\n  }\n}\n\nclass FirebaseStrategy extends OAuthStrategy {\n\n  async authenticate(authentication, params){\n    logger.debug('firebase:strategy:authenticate');\n    return super.authenticate(authentication, params);\n  }\n\n  async getProfile(data, _params){\n    const firebase = require('firebase-admin');\n    let user;\n\n    try {\n      user = await firebase.auth().verifyIdToken(data.access_token);\n    } catch(e){\n      logger.error(e);\n      throw new NotAuthenticated();\n    }\n\n    logger.debug(`firebase:strategy:getProfile:successful ${user.user_id}`);\n\n    return {\n      email: user.email,\n      id: user.user_id\n    };\n  }\n\n  async getEntityData(profile) {\n    const baseData = await super.getEntityData(profile);\n\n    return {\n      ...baseData,\n      email: profile.email\n    };\n  }\n}\n\nmodule.exports = { initialize, FirebaseStrategy };\n```\n\nNow we can edit `src/authentication.js`\n\n```js\nconst { AuthenticationService, JWTStrategy } = require('@feathersjs/authentication');\nconst { expressOauth } = require('@feathersjs/authentication-oauth');\n\nconst { FirebaseStrategy } = require('./firebase');\n\nmodule.exports = app => {\n  const authentication = new AuthenticationService(app);\n\n  authentication.register('firebase', new FirebaseStrategy());\n\n  app.use('/authentication', authentication);\n  app.configure(expressOauth());\n};\n```\n\n## Building frontend\n\nTo save time, you can leverage the pre-built UI provided by [Firebase UI](https://firebase.google.com/docs/auth/web/firebaseui).\n\n### Create auth page\n\nFirst, create a `public/firebase_auth.html` file that initializes everything we'll need for our different auth components.\n\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Firebase Authentication Example</title>\n  <!-- The core Firebase JS SDK is always required and must be listed first -->\n  <script src=\"https://www.gstatic.com/firebasejs/7.21.0/firebase-app.js\"></script>\n\n  <!-- TODO: Add SDKs for Firebase products that you want to use\n       https://firebase.google.com/docs/web/setup#available-libraries -->\n  <script src=\"https://www.gstatic.com/firebasejs/7.21.0/firebase-auth.js\"></script>\n\n  <!-- Firebase UI -->\n  <script src=\"https://www.gstatic.com/firebasejs/ui/4.6.1/firebase-ui-auth.js\"></script>\n  <link type=\"text/css\" rel=\"stylesheet\" href=\"https://www.gstatic.com/firebasejs/ui/4.6.1/firebase-ui-auth.css\" />\n\n</head>\n<body>\n  <!-- The surrounding HTML is left untouched by FirebaseUI.\n      Your app may use that space for branding, controls and other customizations.-->\n  <h1>Welcome to My Awesome App</h1>\n\n  <!-- Optionally show a preparing state, until the guest or member app is ready. Usually after authentication is determined -->\n  <div id=\"app-preparing\"></div>\n\n  <!-- App for guests to auth, etc. -->\n  <div id=\"app-guest\" style=\"display: none;\">\n    <div id=\"firebaseui-auth-container\"></div>\n    <div id=\"loader\">Loading...</div>\n  </div>\n\n  <!-- App for members only -->\n  <div id=\"app-member\" style=\"display: none;\"></div>\n\n  <!-- Custom -->\n  <script src=\"//unpkg.com/@feathersjs/client@^4.3.0/dist/feathers.js\"></script>\n  <script src=\"/socket.io/socket.io.js\"></script>\n  <script src=\"/client.js\"></script>\n</body>\n</html>\n```\n\n### Initialize client w/Firebase auth\nNow, let's make a `public/client.js` file where all of our JavaScript will live.\n\n> Be sure to update `firebaseConfig` with the one provided from your [Firebase Console](https://console.firebase.google.com/). Additionally, checkout [Firebase UI](https://firebase.google.com/docs/auth/web/firebaseui) docs for more information on customizing `ui.start`. This includes theming options, all providers supported by Firebase & more.\n\n\n```js\nlet client, ui;\n\ninit();\n\nfunction init(){\n  initializeFeathers();\n  initializeAuth();\n  initializeFirebase();\n}\n\nfunction initializeFeathers(){\n  // Establish a Socket.io connection\n  const socket = io();\n  // Initialize our Feathers client application through Socket.io\n  // with hooks and authentication.\n  client = feathers();\n\n  client.configure(feathers.socketio(socket));\n  // Use localStorage to store our login token\n  client.configure(feathers.authentication());\n}\n\n// Either re-authenticate existing session, or start Firebase UI\nasync function initializeAuth(){\n  try {\n    await client.reAuthenticate();\n    showMemberApp();\n  } catch(e){\n    // Error re-authenticating, so let's start Firebase UI\n    showGuestApp();\n  }\n\n  // No longer need to prepare anything\n  document.getElementById('app-preparing').style.display = 'none';\n}\n\nfunction initializeFirebase(){\n  // Your web app's Firebase configuration\n  // For Firebase JS SDK v7.20.0 and later, measurementId is optional\n  var firebaseConfig = {\n    // Copy this from your Firebase Console\n    // Under Project Settings -> Web App\n  };\n  // Initialize Firebase\n  firebase.initializeApp(firebaseConfig);\n\n  // Initialize the FirebaseUI Widget using Firebase.\n  ui = new firebaseui.auth.AuthUI(firebase.auth());\n}\n\n\nasync function showMemberApp(){\n  // Get user information\n  const { user } = await client.get('authentication');\n\n  // Hide Guest App\n  document.getElementById('app-guest').style.display = 'none';\n\n  // Show member app\n  document.getElementById('app-member').style.display = 'block';\n  document.getElementById('app-member').innerHTML = `Logged in as, ${user.email}. <a href=\"#\" id=\"logout\">Logout</a>`;\n\n}\n\nfunction showGuestApp(){\n  // Hide & clear member app\n  document.getElementById('app-member').style.display = 'none';\n  document.getElementById('app-member').innerHTML = '';\n\n  // Show Guest app\n  document.getElementById('app-guest').style.display = 'block';\n  startFirebaseUI();\n}\n\nfunction startFirebaseUI(){\n  ui.start('#firebaseui-auth-container', {\n    callbacks: {\n      signInSuccessWithAuthResult: function(authResult, redirectUrl) {\n        // User successfully signed in.\n        // Return type determines whether we continue the redirect automatically\n        // or whether we leave that to developer to handle.\n        firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(async function(idToken) {\n          await client.authenticate({\n            strategy: 'firebase',\n            access_token: idToken,\n          });\n          showMemberApp();\n        });\n\n        return false;\n      },\n      uiShown: function() {\n        // The widget is rendered.\n        // Hide the loader.\n        document.getElementById('loader').style.display = 'none';\n      }\n    },\n    // Will use popup for IDP Providers sign-in flow instead of the default, redirect.\n    signInFlow: 'popup',\n    credentialHelper: firebaseui.auth.CredentialHelper.NONE, // disable accountchooter.com helper\n    signInOptions: [\n      firebase.auth.EmailAuthProvider.PROVIDER_ID,\n      firebase.auth.FacebookAuthProvider.PROVIDER_ID,\n      firebase.auth.TwitterAuthProvider.PROVIDER_ID,\n    ],\n    // Other config options...\n  });\n}\n\nconst addEventListener = (selector, event, handler) => {\n  document.addEventListener(event, async ev => {\n    if (ev.target.closest(selector)) {\n      handler(ev);\n    }\n  });\n};\n\n// \"Logout\" button click handler\naddEventListener('#logout', 'click', async () => {\n  await client.logout();\n\n  showGuestApp();\n});\n```\n\nNow you should be able to visit your Firebase auth at the\n\n```\nhttp://localhost:3030/firebase_auth.html\n```\n\npage locally and authenticate w/any Firebase Providers you've set up in your Firebase Project 🔥\n"
  },
  {
    "path": "docs/cookbook/authentication/google.md",
    "content": "---\noutline: deep\n---\n\n# Google\n\nTo enable Google login, add the app id, app secret and scope property to `config/default.json`:\n\n```js\n{\n  \"authentication\": {\n    \"oauth\": {\n      \"google\": {\n        \"key\": \"<App ID>\",\n        \"secret\": \"<App Secret>\",\n        \"scope\": [\"openid\"]\n      }\n    }\n  }\n}\n```\n\nAccording to the [documentation of Google](https://developers.google.com/identity/protocols/OpenIDConnect#scope-param):\n\"The scope value must begin with the string openid and then include profile or email or both.\".\n\n\nTo also request the email address, add the string \"email\" to the array of the 'scope' property:\n```js\n{\n  \"authentication\": {\n    \"oauth\": {\n      \"google\": {\n        \"key\": \"<App ID>\",\n        \"secret\": \"<App Secret>\",\n        \"scope\": [\"openid\", \"email\"],\n        \"nonce\": true\n      }\n    }\n  }\n}\n```\n\nThe property 'nonce', according to the documentation: \"A random value generated by your app that enables replay protection.\".\n\n## Application client and secret\n\nThe client id (App ID) and secret can be acquired by creating a [OAuth client ID](https://console.developers.google.com/apis/credentials):\n1. Click on 'OAuth client ID'\n![Creating OAuth client ID - step 1](https://bartduisters.com/img/feathers/oauth-client-id-1.png)\n2. Select 'web application', fill in the information and click 'Create'\n![Creating OAuth client ID - step 2](https://bartduisters.com/img/feathers/oauth-client-id-2.png)\n\n**Important**: Fill in the callback url, in a default Feathers setup it will be /oauth/google/callback.\n\n3. Replace `<App ID>` and `<App Secret>` with the id and secret of the created OAuth client ID application\n\n```js\n{\n  \"authentication\": {\n    \"oauth\": {\n      \"google\": {\n        \"key\": \"<client-id>.apps.googleusercontent.com\",\n        \"secret\": \"<client-secret>\",\n        \"scope\": [\"openid\", \"email\"],\n        \"nonce\": true\n      }\n    }\n  }\n}\n```\n\nNote: Use the generated credentials of the OAuth client ID.\n\nNote: `<client-id>` will be replaced by a string similar to **481298021138-hv27glb811ocr7pdon5lsg8hh5a6pgjv**.apps.googleusercontent.com.\n\nNote: `<client-secret>` will be replaced by a string similar to **XkWl0witdP4ogeNIgyOi-CeS**.\n\n## Using the data returned from the Google App through a custom OAuth Strategy\n\nIn `src/authentication.js`:\n\n```js\nconst axios = require('axios');\nconst { OAuthStrategy } = require('@feathersjs/authentication-oauth');\n\nclass GoogleStrategy extends OAuthStrategy {\n  async getEntityData(profile) {\n\n    // this will set 'googleId'\n    const baseData = await super.getEntityData(profile);\n\n    // this will grab the picture and email address of the Google profile\n    return {\n      ...baseData,\n      profilePicture: profile.picture,\n      email: profile.email\n    };\n  }\n}\n\nmodule.exports = app => {\n  const authentication = new AuthenticationService(app);\n\n  authentication.register('jwt', new JWTStrategy());\n  authentication.register('local', new LocalStrategy());\n  authentication.register('google', new GoogleStrategy());\n\n  app.use('/authentication', authentication);\n  app.configure(expressOauth());\n};\n```\n**Important**: googleId, profilePicture and email are properties that should exist on the database model!\n\n\n"
  },
  {
    "path": "docs/cookbook/authentication/revoke-jwt.md",
    "content": "---\noutline: deep\n---\n\n# Revoking JWTs\n\nBy default a valid JWT can be used for as long as it is valid. To do a normal logout the client just \"forgets\" their JWT (usually by removing it from localStorage).\n\nTo add the ability to revoke an access token so that it can be no longer used even if it is still valid [the authentication service](../../api/authentication/service.md) can be customized as follows.\n\n## Basic example\n\nThe following example shows the basic flow of how a JWT can be revoked by storing it in a plain object. In a normal application you would use something like the [Redis storage shown below](#using-redis).\n\n```js\nconst { AuthenticationService } = require('@feathersjs/authentication');\nconst { NotAuthenticated } = require('@feathersjs/errors');\n\nconst revokedTokens = {};\n\nclass RevokableAuthService extends AuthenticationService {\n  async revokeAccessToken (accessToken) {\n    // First make sure the access token is valid\n    const verified = await this.verifyAccessToken(accessToken);\n\n    revokedTokens[accessToken] = true;\n\n    return verified;\n  }\n\n  async verifyAccessToken(accessToken) {\n    // First check if the token has been revoked\n    if (revokedTokens[accessToken]) {\n      throw new NotAuthenticated('Token revoked');\n    }\n\n    return super.verifyAccessToken(accessToken);\n  }\n\n  async remove (id, params) {\n    const authResult = await super.remove(id, params);\n    const { accessToken } = authResult;\n\n    if (accessToken) {\n      // If there is an access token, revoke it\n      await this.revokeAccessToken(accessToken);\n    }\n\n    return authResult;\n  }\n}\n\napp.use('/authentication', new RevokableAuthService(app));\n```\n\n## Using Redis\n\n[Redis](https://redis.io/) is a great storage mechanism for revoked JWTs because it allows to remove keys after a certain time. A revoked JWT does not have to be stored forever and can be removed from storage after it has expired since it will no longer be valid anyway. The flow is the same as shown above but using the NodeJS Redis adapter instead:\n\n```\nnpm install redis\n```\n\n```js\nconst redis = require('redis');\n\nconst { AuthenticationService } = require('@feathersjs/authentication');\nconst { NotAuthenticated } = require('@feathersjs/errors');\n\nclass RedisAuthService extends AuthenticationService {\n  constructor (app, configKey) {\n    super(app, configKey);\n\n    const client = redis.createClient();\n\n    this.redis = {\n      client,\n      get: client.get.bind(client),\n      set: client.set.bind(client),\n      exists: client.exists.bind(client),\n      expireat: client.exists.bind(client)\n    }\n\n    (async () => {\n      await this.redis.client.connect();\n    })()\n  }\n\n  async revokeAccessToken (accessToken) {\n    // First make sure the access token is valid\n    const verified = await this.verifyAccessToken(accessToken);\n    // Calculate the remaining valid time for the token (in seconds)\n    const expiry = verified.exp - Math.floor(Date.now() / 1000);\n\n    // Add the revoked token to Redis and set expiration\n    await this.redis.set(accessToken, 1, { EX: expiry });\n\n    return verified;\n  }\n\n  async verifyAccessToken(accessToken) {\n    if (await this.redis.exists(accessToken)) {\n      throw new NotAuthenticated('Token revoked');\n    }\n\n    return super.verifyAccessToken(accessToken);\n  }\n\n  async remove (id, params) {\n    const authResult = await super.remove(id, params);\n    const { accessToken } = authResult;\n\n    if (accessToken) {\n      // If there is an access token, revoke it\n      await this.revokeAccessToken(accessToken);\n    }\n\n    return authResult;\n  }\n}\n\napp.use('/authentication', new RedisAuthService(app));\n```\n"
  },
  {
    "path": "docs/cookbook/authentication/stateless.md",
    "content": "---\noutline: deep\n---\n\n# Stateless JWT\n\nBy default, an authentication token is associated to an entity (usually a user). It is also possible to issue tokens that are stateless and not tied to an entity lookup. This can be useful when all the information necessary can be contained in the token payload. The drawback is that the token information can not be changed and will always be valid until the token expires so it is e.g. not possible to disable a user or change their permissions before the token expires.\n\n## Configuration\n\nStateless tokens can be issued by setting the `entity` option in the [JWT strategy authentication configuration](../../api/authentication/jwt.md#configuration) to `null` (in which case `service` option also won't be used):\n\n```json\n{\n  \"authentication\": {\n    \"secret\": \"CHANGE_ME\",\n    \"entity\": null,\n    \"authStrategies\": [ \"jwt\", \"local\" ],\n    \"jwtOptions\": {\n      \"header\": { \"typ\": \"access\" },\n      \"audience\": \"https://yourdomain.com\",\n      \"issuer\": \"feathers\",\n      \"algorithm\": \"HS256\",\n      \"expiresIn\": \"1d\"\n    }\n  }\n}\n```\n\n> __Note:__ When still using other built-in strategies (like the [local strategy](../../api/authentication/local.md)) with an entity, the option can be set for each strategy (e.g. `{ \"authentication\": { \"local\": { \"entity\": \"user\" } } }`).\n\n## Customizing the payload\n\nIn order for the token to contain information, the `getPayload` method needs to be customize by [extending the authentication service](../../api/authentication/service.md#customization):\n\n```js\nconst { AuthenticationService } = require('@feathersjs/authentication');\n\nclass MyAuthService extends AuthenticationService {\n  async getPayload(authResult, params) {\n    // Call original `getPayload` first\n    const payload = await super.getPayload(authResult, params);\n    const { user } = authResult;\n\n    if (user && user.permissions) {\n      payload.permissions = user.permissions;\n    }\n\n    return payload;\n  }\n}\n\napp.use('/authentication', new MyAuthService(app));\n```\n"
  },
  {
    "path": "docs/cookbook/deploy/docker.md",
    "content": "---\noutline: deep\n---\n\n# Dockerize a Feathers application\n\nA Feathers application can be [dockerized like any other Node.js application](https://nodejs.org/en/docs/guides/nodejs-docker-webapp/).\n\n## Create an app\n\n```sh\nmkdir feathers-app\ncd feathers-app/\nfeathers generate app\n```\n\n### Dockerfile\n\nAdd the following `Dockerfile` to the project directory:\n\n```\nFROM node:lts-alpine\n\nWORKDIR /usr/src/app\n\nCOPY package*.json ./\n\nRUN npm install\n\nCOPY . .\n\nEXPOSE 3030\n\nCMD [\"npm\", \"run\", \"start\"]\n```\n\n## Build the image\n\n```sh\ndocker build -t my-feathers-image .\n```\n\n## Start the container\n\n```sh\ndocker run -d -p 3030:3030 --name my-feathers-container my-feathers-image\n```\n"
  },
  {
    "path": "docs/cookbook/express/file-uploading.md",
    "content": "---\noutline: deep\n---\n\n# File uploads in FeathersJS\n\nOver the last months we at [ciancoders.com](https://ciancoders.com/) have been working in a new SPA project using Feathers and React, the combination of those two turns out to be **just amazing**.\n\nRecently we were struggling to find a way to upload files without having to write a separate Express middleware or having to (re)write a complex Feathers service.\n\n## Our Goals\n\nWe want to implement an upload service to accomplish a few important things:\n\n1. It has to handle large files (+10MB).\n2. It needs to work with the app's authentication and authorization.\n3. The files need to be validated.\n4. At the moment there is no third party storage service involved, but this will change in the near future, so it has to be prepared.\n5. It has to show the upload progress.\n\nThe plan is to upload the files to a feathers service so we can take advantage of hooks for authentication, authorization and validation, and for service events.\n\nFortunately, there exists a file storage service: [feathers-blob](https://github.com/feathersjs/feathers-blob). With it we can meet our goals, but (spoiler alert) it isn't an ideal solution.  We discuss some of its problems below.\n\n\n## Basic upload with feathers-blob and feathers-client\n\nFor the sake of simplicity, we will be working over a very basic feathers server, with just the upload service.\n\nLets look at the server code:\n\n```javascript\n/* --- server.js --- */\n\nconst feathers = require('@feathersjs/feathers');\nconst express = require('@feathersjs/express');\nconst socketio = require('@feathersjs/socketio');\n\n// feathers-blob service\nconst blobService = require('feathers-blob');\n// Here we initialize a FileSystem storage,\n// but you can use feathers-blob with any other\n// storage service like AWS or Google Drive.\nconst fs = require('fs-blob-store');\nconst blobStorage = fs(__dirname + '/uploads');\n\n\n// Feathers app\nconst app = express(feathers());\n\n// Parse HTTP JSON bodies\napp.use(express.json());\n// Parse URL-encoded params\napp.use(express.urlencoded({ extended: true }));\n// Add REST API support\napp.configure(express.rest());\n// Configure Socket.io real-time APIs\napp.configure(socketio());\n\n\n// Upload Service\napp.use('/uploads', blobService({Model: blobStorage}));\n\n\n// Register a nicer error handler than the default Express one\napp.use(express.errorHandler());\n\n// Start the server\napp.listen(3030, function(){\n    console.log('Feathers app started at localhost:3030')\n});\n```\n\nLet's look at this implemented in the `@feathersjs/cli` generated server code:\n\n```javascript\n/* --- /src/services/uploads/uploads.service.js --- */\n\n// Initializes the `uploads` service on path `/uploads'\n\nconst createModel = require('../../models/uploads.model');\nconst hooks = require('./uploads.hooks');\nconst filters = require('./uploads.filters');\n\n\n// feathers-blob service\nconst blobService = require('feathers-blob');\n// Here we initialize a FileSystem storage,\n// but you can use feathers-blob with any other\n// storage service like AWS or Google Drive.\nconst fs = require('fs-blob-store');\n\n\n// File storage location. Folder must be created before upload.\n// Example: './uploads' will be located under feathers app top level.\nconst blobStorage = fs('./uploads');\n\nmodule.exports = function() {\n  const app = this;\n  const Model = createModel(app);\n  const paginate = app.get('paginate');\n\n  // Initialize our service with any options it requires\n  app.use('/uploads', blobService({ Model: blobStorage}));\n\n  // Get our initialized service so that we can register hooks and filters\n  const service = app.service('uploads');\n\n  service.hooks(hooks);\n\n  if (service.filter) {\n    service.filter(filters);\n  }\n};\n```\n\n`feathers-blob` works over abstract-blob-store, which is an abstract interface to various storage backends, such as filesystem, AWS, or Google Drive. It only accepts and retrieves files encoded as dataURI strings.\n\nJust like that we have our backend ready, go ahead and POST something to localhost:3030/uploads`, for example with postman:\n\n```json\n{\n    'uri': 'data:image/gif;base64,R0lGODlhEwATAPcAAP/+//7/////+////fvzYvryYvvzZ/fxg/zxWfvxW/zwXPrtW/vxXvfrXv3xYvrvYvntYvnvY/ruZPrwZPfsZPjsZfjtZvfsZvHmY/zxavftaPrvavjuafzxbfnua/jta/ftbP3yb/zzcPvwb/zzcfvxcfzxc/3zdf3zdv70efvwd/rwd/vwefftd/3yfPvxfP70f/zzfvnwffvzf/rxf/rxgPjvgPjvgfnwhPvzhvjvhv71jfz0kPrykvz0mv72nvblTPnnUPjoUPrpUvnnUfnpUvXlUfnpU/npVPnqVPfnU/3uVvvsWPfpVvnqWfrrXPLiW/nrX/vtYv7xavrta/Hlcvnuf/Pphvbsif3zk/zzlPzylfjuk/z0o/LqnvbhSPbhSfjiS/jlS/jjTPfhTfjlTubUU+/iiPPokfrvl/Dll/ftovLWPfHXPvHZP/PbQ/bcRuDJP/PaRvjgSffdSe3ddu7fge7fi+zkuO7NMvPTOt2/Nu7SO+3OO/PWQdnGbOneqeneqvDqyu3JMuvJMu7KNfHNON7GZdnEbejanObXnOW8JOa9KOvCLOnBK9+4Ku3FL9ayKuzEMcenK9e+XODOiePSkODOkOW3ItisI9yxL+a9NtGiHr+VH5h5JsSfNM2bGN6rMJt4JMOYL5h4JZl5Jph3Jpl4J5h5J5h3KJl4KZp5Ks+sUN7Gi96lLL+PKMmbMZt2Jpp3Jpt3KZl4K7qFFdyiKdufKsedRdm7feOpQN2QKMKENrpvJbFfIrNjJL1mLMBpLr9oLrFhK69bJFkpE1kpFYNeTqFEIlsoFbmlnlsmFFwpGFkoF/////7+/v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAANAALAAAAAATABMAAAj/AKEJHCgokKJKlhThGciQYSIva7r8SHPFzqGGAwPd4bKlh5YsPKy0qFLnT0NAaHTcsIHDho0aKkaAwGCGEkM1NmSkIjWLBosVJT6cOjUrzsBKPl54KmYsACoTMmk1WwaA1CRoeM7siJEqmTIAsjp40ICK2bEApfZcsoQlxwxRzgI8W8XhgoVYA+Kq6sMK0QEYKVCUkoVqQwQJFTwFEAAAFZ9PlFy4OEEiRIYJD55EodDA1ClTbPp0okRFxBQDBRgskAKhiRMlc+Sw4SNpFCIoBBwkUMBkCBIiY8qAgcPG0KBHrBTFQbCEV5EjQYQACfNFjp5CgxpxagVtUhIjwzaJYSHzhQ4cP3ryQHLEqJbASnu+6EIW6o2b2X0ISXK0CFSugazs0YYmwQhziyuE2PLLIv3h0hArkRhiCCzAENOLL7tgAoqDGLXSSSaPMLIIJpmAUst/GA3UCiuv1PIKLtw1FBAAOw=='\n}\n```\n\nThe service will respond with something like this:\n\n```json\n{\n  'id': '6454364d8facd7a88e627e4c4b11b032d2f83af8f7f9329ffc2b7a5c879dc838.gif',\n  'uri': 'the-same-uri-we-uploaded',\n  'size': 1156\n}\n```\n\nOr we can implement a very basic frontend with `feathers-client` and `jQuery`:\n\n```html\n<!doctype html>\n<html>\n    <head>\n        <title>Feathersjs File Upload</title>\n        <script   src='https://code.jquery.com/jquery-2.2.3.min.js'   integrity='sha256-a23g1Nt4dtEYOj7bR+vTu7+T8VP13humZFBJNIYoEJo='   crossorigin='anonymous'></script>\n        <script type='text/javascript' src='//cdnjs.cloudflare.com/ajax/libs/core-js/2.1.4/core.min.js'></script>\n        <script type='text/javascript' src='//unpkg.com/feathers-client@^2.0.0/dist/feathers.js'></script>\n        <script type='text/javascript'>\n            // feathers client initialization\n            const rest = feathers.rest('http://localhost:3030');\n            const app = feathers()\n            .configure(feathers.hooks())\n            .configure(rest.jquery($));\n\n            // setup jQuery to watch the ajax progress\n            $.ajaxSetup({\n                xhr: function () {\n                    var xhr = new window.XMLHttpRequest();\n                    // upload progress\n                    xhr.addEventListener('progress', function (evt) {\n                        if (evt.lengthComputable) {\n                            var percentComplete = evt.loaded / evt.total;\n                            console.log('upload progress: ', Math.round(percentComplete * 100) + '%');\n                        }\n                    }, false);\n                    return xhr;\n                }\n            });\n\n            const uploadService = app.service('uploads');\n            const reader  = new FileReader();\n\n            // encode selected files\n            $(document).ready(function(){\n                $('input#file').change(function(){\n                    var file = this.files[0];\n                    // encode dataURI\n                    reader.readAsDataURL(file);\n                })\n            });\n\n            // when encoded, upload\n            reader.addEventListener('load', function () {\n                console.log('encoded file: ', reader.result);\n                var upload = uploadService\n                    .create({uri: reader.result})\n                    .then(function(response){\n                        // success\n                        alert('UPLOADED!! ');\n                        console.log('Server responded with: ', response);\n                    });\n            }, false);\n        </script>\n    </head>\n    <body>\n        <h1>Let's upload some files!</h1>\n        <input type='file' id='file'/>\n    </body>\n</html>\n\n```\n\nThis code watches for file selection, then encodes it and does an ajax post to upload it, watching the upload progress via the xhr object. Everything works as expected.\n\nEvery file we select gets uploaded and saved to the `./uploads` directory.\n\nWork done!, let's call it a day, shall we?\n\n... But hey, there is something that doesn't feel quite right ...right?\n\n### DataURI upload problems\n\nIt doesn't feel right because it is not. Let's imagine what would happen if we try to upload a large file, say 25MB or more: The entire file (plus some extra MB due to the encoding) has to be kept in memory for the entire upload process, this could look like nothing for a normal computer but for mobile devices it's a big deal.\n\nWe have a big RAM consumption problem. Not to mention we have to encode the file before sending it...\n\nThe solution would be to modify the service, adding support for splitting the dataURI into small chunks, then uploading one at a time, collecting and reassembling everything on the server. But hey, it's not that the same thing   browsers and web servers have been doing since maybe the very early days of the web?  Maybe since Netscape Navigator?\n\nWell, actually it is, and doing a `multipart/form-data` post is still the easiest way to upload a file.\n\n\n## Feathers-blob with multipart support.\n\nBack with the backend, in order to accept multipart uploads, we need a way to handle the `multipart/form-data` received by the web server. Given that Feathers behaves like Express, let's just use `multer` and a custom middleware to handle that.\n\n``` javascript\n/* --- server.js --- */\nconst multer = require('multer');\nconst multipartMiddleware = multer();\n\n// Upload Service with multipart support\napp.use('/uploads',\n\n    // multer parses the file named 'uri'.\n    // Without extra params the data is\n    // temporarely kept in memory\n    multipartMiddleware.single('uri'),\n\n    // another middleware, this time to\n    // transfer the received file to feathers\n    function(req,res,next){\n        req.feathers.file = req.file;\n        next();\n    },\n    blobService({Model: blobStorage})\n);\n```\n\nNotice we kept the file field name as *uri* just to maintain uniformity, as the service will always work with that name anyways, but you can change it if you prefer.\n\nFeathers-blob only understands files encoded as dataURI, so we need to convert them first. Let's make a Hook for that:\n\n```javascript\n/* --- server.js --- */\nconst dauria = require('dauria');\n\n// before-create Hook to get the file (if there is any)\n// and turn it into a datauri,\n// transparently getting feathers-blob to work\n// with multipart file uploads\napp.service('/uploads').before({\n    create: [\n        function(context) {\n            if (!context.data.uri && context.params.file){\n                const file = context.params.file;\n                const uri = dauria.getBase64DataURI(file.buffer, file.mimetype);\n                context.data = {uri: uri};\n            }\n        }\n    ]\n});\n```\n\n*Et voilà!*. Now we have a FeathersJS file storage service working, with support for traditional multipart uploads, and a variety of storage options to choose.\n\n**Simply awesome.**\n\n\n## Further improvements\n\nThe service always returns the dataURI back to us, which may not be necessary as we just uploaded the file. We also need to validate the file and check for authorization.\n\nAll those things can be easily done with more Hooks, and that's the benefit of keeping all inside FeathersJS services. I leave that to you.\n\nFor the frontend, there is a problem with the client: in order to show the upload progress it's stuck with only REST functionality and not real-time with socket.io.\n\nThe solution is to switch `feathers-client` from REST to `socket.io`, and just use wherever you like for uploading the files, that's an easy task now that we are able to do a traditional `form-multipart` upload.\n\nHere is an example using dropzone:\n\n```html\n<!doctype html>\n<html>\n    <head>\n        <title>Feathersjs File Upload</title>\n\n        <link rel='stylesheet' href='assets/dropzone.css'>\n        <script src='assets/dropzone.js'></script>\n\n        <script type='text/javascript' src='socket.io/socket.io.js'></script>\n        <script type='text/javascript' src='//cdnjs.cloudflare.com/ajax/libs/core-js/2.1.4/core.min.js'></script>\n        <script type='text/javascript' src='//unpkg.com/feathers-client@^2.0.0/dist/feathers.js'></script>\n        <script type='text/javascript'>\n            // feathers client initialization\n            var socket = io('http://localhost:3030');\n            const app = feathers()\n            .configure(feathers.hooks())\n            .configure(feathers.socketio(socket));\n            const uploadService = app.service('uploads');\n\n            // Now with Real-Time Support!\n            uploadService.on('created', function(file){\n                alert('Received file created event!', file);\n            });\n\n\n            // Let's use DropZone!\n            Dropzone.options.myAwesomeDropzone = {\n                paramName: 'uri',\n                uploadMultiple: false,\n                init: function(){\n                    this.on('uploadprogress', function(file, progress){\n                        console.log('progresss', progress);\n                    });\n                }\n            };\n        </script>\n    </head>\n    <body>\n        <h1>Let's upload some files!</h1>\n        <form action='/uploads'\n          class='dropzone'\n          id='my-awesome-dropzone'></form>\n    </body>\n</html>\n```\n\nAll the code is available via github here: https://github.com/CianCoders/feathers-example-fileupload\n\n\nHope you have learned something today, as I learned a lot writing this.\n\nCheers!\n"
  },
  {
    "path": "docs/cookbook/express/view-engine.md",
    "content": "---\noutline: deep\n---\n\n# Server Side Rendering\n\nSince Feathers is just an extension of Express it's really simple to render templated views on the server with data from your Feathers services. There are a few different ways that you can structure your app so this guide will show you 3 typical ways you might have your Feathers app organized.\n\n## Rendering views from services\n\nYou probably already know that when you register a Feathers service, Feathers creates RESTful endpoints for that service automatically. Well, really those are just Express routes, so you can define your own as well.\n\n> **ProTip:** Your own defined REST endpoints won't work with hooks and won't emit socket events. If you find you need that functionality it's probably better for you to turn your endpoints into a minimal Feathers service.\n\nLet's say you want to render a list of messages from most recent to oldest using the [Pug](https://pugjs.org/) template engine.\n\n```js\n// You've set up your main Feathers app already\n\n// Register your view engine\napp.set('view engine', 'pug');\n\n// Register your message service\napp.use('/api/messages', memory());\n\n// Inside your main Feathers app\napp.get('/messages', function(req, res, next){\n  // You namespace your feathers service routes so that\n  // don't get route conflicts and have nice URLs.\n  app.service('api/messages')\n    .find({ query: {$sort: { updatedAt: -1 } } })\n    .then(result => res.render('message-list', result.data))\n    .catch(next);\n});\n```\n\nSimple right? We've now rendered a list of messages using the `/views/message-list.pug` view template. All your hooks will get triggered just like they would normally so you can use hooks to pre-filter your data and keep your template rendering routes super tight. See [Using Template Engines with Express](https://expressjs.com/en/guide/using-template-engines.html) for more information.\n\n> **ProTip:** If you call a Feathers service \"internally\" (ie. not over sockets or REST) you won't have a `context.params.provider` attribute. This allows you to have hooks only execute when services are called externally vs. from your own code.\n\n## Using authentication\n\nFeathers is by default stateless and does not use any sessions. You already can protect Express endpoints with the [express.authenticate](../../api/express.md#express-authenticate) middleware, however this will only work when passing the `Authorization` header (usually with a JWT) which a normal browser request does not support.\n\nIn order to render authenticated pages, [express-session](https://www.npmjs.com/package/express-session) can be used to add the authentication information to the (browser) session:\n\n> npm i express-session --save\n\nNow you can add the following to `src/middleware/index.js|ts`:\n\n```js\nconst session = require('express-session');\nconst { authenticate } = require('@feathersjs/express');\n\n// This sets `req.authentication` from the information added to the session\nconst setSessionAuthentication = (req, res, next) => {\n  req.authentication = req.session.authentication;\n  next();\n};\n\nmodule.exports = function (app) {\n  // Initialize Express-session - might have to be configured\n  // with a persisten storage adapter (like Redis)\n  app.use(session({\n    secret: 'session-secret',\n    saveUninitialized: false,\n    resave: true\n  }));\n\n  // An endpoint that you can POST to with `email` and `password` that\n  // will then perform a local user authentication\n  // e.g <form action=\"/login\" method=\"post\"></form>\n  app.post('/login', async (req, res, next) => {\n    try {\n      const { email, password } = req.body;\n      // Run normal local authentication through our service\n      const { accessToken } = await app.service('authentication').create({\n        strategy: 'local',\n        email,\n        password\n      });\n\n      // Register the JWT authentication information on the session\n      req.session.authentication = {\n        strategy: 'jwt',\n        accessToken\n      };\n\n      // Redirect to an authenticated page\n      res.redirect('/hello');\n    } catch (error) {\n      next(error);\n    }\n  });\n\n  // Remove the authentication information from the session to log out\n  app.get('logout', (req, res) => {\n    delete req.session.authentication;\n    res.end('You are now logged out');\n  });\n\n  // Renders an authenticated page or an 401 error page\n  // Always needs `setSessionAuthentication, authenticate('jwt')` middleware first\n  app.get('/hello', setSessionAuthentication, authenticate('jwt'), (req, res) => {\n    res.end(`Authenticated page with user ${req.user.email}`);\n  });\n};\n```\n"
  },
  {
    "path": "docs/cookbook/general/client-test.md",
    "content": "---\noutline: deep\n---\n\n# Client/server testing\n\nYou can write tests which start up both a server for your app, and a Feathers client which your test can use to call the server. Such tests can expose faults in the interaction between the client and the server. They are also useful in testing the authentication of requests from the client. Install it as a development dependency:\n\n```\nnpm install @feathersjs/client --save-dev\n```\n\nTest `test/services/users.test.js` from above runs on the server. We convert it, in the following `tests/services/client-users.test.js`, so the tests are run on the client instead of on the server. This also causes client authentication to be tested.\n\n```js\nconst assert = require('assert');\nconst feathersClient = require('@feathersjs/client');\nconst io = require('socket.io-client');\nconst app = require('../../src/app');\n\nconst host = app.get('host');\nconst port = app.get('port');\nconst email = 'login@example.com';\nconst password = 'login';\n\ndescribe('\\'users\\' service - client', function () {\n  this.timeout(10000);\n  let server;\n  let client;\n\n  before(async () => {\n    await app.service('users').create({ email, password });\n\n    server = app.listen(port);\n    server.on('listening', async () => {\n      // eslint-disable-next-line no-console\n      console.log('Feathers application started on http://%s:%d', host, port);\n    });\n\n    client = await makeClient(host, port, email, password);\n  });\n\n  after(() => {\n    client.logout();\n    server.close();\n  });\n\n  describe('Run tests using client and server', () => {\n    it('registered the service', () => {\n      const service = client.service('users');\n\n      assert.ok(service, 'Registered the service');\n    });\n\n    it('creates a user, encrypts password and adds gravatar', async () => {\n      const user = await client.service('users').create({\n        email: 'testclient@example.com',\n        password: 'secret'\n      });\n\n      // Verify Gravatar has been set to what we'd expect\n      assert.equal(user.avatar, 'https://s.gravatar.com/avatar/1b9c869fa7a93e59463c31a377fe0cf6?s=60');\n      // Makes sure the password got encrypted\n      assert.ok(user.password !== 'secret');\n    });\n\n    it('removes password for external requests', async () => {\n      // Setting `provider` indicates an external request\n      const params = { provider: 'rest' };\n\n      const user = await client.service('users').create({\n        email: 'testclient2@example.com',\n        password: 'secret'\n      }, params);\n\n      // Make sure password has been removed\n      assert.ok(!user.password);\n    });\n  });\n});\n\nasync function makeClient(host, port, email, password) {\n  const client = feathersClient();\n  const socket = io(`http://${host}:${port}`, {\n    transports: ['websocket'], forceNew: true, reconnection: false, extraHeaders: {}\n  });\n  client.configure(feathersClient.socketio(socket));\n  client.configure(feathersClient.authentication({\n    storage: localStorage()\n  }));\n\n  await client.authenticate({\n    strategy: 'local',\n    email,\n    password,\n  });\n\n  return client;\n}\n\nfunction localStorage () {\n  const store = {};\n\n  return {\n    setItem (key, value) {\n      store[key] = value;\n    },\n    getItem (key) {\n      return store[key];\n    },\n    removeItem (key) {\n      delete store[key];\n    }\n  };\n}\n```\n\nWe first make a call on the *server* to create a new user. We then start up a server for our app. Finally the function `makeClient` is called to create a Feathers client and authenticate it using the newly created user.\n\nThe individual tests remain unchanged except that the service calls are now made on the client (`client.service(...).create`) instead of on the server (`app.service(...).create`).\n\nThe `describe('Run tests using client and server',` statement stops a new server and client from being created for each test. This results in the test module running noticeably faster, though the tests are now exposed to potential interactions. You can remove the statement to isolate the tests from one another."
  },
  {
    "path": "docs/cookbook/general/scaling.md",
    "content": "---\noutline: deep\n---\n\n# Scaling\n\nDepending on your requirements, your feathers application may need to provide high availability. Feathers is designed to scale.\n\nThe types of transports used in a feathers application will impact the scaling configuration. For example, a feathers app that uses the `feathers-rest` adapter exclusively will require less scaling configuration because HTTP is a stateless protocol. If using websockets (a stateful protocol) through the `feathers-socketio` or `feathers-primus` adapters, configuration may be more complex to ensure websockets work properly.\n\n## Horizontal Scaling\n\nScaling horizontally refers to either:\n\n- setting up a [cluster](https://nodejs.org/api/cluster.html), or\n- adding more machines to support your application\n\nTo achieve high availability, varying combinations of both strategies may be used.\n\n## Cluster configuration\n\n[Cluster](https://nodejs.org/api/cluster.html) support is built into core NodeJS. Since NodeJS is single threaded, clustering allows you to easily distribute application requests among multiple child processes (and multiple threads). Clustering is a good choice when running feathers in a multi-core environment.\n\nBelow is an example of adding clustering to feathers with the `feathers-socketio` provider. By default, websocket connections begin via a handshake of multiple HTTP requests and are upgraded to the websocket protocol. However, when clustering is enabled, the same worker will not process all HTTP requests for a handshake, leading to HTTP 400 errors. To ensure a successful handshake, force a single worker to process the handshake by disabling the http transport and exclusively using the `websocket` transport.\n\n```js\nimport cluster from 'cluster';\nimport feathers from '@feathersjs/feathers';\nimport socketio from '@feathersjs/socketio';\n\nconst CLUSTER_COUNT = 4;\n\nif (cluster.isMaster) {\n  for (let i = 0; i < CLUSTER_COUNT; i++) {\n    cluster.fork();\n  }\n} else {\n  const app = feathers();\n  // ensure the same worker handles websocket connections\n  app.configure(socketio({\n    transports: ['websocket']\n  }));\n  app.listen(4000);\n}\n```\n\nIn your feathers client code, limit the socket.io-client to the `websocket` transport and disable `upgrade`.\n\n```js\nimport feathers from '@feathersjs/client';\nimport socketio from '@feathersjs/socketio-client';\nimport io from 'socket.io-client';\n\nconst app = feathers()\n  .configure(socketio(\n    io('http://api.feathersjs.com', {\n      transports: ['websocket'],\n      upgrade: false\n    })\n  ));\n```\n## Multiple instances\nWhen running multiple instances of your Feathers application (e.g. on several Heroku Dynos), service events (created, updated, patched, removed and any custom defined events) do not get propagated to other instances for such cases you may want to use: https://github.com/feathersjs-ecosystem/feathers-sync\n\nWhich will use a messaging mechanism to propagate all events to all application instances like redis or RabbitMQ\n\n"
  },
  {
    "path": "docs/cookbook/index.md",
    "content": "---\noutline: deep\n---\n\n# The Feathers cookbook\n\nThis cookbook contains a growing collection of recipes for common tasks you might run into with Feathers. Make sure you have [followed the Feathers guide first](../guides/) before jumping into the cookbook.\n\nHave a recipe idea? [Submit an issue with a suggestion](https://github.com/feathersjs/docs/issues/new?title=Cookbook%20Suggestion:).\n"
  },
  {
    "path": "docs/ecosystem/PackageCard.vue",
    "content": "<script setup lang=\"ts\">\nimport { PropType } from 'vue'\nimport { nFormatter } from './helpers'\nimport { formatDistance as _formatDistance } from 'date-fns'\nimport { PackageOutput } from './types'\nconst intlFormat = new Intl.DateTimeFormat('en-US', {\n  year: 'numeric',\n  month: 'long',\n  day: 'numeric'\n})\nconst props = defineProps({\n  stats: {\n    type: Object as PropType<PackageOutput>,\n    required: true\n  },\n  isOld: {\n    type: Boolean,\n    default: false\n  }\n})\nconst formatDistance = (date: Date, baseDate: Date) => {\n  try {\n    return _formatDistance(date, new Date())\n  } catch (err) {\n    return ''\n  }\n}\nconst formatDate = (date: Date) => {\n  try {\n    return intlFormat.format(date)\n  } catch (err) {\n    return ''\n  }\n}\n</script>\n\n<template>\n  <div class=\"feathers-package\">\n    <div class=\"flex items-center flex-col sm:flex-row mb-1\">\n      <a :href=\"`https://github.com/${stats.ownerName}`\" target=\"_blank\">\n        <img v-if=\"stats.ownerAvatar\" :src=\"stats.ownerAvatar\" class=\"w-10 h-10 rounded-full mr-2\" />\n      </a>\n      <div class=\"flex-1\">\n        <div class=\"flex justify-between flex-col sm:flex-row\">\n          <a\n            :title=\"stats.hasNPM ? stats.name : stats.repository?.name\"\n            :href=\"stats.hasNPM ? stats.npmLink : stats.ghLink\"\n            target=\"_blank\"\n            rel=\"noopener noreferrer\"\n            class=\"text-lg flex flex-wrap justify-center md:justify-normal\"\n          >\n            <template v-if=\"stats.name\">{{ stats.name }}</template>\n            <template v-else>{{ stats.repository?.name }}</template>\n          </a>\n          <div v-if=\"stats.hasNPM\" class=\"flex justify-center md:justify-normal ml-2\">\n            <div>\n              <span class=\"text-gray-500 font-extralight\">v</span>\n              <span class=\"font-semibold\">{{ stats.version }}</span>\n            </div>\n          </div>\n        </div>\n        <div class=\"flex my-1 text-sm\">\n          <div\n            v-if=\"stats.hasNPM\"\n            :title=\"`${stats.downloads} monthly npm downloads`\"\n            class=\"flex mx-2 items-center min-w-14\"\n          >\n            <div class=\"i-carbon-download mr-1 w-3.5 h-3.5 text-gray-500\" />\n            <div class=\"flex-1 flex justify-center\">{{ stats.downloads && nFormatter(stats.downloads) }}</div>\n          </div>\n          <div :title=\"`${stats.stars} stars on github`\" class=\"flex mx-2 items-center min-w-14\">\n            <div class=\"i-carbon-star-filled mr-1 w-3.5 h-3.5 text-gray-500\" />\n            <div class=\"flex-1 flex justify-center\">{{ nFormatter(stats.stars) }}</div>\n          </div>\n          <div\n            v-if=\"stats.hasNPM\"\n            :title=\"`published on ${formatDate(stats.lastPublish)}`\"\n            class=\"flex mx-2 items-center min-w-16\"\n          >\n            <div class=\"i-carbon-time mr-1 w-3.5 h-3.5 text-gray-500\"></div>\n            {{ formatDistance(stats.lastPublish, new Date()) }}\n          </div>\n        </div>\n      </div>\n    </div>\n    <div class=\"flex text-sm mb-2 justify-center sm:justify-start\">\n      <div v-if=\"stats.license\" class=\"mx-2\">{{ stats.license }}</div>\n      <a\n        v-if=\"stats.ghLink\"\n        :href=\"stats.ghLink\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n        class=\"flex items-center mx-2\"\n      >\n        <div class=\"i-carbon-arrow-up-right mr-1 w-3.5 h-3.5\" />\n        Github\n      </a>\n      <a\n        v-if=\"stats.hasNPM\"\n        :href=\"stats.npmLink\"\n        target=\"_blank\"\n        rel=\"noopener noreferrer\"\n        class=\"flex items-center mx-2\"\n      >\n        <div class=\"i-carbon-arrow-up-right mr-1 w-3.5 h-3.5\" />\n        npm\n      </a>\n    </div>\n    <div class=\"text-gray-600 my-2 ml-2 text-sm md:text-base .dark:text-gray-300\">\n      <div v-if=\"isOld\" class=\"border-l-4 border-red-500 bg-red-500/20 p-2 mb-2 text-sm\">\n        This package seems to be unmaintained. Please use with caution and consider taking over the\n        maintenance! Please contact us if you want to over discord! ❤️\n      </div>\n      {{ stats.description }}\n    </div>\n    <div>\n      <div\n        v-for=\"keyword in stats.keywords\"\n        :key=\"keyword\"\n        class=\"inline-block bg-gray-200 rounded-full px-3 py-1 text-xs text-gray-700 mr-2 mb-1 .dark:bg-gray-700 .dark:text-gray-200\"\n      >\n        {{ keyword }}\n      </div>\n    </div>\n  </div>\n</template>\n\n<style scoped>\n.feathers-package {\n  margin-bottom: 30px;\n}\n</style>\n"
  },
  {
    "path": "docs/ecosystem/Packages.vue",
    "content": "<script setup lang=\"ts\">\nimport PackageCard from './PackageCard.vue'\nimport { PackageOutput } from './types'\nimport { ref, computed, onMounted } from 'vue'\nimport { uniqBy } from './helpers'\nimport { useQuery } from './useQuery'\n\nconst packageSource = 'https://ecosystem.featherscloud.workers.dev/'\n\nconst makeDate = (obj: Record<string, any>, key: string) => {\n  if (obj[key]) {\n    obj[key] = new Date(obj[key])\n  }\n}\nconst fetchedPackages = ref<PackageOutput[]>([])\nasync function getPackageStats(): Promise<PackageOutput[]> {\n  const packages = await fetch(packageSource).then((response) => response.json())\n\n  packages.forEach((pkg: any) => {\n    makeDate(pkg, 'lastPublish')\n\n    pkg.id = pkg.name || `${pkg.repository?.name}/${pkg.repository?.directory}`\n\n    const hasNPM = !isNaN(pkg.lastPublish.getTime())\n    pkg.hasNPM = hasNPM\n  })\n\n  const uniq = uniqBy(packages, (pkg) => pkg.id)\n  return uniq\n}\n\nconst categories: CategoryOption[] = [\n  { label: 'Authentication', value: ['authentication'] },\n  { label: 'Authorization', value: ['authorization'] },\n  { label: 'Caching', value: ['caching'] },\n  { label: 'Client', value: ['client'] },\n  { label: 'Database', value: ['database'] },\n  { label: 'APIs', value: ['api', 'apis'] },\n  { label: 'Documentation', value: ['documentation', 'docs'] },\n  { label: 'Email & SMS', value: ['email', 'mail', 'mailer', 'nodemailer', 'sms'] },\n  { label: 'Frontend', value: ['frontend', 'front-end'] },\n  { label: 'Google', value: ['google'] },\n  { label: 'Hooks', value: ['hook', 'hooks'] },\n  { label: 'Images', value: ['image', 'images'] },\n  { label: 'Payments', value: ['payment', 'payments'] },\n  { label: 'Scaling', value: ['scale', 'scaling'] },\n  { label: 'Search', value: ['search'] },\n  { label: 'Social Media', value: ['social media', 'social-media', 'socialmedia'] },\n  { label: 'Testing', value: ['test', 'testing'] },\n  { label: 'Logging', value: ['log', 'logs', 'logging'] },\n  { label: 'Transports', value: ['transport', 'transports'] },\n  { label: 'Utilities', value: ['utility', 'utilities'] },\n  { label: 'Validation', value: ['validation', 'validator', 'validators'] }\n]\n\nconst keyToSortBy = ref<'stars' | 'downloads' | 'lastPublish'>('lastPublish')\nconst showCore = ref(true)\n\nfunction filterCore(pkg: PackageOutput) {\n  return pkg.ownerName === 'feathersjs'\n}\nconst coreCount = computed(() => {\n  return fetchedPackages.value.filter(filterCore).length\n})\n\nconst packagesAreOldIfOlderThan = 1000 * 60 * 60 * 24 * 365 * 5\nconst showOld = ref(false)\n\nfunction filterOld(pkg: PackageOutput) {\n  return pkg.lastPublish.getTime() < Date.now() - packagesAreOldIfOlderThan\n}\nconst oldCount = computed(() => {\n  return fetchedPackages.value.filter(filterOld).length\n})\nconst countByCategory = computed(() => {\n  const counts: Record<string, number> = {}\n  categories.forEach((category) => {\n    counts[category.label] = fetchedPackages.value.filter((pkg) => {\n      return category.value.some((value) => {\n        return pkg.keywords?.some((keyword) => keyword.toLowerCase().includes(value))\n      })\n    }).length\n  })\n  return counts\n})\n\nconst categoriesToFilter = ref<string[]>([])\n\nconst categoriesToShow = computed(() => {\n  const cats = categories.filter((category) => {\n    return categoriesToFilter.value.includes(category.label)\n  })\n  return cats\n})\n\ntype Category = string[]\ntype CategoryOption = {\n  label: string\n  value: Category\n}\n\nconst search = ref('')\n\nconst filteredPackages = computed(() => {\n  let pkgs = [...fetchedPackages.value]\n  if (!showCore.value) {\n    pkgs = pkgs.filter((pkg) => !filterCore(pkg))\n  }\n  if (!showOld.value) {\n    pkgs = pkgs.filter((pkg) => !filterOld(pkg))\n  }\n  if (search.value) {\n    const _search = search.value.toLowerCase()\n    pkgs = pkgs.filter(\n      (pkg) =>\n        pkg.id.includes(_search) ||\n        pkg.description?.includes(_search) ||\n        pkg.keywords?.some((keyword) => keyword.includes(_search))\n    )\n  }\n  if (categoriesToShow.value.length) {\n    pkgs = pkgs.filter((pkg) => {\n      return pkg.keywords?.some((keyword) => {\n        return categoriesToShow.value.some((category) => {\n          return category.value.some((value) => {\n            return keyword.toLowerCase().includes(value)\n          })\n        })\n      })\n    })\n  }\n  return pkgs\n})\n\nconst packagesToShow = computed(() => {\n  const key = keyToSortBy.value\n  const result = filteredPackages.value.sort((a, b) => {\n    if (key === 'lastPublish' && (!a.hasNPM || !b.hasNPM)) {\n      return a.hasNPM ? -1 : 1\n    }\n\n    const valA = a[key] || 0\n    const valB = b[key] || 0\n\n    if (valA > valB) {\n      return -1\n    } else if (valA < valB) {\n      return 1\n    } else {\n      return 0\n    }\n  })\n  return result\n})\n\nonMounted(async () => {\n  fetchedPackages.value = await getPackageStats()\n\n  // sync values with URL\n  useQuery(keyToSortBy, 'sort', 'string')\n  useQuery(showCore, 'core', 'boolean')\n  useQuery(showOld, 'old', 'boolean')\n  useQuery(search, 's', 'string')\n  useQuery(categoriesToFilter, 'cat', 'string[]')\n})\n</script>\n\n<template>\n  <div>\n    <el-input v-model=\"search\" placeholder=\"Search package\" clearable class=\"mb-1\" />\n    <div class=\"flex justify-between mb-2\">\n      <div>\n        <el-checkbox v-model=\"showCore\" size=\"small\" title=\"packages under '@feathersjs/'\"\n          >core ({{ coreCount }})</el-checkbox\n        >\n        <el-checkbox v-model=\"showOld\" size=\"small\" title=\"older than 3 years\"\n          >outdated ({{ oldCount }})</el-checkbox\n        >\n      </div>\n      <el-select\n        v-model=\"categoriesToFilter\"\n        multiple\n        collapse-tags\n        collapse-tags-tooltip\n        placeholder=\"Filter by category\"\n        style=\"width: 240px\"\n        value-key=\"label\"\n        clearable\n      >\n        <el-option\n          v-for=\"option in categories\"\n          :key=\"option.label\"\n          :label=\"option.label\"\n          :value=\"option.label\"\n          :title=\"option.value.join(', ')\"\n        >\n          {{ option.label }} ({{ countByCategory[option.label] }})\n        </el-option>\n      </el-select>\n    </div>\n    <div class=\"flex justify-end mb-3\">\n      <el-radio-group v-model=\"keyToSortBy\">\n        <el-radio label=\"downloads\" size=\"small\" title=\"Monthly npm downloads\">Downloads</el-radio>\n        <el-radio label=\"stars\" size=\"small\" title=\"Github stars\">Stars</el-radio>\n        <el-radio label=\"lastPublish\" size=\"small\" title=\"Recently published on npm\">Newest</el-radio>\n      </el-radio-group>\n    </div>\n\n    <div class=\"font-bold mb-5\">{{ packagesToShow.length }}/{{ fetchedPackages.length }} packages:</div>\n    <TransitionGroup name=\"list\" tag=\"div\">\n      <package-card\n        v-for=\"pkg in packagesToShow\"\n        :key=\"pkg.id\"\n        :stats=\"pkg\"\n        :is-old=\"pkg.lastPublish.getTime() < Date.now() - packagesAreOldIfOlderThan\"\n      />\n    </TransitionGroup>\n  </div>\n</template>\n<style scoped>\n.list-move, /* apply transition to moving elements */\n.list-enter-active,\n.list-leave-active {\n  transition: all 0.5s ease;\n}\n.list-enter-from {\n  opacity: 0;\n  transform: translateX(-30px);\n}\n.list-leave-to {\n  opacity: 0;\n  transform: translateX(30px);\n}\n/* ensure leaving items are taken out of layout flow so that moving\n   animations can be calculated correctly. */\n.list-leave-active {\n  position: absolute;\n}\n</style>\n"
  },
  {
    "path": "docs/ecosystem/helpers.ts",
    "content": "export function nFormatter(num: number, digits?: number) {\n  const lookup = [\n    { value: 1, symbol: '' },\n    { value: 1e3, symbol: 'k' },\n    { value: 1e6, symbol: 'M' },\n    { value: 1e9, symbol: 'G' },\n    { value: 1e12, symbol: 'T' },\n    { value: 1e15, symbol: 'P' },\n    { value: 1e18, symbol: 'E' }\n  ]\n  const rx = /\\.0+$|(\\.[0-9]*[1-9])0+$/\n  const item = lookup\n    .slice()\n    .reverse()\n    .find(function (item) {\n      return num >= item.value\n    })\n  return item ? (num / item.value).toFixed(digits).replace(rx, '$1') + item.symbol : '0'\n}\n\nexport const uniqBy = <T = any, V = any>(arr: T[], selector: (item: T) => V) => {\n  const map = new Map<V, T>()\n  arr.forEach((item) => {\n    const prop = selector(item)\n    if (!map.has(prop)) map.set(prop, item)\n  })\n  return [...map.values()]\n}\n"
  },
  {
    "path": "docs/ecosystem/index.md",
    "content": "---\nlastUpdated: false\n---\n\n<script setup lang=\"ts\">\nimport Packages from './Packages.vue'\n</script>\n\n# FeathersJS Ecosystem\n\n## The Feathers Flightpath Blog\n\nCatch up on the latest FeathersJS news and community-contributed articles on the [Feathers Flightpath Blog](https://blog.feathersjs.com/).\n\n## YouTube Playlist\n\nWatch the [FeathersJS Playlist on YouTube](https://www.youtube.com/playlist?list=PLwSdIiqnDlf_lb5y1liQK2OW5daXYgKOe).\n\n## Awesome Packages\n\nThis is a curated list of feathers packages. You can sort by various criteria. Core packages are hidden by default.\n\n<ClientOnly>\n  <Suspense>\n    <Packages class=\"mt-4\" />\n  </Suspense>\n</ClientOnly>\n"
  },
  {
    "path": "docs/ecosystem/types.ts",
    "content": "export type PackageInput = {\n  npm: string\n  repo: string\n}\n\nexport type PackagesInput = Record<string, PackageInput>\n\nexport type PackageOutput = {\n  id: string\n  name: string\n  description: string\n  keywords: string[]\n  /** npm license */\n  license: string\n  /** npm version */\n  version: string\n  /** npm monthly downloads */\n  downloads: number\n  /** npm last published Date */\n  lastPublish: Date\n  /** npm last published Date as unix */\n  lastPublishUnix: number\n  /** github: stars count */\n  stars: number\n  /** github: open issues count */\n  issues: number\n  /** github: age of repo */\n  createdAt: Date\n  /** github: name of the owner */\n  ownerName: string\n  /** github: url of the users avatar */\n  ownerAvatar: string\n  /** github: url of the repo */\n  ghLink: string\n  hasNPM: boolean\n  /** npm: url of the package */\n  npmLink: string\n  repository: {\n    name: string\n    directory: string\n  }\n}\n"
  },
  {
    "path": "docs/ecosystem/useQuery.ts",
    "content": "import { Ref, watch } from 'vue'\nimport queryString from 'query-string'\n\ntype MaybeArray<T> = T | T[]\n\ntype FieldType = MaybeArray<'string' | 'number' | 'boolean'>\n\nexport const useQuery = <T extends FieldType>(reference: Ref<T>, field: string) => {\n  function getQuery() {\n    return queryString.parse(window.location.search, {\n      parseNumbers: true,\n      parseBooleans: true,\n      arrayFormat: 'none'\n    })\n  }\n\n  function getFromUrl() {\n    const q = getQuery()\n    const result = q[field]\n    // explicitly return false instead of undefined\n    if (typeof reference.value === 'boolean' && !result) {\n      return false\n    }\n    if (result == null) return\n    if (Array.isArray(reference.value)) {\n      return Array.isArray(result) ? result : [result]\n    }\n    return result\n  }\n\n  const fromUrl = getFromUrl()\n\n  if (fromUrl != null) {\n    // @ts-expect-error arbitrary type\n    reference.value = fromUrl\n  }\n\n  function setToUrl(val: any) {\n    const q = getQuery()\n    if (val && (!Array.isArray(reference.value) || (Array.isArray(val) && val.length > 0))) {\n      q[field] = val\n    } else {\n      delete q[field]\n    }\n    const prepend = Object.keys(q).length ? '?' : ''\n    const newQuery = `${prepend}${queryString.stringify(q, { skipNull: true })}`\n    window.history.replaceState(null, '', newQuery)\n  }\n\n  watch(\n    reference,\n    (val) => {\n      setToUrl(val)\n    },\n    { immediate: true }\n  )\n}\n"
  },
  {
    "path": "docs/feathers-vs-firebase.md",
    "content": "# Feathers vs Firebase\n\nFirebase is a hosted platform for mobile or web applications. Just like Feathers, Firebase provides REST and real-time APIs but also includes CDN support. Feathers on the other hand leaves setting up a CDN and hosting your Feathers app up to the developer.\n\nFirebase is a closed-source, paid hosted service starting at $5/month with the next plan level starting at $49/month. Feathers is open source and can run on any hosting platform like Heroku, Modulus or on your own servers like Amazon AWS, Microsoft Azure, Digital Ocean and your local machine. Because Firebase can't be run locally you typically need to pay for both a shared development environment on top of any production and testing environment.\n\nFirebase has JavaScript and mobile clients and also provides framework specific bindings. Feathers currently focuses on universal usage in JavaScript environments and does not have any framework specific bindings. Mobile applications can use Feathers REST and websocket endpoints directly but at the moment there are no Feathers specific iOS and Android SDKs.\n\nFirebase currently supports offline mode whereas that is currently left up to the developer with Feathers.\n\nBoth Firebase and Feathers support email/password, token, and OAuth authentication. Firebase has not publicly disclosed the database technology they use to store your data behind their API but it seems to be an SQL variant. Feathers supports multiple databases, NoSQL and SQL alike.\n\nFor more technical details on the difference and how to potentially migrate an application you can read [how to use Feathers as an open source alternative to Firebase](https://medium.com/all-about-feathersjs/using-feathersjs-as-an-open-source-alternative-to-firebase-b5d93c200cee#.olu25brld)."
  },
  {
    "path": "docs/feathers-vs-loopback.md",
    "content": "# Feathers vs LoopBack\n\nBoth LoopBack, and Feathers are frameworks primarily meant for building APIs, and mediating between front-end clients, and backend data sources.\n\nLoopBack is maintained by StrongLoop (an IBM company); while Feathers is community maintained. Folks behind StrongLoop are also the current maintainers of the Express framework atop of which both Feathers, and LoopBack are built.\n\nWhile LoopBack is a MVC framework bringing in its own set of conventions/concepts, with route-based CRUD config for its entities, Feathers propagates a service-oriented thinking model, where in you can build lightweight services to define entities — **\"you're no longer thinking CRUD routes for an entity; but a corresponding service, which represents an entity, and the CRUD methods for it\"** — and it gets out of your way allowing you to set your own conventions.\n\nFeathers has support for multiple databases and ORMs. LoopBack only supports its inbuilt ORM (based on Juggler). It should be noted, that LoopBack v4, which is under heavy development as of this writing would open support for multiple ORMs.\n\nFeathers core is engine-agnostic; meaning it works on both client, server sides. LoopBack comes with a separate in-built client.\n\nFeathers has official libraries which can be integrated with Feathers to support multiple transport layers apart from rest; like sockets, primus, etc... This can be achieved in LoopBack via various community libraries.\n\nLoopBack comes with in-built support for generating ACLs and an in-built API explorer, which makes it easier to analyse the built APIs, via auto-generated docs. Thanks to a rich ecosystem of libraries around Feathers, this can be achieved in Feathers via third party libraries like [feathers-permissions](https://github.com/feathersjs-ecosystem/feathers-permissions), and [feathers-swagger](https://github.com/feathersjs-ecosystem/feathers-swagger), respectively.\n\nThe conveniences brought in by LoopBack come with a tradeoff of a large knowledge surface area. While LoopBack is a \"convention-over-configuration\" framework, Feathers (core) is a really small/lightweight library which gets out of your way, without enforcing any specific way of building your service-oriented APIs."
  },
  {
    "path": "docs/feathers-vs-meteor.md",
    "content": "# Feathers vs Meteor\n\nBoth Feathers and Meteor are open source real-time JavaScript platforms that provide front end and back end support. They both allow clients to send and receive messages over websockets. Feathers lets you choose which real-time transport(s) you want to use via Socket.io or Primus, while Meteor relies on SockJS.\n\nFeathers is community supported, whereas Meteor is venture backed and has raised 31.2 million dollars to date.\n\nMeteor only has official support for MongoDB but there are some community modules of various levels of quality that support other databases. Meteor has it's own package manager and package ecosystem. They have their own template engine called Blaze which is based off of Mustache along with their own build system, but also have guides for Angular and React.\n\nFeathers has official support for many more databases and supports any front-end framework or view engine that you want by working seamlessly on the client.\n\nFeathers uses the defacto JavaScript package manager npm. As a result you can utilize the hundreds of thousands of modules published to npm. Feathers lets you decide whether you want to use Gulp, Grunt, Browserify, Webpack or any other build tool.\n\nMeteor has optimistic UI rendering and oplog tailing whereas currently Feathers leaves that up to the developer. However, we've found that being universal and utilizing websockets for both sending and receiving data alleviates the need for optimistic UI rendering and complex data diffing in most cases.\n\nBoth Meteor and Feathers provide support for email/password and OAuth authentication. Once authenticated Meteor uses sessions to maintain a logged in state, whereas Feathers keeps things stateless and uses [JSON Web Tokens](https://jwt.io/) (JWT) to assess authentication state.\n\nOne big distinction is how Feathers and Meteor provide real-time across a cluster of apps. Feathers does it at the service layer or using another pub-sub service like Redis whereas Meteor relies on having access to and monitoring MongoDB operation logs as the central hub for real-time communication."
  },
  {
    "path": "docs/feathers-vs-nest.md",
    "content": "# Feathers vs Nest\n\nNest is a backend framework that have similar capabilities with Feathers.\n\nNest uses dependency injection system and a module based architecture, Feathers uses service based architecture with a more functional approach.\n\nNest can only be written in TypeScript whereas Feathers supports JavaScript and TypeScript.\n\nFeathers can generate client code for its server, Nest can't.\n\nNest uses RxJS for running interceptors, guards, filters or validation pipes. Feathers uses before, after and around hooks.\n\nFor more details on the difference between them you can read more here: [FeathersJS vs NestJS - Compared In 3 Key Areas](https://blog.feathersjs.com/feathersjs-vs-nestjs-compared-in-3-key-areas-427def783555)\n"
  },
  {
    "path": "docs/feathers-vs-sails.md",
    "content": "# Feathers vs Sails\n\nFrom a feature standpoint, Feathers and Sails are probably the most similar of the comparisons offered here. Both provide real-time REST API's, multiple DB support, and are client-agnostic. Sails is bound to the server whereas Feathers can also be used in the browser and in React Native apps. Both frameworks use Express, with Feathers supporting the latest Express 4, while Sails supports Express 3.\n\nSails follows the MVC pattern while Feathers provides lightweight services to define your resources. Feathers uses hooks to define your business logic including validations, security policies, and serialization in reusable, chainable modules, whereas with Sails, these reside in more of a configuration file format.\n\nFeathers supports multiple ORMs while Sails only supports its own Waterline ORM.\n\nSails allows you to receive messages via websockets on the client, but, unlike Feathers, does not directly support data being sent from the client to the server over websockets. Additionally, Sails uses Socket.io for its websocket transport. Feathers also supports Socket.io but also many other socket implementations and transports.\n\nEven though the features are very similar, Feathers achieves this with much less code. Feathers also doesn't assume how you want to manage your assets or that you even have any (because you might be making a JSON API). Instead of coming bundled with Grunt, Feathers lets you use your build tool of choice.\n\nSails doesn't come with any built-in authentication support. Instead, it offers guides on how to configure Passport. By contrast, Feathers supports an official authentication plugin that is a drop-in, minimal configuration, module that provides email/password, token, and OAuth authentication much more like Meteor. Using this you can authenticate using those providers over ANY transport - HTTP, Websockets, and others.\n\nScaling a Sails app is as simple as deploying your large app multiple times behind a load balancer with some pub-sub mechanism like Redis. With Feathers you can do the same but you also have the option to mount sub-apps more like Express, spin up additional services in the same app, or split your services into small standalone microservice applications."
  },
  {
    "path": "docs/guides/basics/authentication.md",
    "content": "---\noutline: deep\n---\n\n# Authentication\n\nAuthentication is an important aspect of any web application that involves user accounts. It allows users to log in and prove their identity, which is critical for keeping the application secure and ensuring that only authorized users can access sensitive information or perform certain actions.\n\nThe Feathers CLI allows to easily add authentication to our application, including features such as creating and verifying tokens, storing and retrieving user credentials securely, and implementing OAuth-based authentication with third-party providers. The following authentication strategies are included:\n\n- __JWT__ for authenticating a request with a [JSON Web Token](https://jwt.io/). It is an access token that is issued by the Feathers server for a limited time (one day by default). When someone logs in, Feathers issues a JWT that they need to include with every request they make to the application.\n- __Local Authentication__ allows someone to log in and create a JWT using a username (usually an email address) and password that they have already registered with our application. The CLI will also help you set up a database to store this information securely.\n- __OAuth Authentication__ allows someone to log in using their account from a third-party provider like Google, GitHub, or Twitter. The Feathers CLI can set this up too.\n\n## Generating authentication\n\nTo initialize a standard authentication setup we can run\n\n```\nnpx feathers generate authentication\n```\n\nFor the first prompt, let's select GitHub in addition to _Email + Password_ by navigating to it with the arrow down key and then pressing space. All other questions can be answered with the default by pressing enter:\n\n<DatabaseBlock global-id=\"sql\">\n\n![feathers generate authentication prompts](./assets/generate-authentication.png)\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\n![feathers generate authentication prompts](./assets/generate-authentication-mongodb.png)\n\n</DatabaseBlock>\n\n\n\n## What's next?\n\nBy running this command we set up a `users` endpoint to register and store users and an `authentication` endpoint to log them in. It also generated everything necessary for a log in via GitHub. \n\nIf you're not familiar with how the authentication process works, don't worry. We'll cover that in the [Logging In](./login.md) chapter of this guide but first let's look at Feathers [core concepts of services](./services.md) that our new `users` endpoint already uses.\n"
  },
  {
    "path": "docs/guides/basics/generator.md",
    "content": "---\noutline: deep\n---\n\n# Creating an app\n\nIn the [quick start](./starting.md) we created a Feathers application in a single file to get a better understanding of how Feathers itself works.\n\n<img style=\"margin: 2em;\" src=\"/img/main-character-coding.svg\" alt=\"Getting started\">\n\nThe [Feathers CLI](../cli/index.md) allows us to initialize a new Feathers server with a recommended structure and generate things we commonly need like authentication, a database connection or new services. In this guide we will create a Feathers HTTP and real-time API for a chat application using the Feathers CLI. Using it, for example with [a JavaScript frontend](../frontend/javascript.md), looks like this:\n\n![The Feathers chat application](../basics/assets/feathers-chat.png)\n\nYou can find the complete example in the [feathers-chat repository](https://github.com/feathersjs/feathers-chat).\n\n## Generating the application\n\nYou can create a new Feathers application by running `npm create feathers <name>`. To create a new Feathers application called `feathers-chat` we can run:\n\n```sh\nnpm create feathers@latest feathers-chat\n```\n\nIf you never ran the command before you might be asked to confirm the package installation by pressing enter. The `@latest` in the command makes sure that the most recent released version of the CLI is used.\n\n<BlockQuote type=\"warning\" label=\"Note\">\n\nSince the generated application is using modern features like ES modules, the Feathers CLI requires __Node 16 or newer__.\n\n</BlockQuote>\n\nFirst, choose if you want to use JavaScript or TypeScript. When presented with the project name, just hit enter, or enter a name (no spaces). Next, write a short description for your application. Confirm the next questions with the default selection by pressing Enter. If you choose a database other than __SQLite__, make sure it is reachable at the connection string. For following this guide using MongoDB, change the database selection in the dropdown below.\n\n<DatabaseSelect />\n<hr />\n\nOnce you confirm the last prompt, the final selection should look similar to this:\n\n<DatabaseBlock global-id=\"sql\">\n\n![feathers generate app prompts](./assets/generate-app.png)\n\n<BlockQuote type=\"info\" label=\"Note\">\n\n`SQLite` creates an SQL database in a file so we don't need to have a database server running.\n\n</BlockQuote>\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\n![feathers generate app prompts](./assets/generate-app-mongodb.png)\n\n</DatabaseBlock>\n\nSweet! We generated our first Feathers application in a new folder called `feathers-chat` so we need to go there.\n\n```sh\ncd feathers-chat\n```\n\n<BlockQuote type=\"tip\">\n\nMost generated files have a page in the [CLI guide](../cli/index.md) which contains more information about the file and what it does.\n\n</BlockQuote>\n\n## Running the server and tests\n\nThe server can be started by running\n\n<LanguageBlock global-id=\"ts\">\n\n<DatabaseBlock global-id=\"sql\">\n\n```sh\nnpm run compile\nnpm run migrate\nnpm start\n```\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\n```sh\nnpm run compile\nnpm start\n```\n\n</DatabaseBlock>\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\n```sh\nnpm start\n```\n\n</LanguageBlock>\n\nAfter that, you will see the Feathers logo at\n\n```\nhttp://localhost:3030\n```\n\n<BlockQuote type=\"warning\" label=\"Note\">\n\nYou can exit the running process by pressing **CTRL + C**\n\n</BlockQuote>\n\nThe app also comes with a set of basic tests which can be run with\n\n```sh\nnpm test\n```\n\nThere is also a handy development command that restarts the server automatically whenever we make a code change:\n\n```sh\nnpm run dev\n```\n\n<BlockQuote type=\"warning\" label=\"Note\">\n\nKeep this command running throughout the rest of this guide so it will reload all our changes automatically.\n\n</BlockQuote>\n\n## What's next?\n\nIn this chapter, we've created a new Feathers application. To learn more about the generated files and what you can do with the CLI, have a look at the [CLI guide](../cli/index.md) after finishing the Getting Started guide. In [the next chapter](./authentication.md) we will set up user authentication.\n"
  },
  {
    "path": "docs/guides/basics/hooks.md",
    "content": "---\noutline: deep\n---\n\n# Hooks\n\nWhen we created our messages service in [the services chapter](./services.md), we saw that Feathers services are a great way to implement data storage and modification. Technically, we could write our entire app with services but very often we need similar functionality across multiple services. For example, we might want to check for all services if a user is allowed to access it. With just services, we would have to write this every time.\n\nThis is where Feathers hooks come in. Hooks are pluggable middleware functions that can be registered **around**, **before**, **after** or on **errors** of a service method without changing the original code.\n\nJust like services themselves, hooks are _transport independent_. They are usually also service independent, meaning they can be used with ​*any*​ service. This pattern keeps your application logic flexible, composable, and much easier to trace through and debug.\nHooks are commonly used to handle things like validation, authorization, logging, sending emails and more.\n\n<BlockQuote type=\"tip\">\n\nA full overview of the hook API can be found in the [hooks API documentation](../../api/hooks.md). For the general design pattern behind hooks see [this blog post](https://blog.feathersjs.com/design-patterns-for-modern-web-apis-1f046635215).\n\n</BlockQuote>\n\n## Generating a hook\n\nLet's generate a hook that logs the total runtime of a service method to the console.\n\n```sh\nnpx feathers generate hook\n```\n\nWe call our hook `log-runtime` and confirm the type with enter to make it an `around` hook.\n\n![feathers generate hook prompts](./assets/generate-hook.png)\n\n<LanguageBlock global-id=\"ts\">\n\nNow update `src/hooks/log-runtime.ts` as follows:\n\n</LanguageBlock>\n<LanguageBlock global-id=\"js\">\n\nNow update `src/hooks/log-runtime.js` as follows:\n\n</LanguageBlock>\n\n```ts{2,5-10}\nimport type { HookContext, NextFunction } from '../declarations'\nimport { logger } from '../logger'\n\nexport const logRuntime = async (context: HookContext, next: NextFunction) => {\n  const startTime = Date.now()\n  // Run everything else (other hooks and service call)\n  await next()\n\n  const duration = Date.now() - startTime\n  logger.info(`Calling ${context.method} on ${context.path} took ${duration}ms`)\n}\n\n```\n\nIn this hook, we store the start time and then run all other hooks and the service method by calling `await next()`. After that we can calculate the duration in milliseconds by subtracting the start time from the current time and log the information using the application [logger](../cli/logger.md).\n\n## Hook functions\n\nA hook function is an `async` function that takes the [hook `context`](#hook-context) and a `next` function as the parameter. If the hook should only run on **error**, **before** or **after** the service method, it does not need a `next` function. However since we need to do both, get the start time before and the end time after, we created an `around` hook.\n\nHooks run in the order they are registered and if a hook function throws an error, all remaining hooks (and the service call if it didn't run yet) will be skipped and the error will be returned.\n\n## Hook context\n\nThe hook `context` is an object which contains information about the service method call. It has read-only and writable properties.\n\nRead-only properties are:\n\n- `context.app` - The Feathers application object. This commonly used to call other services\n- `context.service` - The service object this hook is currently running on\n- `context.path` - The path (name) of the service\n- `context.method` - The name of the service method being called\n- `context.type` - The hook type (around, before, etc)\n\nWriteable properties are:\n\n- `context.params` - The service method call `params`. For external calls, `params` usually contains:\n  - `context.params.query` - The query filter (e.g. from the REST query string) for the service call\n  - `context.params.provider` - The name of the transport the call has been made through. Usually `\"rest\"` or `\"socketio\"`. Will be `undefined` for internal calls.\n  - `context.params.user` - _If authenticated_, the data of the user making the service method call.\n- `context.id` - The `id` of the record if the service method call is a `get`, `remove`, `update` or `patch`\n- `context.data` - The `data` sent by the user in a `create`, `update` and `patch` and custom service method call\n- `context.error` - The error that was thrown (in `error` hooks)\n- `context.result` - The result of the service method call (available after calling `await next()` or in `after` hooks)\n\n<BlockQuote type=\"tip\">\n\nFor more information about the hook context see the [hooks API documentation](../../api/hooks.md).\n\n</BlockQuote>\n\n## Registering hooks\n\nIn a Feathers application, hooks are being registered in the [&lt;servicename&gt;](../cli/service.md) file. The hook registration object is an object with `{ around, before, after, error }` and a list of hooks per method like `{ all: [], find: [], create: [] }`.\n\n<LanguageBlock global-id=\"ts\">\n\nTo log the runtime of our `messages` service calls we can update `src/services/messages/messages.ts` like this:\n\n</LanguageBlock>\n<LanguageBlock global-id=\"js\">\n\nTo log the runtime of all `messages` service calls we can update `src/services/messages/messages.js` like this:\n\n</LanguageBlock>\n\n```ts{20,38}\n// For more information about this file see https://dove.feathersjs.com/guides/cli/service.html\nimport { authenticate } from '@feathersjs/authentication'\n\nimport { hooks as schemaHooks } from '@feathersjs/schema'\n\nimport {\n  messageDataValidator,\n  messagePatchValidator,\n  messageQueryValidator,\n  messageResolver,\n  messageExternalResolver,\n  messageDataResolver,\n  messagePatchResolver,\n  messageQueryResolver\n} from './messages.schema'\n\nimport type { Application } from '../../declarations'\nimport { MessageService, getOptions } from './messages.class'\nimport { messagePath, messageMethods } from './messages.shared'\nimport { logRuntime } from '../../hooks/log-runtime'\n\nexport * from './messages.class'\nexport * from './messages.schema'\n\n// A configure function that registers the service and its hooks via `app.configure`\nexport const message = (app: Application) => {\n  // Register our service on the Feathers application\n  app.use(messagePath, new MessageService(getOptions(app)), {\n    // A list of all methods this service exposes externally\n    methods: messageMethods,\n    // You can add additional custom events to be sent to clients here\n    events: []\n  })\n  // Initialize hooks\n  app.service(messagePath).hooks({\n    around: {\n      all: [\n        logRuntime,\n        authenticate('jwt'),\n        schemaHooks.resolveExternal(messageExternalResolver),\n        schemaHooks.resolveResult(messageResolver)\n      ]\n    },\n    before: {\n      all: [schemaHooks.validateQuery(messageQueryValidator), schemaHooks.resolveQuery(messageQueryResolver)],\n      find: [],\n      get: [],\n      create: [schemaHooks.validateData(messageDataValidator), schemaHooks.resolveData(messageDataResolver)],\n      patch: [schemaHooks.validateData(messagePatchValidator), schemaHooks.resolveData(messagePatchResolver)],\n      remove: []\n    },\n    after: {\n      all: []\n    },\n    error: {\n      all: []\n    }\n  })\n}\n\n// Add this service to the service type index\ndeclare module '../../declarations' {\n  interface ServiceTypes {\n    [messagePath]: MessageService\n  }\n}\n```\n\nNow every time our messages service is accessed successfully, the name, method and runtime will be logged.\n\n<BlockQuote type=\"tip\">\n\n`all` is a special keyword which means those hooks will run before the method specific hooks. Method specific hooks can be registered based on their name, e.g. to only log the runtime for `find` and `get`:\n\n```ts\napp.service('messages').hooks({\n  around: {\n    all: [authenticate('jwt')],\n    find: [logRuntime],\n    get: [logRuntime]\n  }\n  // ...\n})\n```\n\n</BlockQuote>\n\n## What's next?\n\nIn this chapter we learned how Feathers hooks can be used as middleware for service method calls without having to change our service. Here we just logged the runtime of a service method to the console but you can imagine that hooks can be useful for many other things like more advanced logging, sending notifications or checking user permissions.\n\nYou may also have noticed above that there are already some hooks like `schemaHooks.validateQuery` or `schemaHooks.resolveResult` registered on our service. This brings us to the next chapter on how to define our data model with [schemas and resolvers](./schemas.md).\n"
  },
  {
    "path": "docs/guides/basics/login.md",
    "content": "# Logging in\n\nWe now have a fully functional chat application consisting of [services](./services.md) and [schemas](./schemas.md). In the [authentication chapter](./authentication.md) we generated everything necessary for using Feathers authentication so let's look at how to register users and add a log in with GitHub to our chat.\n\n## Registering a user\n\nThe HTTP REST API can be used directly to register a new user. We can do this by sending a POST request to `http://localhost:3030/users` with JSON data like this as the body:\n\n```js\n// POST /users\n{\n  \"email\": \"hello@feathersjs.com\",\n  \"password\": \"supersecret\"\n}\n```\n\nTry it:\n\n```sh\ncurl 'http://localhost:3030/users/' \\\n  -H 'Content-Type: application/json' \\\n  --data-binary '{ \"email\": \"hello@feathersjs.com\", \"password\": \"supersecret\" }'\n```\n\n[![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/6bcea48aac6c7494c2ad)\n\n<BlockQuote type=\"info\">\n\nFor SQL databases, creating a user with the same email address will only work once, then fail since it already exists. With the default database selection, you can reset your database by removing the `feathers-chat.sqlite` file and running `npm run migrate` to initialise it again.\n\n</BlockQuote>\n\nThis will return something like this:\n\n<DatabaseBlock global-id=\"sql\">\n\n```json\n{\n  \"id\": 123,\n  \"email\": \"hello@feathersjs.com\",\n  \"avatar\": \"https://s.gravatar.com/avatar/ffe2a09df37d7c646e974a2d2b8d3e03?s=60\"\n}\n```\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\n```json\n{\n  \"_id\": \"63c00098502debdeec31bd77\",\n  \"email\": \"hello@feathersjs.com\",\n  \"avatar\": \"https://s.gravatar.com/avatar/ffe2a09df37d7c646e974a2d2b8d3e03?s=60\"\n}\n```\n\n</DatabaseBlock>\n\nWhich means our user has been created successfully.\n\n<BlockQuote type=\"info\">\n\nThe password has been hashed and stored securely in the database but will never be included in an external response.\n\n</BlockQuote>\n\n## Logging in\n\nBy default, Feathers uses [JSON Web Tokens](https://jwt.io/) for authentication. It is an access token that is issued by the Feathers server for a limited time (one day by default) and needs to be sent with every API request that requires authentication. Usually a token is issued for a specific user. Let's see if we can issue a JWT for the user that we just created.\n\n<BlockQuote type=\"tip\">\n\nIf you are wondering why Feathers is using JWT for authentication, have a look at [this FAQ](../../help/faq.md#why-are-you-using-jwt-for-sessions).\n\n</BlockQuote>\n\nTokens can be created by sending a POST request to the `/authentication` endpoint (which is the same as calling the `create` method on the `authentication` service set up in `src/authentication`) and passing the authentication strategy you want to use along with any other relevant data. To get a JWT for an existing user through a username (email) and password login, we can use the built-in `local` authentication strategy with a request like this:\n\n```js\n// POST /authentication\n{\n  \"strategy\": \"local\",\n  \"email\": \"hello@feathersjs.com\",\n  \"password\": \"supersecret\"\n}\n```\n\nTry it:\n\n```sh\ncurl 'http://localhost:3030/authentication/' \\\n  -H 'Content-Type: application/json' \\\n  --data-binary '{ \"strategy\": \"local\", \"email\": \"hello@feathersjs.com\", \"password\": \"supersecret\" }'\n```\n\n[![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/6bcea48aac6c7494c2ad)\n\nThis will return something like this:\n\n<DatabaseBlock global-id=\"sql\">\n\n```json\n{\n  \"accessToken\": \"<JWT for this user>\",\n  \"authentication\": {\n    \"strategy\": \"local\"\n  },\n  \"user\": {\n    \"id\": 123,\n    \"email\": \"hello@feathersjs.com\",\n    \"avatar\": \"https://s.gravatar.com/avatar/ffe2a09df37d7c646e974a2d2b8d3e03?s=60\"\n  }\n}\n```\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\n```json\n{\n  \"accessToken\": \"<JWT for this user>\",\n  \"authentication\": {\n    \"strategy\": \"local\"\n  },\n  \"user\": {\n    \"_id\": \"63c00098502debdeec31bd77\",\n    \"email\": \"hello@feathersjs.com\",\n    \"avatar\": \"https://s.gravatar.com/avatar/ffe2a09df37d7c646e974a2d2b8d3e03?s=60\"\n  }\n}\n```\n\n</DatabaseBlock>\n\nThe `accessToken` can now be used for other REST requests that require authentication by sending the `Authorization: Bearer <accessToken>` HTTP header. For example to create a new message:\n\n```sh\ncurl 'http://localhost:3030/messages/' \\\n  -H 'Content-Type: application/json' \\\n  -H 'Authorization: Bearer <accessToken>' \\\n  --data-binary '{ \"text\": \"Hello from the console\" }'\n```\n\n<BlockQuote type=\"tip\">\n\nMake sure to replace the `<accessToken>` in the above request. For more information about the direct usage of the REST API see the [REST client API](../../api/client/rest.md) and for websockets the [Socket.io client API](../../api/client/socketio.md).\n\n</BlockQuote>\n\nThat's pretty neat, but emails and passwords are boring, let's spice things up a bit.\n\n## Login with GitHub\n\nOAuth is an open authentication standard supported by almost every major social platform and what gets us the log in with Facebook, Google, GitHub etc. buttons. From the Feathers perspective, the authentication flow with OAuth is pretty similar. Instead of authenticating with the `local` strategy by sending a username and password, Feathers directs the user to authorize the application with the login provider. If it is successful, Feathers authentication finds or creates the user in the `users` service with the information it got back from the provider and then issues a token for them.\n\nTo allow login with GitHub, we first have to [create a new OAuth application on GitHub](https://github.com/settings/applications/new). You can put anything in the name, homepage and description fields. The callback URL **must** be set to\n\n```sh\nhttp://localhost:3030/oauth/github/callback\n```\n\n![Screenshot of the GitHub application screen](./assets/github-app.png)\n\n<BlockQuote type=\"info\">\n\nYou can find your existing applications in the [GitHub OAuth apps developer settings](https://github.com/settings/developers).\n\n</BlockQuote>\n\nOnce you've clicked \"Register application\", we need to update our Feathers app configuration with the client id and secret copied from the GitHub application settings.\n\nFind the `authentication` section in `config/default.json` replace the `<Client ID>` and `<Client Secret>` in the `github` section with the proper values:\n\n```js\n{\n  \"authentication\": {\n    \"oauth\": {\n      \"github\": {\n        \"key\": \"<Client ID>\",\n        \"secret\": \"<Client Secret>\"\n      }\n    },\n    // Other authentication configuration is here\n    // ...\n  }\n}\n```\n\n<BlockQuote type=\"info\" label=\"note\">\n\nIn a production environment you would set those values as [custom environment variables](../cli/custom-environment-variables.md).\n\n</BlockQuote>\n\nThis tells the OAuth strategy to redirect back to our index page after a successful login and already makes a basic login with GitHub possible. Because of the changes we made in the `users` service in the [services chapter](./services.md) we do need a small customization though. Instead of only adding `githubId` to a new user when they log in with GitHub we also include their email and the avatar image from the profile we get back. We can do this by extending the standard OAuth strategy and registering it as a GitHub specific one and overwriting the `getEntityData` method:\n\nUpdate `src/authentication.ts` as follows:\n\n```ts{1,5,14-26,33}\nimport type { Params } from '@feathersjs/feathers'\nimport { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'\nimport { LocalStrategy } from '@feathersjs/authentication-local'\nimport { oauth, OAuthStrategy } from '@feathersjs/authentication-oauth'\nimport type { OAuthProfile } from '@feathersjs/authentication-oauth'\nimport type { Application } from './declarations'\n\ndeclare module './declarations' {\n  interface ServiceTypes {\n    authentication: AuthenticationService\n  }\n}\n\nclass GitHubStrategy extends OAuthStrategy {\n  async getEntityData(profile: OAuthProfile, existing: any, params: Params) {\n    const baseData = await super.getEntityData(profile, existing, params)\n\n    return {\n      ...baseData,\n      // The GitHub profile image\n      avatar: profile.avatar_url,\n      // The user email address (if available)\n      email: profile.email || profile.login\n    }\n  }\n}\n\nexport const authentication = (app: Application) => {\n  const authentication = new AuthenticationService(app)\n\n  authentication.register('jwt', new JWTStrategy())\n  authentication.register('local', new LocalStrategy())\n  authentication.register('github', new GitHubStrategy())\n\n  app.use('authentication', authentication)\n  app.configure(oauth())\n}\n```\n\n<BlockQuote type=\"info\">\n\nFor more information about the OAuth flow and strategy see the [OAuth API documentation](../../api/authentication/oauth.md).\n\n</BlockQuote>\n\nTo log in with GitHub, visit\n\n```\nhttp://localhost:3030/oauth/github\n```\n\nIt will redirect to GitHub and ask to authorize our application. If everything went well, we get redirected to our homepage with the Feathers logo with the token information in the location hash. This will be used by the Feathers authentication client to authenticate our user.\n\n## What's next?\n\nSweet! We now have an API that can register new users with email/password and GitHub. This means we have everything we need for a frontend for our chat application. See the [JavaScript frontend guide](../frontend/javascript.md) on how to create a plain JavaScript chat application.\n"
  },
  {
    "path": "docs/guides/basics/schemas.md",
    "content": "# Schemas and resolvers\n\nIn Feathers, schemas and resolvers allow us to define, validate and secure our data model and types.\n\n<img style=\"margin: 2em;\" src=\"/img/professor-bird-server.svg\" alt=\"Professor bird at work\">\n\nAs we've briefly seen in the [previous chapter about hooks](./hooks.md), there were a few hooks registered already to validate schemas and resolve data. Schema validators and resolvers are used with those hooks to modify data in the hook context. Similar to how Feathers services are transport independent, schemas and resolvers are database independent. It comes in two main parts:\n\n- [TypeBox](../../api/schema/typebox.md) or [JSON schema](../../api/schema/schema.md) to define a schema. This allows us to do things like:\n  - Ensure data is valid and always in the right format\n  - Automatically get up to date TypeScript types from schema definitions\n  - Create a typed client that can be used in React, Vue etc. apps\n  - Automatically generate API documentation\n  - Validate query string filters and convert them to the correct types\n- [Resolvers](../../api/schema/resolvers.md) - Resolve schema properties based on a context (usually the [hook context](./hooks.md)). This can be used for many different things like:\n  - Populating associations\n  - Securing queries and limiting the type of requests the logged in user can perform\n  - Safely hiding sensitive data for external clients\n  - Adding read and write permissions on the property field level\n  - Hashing passwords and validating dynamic password policies\n\nIn this chapter we will look at the generated schemas and resolvers and update them with the information we need for our chat application.\n\n## Feathers schemas\n\nWhile schemas and resolvers can be used outside of a Feathers application, you will usually encounter them in a Feathers context where they come in four kinds:\n\n- **Result** schemas and resolvers that define the data that is being returned. This is also where associated data would be fetched\n- **Data** schemas and resolvers handle the data from a `create`, `update`, `patch`, or custom service method and can be used to add/replace things like default or calculated values (e.g. the `createdAt` or `updatedAt` date) before saving it to the database\n- **Query** schemas and resolvers validate and convert the query string and can also be used for additional limitations like only allowing a user to see and modify their own data\n- **External** resolvers return a safe version of the data (by e.g. hiding a users password) that can be sent to external clients\n\nWhile it may initially look like a bit more code, schema driven development is a great way to have the data models and how data is modified in a single place.\n\n## Adding a user avatar\n\nLet's extend our existing users schema to add an `avatar` property so that our users can have a profile image.\n\n<LanguageBlock global-id=\"ts\">\n\nFirst we need to update the `src/services/users/users.schema.ts` file with the schema property for the avatar and a resolver property that sets a default avatar using the [Gravatar](https://en.gravatar.com/) based on the email address:\n\n</LanguageBlock>\n<LanguageBlock global-id=\"js\">\n\nFirst we need to update the `src/services/users/users.schema.js` file with the schema property for the avatar and a resolver property that sets a default avatar using the [Gravatar](https://en.gravatar.com/) based on the email address:\n\n</LanguageBlock>\n\n<DatabaseBlock global-id=\"sql\">\n\n```ts{2,17-18,34,44-54,68,82-86}\n// For more information about this file see https://dove.feathersjs.com/guides/cli/service.schemas.html\nimport crypto from 'crypto'\nimport { resolve } from '@feathersjs/schema'\nimport { Type, getValidator, querySyntax } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\nimport { passwordHash } from '@feathersjs/authentication-local'\n\nimport type { HookContext } from '../../declarations'\nimport { dataValidator, queryValidator } from '../../validators'\n\n// Main data model schema\nexport const userSchema = Type.Object(\n  {\n    id: Type.Number(),\n    email: Type.String(),\n    password: Type.Optional(Type.String()),\n    githubId: Type.Optional(Type.Number()),\n    avatar: Type.Optional(Type.String())\n  },\n  { $id: 'User', additionalProperties: false }\n)\nexport type User = Static<typeof userSchema>\nexport const userValidator = getValidator(userSchema, dataValidator)\nexport const userResolver = resolve<User, HookContext>({})\n\nexport const userExternalResolver = resolve<User, HookContext>({\n  // The password should never be visible externally\n  password: async () => undefined\n})\n\n// Schema for creating new users\nexport const userDataSchema = Type.Pick(\n  userSchema,\n  ['email', 'password', 'githubId', 'avatar'],\n  {\n    $id: 'UserData',\n    additionalProperties: false\n  }\n)\nexport type UserData = Static<typeof userDataSchema>\nexport const userDataValidator = getValidator(userDataSchema, dataValidator)\nexport const userDataResolver = resolve<User, HookContext>({\n  password: passwordHash({ strategy: 'local' }),\n  avatar: async (value, user) => {\n    // If the user passed an avatar image, use it\n    if (value !== undefined) {\n      return value\n    }\n\n    // Gravatar uses MD5 hashes from an email address to get the image\n    const hash = crypto.createHash('md5').update(user.email.toLowerCase()).digest('hex')\n    // Return the full avatar URL\n    return `https://s.gravatar.com/avatar/${hash}?s=60`\n  }\n})\n\n// Schema for updating existing users\nexport const userPatchSchema = Type.Partial(userSchema, {\n  $id: 'UserPatch'\n})\nexport type UserPatch = Static<typeof userPatchSchema>\nexport const userPatchValidator = getValidator(userPatchSchema, dataValidator)\nexport const userPatchResolver = resolve<User, HookContext>({\n  password: passwordHash({ strategy: 'local' })\n})\n\n// Schema for allowed query properties\nexport const userQueryProperties = Type.Pick(userSchema, ['id', 'email', 'githubId'])\nexport const userQuerySchema = Type.Intersect(\n  [\n    querySyntax(userQueryProperties),\n    // Add additional query properties here\n    Type.Object({}, { additionalProperties: false })\n  ],\n  { additionalProperties: false }\n)\nexport type UserQuery = Static<typeof userQuerySchema>\nexport const userQueryValidator = getValidator(userQuerySchema, queryValidator)\nexport const userQueryResolver = resolve<UserQuery, HookContext>({\n  // If there is a user (e.g. with authentication), they are only allowed to see their own data\n  id: async (value, user, context) => {\n    // We want to be able to get a list of all users but\n    // only let a user modify their own data otherwise\n    if (context.params.user && context.method !== 'find') {\n      return context.params.user.id\n    }\n\n    return value\n  }\n})\n```\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\n```ts{2,18-19,35,44-54,82-87}\n// // For more information about this file see https://dove.feathersjs.com/guides/cli/service.schemas.html\nimport crypto from 'crypto'\nimport { resolve } from '@feathersjs/schema'\nimport { Type, getValidator, querySyntax } from '@feathersjs/typebox'\nimport { ObjectIdSchema } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\nimport { passwordHash } from '@feathersjs/authentication-local'\n\nimport type { HookContext } from '../../declarations'\nimport { dataValidator, queryValidator } from '../../validators'\n\n// Main data model schema\nexport const userSchema = Type.Object(\n  {\n    _id: ObjectIdSchema(),\n    email: Type.String(),\n    password: Type.Optional(Type.String()),\n    githubId: Type.Optional(Type.Number()),\n    avatar: Type.Optional(Type.String())\n  },\n  { $id: 'User', additionalProperties: false }\n)\nexport type User = Static<typeof userSchema>\nexport const userValidator = getValidator(userSchema, dataValidator)\nexport const userResolver = resolve<User, HookContext>({})\n\nexport const userExternalResolver = resolve<User, HookContext>({\n  // The password should never be visible externally\n  password: async () => undefined\n})\n\n// Schema for creating new entries\nexport const userDataSchema = Type.Pick(\n  userSchema,\n  ['email', 'password', 'githubId', 'avatar'],\n  {\n    $id: 'UserData'\n  }\n)\nexport type UserData = Static<typeof userDataSchema>\nexport const userDataValidator = getValidator(userDataSchema, dataValidator)\nexport const userDataResolver = resolve<User, HookContext>({\n  password: passwordHash({ strategy: 'local' }),\n  avatar: async (value, user) => {\n    // If the user passed an avatar image, use it\n    if (value !== undefined) {\n      return value\n    }\n\n    // Gravatar uses MD5 hashes from an email address to get the image\n    const hash = crypto.createHash('md5').update(user.email.toLowerCase()).digest('hex')\n    // Return the full avatar URL\n    return `https://s.gravatar.com/avatar/${hash}?s=60`\n  }\n})\n\n// Schema for updating existing entries\nexport const userPatchSchema = Type.Partial(userSchema, {\n  $id: 'UserPatch'\n})\nexport type UserPatch = Static<typeof userPatchSchema>\nexport const userPatchValidator = getValidator(userPatchSchema, dataValidator)\nexport const userPatchResolver = resolve<User, HookContext>({\n  password: passwordHash({ strategy: 'local' })\n})\n\n// Schema for allowed query properties\nexport const userQueryProperties = Type.Pick(userSchema, ['_id', 'email', 'githubId'])\nexport const userQuerySchema = Type.Intersect(\n  [\n    querySyntax(userQueryProperties),\n    // Add additional query properties here\n    Type.Object({}, { additionalProperties: false })\n  ],\n  { additionalProperties: false }\n)\nexport type UserQuery = Static<typeof userQuerySchema>\nexport const userQueryValidator = getValidator(userQuerySchema, queryValidator)\nexport const userQueryResolver = resolve<UserQuery, HookContext>({\n  // If there is a user (e.g. with authentication), they are only allowed to see their own data\n  _id: async (value, user, context) => {\n    // We want to be able to get a list of all users but\n    // only let a user modify their own data otherwise\n    if (context.params.user && context.method !== 'find') {\n      return context.params.user._id\n    }\n\n    return value\n  }\n})\n```\n\n</DatabaseBlock>\n\nWhat happened here?\n\n- We are adding an optional `avatar` field to our user object. This is where we store a user image to show in the chat.\n- The `userDataSchema` is updated to include the `avatar` so that a new user can be created with a custom avatar\n- In the `userDataResolver`, if an `avatar` is not set, we set a default image using the [Gravatar avatar](https://en.gravatar.com/) for the email address\n- The `userQueryResolver` for the user id property allows for a user to `find` all other users but only change (`patch`, `remove`) their own data\n\n## Handling messages\n\nNext we can look at the messages service schema. We want to include the date when the message was created as `createdAt` and the id of the user who sent it as `userId`. When we get a message back, we also want to populate the `user` with the user data from `userId` so that we can show their avatar and email.\n\n<LanguageBlock global-id=\"ts\">\n\nUpdate the `src/services/messages/messages.schema.ts` file like this:\n\n</LanguageBlock>\n<LanguageBlock global-id=\"js\">\n\nUpdate the `src/services/messages/messages.schema.js` file like this:\n\n</LanguageBlock>\n\n<DatabaseBlock global-id=\"sql\">\n\n```ts{2,8,15-17,24-27,39-45,58-61,74-82}\n// For more information about this file see https://dove.feathersjs.com/guides/cli/service.schemas.html\nimport { resolve, virtual } from '@feathersjs/schema'\nimport { Type, getValidator, querySyntax } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\n\nimport type { HookContext } from '../../declarations'\nimport { dataValidator, queryValidator } from '../../validators'\nimport { userSchema } from '../users/users.schema'\n\n// Main data model schema\nexport const messageSchema = Type.Object(\n  {\n    id: Type.Number(),\n    text: Type.String(),\n    createdAt: Type.Number(),\n    userId: Type.Number(),\n    user: Type.Ref(userSchema)\n  },\n  { $id: 'Message', additionalProperties: false }\n)\nexport type Message = Static<typeof messageSchema>\nexport const messageValidator = getValidator(messageSchema, dataValidator)\nexport const messageResolver = resolve<Message, HookContext>({\n  user: virtual(async (message, context) => {\n    // Associate the user that sent the message\n    return context.app.service('users').get(message.userId)\n  })\n})\n\nexport const messageExternalResolver = resolve<Message, HookContext>({})\n\n// Schema for creating new entries\nexport const messageDataSchema = Type.Pick(messageSchema, ['text'], {\n  $id: 'MessageData'\n})\nexport type MessageData = Static<typeof messageDataSchema>\nexport const messageDataValidator = getValidator(messageDataSchema, dataValidator)\nexport const messageDataResolver = resolve<Message, HookContext>({\n  userId: async (_value, _message, context) => {\n    // Associate the record with the id of the authenticated user\n    return context.params.user.id\n  },\n  createdAt: async () => {\n    return Date.now()\n  }\n})\n\n// Schema for updating existing entries\nexport const messagePatchSchema = Type.Partial(messageSchema, {\n  $id: 'MessagePatch'\n})\nexport type MessagePatch = Static<typeof messagePatchSchema>\nexport const messagePatchValidator = getValidator(messagePatchSchema, dataValidator)\nexport const messagePatchResolver = resolve<Message, HookContext>({})\n\n// Schema for allowed query properties\nexport const messageQueryProperties = Type.Pick(messageSchema,[\n  'id',\n  'text',\n  'createdAt',\n  'userId'\n])\nexport const messageQuerySchema = Type.Intersect(\n  [\n    querySyntax(messageQueryProperties),\n    // Add additional query properties here\n    Type.Object({}, { additionalProperties: false })\n  ],\n  { additionalProperties: false }\n)\nexport type MessageQuery = Static<typeof messageQuerySchema>\nexport const messageQueryValidator = getValidator(messageQuerySchema, queryValidator)\nexport const messageQueryResolver = resolve<MessageQuery, HookContext>({\n  userId: async (value, user, context) => {\n    // We want to be able to find all messages but\n    // only let a user modify their own messages otherwise\n    if (context.params.user && context.method !== 'find') {\n      return context.params.user.id\n    }\n\n    return value\n  }\n})\n```\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\n```ts{2,9,16-18,25-28,40-46,59-62,75-83}\n// // For more information about this file see https://dove.feathersjs.com/guides/cli/service.schemas.html\nimport { resolve, virtual } from '@feathersjs/schema'\nimport { Type, getValidator, querySyntax } from '@feathersjs/typebox'\nimport { ObjectIdSchema } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\n\nimport type { HookContext } from '../../declarations'\nimport { dataValidator, queryValidator } from '../../validators'\nimport { userSchema } from '../users/users.schema'\n\n// Main data model schema\nexport const messageSchema = Type.Object(\n  {\n    _id: ObjectIdSchema(),\n    text: Type.String(),\n    createdAt: Type.Number(),\n    userId: Type.String({ objectid: true }),\n    user: Type.Ref(userSchema)\n  },\n  { $id: 'Message', additionalProperties: false }\n)\nexport type Message = Static<typeof messageSchema>\nexport const messageValidator = getValidator(messageSchema, dataValidator)\nexport const messageResolver = resolve<Message, HookContext>({\n  user: virtual(async (message, context) => {\n    // Associate the user that sent the message\n    return context.app.service('users').get(message.userId)\n  })\n})\n\nexport const messageExternalResolver = resolve<Message, HookContext>({})\n\n// Schema for creating new entries\nexport const messageDataSchema = Type.Pick(messageSchema, ['text'], {\n  $id: 'MessageData'\n})\nexport type MessageData = Static<typeof messageDataSchema>\nexport const messageDataValidator = getValidator(messageDataSchema, dataValidator)\nexport const messageDataResolver = resolve<Message, HookContext>({\n  userId: async (_value, _message, context) => {\n    // Associate the record with the id of the authenticated user\n    return context.params.user._id\n  },\n  createdAt: async () => {\n    return Date.now()\n  }\n})\n\n// Schema for updating existing entries\nexport const messagePatchSchema = Type.Partial(messageSchema, {\n  $id: 'MessagePatch'\n})\nexport type MessagePatch = Static<typeof messagePatchSchema>\nexport const messagePatchValidator = getValidator(messagePatchSchema, dataValidator)\nexport const messagePatchResolver = resolve<Message, HookContext>({})\n\n// Schema for allowed query properties\nexport const messageQueryProperties = Type.Pick(messageSchema, ['_id', 'text', 'createdAt', 'userId'])\nexport const messageQuerySchema = Type.Intersect(\n  [\n    querySyntax(messageQueryProperties),\n    // Add additional query properties here\n    Type.Object({}, { additionalProperties: false })\n  ],\n  { additionalProperties: false }\n)\nexport type MessageQuery = Static<typeof messageQuerySchema>\nexport const messageQueryValidator = getValidator(messageQuerySchema, queryValidator)\nexport const messageQueryResolver = resolve<MessageQuery, HookContext>({\n  userId: async (value, user, context) => {\n    // We want to be able to find all messages but\n    // only let a user modify their own messages otherwise\n    if (context.params.user && context.method !== 'find') {\n      return context.params.user._id\n    }\n\n    return value\n  }\n})\n```\n\n</DatabaseBlock>\n\n<BlockQuote type=\"info\">\n\nThe `virtual()` in the `messageResolver` `user` property is a [virtual property](../../api/schema/resolvers.md#virtual-property-resolvers) and indicates that the value does not come from the messages database table.\n\n</BlockQuote>\n\n## Creating a migration\n\n<DatabaseBlock global-id=\"sql\">\n\nNow that our schemas and resolvers have everything we need, we also have to update the database with those changes. For SQL databases this is done with migrations. Migrations are a best practice for SQL databases to roll out and undo changes to the data model. Every change we make in a schema will need its corresponding migration step.\n\nInitially, every database service will automatically add a migration that creates a table for it with an `id` and `text` property. Our users service also already added a migration to add the email and password fields for logging in. The migration for the changes we made in this chapter needs to\n\n- Add the `avatar` string field to the `users` table\n- Add the `createdAt` number field to the `messages` table\n- Add the `userId` number field to the `messages` table and reference it with the `id` in the `users` table\n\nTo create a new migration with the name `chat` run\n\n```\nnpm run migrate:make -- chat\n```\n\nYou should see something like\n\n```\nCreated Migration: /path/to/feathers-chat/migrations/20220622012334_chat.(ts|js)\n```\n\nOpen that file and update it as follows\n\n```ts{4-11,15-22}\nimport type { Knex } from 'knex'\n\nexport async function up(knex: Knex): Promise<void> {\n  await knex.schema.alterTable('users', (table) => {\n    table.string('avatar')\n  })\n\n  await knex.schema.alterTable('messages', (table) => {\n    table.bigint('createdAt')\n    table.bigint('userId').references('id').inTable('users')\n  })\n}\n\nexport async function down(knex: Knex): Promise<void> {\n  await knex.schema.alterTable('users', (table) => {\n    table.dropColumn('avatar')\n  })\n\n  await knex.schema.alterTable('messages', (table) => {\n    table.dropColumn('createdAt')\n    table.dropColumn('userId')\n  })\n}\n```\n\nWe can run the migrations on the current database with\n\n```\nnpm run migrate\n```\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\n<BlockQuote type=\"tip\">\n\nFor MongoDB no migrations are necessary.\n\n</BlockQuote>\n\n</DatabaseBlock>\n\n## What's next?\n\nIn this chapter we learned about schemas and implemented all the things we need for our chat application. In the next chapter we will learn about [authentication](./authentication.md) and add a \"Login with GitHub\" button.\n"
  },
  {
    "path": "docs/guides/basics/services.md",
    "content": "---\noutline: deep\n---\n\n# Services\n\nServices are the heart of every Feathers application. You probably remember the service we made in the [quick start](./starting.md) to create and find messages. In this chapter we will dive more into services and create a database backed service for our chat messages.\n\n## Feathers services\n\nIn Feathers, a service is an object or instance of a class that implements certain methods. Services provide a way for Feathers to interact with different kinds of data sources in a uniform, protocol-independent way.\n\nFor example, you could use services to read and/or write data to one of the supported databases, interact with the file system, call a third-party API/service (such as MailGun for sending emails, Stripe for processing payments, or OpenWeatherMap for returning weather information), or even read and/or write to a completely different type of database.\n\nA standardized interface allows us to interact with the Database/API/Gnomes inside in a uniform manner across any transport protocol, be it REST, websockets, internally within the application, or Carrier Pigeon 🕊️\n\nOnce you write a service method, which usually does not do anything Feathers-specific, you can automatically use it as a REST endpoint or call it through a websocket. Feathers takes care of all the necessary boilerplate, so you can focus on writing the service method itself.\n\n### Service methods\n\nService methods are [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) methods that a service can implement. Feathers offers a set of general methods that a service can implement, these are:\n\n- `find` - Find all data (potentially matching a query)\n- `get` - Get a single data entry by its unique identifier\n- `create` - Create new data\n- `update` - Update an existing data entry by completely replacing it\n- `patch` - Update one or more data entries by merging with the new data\n- `remove` - Remove one or more existing data entries\n- `setup` - Called when the application is started\n- `teardown` - Called when the application is shut down\n\nBelow is an example of Feathers service interface as a class and basic registration on a Feathers application via [app.use(name, service[, options])](../../api/application.md#use-path-service):\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport type { Application, Id, NullableId, Params } from '@feathersjs/feathers'\n\nclass MyService {\n  async find(params: Params) {}\n  async get(id: Id, params: Params) {}\n  async create(data: any, params: Params) {}\n  async update(id: NullableId, data: any, params: Params) {}\n  async patch(id: NullableId, data: any, params: Params) {}\n  async remove(id: NullableId, params: Params) {}\n  async setup(path: string, app: Application) {}\n  async teardown(path: string, app: Application) {}\n}\n\nconst app = feathers<{ myservice: MyService }>()\n\napp.use('myservice', new MyService())\n```\n\nThe parameters for service methods are:\n\n- `id` - The unique identifier for the data\n- `data` - The data sent by the user (for `create`, `update`, `patch` and custom methods)\n- `params` - Additional parameters, for example the authenticated user or the query\n\nFor `setup` and `teardown` (which are only called once on application startup and shutdown) we have\n\n- `path` - The path the service is registered on\n- `app` - The [Feathers application](./../../api/application.md)\n\nUsually those methods can be used for most API functionality but it is also possible to add your own [custom service methods](../../api/services.md#custom-methods).\n\n<BlockQuote type=\"info\">\n\nA service does not have to implement all those methods but must have at least one. For more information about services, service methods, and parameters see the [Service API documentation](../../api/services.md).\n\n</BlockQuote>\n\nWhen used as a REST API, incoming requests get mapped automatically to their corresponding service method like this:\n\n| Service method                              | HTTP method | Path                  |\n| ------------------------------------------- | ----------- | --------------------- |\n| `service.find({ query: {} })`               | GET         | /messages             |\n| `service.find({ query: { unread: true } })` | GET         | /messages?unread=true |\n| `service.get(123)`                          | GET         | /messages/123         |\n| `service.create(body)`                      | POST        | /messages             |\n| `service.update(123, body)`                 | PUT         | /messages/123         |\n| `service.patch(123, body)`                  | PATCH       | /messages/123         |\n| `service.remove(123)`                       | DELETE      | /messages/123         |\n\n### Service events\n\nA registered service will automatically become a [NodeJS EventEmitter](https://nodejs.org/api/events.html) that sends events with the new data when a service method that modifies data (`create`, `update`, `patch` and `remove`) returns. Events can be listened to with `app.service('messages').on('eventName', data => {})`. Here is a list of the service methods and their corresponding events:\n\n| Service method     | Service event           |\n| ------------------ | ----------------------- |\n| `service.create()` | `service.on('created')` |\n| `service.update()` | `service.on('updated')` |\n| `service.patch()`  | `service.on('patched')` |\n| `service.remove()` | `service.on('removed')` |\n\nThis is how Feathers does real-time.\n\n```js\napp.service('myservice').on('created', (data) => {\n  console.log('Got created event', data)\n})\n```\n\n## Database adapters\n\nNow that we have all those service methods, we could go ahead and implement any kind of custom logic using any backend, similar to what we did in the [quick start guide](./starting.md). Very often, this means creating, reading, updating and removing data from a database.\n\nWriting all that code yourself for every service is pretty repetitive and cumbersome, which is why Feathers has a collection of pre-built services for different databases. They offer most of the basic functionality and can always be customized to your needs. Feathers database adapters support a common [usage API](../../api/databases/common.md), pagination and [querying syntax](../../api/databases/querying.md) for many popular databases. The following database adapters are maintained as part of Feathers core:\n\n- [SQL](../../api/databases/knex.md) for databases like PostgreSQL, SQLite, MySQL, MariaDB, MSSQL\n- [MongoDB](../../api/databases/mongodb.md) for MongoDB\n- [Memory](../../api/databases/memory.md) for in-memory data\n\n<BlockQuote type=\"tip\">\n\nThere are also many other community maintained database integrations which you can explore on the [ecosystem page](/ecosystem/?cat=Database&sort=downloads). Since they are not part of Feathers core, they are outside the scope of these guides.\n\n</BlockQuote>\n\nIf you went with the default selection, we will use **SQLite** which writes the database to a file and does not require any additional setup. The user service that was created when we [generated authentication](./authentication.md) is already using it.\n\n## Generating a service\n\nIn our new `feathers-chat` application, we can create database backed services with the following command:\n\n```sh\nnpx feathers generate service\n```\n\nThe name for our service is `message` (this is used for variable names etc.) and for the path we use `messages`. Anything else we can confirm with the default:\n\n<DatabaseBlock global-id=\"sql\">\n\n![feathers generate service prompts](./assets/generate-service.png)\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\n![feathers generate service prompts](./assets/generate-service-mongodb.png)\n\n</DatabaseBlock>\n\nThis is it, we now have a database backed messages service with authentication enabled.\n\n## What's next?\n\nIn this chapter we learned about services as a Feathers core concept for abstracting data operations. We also saw how a service sends events which we will use later to create real-time applications. After that, we generated a messages service. Next, we will [look at Feathers hooks](./hooks.md) as a way to create middleware for services.\n"
  },
  {
    "path": "docs/guides/basics/starting.md",
    "content": "---\noutline: deep\n---\n\n# Quick start\n\nAlright then! Let's learn Feathers. In this quick start guide we'll create our first Feathers app, an API server and a simple website to use it. You'll see how easy it is to get started with Feathers in just a single file without additional boilerplate or tooling. If you want to jump right into creating a complete application you can go to the [Creating An App](./generator.md) chapter.\n\n<img style=\"margin: 2em;\" src=\"/img/main-character-bench.svg\" alt=\"Getting started\">\n\nFeathers works with all [currently active NodeJS releases](https://github.com/nodejs/Release#release-schedule). All guides are assuming the languages features from the most current stable NodeJS release which you can get from the [NodeJS website](https://nodejs.org/en/).\n\n<BlockQuote type=\"tip\">\n\nYou can follow this guide on your own computer in the terminal or try the steps out live without installing anything in the [Feathers Quick Start on Stackblitz](https://stackblitz.com/@daffl/collections/feathers-quick-start).\n\n</BlockQuote>\n\nAfter successful installation, the `node` and `npm` commands should be available on the terminal:\n\n```\nnode --version\n```\n\n```\nnpm --version\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nRunning NodeJS and npm should not require admin or root privileges.\n\n</BlockQuote>\n\nLet's create a new folder for our application:\n\n```sh\nmkdir feathers-basics\ncd feathers-basics\n```\n\nSince any Feathers application is a Node application, we can create a default [package.json](https://docs.npmjs.com/files/package.json) using `npm`:\n\n<LanguageBlock global-id=\"ts\">\n\n```sh\nnpm init --yes\n# Install TypeScript and its NodeJS wrapper\nnpm i typescript ts-node @types/node --save-dev\n# Also initialize a TS configuration file that uses modern JavaScript\nnpx tsc --init --target es2020\n```\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\n```sh\nnpm init --yes\n```\n\n</LanguageBlock>\n\n## Installing Feathers\n\nFeathers can be installed like any other Node module by installing the [@feathersjs/feathers](https://www.npmjs.com/package/@feathersjs/feathers) package through [npm](https://www.npmjs.com). The same package can also be used with module loaders like Vite, Webpack, and in React Native.\n\n```sh\nnpm install @feathersjs/feathers --save\n```\n\n<BlockQuote label=\"note\">\n\nAll Feathers core modules are in the `@feathersjs` namespace.\n\n</BlockQuote>\n\n## Our first app\n\nNow we can create a Feathers application with a simple `messages` service that allows us to create new messages and find all existing ones.\n\n<LanguageBlock global-id=\"ts\">\n\nCreate a file called `app.ts` with the following content:\n\n</LanguageBlock>\n<LanguageBlock global-id=\"js\">\n\nCreate a file called `app.mjs` with the following content:\n\n</LanguageBlock>\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\n\n// This is the interface for the message data\ninterface Message {\n  id?: number\n  text: string\n}\n\n// A messages service that allows us to create new\n// and return all existing messages\nclass MessageService {\n  messages: Message[] = []\n\n  async find() {\n    // Just return all our messages\n    return this.messages\n  }\n\n  async create(data: Pick<Message, 'text'>) {\n    // The new message is the data text with a unique identifier added\n    // using the messages length since it changes whenever we add one\n    const message: Message = {\n      id: this.messages.length,\n      text: data.text\n    }\n\n    // Add new message to the list\n    this.messages.push(message)\n\n    return message\n  }\n}\n\n// This tells TypeScript what services we are registering\ntype ServiceTypes = {\n  messages: MessageService\n}\n\nconst app = feathers<ServiceTypes>()\n\n// Register the message service on the Feathers application\napp.use('messages', new MessageService())\n\n// Log every time a new message has been created\napp.service('messages').on('created', (message: Message) => {\n  console.log('A new message has been created', message)\n})\n\n// A function that creates messages and then logs\n// all existing messages on the service\nconst main = async () => {\n  // Create a new message on our message service\n  await app.service('messages').create({\n    text: 'Hello Feathers'\n  })\n\n  // And another one\n  await app.service('messages').create({\n    text: 'Hello again'\n  })\n\n  // Find all existing messages\n  const messages = await app.service('messages').find()\n\n  console.log('All messages', messages)\n}\n\nmain()\n```\n\n<LanguageBlock global-id=\"ts\">\n\nWe can run it with\n\n```sh\nnpx ts-node app.ts\n```\n\n</LanguageBlock>\n<LanguageBlock global-id=\"js\">\n\nWe can run it with\n\n```sh\nnode app.mjs\n```\n\n</LanguageBlock>\n\n[Try it out live >](https://stackblitz.com/edit/node-mupbmh?embed=1&file=app.ts&view=editor)\n\nWe will see something like this in the terminal:\n\n```sh\nA new message has been created { id: 0, text: 'Hello Feathers' }\nA new message has been created { id: 1, text: 'Hello again' }\nAll messages [ { id: 0, text: 'Hello Feathers' },\n  { id: 1, text: 'Hello again' } ]\n```\n\nHere we implemented only `find` and `create`, but a service can also have a few other methods, specifically `get`, `update`, `patch` and `remove`. We will learn more about service methods and events throughout this guide, but this sums up some of the most important concepts upon which Feathers is built.\n\n## An API Server\n\nSo far we've created a Feathers application, a message service, and are listening to events. However, this is only a simple NodeJS script that prints some output and then exits. What we really want is to host it as an API server. This is where Feathers transports come in.\n\nA transport takes a service like the one we created above and turns it into a server that other clients can talk to, like a website or mobile application.\n\nIn the following example we will take our existing service and use:\n\n- `@feathersjs/koa` which uses [KoaJS](https://koajs.com/) to automatically turn our services into a REST API\n- `@feathersjs/socketio` which uses Socket.io to do the same as a WebSocket, real-time API (as we will see in a bit this is where the `created` event we saw above comes in handy).\n\nRun:\n\n<LanguageBlock global-id=\"ts\">\n\n```sh\nnpm install @feathersjs/socketio @feathersjs/koa --save\n```\n\nThen update `app.ts` with the following content:\n\n</LanguageBlock>\n<LanguageBlock global-id=\"js\">\n\n```sh\nnpm install @feathersjs/socketio @feathersjs/koa koa-static --save\n```\n\nThen update `app.mjs` with the following content:\n\n</LanguageBlock>\n\n```ts{2-4,42-55,58-65}\nimport { feathers } from '@feathersjs/feathers'\nimport { koa, rest, bodyParser, errorHandler, serveStatic } from '@feathersjs/koa'\nimport socketio from '@feathersjs/socketio'\n\n// This is the interface for the message data\ninterface Message {\n  id?: number\n  text: string\n}\n\n// A messages service that allows us to create new\n// and return all existing messages\nclass MessageService {\n  messages: Message[] = []\n\n  async find() {\n    // Just return all our messages\n    return this.messages\n  }\n\n  async create(data: Pick<Message, 'text'>) {\n    // The new message is the data text with a unique identifier added\n    // using the messages length since it changes whenever we add one\n    const message: Message = {\n      id: this.messages.length,\n      text: data.text\n    }\n\n    // Add new message to the list\n    this.messages.push(message)\n\n    return message\n  }\n}\n\n// This tells TypeScript what services we are registering\ntype ServiceTypes = {\n  messages: MessageService\n}\n\n// Creates an KoaJS compatible Feathers application\nconst app = koa<ServiceTypes>(feathers())\n\n// Use the current folder for static file hosting\napp.use(serveStatic('.'))\n// Register the error handle\napp.use(errorHandler())\n// Parse JSON request bodies\napp.use(bodyParser())\n\n// Register REST service handler\napp.configure(rest())\n// Configure Socket.io real-time APIs\napp.configure(socketio())\n// Register our messages service\napp.use('messages', new MessageService())\n\n// Add any new real-time connection to the `everybody` channel\napp.on('connection', (connection) => app.channel('everybody').join(connection))\n// Publish all events to the `everybody` channel\napp.publish((_data) => app.channel('everybody'))\n\n// Start the server\napp\n  .listen(3030)\n  .then(() => console.log('Feathers server listening on localhost:3030'))\n\n// For good measure let's create a message\n// So our API doesn't look so empty\napp.service('messages').create({\n  text: 'Hello world from the server'\n})\n```\n\n[Try it out live >](https://stackblitz.com/edit/node-zfinli?embed=1&file=app.ts)\n\n<LanguageBlock global-id=\"ts\">\n\nWe can start the server with\n\n```sh\nnpx ts-node app.ts\n```\n\n</LanguageBlock>\n<LanguageBlock  global-id=\"js\">\n\nWe can start the server with\n\n```sh\nnode app.mjs\n```\n\n</LanguageBlock>\n\n<BlockQuote type=\"info\">\n\nThe server will stay running until you stop it by pressing **Control + C** in the terminal.\n\n</BlockQuote>\n\nAnd in the browser visit\n\n```\nhttp://localhost:3030/messages\n```\n\nto see an array with the one message we created on the server.\n\n<BlockQuote>\n\nThe built-in [JSON viewer in Firefox](https://developer.mozilla.org/en-US/docs/Tools/JSON_viewer) or a browser plugin like [JSON viewer for Chrome](https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh) makes it nicer to view JSON responses in the browser.\n\n</BlockQuote>\n\nThis is the basic setup of a Feathers API server.\n\n- The `app.use` calls probably look familiar if you have used something like Koa or Express before.\n- `app.configure` calls set up the Feathers transport to host the API.\n- `app.on('connection')` and `app.publish` are used to set up event channels, which send real-time events to the proper clients (everybody that is connected to our server in this case). You can learn [more about the channels API](../../api/channels.md) after finishing this guide.\n\n## In the browser\n\nNow we can look at one of the really cool features of Feathers: **It works the same in a web browser!** This means that we could take [our first app example](#our-first-app) from above and run it just the same in a website. Since we already have a server running, however, let's go a step further and create a Feathers app that talks to our `messages` service on the server using a real-time Socket.io connection.\n\nIn the same folder, add the following `index.html` page:\n\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>Feathers Example</title>\n    <link href=\"https://cdn.jsdelivr.net/npm/daisyui@2.46.1/dist/full.css\" rel=\"stylesheet\" type=\"text/css\" />\n    <link\n      href=\"https://cdn.jsdelivr.net/npm/tailwindcss@2.2/dist/tailwind.min.css\"\n      rel=\"stylesheet\"\n      type=\"text/css\"\n    />\n    <link rel=\"stylesheet\" href=\"https://feathersjs.com/feathers-chat.css\" />\n  </head>\n  <body data-theme=\"dracula\">\n    <main id=\"main\" class=\"p-8\">\n      <h1 class=\"font-medium leading-tight text-5xl mt-0 mb-2\">Welcome to Feathers</h1>\n\n      <div class=\"form-control w-full py-2\">\n        <form class=\"input-group overflow-hidden\" onsubmit=\"sendMessage(event)\">\n          <input name=\"message\" id=\"message-text\" type=\"text\" class=\"input input-bordered w-full\" />\n          <button type=\"submit\" class=\"btn\">Send</button>\n        </form>\n      </div>\n      <h2 class=\"pt-1 pb-2 text-lg\">Messages</h2>\n    </main>\n\n    <script src=\"//unpkg.com/@feathersjs/client@^5.0.0/dist/feathers.js\"></script>\n    <script src=\"/socket.io/socket.io.js\"></script>\n    <script type=\"text/javascript\">\n      // Set up socket.io\n      const socket = io('http://localhost:3030')\n      // Initialize a Feathers app\n      const app = feathers()\n\n      // Register socket.io to talk to our server\n      app.configure(feathers.socketio(socket))\n\n      // Form submission handler that sends a new message\n      async function sendMessage(event) {\n        const messageInput = document.getElementById('message-text')\n\n        event.preventDefault()\n\n        // Create a new message with the input field value\n        await app.service('messages').create({\n          text: messageInput.value\n        })\n\n        messageInput.value = ''\n      }\n\n      // Renders a single message on the page\n      function addMessage(message) {\n        document.getElementById('main').innerHTML += `<div class=\"chat chat-start\">\n          <div class=\"chat-bubble\">${message.text}</div>\n        </div>`\n      }\n\n      const main = async () => {\n        // Find all existing messages\n        const messages = await app.service('messages').find()\n\n        // Add existing messages to the list\n        messages.forEach(addMessage)\n\n        // Add any newly created message to the list in real-time\n        app.service('messages').on('created', addMessage)\n      }\n\n      main()\n    </script>\n  </body>\n</html>\n```\n\n[Try it out live >](https://stackblitz.com/edit/node-m7cjfd?embed=1&file=index.html)\n\nNow in the browser if you go to\n\n```\nhttp://localhost:3030\n```\n\nyou will see a simple website that allows creating new messages. It is possible to open the page in two tabs and see new messages show up on either side in real-time. You can verify that the messages got created by visiting\n\n```\nhttp://localhost:3030/messages\n```\n\nYou'll see the JSON response including all current messages.\n\n## What's next?\n\nIn this chapter we created our first Feathers application and a service that allows creating new messages, storing them in memory, and retrieving them. We then hosted that service as a REST and real-time API server and used Feathers in the browser to connect to that server and create a website that can send new messages and show all existing messages in real-time.\n\nEven though we are using just NodeJS and Feathers from scratch without any additional tools, we didn't write a lot of code. In the [next chapter](./generator.md) we will look at the Feathers CLI which can create a similar Feathers application with a recommended file structure, models, database connections, authentication and more.\n"
  },
  {
    "path": "docs/guides/basics/testing.md",
    "content": "---\noutline: deep\n---\n\n# Writing tests\n\nThe best way to test an application is by writing tests that make sure it behaves to clients as we would expect. Feathers makes testing your application a lot easier because the services we create can be tested directly instead of having to fake HTTP requests and responses. In this chapter we will implement unit tests for our users and messages services.\n\nYou can run code linting and Mocha tests with:\n\n```sh\nnpm test\n```\n\nThis should already pass but it won't be testing any of the functionality we added in the guide so far.\n\n## Test database setup\n\nWhen testing database functionality, we want to make sure that the tests use a different database. We can achieve this by updating the test environment configuration in `config/test.json` with the following content:\n\n```json\n{\n  \"nedb\": \"../test/data\"\n}\n```\n\nThis will set up the NeDB database to use `test/data` as the base directory instead of `data/` when the `NODE_ENV` environment variable is set to `test`. The same thing can be done with connection strings for other databases.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nWhen using Git for version control, the `data/` and `test/data` folders should be added to `.gitignore`.\n\n</BlockQuote>\n\nWe also want to make sure that the database is cleaned up before every test run. To make that possible across platforms, first run:\n\n```sh\nnpm install shx --save-dev\n```\n\nNow we can update the `scripts` section of our `package.json` to the following:\n\n\n\n<LanguageBlock global-id=\"ts\">\n\n```json\n  \"scripts\": {\n    \"test\": \"npm run compile && npm run mocha\",\n    \"dev\": \"ts-node-dev --no-notify src/\",\n    \"start\": \"npm run compile && node lib/\",\n    \"clean\": \"shx rm -rf test/data/\",\n    \"mocha\": \"npm run clean && NODE_ENV=test ts-mocha \\\"test/**/*.ts\\\" --recursive --exit\",\n    \"compile\": \"shx rm -rf lib/ && tsc\"\n  },\n```\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\n```json\n  \"scripts\": {\n    \"test\": \"npm run eslint && npm run mocha\",\n    \"eslint\": \"eslint src/. test/. --config .eslintrc.json\",\n    \"start\": \"node src/\",\n    \"clean\": \"shx rm -rf test/data/\",\n    \"mocha\": \"npm run clean && NODE_ENV=test mocha test/ --recursive --exit\"\n  }\n```\n\n</LanguageBlock>\n\n\n\nOn Windows the `mocha` command should look like this:\n\n```sh\nnpm run clean & SET NODE_ENV=test& mocha test/ --recursive --exit\n```\n\nThis will make sure that the `test/data` folder is removed before every test run and `NODE_ENV` is set properly.\n\n## Testing services\n\nTo test the `messages` and `users` services (with all hooks wired up), we could use any REST API testing tool to make requests and verify that they return correct responses.\n\nThere is a much faster, easier and complete approach. Since everything on top of our own hooks and services is already provided (and tested) by Feathers, we can require the [application](../../api/application.md) object and use the [service methods](../../api/services.md) directly. We \"fake\" authentication by setting `params.user` manually.\n\nBy default, the generator creates a service test file that only tests that the service exists.\n\n\n\n<LanguageBlock global-id=\"ts\">\n\nE.g. like this in `test/services/users.test.ts`:\n\n```ts\nimport assert from 'assert';\nimport app from '../../src/app';\n\ndescribe('\\'users\\' service', () => {\n  it('registered the service', () => {\n    const service = app.service('users');\n\n    assert.ok(service, 'Registered the service');\n  });\n});\n```\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\nE.g. like this in `test/services/users.test.js`:\n\n```js\nconst assert = require('assert');\nconst app = require('../../src/app');\n\ndescribe('\\'users\\' service', () => {\n  it('registered the service', () => {\n    const service = app.service('users');\n\n    assert.ok(service, 'Registered the service');\n  });\n});\n```\n\n</LanguageBlock>\n\n\n\nWe can then add similar tests that use the service. In this case we are:\n1. verifying that users can be created, the default profile image gets set and the password is encrypted\n2. ensuring that the password does not get sent to external requests\n\n\n\n<LanguageBlock global-id=\"ts\">\n\nReplace `test/services/users.test.ts` with the following:\n\n```ts\nimport assert from 'assert';\nimport app from '../../src/app';\n\ndescribe('\\'users\\' service', () => {\n  it('registered the service', () => {\n    const service = app.service('users');\n\n    assert.ok(service, 'Registered the service');\n  });\n\n  it('creates a user, encrypts password and adds gravatar', async () => {\n    const user = await app.service('users').create({\n      email: 'test@example.com',\n      password: 'secret'\n    });\n\n    // Verify Gravatar has been set as we'd expect\n    assert.equal(user.avatar, 'https://s.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0?s=60');\n    // Makes sure the password got encrypted\n    assert.ok(user.password !== 'secret');\n  });\n\n  it('removes password for external requests', async () => {\n    // Setting `provider` indicates an external request\n    const params = { provider: 'rest' };\n\n    const user = await app.service('users').create({\n      email: 'test2@example.com',\n      password: 'secret'\n    }, params);\n\n    // Make sure password has been removed\n    assert.ok(!user.password);\n  });\n});\n```\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\nReplace `test/services/users.test.js` with the following:\n\n```js\nconst assert = require('assert');\nconst app = require('../../src/app');\n\ndescribe('\\'users\\' service', () => {\n  it('registered the service', () => {\n    const service = app.service('users');\n\n    assert.ok(service, 'Registered the service');\n  });\n\n  it('creates a user, encrypts password and adds gravatar', async () => {\n    const user = await app.service('users').create({\n      email: 'test@example.com',\n      password: 'secret'\n    });\n\n    // Verify Gravatar has been set as we'd expect\n    assert.equal(user.avatar, 'https://s.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0?s=60');\n    // Makes sure the password got encrypted\n    assert.ok(user.password !== 'secret');\n  });\n\n  it('removes password for external requests', async () => {\n    // Setting `provider` indicates an external request\n    const params = { provider: 'rest' };\n\n    const user = await app.service('users').create({\n      email: 'test2@example.com',\n      password: 'secret'\n    }, params);\n\n    // Make sure password has been removed\n    assert.ok(!user.password);\n  });\n});\n```\n\n</LanguageBlock>\n\n\n\nWe take a similar approach for the messages service test by creating a test-specific user from the `users` service, then pass it as `params.user` when creating a new message and validates that message's content:\n\n\n\n<LanguageBlock global-id=\"ts\">\n\nUpdate `test/services/messages.test.ts` as follows:\n\n```ts\nimport assert from 'assert';\nimport app from '../../src/app';\n\ndescribe('\\'messages\\' service', () => {\n  it('registered the service', () => {\n    const service = app.service('messages');\n\n    assert.ok(service, 'Registered the service');\n  });\n\n  it('creates and processes message, adds user information', async () => {\n    // Create a new user we can use for testing\n    const user = await app.service('users').create({\n      email: 'messagetest@example.com',\n      password: 'supersecret'\n    });\n\n    // The messages service call params (with the user we just created)\n    const params = { user };\n    const message = await app.service('messages').create({\n      text: 'a test',\n      additional: 'should be removed'\n    }, params);\n\n    assert.equal(message.text, 'a test');\n    // `userId` should be set to passed users it\n    assert.equal(message.userId, user._id);\n    // Additional property has been removed\n    assert.ok(!message.additional);\n    // `user` has been populated\n    assert.deepEqual(message.user, user);\n  });\n});\n```\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\nUpdate `test/services/messages.test.js` as follows:\n\n```js\nconst assert = require('assert');\nconst app = require('../../src/app');\n\ndescribe('\\'messages\\' service', () => {\n  it('registered the service', () => {\n    const service = app.service('messages');\n\n    assert.ok(service, 'Registered the service');\n  });\n\n  it('creates and processes message, adds user information', async () => {\n    // Create a new user we can use for testing\n    const user = await app.service('users').create({\n      email: 'messagetest@example.com',\n      password: 'supersecret'\n    });\n\n    // The messages service call params (with the user we just created)\n    const params = { user };\n    const message = await app.service('messages').create({\n      text: 'a test',\n      additional: 'should be removed'\n    }, params);\n\n    assert.equal(message.text, 'a test');\n    // `userId` should be set to the provided user's id\n    assert.equal(message.userId, user._id);\n    // Additional property has been removed\n    assert.ok(!message.additional);\n    // `user` has been populated\n    assert.deepEqual(message.user, user);\n  });\n});\n```\n\n</LanguageBlock>\n\n\n\nRun `npm test` one more time, to verify that all tests are passing.\n\n## Code coverage\n\nCode coverage is a great way to get some insights into how much of our code is actually executed during the tests. Using [Istanbul](https://github.com/gotwarlost/istanbul) we can add it easily:\n\n```sh\nnpm install nyc --save-dev\n```\n\n\n\n<LanguageBlock global-id=\"ts\">\n\nFor TypeScript we also have to install the TypeScript reporter:\n\n```sh\nnpm install @istanbuljs/nyc-config-typescript --save-dev\n```\n\nAdd the following `.nycrc` file:\n\n```json\n{\n  \"extends\": \"@istanbuljs/nyc-config-typescript\",\n  \"include\": [\n    \"src/**/*.ts\",\n    \"src/**/*.tsx\"\n  ]\n}\n```\n\nAnd then update the `scripts` section of our `package.json` to:\n\n```json\n  \"scripts\": {\n    \"test\": \"npm run compile && npm run coverage\",\n    \"dev\": \"ts-node-dev --no-notify src/\",\n    \"start\": \"npm run compile && node lib/\",\n    \"clean\": \"shx rm -rf test/data/\",\n    \"coverage\": \"nyc npm run mocha\",\n    \"mocha\": \"npm run clean && NODE_ENV=test ts-mocha \\\"test/**/*.ts\\\" --recursive --exit\",\n    \"compile\": \"shx rm -rf lib/ && tsc\"\n  },\n```\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\nNow we have to update the `scripts` section of our `package.json` to:\n\n```js\n  \"scripts\": {\n    \"test\": \"npm run eslint && npm run coverage\",\n    \"coverage\": \"nyc npm run mocha\",\n    \"eslint\": \"eslint src/. test/. --config .eslintrc.json\",\n    \"dev\": \"nodemon src/\",\n    \"start\": \"node src/\",\n    \"clean\": \"shx rm -rf test/data/\",\n    \"mocha\": \"npm run clean && NODE_ENV=test mocha test/ --recursive --exit\"\n  },\n```\n\n</LanguageBlock>\n\nOn Windows, the `coverage` command looks like this:\n\n```sh\nnpm run clean & SET NODE_ENV=test& nyc mocha\n```\n\nNow run:\n\n```sh\nnpm test\n```\n\nThis will print out some additional coverage information.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nWhen using Git for version control, the `.nyc_output/` folder should be added to `.gitignore`.\n\n</BlockQuote>\n\n## What's next?\n\nThat’s it! Our chat guide is completed! We now have a fully-tested REST and real-time API, with a plain JavaScript frontend including login and signup. Follow up in the [Feathers API documentation](../../api/) for more details about using Feathers, or start building your own first Feathers application!\n"
  },
  {
    "path": "docs/guides/cli/app.md",
    "content": "---\noutline: deep\n---\n\n# Application\n\nThe `src/app.ts` file is the main file where the [Feathers application](../../api/application.md) gets initialized and wired up with a Feathers transport.\n\n## Transports\n\nThe available transports are [Koa](../../api/koa.md) or [Express](../../api/express.md) for HTTP and [Socket.io](../../api/socketio.md) for real-time functionality. For both, Koa and Express, the Feathers application (`app` object) will also be fully compatible with the respective framework. For both frameworks, additional required middleware will be registered in the application file. More information can be found in the linked API documentation.\n\n## Configure functions\n\nThe Feathers application does not use a complicated dependency injection mechanism. Instead, the application is wired together using _configure functions_ to split things up into individual files. They are functions that are exported from a file and that take the Feathers [app object](../../api/application.md) and then use it to e.g. register services. Those functions are then passed to [app.configure](../../api/application.md#configurecallback).\n\nFor example, have a look at the following files:\n\n`src/services/index.ts` looks like this:\n\n```ts\nimport type { Application } from '../declarations'\nimport { user } from './users/users'\n\nexport const services = (app: Application) => {\n  app.configure(user)\n  // All services will be registered here\n}\n```\n\nIt uses another configure function exported from `src/services/users/users.ts`. The export from `src/services/index.js` is in turn used in `src/app.ts` as:\n\n```ts\n// ...\nimport { services } from './services'\n\n// ...\napp.configure(authentication)\napp.configure(services)\n// ...\n```\n\nThis is how the generator splits things up into separate files and any documentation example that uses the `app` object can be used in a configure function. You can create your own files that export a configure function and `require`/`import` and `app.configure` them.\n\n<BlockQuote type=\"info\">\n\nKeep in mind that the order in which configure functions are called might matter, e.g. if it is using a service, that service has to be registered first. Configure functions are not asynchronous. Any asynchronous operations should be done in [application setup hooks](#application-hooks).\n\n</BlockQuote>\n\n## Application hooks\n\nThe application file also includes a section to set up [application hooks](../../api/hooks.md#application-hooks) which are hooks that run for every service. In our case, the `logErrorHook` to log any service errors has already been registered:\n\n```ts\n// Register hooks that run on all service methods\napp.hooks({\n  around: {\n    all: [logErrorHook]\n  },\n  before: {},\n  after: {},\n  error: {}\n})\n```\n\nFollowing that is the special [setup and teardown](../../api/hooks.md#setup-and-teardown) hook section to register hooks that run once when the application starts or shuts down. This can be used to e.g. set dynamic configuration values.\n\n```ts\n// Register application setup and teardown hooks here\napp.hooks({\n  setup: [],\n  teardown: []\n})\n```\n\n## Tests, jobs and SSR\n\nThe `app` file can be imported like any other Node module. This means it can be used directly in tests, scheduled jobs or server side rendering without having to start a separate server instance. For example, the unit tests import the application like this:\n\n```ts\nimport assert from 'assert'\nimport { app } from '../../src/app'\n\ndescribe('messages service', () => {\n  it('registered the service', () => {\n    const service = app.service('messages')\n\n    assert.ok(service, 'Registered the service')\n  })\n})\n```\n"
  },
  {
    "path": "docs/guides/cli/app.test.md",
    "content": "---\noutline: deep\n---\n\n# Application tests\n\nThe `app.test` file starts the server and then tests that it shows the index page and that 404 (Not Found) JSON errors are being returned. It uses the [Axios HTTP](https://axios-http.com/) library to make the calls.\n\nThis file can e.g. be used to test application [setup](../../api/application.md#setupserver) and [teardown](../../api/application.md#teardownserver).\n\nAll tests are using [MochaJS](https://mochajs.org/) but will be moving to the [NodeJS test runner](https://nodejs.org/api/test.html) in the future.\n"
  },
  {
    "path": "docs/guides/cli/authentication.md",
    "content": "---\noutline: deep\n---\n\n# Authentication\n\nThe file in `src/authentication.ts` sets up an [authentication service](../../api/authentication/service.md) and registers [authentication strategies](../../api/authentication/strategy.md). Depending on the strategies you selected it looks similar to this:\n\n```ts\nimport { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'\nimport { LocalStrategy } from '@feathersjs/authentication-local'\n\nimport type { Application } from './declarations'\n\ndeclare module './declarations' {\n  interface ServiceTypes {\n    authentication: AuthenticationService\n  }\n}\n\nexport const authentication = (app: Application) => {\n  const authentication = new AuthenticationService(app)\n\n  authentication.register('jwt', new JWTStrategy())\n  authentication.register('local', new LocalStrategy())\n\n  app.use('authentication', authentication)\n}\n```\n\n## oAuth\n\nNote that when selecting oAuth logins (Google, Facebook, GitHub etc.), the standard registered oAuth strategy only uses the `<name>Id` property to create a new user. This will fail validation against the default user [schema](./service.schemas.md) which requires an `email` property to exist. If the provider (and user) allows fetching the email, you can customize the oAuth strategy like shown for GitHub in the [oAuth authentication guide](../basics/authentication.md#login-with-github). You can also make the email in the schema optional with `email: Type.Optional(Type.String())`.\n"
  },
  {
    "path": "docs/guides/cli/channels.md",
    "content": "# Channels\n\n> This page is currently a work in progress\n\nFor more information see the [channel API](../../api/channels.md).\n"
  },
  {
    "path": "docs/guides/cli/client.md",
    "content": "---\noutline: deep\n---\n\n# Client\n\nA generated application can be used as an npm module that provides a [Feathers client](../../api/client.md). It gives you a fully typed client that can be installed in any TypeScript (e.g. React, VueJS, React Native etc.) application.\n\n## Local installation\n\nThe application can be linked into a client application by running\n\n```\nnpm run bundle:client\nnpm link\n```\n\nThen go to your client side app\n\n```\ncd path/to/client\nnpm link my-app\n```\n\n## Creating a package\n\nTo create an installable SDK package that does not include any of the server code (other than the shared types) you can run\n\n```\nnpm run bundle:client\n```\n\nBy default this will create an `appname-x.x.x.tgz` npm package in the `public/` folder.\nThis package can be installed from a running server via\n\n```\nnpm install https://myapp.com/appname-x.x.x.tgz\n```\n\n## Usage\n\nOnce installed, the application can be used as follows with Socket.io:\n\n```ts\nimport io from 'socket.io-client'\nimport socketio from '@feathersjs/socketio-client'\nimport { createClient } from 'my-app'\n\nconst connection = socketio(io('https://myapp.com'))\n\nconst client = createClient(connection)\n```\n\nAnd like this with a REST client:\n\n```ts\nimport rest from '@feathersjs/rest-client'\nimport { createClient } from 'my-app'\n\nconst connection = rest('https://myapp.com').fetch(window.fetch.bind(window))\n\nconst client = createClient(connection)\n```\n"
  },
  {
    "path": "docs/guides/cli/client.test.md",
    "content": "# Client test\n\nThe `client.test` file contains end-to-end integration tests for the [generated client](./client.md).\n\n## Authentication\n\nIf you selected a local strategy, `src/client.ts` will be updated with a client side integration test that looks similar to this:\n\n```ts\nit('creates and authenticates a user with email and password', async () => {\n  const userData: userData = {\n    email: 'someone@example.com',\n    password: 'supersecret'\n  }\n\n  await client.service('users').create(userData)\n\n  const { user, accessToken } = await client.authenticate({\n    strategy: 'local',\n    ...userData\n  })\n\n  assert.ok(accessToken, 'Created access token for user')\n  assert.ok(user, 'Includes user in authentication data')\n  assert.strictEqual(user.password, undefined, 'Password is hidden to clients')\n\n  await client.logout()\n\n  // Remove the test user on the server\n  await app.service('users').remove(user.id)\n})\n```\n\nThis test will create a new user with the generated client, log in, verify a user was returned and log out again. To keep the test self-contained it will then remove the test user on the server\n\n<BlockQuote type=\"tip\">\n\nNote that you can use `client` for client side interactions and the server side [application](./app.md#application) `app` object for server side calls in the same file. For example, if the user required an email verification but you don't want to test sending out emails you can call something like `app.service('users').patch(user.id, { isVerified: true })` to enable the new user on the server.\n\n</BlockQuote>\n"
  },
  {
    "path": "docs/guides/cli/configuration.md",
    "content": "---\noutline: deep\n---\n\n### Configuration Schemas\n\nA generated application comes with a schema that validates the initial configuration when the application is started. This makes it much easier to catch configuration errors early which can otherwise be especially difficult to debug in remote environments.\n\nThe configuration [schema definition](../../api/schema/index.md) can be found in `configuration.ts`. It is used as a [configuration schema](../../api/configuration.md#configuration-validation) and loads some default schemas for authentication and database connection configuration and adds values for `host`, `port` and the `public` hosted file folder. The types of this schema are also used for `app.get()` and `app.set()` [typings](./declarations.md). The initial configuration schema will be validated on application startup when calling [`app.listen()`](../../api/application.md#listenport) or [`app.setup()`](../../api/application.md#setupserver).\n"
  },
  {
    "path": "docs/guides/cli/custom-environment-variables.md",
    "content": "# Custom Environment Variables\n\nWhile `node-config` used for [application configuration](./default.json.md) recommends to pass environment based configuration as a JSON string in a single `NODE_CONFIG` environment variable, it is also possible to use other environment variables via the `config/custom-environment-variables.json` file which looks like this by default:\n\n```json\n{\n  \"port\": {\n    \"__name\": \"PORT\",\n    \"__format\": \"number\"\n  },\n  \"host\": \"HOSTNAME\",\n  \"authentication\": {\n    \"secret\": \"FEATHERS_SECRET\"\n  }\n}\n```\n\nThis sets `app.get('port')` using the `PORT` environment variable (if it is available) parsing it as a number and `app.get('host')` from the `HOSTNAME` environment variable and the authentication secret to the `FEATHERS_SECRET` environment variable.\n\n<BlockQuote type=\"tip\">\n\nSee the [node-config custom environment variable](https://github.com/node-config/node-config/wiki/Environment-Variables#custom-environment-variables) documentation for more information.\n\n</BlockQuote>\n\n## Dotenv\n\nTo add support for [dotenv](https://www.dotenv.org/) `.env` files run\n\n```\nnpm install dotenv --save\n```\n\nAnd update `src/app.ts` as follows:\n\n```ts\n// dotenv replaces all environmental variables from ~/.env in ~/config/custom-environment-variables.json\nimport * as dotenv from 'dotenv'\ndotenv.config()\n\n// or for ES6\n\nimport 'dotenv/config';\n\nimport configuration from '@feathersjs/configuration'\n```\n\n<BlockQuote type=\"warning\" label=\"important\">\n\n`dotenv.config()` needs to run _before_ `import configuration from '@feathersjs/configuration'`\n\n</BlockQuote>\n"
  },
  {
    "path": "docs/guides/cli/databases.md",
    "content": "---\noutline: deep\n---\n\n# Databases\n\n<hr/>\n<DatabaseSelect />\n\n## Connection\n\n<DatabaseBlock global-id=\"sql\">\n\nDepending on the SQL database you selected, a `src/<database>.ts` file will be created that sets up a connection using [KnexJS](../../api/databases/knex.md). It uses the connection settings from the `<database>` [configuration value](./default.json.md) and exports a [configure function](./app.md#configure-functions) that initializes the database connection. The Knex connection object is then accessible wherever you have access to the [app object](./app.md) via\n\n```ts\nconst knex = app.get('<database>Client')\n```\n\nThe database pool size can be set in the [configuration](./default.json.md) like this:\n\n```json\n\"postgresql\": {\n  \"client\": \"pg\",\n  \"connection\": \"<pg connection string>\",\n  \"pool\": {\n    \"min\": 0,\n    \"max\": 7\n  }\n},\n```\n\n`connection` can also be an object instead of a connection string:\n\n```json\n\"postgresql\": {\n  \"client\": \"pg\",\n  \"connection\": {\n    \"host\": \"localhost\",\n    \"port\": 5432,\n    \"user\": \"postgres\",\n    \"password\": \"postgres\",\n    \"database\": \"pgtest\"\n  }\n}\n```\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\n`src/mongodb.ts` exports a [configure function](./app.md#configure-functions) that connects to the MongoDB connection string set as `mongodb` in your [configuration](./default.json.md). The [MongoDB NodeJS client](https://www.mongodb.com/languages/mongodb-with-nodejs) is then accessible wherever you have access to the [app object](./app.md) via\n\n```ts\nconst db = await app.get('mongodbClient')\n```\n\nThe default connection string tries to connect to a local MongoDB instance with no password. To use e.g. [MongoDB Atlas](https://www.mongodb.com/cloud) change the `mongodb` property in `config/default.json` or add it as an [environment variable](./configuration.md#environment-variables) with the connection string that will look similar to this:\n\n```\nmongodb+srv://<user>:<password>@cluster0.xyz.mongodb.net/?retryWrites=true&w=majority\n```\n\n</DatabaseBlock>\n\n## Models\n\n<DatabaseBlock global-id=\"sql\">\n\nKnexJS does not have a concept of models. Instead a new service is initialized with the table name and `app.get('<database>Client')` as the connection. For more information on how to create custom queries and more, see the [SQL database adapter API documentation](../../api/databases/knex.md).\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\nThe collection for a MongoDB service can be accessed via\n\n```ts\nconst userCollection = await app.service('users').getModel()\n```\n\nSee the [MongoDB service API documentation](../../api/databases/mongodb.md) for more information.\n\n</DatabaseBlock>\n"
  },
  {
    "path": "docs/guides/cli/declarations.md",
    "content": "---\noutline: deep\n---\n\n# TypeScript\n\n<LanguageBlock global-id=\"ts\">\n\nThe main file for application specific TypeScript declarations can be found at `src/declarations.ts`.\n\n## Compilation\n\nIn order to compile and start the application use\n\n```\nnpm run compile\nnpm start\n```\n\nFor development with live reload use\n\n```\nnpm run dev\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nTo get the latest types in the [client](./client.md) and any time before `npm start`, `npm run compile` needs to run.\n\n</BlockQuote>\n\n## Configuration Types\n\nThe `Configuration` interface defines the types for [app.get](../../api/application.md#getname) and [app.set](../../api/application.md#setname-value). It is extended from the type inferred from the [configuration schema](./configuration.md#configuration-schemas). Since you can store anything global to the application in `app.get` and `app.set`, you can add additional types that are not part of the initial application configuration here.\n\n```ts\n// The types for app.get(name) and app.set(name)\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface Configuration extends ApplicationConfiguration {\n  startupTime: Date\n}\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nBoth `Configuration` and `ServiceTypes` need to be declared as an `interface` (even if it is empty) so they can be extended via `declare module` in other files. Do not remove the `eslint-disable-next-line` comments.\n\n</BlockQuote>\n\n## Service Types\n\nThe `ServiceTypes` interface contains a mapping of all service paths to their service type so that [app.use](../../api/application.md#usepath-service--options) and [app.service](../../api/application.md#servicepath) use the correct type.\n\n```ts\n// A mapping of service names to types. Will be extended in service files.\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface ServiceTypes {}\n```\n\nUsually the `ServiceTypes` interface is not modified directly in this file but instead extended via `declare module` in the files where the services are registered. This usually looks like this:\n\n```ts\n// Add this service to the service type index\ndeclare module '../../declarations' {\n  interface ServiceTypes {\n    users: UserService\n  }\n}\n```\n\n## Application\n\nThe `Application` interface is the type for the main [app object](./app.md) using the [ServiceTypes](#service-types) interface as the service index and [ConfigurationTypes](#configuration-types) for `app.get` and `app.set`.\n\n```ts\n// The application instance type that will be used everywhere else\nexport type Application = FeathersApplication<ServiceTypes, Configuration>\n```\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nAlways use `import { Application } from './declarations'` to get the proper service and configuration typings. You normally do **not** need to use `import { Application } from '@feathersjs/feathers'` directly.\n\n</BlockQuote>\n\n## Hook Context\n\nThe `HookContext` type exports a [hook context](../../api/hooks.md) type with the `Application` and a generic service type `S`.\n\n```ts\n// The context for hook functions - can be typed with a service class\nexport type HookContext<S = any> = FeathersHookContext<Application, S>\n```\n\nUse `HookContext<UserService>` to get the full hook context for a service.\n\n## Services and Params\n\nSee the [services chapter](./service.md) for more information on service and parameter typings.\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"js\">\n\n<BlockQuote type=\"danger\">\n\nPlease pick **TypeScript** as the Code language in the main menu dropdown.\n\n</BlockQuote>\n\n</LanguageBlock>\n"
  },
  {
    "path": "docs/guides/cli/default.json.md",
    "content": "---\noutline: deep\n---\n\n# Application configuration\n\nA generated application uses the **[configuration module](../../api/configuration.md)** to load configuration information based on the environment. It is based on the battle-tested and widely used [node-config](https://github.com/node-config/node-config) and loads configuration settings so that they are available via [app.get()](../../api/application.md#getname). On application startup, the configuration will be validated against the [configuration schema](./configuration.md).\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nFor more information on application configuration and schemas see the [configuration API documentation](../../api/configuration.md).\n\n</BlockQuote>\n\n## Environments\n\nThe `NODE_ENV` environment variable determines which configuration file is used. For example, setting `NODE_ENV=development` (in a single command e.g. as `NODE_ENV=development npm run dev`) will first load `config/default.json` and then merge it with `config/development.json`. If no environment is set, `config/default.json` will be used.\n\n## Default configuration\n\nThe application uses the following configuration values.\n\n### host, port, public\n\nThese options are used directly in the generated application\n\n- `host` - Is the hostname of the API server\n- `port` - The port it listens on\n- `public` - The name of the folder static assets are hosted in\n\n### paginate\n\n`paginate` sets the default and maximum page size when using [pagination](../../api/databases/common.md#pagination) with a [database service](../../api/databases/adapters.md).\n\n```json\n{\n  \"paginate\": {\n    \"default\": 10,\n    \"max\": 100\n  }\n}\n```\n\n### origins\n\n`origins` contains a list of frontend URLs that requests can be made from. This is used to configure cross origin (CORS) policies and oAuth (Twitter, Facebook etc.) login redirects. For example to develop locally with a [create-react-app](https://create-react-app.dev/) frontend and deploy to `app.feathersjs.com`:\n\n```json\n{\n  \"origins\": [\"http://localhost:3030\", \"http://localhost:5000\", \"https://app.feathersjs.com\"]\n}\n```\n\n### authentication\n\n`authentication` contains the configuration for the authentication service and strategies. See the [authentication service configuration](../../api/authentication/service.md#configuration) for more information. For strategy specific settings refer to the [jwt](../../api/authentication/jwt.md#options), [local](../../api/authentication/local.md#options) and [oAuth](../../api/authentication/oauth.md#options) API documentation.\n\n### Databases\n\n<DatabaseBlock global-id=\"sql\">\n\nDepending on the SQL database selected the `<database>` setting contains a `connection` with the database driver package name and a `client` option with the database connection string.\n\n```json\n{\n  \"postgresql\": {\n    \"connection\": \"pg\",\n    \"client\": \"postgres://postgres:@localhost:5432/feathers-chat\"\n  }\n}\n```\n\nFor additional configuration see the [database connection guide](./databases.md#connection).\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\nWhen selecting MongoDB, the `mongodb` setting contains the MongoDB connection string.\n\n</DatabaseBlock>\n"
  },
  {
    "path": "docs/guides/cli/hook.md",
    "content": "---\noutline: deep\n---\n\n# Hooks\n\n## Generating a hook\n\nA new hook can be generated via\n\n```\nnpx feathers generate hook\n```\n\n## Hook name\n\nThe hook generator will first ask for a name. Based on the name it will create a kebab-cased filename in the `hooks/` folder that exports a camelCased hook function. For example a name of `my fancy Hook` will create a `src/my-fancy-hook.ts` file that exports a `myFancyHook` [hook function](../../api/hooks.md#hook-functions).\n\n## Hook types\n\nThere are two hook types that can be generated.\n\n<BlockQuote type=\"tip\">\n\nFor more information see the [hooks API documentation](../../api/hooks.md).\n\n</BlockQuote>\n\n### Around hooks\n\n[Around hooks](../../api/hooks.md#around) allow to control the entire `before`, `after` and `error` flow in a single function. An `around` hook is an `async` function that accepts two arguments:\n\n- The [hook context](../../api/hooks.md#hook-context)\n- An asynchronous `next` function. Somewhere in the body of the hook function, there is a call to `await next()`, which calls the `next` hooks OR the original function if all other hooks have run.\n\n```ts\nimport type { HookContext, NextFunction } from '../declarations'\n\nexport const myFancyHook = async (context: HookContext, next: NextFunction) => {\n  console.log(`Running hook ${name} on ${context.path}.${context.method}`)\n  await next()\n  // Do things after here\n}\n```\n\nYou can wrap the `await next()` in a `try/catch` block to also handle errors.\n\n### Before, after, error\n\n[Before, after or error hooks](../../api/hooks.md#before-after-and-error) are `async` functions that take the [hook context](#hook-context) as the parameter.\n\n```ts\nimport type { HookContext } from '../declarations'\n\nexport const myFancyHook = async (context: HookContext) => {\n  console.log(`Running hook ${name} on ${context.path}.${context.method}`)\n}\n```\n\n## Context types\n\nIf the hook is for a specific service, you can pass the service as a generic to the [HookContext](./declarations.md#hook-context) type which will give you the correct types for [context.data](../../api/hooks.md#contextdata), [context.result](../../api/hooks.md#contextresult) and [context.params](../../api/hooks.md#contextparams):\n\n```ts\nimport type { UserService } from '../services/users/users'\nimport type { HookContext } from '../declarations'\n\nexport const myFancyUserHook = async (context: HookContext<UserService>) => {\n  console.log(`Running hook ${name} on ${context.path}.${context.method}`)\n}\n```\n\n## Registering hooks\n\nA generated hook can be registered as an [application hook](./app.md#application-hooks) or as a [service hook](./service.md#registering-hooks). Also see the [hook registration API documentation](../../api/hooks.md#registering-hooks).\n\n## Profiling example\n\nTo log some basic profiling information like which method was called and how long it took to run you can create a new _around_ hook called `profiler` via\n\n```\nnpx feathers generate hook\n```\n\nThen update `src/hooks/profiler.ts` as follows:\n\n```ts\nimport type { HookContext, NextFunction } from '../declarations'\nimport { logger } from '../logger'\n\nexport const profiler = async (context: HookContext, next: NextFunction) => {\n  const startTime = Date.now()\n\n  await next()\n\n  const runtime = Date.now() - startTime\n\n  console.log(`Calling ${context.method} on service ${context.path} took ${runtime}ms`)\n}\n```\n\nAnd add it in `src/app.ts` as an application hook after the `logError` hook as follows:\n\n```ts{1,8}\nimport { profiler } from './hooks/profiler'\n\n//...\n\n// Register hooks that run on all service methods\napp.hooks({\n  around: {\n    all: [ logError, profiler ]\n  },\n  before: {},\n  after: {},\n  error: {}\n})\n```\n"
  },
  {
    "path": "docs/guides/cli/index.md",
    "content": "---\noutline: deep\n---\n\n# The Feathers CLI\n\nThe Feathers generator allows you to quickly scaffold a Feathers app with the latest standardized file structure.\n\n## Install the CLI\n\nWhen creating an application (e.g. `my-app`) with\n\n```\nnpm create feathers@latest my-app\n```\n\nthe Feathers CLI will be installed locally into your new project. This is preferred over global installation so that everybody working on your project has the same version and commands available by running `npx feathers`.\n\n## CLI Commands\n\nIn a generated application you should be able to run the `generate` command with no arguments:\n\n```bash\nnpx feathers generate\n```\n\nYou'll see the following output:\n\n```bash\nUsage: feathers generate|g [options] [command]\n\nRun a generator. Currently available:\n  app: Generate a new application\n  service: Generate a new service\n  hook: Generate a hook\n  connection: Add a new database connection\n  authentication: Add authentication to the application\n\nOptions:\n  -h, --help         display help for command\n\nCommands:\n  app [options]      Generate a new application\n  service [options]  Generate a new service\n  hook [options]     Generate a hook\n  connection         Add a new database connection\n  authentication     Add authentication to the application\n  help [command]     display help for command\n```\n\n### Authentication\n\n```\nnpx feathers generate authentication\n```\n\nWill set up Feathers authentication and a users service. This is required for any other service that needs authentication.\n\n### Service\n\n```\nnpx feathers generate service\n```\n\nGenerates a service connected to a database or a custom service.\n\n### Connection\n\n```\nnpx feathers generate connection\n```\n\nSets up a new database connection. This is already done when creating a new application but you can still set up other databases.\n\n### Hook\n\n```\nnpx feathers generate hook\n```\n\nGenerates a new hook in the `hooks` folder that can then be registered in your services.\n\n### App\n\nThis is the command that runs automatically when calling\n\n```\nnpm create feathers@latest my-app\n```\n"
  },
  {
    "path": "docs/guides/cli/knexfile.md",
    "content": "# Knexfile\n\n## Migrations\n\nMigrations are a best practise for SQL databases to roll out and undo changes to the data model and are set up automatically with an SQL database connection. The generated `knexfile.ts` imports the [app object](./app.md) to establish the connection to the database. To run migration scripts for the connection from the [configuration environment](./configuration.md#environment-variables) use:\n\n```\nnpm run migrate\n```\n\nTo create a new migration, run\n\n```\nnpm run migrate:make -- <name>\n```\n\nand replace `<name>` with the name of the migration you want to create. This will create a new file in the `migrations/` folder.\n\n<BlockQuote type=\"tip\">\n \nFor more information on what is available in migration files, see the [Knex migrations documentation](https://knexjs.org/guide/migrations.html).\n\n</BlockQuote>\n"
  },
  {
    "path": "docs/guides/cli/log-error.md",
    "content": "# Error logging hook\n\nThe `src/hooks/log-error.ts` file exports a `logError` hook that uses the [logger](./logger.md) to log any error for a service method, including validation error details (when they are available). It is registered as an [application hook](./app.md#application-hooks) `all` hook, meaning it will log errors for any service method.\n"
  },
  {
    "path": "docs/guides/cli/logger.md",
    "content": "---\noutline: deep\n---\n\n# Logging\n\n## Logger\n\nThe `src/logger.ts` file initialises the widely used [Winston logger](https://github.com/winstonjs/winston) library, by default with the `info` log level, logging to the console.\n\n```ts\nimport { createLogger, format, transports } from 'winston'\n\n// Configure the Winston logger. For the complete documentation see https://github.com/winstonjs/winston\nexport const logger = createLogger({\n  // To see more detailed errors, change this to 'debug'\n  level: 'info',\n  format: format.combine(format.splat(), format.simple()),\n  transports: [new transports.Console()]\n})\n```\n\nYou can import the logger directly in any file where you want to add logging information.\n\n```ts\nimport { logger } from './logger'\n\nlogger.info('Log some information here')\n```\n"
  },
  {
    "path": "docs/guides/cli/package.md",
    "content": "# package.json\n\n## Folders\n\nThe source and test folders to which files are generated is set in the `package.json`. To change them, rename the `src/` or `test/` folder to what you want it to and then update `package.json` `directories` section accordingly:\n\n```json\n{\n  \"directories\": {\n    \"lib\": \"api/src\",\n    \"test\": \"api/test\"\n  }\n}\n```\n"
  },
  {
    "path": "docs/guides/cli/prettierrc.md",
    "content": "# Prettier\n\nThe Feathers CLI uses [Prettier](https://prettier.io/) for code formatting and generates a configuration for it in a new application. To change the options, like the use of semicolons, quotes etc, edit the `.prettierrc` file with the [options available](https://prettier.io/docs/en/options.html). To update all existing source files with the new code style run\n\n```\nnpm run prettier\n```\n\nWhen new files are generated, they will use the current Prettier configuration. See the [Prettier Integration with Linters](https://prettier.io/docs/en/integrating-with-linters.html) documentation for how to integrate with tools like ESLint.\n"
  },
  {
    "path": "docs/guides/cli/service.class.md",
    "content": "---\noutline: deep\n---\n\n# Service classes\n\nThe `<service>.class` file exports the [service class or object](../../api/services.md).\n\n## Database services\n\nWhen using a database, the service class will be extended from the [Feathers database adapter service](../../api/databases/common.md). Like any class, existing methods can be overriden or you can add your own methods (which can also be made available externally [as custom methods when registering the service](./service.md#registration)).\n\n<LanguageBlock global-id=\"ts\">\n\n<BlockQuote type=\"tip\" label=\"Note\">\n\nThe generic types for a database service are always `AdapterService<MessageType, DataType, ParamsType, PatchType>`. The `MessageService<ServiceParams extends Params = MessageParams>` generic is used to change the parameter type when using this service interface as a [client side service](./client.md).\n\n</BlockQuote>\n\n</LanguageBlock>\n\n### Overriding methods\n\nWhen overriding an existing [service method](../../api/services.md#service-methods) on a database adapter the method and overload signatures have to match. The following example shows how to override every service method. Only the methods you want to customize have to be added.\n\n<DatabaseBlock global-id=\"sql\">\n\nThe [SQL Knex service](../../api/databases/knex.md) methods can be customized like this:\n\n```ts\nimport { Id, NullableId, Paginated } from '@feathersjs/feathers'\n\nexport interface MessageParams extends KnexAdapterParams<MessageQuery> {}\n\n// By default calls the standard Knex adapter service methods but can be customized with your own functionality.\nexport class MessageService<ServiceParams extends Params = MessageParams> extends KnexService<\n  Message,\n  MessageData,\n  MessageParams,\n  MessagePatch\n> {\n  async find(\n    params?: MessageParams & { paginate?: { default?: number; max?: number } }\n  ): Promise<Paginated<Message>>\n  async find(params?: ServiceParams & { paginate: false }): Promise<Message[]>\n  async find(params?: ServiceParams): Promise<Paginated<Message> | Message[]>\n  async find(params?: ServiceParams): Promise<Paginated<Message> | Message[]> {\n    return super.find(params)\n  }\n\n  async get(id: Id, params?: ServiceParams): Promise<Message> {\n    return super.get(id, params)\n  }\n\n  async create(data: MessageData, params?: ServiceParams): Promise<Message>\n  async create(data: MessageData[], params?: ServiceParams): Promise<Message[]>\n  async create(data: MessageData | MessageData[], params?: ServiceParams): Promise<Message | Message[]> {\n    return super.create(data, params)\n  }\n\n  async update(id: Id, data: Data, params?: ServiceParams): Promise<Message> {\n    return super.update(id, data, params)\n  }\n\n  async patch(id: Id, data: MessagePatch, params?: ServiceParams): Promise<Message>\n  async patch(id: null, data: MessagePatch, params?: ServiceParams): Promise<Message[]>\n  async patch(id: NullableId, data: MessagePatch, params?: ServiceParams): Promise<Message | Message[]> {\n    return super.patch(id, data, params)\n  }\n\n  async remove(id: Id, params?: ServiceParams): Promise<Message>\n  async remove(id: null, params?: ServiceParams): Promise<Message[]>\n  async remove(id: NullableId, params?: ServiceParams): Promise<Message | Message[]> {\n    return super.remove(id, params)\n  }\n}\n```\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\nThe [MongoDB service](../../api/databases/mongodb.md) methods can be customized like this:\n\n```ts\nimport { Paginated } from '@feathersjs/feathers'\nimport { AdapterId } from '@feathersjs/mongodb'\n\nexport interface MessageParams extends MongoDBAdapterParams<MessageQuery> {}\n\n// By default calls the standard MongoDB adapter service methods but can be customized with your own functionality.\nexport class MessageService<ServiceParams extends Params = MessageParams> extends MongoDBService<\n  Message,\n  MessageData,\n  MessageParams,\n  MessagePatch\n> {\n  async find(\n    params?: ServiceParams & { paginate?: { paginate?: { default?: number; max?: number } } }\n  ): Promise<Paginated<Message>>\n  async find(params?: ServiceParams & { paginate: false }): Promise<Message[]>\n  async find(params?: ServiceParams): Promise<Paginated<Message> | Message[]>\n  async find(params?: ServiceParams): Promise<Paginated<Message> | Message[]> {\n    return super.find(params)\n  }\n\n  async get(id: AdapterId, params?: ServiceParams): Promise<Message> {\n    return super.get(id, params)\n  }\n\n  async create(data: MessageData, params?: ServiceParams): Promise<Message>\n  async create(data: MessageData[], params?: ServiceParams): Promise<Message[]>\n  async create(data: MessageData | MessageData[], params?: ServiceParams): Promise<Message | Message[]> {\n    return super.create(data, params)\n  }\n\n  async update(id: AdapterId, data: MessageData, params?: ServiceParams): Promise<Message> {\n    return super.update(id, data, params)\n  }\n\n  async patch(id: null, data: MessagePatch, params?: ServiceParams): Promise<Message[]>\n  async patch(id: AdapterId, data: MessagePatch, params?: ServiceParams): Promise<Message>\n  async patch(\n    id: NullableAdapterId,\n    data: MessagePatch,\n    params?: ServiceParams\n  ): Promise<Message | Message[]> {\n    return super.patch(id, data, params)\n  }\n\n  async remove(id: AdapterId, params?: ServiceParams): Promise<Message>\n  async remove(id: null, params?: ServiceParams): Promise<Message[]>\n  async remove(id: NullableAdapterId, params?: ServiceParams): Promise<Message | Message[]> {\n    return super.remove(id, params)\n  }\n}\n```\n\n</DatabaseBlock>\n\n### Other service methods\n\n<DatabaseBlock global-id=\"sql\">\n\nIt is also possible to write your own service methods where the signatures don't have to match by extending from the `KnexAdapter` (instead of the `KnexService`) class. It does not have any of the service methods implemented but you can use the internal `_find`, `_get`, `_update`, `_patch` and `_remove` [adapter methods](../../api/databases/common.md#methods-without-hooks) to work with the database and implement the service method in the way you need.\n\n```ts\nimport { Id } from '@feathersjs/feathers'\nimport { KnexAdapter } from '@feathersjs/knex'\n\nexport interface MessageParams extends KnexAdapterParams<MessageQuery> {}\n\n// By default calls the standard Knex adapter service methods but can be customized with your own functionality.\nexport class MessageService<ServiceParams extends Params = MessageParams> extends KnexAdapter<\n  Message,\n  MessageData,\n  MessageParams,\n  MessagePatch\n> {\n  async find(params: ServiceParams) {\n    const page = this._find(params)\n\n    return {\n      status: 'ok',\n      ...page\n    }\n  }\n\n  async get(id: Id, params: ServiceParams) {\n    return {\n      message: `Hello ${id}`\n    }\n  }\n}\n```\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\nIt is also possible to write your own service methods where the signatures don't have to match by extending from the `MongoDbAdapter` (instead of the `MongoDBService`) class. It does not have any of the service methods implemented but you can use the internal `_find`, `_get`, `_update`, `_patch` and `_remove` [adapter methods](../../api/databases/common.md#methods-without-hooks) to work with the database and implement the service method the way you need.\n\n```ts\nimport { Id } from '@feathersjs/feathers'\nimport { MongoDbAdapter } from '@feathersjs/mongodb'\n\nexport interface MessageParams extends MongoDBAdapterParams<MessageQuery> {}\n\n// By default calls the standard MongoDB adapter service methods but can be customized with your own functionality.\nexport class MessageService<ServiceParams extends Params = MessageParams> extends MongoDbAdapter<\n  Message,\n  MessageData,\n  MessageParams,\n  MessagePatch\n> {\n  async find(params: ServiceParams) {\n    const page = this._find(params)\n\n    return {\n      status: 'ok',\n      ...page\n    }\n  }\n\n  async get(id: Id, params: ServiceParams) {\n    return {\n      message: `Hello ${id}`\n    }\n  }\n}\n```\n\n</DatabaseBlock>\n\n### Custom methods\n\n<DatabaseBlock global-id=\"sql\">\n\n[Custom service methods](../../api/services.md#custom-methods) can be added to an [SQL Knex service](../../api/databases/knex.md) as follows:\n\n```ts\nexport interface MessageParams extends KnexAdapterParams<MessageQuery> {}\n\nexport type MyMethodData = { greeting: string }\n\n// By default calls the standard Knex adapter service methods but can be customized with your own functionality.\nexport class MessageService<ServiceParams extends Params = MessageParams> extends KnexService<\n  Message,\n  MessageData,\n  MessageParams,\n  MessagePatch\n> {\n  async myMethod(data: MyMethodData, params: ServiceParams) {\n    return {\n      message: `${data.greeting || 'Hello'} ${params.user.name}!`\n    }\n  }\n}\n```\n\n</DatabaseBlock>\n\n<DatabaseBlock global-id=\"mongodb\">\n\n[Custom service methods](../../api/services.md#custom-methods) can be added to a [MongoDB service](../../api/databases/mongodb.md) like this:\n\n```ts\nexport interface MessageParams extends MongoDBAdapterParams<MessageQuery> {}\n\nexport type MyMethodData = { name: string }\n\n// By default calls the standard MongoDB adapter service methods but can be customized with your own functionality.\nexport class MessageService<ServiceParams extends Params = MessageParams> extends MongoDBService<\n  Message,\n  MessageData,\n  MessageParams,\n  MessagePatch\n> {\n  async myMethod(data: MyMethodData, params: ServiceParams) {\n    return {\n      message: `${data.greeting || 'Hello'} ${params.user.name}!`\n    }\n  }\n}\n```\n\n</DatabaseBlock>\n\n## Custom services\n\nAs shown in the [Quick start](../basics/starting.md), Feathers can work with any database, third party API or custom functionality by implementing your own [services](../../api/services.md). When generating a custom service, a basic skeleton service will be created. You can remove the methods you don't need and add others you need.\n\n<LanguageBlock global-id=\"ts\">\n\nWhile service methods still have to follow the [standard](../../api/services.md#service-methods) or [custom](../../api/services.md#custom-methods) method signatures, the parameter and return types can be whatever works best for the service you are implementing. If a service method is only for internal use (and not for clients to call) there are no method signature or return value restrictions.\n\n```ts\nimport type { Id, NullableId, Params } from '@feathersjs/feathers'\n\ninterface MyParams extends Params {}\n\nclass MyService {\n  async find(params: MyParams) {\n    return {\n      message: 'This type is inferred'\n    }\n  }\n\n  async get(id: Id) {\n    return [\n      {\n        id\n      }\n    ]\n  }\n\n  async create(data: Message, params: MyParams) {\n    return data\n  }\n\n  // Custom method made available to clients needs to have `data` and `params`\n  async customMethod(data: CustomMethodData, params: MyParams) {}\n\n  // A method that is only available internally can do anything\n  async anyOtherMethod() {\n    const [entry] = await this.get('david')\n\n    return entry.id\n  }\n}\n```\n\n</LanguageBlock>\n\n## getOptions\n\nThe `getOptions` function is a function that returns the options based on the [application](./app.md) that will be passed to the service class constructor. This is where you can pass [common adapter options](../../api/databases/common.md#options) as well as [MongoDB](../../api/databases/mongodb.md#serviceoptions) or [SQL](../../api/databases/knex.md#serviceoptions) specific or custom service options.\n"
  },
  {
    "path": "docs/guides/cli/service.md",
    "content": "---\noutline: deep\n---\n\n# Service\n\nThe main service file registers the service on the [application](./app.md) as well as the hooks used on this service.\n\n## Registration\n\nThe service is added to the main application via [app.use](../../api/application.md#usepath-service--options) under the path you chose when creating the service. It usses the following options:\n\n- `methods` - A list of methods available for external clients. You can remove methods that are not used or add your own [custom methods](../../api/services.md#custom-methods). Not that this list also has to be updated in the [client file](./client.md).\n- `events` - A list of additional [custom events](../../api/events.md#custom-events) sent to clients.\n\n<LanguageBlock global-id=\"ts\">\n\nIn TypeScript the `ServiceTypes` interface defined in the [declarations](./declarations.md) will also be extended with the correct service class type using the [shared path](./service.shared.md) as a key:\n\n```ts\ndeclare module '../../../declarations' {\n  interface ServiceTypes {\n    [testingPath]: TestingService\n  }\n}\n```\n\n</LanguageBlock>\n\n## Registering hooks\n\nThis file is also where service [hooks](../../api/hooks.md) are registered on the service. Depending on the selection, it commonly includes the [authentication hook](../../api/authentication/hook.md) and hooks that validate and resolve the schemas from the [service.schemas file](./service.schemas.md).\n\n```ts\n// Initialize hooks\napp.service(messagePath).hooks({\n  around: {\n    all: [\n      authenticate('jwt'),\n      schemaHooks.resolveExternal(messageExternalResolver),\n      schemaHooks.resolveResult(messageResolver)\n    ]\n  },\n  before: {\n    all: [schemaHooks.validateQuery(messageQueryValidator), schemaHooks.resolveQuery(messageQueryResolver)],\n    find: [],\n    get: [],\n    create: [schemaHooks.validateData(messageDataValidator), schemaHooks.resolveData(messageDataResolver)],\n    patch: [schemaHooks.validateData(messagePatchValidator), schemaHooks.resolveData(messagePatchResolver)],\n    remove: []\n  },\n  after: {\n    all: []\n  },\n  error: {\n    all: []\n  }\n})\n```\n\nNote that you can add hooks to a specific method as documented in the [hook registration API](../../api/hooks.md#registering-hooks). For example, to use the [profiling hook](./hook.md#profiling-example) only for `find` and `get` the registration can be updated like this:\n\n```ts{12-13}\nimport { profiler } from '../../hooks/profiler'\n// ...\n\n// Initialize hooks\napp.service(messagePath).hooks({\n  around: {\n    all: [\n      authenticate('jwt'),\n      schemaHooks.resolveExternal(messageExternalResolver),\n      schemaHooks.resolveResult(messageResolver)\n    ],\n    find: [profiler],\n    get: [profiler]\n  },\n  before: {\n    all: [schemaHooks.validateQuery(messageQueryValidator), schemaHooks.resolveQuery(messageQueryResolver)],\n    find: [],\n    get: [],\n    create: [schemaHooks.validateData(messageDataValidator), schemaHooks.resolveData(messageDataResolver)],\n    patch: [schemaHooks.validateData(messagePatchValidator), schemaHooks.resolveData(messagePatchResolver)],\n    remove: []\n  },\n  after: {\n    all: []\n  },\n  error: {\n    all: []\n  }\n})\n```\n\nThis also applies to any hook plugins like [feathers-hooks-common](https://hooks-common.feathersjs.com/).\n"
  },
  {
    "path": "docs/guides/cli/service.schemas.md",
    "content": "---\noutline: deep\n---\n\n# Service Schemas and Resolvers\n\nThe `<service>.schemas` file contains the [schemas and resolvers](../../api/schema/index.md) for this service.\n\n<BlockQuote type=\"info\">\n\nThe examples on this page are using [TypeBox](../../api/schema/typebox.md). For more information on plain JSON schema see the [JSON schema API documentation](../../api/schema/schema.md).\n\n</BlockQuote>\n\n## Patterns\n\nThere a four main types of schemas and resolvers. The schemas, resolvers and types are declared as follows:\n\n```ts\n// The schema definition\nexport const nameSchema = Type.Object({\n  text: Type.String()\n})\n// The TypeScript type inferred from the schema\nexport type Name = Static<typeof nameSchema>\n// The validator for the schema\nexport const nameValidator = getValidator(nameSchema, dataValidator)\n// The resolver for the schema\nexport const nameResolver = resolve<Name, HookContext>({})\n```\n\n## Main schema and resolvers\n\nThis schema defines the main data model of all properties and is normally the shape of the data that is returned. This includes database properties as well as associations and other computed properties.\n\n```ts\n// Main data model schema\nexport const messageSchema = Type.Object(\n  {\n    id: Type.Number(),\n    text: Type.String()\n  },\n  { $id: 'Message', additionalProperties: false }\n)\nexport type Message = Static<typeof messageSchema>\nexport const messageValidator = getValidator(messageSchema, dataValidator)\nexport const messageResolver = resolve<Message, HookContext>({})\n```\n\n## External Resolvers\n\nThe external resolver defines the data that is sent to a client and is often use to e.g. hide protected properties they should not see:\n\n```ts\nexport const messagesExternalResolver = resolve<Messages, HookContext>({\n  someSecretProperty: async () => undefined\n})\n```\n\n## Data schema and resolvers\n\nThe data schema validates the data when creating a new entry calling [service.create](../../api/services.md#createdata-params). It usually picks its properties from the [main schema](#main-schemas-and-resolvers) but can be changed to whatever is needed.\n\n```ts\n// Schema for creating new entries\nexport const messageDataSchema = Type.Pick(messageSchema, ['text'], {\n  $id: 'MessageData'\n})\nexport type MessageData = Static<typeof messageDataSchema>\nexport const messageDataValidator = getValidator(messageDataSchema, dataValidator)\nexport const messageDataResolver = resolve<Message, HookContext>({})\n```\n\n## Patch schema and Resolvers\n\nThe patch schema is used for updating existing entries calling [service.patch](../../api/services.md#patchid-data-params). This is often different then the data schema for new entries and by default is a partial of the [main schema](#main-schemas-and-resolvers).\n\n```ts\n// Schema for updating existing entries\nexport const messagePatchSchema = Type.Partial(messageSchema, {\n  $id: 'MessagePatch'\n})\nexport type MessagePatch = Static<typeof messagePatchSchema>\nexport const messagePatchValidator = getValidator(messagePatchSchema, dataValidator)\nexport const messagePatchResolver = resolve<Message, HookContext>({})\n```\n\n## Query Schema and Resolvers\n\nThe query schema defines what can be sent in queries in [params.query](../../api/services.md#params) and also converts strings to the correct type.\n\n```ts\n// Schema for allowed query properties\nexport const messageQueryProperties = Type.Pick(messageSchema, ['id', 'text', 'createdAt', 'userId'])\nexport const messageQuerySchema = Type.Intersect(\n  [\n    querySyntax(messageQueryProperties),\n    // Add additional query properties here\n    Type.Object({}, { additionalProperties: false })\n  ],\n  { additionalProperties: false }\n)\nexport type MessageQuery = Static<typeof messageQuerySchema>\nexport const messageQueryValidator = getValidator(messageQuerySchema, queryValidator)\nexport const messageQueryResolver = resolve<MessageQuery, HookContext>({})\n```\n\nTo add additional operators like `$like` see the [querySyntax](../../api/schema/typebox.md#querysyntax) documentation. You can also add your own query parameters in the `Type.Object({}, { additionalProperties: false })` definition.\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nNote that references (`Type.Ref`) can not be used in a query schema. Association querying is usually done by dot separated properties which have to be added manually in [MongoDB](../../api/databases/mongodb.md#querying) and [SQL](../../api/databases/knex.md#associations).\n\n</BlockQuote>\n"
  },
  {
    "path": "docs/guides/cli/service.shared.md",
    "content": "---\noutline: deep\n---\n\n# Service Shared\n\nThe `<service>.shared` file contains variables and type declarations that are shared between the [client](./client.md) and the [server application](./app.md). It can also be used for shared utility functions or schemas (e.g. for client side validation).\n\n## Variables\n\nBy default two shared variables are exported:\n\n- `<name>Path` - The path of the service. Changing this will change the path for the service in all places like the application, the client and types\n- `<name>Methods` - The list of service methods available to the client. This can be updated with service and custom methods a client should be able to use.\n\n## Client setup\n\nThis file also includes the client side service registration which will be included in the [client](./client.md). It will register a client side service based on the shared path and methods.\n"
  },
  {
    "path": "docs/guides/cli/service.test.md",
    "content": "---\noutline: deep\n---\n\n# Service tests\n\nThe `<service>.test` file contains tests for a specific service. By default it just checks if the service has been registered.\n\n## Testing the service\n\nServices can be tested by using the [application](./app.md) object through Feathers standard APIs:\n\n```ts\n// For more information about this file see https://dove.feathersjs.com/guides/cli/service.test.html\nimport assert from 'assert'\nimport { app } from '../../../src/app'\n\ndescribe('users service', () => {\n  it('registered the service', () => {\n    const service = app.service('users')\n\n    assert.ok(service, 'Registered the service')\n  })\n\n  it('finds all users', async () => {\n    const users = await app.service('users').find({\n      paginate: false\n    })\n\n    assert.ok(Array.isArray(users))\n  })\n})\n```\n\n## Authenticated tests\n\nTo test service internals that require a logged in user, it is not necessary to go through the full authentication flow. Instead a test user can be created and then passed as `params.user` just like it would when authenticated:\n\n```ts\n// For more information about this file see https://dove.feathersjs.com/guides/cli/service.test.html\nimport assert from 'assert'\nimport { app } from '../../../src/app'\n\ndescribe('messages service', () => {\n  it('registered the service', () => {\n    const service = app.service('messages')\n\n    assert.ok(service, 'Registered the service')\n  })\n\n  it('can create a new message for a user', async () => {\n    const user = await app.service('users').create({\n      email: 'test@feathersjs.com',\n      password: 'supersecret'\n    })\n\n    const message = await app.service('messages').create(\n      {\n        text: 'Hello world'\n      },\n      { user }\n    )\n\n    assert.strictEqual(message.userId, user.id)\n\n    await app.service('messages').remove(message.id)\n    await app.service('users').remove(user.id)\n  })\n})\n```\n\n<BlockQuote label=\"tip\">\n\nIf you want to test the full authentication and external access flow the [client.test](./client.test.md) can be used.\n\n</BlockQuote>\n"
  },
  {
    "path": "docs/guides/cli/tsconfig.md",
    "content": "# tsconfig.json\n"
  },
  {
    "path": "docs/guides/cli/validators.md",
    "content": "---\noutline: deep\n---\n\n# Validators\n\nFor all currently supported schema types, AJV is used as the default validator. See the [validators API documentation](../../api/schema/validators.md) for more information.\n\n## AJV validators\n\nThe `src/validators.ts` file sets up two Ajv instances for data and querys (for which string types will be coerced automatically). It also sets up a collection of additional formats using [ajv-formats](https://ajv.js.org/packages/ajv-formats.html). The validators in this file can be customized according to the [Ajv documentation](https://ajv.js.org/) and [its plugins](https://ajv.js.org/packages/). You can find the available Ajv options in the [Ajs class API docs](https://ajv.js.org/options.html).\n\n```ts\nimport { Ajv, addFormats } from '@feathersjs/schema'\nimport type { FormatsPluginOptions } from '@feathersjs/schema'\n\nconst formats: FormatsPluginOptions = [\n  'date-time',\n  'time',\n  'date',\n  'email',\n  'hostname',\n  'ipv4',\n  'ipv6',\n  'uri',\n  'uri-reference',\n  'uuid',\n  'uri-template',\n  'json-pointer',\n  'relative-json-pointer',\n  'regex'\n]\n\nexport const dataValidator = addFormats(new Ajv({}), formats)\n\nexport const queryValidator = addFormats(\n  new Ajv({\n    coerceTypes: true\n  }),\n  formats\n)\n```\n\n## MongoDB ObjectIds\n\nWhen choosing MongoDB, the validators file will also register the [`objectid` keyword](../../api/databases/mongodb.md#ajv-keyword) to convert strings to MongoDB Object ids.\n"
  },
  {
    "path": "docs/guides/frameworks.md",
    "content": "# Frontend Frameworks\n\nFeathers works the same on the server and on the client and is front-end framework agnostic. You can use it with Vue, React, React Native, Angular, or whatever other front-end tech stack you choose.\n\n## Client Side Docs\n\nIf you want to learn how to use Feathers as a client in Node.js, React Native, or in the browser with a module loader like Webpack refer to the [client API docs](../api/client.md).\n\n## The Feathers chat\n\nThe [Feathers Chat application](../guides/) from guide gives a basic intro to using the Feathers Client in a vanilla JavaScript environment. That's a good place to start to see how things fit together. Framework specific repositories can be found at:\n\n- JavaScript + plain JS frontend: [feathersjs/feathers-chat](https://github.com/feathersjs/feathers-chat)\n- TypeScript + plain JS frontend: [feathersjs/feathers-chat-ts](https://github.com/feathersjs/feathers-chat-ts)\n- React: [feathersjs-ecosystem/feathers-chat-react](https://github.com/feathersjs-ecosystem/feathers-chat-react)\n- React Native: [feathersjs-ecosystem/feathers-react-native-chat](https://github.com/feathersjs-ecosystem/feathers-react-native-chat)\n- Angular: [feathersjs-ecosystem/feathers-chat-angular](https://github.com/feathersjs-ecosystem/feathers-chat-angular)\n- VueJS with Vuex: [feathersjs-ecosystem/feathers-chat-vuex](https://github.com/feathersjs-ecosystem/feathers-chat-vuex)\n\n## Examples\n\nBeyond the basics, see [this list](https://github.com/feathersjs/awesome-feathersjs#examples) of Feathers examples in [awesome-feathersjs](https://github.com/feathersjs/awesome-feathersjs).\n\n## Framework Integrations\n\nSee [this list](https://github.com/feathersjs/awesome-feathersjs#frontend-frameworks) of Feathers front-end framework integrations if you are looking for something that makes Feathers even easier to use with things like React, Vue or others.\n"
  },
  {
    "path": "docs/guides/frontend/javascript.md",
    "content": "---\noutline: deep\n---\n\n# JavaScript web app\n\nAs we have seen [in the quick start guide](../basics/starting.md), Feathers works great in the browser and comes with client services that allow it to easily connect to a Feathers server.\n\nIn this chapter we will create a real-time chat web application with signup and login using modern plain JavaScript that connects to the API server we built in the [getting started guide](../basics/generator.md). It is mobile friendly and will work in the latest versions of Chrome, Firefox, Safari and Edge. We won't be be using a transpiler like Webpack or Babel which is also why there is no TypeScript option. The final version can be found in `public/` folder of the [feathers-chat repository](https://github.com/feathersjs/feathers-chat/tree/dove/public).\n\n![The Feathers chat application](../basics/assets/feathers-chat.png)\n\n<BlockQuote type=\"tip\">\n\nWe will not be using a frontend framework so we can focus on what Feathers is all about. Feathers is framework agnostic and can be used with any frontend framework like React, VueJS or Angular. For more information see the [frameworks section](../frameworks.md).\n\n</BlockQuote>\n\n## Set up the page\n\nFirst, let's update `public/index.html` to initialize everything we need for the chat frontend:\n\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>feathers-chat</title>\n    <meta name=\"description\" content=\"A Feathers chat application\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <link\n      href=\"https://cdn.jsdelivr.net/npm/tailwindcss@2.2/dist/tailwind.min.css\"\n      rel=\"stylesheet\"\n      type=\"text/css\"\n    />\n    <link href=\"https://cdn.jsdelivr.net/npm/daisyui@2.18.1/dist/full.css\" rel=\"stylesheet\" type=\"text/css\" />\n    <link rel=\"stylesheet\" href=\"https://dove.feathersjs.com/feathers-chat.css\" />\n  </head>\n  <body>\n    <div id=\"app\" data-theme=\"dracula\"></div>\n    <script src=\"https://unpkg.com/@feathersjs/client@^5.0.0-pre.34/dist/feathers.js\"></script>\n    <script src=\"/socket.io/socket.io.js\"></script>\n    <script type=\"module\" src=\"client.js\"></script>\n  </body>\n</html>\n```\n\nThis will load our chat CSS style, add a container div `#app` and load several libraries:\n\n- The browser version of Feathers (since we are not using a module loader like Webpack or Browserify)\n- Socket.io provided by the chat API\n- [daisyUI](https://daisyui.com/) for a collection of CSS components\n- A `client.js` for our code to live in\n\nLet’s create `public/client.js` where all the following code will live. Each of the following code samples should be added to the end of that file.\n\n## Connect to the API\n\nWe’ll start with the most important thing first, the connection to our Feathers API that connects to our server using websockets and initializes the [authentication client](../basics/authentication.md):\n\n```js\n/* global io, feathers, moment */\n// Establish a Socket.io connection\nconst socket = io()\n// Initialize our Feathers client application through Socket.io\n// with hooks and authentication.\nconst client = feathers()\n\nclient.configure(feathers.socketio(socket))\n// Use localStorage to store our login token\nclient.configure(feathers.authentication())\n```\n\n## Base HTML\n\nNext, we have to define some static and dynamic HTML that we can insert into the page when we want to show the login page (which also doubles as the signup page) and the actual chat interface:\n\n```js\n// Login screen\nconst loginTemplate = (error) => `<div class=\"login flex min-h-screen bg-neutral justify-center items-center\">\n<div class=\"card w-full max-w-sm bg-base-100 px-4 py-8 shadow-xl\">\n  <div class=\"px-4\"><i alt=\"\" class=\"h-32 w-32 block mx-auto i-logos-feathersjs invert\"></i>\n    <h1 class=\"text-5xl font-bold text-center my-5 bg-clip-text bg-gradient-to-br\">\n      Feathers Chat\n    </h1>\n  </div>\n  <form class=\"card-body pt-2\">\n    ${\n      error\n        ? `<div class=\"alert alert-error justify-start\">\n      <i class=\"i-feather-alert-triangle\"></i>\n      <span class=\"flex-grow\">${error.message}</span>\n    </div>`\n        : ''\n    }\n    <div class=\"form-control\">\n      <label for=\"email\" class=\"label\"><span class=\"label-text\">Email</span></label>\n      <input type=\"text\" name=\"email\" placeholder=\"enter email\" class=\"input input-bordered\">\n    </div>\n    <div class=\"form-control mt-0\">\n      <label for=\"password\" class=\"label\"><span class=\"label-text\">Password</span></label>\n      <input type=\"password\" name=\"password\" placeholder=\"enter password\" class=\"input input-bordered\">\n    </div>\n    <div class=\"form-control mt-6\"><button id=\"login\" type=\"button\" class=\"btn\">Login</button></div>\n    <div class=\"form-control mt-6\"><button id=\"signup\" type=\"button\" class=\"btn\">Signup</button></div>\n    <div class=\"form-control mt-6\"><a href=\"/oauth/github\" id=\"github\" class=\"btn\">Login with GitHub</a></div>\n  </form>\n</div>\n</div>`\n\n// Main chat view\nconst chatTemplate =\n  () => `<div class=\"drawer drawer-mobile\"><input id=\"drawer-left\" type=\"checkbox\" class=\"drawer-toggle\">\n  <div class=\"drawer-content flex flex-col\">\n    <div class=\"navbar w-full\">\n      <div class=\"navbar-start\">\n        <label for=\"drawer-left\" class=\"btn btn-square btn-ghost lg:hidden drawer-button\">\n          <i class=\"i-feather-menu text-lg\"></i>\n        </label>\n      </div>\n      <div class=\"navbar-center flex flex-col\">\n        <p>Feathers Chat</p>\n        <label for=\"drawer-right\" class=\"text-xs cursor-pointer\">\n          <span class=\"online-count\">0</span> User(s)\n        </label>\n      </div>\n      <div class=\"navbar-end\">\n        <div class=\"tooltip tooltip-left\" data-tip=\"Logout\">\n        <button type=\"button\" id=\"logout\" class=\"btn btn-ghost\"><i class=\"i-feather-log-out text-lg\"></i></button>\n      </div>\n      </div>\n    </div>\n    <div id=\"chat\" class=\"h-full overflow-y-auto px-3\"></div>\n    <div class=\"form-control w-full py-2 px-3\">\n      <form class=\"input-group overflow-hidden\" id=\"send-message\">\n        <input name=\"text\" type=\"text\" placeholder=\"Compose message\" class=\"input input-bordered w-full\">\n        <button type=\"submit\" class=\"btn\">Send</button>\n      </form>\n    </div>\n  </div>\n  <div class=\"drawer-side\"><label for=\"drawer-left\" class=\"drawer-overlay\"></label>\n    <ul class=\"menu user-list compact p-2 overflow-y-auto w-60 bg-base-300 text-base-content\">\n      <li class=\"menu-title\"><span>Users</span></li>\n    </ul>\n  </div>\n</div>`\n\n// Helper to safely escape HTML\nconst escapeHTML = (str) => str.replace(/&/g, '&amp').replace(/</g, '&lt').replace(/>/g, '&gt')\n\nconst formatDate = (timestamp) =>\n  new Intl.DateTimeFormat('en-US', {\n    timeStyle: 'short',\n    dateStyle: 'medium'\n  }).format(new Date(timestamp))\n\n// Add a new user to the list\nconst addUser = (user) => {\n  const userList = document.querySelector('.user-list')\n\n  if (userList) {\n    // Add the user to the list\n    userList.innerHTML += `<li class=\"user\">\n      <a>\n        <div class=\"avatar indicator\">\n          <div class=\"w-6 rounded\"><img src=\"${user.avatar}\" alt=\"${user.email}\"></div>\n        </div><span>${user.email}</span>\n      </a>\n    </li>`\n\n    // Update the number of users\n    const userCount = document.querySelectorAll('.user-list li.user').length\n\n    document.querySelector('.online-count').innerHTML = userCount\n  }\n}\n\n// Renders a message to the page\nconst addMessage = (message) => {\n  // The user that sent this message (added by the populate-user hook)\n  const { user = {} } = message\n  const chat = document.querySelector('#chat')\n  // Escape HTML to prevent XSS attacks\n  const text = escapeHTML(message.text)\n\n  if (chat) {\n    chat.innerHTML += `<div class=\"chat chat-start py-2\">\n      <div class=\"chat-image avatar\">\n        <div class=\"w-10 rounded-full\">\n          <img src=\"${user.avatar}\" />\n        </div>\n      </div>\n      <div class=\"chat-header pb-1\">\n        ${user.email}\n        <time class=\"text-xs opacity-50\">${formatDate(message.createdAt)}</time>\n      </div>\n      <div class=\"chat-bubble\">${text}</div>\n    </div>`\n\n    // Always scroll to the bottom of our message list\n    chat.scrollTop = chat.scrollHeight - chat.clientHeight\n  }\n}\n```\n\nThis will add the following variables and functions:\n\n- `loginTemplate` - A function that returns static HTML for the login/signup page. We can also pass an error to render an additional error message\n- `chatTemplate` - Returns the HTML for the main chat page content (once a user is logged in)\n- `addUser(user)` is a function to add a new user to the user list on the left\n- `addMessage(message)` is a function to add a new message to the list. It will also make sure that we always scroll to the bottom of the message list as messages get added\n\n## Displaying pages\n\nNext, we'll add two functions to display the login and chat page, where we'll also add a list of the 25 newest chat messages and the registered users.\n\n```js\n// Show the login page\nconst showLogin = () => {\n  document.getElementById('app').innerHTML = loginTemplate()\n}\n\n// Shows the chat page\nconst showChat = async () => {\n  document.getElementById('app').innerHTML = chatTemplate()\n\n  // Find the latest 25 messages. They will come with the newest first\n  const messages = await client.service('messages').find({\n    query: {\n      $sort: { createdAt: -1 },\n      $limit: 25\n    }\n  })\n\n  // We want to show the newest message last\n  messages.data.reverse().forEach(addMessage)\n\n  // Find all users\n  const users = await client.service('users').find()\n\n  // Add each user to the list\n  users.data.forEach(addUser)\n}\n```\n\n- `showLogin(error)` will either show the content of loginTemplate or, if the login page is already showing, add an error message. This will happen when you try to log in with invalid credentials or sign up with a user that already exists.\n- `showChat()` does several things. First, we add the static chatTemplate to the page. Then we get the latest 25 messages from the messages Feathers service (this is the same as the `/messages` endpoint of our chat API) using the Feathers query syntax. Since the list will come back with the newest message first, we need to reverse the data. Then we add each message by calling our `addMessage` function so that it looks like a chat app should — with old messages getting older as you scroll up. After that we get a list of all registered users to show them in the sidebar by calling addUser.\n\n## Login and signup\n\nAlright. Now we can show the login page (including an error message when something goes wrong) and if we are logged in, call the `showChat` we defined above. We’ve built out the UI, now we have to add the functionality to actually allow people to sign up, log in and also log out.\n\n```js\n// Retrieve email/password object from the login/signup page\nconst getCredentials = () => {\n  const user = {\n    email: document.querySelector('[name=\"email\"]').value,\n    password: document.querySelector('[name=\"password\"]').value\n  }\n\n  return user\n}\n\n// Log in either using the given email/password or the token from storage\nconst login = async (credentials) => {\n  try {\n    if (!credentials) {\n      // Try to authenticate using an existing token\n      await client.reAuthenticate()\n    } else {\n      // Otherwise log in with the `local` strategy using the credentials we got\n      await client.authenticate({\n        strategy: 'local',\n        ...credentials\n      })\n    }\n\n    // If successful, show the chat page\n    showChat()\n  } catch (error) {\n    // If we got an error, show the login page\n    showLogin(error)\n  }\n}\n```\n\n- `getCredentials()` gets us the values of the username (email) and password fields from the login/signup page to be used directly with Feathers authentication.\n- `login(credentials)` will either authenticate the credentials returned by getCredentials against our Feathers API using the local authentication strategy (e.g. username and password) or, if no credentials are given, try to use the JWT stored in localStorage. This will try and get the JWT from localStorage first where it is put automatically once you log in successfully so that we don’t have to log in every time we visit the chat. Only if that doesn’t work will it show the login page. Finally, if the login was successful it will show the chat page.\n\n## Event listeners and real-time\n\nIn the last step we will add event listeners for all buttons and functionality to send new messages and make the user and message list update in real-time.\n\n```js\nconst addEventListener = (selector, event, handler) => {\n  document.addEventListener(event, async (ev) => {\n    if (ev.target.closest(selector)) {\n      handler(ev)\n    }\n  })\n}\n\n// \"Signup and login\" button click handler\naddEventListener('#signup', 'click', async () => {\n  // For signup, create a new user and then log them in\n  const credentials = getCredentials()\n\n  // First create the user\n  await client.service('users').create(credentials)\n  // If successful log them in\n  await login(credentials)\n})\n\n// \"Login\" button click handler\naddEventListener('#login', 'click', async () => {\n  const user = getCredentials()\n\n  await login(user)\n})\n\n// \"Logout\" button click handler\naddEventListener('#logout', 'click', async () => {\n  await client.logout()\n\n  document.getElementById('app').innerHTML = loginTemplate()\n})\n\n// \"Send\" message form submission handler\naddEventListener('#send-message', 'submit', async (ev) => {\n  // This is the message text input field\n  const input = document.querySelector('[name=\"text\"]')\n\n  ev.preventDefault()\n\n  // Create a new message and then clear the input field\n  await client.service('messages').create({\n    text: input.value\n  })\n\n  input.value = ''\n})\n\n// Listen to created events and add the new message in real-time\nclient.service('messages').on('created', addMessage)\n\n// We will also see when new users get created in real-time\nclient.service('users').on('created', addUser)\n\n// Call login right away so we can show the chat window\n// If the user can already be authenticated\nlogin()\n```\n\n- `addEventListener` is a helper function that lets us add listeners to elements that get added or removed dynamically\n- We also added click event listeners for three buttons. `#login` will get the credentials and just log in with those. Clicking `#signup` will signup and log in at the same time. It will first create a new user on our API and then log in with that same user information. Finally, `#logout` will forget the JWT and then show the login page again.\n- The `#submit` button event listener gets the message text from the input field, creates a new message on the messages service and then clears out the field.\n- Next, we added two `created` event listeners. One for `messages` which calls the `addMessage` function to add the new message to the list and one for `users` which adds the user to the list via `addUser`. This is how Feathers does real-time and everything we need to do in order to get everything to update automatically.\n- To kick our application off, we call `login()` which as mentioned above will either show the chat application right away (if we signed in before and the token hasn’t expired) or the login page.\n\n## Using the chat application\n\nThat’s it. We now have a plain JavaScript real-time chat frontend with login and signup. This example demonstrates many of the basic principles of how you interact with a Feathers API. You can log in with the email (`hello@feathersjs.com`) and password (`supersecret`) from the user we registered in the [authentication chapter](../basics/authentication.md) or sign up and log in with a different email address.\n\nIf you run into an issue, remember you can find the complete working example at the [feathersjs/feathers-chat](https://github.com/feathersjs/feathers-chat) repository.\n"
  },
  {
    "path": "docs/guides/index.md",
    "content": "---\noutline: deep\n---\n\n# Getting started with Feathers\n\nWelcome to the Feathers guides! This is the place to find all the resources to get started with Feathers.\n\n<img style=\"margin: 2em 0;\" src=\"/img/main-character-starting.svg\" alt=\"Setting up\">\n\n## The Feathers guide\n\nThe Feathers guide will walk you through all the important parts of Feathers. The [quick start](./basics/starting.md) gets you up and running with a Feathers API and real-time website in less than 15 minutes from scratch to give you an idea what Feathers is about.\n\nIn the next parts we will [generate an application](./basics/generator.md) and then walk through Feathers core concepts like services, hooks and authentication by building a complete real-time chat application with an API and a website that can register users and send and receive messages in real-time. We will also add a login with GitHub and write unit tests for our API.\n\n[Get started with the Feathers guide >](./basics/starting.md)\n\n## Follow up with\n\n[The API documentation >](../api/)\n\n[The cookbook for common tasks and patterns >](../cookbook/)\n\n[The Awesome FeathersJS Ecosystem >](https://github.com/feathersjs/awesome-feathersjs)\n\n[Feathers on YouTube >](https://www.youtube.com/playlist?list=PLwSdIiqnDlf_lb5y1liQK2OW5daXYgKOe)\n\n## More about Feathers how and why\n\n[Read about the philosophy behind Feathers and where it came from >](https://blog.feathersjs.com/why-we-built-the-best-web-framework-you-ve-probably-never-heard-of-until-now-176afc5c6aac)\n\n[Learn about the high level design patterns behind Feathers >](https://blog.feathersjs.com/design-patterns-for-modern-web-apis-1f046635215)\n\n[See how Feathers compares to others >](https://feathersjs.com/comparison)\n"
  },
  {
    "path": "docs/guides/migrating.md",
    "content": "---\noutline: deep\n---\n\n# Migrating to v5\n\nThis guide explains the new features and changes necessary to migrate to the Feathers v5 (Dove) release. It expects applications to be using the previous Feathers v4 (Crow). See the [v4 (Crow) migration guide](https://crow.docs.feathersjs.com/guides/migrating.html) for upgrading to the previous version.\n\n## Testing the prerelease\n\nYou can run the following to upgrade all Feathers core packages:\n\n```\nnpx npm-check-updates --upgrade --filter /@feathersjs/\nnpm install\n```\n\nYou can see the migration steps necessary for the Feathers chat [here for Javascript](https://github.com/feathersjs/feathers-chat/compare/dove-pre) and [here for TypeScript](https://github.com/feathersjs/feathers-chat-ts/compare/dove-pre).\n\n## New Features\n\nThere are so many new features in this release that they got their own page! Read about the new features on the [What's New in v5](./whats-new.md) page.\n\n## Core SQL and MongoDB\n\nThe new [schemas and resolvers](../api/schema/index.md) cover most use cases previously provided by higher level ORMs like Sequelize or Mongoose in a more flexible and Feathers friendly way. This allows for a better database integration into Feathers without the overhead of a full ORM which is why the more low level [MongoDB](../api/databases/mongodb.md) and [Knex](../api/databases/knex.md) (SQL) database adapters have been moved into Feathers core for first-class SQL and MongoDB database support.\n\n## TypeScript\n\n<LanguageBlock global-id=\"js\">\n\nYou have selected JavaScript as the language which does not have type information.\n\n</LanguageBlock>\n\n<LanguageBlock global-id=\"ts\">\n\nThe new version comes with major improvements in TypeScript support from improved service typings, fully typed hook context and typed configuration. You can see the changes necessary in the Feathers chat [here](https://github.com/feathersjs/feathers-chat-ts/compare/dove-pre).\n\n### Application and hook context\n\nTo get the typed hook context and application configuration update your `declarations.ts` as follows:\n\n```ts\nimport '@feathersjs/transport-commons'\nimport { Application as ExpressFeathers } from '@feathersjs/express'\nimport { HookContext as FeathersHookContext } from '@feathersjs/feathers'\n\nexport interface Configuration {\n  // Put types for app.get and app.set here\n  port: number\n}\n// A mapping of service names to types. Will be extended in service files.\nexport interface ServiceTypes {}\n// The application instance type that will be used everywhere else\nexport type Application = ExpressFeathers<ServiceTypes, Configuration>\nexport type HookContext = FeathersHookContext<Application>\n```\n\nNow `import { HookContext } from './declarations'` can be used as the context in hooks.\n\n### Service types\n\n\n\nService types now only need the actual service class type and should no longer include the `& ServiceAddons<any>`. E.g. for the messages service like this:\n\n```ts\n// Add this service to the service type index\ndeclare module '../../declarations' {\n  interface ServiceTypes {\n    messages: Messages\n  }\n}\n```\n\n### Configuration types\n\nA Feathers application can now also include types for the values of `app.set` and `app.get`. The configuration can also be validated and the type inferred from a [Feathers schema](../api/schema/index.md).\n\n### Typed params and query\n\nService `Params` no longer include a catchall property type and need to be explicitly declared for services that use extended `params`. It is also possible to pass your own query type to use with `params.query`:\n\n```ts\nimport { Params } from '@feathersjs/feathers'\n\nexport type MyQuery = {\n  name: string\n}\n\nexport interface MyServiceParams extends Params<MyQuery> {\n  user: User\n}\n```\n\nYou can revert to the previous behaviour by overriding he `Params` declaration:\n\n```ts\ndeclare module '@feathersjs/feathers/lib/declarations' {\n  interface Params {\n    [key: string]: any\n  }\n}\n```\n\n</LanguageBlock>\n\n## Deprecations and breaking changes\n\n### Express middleware order\n\nThe Express `rest` adapter now needs to be configured in the correct order, usually right after the `json()` middleware and before any services are registered. This is already the case in generated applications but it may have to be adjusted in a custom setup.\n\n### Core named export\n\nThe import of `feathers` has changed from\n\n```ts\nconst feathers = require('@feathersjs/feathers')\n\nimport feathers from '@feathersjs/feathers'\n```\n\nTo\n\n```ts\nconst { feathers } = require('@feathersjs/feathers')\n\nimport { feathers } from '@feathersjs/feathers'\n```\n\nThe Express exports for TypeScript have changed from\n\n```ts\nimport express from '@feathersjs/express'\n\napp.use(express.json())\napp.use(express.urlencoded())\napp.use(express.notFound())\napp.use(express.errorHandler())\n```\n\nTo\n\n```ts\nimport express, { json, urlencoded, notFound, errorHandler } from '@feathersjs/express'\n\napp.use(json())\napp.use(urlencoded())\napp.use(notFound())\napp.use(errorHandler())\n```\n\n### Custom Filters & Operators\n\n<BlockQuote type=\"warning\" label=\"pending\">\n\nWe are exploring the best migration strategy to replace \"whitelisting\" options with a solution based on [Feathers schema](/api/schema/index). We'll update this guide once the solution is in place.\n\n</BlockQuote>\n\nThe `whitelist` option is now split into two options: `operators` and `filters`. To migrate, you need to figure out how you're using each item from your old `whitelist`, then move them to the correct option. You can determine if each one is a filter or an operator based on where it is used in a query.\n\n- `filters` are top-level query properties.\n- `operators` are positioned under an attribute.\n\nIn the below example, `$customFilter` would be a filter, `$regex` and `$options` would be operators.\n\n```ts\nconst query = {\n  $customFilter: 'value',\n  name: {\n    $regex: /pattern/,\n    $options: 'igm'\n  }\n}\n```\n\nFor v5 service adapters, split the `whitelist` options into the `filters` object or the `operators` array.\n\n```ts\n// 👎`whitelist` and `allow are unsupported.\nconst oldServiceOptions = {\n  whitelist: ['$customFilter', '$ignoreCase', '$regex', '$options']\n}\n\n// 👍 Separate items into `filters` and `operators` for v5 service adapters\nconst serviceOptions = {\n  filters: {\n    // Map a custom filter to a converter function\n    $ignoreCase: (value: any) => (value === 'true' ? true : false),\n    // Enable a custom param without converting\n    $customQueryOperator: true\n  } as const,\n  operators: ['$regex', '$options']\n}\n```\n\n<LanguageBlock global-id=\"ts\">\n\nIf you're using TypeScript, notice the `as const` after the `filters` object in the options, above. That will keep type errors from happening when passing the `serviceOptions` to the service.\n\n</LanguageBlock>\n\n<BlockQuote>\n\nThis change only affects service adapters that have been upgraded to v5, like [@feathersjs/mongodb](/api/databases/mongodb), [@feathersjs/knex](/api/databases/knex), and [@feathersjs/memory](/api/databases/memory). This also applies to any community-supported adapters which have been upgraded to v5. If you use a v4 adapter for a service in your v5 app, you do not need to make this change for that service.\n\n</BlockQuote>\n\n### Asynchronous setup\n\n`service.setup`, `app.setup` and `app.listen` return a Promise:\n\n```js\n// Before\nconst server = app.listen(3030)\n\n// Now\napp.listen(3030).then((server) => {})\n```\n\nUsually you would call `app.listen`. In case you are calling `app.setup` instead (e.g. for internal jobs or seed scripts) it is now also asynchronous:\n\n```js\n// Before\napp.setup()\n// Do something here\n\n// Now\nawait app.setup()\n// Do something here\n```\n\n### Socket.io 4 and Grant 5\n\nThe Socket.io and Grant (oAuth) dependencies have been updated to their latest versions. For more information on breaking changes see:\n\n- The Socket.io [version 3](https://socket.io/docs/v3/migrating-from-2-x-to-3-0/index.html#How-to-upgrade-an-existing-production-deployment) and [version 4](https://socket.io/docs/v3/migrating-from-3-x-to-4-0/) upgrade guide. Important points to note are a new improved [CORS policy](https://socket.io/docs/v3/migrating-from-2-x-to-3-0/index.html#CORS-handling) and an [explicit v2 client compatibility opt-in](https://socket.io/docs/v3/migrating-from-2-x-to-3-0/index.html#How-to-upgrade-an-existing-production-deployment)\n- For oAuth authentication the Grant standard configuration should continue to work as is. If you customized any other settings, see the [Grant v4 to v5 migration guide](https://github.com/simov/grant/blob/master/MIGRATION.md) for the changes necessary.\n\n### Configuration\n\nThe automatic environment variable substitution in `@feathersjs/configuration` was causing subtle and hard to debug issues. It has been removed to instead rely on the functionality already provided and battle tested by the underlying [node-config](https://github.com/lorenwest/node-config). To update your configuration:\n\n- Relative paths are no longer relative to the configuration file, but instead to where the application runs. This normally (when running from the application folder) means that paths starting with `../` and `./` have to be replaced with `./` and `./config/`.\n- Configuration through environment variables should be included via the `NODE_CONFIG` JSON string or as [Custom Environment Variable support](https://github.com/lorenwest/node-config/wiki/Environment-Variables#custom-environment-variables). To use existing environment variables add the following configuration file in `config/custom-environment-variables.json` like this:\n\n```json\n// config/custom-environment-variables.json\n{\n  \"hostname\": \"HOSTNAME\",\n  \"port\": \"PORT\",\n  \"someSetting\": {\n    \"apiKey\": \"MY_CUSTOM_API_KEY\"\n  }\n}\n```\n\n### Debugging\n\nThe `debug` module has been removed as a direct dependency. This reduces the the client bundle size and allows to support other platforms (like Deno). The original `debug` functionality can now be initialized as follows:\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\nimport debug from 'debug'\n\nfeathers.setDebug(debug)\n```\n\nIt is also possible to set a custom logger like this:\n\n```ts\nimport { feathers } from '@feathersjs/feathers'\n\nconst customDebug =\n  (name) =>\n  (...args) => {\n    console.log(name, ...args)\n  }\n\nfeathers.setDebug(customDebug)\n```\n\nSetting the debugger will apply to all `@feathersjs` modules.\n\n### Client\n\n- The `request` library has been deprecated and request support has been removed from the REST client.\n- Since all modern browsers now support built-in [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), the Angular and jQuery REST clients have been removed as well.\n- The `@feathersjs/client` package now only comes with a full (`dist/feathers.js`) and core (`dist/core.js`) browser build. Using Feathers [with a module loader](../api/client.md#module-loaders) is recommended for all other use cases.\n\n### Removed Primus Transport\n\nDue to low usage `@feathersjs/primus` and `@feathers/primus-client` have been removed from Feathers core.\n\n### Changes to WebSockets\n\n#### Legacy Socket Format\n\nThe legacy `servicename::method` socket message format has been deprecated since Feathers 3 and has now been removed. Use a v3 or later [Feathers client](../api/client.md) or the [current Socket.io direct connection API](../api/client/socketio.md).\n\n#### Timeouts\n\nThe `timeout` setting for socket services has been removed. It was mainly intended as a fallback for the old message format and interfered with the underlying timeout and retry mechanism provided by the websocket libraries themselves.\n\n### NotFound for `app.service`\n\nBy default, when getting a non existing service via `app.service('something')` on the server, it will now throw a `NotFound` error instead of returning `undefined`. The previous behaviour can be restored by setting [app.defaultService](../api/application.md#defaultservice):\n\n```js\napp.defaultService = () => {\n  return null // undefined\n}\n```\n\n### Removed `service.mixin()`\n\nServices are no longer Uberproto (an ES5 inheritance utility) objects and instead rely on modern JavaScript classes and extension. This means `app.service(name).mixin(data)` is no longer available which can be replaced with a basic `Object.assign(app.service(name), data)`:\n\n```js\n// Before\napp.mixins.push((service, path) => {\n  service.mixin({\n    create(data, params) {\n      // do something here\n      return this._super(data, params)\n    }\n  })\n})\n\n// Now\napp.mixins.push((service, path) => {\n  const { create } = service\n\n  Object.assign(service, {\n    create(data, params) {\n      // do something here, then invoke the old method\n      // through normal JavaScript functionality\n      return create.call(this, data, params)\n    }\n  })\n})\n```\n\n### `finally` hook\n\nThe undocumented `finally` hook type is no longer available and should be replaced by the new `around` hooks which offer the same functionality using plain JavaScript:\n\n```js\napp.service('myservice').hooks([\n  async (context, next) => {\n    try {\n      await next()\n    } finally {\n      // Do finally hook stuff here\n    }\n  }\n])\n```\n\n### Other internal changes\n\n- The undocumented `service._setup` method introduced in v1 will no longer be called. It was used to circumvent middleware inconsistencies from Express 3 and is no longer necessary.\n- The undocumented `app.providers` has been removed since it provided the same functionality as [`app.mixins`](../api/application.md#mixins)\n- `app.disable`, `app.disabled`, `app.enable` and `app.enabled` have been removed from basic Feathers applications. It will still be available in an Express-compatible Feathers application. `app.get()` and `app.set()` should be used instead.\n- The `req.authentication` property is no longer set on the express requests, use `req.feathers.authentication` instead.\n"
  },
  {
    "path": "docs/guides/security.md",
    "content": "# Security\n\nWe 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. However, as a web application developer, you are responsible for the security of your application. We do our very best to make sure Feathers is as secure as possible.\n\n## Reporting security issues\n\nIn order to give the community time to respond and upgrade, we strongly urge you report all security issues to us. Send us a PM on [Discord](https://discord.gg/qa8kez8QBx) or email us at [hello@feathersjs.com](mailto:hello@feathersjs.com) with details, and we will respond ASAP. Security issues always take precedence over bug fixes and feature work; so, we'll work with you to come up with a resolution and plan and document the issue on Github in the appropriate repo.\n\nIssuing releases is typically very quick. Once an issue is resolved it is usually released immediately with the appropriate semantic version.\n\n## Security considerations\n\nHere are some things that you should be aware of when writing your app to make sure it is secure.\n\n- Make sure to set up proper [event channels](../api/channels.md) so that only clients that are allowed to see them can see real-time updates\n- Use hooks to check security roles to make sure users can only access data they should be permitted to. You can find useful hook utilities in [feathers-hooks-common](https://hooks-common.feathersjs.com/) and [feathers-authentication-hooks](https://github.com/feathersjs-ecosystem/feathers-authentication-hooks/).\n- Restrict the [allowed database queries](../api/databases/querying.md) to only the use cases your application requires by sanitizing `params.query` in a hook.\n- When you explicitly allow multiple element changes, make sure queries are secured properly to limit the items that can be changed.\n\n- Escape any HTML and JavaScript to avoid XSS attacks.\n- Escape any SQL (typically done by the SQL library) to avoid SQL injection.\n- JSON Web Tokens (JWT's) are only signed. They are **not** encrypted. Therefore, the payload can be examined on the client. This is by design. **DO NOT** put anything that should be private in the JWT `payload` unless you encrypt it first.\n- Don't use a weak `secret` for your token service. The generator creates a strong one for you automatically. No need to change it.\n\n## Technologies used\n\n- Password storage inside `@feathers/authentication-local` uses [bcrypt](https://github.com/dcodeIO/bcrypt.js). We don't store the salts separately since they are included in the bcrypt hashes.\n- By default, [JWT](https://jwt.io/)'s are stored in Local Storage (instead of cookies) to avoid CSRF attacks. For JWT, we use the `HS256` algorithm by default (HMAC using SHA-256 hash algorithm). If you choose to store JWT's in cookies, your app may have CSRF vulnerabilities.\n\n## XSS attacks\n\nAs with any web application **you** need to guard against XSS attacks. Since Feathers persists the JWT in localstorage in the browser, if your app falls victim to a XSS attack your JWT could be used by an attacker to make malicious requests on your behalf. This is far from ideal. Therefore you need to take extra care in preventing XSS attacks. Our stance on this particular attack vector is that if you are susceptible to XSS attacks, then a compromised JWT is the least of your worries because keystrokes could be logged and attackers can just steal passwords, credit card numbers, or anything else your users type directly.\n\nFor more information see [this issue](https://github.com/feathersjs/authentication/issues/132)\n"
  },
  {
    "path": "docs/guides/whats-new.md",
    "content": "---\noutline: deep\n---\n\n# What's New in v5\n\nFeathers Dove (v5) is a super-ambitious release which adds some really great tools and APIs. We don't have to mince words. This release is awesome with so many useful features.\n\nHere is an overview of each new feature, followed by links to learn more.\n\n## New TypeScript Benefits\n\nFeathers has been a TypeScript-friendly framework for years, but TypeScript support took a huge leap forward with Feathers Dove.\n\n### Complete TypeScript Rewrite\n\nWe've completely rewritten all of Feathers in TypeScript. And we're not talking about a lightweight TypeScript implementation. It's TypeScript all the way down. Everything from the official database adapters, built-in hooks, and utilities, right down to Feathers core. The newly-rebuilt [v5 CLI and generator](#rebuilt-cli) even produces a TypeScript application, by default.\n\nYou can find the shiny new TypeScript packages on GitHub, [here](https://github.com/feathersjs/feathers/tree/dove/packages).\n\n### Typed Client\n\nFeathers has had an isomorphic API - working equally well in browser and server - since 2016. Now with Dove, our [new CLI](#rebuilt-cli) generates **shared types for the Feathers server and client**. We even integrated the types with our new [schemas feature](#official-schemas), so you define your types once, in a single location, and use them everywhere. Everything still uses Feathers tried and proven [standard HTTP and websocket](../api/client.md) communication mechanism. There is no custom protocol or the slow parsing of a domain specific language (like GraphQL) necessary and since it is all plain TypeScript with type information removed at compile time, there is also no bundle size overhead.\n\nThanks to FeathersJS's clean, modular, loosely-coupled architecture, it was pleasantly simple to add this feature. This is another one of the benefits we get from building a pattern-driven framework.\n\nYou can learn more about the Feathers Client, [here](../guides/cli/client.md).\n\n## New Documentation\n\nThe new docs are built on [Vitepress](https://vitepress.vuejs.org/). It had become difficult to maintain all of the examples in two languages: JavaScript and TypeScript. To simplify, we now ONLY write documentation examples in TypeScript. You can still switch languages in the sidebar thanks to our custom highlighter for Vitepress, which transpiles TypeScript examples to JavaScript.\n\nYou can find the `docs` folder, [here](https://github.com/feathersjs/feathers/tree/dove/docs).\n\n## Framework Agnostic API\n\nIn 2016, we realized that we could decouple Feathers from the underlying HTTP transport, resulting in our first framework-agnostic, isomorphic build. As of Feathers v5, we now support three ways of using Feathers:\n\n- The Feathers client, which provides the same API in the browser, React Native and in Node.js.\n- The [KoaJS transport](../api/koa.md) (new in Feathers Dove)\n- The [ExpressJS transport](../api/express.md)\n\n### KoaJS Support\n\nThe CLI's official HTTP integration has always been built on the Express adapter. Lately, Express has been \"showing its age\", so we've made some inviting changes.\n\n- We've released the [`@feathersjs/koa`](../api/koa.md) adapter and utilities. Now Feathers apps can use [KoaJS](https://koajs.com/) as an API base.\n- The Feathers CLI now uses KoaJS as the default transport.\n- The Express adapter will continue to function alongside KoaJS.\n\nFeathersJS has its own, isomorphic middleware layer, based on [hooks](../api/hooks.md), so you likely won't need to tap into the middleware layer of any framework adapter. But, in those cases that you need framework middleware, it's available to you.\n\nRead about the KoaJS adapter, [here](../api/koa.md).\n\n### Lightning-Fast Routing\n\nFeathers just got a huge speed upgrade, now including its own [Radix Trie](https://iq.opengenus.org/radix-tree/) router. This means that the algorithm behind Fastify's speed is now built into Feathers, and it works no matter which framework transport you use under the hood.\n\nThe best part about the new router is that there's not another API you have to learn in order to use Feathers. It just works.\n\nFor those who want to build a custom framework transport, there's a single `.lookup` method which routes requests through Feathers.\n\nLearn about the `lookup` method, [here](/api/application#lookup).\n\n### Service De-Registration\n\nNow that Feathers comes with [its own router](#lightning-fast-routing), it's possible to de-register a service to completely remove it from the application. This allows you to build cleaner, dynamically generated applications. This is a coveted feature for those who want to build, for example, a dynamic CRUD admin application that's driven by some sort of schema.\n\nLearn about service de-registration [here](../api/application.md#unusepath).\n\n## Custom Methods\n\nWhile Feathers [standard service methods](../api/services.md) cover 90% of the functionality you need to create and modify data, a service might also provide other custom functionality making custom Method creation one of the most-requested features for Feathers. Feathers Dove introduces an elegant solution for custom methods on top of the Feathers service interface.\n\nWhen you define your service class, you can specify additional methods on the class to create an internal-only method. To expose the method to the public API, add the method's name to the `methods` options when registering the service. Custom methods are similar to the `create` method, so you can POST to them when using HTTP-based adapters.\n\nRead more about custom methods, [here](../api/services#custom-methods).\n\n## Official Schemas\n\nFeathers Dove (v5) introduces new, official tools for data validation in the new core package, [@feathersjs/schema](../api/schema/index.md). This same package includes schema-based resolvers, which you'll learn about in the next section. Schemas are powered by JSON Schema (an IETF standard) which makes them powerful and portable.\n\n### Schema-Driven Types\n\nOne of the problems we wanted to avoid was the need to define schemas and/or types in multiple places. If we had a motto/slogan for types, it would be\n\n**\"Define it once, use it everywhere.\"**\n\nSo in Feathers Dove, when you create a schema, it dynamically generates validation and proper TypeScript types. You can use the powerful and concise [TypeBox schema format](../api/schema/typebox.md) or [plain JSON schema](../api/schema/schema.md).\n\n### Configuration Schemas\n\nIf you've ever experienced pains of deploying to production, you'll appreciate this feature. When your app starts in production, all of your configuration and environment variables are checked against the configuration schema. The app won't start if the schema validation fails. This keeps bugs from missing environment variables from showing up in production days to weeks after deployment.\n\nConfiguration schemas also produce TypeScript types, so the [TypeScript improvements](#new-typescript-benefits) in Feathers Dove include typed configuration lookup for `app.get()` and `app.set()`. It's really convenient.\n\nRead more about configuration schemas, [here](/api/configuration#configuration-schema)\n\n## Resolvers\n\nCombined with the new [schemas](#official-schemas), resolvers allow to dynamically populate properties. It's a powerful tool that has many use cases from populating associations, securing queries or protecting secure data to easily setting values like the creation date or associated user. See the [chat guide](../guides/basics/generator.md) for an example on how to set the user avatar, populate the user associated with a message and let users only modify their own data.\n\n### Resolver Utility Hooks\n\nResolvers are powered by new hook utilities:\n\n- [resolveData](../api/schema/resolvers.md#data-resolvers) for incoming data.\n- [resolveResult](../api/schema/resolvers.md#result-resolvers) for results coming from databases or other services\n- [resolveDispatch](../api/schema/resolvers.md#safe-data-resolvers) for cleanly defining safe data for WebSocket / Real-time events.\n- [resolveQuery](../api/schema/resolvers.md#query-resolvers) for incoming query parameters\n\nRead about the new hooks using the links, above. These new hook utils allow you to\n\n- More cleanly manage properties on incoming records, query objects, and/or results\n- Perform advanced validation beyond what's possible with JSON Schema.\n- More efficiently write code for populating relational data (often faster than a normal ORM)\n- Save yourself a lot of boilerplate compared to writing the three features, above, manually with hooks.\n\nYou can start using resolvers right away. The new [CLI](../guides/basics/services#generating-a-service) generates them with all new services. Resolvers are one of the new tools provided in the new core package: [@feathersjs/schema](../api/schema/index.md).\n\nYou can read more about resolvers, [here](../api/schema/resolvers.md).\n\n### Hooks vs Resolvers\n\nAt first glance, choosing where to put logic might seem complex. Should the feature go into a hook or a resolver? Here are some general guidelines to assist you:\n\n- Data manipulation and **custom** validation probably fit best in a resolver.\n- Adding or pulling in data from other sources will likely fit best in a resolver.\n- Side effects that manipulate external data should go into a hook with few exceptions.\n\n## More Powerful Hooks\n\nIn Feathers Dove there are now two hook formats. One for `before`, `after`, and `error` hooks, and a new one for `around` hooks:\n\n- **Before, after, and error hooks** have been Feathers' most-used API for years.\n  - Are registered as `before`, `after`, or `error` hooks in the hook object.\n  - Continue to work fully in Feathers Dove.\n  - Are less powerful than the new \"around\" hooks, but visually simpler.\n- **Around Hooks** are new in Feathers Dove.\n  - Are registered in the `around` key of a hook object.\n  - Are capable of handling before, after, and error logic, all within a single hook function.\n  - Have a slightly different function definition than before, after, and error hooks\n  - Are more powerful yet also more visually complex (The \"after\" part of each hook runs in reverse-registered order).\n\nLet's compare the signature of the two types of hooks.\n\n### Before, After, & Error Hooks\n\nLet's look at an example of the before/after/error hook format. These hooks receive the `context` as their only argument. They return either the `context` object or `undefined`.\n\n```ts\nimport type { HookContext } from '../../declarations'\n\nexport const myHook = async (context: HookContext) => {\n  return context\n}\n```\n\nYou can learn more about before/after/error hooks, [here](../api/hooks.md#before-after-and-error)\n\n### Around Hooks\n\nNow let's see an around hook. An around hook receives two arguments: the `context` object and a `next` function.\n\n```ts\nimport type { HookContext, NextFunction } from '../../declarations'\n\nexport const myHook = async (context: HookContext, next: NextFunction) => {\n  await next()\n}\n```\n\nYou can learn more about around hooks, [here](../api/hooks.md#around)\n\n### Registering Hooks\n\nThe hooks object now has a new `around` property, which is specifically for `around` hooks. Since around hooks have different function signatures, they are not interchangeable with before/after/error hooks.\n\n```ts\nexport const serviceHooks = {\n  // `around` hook are new in Feathers Dove\n  around: {\n    all: [],\n    find: [],\n    get: [],\n    create: [],\n    update: [],\n    patch: [],\n    remove: []\n  },\n  // before/after/error hooks also continue to work\n  before: {},\n  after: {},\n  error: {}\n}\n```\n\nLearn more about registering hooks, [here](../api/hooks.md#registering-hooks).\n\n### When to use Around Hooks\n\nUsing `around` hooks or `regular` hooks is mostly a matter of preference. There's no imminent need to rewrite all of your regular hooks into around hooks. Both hooks work together, as explained [here](/api/hooks#hook-flow).\n\nStarting with Dove, the CLI templates and new tooling features are written in `around` hooks. The around hooks simplify code in core tools because we can keep the logic for the entire hook flow (before, after, error) all in one file.\n\nHere are a couple of examples of where `around` hooks work really well:\n\n<BlockQuote type=\"details\" label=\"Data Caching Example\">\n\nOne great use case for `around` hooks is data caching. A caching hook typically has the following responsibilities:\n\n- Check the cache for existing results. (before the service method executes)\n- Push new results into the cache, once received. (after the service method executes)\n- Handle and report errors which occur in the hook.\n\nWith regular hooks, a cache hook has to be split into three parts, one for each responsibility. Instead, a single `around` hook can handle everything on its own.\n\nBelow is an example of an overly-simple cache hook using JavaScript's `Map` API. Everything before `await next()` runs before the database call. Everything afterwards runs after the database call. You could also drop in a try/catch to handle possible errors.\n\n```ts\nimport type { HookContext, NextFunction } from '../../declarations'\n\nexport const simpleCache = new Map()\n\nexport const myHook = async (context: HookContext, next: NextFunction) => {\n  // Check the cache for an existing record\n  const existing = simpleCache.get(context.id)\n\n  // If an existing record was found, set it as context.result to skip the database call.\n  if (existing) {\n    context.result = existing\n  }\n\n  await next()\n\n  // Cache the latest record by its id\n  simpleCache.set(context.result.id, context.result)\n}\n```\n\n</BlockQuote>\n\n### Setup and Teardown Hooks\n\nFeathers v5 Dove adds built-in support for app-level `setup` and `teardown` hooks. They are special hooks that don't run on the service level but instead directly on [app.setup](../api/application.md#setupserver) or `app.listen` and [app.teardown](../api/application.md#teardownserver). They allow you to perform some async logic while starting and stopping the Feathers server.\n\n```ts\napp.hooks({\n  setup: [connectMongoDB],\n  teardown: [closeMongoDB]\n})\n```\n\nLearn more about `setup` and `teardown` hooks, [here](../api/hooks.md#setup-and-teardown)\n\n## Rebuilt CLI\n\nThe new CLI is completely different under the hood, and very familiar on the surface. There are a few differences in file structure compared to apps generated with previous versions of the CLI.\n\n### State of the Art\n\nWhen creating the new generator, we looked at open-source generators already available. We were very impressed with [Hygen](https://hygen.io). It's absolutely impressive work, for sure, so we even wrote a custom generator to try it out. Then [@fratzinger](https://github.com/fratzinger) came up with the idea of a 100% TypeScript generator based on JavaScript template strings. We couldn't find an existing project, so we made one!\n\nThe new Feathers CLI is built on top of [Pinion](https://github.com/feathershq/pinion), our own generator with TypeScript-based templates. Instead of using some custom templating language, like Handlebars or EJS, Pinion uses Typed [Template Literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals), providing some wonderful benefits:\n\n- No more mystery context. You always know the exact context of the templates and what helpers are available.\n- It just works™ with existing npm packages. There's no need to make an EJS plugin for some custom helper using an obscure API. Just import the module and use it in your template.\n- Integrates with all existing TypeScript tooling. Hover over a variable and inspect the context like you would any TS code.\n\nNow that we have what we consider the best generator on the planet, we have some exciting plans for the Feathers CLI, which we will announce in the future.\n\nYou can read more about Pinion, [here](https://github.com/feathershq/pinion)\n\n### Fully TypeScript\n\nWe have dramatically reduced the surface area for bugs to be introduced into the app. We've committed 100% to TypeScript, while making sure that you can still generate a JavaScript app.\n\nWhen you select `JavaScript` to generate an app, the CLI works some magic under the hood by\n\n- Compiling the `.ts` templates to JavaScript, in memory\n- Formatting the JavaScript code with Prettier\n- Writing clean `.js` to the file system.\n\nFor Feathers Maintainers, committing to TypeScript means we only contribute to a single set of templates. And they get magically compiled - on the fly - to plain JavaScript when you want it.\n\n### Shared Types\n\nWe covered this [in more detail, earlier](#typed-client), but it's worth briefly mentioning again. The new generator powers Shared Types for both the Feathers server and client. You can make your public-facing API easier to use and give developers a typed client SDK.\n\nRead more about shared types, [here](#typed-client).\n\n### New App Structure\n\nThe file and folder structure of generated apps has changed a little bit. Here's an overview of the changes:\n\n- Each service has its own schema and resolver file\n- The service hooks are now found together with the service registration.\n- The `src/models` folder no longer gets created, since [Feathers schemas](#official-schemas) replace models.\n- Each service has its own folder inside the `tests` folder.\n\nYou can learn more about the generated files in the [CLI guide](./cli/index.md).\n\n## The Future\n\nWe are self-funded and community powered. In every way, Feathers has a solid foundation for a steady, stable future. How did we ever manage to build such a great framework without millions of dollars? Really, we have a wonderful, active community of contributors who share values of good API design, boilerplate elimination, and making development fun. This is rewarding for us!\n\nWe started in 2013 from a core architecture that's unique among frameworks - in **any** language. We offer the same API across multiple transports, which allows us all to build real-time, restful applications. The result is a robust, flexible framework that continues to be unique while showing its maturity. Feathers has made its way into enterprises that serve a large portion of the connected planet. With all of the new features in Feathers v5 (Dove), we're excited to build! And we're even more excited to see what you build!\n\nWe have a few more things to show off in the coming months. Stay tuned!\n\nEnjoy the release! And come chat with us on [Discord](https://discord.gg/qa8kez8QBx) when you feel like it.\n"
  },
  {
    "path": "docs/help/faq.md",
    "content": "---\noutline: deep\n---\n\n# FAQ\n\nWe've been collecting some commonly asked questions here. We'll either be updating the guide directly, providing answers here, or both.\n\n## Why should I use Feathers?\n\nThere are many other Frameworks that let you build web applications so this is definitely a justified question. The key part for Feathers is that it takes a different approach to both, traditional MVC frameworks like Rails, Sails or NestJS and low level HTTP frameworks like Sinatra, Express or Fastify. Instead of creating routes, controllers and HTTP request and response handlers, Feathers uses services and workflows (hooks) that let you focus on your application logic independently from how it is being accessed.\n\nThis makes applications easier to understand and test and it allows Feathers to automatically provide REST APIs, websocket real-time APIs (which can often be quite a bit faster) and universal usage on the client and the server. It also makes it possible to add new communication protocols (like HTTP2 or GraphQL) without having to change anything in your application code. Feathers does all that while staying lightweight with a small API surface and codebase and flexible by letting you use it with the backend and frontend technology that best suits your needs.\n\nFor more information\n\n- [Read about the philosophy behind Feathers and where it came from](https://blog.feathersjs.com/why-we-built-the-best-web-framework-you-ve-probably-never-heard-of-until-now-176afc5c6aac)\n- [Learn about the high level design patterns behind Feathers](https://blog.feathersjs.com/design-patterns-for-modern-web-apis-1f046635215)\n- [See how Feathers compares to others](https://feathersjs.com/comparison)\n\n## Is Feathers production ready?\n\nYes! Feathers had its first stable release in 2014 and is being used in production by a bunch of companies from startups to fortune 500s. For some more details see [this answer on Quora](https://www.quora.com/Is-FeathersJS-production-ready).\n\n## What Node versions does Feathers support\n\nFeathers supports all NodeJS versions from the current Active LTS upwards. See [the Node.JS working group release schedule](https://github.com/nodejs/Release#release-schedule) for more information.\n\n## How do I create custom methods?\n\nFeathers is built around the [REST architectural constraints](https://en.wikipedia.org/wiki/Representational_state_transfer#Architectural_constraints) reflected by its standard service methods. There are many benefits using those methods like security, predictability and sending pre-defined real-time events so you should try to structure your application with the [standard service methods](../api/services.md#service-methods). For example:\n\n> Send email action that does not store mail message in database.\n\nResources (services) don't have to be database records. It can be any kind of resource (like the current weather for a city or creating an email which will send it). Sending emails is usually done with either a separate email [service](../api/services.md):\n\n```ts\nclass EmailService {\n  async create(data: EmailData) {\n    return sendEmail(data)\n  }\n}\n\napp.use('/email', new EmailService())\n```\n\n> Place an order in e-commerce web site. Behind the scenes, there are many records will be inserted in one transaction: order_item, order_header, voucher_tracking etc.\n\nThis is what [Feathers hooks](../api/hooks.md) are used for. When creating a new order you also have a well defined hook chain:\n\n```ts\napp.service('orders').hooks({\n  before: {\n    create: [validateData(), checkStock(), checkVoucher()]\n  },\n  after: {\n    create: [\n      chargePayment(), // hook that calls `app.service('payment').create()`\n      sendEmail(), // hook that calls `app.service('email').create()`\n      updateStock() // Update product stock here\n    ]\n  }\n})\n```\n\nHowever, there are some use cases where you might still want to allow additional methods for a client to call (like re-sending a verification email or resetting a password on the user service) and this is what [custom service method](../api/services.md#custom-methods) can be used for.\n\n## How do I do nested or custom routes?\n\nNormally we find that they actually aren't needed and that it is much better to keep your routes as flat as possible. For example something like `users/:userId/posts` is - although nice to read for humans - actually not as easy to parse and process as the equivalent `/posts?userId=<userid>` that is already [supported by Feathers database adapters](../api/databases/querying.md). Additionally, this will also work much better when using Feathers through websocket connections which do not have a concept of routes at all.\n\nHowever, nested routes for services can still be created by registering an existing service on the nested route and mapping the route parameter to a query parameter like this:\n\n```ts\napp.use('/posts', postService)\napp.use('/users', userService)\n\n// re-export the posts service on the /users/:userId/posts route\napp.use('/users/:userId/posts', app.service('posts'))\n\n// A hook that updates `data` with the route parameter\nasync function mapUserIdToData(context: HookContext) {\n  if (context.data && context.params.route.userId) {\n    context.data.userId = context.params.route.userId\n  }\n}\n\n// For the new route, map the `:userId` route parameter to the query in a hook\napp.service('users/:userId/posts').hooks({\n  before: {\n    find: [\n      async (context: HookContext) => {\n        // Map the `userId` route parameter to the query\n        context.params.query = {\n          ...context.params.query,\n          userId: context.params.route.userId\n        }\n      }\n    ],\n    create: mapUserIdToData,\n    update: mapUserIdToData,\n    patch: mapUserIdToData\n  }\n})\n```\n\nNow going to `/users/123/posts` will call `postService.find({ query: { userId: 123 } })` and return all posts for that user.\n\nFor more information about URL routing and parameters, refer to [the Express chapter](../api/express.md).\n\n<BlockQuote type=\"warning\" label=\"important\">\n\nURLs should never contain actions that change data (like `post/publish` or `post/delete`). This has always been an important part of the HTTP protocol and Feathers enforces this more strictly than most other frameworks. For example to publish a post you would call `.patch(id, { published: true })`.\n\n</BlockQuote>\n\n## Why are you using JWT for sessions\n\nFeathers is using [JSON web tokens (JWT)](https://jwt.io/) for its standard authentication mechanism. Some articles like [Stop using JWT for sessions](http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/) promotes using standard cookies and HTTP sessions. While it brings up some valid points, not all of them apply to Feathers and there are other good reasons why Feathers relies on JWT:\n\n- Feathers is designed to support many different transport mechanisms, most of which do not rely on HTTP but do work well with JWT as the authentication mechanism. This is even already the case for websockets where an established connection normally is not secured by a traditional HTTP session.\n- By default the only thing that Feathers stored in the JWT payload is the user id. It is a stateful token. You can change this and make the token stateless by putting more data into the JWT payload but this is at your discretion. Currently the user is looked up on every request after the JWT is verified to not be expired or tampered with.\n- You need to make sure that you revoke JWT tokens or set a low expiration date or add custom logic to verify that a user’s account is still valid/active. Currently the default expiration is 1 day. We chose a reasonable default for most apps but depending on your application this might be too long or too short.\n\nAdditionally, it is still possible to use Feathers with existing _traditional_ Express session mechanism by using [custom Express middleware](../api/express.md). For example, `params.user` for all service calls from a traditional Express session can be passed like this:\n\n```ts\napp.use(function (req, res, next) {\n  // Set service call `param.user` from `session.user`\n  req.feathers.user = req.session.user\n})\n```\n\n## Can you support another database?\n\nFeathers [database adapters](../api/databases/adapters.md) implement 90% of the functionality you may need to use Feathers with certain databases. You can also find a wide variety of community maintained database adapters [in the ecosystem](/ecosystem/?cat=Database&sort=lastPublish). However, even if your favourite database or ORM is not on the list or the adapter does not support specific functionality you are looking for, Feathers can still accommodate all your needs by [writing your own services](../api/services.md).\n\n<BlockQuote type=\"warning\" label=\"Important\">\n\nTo use Feathers properly it is very important to understand how services work and that all existing database adapters are just services that talk to the database themselves.\n\n</BlockQuote>\n\nThe why and how to write your own services is covered [in the Feathers guide](../guides/). A custom service can be generated by running `npx feathers generate service`, choosing \"A custom service\" and then editing the `<servicename>/<servicename>.class.js` file to make the database calls.\n\nIf you would like to publish your own database adapter, first make sure there isn't already a [community maintained adapter](/ecosystem/?cat=Database&sort=lastPublish) for that database. If one exists, many maintainers are happy to get some help. If not, you can find a database adapter reference implementation in the [@feathersjs/memory module](https://github.com/feathersjs/feathers/tree/dove/packages/memory). It is always possible for community maintained adapters to graduate into an _official_ Feathers adapter, at the moment there are however no plans to add support for any new databases from the Feathers team directly.\n\n## How do I watch for database changes?\n\nIn order to get real-time updates for a change, all requests have to go through your Feathers application or API server. Feathers **does not** watch the database for changes so if changes in the database are made outside of the Feathers application and clients should be notified, the notification needs to be sent manually.\n\n## How do I do search?\n\nThis depends on the database adapter you are using. See [the search querying chapter](../api/databases/querying.md#search) for more information.\n\n## Why am I not getting JSON errors?\n\nIf you get a plain text error and a 500 status code for errors that should return different status codes, make sure you have the `express.errorHandler()` from the `@feathersjs/express` module configured as described in the [Express errors](../api/express.md#expresserrorhandler) chapter.\n\n## Why am I not getting the correct HTTP error code\n\nSee the above answer.\n\n## How can I do custom methods like `findOrCreate`?\n\nCustom functionality can almost always be mapped to an existing service method using hooks. For example, `findOrCreate` can be implemented as a before-hook on the service's `get` method. [See this gist](https://gist.github.com/marshallswain/9fa3b1e855633af00998) for an example of how to implement this in a before-hook. It is also possible to implement [custom methods](../api/services.md#custom-methods) on the service for functionality that can't be implemented in a hook.\n\n## How do I create channels or rooms\n\nIn Feathers [channels](../api/channels.md) are the way to send [real-time events](../api/events.md) to only certain clients.\n\n## How do I do validation?\n\n[Schemas](../api/schema/index.md) and [validator](../api/schema/validators.md) are the recommended way to implement basic validations based on JSON schema. [Resolvers](../api/schema/resolvers.md) can be used for advanced validation like dynamic password policies.\n\nSchemas and resolvers are then used as [validation hooks](../api/schema/validators.md#hooks) and [resolver hooks](../api/schema/resolvers.md#hooks). Hooks are also the place to perform validation without schemas and resolvers.\n\n## How do I do associations?\n\nThe preferred way for associations are [resolvers](../api/schema/resolvers.md). See [the guide](../guides/basics/schemas.md) for an example on how to do associations.\n\n## How do I access the request object in hooks or services?\n\nIn short, you shouldn't need to. If you look at the [hooks chapter](../api/hooks.md) you'll see all the params that are available on a hook.\n\nIf you still need something from the request object (for example, the requesting IP address) you can tack it on to the `req.feathers` object as described [here for Express](../api/express.md#params), here [for Koa](../api/koa.md#params) or `socket.feathers` when using web sockets as [described here](../api/socketio.md#appconfiguresocketiocallback).\n\n## How do I mount sub apps?\n\nIt's pretty much exactly the same as Express. More information can be found [here](../api/express.md#sub-apps).\n\n## How do I do some processing after sending the response to the user?\n\nThe hooks workflow allows you to handle these situations quite gracefully. It depends if you `await` or not in your hook. Here's an example of a hook that sends an email, but doesn't wait for a success message.\n\n```ts\n;async (context: HookContext) => {\n  // Send an email by calling to the email service.\n  context.app.service('emails').create({\n    to: 'user@email.com',\n    body: 'You are so great!'\n  })\n\n  // Send a message to some logging service.\n  context.app.service('logging').create(context.data)\n\n  return context\n}\n```\n\n## How do I debug my app\n\nIt's really no different than debugging any other NodeJS app but you can refer to [this blog post](https://blog.feathersjs.com/debugging-feathers-with-visual-studio-code-406e6adf2882) for more Feathers specific tips and tricks.\n\n## Why can't I pass `params` from the client?\n\nWhen you make a call like:\n\n```ts\nconst params = { foo: 'bar' }\n\nconst user = await client.service('users').patch(1, { admin: true }, params)\n```\n\non the client the `context.params` object will only be available in your client side hooks. It will not be provided to the server. The reason for this is because `context.params` on the server usually contains information that should be server-side only. This can be database options, whether a request is authenticated, etc. If we passed those directly from the client to the server this would be a big security risk. **Only the client side** `context.params.query` and `context.params.headers` objects are provided to the server.\n\nIf you need to pass info from the client to the server that is not part of the query you need to add it to `context.params.query` on the client side and explicitly pull it out of `context.params.query` on the server side. This can be achieved like so:\n\n```ts\n// client side\nclient.hooks({\n  before: {\n    all: [\n      async (context: HookContext) => {\n        context.params.query = {\n          ...context.params.query,\n          $client: {\n            platform: 'ios',\n            version: '1.0'\n          }\n        }\n      }\n    ]\n  }\n})\n```\n\nOn the server in `src/app`:\n\n```ts\napp.hooks({\n  before: {\n    all: [\n      async (context: HookContext) => {\n        // Pull out `$client` parameter and create a new `query` object\n        const {\n          $client: { platform, version },\n          ...query\n        } = params.query\n\n        // Update context.params with the new information\n        context.params = {\n          ...context.params,\n          platform,\n          version,\n          query\n        }\n      }\n    ]\n  }\n})\n```\n\n<BlockQuote type=\"danger\">\n\nMake sure to validate and sanitize any client side values to prevent security issues.\n\n</BlockQuote>\n\n## My queries with null values aren't working\n\n<BlockQuote type=\"tip\">\n\nQuery values will be converted to the correct type automatically when using a [query schema](../api/schema/index.md). This issue also does not happen when using websockets since it retains all type information.\n\n</BlockQuote>\n\nWhen making a request using REST (HTTP) query _string_ values don't have any type information and will always be strings. Some database adapters that have a schema (like `feathers-mongoose` or `feathers-sequelize`) will try to convert values to the correct type but others (like `feathers-mongodb`) can't. Additionally, `null` will always be a string and always has to be converted if you want to query for `null`. This can be done in a `before` [hook](../api/hooks.md):\n\n```ts\napp.service('myservice').hooks({\n  before: {\n    find: [\n      async (context: HookContext) => {\n        const {\n          params: { query = {} }\n        } = context\n\n        if (query.phone === 'null') {\n          query.phone = null\n        }\n\n        context.params.query = query\n\n        return context\n      }\n    ]\n  }\n})\n```\n\nAlso see [this issue](https://github.com/feathersjs/feathers/issues/894).\n\n## Why are queries with arrays failing?\n\nIf you are using REST and queries with larger arrays (more than 21 items to be exact) are failing, you are probably running into an issue with the [querystring](https://github.com/ljharb/qs) module which [limits the size of arrays to 21 items](https://github.com/ljharb/qs#parsing-arrays) by default. The recommended solution is to implement a custom query string parser function via `app.set('query parser', parserFunction)` with the `arrayLimit` option set to a higher value:\n\n```js\nvar qs = require('qs')\n\napp.set('query parser', function (str) {\n  return qs.parse(str, {\n    arrayLimit: 100\n  })\n})\n```\n\nFor more information see the [Express application settings](http://expressjs.com/en/4x/api.html#app.set) [@feathersjs/rest#88](https://github.com/feathersjs/feathers-rest/issues/88) and [feathers-mongoose#205](https://github.com/feathersjs-ecosystem/feathers-mongoose/issues/205).\n\n## I always get a 404 for my custom middleware\n\nJust like in Express itself, the order of middleware matters. If you registered a custom middleware outside of the generator, you have to make sure that it runs before the `notFound()` error midlleware.\n\n## My configuration isn't loaded\n\nIf you are running or requiring the Feathers app from a different folder [Feathers configuration](../api/configuration.md) needs to be instructed where the configuration files for the app are located. Since it uses [node-config](https://github.com/lorenwest/node-config) this can be done by setting the [NODE_CONFIG_DIR envorinment variable](https://github.com/lorenwest/node-config/wiki/Environment-Variables#node_config_dir).\n\n## How do I set up HTTPS?\n\nIn most production environments your Feathers application should be behind an NginX proxy that handles HTTPS. It is also possible to add SSL directly to your Feathers application which is described in the [Express HTTPS docs](../api/express.md#https).\n"
  },
  {
    "path": "docs/help/index.md",
    "content": "---\noutline: deep\n---\n\n# Getting Help\n\nThere are many ways that you can get help if you are stuck or have a question about Feathers.\n\n## Resources\n\nExisting resources may already have an answer to your question, so it always makes sense checking them first:\n\n- [API Docs >](../api/)\n- [FAQ >](./faq.md)\n- [GitHub issues >](https://github.com/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+user%3Afeathersjs+)\n- [GitHub discussions](https://github.com/feathersjs/feathers/discussions)\n- [Cookbook](/cookbook/)\n- [Blog >](https://blog.feathersjs.com/)\n- [Stack Overflow >](http://stackoverflow.com/questions/tagged/feathersjs)\n\n## Help channels\n\nIf none of those work it's a very real possibility that we screwed something up or it's just not clear. We're sorry :disappointed_relieved: We want to hear about it and are very friendly so feel free to come talk to us:\n\n[Join our Discord server >](https://discord.gg/qa8kez8QBx)\n\n[Submit an issue to GitHub >](https://github.com/feathersjs/feathers/issues/new)\n\n[Ask on StackOverflow using the `feathersjs` tag >](http://stackoverflow.com)\n\n## Consulting and app development\n\n[Feathers Cloud](https://feathers.cloud/) specialize in app development and consulting to get your app on the right track. [Contact us](https://feathers.cloud/consulting.html) to see how we can help.\n\n## Support Feathers, get help\n\nBy [becoming a sponsor](https://github.com/sponsors/daffl/) you support Feathers continued development and get access to a Feathers newsletter and tiers with 30 or 60 minute monthly office hour sessions to walk you through any issues you may be facing using FeathersJS. This may include architecture discussions, debug sessions, patterns, or more.\n"
  },
  {
    "path": "docs/index.md",
    "content": "---\nlayout: page\nsidebar: false\n\ntitle: Feathers\ntitleTemplate: The API and Real-time Application Framework\n---\n\n<script setup>\nimport HomeHero from './components/HomeHero.vue'\nimport HomeFeature1 from './components/HomeFeature1.vue'\nimport HomeFeature2 from './components/HomeFeature2.vue'\nimport HomeQuickStart from './components/HomeQuickStart.vue'\nimport HomeCreateFirstApp from './components/HomeCreateFirstApp.vue'\nimport HomeFeatureGrid from './components/HomeFeatureGrid.vue'\nimport HomeCTATextSection from './components/HomeCTATextSection.vue'\nimport Footer from './components/Footer.vue'\n</script>\n\n<HomeHero />\n<HomeFeature1 />\n<HomeFeature2 />\n<!-- <HomeQuickStart /> -->\n<HomeCreateFirstApp />\n<HomeFeatureGrid />\n<HomeCTATextSection text=\"Create your first Feathers app, today!\" />\n"
  },
  {
    "path": "docs/package.json",
    "content": "{\n  \"name\": \"docs\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"dev\": \"vitepress --port 3333 --open\",\n    \"build\": \"vitepress build\",\n    \"serve\": \"vitepress serve\",\n    \"preview-https\": \"pnpm run build && serve .vitepress/dist\",\n    \"prefetch\": \"esno .vitepress/scripts/fetch-avatars.ts\",\n    \"start\": \"npm run dev\"\n  },\n  \"dependencies\": {\n    \"@vueuse/core\": \"^14.2.1\",\n    \"date-fns\": \"^4.1.0\",\n    \"element-plus\": \"^2.13.2\",\n    \"query-string\": \"^9.3.1\",\n    \"shiki\": \"^3.22.0\",\n    \"vue\": \"^3.5.28\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/generators\": \"^5.0.40\",\n    \"@iconify-json/carbon\": \"^1.2.18\",\n    \"@types/node\": \"^25.3.0\",\n    \"@unocss/preset-typography\": \"^66.6.0\",\n    \"@unocss/reset\": \"^66.6.0\",\n    \"@unocss/transformer-directives\": \"^66.6.0\",\n    \"@vitejs/plugin-vue\": \"^6.0.4\",\n    \"esno\": \"^4.8.0\",\n    \"fast-glob\": \"^3.3.3\",\n    \"flexsearch\": \"^0.7.31\",\n    \"https-localhost\": \"^4.7.1\",\n    \"markdown-it\": \"^14.1.1\",\n    \"sass\": \"^1.97.3\",\n    \"sitemap\": \"^9.0.0\",\n    \"unocss\": \"^66.6.0\",\n    \"unplugin-auto-import\": \"^21.0.0\",\n    \"unplugin-vue-components\": \"^31.0.0\",\n    \"vite-plugin-pwa\": \"^1.2.0\",\n    \"vitepress\": \"^1.6.4\",\n    \"vitepress-plugin-google-analytics\": \"^1.0.2\",\n    \"vitepress-plugin-search\": \"^1.0.4-alpha.22\",\n    \"workbox-window\": \"^7.4.0\"\n  }\n}\n"
  },
  {
    "path": "docs/public/_headers",
    "content": "/\n  X-Frame-Options: DENY\n  X-XSS-Protection: 1; mode=block\n\n/api/\n  X-Frame-Options: DENY\n  X-XSS-Protection: 1; mode=block\n\n/config/\n  X-Frame-Options: DENY\n  X-XSS-Protection: 1; mode=block\n\n/guide/\n  X-Frame-Options: DENY\n  X-XSS-Protection: 1; mode=block\n\n/*.html\n  X-Frame-Options: DENY\n  X-XSS-Protection: 1; mode=block\n\n/*\n  X-Content-Type-Options: nosniff\n  Referrer-Policy: no-referrer\n  Strict-Transport-Security: max-age=31536000; includeSubDomains\n\n/assets/*\n  cache-control: max-age=31536000\n  cache-control: immutable\n"
  },
  {
    "path": "docs/public/_redirects",
    "content": "# Crow Redirects\n\n/migrating.html                             /guides/migrating.html\n/security.html                              /guides/security.html\n/help/readme.html                           /help/\n/faq/readme.html                            /help/faq.html\n\n/api/authentication/oauth1.html             /api/authentication/oauth.html\n/api/authentication/oauth2.html             /api/authentication/oauth.html\n/api/authentication/server.html             /api/authentication/\n\n/guides/frameworks/readme.html              /guides/frameworks.html\n/guides/basics/readme.html                  /guides/\n/guides/basics/clients.html                 /guides/basics/starting.html\n/guides/basics/databases.html               /guides/basics/services.html\n/guides/basics/real-time.html               /guides/basics/services.html\n\n/guides/chat/readme.html                    /guides/\n/guides/chat/authentication.html            /guides/basics/authentication.html\n/guides/chat/creating.html                  /guides/basics/generator.html\n/guides/chat/frontend.html                  /guides/basics/frontend.html\n/guides/chat/processing.html                /guides/basics/hooks.html\n/guides/chat/service.html                   /guides/basics/services.html\n/guides/chat/testing.html                   /guides/basics/testing.html\n\n/*/readme.html                              /:splat 301!\n"
  },
  {
    "path": "docs/public/feathers-chat.css",
    "content": ":root {\n  font-synthesis: none;\n  text-rendering: optimizeLegibility;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  -webkit-text-size-adjust: 100%;\n}\n\nbody,\n#app {\n  height: 100vh;\n  width: 100vw;\n  margin: 0;\n  padding: 0;\n}\n\n/* layer: preflights */\n*,\n::before,\n::after {\n  --un-rotate: 0;\n  --un-rotate-x: 0;\n  --un-rotate-y: 0;\n  --un-rotate-z: 0;\n  --un-scale-x: 1;\n  --un-scale-y: 1;\n  --un-scale-z: 1;\n  --un-skew-x: 0;\n  --un-skew-y: 0;\n  --un-translate-x: 0;\n  --un-translate-y: 0;\n  --un-translate-z: 0;\n  --un-pan-x: ;\n  --un-pan-y: ;\n  --un-pinch-zoom: ;\n  --un-scroll-snap-strictness: proximity;\n  --un-ordinal: ;\n  --un-slashed-zero: ;\n  --un-numeric-figure: ;\n  --un-numeric-spacing: ;\n  --un-numeric-fraction: ;\n  --un-border-spacing-x: 0;\n  --un-border-spacing-y: 0;\n  --un-ring-offset-shadow: 0 0 rgba(0, 0, 0, 0);\n  --un-ring-shadow: 0 0 rgba(0, 0, 0, 0);\n  --un-shadow-inset: ;\n  --un-shadow: 0 0 rgba(0, 0, 0, 0);\n  --un-ring-inset: ;\n  --un-ring-offset-width: 0px;\n  --un-ring-offset-color: #fff;\n  --un-ring-width: 0px;\n  --un-ring-color: rgba(147, 197, 253, 0.5);\n  --un-blur: ;\n  --un-brightness: ;\n  --un-contrast: ;\n  --un-drop-shadow: ;\n  --un-grayscale: ;\n  --un-hue-rotate: ;\n  --un-invert: ;\n  --un-saturate: ;\n  --un-sepia: ;\n  --un-backdrop-blur: ;\n  --un-backdrop-brightness: ;\n  --un-backdrop-contrast: ;\n  --un-backdrop-grayscale: ;\n  --un-backdrop-hue-rotate: ;\n  --un-backdrop-invert: ;\n  --un-backdrop-opacity: ;\n  --un-backdrop-saturate: ;\n  --un-backdrop-sepia: ;\n}\n\n::backdrop {\n  --un-rotate: 0;\n  --un-rotate-x: 0;\n  --un-rotate-y: 0;\n  --un-rotate-z: 0;\n  --un-scale-x: 1;\n  --un-scale-y: 1;\n  --un-scale-z: 1;\n  --un-skew-x: 0;\n  --un-skew-y: 0;\n  --un-translate-x: 0;\n  --un-translate-y: 0;\n  --un-translate-z: 0;\n  --un-pan-x: ;\n  --un-pan-y: ;\n  --un-pinch-zoom: ;\n  --un-scroll-snap-strictness: proximity;\n  --un-ordinal: ;\n  --un-slashed-zero: ;\n  --un-numeric-figure: ;\n  --un-numeric-spacing: ;\n  --un-numeric-fraction: ;\n  --un-border-spacing-x: 0;\n  --un-border-spacing-y: 0;\n  --un-ring-offset-shadow: 0 0 rgba(0, 0, 0, 0);\n  --un-ring-shadow: 0 0 rgba(0, 0, 0, 0);\n  --un-shadow-inset: ;\n  --un-shadow: 0 0 rgba(0, 0, 0, 0);\n  --un-ring-inset: ;\n  --un-ring-offset-width: 0px;\n  --un-ring-offset-color: #fff;\n  --un-ring-width: 0px;\n  --un-ring-color: rgba(147, 197, 253, 0.5);\n  --un-blur: ;\n  --un-brightness: ;\n  --un-contrast: ;\n  --un-drop-shadow: ;\n  --un-grayscale: ;\n  --un-hue-rotate: ;\n  --un-invert: ;\n  --un-saturate: ;\n  --un-sepia: ;\n  --un-backdrop-blur: ;\n  --un-backdrop-brightness: ;\n  --un-backdrop-contrast: ;\n  --un-backdrop-grayscale: ;\n  --un-backdrop-hue-rotate: ;\n  --un-backdrop-invert: ;\n  --un-backdrop-opacity: ;\n  --un-backdrop-saturate: ;\n  --un-backdrop-sepia: ;\n}\n\n/* layer: icons */\n.i-feather-alert-triangle {\n  --un-icon: url(\"data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='xMidYMid meet' viewBox='0 0 24 24' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0zM12 9v4m0 4h.01'/%3E%3C/svg%3E\");\n  mask: var(--un-icon) no-repeat;\n  mask-size: 100% 100%;\n  -webkit-mask: var(--un-icon) no-repeat;\n  -webkit-mask-size: 100% 100%;\n  background-color: currentColor;\n  width: 1em;\n  height: 1em;\n}\n\n.i-feather-hash {\n  --un-icon: url(\"data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='xMidYMid meet' viewBox='0 0 24 24' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 9h16M4 15h16M10 3L8 21m8-18l-2 18'/%3E%3C/svg%3E\");\n  mask: var(--un-icon) no-repeat;\n  mask-size: 100% 100%;\n  -webkit-mask: var(--un-icon) no-repeat;\n  -webkit-mask-size: 100% 100%;\n  background-color: currentColor;\n  width: 1em;\n  height: 1em;\n}\n\n.i-feather-log-out {\n  --un-icon: url(\"data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='xMidYMid meet' viewBox='0 0 24 24' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4m7 14l5-5l-5-5m5 5H9'/%3E%3C/svg%3E\");\n  mask: var(--un-icon) no-repeat;\n  mask-size: 100% 100%;\n  -webkit-mask: var(--un-icon) no-repeat;\n  -webkit-mask-size: 100% 100%;\n  background-color: currentColor;\n  width: 1em;\n  height: 1em;\n}\n\n.i-feather-menu {\n  --un-icon: url(\"data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='xMidYMid meet' viewBox='0 0 24 24' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M3 12h18M3 6h18M3 18h18'/%3E%3C/svg%3E\");\n  mask: var(--un-icon) no-repeat;\n  mask-size: 100% 100%;\n  -webkit-mask: var(--un-icon) no-repeat;\n  -webkit-mask-size: 100% 100%;\n  background-color: currentColor;\n  width: 1em;\n  height: 1em;\n}\n\n.i-feather-x {\n  --un-icon: url(\"data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='xMidYMid meet' viewBox='0 0 24 24' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M18 6L6 18M6 6l12 12'/%3E%3C/svg%3E\");\n  mask: var(--un-icon) no-repeat;\n  mask-size: 100% 100%;\n  -webkit-mask: var(--un-icon) no-repeat;\n  -webkit-mask-size: 100% 100%;\n  background-color: currentColor;\n  width: 1em;\n  height: 1em;\n}\n\n.i-logos-feathersjs {\n  background: url(\"data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='xMidYMid meet' viewBox='0 0 256 256' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='%23333' d='M128 9.102c65.665 0 118.898 53.233 118.898 118.898c0 65.665-53.233 118.898-118.898 118.898C62.335 246.898 9.102 193.665 9.102 128C9.102 62.335 62.335 9.102 128 9.102M128 0C57.421 0 0 57.421 0 128c0 70.579 57.421 128 128 128c70.579 0 128-57.421 128-128C256 57.421 198.579 0 128 0m20.83 25.524c-10.43-1.896-35.651 36.409-43.994 59.734c-.634 1.769-2.086 8.249-2.086 9.955c0 0 6.531 14.055 8.343 17.351c-3.034-1.58-9.323-13.756-9.323-13.756c-3.034 5.784-5.942 32.34-4.994 37.271c0 0 6.762 10.062 9.387 12.578c-3.603-1.201-9.671-9.355-9.671-9.355c-1.138 3.508-.916 10.807-.379 13.274c4.551 6.637 10.619 7.396 10.619 7.396s-6.637 66.181 3.413 71.111c6.258-1.327 7.775-73.956 7.775-73.956s7.585.569 9.292-1.327c3.856-2.655 12.826-30.224 12.958-34.202c0 0-10.41 1.952-15.487 3.924c3.826-3.8 16.049-6.352 16.049-6.352c3.315-3.979 10.291-31.047 10.994-39.391c.176-2.093.583-4.657.268-8.398c0 0-9.941 2.177-12.014 1.424c2.104-.237 12.263-4.14 12.263-4.14c1.801-16.213 2.358-42.091-3.413-43.141Zm-36.38 171.691c-.795 19.496-1.294 25.004-2.115 29.601c-.379.857-.758.997-1.138-.095c-3.477-15.992-3.224-136.438 36.409-191.241c-23.05 42.092-33.535 122.861-33.156 161.735Z'/%3E%3C/svg%3E\") no-repeat;\n  background-size: 100% 100%;\n  background-color: transparent;\n  width: 1em;\n  height: 1em;\n}\n\n/* layer: default */\n.relative {\n  position: relative;\n}\n\n.mx-auto {\n  margin-left: auto;\n  margin-right: auto;\n}\n\n.my-5 {\n  margin-top: 1.25rem;\n  margin-bottom: 1.25rem;\n}\n\n.ml-2 {\n  margin-left: 0.5rem;\n}\n\n.mt-0 {\n  margin-top: 0rem;\n}\n\n.mt-6 {\n  margin-top: 1.5rem;\n}\n\n.block {\n  display: block;\n}\n\n.h-10 {\n  height: 2.5rem;\n}\n\n.h-2\\.2 {\n  height: 0.55rem;\n}\n\n.h-32 {\n  height: 8rem;\n}\n\n.h-full {\n  height: 100%;\n}\n\n.max-w-sm {\n  max-width: 24rem;\n}\n\n.min-h-screen {\n  min-height: 100vh;\n}\n\n.w-10 {\n  width: 2.5rem;\n}\n\n.w-2\\.2 {\n  width: 0.55rem;\n}\n\n.w-32 {\n  width: 8rem;\n}\n\n.w-4 {\n  width: 1rem;\n}\n\n.w-6 {\n  width: 1.5rem;\n}\n\n.w-60 {\n  width: 15rem;\n}\n\n.w-full {\n  width: 100%;\n}\n\n.flex {\n  display: flex;\n}\n\n.flex-grow {\n  flex-grow: 1;\n}\n\n.flex-row {\n  flex-direction: row;\n}\n\n.flex-col {\n  flex-direction: column;\n}\n\n.cursor-pointer {\n  cursor: pointer;\n}\n\n.items-center {\n  align-items: center;\n}\n\n.justify-start {\n  justify-content: flex-start;\n}\n\n.justify-center {\n  justify-content: center;\n}\n\n.overflow-hidden {\n  overflow: hidden;\n}\n\n.overflow-y-auto {\n  overflow-y: auto;\n}\n\n.border-2 {\n  border-width: 2px;\n  border-style: solid;\n}\n\n.border-neutral {\n  border-color: hsla(var(--n));\n}\n\n.rounded {\n  border-radius: 0.25rem;\n}\n\n.bg-neutral {\n  background-color: hsla(var(--n));\n}\n\n.from-orange-500 {\n  --un-gradient-from: rgba(249, 115, 22, var(--un-from-opacity, 1));\n  --un-gradient-to: rgba(249, 115, 22, 0);\n  --un-gradient-stops: var(--un-gradient-from), var(--un-gradient-to);\n}\n\n.to-red-900 {\n  --un-gradient-to: rgba(127, 29, 29, var(--un-to-opacity, 1));\n}\n\n.bg-gradient-to-br {\n  --un-gradient-shape: to bottom right;\n  --un-gradient: var(--un-gradient-shape), var(--un-gradient-stops);\n  background-image: linear-gradient(var(--un-gradient));\n}\n\n.bg-clip-text {\n  -webkit-background-clip: text;\n  background-clip: text;\n}\n\n.p-0 {\n  padding: 0rem;\n}\n\n.p-2 {\n  padding: 0.5rem;\n}\n\n.px-3 {\n  padding-left: 0.75rem;\n  padding-right: 0.75rem;\n}\n\n.px-4 {\n  padding-left: 1rem;\n  padding-right: 1rem;\n}\n\n.py-2 {\n  padding-top: 0.5rem;\n  padding-bottom: 0.5rem;\n}\n\n.py-8 {\n  padding-top: 2rem;\n  padding-bottom: 2rem;\n}\n\n.pb-3 {\n  padding-bottom: 0.75rem;\n}\n\n.pt-2 {\n  padding-top: 0.5rem;\n}\n\n.text-center {\n  text-align: center;\n}\n\n.text-5xl {\n  font-size: 3rem;\n  line-height: 1;\n}\n\n.text-lg {\n  font-size: 1.125rem;\n  line-height: 1.75rem;\n}\n\n.text-sm {\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n}\n\n.text-xl {\n  font-size: 1.25rem;\n  line-height: 1.75rem;\n}\n\n.text-xs {\n  font-size: 0.75rem;\n  line-height: 1rem;\n}\n\n.font-bold {\n  font-weight: 700;\n}\n\n.font-light {\n  font-weight: 300;\n}\n\n.leading-4 {\n  line-height: 1rem;\n}\n\n.tracking-tight {\n  letter-spacing: -0.025em;\n}\n\n.text-error {\n  color: hsla(var(--er));\n}\n\n.text-transparent {\n  color: transparent;\n}\n\n.shadow-xl {\n  --un-shadow: var(--un-shadow-inset) 0 20px 25px -5px var(--un-shadow-color, rgba(0, 0, 0, 0.1)), var(--un-shadow-inset) 0 8px 10px -6px var(--un-shadow-color, rgba(0, 0, 0, 0.1));\n  box-shadow: var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);\n}\n\n.invert {\n  --un-invert: invert(1);\n  filter: var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia);\n}\n\n.transition-colors {\n  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n  transition-duration: 150ms;\n}\n\n.duration-300 {\n  transition-duration: 300ms;\n}\n\n@media (min-width: 640px) {\n  .sm\\:mt-1\\.5 {\n    margin-top: 0.375rem;\n  }\n\n  .sm\\:h-12 {\n    height: 3rem;\n  }\n\n  .sm\\:w-12 {\n    width: 3rem;\n  }\n}\n\n@media (min-width: 768px) {\n  .md\\:leading-5 {\n    line-height: 1.25rem;\n  }\n}\n\n@media (min-width: 1024px) {\n  .lg\\:hidden {\n    display: none;\n  }\n}\n"
  },
  {
    "path": "docs/public/robots.txt",
    "content": "User-agent: *\nAllow: /\n"
  },
  {
    "path": "docs/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"esnext\",\n    \"module\": \"esnext\",\n    \"lib\": [\"esnext\", \"dom\"],\n    \"moduleResolution\": \"node\",\n    \"esModuleInterop\": true,\n    \"strict\": true,\n    \"strictNullChecks\": true,\n    \"resolveJsonModule\": true,\n    \"skipDefaultLibCheck\": true,\n    \"skipLibCheck\": true,\n    \"outDir\": \"./dist\",\n    \"declaration\": true,\n    \"inlineSourceMap\": true,\n    \"paths\": {\n      \"@vitest/ws-client\": [\"./packages/ws-client/src/index.ts\"],\n      \"@vitest/ui\": [\"./packages/ui/node/index.ts\"],\n      \"#types\": [\"./packages/vitest/src/index.ts\"],\n      \"~/*\": [\"./packages/ui/client/*\"],\n      \"vitest\": [\"./packages/vitest/src/index.ts\"],\n      \"vitest/globals\": [\"./packages/vitest/globals.d.ts\"],\n      \"vitest/node\": [\"./packages/vitest/src/node/index.ts\"],\n      \"vitest/config\": [\"./packages/vitest/src/config.ts\"],\n      \"vite-node\": [\"./packages/vite-node/src/index.ts\"],\n      \"vite-node/client\": [\"./packages/vite-node/src/client.ts\"],\n      \"vite-node/server\": [\"./packages/vite-node/src/server.ts\"],\n      \"vite-node/utils\": [\"./packages/vite-node/src/utils.ts\"]\n    },\n    \"types\": [\n      \"vite/client\"\n    ]\n  },\n  \"exclude\": [\n    \"**/dist/**\",\n    \"./packages/vitest/dist/**\",\n    \"./packages/ui/client/**\",\n    \"./examples/**/*.*\",\n    \"./bench/**\"\n  ]\n}\n"
  },
  {
    "path": "docs/vite.config.ts",
    "content": "import fs from 'fs'\nimport type { Plugin } from 'vite'\nimport { defineConfig } from 'vite'\nimport AutoImport from 'unplugin-auto-import/vite'\nimport Components from 'unplugin-vue-components/vite'\nimport Unocss from 'unocss/vite'\nimport transformerDirective from '@unocss/transformer-directives'\nimport { presetAttributify, presetIcons, presetUno, presetTypography } from 'unocss'\nimport { resolve } from 'pathe'\nimport type { VitePluginPWAAPI } from 'vite-plugin-pwa'\nimport { VitePWA } from 'vite-plugin-pwa'\nimport fg from 'fast-glob'\nimport {\n  pwaFontStylesRegex,\n  pwaFontsRegex,\n  feathersDescription,\n  feathersName,\n  feathersShortName\n} from './.vitepress/meta'\nimport { optimizePages } from './.vitepress/scripts/assets'\nimport { ElementPlusResolver } from 'unplugin-vue-components/resolvers'\nimport { SearchPlugin } from 'vitepress-plugin-search'\n\nconst PWA = VitePWA({\n  outDir: '.vitepress/dist',\n  registerType: 'autoUpdate',\n  // include all static assets under public/\n  includeAssets: fg.sync('**/*.{png,svg,ico,txt}', { cwd: resolve(__dirname, 'public') }),\n  manifest: {\n    id: '/',\n    name: feathersName,\n    short_name: feathersShortName,\n    description: feathersDescription,\n    theme_color: '#ffffff',\n    icons: [\n      {\n        src: 'pwa-192x192.png',\n        sizes: '192x192',\n        type: 'image/png'\n      },\n      {\n        src: 'pwa-512x512.png',\n        sizes: '512x512',\n        type: 'image/png'\n      },\n      {\n        src: 'logo.svg',\n        sizes: '165x165',\n        type: 'image/svg',\n        purpose: 'any maskable'\n      }\n    ]\n  },\n  workbox: {\n    navigateFallbackDenylist: [/^\\/new$/],\n    runtimeCaching: [\n      {\n        urlPattern: pwaFontsRegex,\n        handler: 'CacheFirst',\n        options: {\n          cacheName: 'google-fonts-cache',\n          expiration: {\n            maxEntries: 10,\n            maxAgeSeconds: 60 * 60 * 24 * 365 // <== 365 days\n          },\n          cacheableResponse: {\n            statuses: [0, 200]\n          }\n        }\n      },\n      {\n        urlPattern: pwaFontStylesRegex,\n        handler: 'CacheFirst',\n        options: {\n          cacheName: 'gstatic-fonts-cache',\n          expiration: {\n            maxEntries: 10,\n            maxAgeSeconds: 60 * 60 * 24 * 365 // <== 365 days\n          },\n          cacheableResponse: {\n            statuses: [0, 200]\n          }\n        }\n      }\n    ]\n  }\n})\n\nexport default defineConfig({\n  plugins: [\n    SearchPlugin(),\n    AutoImport({\n      resolvers: [ElementPlusResolver()]\n    }),\n    Components({\n      include: [/\\.vue/, /\\.md/],\n      dirs: '.vitepress/components',\n      dts: '.vitepress/components.d.ts',\n      resolvers: [ElementPlusResolver({ ssr: false })]\n    }),\n    Unocss({\n      shortcuts: [\n        [\n          'btn',\n          'px-4 py-1 rounded inline-flex justify-center gap-2 text-white leading-30px children:mya !no-underline cursor-pointer disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'\n        ]\n      ],\n      presets: [\n        presetUno({\n          dark: 'media'\n        }),\n        presetAttributify(),\n        presetIcons({\n          scale: 1.2\n        }),\n        presetTypography()\n      ],\n      transformers: [transformerDirective()]\n    }),\n    IncludesPlugin(),\n    PWA,\n    {\n      name: 'pwa:post',\n      enforce: 'post',\n      async buildEnd() {\n        const pwaPlugin: VitePluginPWAAPI = PWA.find((i) => i.name === 'vite-plugin-pwa')?.api\n        const pwa = pwaPlugin && !pwaPlugin.disabled\n        await optimizePages(pwa)\n        if (pwa) await pwaPlugin.generateSW()\n      }\n    }\n  ],\n  ssr: { noExternal: ['element-plus'] }\n})\n\nfunction IncludesPlugin(): Plugin {\n  return {\n    name: 'include-plugin',\n    enforce: 'pre',\n    transform(code, id) {\n      let changed = false\n      code = code.replace(/\\[@@include\\]\\((.*?)\\)/, (_, url) => {\n        changed = true\n        const full = resolve(id, url)\n        return fs.readFileSync(full, 'utf-8')\n      })\n      if (changed) return code\n    }\n  }\n}\n"
  },
  {
    "path": "generators/package/index.tpl.ts",
    "content": "import { generator, renderTemplate, toFile } from '@featherscloud/pinion'\nimport { ModuleContext } from '../package'\n\ninterface Context extends ModuleContext {}\n\nconst template = ({ name }: Context) => `\nexport function ${name}() {\n  return 'Hello from ${name}'\n}\n`\n\nexport const generate = (context: Context) =>\n  generator(context).then(renderTemplate(template, toFile(context.packagePath, 'src', 'index.ts')))\n"
  },
  {
    "path": "generators/package/license.tpl.ts",
    "content": "import { generator, renderTemplate, toFile } from '@featherscloud/pinion'\nimport { ModuleContext } from '../package'\n\ninterface Context extends ModuleContext {}\n\nexport const generate = (context: Context) =>\n  generator(context).then(\n    renderTemplate(\n      `The MIT License (MIT)\n\nCopyright (c) ${new Date().getFullYear()} Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n  `,\n      toFile<Context>(context.packagePath, 'LICENSE')\n    )\n  )\n"
  },
  {
    "path": "generators/package/package.json.tpl.ts",
    "content": "import { generator, toFile, writeJSON } from '@featherscloud/pinion'\nimport { ModuleContext } from '../package'\n\ninterface Context extends ModuleContext {}\n\nexport const generate = (context: Context) =>\n  generator(context).then(\n    writeJSON<Context>(\n      ({ moduleName, description, name }) => ({\n        name: moduleName,\n        description,\n        version: '0.0.0',\n        homepage: 'https://feathersjs.com',\n        keywords: ['feathers'],\n        license: 'MIT',\n        repository: {\n          type: 'git',\n          url: 'git://github.com/feathersjs/feathers.git',\n          directory: `packages/${name}`\n        },\n        author: {\n          name: 'Feathers contributor',\n          email: 'hello@feathersjs.com',\n          url: 'https://feathersjs.com'\n        },\n        contributors: [],\n        bugs: {\n          url: 'https://github.com/feathersjs/feathers/issues'\n        },\n        engines: {\n          node: '>= 20'\n        },\n        files: ['CHANGELOG.md', 'LICENSE', 'README.md', 'src/**', 'lib/**', 'esm/**'],\n        // module: './esm/index.js',\n        main: './lib/index.js',\n        types: './src/index.ts',\n        exports: {\n          '.': {\n            // import: './esm/index.js',\n            require: './lib/index.js',\n            types: './src/index.ts'\n          }\n        },\n        scripts: {\n          prepublish: 'npm run compile',\n          pack: 'npm pack --pack-destination ../generators/test/build',\n          compile: 'shx rm -rf lib/ && tsc && npm run pack',\n          test: 'mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts'\n        },\n        publishConfig: {\n          access: 'public'\n        },\n        dependencies: {},\n        devDependencies: {}\n      }),\n      toFile('packages', context.name, 'package.json')\n    )\n  )\n"
  },
  {
    "path": "generators/package/readme.md.tpl.ts",
    "content": "import { generator, renderTemplate, toFile } from '@featherscloud/pinion'\nimport { ModuleContext } from '../package'\n\nconst template = ({ description, moduleName }: ModuleContext) => `# ${moduleName}\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/${moduleName}.svg?style=flat-square)](https://www.npmjs.com/package/${moduleName})\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> ${description}\n\n## Installation\n\n\\`\\`\\`\nnpm install ${moduleName} --save\n\\`\\`\\`\n\n## Documentation\n\nRefer to the [Feathers API documentation](https://feathersjs.com/api) for more details.\n\n## License\n\nCopyright (c) ${new Date().getFullYear()} [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n`\n\nexport const generate = (context: ModuleContext) =>\n  generator(context).then(renderTemplate(template, toFile(context.packagePath, 'README.md')))\n"
  },
  {
    "path": "generators/package/test.tpl.ts",
    "content": "import { generator, renderTemplate, toFile } from '@featherscloud/pinion'\nimport { ModuleContext } from '../package'\n\ninterface Context extends ModuleContext {}\n\nconst template = ({ moduleName, name }: Context) => /** ts */ `import { strict as assert } from 'assert'\nimport { ${name} } from '../src/index'\n\ndescribe('${moduleName}', () => {\n  it('initializes', () => {\n    assert.equal(${name}(), 'Hello from ${name}')\n  })\n})\n`\n\nexport const generate = (context: Context) =>\n  generator(context).then(\n    renderTemplate(template, toFile<Context>(context.packagePath, 'test', 'index.test.ts'))\n  )\n"
  },
  {
    "path": "generators/package/tsconfig.json.tpl.ts",
    "content": "import { generator, toFile, writeJSON } from '@featherscloud/pinion'\nimport { ModuleContext } from '../package'\n\nexport const generate = (context: ModuleContext) =>\n  generator(context).then(\n    writeJSON(\n      {\n        extends: '../../tsconfig',\n        include: ['src/**/*.ts'],\n        compilerOptions: {\n          outDir: 'lib'\n        }\n      },\n      toFile(context.packagePath, 'tsconfig.json')\n    )\n  )\n"
  },
  {
    "path": "generators/package.ts",
    "content": "import type { Callable, PinionContext } from '@featherscloud/pinion'\nimport { generator, install, prompt, runGenerators, toFile } from '@featherscloud/pinion'\n\nexport interface ModuleContext extends PinionContext {\n  name: string\n  uppername: string\n  description: string\n  moduleName: string\n  packagePath: Callable<string, ModuleContext>\n}\n\nexport const generate = (context: ModuleContext) =>\n  generator(context)\n    .then(\n      prompt<ModuleContext>([\n        {\n          type: 'input',\n          name: 'name',\n          message: 'What is the name of the module?'\n        },\n        {\n          type: 'input',\n          name: 'description',\n          message: 'Write a short description'\n        }\n      ])\n    )\n    .then((ctx) => {\n      return {\n        ...ctx,\n        moduleName: `@feathersjs/${ctx.name}`,\n        uppername: ctx.name.charAt(0).toUpperCase() + ctx.name.slice(1),\n        packagePath: toFile('packages', ctx.name)\n      }\n    })\n    .then(runGenerators(__dirname, 'package'))\n    .then(\n      install<ModuleContext>(\n        ['@types/node', 'shx', 'ts-node', 'typescript', 'mocha'],\n        true,\n        (context) => `npm --workspace packages/${context.name}`\n      )\n    )\n"
  },
  {
    "path": "lerna.json",
    "content": "{\n  \"ci\": false,\n  \"packages\": [\"packages/*\"],\n  \"version\": \"5.0.42\",\n  \"command\": {\n    \"bootstrap\": {\n      \"hoist\": true\n    },\n    \"publish\": {\n      \"allowBranch\": [\"crow\", \"dove\"],\n      \"message\": \"chore(release): publish %s\",\n      \"conventionalCommits\": true,\n      \"createRelease\": \"github\"\n    }\n  },\n  \"ignoreChanges\": [\n    \"**/changelog.md\",\n    \"**/CHANGELOG.md\",\n    \"**/package-lock.json\",\n    \"**/yarn.lock\",\n    \"**/test/**\",\n    \"lerna.json\",\n    \"readme.md\"\n  ]\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@feathersjs/feathers\",\n  \"private\": true,\n  \"homepage\": \"http://feathersjs.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributor\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 20\"\n  },\n  \"workspaces\": [\n    \"docs\",\n    \"packages/*\"\n  ],\n  \"scripts\": {\n    \"publish\": \"lerna publish --force-publish && git commit -am \\\"chore: Update changelog\\\" && git push origin\",\n    \"publish:major\": \"lerna publish major && git commit -am \\\"chore: Update changelog\\\" && git push origin\",\n    \"publish:minor\": \"lerna publish minor && git commit -am \\\"chore: Update changelog\\\" && git push origin\",\n    \"publish:patch\": \"lerna publish patch && git commit -am \\\"chore: Update changelog\\\" && git push origin\",\n    \"publish:premajor\": \"lerna publish premajor --preid pre --pre-dist-tag pre && git commit -am \\\"chore: Update version and changelog\\\" && git push origin\",\n    \"publish:prerelease\": \"lerna publish prerelease --preid pre --pre-dist-tag pre --dist-tag pre --force-publish && git commit -am \\\"chore: Update version and changelog\\\" && git push origin\",\n    \"prettier\": \"npx prettier \\\"packages/{,!(node_modules)/**/(src|test)/**/}*.ts\\\" --write\",\n    \"eslint\": \"eslint \\\"packages/**/*.ts\\\" --fix\",\n    \"lint\": \"npm run prettier && npm run eslint\",\n    \"compile\": \"lerna run compile\",\n    \"build:docs\": \"npm run build --workspace docs\",\n    \"update-dependencies\": \"npm exec --workspaces --include-workspace-root -- ncu -u --dep prod,dev,optional,peer -x node-fetch,\\\"@sinclair/typebox\\\",\\\"@types/express\\\",\\\"@types/express-serve-static-core\\\",commander,express,flexsearch,uuid,mongodb\",\n    \"clean\": \"find . -name node_modules -exec rm -rf '{}' + && find . -name package-lock.json -exec rm -rf '{}' +\",\n    \"test:deno\": \"deno test --config deno/tsconfig.json deno/test.ts\",\n    \"test\": \"npm run lint && npm run compile && c8 lerna run test --ignore @feathersjs/tests\",\n    \"generate:package\": \"pinion run generators/package.ts\"\n  },\n  \"devDependencies\": {\n    \"@featherscloud/pinion\": \"^0.5.4\",\n    \"@typescript-eslint/eslint-plugin\": \"^7.8.0\",\n    \"@typescript-eslint/parser\": \"^7.8.0\",\n    \"c8\": \"^9.1.0\",\n    \"eslint\": \"^8.57.0\",\n    \"eslint-config-prettier\": \"^9.1.0\",\n    \"eslint-plugin-prettier\": \"^5.1.3\",\n    \"lerna\": \"^8.1.2\",\n    \"npm-check-updates\": \"^16.14.20\",\n    \"prettier\": \"^3.2.5\",\n    \"typescript\": \"^5.4.5\"\n  }\n}\n"
  },
  {
    "path": "packages/adapter-commons/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n### Bug Fixes\n\n- **adapter-commons:** Faster sorter ([#3495](https://github.com/feathersjs/feathers/issues/3495)) ([22243e4](https://github.com/feathersjs/feathers/commit/22243e4d92edc1a7343b4cf42be6dfb22e8b86d5))\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n### Bug Fixes\n\n- **core:** Add PaginationParams to general find method ([#3095](https://github.com/feathersjs/feathers/issues/3095)) ([8ebdcf5](https://github.com/feathersjs/feathers/commit/8ebdcf5107fae5fa23920390052b871033de3a0a))\n- **core:** Use Symbol.for to instantiate shared symbols ([#3087](https://github.com/feathersjs/feathers/issues/3087)) ([7f3fc21](https://github.com/feathersjs/feathers/commit/7f3fc2167576f228f8183568eb52b077160e8d65))\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n### Features\n\n- **mongodb:** Add Object ID keyword converter and update MongoDB CLI & docs ([#3041](https://github.com/feathersjs/feathers/issues/3041)) ([ca0994e](https://github.com/feathersjs/feathers/commit/ca0994eaecb5a31f310bc980d106834e11f24f41))\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- **databases:** Ensure that query sanitization is not necessary when using query schemas ([#3022](https://github.com/feathersjs/feathers/issues/3022)) ([dbf514e](https://github.com/feathersjs/feathers/commit/dbf514e85d1508b95c007462a39b3cadd4ff391d))\n\n### Features\n\n- **database:** Add and to the query syntax ([#3021](https://github.com/feathersjs/feathers/issues/3021)) ([00cb0d9](https://github.com/feathersjs/feathers/commit/00cb0d9c302ae951ae007d3d6ceba33e254edd9c))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **adapter-commons:** multiple type definition issues ([#2876](https://github.com/feathersjs/feathers/issues/2876)) ([4ff1ed0](https://github.com/feathersjs/feathers/commit/4ff1ed084eb2b2cb687de27a28c96a0dad4530b7))\n\n### Features\n\n- **adapter:** Add patch data type to adapters and refactor AdapterBase usage ([#2906](https://github.com/feathersjs/feathers/issues/2906)) ([9ddc2e6](https://github.com/feathersjs/feathers/commit/9ddc2e6b028f026f939d6af68125847e5c6734b4))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Features\n\n- **knex:** Add KnexJS SQL database adapter to core ([#2671](https://github.com/feathersjs/feathers/issues/2671)) ([9380fff](https://github.com/feathersjs/feathers/commit/9380fff58596e8bb90b8bb098d2795b7eadfec20))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Bug Fixes\n\n- **adapter-commons:** Clarify adapter query filtering ([#2607](https://github.com/feathersjs/feathers/issues/2607)) ([2dac771](https://github.com/feathersjs/feathers/commit/2dac771b0a3298d6dd25994d05186701b0617718))\n\n### Features\n\n- **mongodb:** Add feathers-mongodb adapter as @feathersjs/mongodb ([#2610](https://github.com/feathersjs/feathers/issues/2610)) ([6d43734](https://github.com/feathersjs/feathers/commit/6d43734a53db02c435cafc52a22dca414e5d0940))\n- **typescript:** Improve adapter typings ([#2605](https://github.com/feathersjs/feathers/issues/2605)) ([3b2ca0a](https://github.com/feathersjs/feathers/commit/3b2ca0a6a8e03e8390272c4d7e930b4bffdaacf5))\n- **typescript:** Improve params and query typeability ([#2600](https://github.com/feathersjs/feathers/issues/2600)) ([df28b76](https://github.com/feathersjs/feathers/commit/df28b7619161f1df5e700326f52cca1a92dc5d28))\n\n### BREAKING CHANGES\n\n- **adapter-commons:** Changes the common adapter base class to use `sanitizeQuery` and `sanitizeData`\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n### Features\n\n- **core:** Add app.teardown functionality ([#2570](https://github.com/feathersjs/feathers/issues/2570)) ([fcdf524](https://github.com/feathersjs/feathers/commit/fcdf524ae1995bb59265d39f12e98b7794bed023))\n- **core:** Finalize app.teardown() functionality ([#2584](https://github.com/feathersjs/feathers/issues/2584)) ([1a166f3](https://github.com/feathersjs/feathers/commit/1a166f3ded811ecacf0ae8cb67880bc9fa2eeafa))\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **adapter-commons:** clean up in sort.ts and select function ([#2492](https://github.com/feathersjs/feathers/issues/2492)) ([c3ec8a4](https://github.com/feathersjs/feathers/commit/c3ec8a418bdc85506e3c5100015720a45454d8d3))\n- **adapter-commons:** Fix sorting for embedded objects ([#2488](https://github.com/feathersjs/feathers/issues/2488)) ([9c22f70](https://github.com/feathersjs/feathers/commit/9c22f70a838cb6341775d91705a7527c8fc5590e))\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- Update database adapter common repository urls ([#2380](https://github.com/feathersjs/feathers/issues/2380)) ([3f4db68](https://github.com/feathersjs/feathers/commit/3f4db68d6700c7d9023ecd17d0d39893f75a19fd))\n\n### Features\n\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n- **typescript:** Allow to pass generic service options to adapter services ([#2392](https://github.com/feathersjs/feathers/issues/2392)) ([f9431f2](https://github.com/feathersjs/feathers/commit/f9431f242354f804cafb835519f98dd405ac4f0b))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n### Bug Fixes\n\n- **typescript:** Move Paginated type back for better compatibility ([#2350](https://github.com/feathersjs/feathers/issues/2350)) ([2917d05](https://github.com/feathersjs/feathers/commit/2917d05fffb4716d3c4cdaa5ac6a1aee0972e8a6))\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n### Bug Fixes\n\n- **dependencies:** Fix transport-commons dependency and update other dependencies ([#2284](https://github.com/feathersjs/feathers/issues/2284)) ([05b03b2](https://github.com/feathersjs/feathers/commit/05b03b27b40604d956047e3021d8053c3a137616))\n\n### Features\n\n- **adapter-commons:** Added mongoDB like search in embedded objects ([687e3c7](https://github.com/feathersjs/feathers/commit/687e3c7c36904221b2707d0220c0893e3cb1faa9))\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- **adapter-commons:** Always respect paginate.max ([#2267](https://github.com/feathersjs/feathers/issues/2267)) ([f588257](https://github.com/feathersjs/feathers/commit/f5882575536624ed3a32bb6e3ff1919fa17e366d))\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n- **adapter-commons:** Return missing overloads ([#2203](https://github.com/feathersjs/feathers/issues/2203)) ([bbe7e2a](https://github.com/feathersjs/feathers/commit/bbe7e2a131633e9a6e7aac7f7fa02a312bca63c7))\n\n### Features\n\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n### Features\n\n- **memory:** Move feathers-memory into @feathersjs/memory ([#2153](https://github.com/feathersjs/feathers/issues/2153)) ([dd61fe3](https://github.com/feathersjs/feathers/commit/dd61fe371fb0502f78b8ccbe1f45a030e31ecff6))\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-10-21)\n\n### Bug Fixes\n\n- **typescript:** Remove remaining overloads ([a29fabc](https://github.com/feathersjs/databases/commit/a29fabc9cf6050793a5e93948507ce3e19a235dd))\n\n## [4.5.6](https://github.com/feathersjs/feathers/compare/v4.5.5...v4.5.6) (2020-10-21)\n\n### Bug Fixes\n\n- Revert \"fix(adapter-commons): Add missing overloads ([#4](https://github.com/feathersjs/databases/issues/4))\" ([dfaa850](https://github.com/feathersjs/databases/commit/dfaa8500644021f78d6234a79358f1b26ce2c8d3))\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-10-21)\n\n### Bug Fixes\n\n- **typescript:** Revert \"fix: add overloads for `find` ([#9](https://github.com/feathersjs/databases/issues/9))\" ([85c20b2](https://github.com/feathersjs/databases/commit/85c20b267e67192169ded97dd5056f116a5ad7b5))\n\n## [4.5.4](https://github.com/feathersjs/feathers/compare/v4.5.3...v4.5.4) (2020-09-27)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## 4.5.3 (2020-09-24)\n\n### Bug Fixes\n\n- add overloads for `find` ([#9](https://github.com/feathersjs/databases/issues/9)) ([87c7c29](https://github.com/feathersjs/databases/commit/87c7c29ef017b3cae135e7b7597a7e63fb7d0961))\n- **adapter-commons:** Add missing overloads ([#4](https://github.com/feathersjs/databases/issues/4)) ([b6c80ff](https://github.com/feathersjs/databases/commit/b6c80ff39a32c1b023178f06cffbcaa6d08c554d))\n- Improve Service typings for DB Common API ([#1](https://github.com/feathersjs/databases/issues/1)) ([fd3b949](https://github.com/feathersjs/databases/commit/fd3b9496b0a46f8fd9779c2603faeeb92bd1afc1))\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n### Bug Fixes\n\n- **adapter-commons:** Filter arrays in queries ([#1724](https://github.com/feathersjs/feathers/issues/1724)) ([872b669](https://github.com/feathersjs/feathers/commit/872b66906a806ab92ca41b5f6f504ff0af1ce79e))\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [4.3.8](https://github.com/feathersjs/feathers/compare/v4.3.7...v4.3.8) (2019-10-14)\n\n### Bug Fixes\n\n- Remove adapter commons type alternatives ([#1620](https://github.com/feathersjs/feathers/issues/1620)) ([c9f3086](https://github.com/feathersjs/feathers/commit/c9f3086344420b57dbce7c4169cf550c97509f0d))\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n### Bug Fixes\n\n- improve Service and AdapterService types ([#1567](https://github.com/feathersjs/feathers/issues/1567)) ([baad6a2](https://github.com/feathersjs/feathers/commit/baad6a26f0f543b712ccb40359b3933ad3a21392))\n\n## [4.3.6](https://github.com/feathersjs/feathers/compare/v4.3.5...v4.3.6) (2019-10-07)\n\n### Bug Fixes\n\n- Check query for NaN ([#1607](https://github.com/feathersjs/feathers/issues/1607)) ([f1a781f](https://github.com/feathersjs/feathers/commit/f1a781f))\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n### Bug Fixes\n\n- @feathersjs/adapter-commons: `update` id is non-nullable ([#1468](https://github.com/feathersjs/feathers/issues/1468)) ([43ec802](https://github.com/feathersjs/feathers/commit/43ec802))\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n### Bug Fixes\n\n- @feathersjs/adapter-commons: remove data from `remove` arguments ([#1426](https://github.com/feathersjs/feathers/issues/1426)) ([fd54ae9](https://github.com/feathersjs/feathers/commit/fd54ae9))\n\n### Features\n\n- adapter-commons: add `allowsMulti(method)` to AdapterService ([#1431](https://github.com/feathersjs/feathers/issues/1431)) ([e688851](https://github.com/feathersjs/feathers/commit/e688851))\n- Add hook-less methods and service option types to adapter-commons ([#1433](https://github.com/feathersjs/feathers/issues/1433)) ([857f54a](https://github.com/feathersjs/feathers/commit/857f54a))\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n**Note:** Version bump only for package @feathersjs/adapter-commons\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n- **adapter-commons:** Keep Symbols when filtering a query ([#1141](https://github.com/feathersjs/feathers/issues/1141)) ([c9f55d8](https://github.com/feathersjs/feathers/commit/c9f55d8))\n- **chore:** Add .npmignore to adapter-commons ([8e129d8](https://github.com/feathersjs/feathers/commit/8e129d8))\n- Add whitelist and filter support to common adapter service ([#1132](https://github.com/feathersjs/feathers/issues/1132)) ([df1daaa](https://github.com/feathersjs/feathers/commit/df1daaa))\n- Fix AdapterService multi option when set to true ([#1134](https://github.com/feathersjs/feathers/issues/1134)) ([40402fc](https://github.com/feathersjs/feathers/commit/40402fc))\n- Throw error in `filterQuery` when query parameter is unknown ([#1131](https://github.com/feathersjs/feathers/issues/1131)) ([cd1a183](https://github.com/feathersjs/feathers/commit/cd1a183))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n- Update adapter common tests to check for falsy ([#1140](https://github.com/feathersjs/feathers/issues/1140)) ([2856722](https://github.com/feathersjs/feathers/commit/2856722))\n\n### chore\n\n- **package:** Move adapter tests into their own module ([#1164](https://github.com/feathersjs/feathers/issues/1164)) ([dcc1e6b](https://github.com/feathersjs/feathers/commit/dcc1e6b))\n\n### Features\n\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Authentication v3 core server implementation ([#1205](https://github.com/feathersjs/feathers/issues/1205)) ([1bd7591](https://github.com/feathersjs/feathers/commit/1bd7591))\n- Common database adapter utilities and test suite ([#1130](https://github.com/feathersjs/feathers/issues/1130)) ([17b3dc8](https://github.com/feathersjs/feathers/commit/17b3dc8))\n\n### BREAKING CHANGES\n\n- **package:** Removes adapter tests from @feathersjs/adapter-commons\n- Move database adapter utilities from @feathersjs/commons into its own module\n\n# [2.0.0](https://github.com/feathersjs/feathers/compare/@feathersjs/adapter-commons@1.0.7...@feathersjs/adapter-commons@2.0.0) (2019-01-10)\n\n### chore\n\n- **package:** Move adapter tests into their own module ([#1164](https://github.com/feathersjs/feathers/issues/1164)) ([dcc1e6b](https://github.com/feathersjs/feathers/commit/dcc1e6b))\n\n### BREAKING CHANGES\n\n- **package:** Removes adapter tests from @feathersjs/adapter-commons\n\n## [1.0.7](https://github.com/feathersjs/feathers/compare/@feathersjs/adapter-commons@1.0.6...@feathersjs/adapter-commons@1.0.7) (2019-01-02)\n\n### Bug Fixes\n\n- **chore:** Add .npmignore to adapter-commons ([8e129d8](https://github.com/feathersjs/feathers/commit/8e129d8))\n\n## [1.0.6](https://github.com/feathersjs/feathers/compare/@feathersjs/adapter-commons@1.0.5...@feathersjs/adapter-commons@1.0.6) (2018-12-21)\n\n### Bug Fixes\n\n- **adapter-commons:** Keep Symbols when filtering a query ([#1141](https://github.com/feathersjs/feathers/issues/1141)) ([c9f55d8](https://github.com/feathersjs/feathers/commit/c9f55d8))\n\n## [1.0.5](https://github.com/feathersjs/feathers/compare/@feathersjs/adapter-commons@1.0.4...@feathersjs/adapter-commons@1.0.5) (2018-12-20)\n\n### Bug Fixes\n\n- Update adapter common tests to check for falsy ([#1140](https://github.com/feathersjs/feathers/issues/1140)) ([2856722](https://github.com/feathersjs/feathers/commit/2856722))\n\n## [1.0.4](https://github.com/feathersjs/feathers/compare/@feathersjs/adapter-commons@1.0.3...@feathersjs/adapter-commons@1.0.4) (2018-12-17)\n\n### Bug Fixes\n\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n\n<a name=\"1.0.3\"></a>\n\n## [1.0.3](https://github.com/feathersjs/feathers/compare/@feathersjs/adapter-commons@1.0.2...@feathersjs/adapter-commons@1.0.3) (2018-12-17)\n\n### Bug Fixes\n\n- Fix AdapterService multi option when set to true ([#1134](https://github.com/feathersjs/feathers/issues/1134)) ([40402fc](https://github.com/feathersjs/feathers/commit/40402fc))\n\n<a name=\"1.0.2\"></a>\n\n## [1.0.2](https://github.com/feathersjs/feathers/compare/@feathersjs/adapter-commons@1.0.1...@feathersjs/adapter-commons@1.0.2) (2018-12-17)\n\n### Bug Fixes\n\n- Add whitelist and filter support to common adapter service ([#1132](https://github.com/feathersjs/feathers/issues/1132)) ([df1daaa](https://github.com/feathersjs/feathers/commit/df1daaa))\n\n<a name=\"1.0.1\"></a>\n\n## [1.0.1](https://github.com/feathersjs/feathers/compare/@feathersjs/adapter-commons@1.0.0...@feathersjs/adapter-commons@1.0.1) (2018-12-17)\n\n### Bug Fixes\n\n- Throw error in `filterQuery` when query parameter is unknown ([#1131](https://github.com/feathersjs/feathers/issues/1131)) ([cd1a183](https://github.com/feathersjs/feathers/commit/cd1a183))\n\n<a name=\"1.0.0\"></a>\n\n# 1.0.0 (2018-12-16)\n\n### Features\n\n- Common database adapter utilities and test suite ([#1130](https://github.com/feathersjs/feathers/issues/1130)) ([17b3dc8](https://github.com/feathersjs/feathers/commit/17b3dc8))\n\n### BREAKING CHANGES\n\n- Move database adapter utilities from @feathersjs/commons into its own module\n"
  },
  {
    "path": "packages/adapter-commons/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/adapter-commons/README.md",
    "content": "# Feathers Adapter Commons\n\n[![CI](https://github.com/feathersjs/feathers/workflows/Node.js%20CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3A%22Node.js+CI%22)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/adapter-commons.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/adapter-commons)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Shared utility functions for Feathers adatabase adapters\n\n## Installation\n\n```\nnpm install @feathersjs/adapter-commons --save\n```\n\n## Documentation\n\nRefer to the [Feathers database adapter documentation](https://feathersjs.com/api/databases/common.html) for more details.\n\n## Authors\n\n[Feathers contributors](https://github.com/feathersjs/adapter-commons/graphs/contributors)\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/adapter-commons/package.json",
    "content": "{\n  \"name\": \"@feathersjs/adapter-commons\",\n  \"version\": \"5.0.42\",\n  \"description\": \"Shared database adapter utility functions\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"keywords\": [\n    \"feathers\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/feathers\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/adapter-commons\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributor\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\"\n  },\n  \"devDependencies\": {\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/mongodb\": \"^4.0.6\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"mongodb\": \"^6.19.0\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/adapter-commons/src/declarations.ts",
    "content": "import { Query, Params, Paginated, Id, PaginationParams, PaginationOptions } from '@feathersjs/feathers'\n\nexport type FilterQueryOptions = {\n  filters?: FilterSettings\n  operators?: string[]\n  paginate?: PaginationParams\n}\n\nexport type QueryFilter = (value: any, options: FilterQueryOptions) => any\n\nexport type FilterSettings = {\n  [key: string]: QueryFilter | true\n}\n\n// re-export from @feathersjs/feathers to prevent breaking changes\nexport { PaginationOptions, PaginationParams }\n\nexport interface AdapterServiceOptions {\n  /**\n   * Whether to allow multiple updates for everything (`true`) or specific methods (e.g. `['create', 'remove']`)\n   */\n  multi?: boolean | string[]\n  /**\n   * The name of the id property\n   */\n  id?: string\n  /**\n   * Pagination settings for this service\n   */\n  paginate?: PaginationParams\n  /**\n   * A list of additional property query operators to allow in a query\n   *\n   * @deprecated No longer needed when a query schema is used\n   */\n  operators?: string[]\n  /**\n   * An object of additional top level query filters, e.g. `{ $populate: true }`\n   * Can also be a converter function like `{ $ignoreCase: (value) => value === 'true' ? true : false }`\n   *\n   * @deprecated No longer needed when a query schema is used\n   */\n  filters?: FilterSettings\n  /**\n   * @deprecated Use service `events` option when registering the service with `app.use`.\n   */\n  events?: string[]\n  /**\n   * @deprecated No longer needed when a query schema is used\n   */\n  whitelist?: string[]\n}\n\nexport interface AdapterQuery extends Query {\n  $limit?: number\n  $skip?: number\n  $select?: string[]\n  $sort?: { [key: string]: 1 | -1 }\n}\n/**\n * Additional `params` that can be passed to an adapter service method call.\n */\nexport interface AdapterParams<\n  Q = AdapterQuery,\n  A extends Partial<AdapterServiceOptions> = Partial<AdapterServiceOptions>\n> extends Params<Q> {\n  adapter?: A\n  paginate?: PaginationParams\n}\n\n/**\n * Hook-less (internal) service methods. Directly call database adapter service methods\n * without running any service-level hooks or sanitization. This can be useful if you need the raw data\n * from the service and don't want to trigger any of its hooks.\n *\n * Important: These methods are only available internally on the server, not on the client\n * side and only for the Feathers database adapters.\n *\n * These methods do not trigger events.\n *\n * @see {@link https://docs.feathersjs.com/guides/migrating.html#hook-less-service-methods}\n */\nexport interface InternalServiceMethods<\n  Result = any,\n  Data = Result,\n  PatchData = Partial<Data>,\n  Params extends AdapterParams = AdapterParams,\n  IdType = Id\n> {\n  /**\n   * Retrieve all resources from this service.\n   * Does not sanitize the query and should only be used on the server.\n   *\n   * @param _params - Service call parameters {@link Params}\n   */\n  _find(_params?: Params & { paginate?: PaginationOptions }): Promise<Paginated<Result>>\n  _find(_params?: Params & { paginate: false }): Promise<Result[]>\n  _find(params?: Params): Promise<Result[] | Paginated<Result>>\n\n  /**\n   * Retrieve a single resource matching the given ID, skipping any service-level hooks.\n   * Does not sanitize the query and should only be used on the server.\n   *\n   * @param id - ID of the resource to locate\n   * @param params - Service call parameters {@link Params}\n   * @see {@link HookLessServiceMethods}\n   * @see {@link https://docs.feathersjs.com/api/services.html#get-id-params|Feathers API Documentation: .get(id, params)}\n   */\n  _get(id: IdType, params?: Params): Promise<Result>\n\n  /**\n   * Create a new resource for this service, skipping any service-level hooks.\n   * Does not sanitize data or checks if multiple updates are allowed and should only be used on the server.\n   *\n   * @param data - Data to insert into this service.\n   * @param params - Service call parameters {@link Params}\n   * @see {@link HookLessServiceMethods}\n   * @see {@link https://docs.feathersjs.com/api/services.html#create-data-params|Feathers API Documentation: .create(data, params)}\n   */\n  _create(data: Data, params?: Params): Promise<Result>\n  _create(data: Data[], params?: Params): Promise<Result[]>\n  _create(data: Data | Data[], params?: Params): Promise<Result | Result[]>\n\n  /**\n   * Completely replace the resource identified by id, skipping any service-level hooks.\n   * Does not sanitize data or query and should only be used on the server.\n   *\n   * @param id - ID of the resource to be updated\n   * @param data - Data to be put in place of the current resource.\n   * @param params - Service call parameters {@link Params}\n   * @see {@link HookLessServiceMethods}\n   * @see {@link https://docs.feathersjs.com/api/services.html#update-id-data-params|Feathers API Documentation: .update(id, data, params)}\n   */\n  _update(id: IdType, data: Data, params?: Params): Promise<Result>\n\n  /**\n   * Merge any resources matching the given ID with the given data, skipping any service-level hooks.\n   * Does not sanitize the data or query and should only be used on the server.\n   *\n   * @param id - ID of the resource to be patched\n   * @param data - Data to merge with the current resource.\n   * @param params - Service call parameters {@link Params}\n   * @see {@link HookLessServiceMethods}\n   * @see {@link https://docs.feathersjs.com/api/services.html#patch-id-data-params|Feathers API Documentation: .patch(id, data, params)}\n   */\n  _patch(id: null, data: PatchData, params?: Params): Promise<Result[]>\n  _patch(id: IdType, data: PatchData, params?: Params): Promise<Result>\n  _patch(id: IdType | null, data: PatchData, params?: Params): Promise<Result | Result[]>\n\n  /**\n   * Remove resources matching the given ID from the this service, skipping any service-level hooks.\n   * Does not sanitize query and should only be used on the server.\n   *\n   * @param id - ID of the resource to be removed\n   * @param params - Service call parameters {@link Params}\n   * @see {@link HookLessServiceMethods}\n   * @see {@link https://docs.feathersjs.com/api/services.html#remove-id-params|Feathers API Documentation: .remove(id, params)}\n   */\n  _remove(id: null, params?: Params): Promise<Result[]>\n  _remove(id: IdType, params?: Params): Promise<Result>\n  _remove(id: IdType | null, params?: Params): Promise<Result | Result[]>\n}\n"
  },
  {
    "path": "packages/adapter-commons/src/index.ts",
    "content": "import { _ } from '@feathersjs/commons'\nimport { Params } from '@feathersjs/feathers'\n\nexport * from './declarations'\nexport * from './service'\nexport * from './query'\nexport * from './sort'\n\n// Return a function that filters a result object or array\n// and picks only the fields passed as `params.query.$select`\n// and additional `otherFields`\nexport function select(params: Params, ...otherFields: string[]) {\n  const queryFields: string[] | undefined = params?.query?.$select\n\n  if (!queryFields) {\n    return (result: any) => result\n  }\n\n  const resultFields = queryFields.concat(otherFields)\n  const convert = (result: any) => _.pick(result, ...resultFields)\n\n  return (result: any) => {\n    if (Array.isArray(result)) {\n      return result.map(convert)\n    }\n\n    return convert(result)\n  }\n}\n"
  },
  {
    "path": "packages/adapter-commons/src/query.ts",
    "content": "import { _ } from '@feathersjs/commons'\nimport { BadRequest } from '@feathersjs/errors'\nimport { Query } from '@feathersjs/feathers'\nimport { FilterQueryOptions, FilterSettings, PaginationParams } from './declarations'\n\nconst parse = (value: any) => (typeof value !== 'undefined' ? parseInt(value, 10) : value)\n\nconst isPlainObject = (value: any) => _.isObject(value) && value.constructor === {}.constructor\n\nconst validateQueryProperty = (query: any, operators: string[] = []): Query => {\n  if (!isPlainObject(query)) {\n    return query\n  }\n\n  for (const key of Object.keys(query)) {\n    if (key.startsWith('$') && !operators.includes(key)) {\n      throw new BadRequest(`Invalid query parameter ${key}`, query)\n    }\n\n    const value = query[key]\n\n    if (isPlainObject(value)) {\n      query[key] = validateQueryProperty(value, operators)\n    }\n  }\n\n  return {\n    ...query\n  }\n}\n\nconst getFilters = (query: Query, settings: FilterQueryOptions) => {\n  const filterNames = Object.keys(settings.filters)\n\n  return filterNames.reduce(\n    (current, key) => {\n      const queryValue = query[key]\n      const filter = settings.filters[key]\n\n      if (filter) {\n        const value = typeof filter === 'function' ? filter(queryValue, settings) : queryValue\n\n        if (value !== undefined) {\n          current[key] = value\n        }\n      }\n\n      return current\n    },\n    {} as { [key: string]: any }\n  )\n}\n\nconst getQuery = (query: Query, settings: FilterQueryOptions) => {\n  const keys = Object.keys(query).concat(Object.getOwnPropertySymbols(query) as any as string[])\n\n  return keys.reduce((result, key) => {\n    if (typeof key === 'string' && key.startsWith('$')) {\n      if (settings.filters[key] === undefined) {\n        throw new BadRequest(`Invalid filter value ${key}`)\n      }\n    } else {\n      result[key] = validateQueryProperty(query[key], settings.operators)\n    }\n\n    return result\n  }, {} as Query)\n}\n\n/**\n * Returns the converted `$limit` value based on the `paginate` configuration.\n * @param _limit The limit value\n * @param paginate The pagination options\n * @returns The converted $limit value\n */\nexport const getLimit = (_limit: any, paginate?: PaginationParams) => {\n  const limit = parse(_limit)\n\n  if (paginate && (paginate.default || paginate.max)) {\n    const base = paginate.default || 0\n    const lower = typeof limit === 'number' && !isNaN(limit) && limit >= 0 ? limit : base\n    const upper = typeof paginate.max === 'number' ? paginate.max : Number.MAX_VALUE\n\n    return Math.min(lower, upper)\n  }\n\n  return limit\n}\n\nexport const OPERATORS = ['$in', '$nin', '$lt', '$lte', '$gt', '$gte', '$ne', '$or']\n\nexport const FILTERS: FilterSettings = {\n  $skip: (value: any) => parse(value),\n  $sort: (sort: any): { [key: string]: number } => {\n    if (typeof sort !== 'object' || Array.isArray(sort)) {\n      return sort\n    }\n\n    return Object.keys(sort).reduce(\n      (result, key) => {\n        result[key] = typeof sort[key] === 'object' ? sort[key] : parse(sort[key])\n\n        return result\n      },\n      {} as { [key: string]: number }\n    )\n  },\n  $limit: (_limit: any, { paginate }: FilterQueryOptions) => getLimit(_limit, paginate),\n  $select: (select: any) => {\n    if (Array.isArray(select)) {\n      return select.map((current) => `${current}`)\n    }\n\n    return select\n  },\n  $or: (or: any, { operators }: FilterQueryOptions) => {\n    if (Array.isArray(or)) {\n      return or.map((current) => validateQueryProperty(current, operators))\n    }\n\n    return or\n  },\n  $and: (and: any, { operators }: FilterQueryOptions) => {\n    if (Array.isArray(and)) {\n      return and.map((current) => validateQueryProperty(current, operators))\n    }\n\n    return and\n  }\n}\n\n/**\n * Converts Feathers special query parameters and pagination settings\n * and returns them separately as `filters` and the rest of the query\n * as `query`. `options` also gets passed the pagination settings and\n * a list of additional `operators` to allow when querying properties.\n *\n * @param query The initial query\n * @param options Options for filtering the query\n * @returns An object with `query` which contains the query without `filters`\n * and `filters` which contains the converted values for each filter.\n */\nexport function filterQuery(_query: Query, options: FilterQueryOptions = {}) {\n  const query = _query || {}\n  const settings = {\n    ...options,\n    filters: {\n      ...FILTERS,\n      ...options.filters\n    },\n    operators: OPERATORS.concat(options.operators || [])\n  }\n\n  return {\n    filters: getFilters(query, settings),\n    query: getQuery(query, settings)\n  }\n}\n"
  },
  {
    "path": "packages/adapter-commons/src/service.ts",
    "content": "import { Id, Paginated, Query } from '@feathersjs/feathers'\nimport {\n  AdapterParams,\n  AdapterServiceOptions,\n  InternalServiceMethods,\n  PaginationOptions\n} from './declarations'\nimport { filterQuery } from './query'\n\nexport const VALIDATED = Symbol.for('@feathersjs/adapter/sanitized')\n\nconst alwaysMulti: { [key: string]: boolean } = {\n  find: true,\n  get: false,\n  update: false\n}\n\n/**\n * An abstract base class that a database adapter can extend from to implement the\n * `__find`, `__get`, `__update`, `__patch` and `__remove` methods.\n */\nexport abstract class AdapterBase<\n  Result = any,\n  Data = Result,\n  PatchData = Partial<Data>,\n  ServiceParams extends AdapterParams = AdapterParams,\n  Options extends AdapterServiceOptions = AdapterServiceOptions,\n  IdType = Id\n> implements InternalServiceMethods<Result, Data, PatchData, ServiceParams, IdType> {\n  options: Options\n\n  constructor(options: Options) {\n    this.options = {\n      id: 'id',\n      events: [],\n      paginate: false,\n      multi: false,\n      filters: {},\n      operators: [],\n      ...options\n    }\n  }\n\n  get id() {\n    return this.options.id\n  }\n\n  get events() {\n    return this.options.events\n  }\n\n  /**\n   * Check if this adapter allows multiple updates for a method.\n   * @param method The method name to check.\n   * @param params The service call params.\n   * @returns Wether or not multiple updates are allowed.\n   */\n  allowsMulti(method: string, params: ServiceParams = {} as ServiceParams) {\n    const always = alwaysMulti[method]\n\n    if (typeof always !== 'undefined') {\n      return always\n    }\n\n    const { multi } = this.getOptions(params)\n\n    if (multi === true || !multi) {\n      return multi\n    }\n\n    return multi.includes(method)\n  }\n\n  /**\n   * Returns the combined options for a service call. Options will be merged\n   * with `this.options` and `params.adapter` for dynamic overrides.\n   *\n   * @param params The parameters for the service method call\n   * @returns The actual options for this call\n   */\n  getOptions(params: ServiceParams): Options {\n    const paginate = params.paginate !== undefined ? params.paginate : this.options.paginate\n\n    return {\n      ...this.options,\n      paginate,\n      ...params.adapter\n    }\n  }\n\n  /**\n   * Returns a sanitized version of `params.query`, converting filter values\n   * (like $limit and $skip) into the expected type. Will throw an error if\n   * a `$` prefixed filter or operator value that is not allowed in `filters`\n   * or `operators` is encountered.\n   *\n   * @param params The service call parameter.\n   * @returns A new object containing the sanitized query.\n   */\n  async sanitizeQuery(params: ServiceParams = {} as ServiceParams): Promise<Query> {\n    // We don't need legacy query sanitisation if the query has been validated by a schema already\n    if (params.query && (params.query as any)[VALIDATED]) {\n      return params.query || {}\n    }\n\n    const options = this.getOptions(params)\n    const { query, filters } = filterQuery(params.query, options)\n\n    return {\n      ...filters,\n      ...query\n    }\n  }\n\n  /**\n   * Retrieve all resources from this service.\n   * Does not sanitize the query and should only be used on the server.\n   *\n   * @param _params - Service call parameters {@link ServiceParams}\n   */\n  abstract _find(_params?: ServiceParams & { paginate?: PaginationOptions }): Promise<Paginated<Result>>\n  abstract _find(_params?: ServiceParams & { paginate: false }): Promise<Result[]>\n  abstract _find(params?: ServiceParams): Promise<Result[] | Paginated<Result>>\n\n  /**\n   * Retrieve a single resource matching the given ID, skipping any service-level hooks.\n   * Does not sanitize the query and should only be used on the server.\n   *\n   * @param id - ID of the resource to locate\n   * @param params - Service call parameters {@link ServiceParams}\n   * @see {@link HookLessServiceMethods}\n   * @see {@link https://docs.feathersjs.com/api/services.html#get-id-params|Feathers API Documentation: .get(id, params)}\n   */\n  abstract _get(id: IdType, params?: ServiceParams): Promise<Result>\n\n  /**\n   * Create a new resource for this service, skipping any service-level hooks.\n   * Does not check if multiple updates are allowed and should only be used on the server.\n   *\n   * @param data - Data to insert into this service.\n   * @param params - Service call parameters {@link ServiceParams}\n   * @see {@link HookLessServiceMethods}\n   * @see {@link https://docs.feathersjs.com/api/services.html#create-data-params|Feathers API Documentation: .create(data, params)}\n   */\n  abstract _create(data: Data, params?: ServiceParams): Promise<Result>\n  abstract _create(data: Data[], params?: ServiceParams): Promise<Result[]>\n  abstract _create(data: Data | Data[], params?: ServiceParams): Promise<Result | Result[]>\n\n  /**\n   * Completely replace the resource identified by id, skipping any service-level hooks.\n   * Does not sanitize the query and should only be used on the server.\n   *\n   * @param id - ID of the resource to be updated\n   * @param data - Data to be put in place of the current resource.\n   * @param params - Service call parameters {@link ServiceParams}\n   * @see {@link HookLessServiceMethods}\n   * @see {@link https://docs.feathersjs.com/api/services.html#update-id-data-params|Feathers API Documentation: .update(id, data, params)}\n   */\n  abstract _update(id: IdType, data: Data, params?: ServiceParams): Promise<Result>\n\n  /**\n   * Merge any resources matching the given ID with the given data, skipping any service-level hooks.\n   * Does not sanitize the query and should only be used on the server.\n   *\n   * @param id - ID of the resource to be patched\n   * @param data - Data to merge with the current resource.\n   * @param params - Service call parameters {@link ServiceParams}\n   * @see {@link HookLessServiceMethods}\n   * @see {@link https://docs.feathersjs.com/api/services.html#patch-id-data-params|Feathers API Documentation: .patch(id, data, params)}\n   */\n  abstract _patch(id: null, data: PatchData, params?: ServiceParams): Promise<Result[]>\n  abstract _patch(id: IdType, data: PatchData, params?: ServiceParams): Promise<Result>\n  abstract _patch(id: IdType | null, data: PatchData, params?: ServiceParams): Promise<Result | Result[]>\n\n  /**\n   * Remove resources matching the given ID from the this service, skipping any service-level hooks.\n   * Does not sanitize query and should only be used on the server.\n   *\n   * @param id - ID of the resource to be removed\n   * @param params - Service call parameters {@link ServiceParams}\n   * @see {@link HookLessServiceMethods}\n   * @see {@link https://docs.feathersjs.com/api/services.html#remove-id-params|Feathers API Documentation: .remove(id, params)}\n   */\n  abstract _remove(id: null, params?: ServiceParams): Promise<Result[]>\n  abstract _remove(id: IdType, params?: ServiceParams): Promise<Result>\n  abstract _remove(id: IdType | null, params?: ServiceParams): Promise<Result | Result[]>\n}\n"
  },
  {
    "path": "packages/adapter-commons/src/sort.ts",
    "content": "// Sorting algorithm taken from NeDB (https://github.com/louischatriot/nedb)\n// See https://github.com/louischatriot/nedb/blob/e3f0078499aa1005a59d0c2372e425ab789145c1/lib/model.js#L189\n\nexport function compareNSB(a: number | string | boolean, b: number | string | boolean): 0 | 1 | -1 {\n  if (a === b) {\n    return 0\n  }\n\n  return a < b ? -1 : 1\n}\n\nexport function compareArrays(a: any[], b: any[]): 0 | 1 | -1 {\n  for (let i = 0, l = Math.min(a.length, b.length); i < l; i++) {\n    const comparison = compare(a[i], b[i])\n\n    if (comparison !== 0) {\n      return comparison\n    }\n  }\n\n  // Common section was identical, longest one wins\n  return compareNSB(a.length, b.length)\n}\n\nexport function compare(\n  a: any,\n  b: any,\n  compareStrings: (a: any, b: any) => 0 | 1 | -1 = compareNSB\n): 0 | 1 | -1 {\n  if (a === b) {\n    return 0\n  }\n\n  // null or undefined\n  if (a == null) {\n    return -1\n  }\n  if (b == null) {\n    return 1\n  }\n\n  // detect typeof once\n  const typeofA = typeof a\n  const typeofB = typeof b\n\n  // Numbers\n  if (typeofA === 'number') {\n    return typeofB === 'number' ? compareNSB(a, b) : -1\n  }\n  if (typeofB === 'number') {\n    return 1\n  }\n\n  // Strings\n  if (typeofA === 'string') {\n    return typeofB === 'string' ? compareStrings(a, b) : -1\n  }\n  if (typeofB === 'string') {\n    return 1\n  }\n\n  // Booleans\n  if (typeofA === 'boolean') {\n    return typeofB === 'boolean' ? compareNSB(a, b) : -1\n  }\n  if (typeofB === 'boolean') {\n    return 1\n  }\n\n  // Dates\n  if (a instanceof Date) {\n    return b instanceof Date ? compareNSB(a.getTime(), b.getTime()) : -1\n  }\n  if (b instanceof Date) {\n    return 1\n  }\n\n  // Arrays (first element is most significant and so on)\n  if (Array.isArray(a)) {\n    return Array.isArray(b) ? compareArrays(a, b) : -1\n  }\n  if (Array.isArray(b)) {\n    return 1\n  }\n\n  // Objects\n  const aKeys = Object.keys(a).sort()\n  const bKeys = Object.keys(b).sort()\n\n  for (let i = 0, l = Math.min(aKeys.length, bKeys.length); i < l; i++) {\n    const comparison = compare(a[aKeys[i]], b[bKeys[i]])\n\n    if (comparison !== 0) {\n      return comparison\n    }\n  }\n\n  return compareNSB(aKeys.length, bKeys.length)\n}\n\n// lodash-y get - probably want to use lodash get instead\nconst get = (value: any, path: string[]) => path.reduce((value, key) => value[key], value)\n\n// An in-memory sorting function according to the\n// $sort special query parameter\nexport function sorter($sort: { [key: string]: -1 | 1 }) {\n  const compares = Object.keys($sort).map((key) => {\n    const direction = $sort[key]\n\n    if (!key.includes('.')) {\n      return (a: any, b: any) => direction * compare(a[key], b[key])\n    } else {\n      const path = key.split('.')\n      return (a: any, b: any) => direction * compare(get(a, path), get(b, path))\n    }\n  })\n\n  return function (a: any, b: any) {\n    for (const compare of compares) {\n      const comparison = compare(a, b)\n\n      if (comparison !== 0) {\n        return comparison\n      }\n    }\n\n    return 0\n  }\n}\n"
  },
  {
    "path": "packages/adapter-commons/test/commons.test.ts",
    "content": "import assert from 'assert'\nimport { select } from '../src'\n\ndescribe('@feathersjs/adapter-commons', () => {\n  describe('select', () => {\n    it('select', () => {\n      const selector = select({\n        query: { $select: ['name', 'age'] }\n      })\n\n      return Promise.resolve({\n        name: 'David',\n        age: 3,\n        test: 'me'\n      })\n        .then(selector)\n        .then((result) =>\n          assert.deepStrictEqual(result, {\n            name: 'David',\n            age: 3\n          })\n        )\n    })\n\n    it('select with arrays', () => {\n      const selector = select({\n        query: { $select: ['name', 'age'] }\n      })\n\n      return Promise.resolve([\n        {\n          name: 'David',\n          age: 3,\n          test: 'me'\n        },\n        {\n          name: 'D',\n          age: 4,\n          test: 'you'\n        }\n      ])\n        .then(selector)\n        .then((result) =>\n          assert.deepStrictEqual(result, [\n            {\n              name: 'David',\n              age: 3\n            },\n            {\n              name: 'D',\n              age: 4\n            }\n          ])\n        )\n    })\n\n    it('select with no query', () => {\n      const selector = select({})\n      const data = {\n        name: 'David'\n      }\n\n      return Promise.resolve(data)\n        .then(selector)\n        .then((result) => assert.deepStrictEqual(result, data))\n    })\n\n    it('select with other fields', () => {\n      const selector = select(\n        {\n          query: { $select: ['name'] }\n        },\n        'id'\n      )\n      const data = {\n        id: 'me',\n        name: 'David',\n        age: 10\n      }\n\n      return Promise.resolve(data)\n        .then(selector)\n        .then((result) =>\n          assert.deepStrictEqual(result, {\n            id: 'me',\n            name: 'David'\n          })\n        )\n    })\n  })\n})\n"
  },
  {
    "path": "packages/adapter-commons/test/fixture.ts",
    "content": "import { AdapterBase, AdapterParams, PaginationOptions } from '../src'\nimport { Id, NullableId, Paginated } from '@feathersjs/feathers'\nimport { BadRequest, MethodNotAllowed } from '@feathersjs/errors/lib'\n\nexport type Data = {\n  id: Id\n}\n\nexport class MethodBase extends AdapterBase<Data, Data, Partial<Data>, AdapterParams> {\n  async _find(_params?: AdapterParams & { paginate?: PaginationOptions }): Promise<Paginated<Data>>\n  async _find(_params?: AdapterParams & { paginate: false }): Promise<Data[]>\n  async _find(params?: AdapterParams): Promise<Data | Data[] | Paginated<Data>> {\n    if (params && params.paginate === false) {\n      return []\n    }\n\n    return {\n      total: 0,\n      limit: 10,\n      skip: 0,\n      data: []\n    }\n  }\n\n  async _get(id: Id, _params?: AdapterParams): Promise<Data> {\n    return { id }\n  }\n\n  async _create(data: Data, _params?: AdapterParams): Promise<Data>\n  async _create(data: Data[], _params?: AdapterParams): Promise<Data[]>\n  async _create(data: Data | Data[], _params?: AdapterParams): Promise<Data | Data[]>\n  async _create(data: Data | Data[], _params?: AdapterParams): Promise<Data | Data[]> {\n    if (Array.isArray(data)) {\n      return [\n        {\n          id: 'something'\n        }\n      ]\n    }\n\n    return {\n      id: 'something'\n    }\n  }\n\n  async _update(id: Id, _data: Data, _params?: AdapterParams) {\n    return Promise.resolve({ id: id ?? _data.id })\n  }\n\n  async _patch(id: null, _data: Partial<Data>, _params?: AdapterParams): Promise<Data[]>\n  async _patch(id: Id, _data: Partial<Data>, _params?: AdapterParams): Promise<Data>\n  async _patch(id: NullableId, _data: Partial<Data>, _params?: AdapterParams): Promise<Data | Data[]>\n  async _patch(id: NullableId, _data: Partial<Data>, _params?: AdapterParams): Promise<Data | Data[]> {\n    if (id === null) {\n      return []\n    }\n\n    return { id }\n  }\n\n  async _remove(id: null, _params?: AdapterParams): Promise<Data[]>\n  async _remove(id: Id, _params?: AdapterParams): Promise<Data>\n  async _remove(id: NullableId, _params?: AdapterParams): Promise<Data | Data[]>\n  async _remove(id: NullableId, _params?: AdapterParams) {\n    if (id === null) {\n      return [] as Data[]\n    }\n\n    return { id }\n  }\n}\n\nexport class MethodService extends MethodBase {\n  find(params?: AdapterParams): Promise<Data | Data[] | Paginated<Data>> {\n    return this._find(params)\n  }\n\n  get(id: Id, params?: AdapterParams): Promise<Data> {\n    return this._get(id, params)\n  }\n\n  async create(data: Data[], _params?: AdapterParams): Promise<Data[]>\n  async create(data: Data, _params?: AdapterParams): Promise<Data>\n  async create(data: Data | Data[], params?: AdapterParams): Promise<Data | Data[]> {\n    if (Array.isArray(data) && !this.allowsMulti('create', params)) {\n      throw new MethodNotAllowed('Can not create multiple entries')\n    }\n\n    return this._create(data, params)\n  }\n\n  async update(id: Id, data: Data, params?: AdapterParams) {\n    if (id === null || Array.isArray(data)) {\n      throw new BadRequest(\"You can not replace multiple instances. Did you mean 'patch'?\")\n    }\n\n    return this._update(id, data, params)\n  }\n\n  async patch(id: NullableId, data: Partial<Data>, params?: AdapterParams) {\n    if (id === null && !this.allowsMulti('patch', params)) {\n      throw new MethodNotAllowed('Can not patch multiple entries')\n    }\n\n    return this._patch(id, data, params)\n  }\n\n  async remove(id: NullableId, params?: AdapterParams) {\n    if (id === null && !this.allowsMulti('remove', params)) {\n      throw new MethodNotAllowed('Can not remove multiple entries')\n    }\n\n    return this._remove(id, params)\n  }\n}\n"
  },
  {
    "path": "packages/adapter-commons/test/query.test.ts",
    "content": "import assert from 'assert'\nimport { ObjectId } from 'mongodb'\nimport { filterQuery } from '../src'\n\ndescribe('@feathersjs/adapter-commons/filterQuery', () => {\n  describe('$sort', () => {\n    it('returns $sort when present in query', () => {\n      const originalQuery = { $sort: { name: 1 } }\n      const { filters, query } = filterQuery(originalQuery)\n\n      assert.strictEqual(filters.$sort.name, 1)\n      assert.deepStrictEqual(query, {})\n      assert.deepStrictEqual(\n        originalQuery,\n        {\n          $sort: { name: 1 }\n        },\n        'does not modify original query'\n      )\n    })\n\n    it('returns $sort when present in query as an object', () => {\n      const { filters, query } = filterQuery({\n        $sort: { name: { something: 10 } }\n      })\n\n      assert.strictEqual(filters.$sort.name.something, 10)\n      assert.deepStrictEqual(query, {})\n    })\n\n    it('converts strings in $sort', () => {\n      const { filters, query } = filterQuery({ $sort: { test: '-1' } })\n\n      assert.strictEqual(filters.$sort.test, -1)\n      assert.deepStrictEqual(query, {})\n    })\n\n    it('does not convert $sort arrays', () => {\n      const $sort = [\n        ['test', '-1'],\n        ['a', '1']\n      ]\n      const { filters, query } = filterQuery({ $sort })\n\n      assert.strictEqual(filters.$sort, $sort)\n      assert.deepStrictEqual(query, {})\n    })\n\n    it('throws an error when special parameter is not known', () => {\n      try {\n        const query = { $foo: 1 }\n        filterQuery(query)\n        assert.ok(false, 'Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.name, 'BadRequest')\n        assert.strictEqual(error.message, 'Invalid filter value $foo')\n      }\n    })\n\n    it('returns undefined when not present in query', () => {\n      const query = { foo: 1 }\n      const { filters } = filterQuery(query)\n\n      assert.strictEqual(filters.$sort, undefined)\n    })\n  })\n\n  describe('$limit', () => {\n    let testQuery: any\n\n    beforeEach(() => {\n      testQuery = { $limit: 1 }\n    })\n\n    it('returns $limit when present in query', () => {\n      const { filters, query } = filterQuery(testQuery)\n\n      assert.strictEqual(filters.$limit, 1)\n      assert.deepStrictEqual(query, {})\n    })\n\n    it('returns undefined when not present in query', () => {\n      const query = { foo: 1 }\n      const { filters } = filterQuery(query)\n\n      assert.strictEqual(filters.$limit, undefined)\n    })\n\n    it('removes $limit from query when present', () => {\n      assert.deepStrictEqual(filterQuery(testQuery).query, {})\n    })\n\n    it('parses $limit strings into integers (#4)', () => {\n      const { filters } = filterQuery({ $limit: '2' })\n\n      assert.strictEqual(filters.$limit, 2)\n    })\n\n    it('allows $limit 0', () => {\n      const { filters } = filterQuery({ $limit: 0 }, { paginate: { default: 10 } })\n\n      assert.strictEqual(filters.$limit, 0)\n    })\n\n    describe('pagination', () => {\n      it('limits with default pagination', () => {\n        const { filters } = filterQuery({}, { paginate: { default: 10 } })\n        const { filters: filtersNeg } = filterQuery({ $limit: -20 }, { paginate: { default: 5, max: 10 } })\n\n        assert.strictEqual(filters.$limit, 10)\n        assert.strictEqual(filtersNeg.$limit, 5)\n      })\n\n      it('limits with max pagination', () => {\n        const { filters } = filterQuery({ $limit: 20 }, { paginate: { default: 5, max: 10 } })\n\n        assert.strictEqual(filters.$limit, 10)\n      })\n\n      it('limits with default pagination when not a number', () => {\n        const { filters } = filterQuery({ $limit: 'something' }, { paginate: { default: 5, max: 10 } })\n\n        assert.strictEqual(filters.$limit, 5)\n      })\n\n      it('limits to 0 when no paginate.default and not a number', () => {\n        const { filters } = filterQuery({ $limit: 'something' }, { paginate: { max: 10 } })\n\n        assert.strictEqual(filters.$limit, 0)\n      })\n\n      it('still uses paginate.max when there is no paginate.default (#2104)', () => {\n        const { filters } = filterQuery({ $limit: 100 }, { paginate: { max: 10 } })\n\n        assert.strictEqual(filters.$limit, 10)\n      })\n    })\n  })\n\n  describe('$skip', () => {\n    let testQuery: any\n\n    beforeEach(() => {\n      testQuery = { $skip: 1 }\n    })\n\n    it('returns $skip when present in query', () => {\n      const { filters } = filterQuery(testQuery)\n\n      assert.strictEqual(filters.$skip, 1)\n    })\n\n    it('removes $skip from query when present', () => {\n      assert.deepStrictEqual(filterQuery(testQuery).query, {})\n    })\n\n    it('returns undefined when not present in query', () => {\n      const query = { foo: 1 }\n      const { filters } = filterQuery(query)\n\n      assert.strictEqual(filters.$skip, undefined)\n    })\n\n    it('parses $skip strings into integers (#4)', () => {\n      const { filters } = filterQuery({ $skip: '33' })\n\n      assert.strictEqual(filters.$skip, 33)\n    })\n  })\n\n  describe('$select', () => {\n    let testQuery: any\n\n    beforeEach(() => {\n      testQuery = { $select: 1 }\n    })\n\n    it('returns $select when present in query', () => {\n      const { filters } = filterQuery(testQuery)\n\n      assert.strictEqual(filters.$select, 1)\n    })\n\n    it('removes $select from query when present', () => {\n      assert.deepStrictEqual(filterQuery(testQuery).query, {})\n    })\n\n    it('returns undefined when not present in query', () => {\n      const query = { foo: 1 }\n      const { filters } = filterQuery(query)\n\n      assert.strictEqual(filters.$select, undefined)\n    })\n\n    it('includes Symbols', () => {\n      const TEST = Symbol('testing')\n      const original = {\n        [TEST]: 'message',\n        other: true,\n        sub: { [TEST]: 'othermessage' }\n      }\n\n      const { query } = filterQuery(original)\n\n      assert.deepStrictEqual(query, {\n        [TEST]: 'message',\n        other: true,\n        sub: { [TEST]: 'othermessage' }\n      })\n    })\n\n    it('only converts plain objects', () => {\n      const userId = new ObjectId()\n      const original = {\n        userId\n      }\n\n      const { query } = filterQuery(original)\n\n      assert.deepStrictEqual(query, original)\n    })\n  })\n\n  describe('arrays', () => {\n    it('validates queries in arrays', () => {\n      assert.throws(\n        () => {\n          filterQuery({\n            $or: [{ $exists: false }]\n          })\n        },\n        {\n          name: 'BadRequest',\n          message: 'Invalid query parameter $exists'\n        }\n      )\n    })\n\n    it('allows default operators in $or', () => {\n      const { filters } = filterQuery({\n        $or: [{ value: { $gte: 10 } }]\n      })\n\n      assert.deepStrictEqual(filters, {\n        $or: [{ value: { $gte: 10 } }]\n      })\n    })\n  })\n\n  describe('additional filters', () => {\n    it('throw error when not set as additionals', () => {\n      try {\n        filterQuery({ $select: 1, $known: 1 })\n        assert.ok(false, 'Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.message, 'Invalid filter value $known')\n      }\n    })\n\n    it('returns default and known additional filters (array)', () => {\n      const query = { $select: ['a', 'b'], $known: 1, $unknown: 1 }\n      const { filters } = filterQuery(query, {\n        filters: {\n          $known: true,\n          $unknown: true\n        }\n      })\n\n      assert.strictEqual(filters.$unknown, 1)\n      assert.strictEqual(filters.$known, 1)\n      assert.deepStrictEqual(filters.$select, ['a', 'b'])\n    })\n\n    it('returns default and known additional filters (object)', () => {\n      const { filters } = filterQuery(\n        {\n          $known: 1,\n          $select: 1\n        },\n        { filters: { $known: (value: any) => value.toString() } }\n      )\n\n      assert.strictEqual(filters.$unknown, undefined)\n      assert.strictEqual(filters.$known, '1')\n      assert.strictEqual(filters.$select, 1)\n    })\n  })\n\n  describe('additional operators', () => {\n    it('returns query with default and known additional operators', () => {\n      const { query } = filterQuery(\n        {\n          prop: { $ne: 1, $known: 1 }\n        },\n        { operators: ['$known'] }\n      )\n\n      assert.deepStrictEqual(query, { prop: { $ne: 1, $known: 1 } })\n    })\n\n    it('throws an error with unknown query operator', () => {\n      assert.throws(\n        () =>\n          filterQuery({\n            prop: { $unknown: 'something' }\n          }),\n        {\n          message: 'Invalid query parameter $unknown'\n        }\n      )\n    })\n  })\n})\n"
  },
  {
    "path": "packages/adapter-commons/test/service.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/ban-ts-comment */\nimport assert from 'assert'\nimport { VALIDATED } from '../src'\nimport { MethodService } from './fixture'\n\nconst METHODS: ['find', 'get', 'create', 'update', 'patch', 'remove'] = [\n  'find',\n  'get',\n  'create',\n  'update',\n  'patch',\n  'remove'\n]\n\ndescribe('@feathersjs/adapter-commons/service', () => {\n  describe('works when methods exist', () => {\n    METHODS.forEach((method) => {\n      it(`${method}`, () => {\n        const service = new MethodService({})\n        const args: any[] = []\n\n        if (method !== 'find') {\n          args.push('test')\n        }\n\n        if (method === 'update' || method === 'patch') {\n          args.push({})\n        }\n\n        // @ts-ignore\n        return service[method](...args)\n      })\n    })\n\n    it('does not allow multi patch', async () => {\n      const service = new MethodService({})\n\n      await assert.rejects(() => service.patch(null, {}), {\n        name: 'MethodNotAllowed',\n        message: 'Can not patch multiple entries'\n      })\n    })\n\n    it('does not allow multi remove', async () => {\n      const service = new MethodService({})\n\n      await assert.rejects(() => service.remove(null, {}), {\n        name: 'MethodNotAllowed',\n        message: 'Can not remove multiple entries'\n      })\n    })\n\n    it('does not allow multi create', async () => {\n      const service = new MethodService({})\n\n      await assert.rejects(() => service.create([], {}), {\n        name: 'MethodNotAllowed',\n        message: 'Can not create multiple entries'\n      })\n    })\n\n    it('multi can be set to true', async () => {\n      const service = new MethodService({})\n\n      service.options.multi = true\n\n      await service.create([])\n    })\n  })\n\n  it('sanitizeQuery', async () => {\n    const service = new MethodService({\n      filters: {\n        $something: true\n      },\n      operators: ['$test']\n    })\n\n    assert.deepStrictEqual(\n      await service.sanitizeQuery({\n        query: { $limit: '10', test: 'me' } as any\n      }),\n      { $limit: 10, test: 'me' }\n    )\n\n    assert.deepStrictEqual(\n      await service.sanitizeQuery({\n        adapter: {\n          paginate: { max: 2 }\n        },\n        query: { $limit: '10', test: 'me' } as any\n      }),\n      { $limit: 2, test: 'me' }\n    )\n\n    await assert.rejects(\n      () =>\n        service.sanitizeQuery({\n          query: { name: { $bla: 'me' } }\n        }),\n      {\n        message: 'Invalid query parameter $bla'\n      }\n    )\n\n    assert.deepStrictEqual(\n      await service.sanitizeQuery({\n        adapter: {\n          operators: ['$bla']\n        },\n        query: { name: { $bla: 'Dave' } }\n      }),\n      { name: { $bla: 'Dave' } }\n    )\n\n    const validatedQuery = { name: { $bla: 'me' } }\n\n    Object.defineProperty(validatedQuery, VALIDATED, { value: true })\n\n    assert.deepStrictEqual(\n      await service.sanitizeQuery({\n        query: validatedQuery\n      }),\n      validatedQuery,\n      'validated queries are not sanitized'\n    )\n  })\n\n  it('getOptions', () => {\n    const service = new MethodService({\n      multi: true,\n      paginate: {\n        default: 1,\n        max: 10\n      }\n    })\n    const opts = service.getOptions({\n      adapter: {\n        multi: ['create'],\n        paginate: {\n          default: 10,\n          max: 100\n        }\n      }\n    })\n\n    assert.deepStrictEqual(opts, {\n      id: 'id',\n      events: [],\n      paginate: { default: 10, max: 100 },\n      multi: ['create'],\n      filters: {},\n      operators: []\n    })\n\n    const notPaginated = service.getOptions({\n      paginate: false\n    })\n\n    assert.deepStrictEqual(notPaginated, {\n      id: 'id',\n      events: [],\n      paginate: false,\n      multi: true,\n      filters: {},\n      operators: []\n    })\n  })\n\n  it('allowsMulti', () => {\n    context('with true', () => {\n      const service = new MethodService({ multi: true })\n\n      it('does return true for multiple methodes', () => {\n        assert.equal(service.allowsMulti('patch'), true)\n      })\n\n      it('does return false for always non-multiple methodes', () => {\n        assert.equal(service.allowsMulti('update'), false)\n      })\n\n      it('does return true for unknown methods', () => {\n        assert.equal(service.allowsMulti('other'), true)\n      })\n    })\n\n    context('with false', () => {\n      const service = new MethodService({ multi: false })\n\n      it('does return false for multiple methodes', () => {\n        assert.equal(service.allowsMulti('remove'), false)\n      })\n\n      it('does return true for always multiple methodes', () => {\n        assert.equal(service.allowsMulti('find'), true)\n      })\n\n      it('does return false for unknown methods', () => {\n        assert.equal(service.allowsMulti('other'), false)\n      })\n    })\n\n    context('with array', () => {\n      const service = new MethodService({ multi: ['create', 'get', 'other'] })\n\n      it('does return true for specified multiple methodes', () => {\n        assert.equal(service.allowsMulti('create'), true)\n      })\n\n      it('does return false for non-specified multiple methodes', () => {\n        assert.equal(service.allowsMulti('patch'), false)\n      })\n\n      it('does return false for specified always multiple methodes', () => {\n        assert.equal(service.allowsMulti('get'), false)\n      })\n\n      it('does return true for specified unknown methodes', () => {\n        assert.equal(service.allowsMulti('other'), true)\n      })\n\n      it('does return false for non-specified unknown methodes', () => {\n        assert.equal(service.allowsMulti('another'), false)\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "packages/adapter-commons/test/sort.test.ts",
    "content": "import assert from 'assert'\nimport { sorter } from '../src'\n\ndescribe('@feathersjs/adapter-commons', () => {\n  describe('sorter', () => {\n    it('simple sorter', () => {\n      const array = [\n        {\n          name: 'David'\n        },\n        {\n          name: 'Eric'\n        }\n      ]\n\n      const sort = sorter({\n        name: -1\n      })\n\n      assert.deepStrictEqual(array.sort(sort), [\n        {\n          name: 'Eric'\n        },\n        {\n          name: 'David'\n        }\n      ])\n    })\n\n    it('simple sorter with arrays', () => {\n      const array = [\n        {\n          names: ['a', 'b']\n        },\n        {\n          names: ['c', 'd']\n        }\n      ]\n\n      const sort = sorter({\n        names: -1\n      })\n\n      assert.deepStrictEqual(array.sort(sort), [\n        {\n          names: ['c', 'd']\n        },\n        {\n          names: ['a', 'b']\n        }\n      ])\n    })\n\n    it('simple sorter with objects', () => {\n      const array = [\n        {\n          names: {\n            first: 'Dave',\n            last: 'L'\n          }\n        },\n        {\n          names: {\n            first: 'A',\n            last: 'B'\n          }\n        }\n      ]\n\n      const sort = sorter({\n        names: 1\n      })\n\n      assert.deepStrictEqual(array.sort(sort), [\n        {\n          names: {\n            first: 'A',\n            last: 'B'\n          }\n        },\n        {\n          names: {\n            first: 'Dave',\n            last: 'L'\n          }\n        }\n      ])\n    })\n\n    it('two property sorter', () => {\n      const array = [\n        {\n          name: 'David',\n          counter: 0\n        },\n        {\n          name: 'Eric',\n          counter: 1\n        },\n        {\n          name: 'David',\n          counter: 1\n        },\n        {\n          name: 'Eric',\n          counter: 0\n        }\n      ]\n\n      const sort = sorter({\n        name: -1,\n        counter: 1\n      })\n\n      assert.deepStrictEqual(array.sort(sort), [\n        { name: 'Eric', counter: 0 },\n        { name: 'Eric', counter: 1 },\n        { name: 'David', counter: 0 },\n        { name: 'David', counter: 1 }\n      ])\n    })\n\n    it('two property sorter with names', () => {\n      const array = [\n        {\n          name: 'David',\n          counter: 0\n        },\n        {\n          name: 'Eric',\n          counter: 1\n        },\n        {\n          name: 'Andrew',\n          counter: 1\n        },\n        {\n          name: 'David',\n          counter: 1\n        },\n        {\n          name: 'Andrew',\n          counter: 0\n        },\n        {\n          name: 'Eric',\n          counter: 0\n        }\n      ]\n\n      const sort = sorter({\n        name: -1,\n        counter: 1\n      })\n\n      assert.deepStrictEqual(array.sort(sort), [\n        { name: 'Eric', counter: 0 },\n        { name: 'Eric', counter: 1 },\n        { name: 'David', counter: 0 },\n        { name: 'David', counter: 1 },\n        { name: 'Andrew', counter: 0 },\n        { name: 'Andrew', counter: 1 }\n      ])\n    })\n\n    it('three property sorter with names', () => {\n      const array = [\n        {\n          name: 'David',\n          counter: 0,\n          age: 2\n        },\n        {\n          name: 'Eric',\n          counter: 1,\n          age: 2\n        },\n        {\n          name: 'David',\n          counter: 1,\n          age: 1\n        },\n        {\n          name: 'Eric',\n          counter: 0,\n          age: 1\n        },\n        {\n          name: 'Andrew',\n          counter: 0,\n          age: 2\n        },\n        {\n          name: 'Andrew',\n          counter: 0,\n          age: 1\n        }\n      ]\n\n      const sort = sorter({\n        name: -1,\n        counter: 1,\n        age: -1\n      })\n\n      assert.deepStrictEqual(array.sort(sort), [\n        { name: 'Eric', counter: 0, age: 1 },\n        { name: 'Eric', counter: 1, age: 2 },\n        { name: 'David', counter: 0, age: 2 },\n        { name: 'David', counter: 1, age: 1 },\n        { name: 'Andrew', counter: 0, age: 2 },\n        { name: 'Andrew', counter: 0, age: 1 }\n      ])\n    })\n  })\n\n  describe('sorter mongoDB-like sorting on embedded objects', () => {\n    let data: any[] = []\n\n    beforeEach(() => {\n      data = [\n        { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 },\n        {\n          _id: 2,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 50\n        },\n        {\n          _id: 3,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 15\n        },\n        { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },\n        { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },\n        { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 }\n      ]\n    })\n\n    it('straight test', () => {\n      const sort = sorter({\n        amount: -1\n      })\n\n      assert.deepStrictEqual(data.sort(sort), [\n        {\n          _id: 2,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 50\n        },\n        { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },\n        { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },\n        {\n          _id: 3,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 15\n        },\n        { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 },\n        { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 }\n      ])\n    })\n\n    it('embedded sort 1', () => {\n      const sort = sorter({\n        'item.category': 1,\n        'item.type': 1\n      })\n\n      assert.deepStrictEqual(data.sort(sort), [\n        { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 },\n        { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },\n        { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 },\n        { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },\n        {\n          _id: 2,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 50\n        },\n        {\n          _id: 3,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 15\n        }\n      ])\n    })\n\n    it('embedded sort 2', () => {\n      const sort = sorter({\n        'item.category': 1,\n        'item.type': 1,\n        amount: 1\n      })\n\n      assert.deepStrictEqual(data.sort(sort), [\n        { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 },\n        { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },\n        { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 },\n        { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },\n        {\n          _id: 3,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 15\n        },\n        {\n          _id: 2,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 50\n        }\n      ])\n    })\n\n    it('embedded sort 3', () => {\n      const sort = sorter({\n        'item.category': 1,\n        'item.type': 1,\n        amount: -1\n      })\n\n      assert.deepStrictEqual(data.sort(sort), [\n        { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 },\n        { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },\n        { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 },\n        { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },\n        {\n          _id: 2,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 50\n        },\n        {\n          _id: 3,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 15\n        }\n      ])\n    })\n\n    it('embedded sort 4', () => {\n      const sort = sorter({\n        amount: -1,\n        'item.category': 1\n      })\n\n      assert.deepStrictEqual(data.sort(sort), [\n        {\n          _id: 2,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 50\n        },\n        { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },\n        { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },\n        {\n          _id: 3,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 15\n        },\n        { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 },\n        { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 }\n      ])\n    })\n\n    it('embedded sort 5', () => {\n      const sort = sorter({\n        'item.category': 1,\n        amount: 1\n      })\n\n      assert.deepStrictEqual(data.sort(sort), [\n        { _id: 6, item: { category: 'brownies', type: 'blondie' }, amount: 10 },\n        { _id: 1, item: { category: 'cake', type: 'chiffon' }, amount: 10 },\n        { _id: 5, item: { category: 'cake', type: 'carrot' }, amount: 20 },\n        { _id: 4, item: { category: 'cake', type: 'lemon' }, amount: 30 },\n        {\n          _id: 3,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 15\n        },\n        {\n          _id: 2,\n          item: { category: 'cookies', type: 'chocolate chip' },\n          amount: 50\n        }\n      ])\n    })\n  })\n})\n"
  },
  {
    "path": "packages/adapter-commons/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/adapter-tests/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- @feathersjs/memory update with query ([#3617](https://github.com/feathersjs/feathers/issues/3617)) ([4c6caa2](https://github.com/feathersjs/feathers/commit/4c6caa27e9af1312718d0c233a0c35f7739ac553))\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n### Bug Fixes\n\n- **typebox:** Revert to TypeBox 0.25 ([#3183](https://github.com/feathersjs/feathers/issues/3183)) ([cacedf5](https://github.com/feathersjs/feathers/commit/cacedf59e3d2df836777f0cd06ab1b2484ed87c5))\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- **adapter-commons:** Support non-default import to ease use with ESM projects ([d06f2cf](https://github.com/feathersjs/feathers/commit/d06f2cfcadda7dc23f0e2bec44f64e6be8500d02))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n### Bug Fixes\n\n- **memory/mongodb:** $select as only property & force 'id' in '$select' ([#3081](https://github.com/feathersjs/feathers/issues/3081)) ([fbe3cf5](https://github.com/feathersjs/feathers/commit/fbe3cf5199e102b5aeda2ae33828d5034df3d105))\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- **databases:** Improve documentation for adapters and allow dynamic Knex adapter options ([#3019](https://github.com/feathersjs/feathers/issues/3019)) ([66c4b5e](https://github.com/feathersjs/feathers/commit/66c4b5e72000dd03acb57fca1cad4737c85c9c9e))\n\n### Features\n\n- **database:** Add and to the query syntax ([#3021](https://github.com/feathersjs/feathers/issues/3021)) ([00cb0d9](https://github.com/feathersjs/feathers/commit/00cb0d9c302ae951ae007d3d6ceba33e254edd9c))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Features\n\n- **adapter:** Add patch data type to adapters and refactor AdapterBase usage ([#2906](https://github.com/feathersjs/feathers/issues/2906)) ([9ddc2e6](https://github.com/feathersjs/feathers/commit/9ddc2e6b028f026f939d6af68125847e5c6734b4))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Bug Fixes\n\n- **adapter-commons:** Clarify adapter query filtering ([#2607](https://github.com/feathersjs/feathers/issues/2607)) ([2dac771](https://github.com/feathersjs/feathers/commit/2dac771b0a3298d6dd25994d05186701b0617718))\n- **adapter-tests:** Ensure multi tests can run standalone ([#2608](https://github.com/feathersjs/feathers/issues/2608)) ([d7243f2](https://github.com/feathersjs/feathers/commit/d7243f20e84d9dde428ad8dfc7f48388ca569e6e))\n\n### BREAKING CHANGES\n\n- **adapter-commons:** Changes the common adapter base class to use `sanitizeQuery` and `sanitizeData`\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n### Bug Fixes\n\n- **adapter-tests:** Add tests for pagination in multi updates ([#2472](https://github.com/feathersjs/feathers/issues/2472)) ([98a811a](https://github.com/feathersjs/feathers/commit/98a811ac605575ff812a08d0504729a5efe7a69c))\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- Update database adapter common repository urls ([#2380](https://github.com/feathersjs/feathers/issues/2380)) ([3f4db68](https://github.com/feathersjs/feathers/commit/3f4db68d6700c7d9023ecd17d0d39893f75a19fd))\n\n### Features\n\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n### Bug Fixes\n\n- **adapter-tests:** Add test that verified paginated total ([#2273](https://github.com/feathersjs/feathers/issues/2273)) ([879bd6b](https://github.com/feathersjs/feathers/commit/879bd6b24f42e04eeeeba110ddddda3e1e1dea34))\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Features\n\n- **core:** Remove Uberproto ([#2178](https://github.com/feathersjs/feathers/issues/2178)) ([ddf8821](https://github.com/feathersjs/feathers/commit/ddf8821f53317e6a378657f7d66acb03a037ee47))\n\n### BREAKING CHANGES\n\n- **core:** Services no longer extend Uberproto objects and\n  `service.mixin()` is no longer available.\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n### Features\n\n- **memory:** Move feathers-memory into @feathersjs/memory ([#2153](https://github.com/feathersjs/feathers/issues/2153)) ([dd61fe3](https://github.com/feathersjs/feathers/commit/dd61fe371fb0502f78b8ccbe1f45a030e31ecff6))\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [4.5.4](https://github.com/feathersjs/feathers/compare/v4.5.3...v4.5.4) (2020-09-27)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## 4.5.3 (2020-09-24)\n\n### Bug Fixes\n\n- **adapter-tests:** Update multi patch + query tests ([#5](https://github.com/feathersjs/databases/issues/5)) ([84f1fe4](https://github.com/feathersjs/databases/commit/84f1fe4f13dc3a26891e43b965f75d08243f6c6f))\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n### Bug Fixes\n\n- Fix feathers-memory dependency that did not get updated ([9422b13](https://github.com/feathersjs/feathers/commit/9422b13))\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n**Note:** Version bump only for package @feathersjs/adapter-tests\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Add test to make sure different id in adapter query works ([#1165](https://github.com/feathersjs/feathers/issues/1165)) ([0ba4580](https://github.com/feathersjs/feathers/commit/0ba4580))\n- Update adapter tests to not rely on error instance ([#1202](https://github.com/feathersjs/feathers/issues/1202)) ([6885e0e](https://github.com/feathersjs/feathers/commit/6885e0e))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n\n### chore\n\n- **package:** Move adapter tests into their own module ([#1164](https://github.com/feathersjs/feathers/issues/1164)) ([dcc1e6b](https://github.com/feathersjs/feathers/commit/dcc1e6b))\n\n### Features\n\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Authentication v3 core server implementation ([#1205](https://github.com/feathersjs/feathers/issues/1205)) ([1bd7591](https://github.com/feathersjs/feathers/commit/1bd7591))\n\n### BREAKING CHANGES\n\n- **package:** Removes adapter tests from @feathersjs/adapter-commons\n\n## [1.0.1](https://github.com/feathersjs/feathers/compare/@feathersjs/adapter-tests@1.0.0...@feathersjs/adapter-tests@1.0.1) (2019-01-10)\n\n### Bug Fixes\n\n- Add test to make sure different id in adapter query works ([#1165](https://github.com/feathersjs/feathers/issues/1165)) ([0ba4580](https://github.com/feathersjs/feathers/commit/0ba4580))\n\n# 1.0.0 (2019-01-10)\n\n### chore\n\n- **package:** Move adapter tests into their own module ([#1164](https://github.com/feathersjs/feathers/issues/1164)) ([dcc1e6b](https://github.com/feathersjs/feathers/commit/dcc1e6b))\n\n### BREAKING CHANGES\n\n- **package:** Removes adapter tests from @feathersjs/adapter-commons\n"
  },
  {
    "path": "packages/adapter-tests/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/adapter-tests/README.md",
    "content": "# Feathers Adapter Tests\n\n[![CI](https://github.com/feathersjs/feathers/workflows/Node.js%20CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3A%22Node.js+CI%22)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/adapter-commons.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/adapter-commons)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Feathers shared database adapter test suite\n\n## About\n\nThis is a repository that contains the test suite for the common database adapter syntax. See the [API documentation](https://docs.feathersjs.com/api/databases/common.html) for more information.\n\n## Authors\n\n[Feathers contributors](https://github.com/feathersjs/adapter-tests/graphs/contributors)\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/adapter-tests/package.json",
    "content": "{\n  \"name\": \"@feathersjs/adapter-tests\",\n  \"version\": \"5.0.42\",\n  \"description\": \"Feathers shared database adapter test suite\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"keywords\": [\n    \"feathers\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"opencollective\",\n    \"url\": \"https://opencollective.com/feathers\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/adapter-tests\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributor\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"devDependencies\": {\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/adapter-tests/src/basic.ts",
    "content": "import assert from 'assert'\nimport { AdapterBasicTest } from './declarations'\n\nexport default (test: AdapterBasicTest, app: any, _errors: any, serviceName: string, idProp: string) => {\n  describe('Basic Functionality', () => {\n    let service: any\n\n    beforeEach(() => {\n      service = app.service(serviceName)\n    })\n\n    it('.id', () => {\n      assert.strictEqual(service.id, idProp, 'id property is set to expected name')\n    })\n\n    test('.options', () => {\n      assert.ok(service.options, 'Options are available in service.options')\n    })\n\n    test('.events', () => {\n      assert.ok(service.events.includes('testing'), 'service.events is set and includes \"testing\"')\n    })\n\n    describe('Raw Methods', () => {\n      test('._get', () => {\n        assert.strictEqual(typeof service._get, 'function')\n      })\n\n      test('._find', () => {\n        assert.strictEqual(typeof service._find, 'function')\n      })\n\n      test('._create', () => {\n        assert.strictEqual(typeof service._create, 'function')\n      })\n\n      test('._update', () => {\n        assert.strictEqual(typeof service._update, 'function')\n      })\n\n      test('._patch', () => {\n        assert.strictEqual(typeof service._patch, 'function')\n      })\n\n      test('._remove', () => {\n        assert.strictEqual(typeof service._remove, 'function')\n      })\n    })\n  })\n}\n"
  },
  {
    "path": "packages/adapter-tests/src/declarations.ts",
    "content": "export type AdapterTest = (name: AdapterTestName, runner: any) => void\n\nexport type AdapterBasicTest = (name: AdapterBasicTestName, runner: any) => void\nexport type AdapterMethodsTest = (name: AdapterMethodsTestName, runner: any) => void\nexport type AdapterSyntaxTest = (name: AdapterSyntaxTestName, runner: any) => void\n\nexport type AdapterTestName = AdapterBasicTestName | AdapterMethodsTestName | AdapterSyntaxTestName\n\nexport type AdapterBasicTestName =\n  | '.id'\n  | '.options'\n  | '.events'\n  | '._get'\n  | '._find'\n  | '._create'\n  | '._update'\n  | '._patch'\n  | '._remove'\n  | '.$get'\n  | '.$find'\n  | '.$create'\n  | '.$update'\n  | '.$patch'\n  | '.$remove'\n\nexport type AdapterMethodsTestName =\n  | '.get'\n  | '.get + $select'\n  | '.get + id + query'\n  | '.get + NotFound'\n  | '.get + NotFound (integer)'\n  | '.get + id + query id'\n  | '.find'\n  | '.remove'\n  | '.remove + $select'\n  | '.remove + id + query'\n  | '.remove + NotFound'\n  | '.remove + NotFound (integer)'\n  | '.remove + multi'\n  | '.remove + multi no pagination'\n  | '.remove + id + query id'\n  | '.update'\n  | '.update + $select'\n  | '.update + id + query'\n  | '.update + NotFound'\n  | '.update + NotFound (integer)'\n  | '.update + query + NotFound'\n  | '.update + id + query id'\n  | '.patch'\n  | '.patch + $select'\n  | '.patch + id + query'\n  | '.patch multiple'\n  | '.patch multiple no pagination'\n  | '.patch multi query same'\n  | '.patch multi query changed'\n  | '.patch + NotFound'\n  | '.patch + NotFound (integer)'\n  | '.patch + query + NotFound'\n  | '.patch + id + query id'\n  | '.create'\n  | '.create + $select'\n  | '.create multi'\n  | '.create ignores query'\n  | 'internal .find'\n  | 'internal .get'\n  | 'internal .create'\n  | 'internal .update'\n  | 'internal .patch'\n  | 'internal .remove'\n\nexport type AdapterSyntaxTestName =\n  | '.find + equal'\n  | '.find + equal multiple'\n  | '.find + $sort'\n  | '.find + $sort + string'\n  | '.find + $limit'\n  | '.find + $limit 0'\n  | '.find + $skip'\n  | '.find + $select'\n  | '.find + $or'\n  | '.find + $in'\n  | '.find + $nin'\n  | '.find + $lt'\n  | '.find + $lte'\n  | '.find + $gt'\n  | '.find + $gte'\n  | '.find + $ne'\n  | '.find + $gt + $lt + $sort'\n  | '.find + $or nested + $sort'\n  | '.find + $and'\n  | '.find + $and + $or'\n  | 'params.adapter + paginate'\n  | 'params.adapter + multi'\n  | '.find + paginate'\n  | '.find + paginate + query'\n  | '.find + paginate + $limit + $skip'\n  | '.find + paginate + $limit 0'\n  | '.find + paginate + params'\n"
  },
  {
    "path": "packages/adapter-tests/src/index.ts",
    "content": "/* eslint-disable no-console */\nimport basicTests from './basic'\nimport { AdapterTestName } from './declarations'\nimport methodTests from './methods'\nimport syntaxTests from './syntax'\n\nexport const adapterTests = (testNames: AdapterTestName[]) => {\n  return (app: any, errors: any, serviceName: any, idProp = 'id') => {\n    if (!serviceName) {\n      throw new Error('You must pass a service name')\n    }\n\n    const skippedTests: AdapterTestName[] = []\n    const allTests: AdapterTestName[] = []\n\n    const test = (name: AdapterTestName, runner: any) => {\n      const skip = !testNames.includes(name)\n      const its = skip ? it.skip : it\n\n      if (skip) {\n        skippedTests.push(name)\n      }\n\n      allTests.push(name)\n\n      its(name, runner)\n    }\n\n    describe(`Adapter tests for '${serviceName}' service with '${idProp}' id property`, () => {\n      after(() => {\n        testNames.forEach((name) => {\n          if (!allTests.includes(name)) {\n            console.error(`WARNING: '${name}' test is not part of the test suite`)\n          }\n        })\n        if (skippedTests.length) {\n          console.log(\n            `\\nSkipped the following ${skippedTests.length} Feathers adapter test(s) out of ${allTests.length} total:`\n          )\n          console.log(JSON.stringify(skippedTests, null, '  '))\n        }\n      })\n\n      basicTests(test, app, errors, serviceName, idProp)\n      methodTests(test, app, errors, serviceName, idProp)\n      syntaxTests(test, app, errors, serviceName, idProp)\n    })\n  }\n}\n\nexport * from './declarations'\n\nexport default adapterTests\n\nif (typeof module !== 'undefined') {\n  module.exports = Object.assign(adapterTests, module.exports)\n}\n"
  },
  {
    "path": "packages/adapter-tests/src/methods.ts",
    "content": "import assert from 'assert'\nimport { AdapterMethodsTest } from './declarations'\n\nexport default (test: AdapterMethodsTest, app: any, _errors: any, serviceName: string, idProp: string) => {\n  describe(' Methods', () => {\n    let doug: any\n    let service: any\n\n    beforeEach(async () => {\n      service = app.service(serviceName)\n      doug = await app.service(serviceName).create({\n        name: 'Doug',\n        age: 32\n      })\n    })\n\n    afterEach(async () => {\n      try {\n        await app.service(serviceName).remove(doug[idProp])\n      } catch (error: any) {}\n    })\n\n    describe('get', () => {\n      test('.get', async () => {\n        const data = await service.get(doug[idProp])\n\n        assert.strictEqual(data[idProp].toString(), doug[idProp].toString(), `${idProp} id matches`)\n        assert.strictEqual(data.name, 'Doug', 'data.name matches')\n        assert.strictEqual(data.age, 32, 'data.age matches')\n      })\n\n      test('.get + $select', async () => {\n        const data = await service.get(doug[idProp], {\n          query: { $select: ['name'] }\n        })\n\n        assert.strictEqual(data[idProp].toString(), doug[idProp].toString(), `${idProp} id property matches`)\n        assert.strictEqual(data.name, 'Doug', 'data.name matches')\n        assert.ok(!data.age, 'data.age is falsy')\n      })\n\n      test('.get + id + query', async () => {\n        try {\n          await service.get(doug[idProp], {\n            query: { name: 'Tester' }\n          })\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Got a NotFound Feathers error')\n        }\n      })\n\n      test('.get + NotFound', async () => {\n        try {\n          await service.get('568225fbfe21222432e836ff')\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Error is a NotFound Feathers error')\n        }\n      })\n\n      test('.get + NotFound (integer)', async () => {\n        try {\n          await service.get(123456789)\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Error is a NotFound Feathers error')\n        }\n      })\n\n      test('.get + id + query id', async () => {\n        const alice = await service.create({\n          name: 'Alice',\n          age: 12\n        })\n\n        try {\n          await service.get(doug[idProp], {\n            query: { [idProp]: alice[idProp] }\n          })\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Got a NotFound Feathers error')\n        }\n\n        await service.remove(alice[idProp])\n      })\n    })\n\n    describe('find', () => {\n      test('.find', async () => {\n        const data = await service.find()\n\n        assert.ok(Array.isArray(data), 'Data is an array')\n        assert.strictEqual(data.length, 1, 'Got one entry')\n      })\n    })\n\n    describe('remove', () => {\n      test('.remove', async () => {\n        const data = await service.remove(doug[idProp])\n\n        assert.strictEqual(data.name, 'Doug', 'data.name matches')\n      })\n\n      test('.remove + $select', async () => {\n        const data = await service.remove(doug[idProp], {\n          query: { $select: ['name'] }\n        })\n\n        assert.strictEqual(data[idProp].toString(), doug[idProp].toString(), `${idProp} id property matches`)\n        assert.strictEqual(data.name, 'Doug', 'data.name matches')\n        assert.ok(!data.age, 'data.age is falsy')\n      })\n\n      test('.remove + id + query', async () => {\n        try {\n          await service.remove(doug[idProp], {\n            query: { name: 'Tester' }\n          })\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Got a NotFound Feathers error')\n        }\n      })\n\n      test('.remove + NotFound', async () => {\n        try {\n          await service.remove('568225fbfe21222432e836ff')\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Error is a NotFound Feathers error')\n        }\n      })\n\n      test('.remove + NotFound (integer)', async () => {\n        try {\n          await service.remove(123456789)\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Error is a NotFound Feathers error')\n        }\n      })\n\n      test('.remove + multi', async () => {\n        try {\n          await service.remove(null)\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(\n            error.name,\n            'MethodNotAllowed',\n            'Removing multiple without option set throws MethodNotAllowed'\n          )\n        }\n\n        service.options.multi = ['remove']\n\n        await service.create({ name: 'Dave', age: 29, created: true })\n        await service.create({\n          name: 'David',\n          age: 3,\n          created: true\n        })\n\n        const data = await service.remove(null, {\n          query: { created: true }\n        })\n\n        assert.strictEqual(data.length, 2)\n\n        const names = data.map((person: any) => person.name)\n\n        assert.ok(names.includes('Dave'), 'Dave removed')\n        assert.ok(names.includes('David'), 'David removed')\n      })\n\n      test('.remove + multi no pagination', async () => {\n        try {\n          await service.remove(doug[idProp])\n        } catch (error: any) {}\n\n        const count = 14\n        const defaultPaginate = 10\n\n        assert.ok(count > defaultPaginate, 'count is bigger than default pagination')\n\n        const multiBefore = service.options.multi\n        const paginateBefore = service.options.paginate\n\n        try {\n          service.options.multi = true\n          service.options.paginate = {\n            default: defaultPaginate,\n            max: 100\n          }\n\n          const emptyItems = await service.find({ paginate: false })\n          assert.strictEqual(emptyItems.length, 0, 'no items before')\n\n          const createdItems = await service.create(\n            Array.from(Array(count)).map((_, i) => ({\n              name: `name-${i}`,\n              age: 3,\n              created: true\n            }))\n          )\n          assert.strictEqual(createdItems.length, count, `created ${count} items`)\n\n          const foundItems = await service.find({ paginate: false })\n          assert.strictEqual(foundItems.length, count, `created ${count} items`)\n\n          const foundPaginatedItems = await service.find({})\n          assert.strictEqual(foundPaginatedItems.data.length, defaultPaginate, 'found paginated items')\n\n          const allItems = await service.remove(null, {\n            query: { created: true }\n          })\n\n          assert.strictEqual(allItems.length, count, `removed all ${count} items`)\n        } finally {\n          await service.remove(null, {\n            query: { created: true },\n            paginate: false\n          })\n\n          service.options.multi = multiBefore\n          service.options.paginate = paginateBefore\n        }\n      })\n\n      test('.remove + id + query id', async () => {\n        const alice = await service.create({\n          name: 'Alice',\n          age: 12\n        })\n\n        try {\n          await service.remove(doug[idProp], {\n            query: { [idProp]: alice[idProp] }\n          })\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Got a NotFound Feathers error')\n        }\n\n        await service.remove(alice[idProp])\n      })\n    })\n\n    describe('update', () => {\n      test('.update', async () => {\n        const originalData = { [idProp]: doug[idProp], name: 'Dougler' }\n        const originalCopy = Object.assign({}, originalData)\n\n        const data = await service.update(doug[idProp], originalData)\n\n        assert.deepStrictEqual(originalData, originalCopy, 'data was not modified')\n        assert.strictEqual(data[idProp].toString(), doug[idProp].toString(), `${idProp} id matches`)\n        assert.strictEqual(data.name, 'Dougler', 'data.name matches')\n        assert.ok(!data.age, 'data.age is falsy')\n      })\n\n      test('.update + $select', async () => {\n        const originalData = {\n          [idProp]: doug[idProp],\n          name: 'Dougler',\n          age: 10\n        }\n\n        const data = await service.update(doug[idProp], originalData, {\n          query: { $select: ['name'] }\n        })\n\n        assert.strictEqual(data[idProp].toString(), doug[idProp].toString(), `${idProp} id property matches`)\n        assert.strictEqual(data.name, 'Dougler', 'data.name matches')\n        assert.ok(!data.age, 'data.age is falsy')\n      })\n\n      test('.update + id + query', async () => {\n        try {\n          await service.update(\n            doug[idProp],\n            {\n              name: 'Dougler'\n            },\n            {\n              query: { name: 'Tester' }\n            }\n          )\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Got a NotFound Feathers error')\n        }\n\n        const updatedDoug = await service.get(doug[idProp])\n        assert.strictEqual(updatedDoug.name, 'Doug', 'Doug was not updated')\n      })\n\n      test('.update + NotFound', async () => {\n        try {\n          await service.update('568225fbfe21222432e836ff', {\n            name: 'NotFound'\n          })\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Error is a NotFound Feathers error')\n        }\n      })\n\n      test('.update + NotFound (integer)', async () => {\n        try {\n          await service.update(123456789, {\n            name: 'NotFound'\n          })\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Error is a NotFound Feathers error')\n        }\n      })\n\n      test('.update + query + NotFound', async () => {\n        const dave = await service.create({ name: 'Dave' })\n        try {\n          await service.update(dave[idProp], { name: 'UpdatedDave' }, { query: { name: 'NotDave' } })\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Error is a NotFound Feathers error')\n        }\n        await service.remove(dave[idProp])\n      })\n\n      test('.update + id + query id', async () => {\n        const alice = await service.create({\n          name: 'Alice',\n          age: 12\n        })\n\n        try {\n          await service.update(\n            doug[idProp],\n            {\n              name: 'Dougler',\n              age: 33\n            },\n            {\n              query: { [idProp]: alice[idProp] }\n            }\n          )\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Got a NotFound Feathers error')\n        }\n\n        await service.remove(alice[idProp])\n      })\n    })\n\n    describe('patch', () => {\n      test('.patch', async () => {\n        const originalData = { [idProp]: doug[idProp], name: 'PatchDoug' }\n        const originalCopy = Object.assign({}, originalData)\n\n        const data = await service.patch(doug[idProp], originalData)\n\n        assert.deepStrictEqual(originalData, originalCopy, 'original data was not modified')\n        assert.strictEqual(data[idProp].toString(), doug[idProp].toString(), `${idProp} id matches`)\n        assert.strictEqual(data.name, 'PatchDoug', 'data.name matches')\n        assert.strictEqual(data.age, 32, 'data.age matches')\n      })\n\n      test('.patch + $select', async () => {\n        const originalData = { [idProp]: doug[idProp], name: 'PatchDoug' }\n\n        const data = await service.patch(doug[idProp], originalData, {\n          query: { $select: ['name'] }\n        })\n\n        assert.strictEqual(data[idProp].toString(), doug[idProp].toString(), `${idProp} id property matches`)\n        assert.strictEqual(data.name, 'PatchDoug', 'data.name matches')\n        assert.ok(!data.age, 'data.age is falsy')\n      })\n\n      test('.patch + id + query', async () => {\n        try {\n          await service.patch(\n            doug[idProp],\n            {\n              name: 'id patched doug'\n            },\n            {\n              query: { name: 'Tester' }\n            }\n          )\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Got a NotFound Feathers error')\n        }\n      })\n\n      test('.patch multiple', async () => {\n        try {\n          await service.patch(null, {})\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(\n            error.name,\n            'MethodNotAllowed',\n            'Removing multiple without option set throws MethodNotAllowed'\n          )\n        }\n\n        const params = {\n          query: { created: true }\n        }\n        const dave = await service.create({\n          name: 'Dave',\n          age: 29,\n          created: true\n        })\n        const david = await service.create({\n          name: 'David',\n          age: 3,\n          created: true\n        })\n\n        service.options.multi = ['patch']\n\n        const data = await service.patch(\n          null,\n          {\n            age: 2\n          },\n          params\n        )\n\n        assert.strictEqual(data.length, 2, 'returned two entries')\n        assert.strictEqual(data[0].age, 2, 'First entry age was updated')\n        assert.strictEqual(data[1].age, 2, 'Second entry age was updated')\n\n        await service.remove(dave[idProp])\n        await service.remove(david[idProp])\n      })\n\n      test('.patch multiple no pagination', async () => {\n        try {\n          await service.remove(doug[idProp])\n        } catch (error: any) {}\n\n        const count = 14\n        const defaultPaginate = 10\n\n        assert.ok(count > defaultPaginate, 'count is bigger than default pagination')\n\n        const multiBefore = service.options.multi\n        const paginateBefore = service.options.paginate\n\n        let ids: any[]\n\n        try {\n          service.options.multi = true\n          service.options.paginate = {\n            default: defaultPaginate,\n            max: 100\n          }\n\n          const emptyItems = await service.find({ paginate: false })\n          assert.strictEqual(emptyItems.length, 0, 'no items before')\n\n          const createdItems = await service.create(\n            Array.from(Array(count)).map((_, i) => ({\n              name: `name-${i}`,\n              age: 3,\n              created: true\n            }))\n          )\n          assert.strictEqual(createdItems.length, count, `created ${count} items`)\n          ids = createdItems.map((item: any) => item[idProp])\n\n          const foundItems = await service.find({ paginate: false })\n          assert.strictEqual(foundItems.length, count, `created ${count} items`)\n\n          const foundPaginatedItems = await service.find({})\n          assert.strictEqual(foundPaginatedItems.data.length, defaultPaginate, 'found paginated data')\n\n          const allItems = await service.patch(null, { age: 4 }, { query: { created: true } })\n\n          assert.strictEqual(allItems.length, count, `patched all ${count} items`)\n        } finally {\n          service.options.multi = multiBefore\n          service.options.paginate = paginateBefore\n          if (ids) {\n            await Promise.all(ids.map((id) => service.remove(id)))\n          }\n        }\n      })\n\n      test('.patch multi query same', async () => {\n        const service = app.service(serviceName)\n        const multiBefore = service.options.multi\n\n        service.options.multi = true\n\n        const params = {\n          query: { age: { $lt: 10 } }\n        }\n        const dave = await service.create({\n          name: 'Dave',\n          age: 8,\n          created: true\n        })\n        const david = await service.create({\n          name: 'David',\n          age: 4,\n          created: true\n        })\n\n        const data = await service.patch(\n          null,\n          {\n            age: 2\n          },\n          params\n        )\n\n        assert.strictEqual(data.length, 2, 'returned two entries')\n        assert.strictEqual(data[0].age, 2, 'First entry age was updated')\n        assert.strictEqual(data[1].age, 2, 'Second entry age was updated')\n\n        await service.remove(dave[idProp])\n        await service.remove(david[idProp])\n\n        service.options.multi = multiBefore\n      })\n\n      test('.patch multi query changed', async () => {\n        const service = app.service(serviceName)\n        const multiBefore = service.options.multi\n\n        service.options.multi = true\n\n        const params = {\n          query: { age: 10 }\n        }\n        const dave = await service.create({\n          name: 'Dave',\n          age: 10,\n          created: true\n        })\n        const david = await service.create({\n          name: 'David',\n          age: 10,\n          created: true\n        })\n\n        const data = await service.patch(\n          null,\n          {\n            age: 2\n          },\n          params\n        )\n\n        assert.strictEqual(data.length, 2, 'returned two entries')\n        assert.strictEqual(data[0].age, 2, 'First entry age was updated')\n        assert.strictEqual(data[1].age, 2, 'Second entry age was updated')\n\n        await service.remove(dave[idProp])\n        await service.remove(david[idProp])\n\n        service.options.multi = multiBefore\n      })\n\n      test('.patch + NotFound', async () => {\n        try {\n          await service.patch('568225fbfe21222432e836ff', {\n            name: 'PatchDoug'\n          })\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Error is a NotFound Feathers error')\n        }\n      })\n\n      test('.patch + NotFound (integer)', async () => {\n        try {\n          await service.patch(123456789, {\n            name: 'PatchDoug'\n          })\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Error is a NotFound Feathers error')\n        }\n      })\n\n      test('.patch + query + NotFound', async () => {\n        const dave = await service.create({ name: 'Dave' })\n        try {\n          await service.patch(dave[idProp], { name: 'PatchedDave' }, { query: { name: 'NotDave' } })\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Error is a NotFound Feathers error')\n        }\n        await service.remove(dave[idProp])\n      })\n\n      test('.patch + id + query id', async () => {\n        const alice = await service.create({\n          name: 'Alice',\n          age: 12\n        })\n\n        try {\n          await service.patch(\n            doug[idProp],\n            {\n              age: 33\n            },\n            {\n              query: { [idProp]: alice[idProp] }\n            }\n          )\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotFound', 'Got a NotFound Feathers error')\n        }\n\n        await service.remove(alice[idProp])\n      })\n    })\n\n    describe('create', () => {\n      test('.create', async () => {\n        const originalData = {\n          name: 'Bill',\n          age: 40\n        }\n        const originalCopy = Object.assign({}, originalData)\n\n        const data = await service.create(originalData)\n\n        assert.deepStrictEqual(originalData, originalCopy, 'original data was not modified')\n        assert.ok(data instanceof Object, 'data is an object')\n        assert.strictEqual(data.name, 'Bill', 'data.name matches')\n\n        await service.remove(data[idProp])\n      })\n\n      test('.create ignores query', async () => {\n        const originalData = {\n          name: 'Billy',\n          age: 42\n        }\n        const data = await service.create(originalData, {\n          query: {\n            name: 'Dave'\n          }\n        })\n\n        assert.strictEqual(data.name, 'Billy', 'data.name matches')\n\n        await service.remove(data[idProp])\n      })\n\n      test('.create + $select', async () => {\n        const originalData = {\n          name: 'William',\n          age: 23\n        }\n\n        const data = await service.create(originalData, {\n          query: { $select: ['name'] }\n        })\n\n        assert.ok(idProp in data, 'data has id')\n        assert.strictEqual(data.name, 'William', 'data.name matches')\n        assert.ok(!data.age, 'data.age is falsy')\n\n        await service.remove(data[idProp])\n      })\n\n      test('.create multi', async () => {\n        try {\n          await service.create([], {})\n          throw new Error('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(\n            error.name,\n            'MethodNotAllowed',\n            'Removing multiple without option set throws MethodNotAllowed'\n          )\n        }\n\n        const items = [\n          {\n            name: 'Gerald',\n            age: 18\n          },\n          {\n            name: 'Herald',\n            age: 18\n          }\n        ]\n\n        service.options.multi = ['create', 'patch']\n\n        const data = await service.create(items)\n\n        assert.ok(Array.isArray(data), 'data is an array')\n        assert.ok(typeof data[0][idProp] !== 'undefined', 'id is set')\n        assert.strictEqual(data[0].name, 'Gerald', 'first name matches')\n        assert.ok(typeof data[1][idProp] !== 'undefined', 'id is set')\n        assert.strictEqual(data[1].name, 'Herald', 'second name macthes')\n\n        await service.remove(data[0][idProp])\n        await service.remove(data[1][idProp])\n      })\n    })\n\n    describe(\"doesn't call public methods internally\", () => {\n      let throwing: any\n\n      before(() => {\n        throwing = Object.assign(Object.create(app.service(serviceName)), {\n          get store() {\n            return app.service(serviceName).store\n          },\n\n          find() {\n            throw new Error('find method called')\n          },\n          get() {\n            throw new Error('get method called')\n          },\n          create() {\n            throw new Error('create method called')\n          },\n          update() {\n            throw new Error('update method called')\n          },\n          patch() {\n            throw new Error('patch method called')\n          },\n          remove() {\n            throw new Error('remove method called')\n          }\n        })\n      })\n\n      test('internal .find', () => app.service(serviceName).find.call(throwing))\n\n      test('internal .get', () => service.get.call(throwing, doug[idProp]))\n\n      test('internal .create', async () => {\n        const bob = await service.create.call(throwing, {\n          name: 'Bob',\n          age: 25\n        })\n\n        await service.remove(bob[idProp])\n      })\n\n      test('internal .update', () =>\n        service.update.call(throwing, doug[idProp], {\n          name: 'Dougler'\n        }))\n\n      test('internal .patch', () =>\n        service.patch.call(throwing, doug[idProp], {\n          name: 'PatchDoug'\n        }))\n\n      test('internal .remove', () => service.remove.call(throwing, doug[idProp]))\n    })\n  })\n}\n"
  },
  {
    "path": "packages/adapter-tests/src/syntax.ts",
    "content": "import assert from 'assert'\nimport { AdapterSyntaxTest } from './declarations'\n\nexport default (test: AdapterSyntaxTest, app: any, _errors: any, serviceName: string, idProp: string) => {\n  describe('Query Syntax', () => {\n    let bob: any\n    let alice: any\n    let doug: any\n    let service: any\n\n    beforeEach(async () => {\n      service = app.service(serviceName)\n      bob = await app.service(serviceName).create({\n        name: 'Bob',\n        age: 25\n      })\n      doug = await app.service(serviceName).create({\n        name: 'Doug',\n        age: 32\n      })\n      alice = await app.service(serviceName).create({\n        name: 'Alice',\n        age: 19\n      })\n    })\n\n    afterEach(async () => {\n      await service.remove(bob[idProp])\n      await service.remove(alice[idProp])\n      await service.remove(doug[idProp])\n    })\n\n    test('.find + equal', async () => {\n      const params = { query: { name: 'Alice' } }\n      const data = await service.find(params)\n\n      assert.ok(Array.isArray(data))\n      assert.strictEqual(data.length, 1)\n      assert.strictEqual(data[0].name, 'Alice')\n    })\n\n    test('.find + equal multiple', async () => {\n      const data = await service.find({\n        query: { name: 'Alice', age: 20 }\n      })\n\n      assert.strictEqual(data.length, 0)\n    })\n\n    describe('special filters', () => {\n      test('.find + $sort', async () => {\n        let data = await service.find({\n          query: {\n            $sort: { name: 1 }\n          }\n        })\n\n        assert.strictEqual(data.length, 3)\n        assert.strictEqual(data[0].name, 'Alice')\n        assert.strictEqual(data[1].name, 'Bob')\n        assert.strictEqual(data[2].name, 'Doug')\n\n        data = await service.find({\n          query: {\n            $sort: { name: -1 }\n          }\n        })\n\n        assert.strictEqual(data.length, 3)\n        assert.strictEqual(data[0].name, 'Doug')\n        assert.strictEqual(data[1].name, 'Bob')\n        assert.strictEqual(data[2].name, 'Alice')\n      })\n\n      test('.find + $sort + string', async () => {\n        const data = await service.find({\n          query: {\n            $sort: { name: '1' }\n          }\n        })\n\n        assert.strictEqual(data.length, 3)\n        assert.strictEqual(data[0].name, 'Alice')\n        assert.strictEqual(data[1].name, 'Bob')\n        assert.strictEqual(data[2].name, 'Doug')\n      })\n\n      test('.find + $limit', async () => {\n        const data = await service.find({\n          query: {\n            $limit: 2\n          }\n        })\n\n        assert.strictEqual(data.length, 2)\n      })\n\n      test('.find + $limit 0', async () => {\n        const data = await service.find({\n          query: {\n            $limit: 0\n          }\n        })\n\n        assert.strictEqual(data.length, 0)\n      })\n\n      test('.find + $skip', async () => {\n        const data = await service.find({\n          query: {\n            $sort: { name: 1 },\n            $skip: 1\n          }\n        })\n\n        assert.strictEqual(data.length, 2)\n        assert.strictEqual(data[0].name, 'Bob')\n        assert.strictEqual(data[1].name, 'Doug')\n      })\n\n      test('.find + $select', async () => {\n        const data = await service.find({\n          query: {\n            name: 'Alice',\n            $select: ['name']\n          }\n        })\n\n        assert.strictEqual(data.length, 1)\n        assert.ok(idProp in data[0], 'data has id')\n        assert.strictEqual(data[0].name, 'Alice')\n        assert.strictEqual(data[0].age, undefined)\n      })\n\n      test('.find + $or', async () => {\n        const data = await service.find({\n          query: {\n            $or: [{ name: 'Alice' }, { name: 'Bob' }],\n            $sort: { name: 1 }\n          }\n        })\n\n        assert.strictEqual(data.length, 2)\n        assert.strictEqual(data[0].name, 'Alice')\n        assert.strictEqual(data[1].name, 'Bob')\n      })\n\n      test('.find + $in', async () => {\n        const data = await service.find({\n          query: {\n            name: {\n              $in: ['Alice', 'Bob']\n            },\n            $sort: { name: 1 }\n          }\n        })\n\n        assert.strictEqual(data.length, 2)\n        assert.strictEqual(data[0].name, 'Alice')\n        assert.strictEqual(data[1].name, 'Bob')\n      })\n\n      test('.find + $nin', async () => {\n        const data = await service.find({\n          query: {\n            name: {\n              $nin: ['Alice', 'Bob']\n            }\n          }\n        })\n\n        assert.strictEqual(data.length, 1)\n        assert.strictEqual(data[0].name, 'Doug')\n      })\n\n      test('.find + $lt', async () => {\n        const data = await service.find({\n          query: {\n            age: {\n              $lt: 30\n            }\n          }\n        })\n\n        assert.strictEqual(data.length, 2)\n      })\n\n      test('.find + $lte', async () => {\n        const data = await service.find({\n          query: {\n            age: {\n              $lte: 25\n            }\n          }\n        })\n\n        assert.strictEqual(data.length, 2)\n      })\n\n      test('.find + $gt', async () => {\n        const data = await service.find({\n          query: {\n            age: {\n              $gt: 30\n            }\n          }\n        })\n\n        assert.strictEqual(data.length, 1)\n      })\n\n      test('.find + $gte', async () => {\n        const data = await service.find({\n          query: {\n            age: {\n              $gte: 25\n            }\n          }\n        })\n\n        assert.strictEqual(data.length, 2)\n      })\n\n      test('.find + $ne', async () => {\n        const data = await service.find({\n          query: {\n            age: {\n              $ne: 25\n            }\n          }\n        })\n\n        assert.strictEqual(data.length, 2)\n      })\n    })\n\n    test('.find + $gt + $lt + $sort', async () => {\n      const params = {\n        query: {\n          age: {\n            $gt: 18,\n            $lt: 30\n          },\n          $sort: { name: 1 }\n        }\n      }\n\n      const data = await service.find(params)\n\n      assert.strictEqual(data.length, 2)\n      assert.strictEqual(data[0].name, 'Alice')\n      assert.strictEqual(data[1].name, 'Bob')\n    })\n\n    test('.find + $or nested + $sort', async () => {\n      const params = {\n        query: {\n          $or: [\n            { name: 'Doug' },\n            {\n              age: {\n                $gte: 18,\n                $lt: 25\n              }\n            }\n          ],\n          $sort: { name: 1 }\n        }\n      }\n\n      const data = await service.find(params)\n\n      assert.strictEqual(data.length, 2)\n      assert.strictEqual(data[0].name, 'Alice')\n      assert.strictEqual(data[1].name, 'Doug')\n    })\n\n    test('.find + $and', async () => {\n      const params = {\n        query: {\n          $and: [{ age: 19 }],\n          $sort: { name: 1 }\n        }\n      }\n\n      const data = await service.find(params)\n\n      assert.strictEqual(data.length, 1)\n      assert.strictEqual(data[0].name, 'Alice')\n    })\n\n    test('.find + $and + $or', async () => {\n      const params = {\n        query: {\n          $and: [{ $or: [{ name: 'Alice' }] }],\n          $sort: { name: 1 }\n        }\n      }\n\n      const data = await service.find(params)\n\n      assert.strictEqual(data.length, 1)\n      assert.strictEqual(data[0].name, 'Alice')\n    })\n\n    describe('params.adapter', () => {\n      test('params.adapter + paginate', async () => {\n        const page = await service.find({\n          adapter: {\n            paginate: { default: 3 }\n          }\n        })\n\n        assert.strictEqual(page.limit, 3)\n        assert.strictEqual(page.skip, 0)\n      })\n\n      test('params.adapter + multi', async () => {\n        const items = [\n          {\n            name: 'Garald',\n            age: 200\n          },\n          {\n            name: 'Harald',\n            age: 24\n          }\n        ]\n        const multiParams = {\n          adapter: {\n            multi: ['create']\n          }\n        }\n        const users = await service.create(items, multiParams)\n\n        assert.strictEqual(users.length, 2)\n\n        await service.remove(users[0][idProp])\n        await service.remove(users[1][idProp])\n        await assert.rejects(() => service.patch(null, { age: 2 }, multiParams), {\n          message: 'Can not patch multiple entries'\n        })\n      })\n    })\n\n    describe('paginate', function () {\n      beforeEach(() => {\n        service.options.paginate = {\n          default: 1,\n          max: 2\n        }\n      })\n\n      afterEach(() => {\n        service.options.paginate = {}\n      })\n\n      test('.find + paginate', async () => {\n        const page = await service.find({\n          query: { $sort: { name: -1 } }\n        })\n\n        assert.strictEqual(page.total, 3)\n        assert.strictEqual(page.limit, 1)\n        assert.strictEqual(page.skip, 0)\n        assert.strictEqual(page.data[0].name, 'Doug')\n      })\n\n      test('.find + paginate + query', async () => {\n        const page = await service.find({\n          query: {\n            $sort: { name: -1 },\n            name: 'Doug'\n          }\n        })\n\n        assert.strictEqual(page.total, 1)\n        assert.strictEqual(page.limit, 1)\n        assert.strictEqual(page.skip, 0)\n        assert.strictEqual(page.data[0].name, 'Doug')\n      })\n\n      test('.find + paginate + $limit + $skip', async () => {\n        const params = {\n          query: {\n            $skip: 1,\n            $limit: 4,\n            $sort: { name: -1 }\n          }\n        }\n\n        const page = await service.find(params)\n\n        assert.strictEqual(page.total, 3)\n        assert.strictEqual(page.limit, 2)\n        assert.strictEqual(page.skip, 1)\n        assert.strictEqual(page.data[0].name, 'Bob')\n        assert.strictEqual(page.data[1].name, 'Alice')\n      })\n\n      test('.find + paginate + $limit 0', async () => {\n        const page = await service.find({\n          query: { $limit: 0 }\n        })\n\n        assert.strictEqual(page.total, 3)\n        assert.strictEqual(page.data.length, 0)\n      })\n\n      test('.find + paginate + params', async () => {\n        const page = await service.find({ paginate: { default: 3 } })\n\n        assert.strictEqual(page.limit, 3)\n        assert.strictEqual(page.skip, 0)\n\n        const results = await service.find({ paginate: false })\n\n        assert.ok(Array.isArray(results))\n        assert.strictEqual(results.length, 3)\n      })\n    })\n  })\n}\n"
  },
  {
    "path": "packages/adapter-tests/test/index.test.ts",
    "content": "import { strict as assert } from 'assert'\nimport adapterTests from '../src'\n\nconst testSuite = adapterTests([\n  '.events',\n  '._get',\n  '._find',\n  '._create',\n  '._update',\n  '._patch',\n  '._remove',\n  '.$get',\n  '.$find',\n  '.$create',\n  '.$update',\n  '.$patch',\n  '.$remove',\n  '.get',\n  '.get + $select',\n  '.get + id + query',\n  '.get + NotFound',\n  '.find',\n  '.remove',\n  '.remove + $select',\n  '.remove + id + query',\n  '.remove + multi',\n  '.remove + multi no pagination',\n  '.update',\n  '.update + $select',\n  '.update + id + query',\n  '.update + NotFound',\n  '.patch',\n  '.patch + $select',\n  '.patch + id + query',\n  '.patch multiple',\n  '.patch multiple no pagination',\n  '.patch multi query changed',\n  '.patch multi query same',\n  '.patch + NotFound',\n  '.create',\n  '.create + $select',\n  '.create multi',\n  'internal .find',\n  'internal .get',\n  'internal .create',\n  'internal .update',\n  'internal .patch',\n  'internal .remove',\n  '.find + equal',\n  '.find + equal multiple',\n  '.find + $sort',\n  '.find + $sort + string',\n  '.find + $limit',\n  '.find + $limit 0',\n  '.find + $skip',\n  '.find + $select',\n  '.find + $or',\n  '.find + $in',\n  '.find + $nin',\n  '.find + $lt',\n  '.find + $lte',\n  '.find + $gt',\n  '.find + $gte',\n  '.find + $ne',\n  '.find + $gt + $lt + $sort',\n  '.find + $or nested + $sort',\n  '.find + paginate',\n  '.find + paginate + $limit + $skip',\n  '.find + paginate + $limit 0',\n  '.find + paginate + params',\n  '.get + id + query id',\n  '.remove + id + query id',\n  '.update + id + query id',\n  '.patch + id + query id'\n])\n\ndescribe('Feathers Memory Service', () => {\n  it('loads the test suite', () => {\n    assert.ok(typeof testSuite === 'function')\n  })\n\n  it('exports as CommonJS', () => {\n    assert.equal(typeof require('../lib'), 'function')\n  })\n})\n"
  },
  {
    "path": "packages/adapter-tests/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/authentication/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n### Bug Fixes\n\n- Revert to compatible UUID package ([#3630](https://github.com/feathersjs/feathers/issues/3630)) ([5c8c9e3](https://github.com/feathersjs/feathers/commit/5c8c9e36efbbf695eccd6d8822e36e1ea75c1516))\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n### Bug Fixes\n\n- Reduce usage of lodash ([#3455](https://github.com/feathersjs/feathers/issues/3455)) ([8ce807a](https://github.com/feathersjs/feathers/commit/8ce807a5ca53ff5b8d5107a0656c6329404e6e6c))\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n### Bug Fixes\n\n- **authentication:** Export JwtVerifyOptions ([#3214](https://github.com/feathersjs/feathers/issues/3214)) ([d59896e](https://github.com/feathersjs/feathers/commit/d59896eb0229f1490c712f19cf84eb2bcf123698))\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **authentication:** Fix order of connection and login event handling ([#2909](https://github.com/feathersjs/feathers/issues/2909)) ([801a503](https://github.com/feathersjs/feathers/commit/801a503425062e27f2a32b91493b6ffae3822626))\n- **core:** `context.type` for around hooks ([#2890](https://github.com/feathersjs/feathers/issues/2890)) ([d606ac6](https://github.com/feathersjs/feathers/commit/d606ac660fd5335c95206784fea36530dd2e851a))\n\n### Features\n\n- **schema:** Virtual property resolvers ([#2900](https://github.com/feathersjs/feathers/issues/2900)) ([7d03b57](https://github.com/feathersjs/feathers/commit/7d03b57ae2f633bdd4a368e0d5955011fbd6c329))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n### Bug Fixes\n\n- **authentication:** Improve logout and disconnect connection handling ([#2813](https://github.com/feathersjs/feathers/issues/2813)) ([dd77379](https://github.com/feathersjs/feathers/commit/dd77379d8bdcd32d529bef912e672639e4899823))\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n### Features\n\n- **cli:** Generate full client test suite and improve typed client ([#2788](https://github.com/feathersjs/feathers/issues/2788)) ([57119b6](https://github.com/feathersjs/feathers/commit/57119b6bb2797f7297cf054268a248c093ecd538))\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n- **schema:** Make schemas validation library independent and add TypeBox support ([#2772](https://github.com/feathersjs/feathers/issues/2772)) ([44172d9](https://github.com/feathersjs/feathers/commit/44172d99b566d11d9ceda04f1d0bf72b6d05ce76))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n### Features\n\n- **authentication-oauth:** Koa and transport independent oAuth authentication ([#2737](https://github.com/feathersjs/feathers/issues/2737)) ([9231525](https://github.com/feathersjs/feathers/commit/9231525a24bb790ba9c5d940f2867a9c727691c9))\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Bug Fixes\n\n- **authentication:** Add safe dispatch data for authentication requests ([#2662](https://github.com/feathersjs/feathers/issues/2662)) ([d8104a1](https://github.com/feathersjs/feathers/commit/d8104a19ee9181e6a5ea81014af29ff9a3c28a8a))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Features\n\n- **typescript:** Improve adapter typings ([#2605](https://github.com/feathersjs/feathers/issues/2605)) ([3b2ca0a](https://github.com/feathersjs/feathers/commit/3b2ca0a6a8e03e8390272c4d7e930b4bffdaacf5))\n- **typescript:** Improve params and query typeability ([#2600](https://github.com/feathersjs/feathers/issues/2600)) ([df28b76](https://github.com/feathersjs/feathers/commit/df28b7619161f1df5e700326f52cca1a92dc5d28))\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n### Features\n\n- **authentication:** Add setup method for auth strategies ([#1611](https://github.com/feathersjs/feathers/issues/1611)) ([a3c3581](https://github.com/feathersjs/feathers/commit/a3c35814dccdbbf6de96f04f60b226ce206c6dbe))\n- **configuration:** Allow app configuration to be validated against a schema ([#2590](https://github.com/feathersjs/feathers/issues/2590)) ([a268f86](https://github.com/feathersjs/feathers/commit/a268f86da92a8ada14ed11ab456aac0a4bba5bb0))\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n### Features\n\n- **express, koa:** make transports similar ([#2486](https://github.com/feathersjs/feathers/issues/2486)) ([26aa937](https://github.com/feathersjs/feathers/commit/26aa937c114fb8596dfefc599b1f53cead69c159))\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n### Features\n\n- **authentication-oauth:** Allow dynamic oAuth redirect ([#2469](https://github.com/feathersjs/feathers/issues/2469)) ([b7143d4](https://github.com/feathersjs/feathers/commit/b7143d4c0fbe961e714f79512be04449b9bbd7d9))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- **hooks:** Migrate built-in hooks and allow backwards compatibility ([#2358](https://github.com/feathersjs/feathers/issues/2358)) ([759c5a1](https://github.com/feathersjs/feathers/commit/759c5a19327a731af965c3604119393b3d09a406))\n- **koa:** Use extended query parser for compatibility ([#2397](https://github.com/feathersjs/feathers/issues/2397)) ([b2944ba](https://github.com/feathersjs/feathers/commit/b2944bac3ec6d5ecc80dc518cd4e58093692db74))\n\n### Features\n\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n### Features\n\n- **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n### Features\n\n- Application service types default to any ([#1566](https://github.com/feathersjs/feathers/issues/1566)) ([d93ba9a](https://github.com/feathersjs/feathers/commit/d93ba9a17edd20d3397bb00f4f6e82e804e42ed6))\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n### Bug Fixes\n\n- **authentication:** consistent response return between local and jwt strategy ([#2042](https://github.com/feathersjs/feathers/issues/2042)) ([8d25be1](https://github.com/feathersjs/feathers/commit/8d25be101a2593a9e789375c928a07780b9e28cf))\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n### Bug Fixes\n\n- **authentication:** Add JWT getEntityQuery ([#2013](https://github.com/feathersjs/feathers/issues/2013)) ([e0e7fb5](https://github.com/feathersjs/feathers/commit/e0e7fb5162940fe776731283b40026c61d9c8a33))\n\n## [4.5.6](https://github.com/feathersjs/feathers/compare/v4.5.5...v4.5.6) (2020-07-12)\n\n### Bug Fixes\n\n- **authentication:** Omit query in JWT strategy ([#2011](https://github.com/feathersjs/feathers/issues/2011)) ([04ce7e9](https://github.com/feathersjs/feathers/commit/04ce7e98515fe9d495cd0e83e0da097e9bcd7382))\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n### Bug Fixes\n\n- **authentication:** Include query params when authenticating via authenticate hook [#2009](https://github.com/feathersjs/feathers/issues/2009) ([4cdb7bf](https://github.com/feathersjs/feathers/commit/4cdb7bf2898385ddac7a1692bc9ac2f6cf5ad446))\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n### Bug Fixes\n\n- **authentication:** Remove entity from connection information on logout ([#1889](https://github.com/feathersjs/feathers/issues/1889)) ([b062753](https://github.com/feathersjs/feathers/commit/b0627530d61babe15dd84369d3093ccae4b780ca))\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n### Bug Fixes\n\n- **authentication:** Improve JWT strategy configuration error message ([#1844](https://github.com/feathersjs/feathers/issues/1844)) ([2c771db](https://github.com/feathersjs/feathers/commit/2c771dbb22d53d4f7de3c3f514e57afa1a186322))\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n### Bug Fixes\n\n- Add `params.authentication` type, remove `hook.connection` type ([#1732](https://github.com/feathersjs/feathers/issues/1732)) ([d46b7b2](https://github.com/feathersjs/feathers/commit/d46b7b2abac8862c0e4dbfce20d71b8b8a96692f))\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n### Bug Fixes\n\n- **authentication:** Retain object references in authenticate hook ([#1675](https://github.com/feathersjs/feathers/issues/1675)) ([e1939be](https://github.com/feathersjs/feathers/commit/e1939be19d4e79d3f5e2fe69ba894a11c627ae99))\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n### Bug Fixes\n\n- Add jsonwebtoken TypeScript type dependency ([317c80a](https://github.com/feathersjs/feathers/commit/317c80a9205e8853bb830a12c3aa1a19e95f9abc))\n- Small type improvements ([#1624](https://github.com/feathersjs/feathers/issues/1624)) ([50162c6](https://github.com/feathersjs/feathers/commit/50162c6e562f0a47c6a280c4f01fff7c3afee293))\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [4.3.5](https://github.com/feathersjs/feathers/compare/v4.3.4...v4.3.5) (2019-10-07)\n\n### Bug Fixes\n\n- Authentication type improvements and timeout fix ([#1605](https://github.com/feathersjs/feathers/issues/1605)) ([19854d3](https://github.com/feathersjs/feathers/commit/19854d3))\n- Improve error message when authentication strategy is not allowed ([#1600](https://github.com/feathersjs/feathers/issues/1600)) ([317a312](https://github.com/feathersjs/feathers/commit/317a312))\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n### Bug Fixes\n\n- check for undefined access token ([#1571](https://github.com/feathersjs/feathers/issues/1571)) ([976369d](https://github.com/feathersjs/feathers/commit/976369d))\n- Small improvements in dependencies and code sturcture ([#1562](https://github.com/feathersjs/feathers/issues/1562)) ([42c13e2](https://github.com/feathersjs/feathers/commit/42c13e2))\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n### Bug Fixes\n\n- Use long-timeout for JWT expiration timers ([#1552](https://github.com/feathersjs/feathers/issues/1552)) ([65637ec](https://github.com/feathersjs/feathers/commit/65637ec))\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n### Bug Fixes\n\n- Fix auth publisher mistake ([08bad61](https://github.com/feathersjs/feathers/commit/08bad61))\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Expire and remove authenticated real-time connections ([#1512](https://github.com/feathersjs/feathers/issues/1512)) ([2707c33](https://github.com/feathersjs/feathers/commit/2707c33))\n- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))\n\n### Features\n\n- Let strategies handle the connection ([#1510](https://github.com/feathersjs/feathers/issues/1510)) ([4329feb](https://github.com/feathersjs/feathers/commit/4329feb))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n### Bug Fixes\n\n- Add getEntityId to JWT strategy and fix legacy Socket authentication ([#1488](https://github.com/feathersjs/feathers/issues/1488)) ([9a3b324](https://github.com/feathersjs/feathers/commit/9a3b324))\n- Add method to reliably get default authentication service ([#1470](https://github.com/feathersjs/feathers/issues/1470)) ([e542cb3](https://github.com/feathersjs/feathers/commit/e542cb3))\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n### Bug Fixes\n\n- Updated typings for ServiceMethods ([#1409](https://github.com/feathersjs/feathers/issues/1409)) ([b5ee7e2](https://github.com/feathersjs/feathers/commit/b5ee7e2))\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Make oAuth paths more consistent and improve authentication client ([#1377](https://github.com/feathersjs/feathers/issues/1377)) ([adb2543](https://github.com/feathersjs/feathers/commit/adb2543))\n- Set authenticated: true after successful authentication ([#1367](https://github.com/feathersjs/feathers/issues/1367)) ([9918cff](https://github.com/feathersjs/feathers/commit/9918cff))\n- Typings fix and improvements. ([#1364](https://github.com/feathersjs/feathers/issues/1364)) ([515b916](https://github.com/feathersjs/feathers/commit/515b916))\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n### Bug Fixes\n\n- Throw NotAuthenticated on token verification errors ([#1357](https://github.com/feathersjs/feathers/issues/1357)) ([e0120df](https://github.com/feathersjs/feathers/commit/e0120df))\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n### Bug Fixes\n\n- Always require strategy parameter in authentication ([#1327](https://github.com/feathersjs/feathers/issues/1327)) ([d4a8021](https://github.com/feathersjs/feathers/commit/d4a8021))\n- Bring back params.authenticated ([#1317](https://github.com/feathersjs/feathers/issues/1317)) ([a0ffd5e](https://github.com/feathersjs/feathers/commit/a0ffd5e))\n- Improve authentication parameter handling ([#1333](https://github.com/feathersjs/feathers/issues/1333)) ([6e77204](https://github.com/feathersjs/feathers/commit/6e77204))\n- Merge httpStrategies and authStrategies option ([#1308](https://github.com/feathersjs/feathers/issues/1308)) ([afa4d55](https://github.com/feathersjs/feathers/commit/afa4d55))\n- Rename jwtStrategies option to authStrategies ([#1305](https://github.com/feathersjs/feathers/issues/1305)) ([4aee151](https://github.com/feathersjs/feathers/commit/4aee151))\n\n### Features\n\n- Change and *JWT methods to *accessToken ([#1304](https://github.com/feathersjs/feathers/issues/1304)) ([5ac826b](https://github.com/feathersjs/feathers/commit/5ac826b))\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Added path and method in to express request for passport ([#1112](https://github.com/feathersjs/feathers/issues/1112)) ([afa1cb4](https://github.com/feathersjs/feathers/commit/afa1cb4))\n- Authentication core improvements ([#1260](https://github.com/feathersjs/feathers/issues/1260)) ([c5dc7a2](https://github.com/feathersjs/feathers/commit/c5dc7a2))\n- Improve JWT authentication option handling ([#1261](https://github.com/feathersjs/feathers/issues/1261)) ([31b956b](https://github.com/feathersjs/feathers/commit/31b956b))\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Only merge authenticated property on update ([8a564f7](https://github.com/feathersjs/feathers/commit/8a564f7))\n- reduce authentication connection hook complexity and remove unnecessary checks ([fa94b2f](https://github.com/feathersjs/feathers/commit/fa94b2f))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n- **authentication:** Fall back when req.app is not the application when emitting events ([#1185](https://github.com/feathersjs/feathers/issues/1185)) ([6a534f0](https://github.com/feathersjs/feathers/commit/6a534f0))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n- **docs/new-features:** syntax highlighting ([#347](https://github.com/feathersjs/feathers/issues/347)) ([4ab7c95](https://github.com/feathersjs/feathers/commit/4ab7c95))\n- **package:** update @feathersjs/commons to version 2.0.0 ([#692](https://github.com/feathersjs/feathers/issues/692)) ([ca665ab](https://github.com/feathersjs/feathers/commit/ca665ab))\n- **package:** update debug to version 3.0.0 ([#555](https://github.com/feathersjs/feathers/issues/555)) ([f788804](https://github.com/feathersjs/feathers/commit/f788804))\n- **package:** update jsonwebtoken to version 8.0.0 ([#567](https://github.com/feathersjs/feathers/issues/567)) ([6811626](https://github.com/feathersjs/feathers/commit/6811626))\n- **package:** update ms to version 2.0.0 ([#509](https://github.com/feathersjs/feathers/issues/509)) ([7e4b0b6](https://github.com/feathersjs/feathers/commit/7e4b0b6))\n- **package:** update passport to version 0.4.0 ([#558](https://github.com/feathersjs/feathers/issues/558)) ([dcb14a5](https://github.com/feathersjs/feathers/commit/dcb14a5))\n\n### Features\n\n- @feathersjs/authentication-oauth ([#1299](https://github.com/feathersjs/feathers/issues/1299)) ([656bae7](https://github.com/feathersjs/feathers/commit/656bae7))\n- Add AuthenticationBaseStrategy and make authentication option handling more explicit ([#1284](https://github.com/feathersjs/feathers/issues/1284)) ([2667d92](https://github.com/feathersjs/feathers/commit/2667d92))\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Authentication v3 core server implementation ([#1205](https://github.com/feathersjs/feathers/issues/1205)) ([1bd7591](https://github.com/feathersjs/feathers/commit/1bd7591))\n- Authentication v3 local authentication ([#1211](https://github.com/feathersjs/feathers/issues/1211)) ([0fa5f7c](https://github.com/feathersjs/feathers/commit/0fa5f7c))\n- Remove (hook, next) signature and SKIP support ([#1269](https://github.com/feathersjs/feathers/issues/1269)) ([211c0f8](https://github.com/feathersjs/feathers/commit/211c0f8))\n- Support params symbol to skip authenticate hook ([#1296](https://github.com/feathersjs/feathers/issues/1296)) ([d16cf4d](https://github.com/feathersjs/feathers/commit/d16cf4d))\n\n### BREAKING CHANGES\n\n- Update authentication strategies for @feathersjs/authentication v3\n\n## [2.1.16](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication@2.1.15...@feathersjs/authentication@2.1.16) (2019-01-26)\n\n### Bug Fixes\n\n- **authentication:** Fall back when req.app is not the application when emitting events ([#1185](https://github.com/feathersjs/feathers/issues/1185)) ([6a534f0](https://github.com/feathersjs/feathers/commit/6a534f0))\n\n## [2.1.15](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication@2.1.14...@feathersjs/authentication@2.1.15) (2019-01-02)\n\n### Bug Fixes\n\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n\n<a name=\"2.1.14\"></a>\n\n## [2.1.14](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication@2.1.13...@feathersjs/authentication@2.1.14) (2018-12-16)\n\n### Bug Fixes\n\n- Added path and method in to express request for passport ([#1112](https://github.com/feathersjs/feathers/issues/1112)) ([afa1cb4](https://github.com/feathersjs/feathers/commit/afa1cb4))\n\n<a name=\"2.1.13\"></a>\n\n## [2.1.13](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication@2.1.12...@feathersjs/authentication@2.1.13) (2018-10-26)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n<a name=\"2.1.12\"></a>\n\n## [2.1.12](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication@2.1.11...@feathersjs/authentication@2.1.12) (2018-10-25)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Only merge authenticated property on update ([8a564f7](https://github.com/feathersjs/feathers/commit/8a564f7))\n\n<a name=\"2.1.11\"></a>\n\n## [2.1.11](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication@2.1.10...@feathersjs/authentication@2.1.11) (2018-09-21)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n<a name=\"2.1.10\"></a>\n\n## [2.1.10](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication@2.1.9...@feathersjs/authentication@2.1.10) (2018-09-17)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n<a name=\"2.1.9\"></a>\n\n## [2.1.9](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication@2.1.8...@feathersjs/authentication@2.1.9) (2018-09-02)\n\n**Note:** Version bump only for package @feathersjs/authentication\n\n<a name=\"2.1.8\"></a>\n\n## 2.1.8\n\n- Migrate to Monorepo ([feathers#462](https://github.com/feathersjs/feathers/issues/462))\n\n## [v2.1.7](https://github.com/feathersjs/authentication/tree/v2.1.7) (2018-06-29)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v2.1.6...v2.1.7)\n\n**Fixed bugs:**\n\n- XXXOrRestrict undermines provider \\(security\\) logic [\\#395](https://github.com/feathersjs/authentication/issues/395)\n\n**Closed issues:**\n\n- Customize response of authentication service [\\#679](https://github.com/feathersjs/authentication/issues/679)\n- hook.params.user is null using REST [\\#678](https://github.com/feathersjs/authentication/issues/678)\n- Can't store JWT token to cookie on REST client [\\#676](https://github.com/feathersjs/authentication/issues/676)\n- Is there a way to get req.user without using the authentication middleware? [\\#675](https://github.com/feathersjs/authentication/issues/675)\n\n**Merged pull requests:**\n\n- Remove subject from the JWT verification options [\\#686](https://github.com/feathersjs/authentication/pull/686) ([rasendubi](https://github.com/rasendubi))\n- Replaced feathers.static with express.static [\\#685](https://github.com/feathersjs/authentication/pull/685) ([georgehorrell](https://github.com/georgehorrell))\n- Remove dependency on Express and Express middleware [\\#683](https://github.com/feathersjs/authentication/pull/683) ([daffl](https://github.com/daffl))\n- Update sinon to the latest version 🚀 [\\#681](https://github.com/feathersjs/authentication/pull/681) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.1.6](https://github.com/feathersjs/authentication/tree/v2.1.6) (2018-06-01)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v2.1.5...v2.1.6)\n\n**Closed issues:**\n\n- Authentication local strategy not working with a Custom User service [\\#672](https://github.com/feathersjs/authentication/issues/672)\n- CLI command bug: 'Feathers generate authentication' produces bad working 'users' service [\\#670](https://github.com/feathersjs/authentication/issues/670)\n- config\\default.json generated without callbackURL config needed to set redirect URL for Google Outh2 [\\#669](https://github.com/feathersjs/authentication/issues/669)\n- HELP WANTED: Authentication strategy 'jwt' is not registered. [\\#668](https://github.com/feathersjs/authentication/issues/668)\n- Authenticate shows error: No auth token [\\#667](https://github.com/feathersjs/authentication/issues/667)\n- authentication - Method: remove [\\#662](https://github.com/feathersjs/authentication/issues/662)\n- NotAuthenticated: jwt expired [\\#633](https://github.com/feathersjs/authentication/issues/633)\n- Authentication via phone number [\\#616](https://github.com/feathersjs/authentication/issues/616)\n- Persist auth tokens on db [\\#569](https://github.com/feathersjs/authentication/issues/569)\n- Tighter integration with feathers-authentication-management [\\#393](https://github.com/feathersjs/authentication/issues/393)\n\n**Merged pull requests:**\n\n- Fix tests to work with latest Sinon [\\#674](https://github.com/feathersjs/authentication/pull/674) ([daffl](https://github.com/daffl))\n- add option to allowUnauthenticated [\\#599](https://github.com/feathersjs/authentication/pull/599) ([MichaelErmer](https://github.com/MichaelErmer))\n\n## [v2.1.5](https://github.com/feathersjs/authentication/tree/v2.1.5) (2018-04-16)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v2.1.4...v2.1.5)\n\n**Closed issues:**\n\n- feathersjs Invalid token: expired [\\#661](https://github.com/feathersjs/authentication/issues/661)\n- Safari and iOS facebook login can't redirect back, but others can. [\\#651](https://github.com/feathersjs/authentication/issues/651)\n\n**Merged pull requests:**\n\n- Remove payload and user entity on logout. [\\#665](https://github.com/feathersjs/authentication/pull/665) ([bertho-zero](https://github.com/bertho-zero))\n\n## [v2.1.4](https://github.com/feathersjs/authentication/tree/v2.1.4) (2018-04-12)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v2.1.3...v2.1.4)\n\n**Closed issues:**\n\n- Column \"createdAt\" does not exist\" in Autentication [\\#660](https://github.com/feathersjs/authentication/issues/660)\n- How to make a user automatically logined on server side? [\\#659](https://github.com/feathersjs/authentication/issues/659)\n- authentication-jwt functional example [\\#657](https://github.com/feathersjs/authentication/issues/657)\n- \"No auth token\" with auth0 when following the guide [\\#655](https://github.com/feathersjs/authentication/issues/655)\n- Service returns \\[No Auth Token\\] same by passing Authorization Token on HEADER [\\#641](https://github.com/feathersjs/authentication/issues/641)\n\n**Merged pull requests:**\n\n- Throw an error for unavailable strategy [\\#663](https://github.com/feathersjs/authentication/pull/663) ([daffl](https://github.com/daffl))\n- Update sinon to the latest version 🚀 [\\#656](https://github.com/feathersjs/authentication/pull/656) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.1.3](https://github.com/feathersjs/authentication/tree/v2.1.3) (2018-03-16)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v2.1.2...v2.1.3)\n\n**Closed issues:**\n\n- ts [\\#647](https://github.com/feathersjs/authentication/issues/647)\n- Using /auth/facebook gives a 404 from vue-router [\\#643](https://github.com/feathersjs/authentication/issues/643)\n- Crash after upgrade to feathersjs v3 [\\#642](https://github.com/feathersjs/authentication/issues/642)\n- SameSite cookie option [\\#640](https://github.com/feathersjs/authentication/issues/640)\n- context.params.user is empty object [\\#635](https://github.com/feathersjs/authentication/issues/635)\n- Token is undefined for authenticated user [\\#500](https://github.com/feathersjs/authentication/issues/500)\n- 1.x: logout timers need to be moved [\\#467](https://github.com/feathersjs/authentication/issues/467)\n\n**Merged pull requests:**\n\n- Merge auk to master [\\#653](https://github.com/feathersjs/authentication/pull/653) ([wnxhaja](https://github.com/wnxhaja))\n- Update ws to the latest version 🚀 [\\#645](https://github.com/feathersjs/authentication/pull/645) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update sinon-chai to the latest version 🚀 [\\#644](https://github.com/feathersjs/authentication/pull/644) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.1.2](https://github.com/feathersjs/authentication/tree/v2.1.2) (2018-02-14)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v2.1.1...v2.1.2)\n\n**Fixed bugs:**\n\n- hook failed with auth & sync [\\#540](https://github.com/feathersjs/authentication/issues/540)\n- JWT Cookie [\\#389](https://github.com/feathersjs/authentication/issues/389)\n\n**Closed issues:**\n\n- forgot password [\\#638](https://github.com/feathersjs/authentication/issues/638)\n- registered many authentication services [\\#634](https://github.com/feathersjs/authentication/issues/634)\n- TypeError: Cannot read property '\\_strategy' of undefined [\\#632](https://github.com/feathersjs/authentication/issues/632)\n- How to change 5000ms timeout? [\\#628](https://github.com/feathersjs/authentication/issues/628)\n- cookie reused from server in SSR app [\\#619](https://github.com/feathersjs/authentication/issues/619)\n- Express middleware not setCookie [\\#617](https://github.com/feathersjs/authentication/issues/617)\n- Server to Server Authentication Question [\\#612](https://github.com/feathersjs/authentication/issues/612)\n- No way to share token between socket-rest-express [\\#607](https://github.com/feathersjs/authentication/issues/607)\n- 404 when accessing route using customer authentication [\\#579](https://github.com/feathersjs/authentication/issues/579)\n- \\[question\\] is it possible to protect by role a create method? [\\#564](https://github.com/feathersjs/authentication/issues/564)\n- Authentication with server-side rendering [\\#560](https://github.com/feathersjs/authentication/issues/560)\n- Problem authenticating using REST middleware [\\#495](https://github.com/feathersjs/authentication/issues/495)\n- A supposed way to auth requests from SSR to Feathers API [\\#469](https://github.com/feathersjs/authentication/issues/469)\n- rename `app.authenticate\\(\\)` to `app.\\_authenticate\\(\\)` [\\#468](https://github.com/feathersjs/authentication/issues/468)\n\n**Merged pull requests:**\n\n- Delete slack link [\\#637](https://github.com/feathersjs/authentication/pull/637) ([vodniciarv](https://github.com/vodniciarv))\n- Update @feathersjs/authentication-jwt to the latest version 🚀 [\\#631](https://github.com/feathersjs/authentication/pull/631) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update mocha to the latest version 🚀 [\\#629](https://github.com/feathersjs/authentication/pull/629) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update ws to the latest version 🚀 [\\#625](https://github.com/feathersjs/authentication/pull/625) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Options merged [\\#611](https://github.com/feathersjs/authentication/pull/611) ([Makingweb](https://github.com/Makingweb))\n\n## [v2.1.1](https://github.com/feathersjs/authentication/tree/v2.1.1) (2018-01-03)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v2.1.0...v2.1.1)\n\n**Closed issues:**\n\n- Deleted user successfully signs in using JWT [\\#615](https://github.com/feathersjs/authentication/issues/615)\n- Feathers.authenticate gives window undefined \\(server-rendered\\) [\\#573](https://github.com/feathersjs/authentication/issues/573)\n- Be careful with discard\\('password'\\) in user [\\#434](https://github.com/feathersjs/authentication/issues/434)\n\n**Merged pull requests:**\n\n- Update readme to correspond with latest release [\\#621](https://github.com/feathersjs/authentication/pull/621) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#620](https://github.com/feathersjs/authentication/pull/620) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update mongodb to the latest version 🚀 [\\#618](https://github.com/feathersjs/authentication/pull/618) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.1.0](https://github.com/feathersjs/authentication/tree/v2.1.0) (2017-12-06)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v2.0.1...v2.1.0)\n\n**Closed issues:**\n\n- Method \"Remove\" from Authentication Service gives Internal Server Error when using JWT Authentication with Cookies. [\\#606](https://github.com/feathersjs/authentication/issues/606)\n- Anonymous Authentication fails over Socket.io [\\#457](https://github.com/feathersjs/authentication/issues/457)\n\n**Merged pull requests:**\n\n- Always prevent publishing of authentication events [\\#614](https://github.com/feathersjs/authentication/pull/614) ([daffl](https://github.com/daffl))\n- Update feathers-memory to the latest version 🚀 [\\#613](https://github.com/feathersjs/authentication/pull/613) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.0.1](https://github.com/feathersjs/authentication/tree/v2.0.1) (2017-11-16)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v2.0.0...v2.0.1)\n\n**Merged pull requests:**\n\n- Add default export for better ES module \\(TypeScript\\) compatibility [\\#605](https://github.com/feathersjs/authentication/pull/605) ([daffl](https://github.com/daffl))\n\n## [v2.0.0](https://github.com/feathersjs/authentication/tree/v2.0.0) (2017-11-09)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.3.1...v2.0.0)\n\n**Closed issues:**\n\n- is there a way to detect if the token used is correct or not ? [\\#601](https://github.com/feathersjs/authentication/issues/601)\n- option for non-JWT based session [\\#597](https://github.com/feathersjs/authentication/issues/597)\n\n**Merged pull requests:**\n\n- Update nsp to the latest version 🚀 [\\#603](https://github.com/feathersjs/authentication/pull/603) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.3.1](https://github.com/feathersjs/authentication/tree/v1.3.1) (2017-11-03)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.4.1...v1.3.1)\n\n**Merged pull requests:**\n\n- Only set the JWT UUID if it is not already set [\\#600](https://github.com/feathersjs/authentication/pull/600) ([daffl](https://github.com/daffl))\n\n## [v1.4.1](https://github.com/feathersjs/authentication/tree/v1.4.1) (2017-11-01)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.4.0...v1.4.1)\n\n**Merged pull requests:**\n\n- Update dependencies for release [\\#598](https://github.com/feathersjs/authentication/pull/598) ([daffl](https://github.com/daffl))\n- Finalize v3 dependency updates [\\#596](https://github.com/feathersjs/authentication/pull/596) ([daffl](https://github.com/daffl))\n- Update Codeclimate coverage token [\\#595](https://github.com/feathersjs/authentication/pull/595) ([daffl](https://github.com/daffl))\n\n## [v1.4.0](https://github.com/feathersjs/authentication/tree/v1.4.0) (2017-10-25)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.3.0...v1.4.0)\n\n**Closed issues:**\n\n- An in-range update of socket.io-client is breaking the build 🚨 [\\#588](https://github.com/feathersjs/authentication/issues/588)\n- An in-range update of feathers-hooks is breaking the build 🚨 [\\#587](https://github.com/feathersjs/authentication/issues/587)\n\n**Merged pull requests:**\n\n- Move to npm scope [\\#594](https://github.com/feathersjs/authentication/pull/594) ([daffl](https://github.com/daffl))\n- Update to Feathers v3 \\(Buzzard\\) [\\#592](https://github.com/feathersjs/authentication/pull/592) ([daffl](https://github.com/daffl))\n- Update to new plugin infrastructure [\\#591](https://github.com/feathersjs/authentication/pull/591) ([daffl](https://github.com/daffl))\n\n## [v1.3.0](https://github.com/feathersjs/authentication/tree/v1.3.0) (2017-10-24)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.13...v1.3.0)\n\n**Merged pull requests:**\n\n- updating the codeclimate setup [\\#589](https://github.com/feathersjs/authentication/pull/589) ([ekryski](https://github.com/ekryski))\n\n## [v0.7.13](https://github.com/feathersjs/authentication/tree/v0.7.13) (2017-10-23)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.2.7...v0.7.13)\n\n**Closed issues:**\n\n- Error authenticating! Error: Token provided to verifyJWT is missing or not a string ? [\\#584](https://github.com/feathersjs/authentication/issues/584)\n- Visual Studio Code Debug no authentication [\\#583](https://github.com/feathersjs/authentication/issues/583)\n- \\[Feature Request\\] Cloud DB's [\\#581](https://github.com/feathersjs/authentication/issues/581)\n- Request doesn't contain any headers when user service requested [\\#578](https://github.com/feathersjs/authentication/issues/578)\n- No way to pass Options to auth.express.authenticate. Needed for Google API refreshToken [\\#576](https://github.com/feathersjs/authentication/issues/576)\n- /auth/google 404 Not Found [\\#574](https://github.com/feathersjs/authentication/issues/574)\n- unique email not working while create [\\#572](https://github.com/feathersjs/authentication/issues/572)\n- authentication service not return token jwt [\\#571](https://github.com/feathersjs/authentication/issues/571)\n- typo in jwt default options [\\#570](https://github.com/feathersjs/authentication/issues/570)\n- Generate new app, Google-only auth, throws error [\\#568](https://github.com/feathersjs/authentication/issues/568)\n- An in-range update of feathers is breaking the build 🚨 [\\#565](https://github.com/feathersjs/authentication/issues/565)\n- Documentation not understanding [\\#563](https://github.com/feathersjs/authentication/issues/563)\n- Checking hook.params.headers.authorization [\\#552](https://github.com/feathersjs/authentication/issues/552)\n- Ability to send token as part of URL [\\#546](https://github.com/feathersjs/authentication/issues/546)\n- Anonymous Authentication [\\#544](https://github.com/feathersjs/authentication/issues/544)\n- Quote Error [\\#519](https://github.com/feathersjs/authentication/issues/519)\n- \\[example\\] CustomStrategy using passport-custom [\\#516](https://github.com/feathersjs/authentication/issues/516)\n- \\[Epic\\] Auth 2.0.0 [\\#513](https://github.com/feathersjs/authentication/issues/513)\n- ID set to null - Unable to delete with customer ID field. [\\#422](https://github.com/feathersjs/authentication/issues/422)\n- Prefixing socket events [\\#418](https://github.com/feathersjs/authentication/issues/418)\n- Passwordless auth [\\#409](https://github.com/feathersjs/authentication/issues/409)\n- How to authenticate the application client? not only the users [\\#405](https://github.com/feathersjs/authentication/issues/405)\n- Multi-factor Local Auth [\\#5](https://github.com/feathersjs/authentication/issues/5)\n\n**Merged pull requests:**\n\n- Features/typescript fix [\\#585](https://github.com/feathersjs/authentication/pull/585) ([TimMensch](https://github.com/TimMensch))\n- Update mocha to the latest version 🚀 [\\#582](https://github.com/feathersjs/authentication/pull/582) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update sinon to the latest version 🚀 [\\#580](https://github.com/feathersjs/authentication/pull/580) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update jsonwebtoken to the latest version 🚀 [\\#567](https://github.com/feathersjs/authentication/pull/567) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Include Babel Polyfill for Node 4 [\\#566](https://github.com/feathersjs/authentication/pull/566) ([daffl](https://github.com/daffl))\n- Update passport to the latest version 🚀 [\\#558](https://github.com/feathersjs/authentication/pull/558) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Revert \"Make feathers-authentication match security documents\" [\\#556](https://github.com/feathersjs/authentication/pull/556) ([ekryski](https://github.com/ekryski))\n- Update debug to the latest version 🚀 [\\#555](https://github.com/feathersjs/authentication/pull/555) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Make feathers-authentication match security documents [\\#554](https://github.com/feathersjs/authentication/pull/554) ([micaksica2](https://github.com/micaksica2))\n- Update sinon to the latest version 🚀 [\\#551](https://github.com/feathersjs/authentication/pull/551) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update ws to the latest version 🚀 [\\#549](https://github.com/feathersjs/authentication/pull/549) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update chai to the latest version 🚀 [\\#543](https://github.com/feathersjs/authentication/pull/543) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- adding a default jwt uuid. Refs \\#513 [\\#539](https://github.com/feathersjs/authentication/pull/539) ([ekryski](https://github.com/ekryski))\n- Refresh token must have a user ID [\\#419](https://github.com/feathersjs/authentication/pull/419) ([francisco-sanchez-molina](https://github.com/francisco-sanchez-molina))\n\n## [v1.2.7](https://github.com/feathersjs/authentication/tree/v1.2.7) (2017-07-11)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.2.6...v1.2.7)\n\n**Closed issues:**\n\n- Connection without password [\\#541](https://github.com/feathersjs/authentication/issues/541)\n- email in lower case ? [\\#538](https://github.com/feathersjs/authentication/issues/538)\n- Im unable to ping feathers server from react native. [\\#537](https://github.com/feathersjs/authentication/issues/537)\n- whats the official way to open cors in feather ? [\\#536](https://github.com/feathersjs/authentication/issues/536)\n- Error options.service does not exist after initial auth setup [\\#535](https://github.com/feathersjs/authentication/issues/535)\n- LogoutTimer not being cleared correctly [\\#532](https://github.com/feathersjs/authentication/issues/532)\n- logoutTimer causing early logouts [\\#404](https://github.com/feathersjs/authentication/issues/404)\n\n**Merged pull requests:**\n\n- fixed meta undefined error [\\#542](https://github.com/feathersjs/authentication/pull/542) ([markacola](https://github.com/markacola))\n\n## [v1.2.6](https://github.com/feathersjs/authentication/tree/v1.2.6) (2017-06-22)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.2.5...v1.2.6)\n\n**Closed issues:**\n\n- OAuth 2 login for cordova [\\#530](https://github.com/feathersjs/authentication/issues/530)\n\n**Merged pull requests:**\n\n- Change cleartimeout\\(\\) to lt.clearTimeout\\(\\) [\\#534](https://github.com/feathersjs/authentication/pull/534) ([wnxhaja](https://github.com/wnxhaja))\n- Update feathers-authentication-local to the latest version 🚀 [\\#533](https://github.com/feathersjs/authentication/pull/533) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.2.5](https://github.com/feathersjs/authentication/tree/v1.2.5) (2017-06-21)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.2.4...v1.2.5)\n\n**Closed issues:**\n\n- Cannot read property 'user' of undefined - lib\\socket\\update-entity.js:26:104 [\\#529](https://github.com/feathersjs/authentication/issues/529)\n- Provider is undefined when using restrictToRoles [\\#525](https://github.com/feathersjs/authentication/issues/525)\n- How to make a request to an Endpoint that requires authentication from nodejs? [\\#523](https://github.com/feathersjs/authentication/issues/523)\n\n**Merged pull requests:**\n\n- fixes several issues with update-entity w/ test cases [\\#531](https://github.com/feathersjs/authentication/pull/531) ([jerfowler](https://github.com/jerfowler))\n\n## [v1.2.4](https://github.com/feathersjs/authentication/tree/v1.2.4) (2017-06-08)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.2.3...v1.2.4)\n\n**Fixed bugs:**\n\n- User \\(Entity\\) needs to be updated on the socket after authentication [\\#293](https://github.com/feathersjs/authentication/issues/293)\n\n**Closed issues:**\n\n- Express Middleware local -\\> jwt does not authorize on redirect [\\#518](https://github.com/feathersjs/authentication/issues/518)\n- Issue with feathers-authentication [\\#512](https://github.com/feathersjs/authentication/issues/512)\n- User Authentication Missing Credentials error \\(and subsequent nav authorization\\) [\\#508](https://github.com/feathersjs/authentication/issues/508)\n- passport log failure [\\#505](https://github.com/feathersjs/authentication/issues/505)\n- authenticate with a custom username field \\(rather than email\\) [\\#502](https://github.com/feathersjs/authentication/issues/502)\n- app.get\\('auth'\\) vs app.get\\('authentication'\\) [\\#497](https://github.com/feathersjs/authentication/issues/497)\n- Can't get success authorization with pure feathers server [\\#491](https://github.com/feathersjs/authentication/issues/491)\n\n**Merged pull requests:**\n\n- Test and fix for authenticate event with invalid data [\\#524](https://github.com/feathersjs/authentication/pull/524) ([daffl](https://github.com/daffl))\n- Remove hook.data.payload [\\#522](https://github.com/feathersjs/authentication/pull/522) ([marshallswain](https://github.com/marshallswain))\n- Update socket entity [\\#521](https://github.com/feathersjs/authentication/pull/521) ([marshallswain](https://github.com/marshallswain))\n- Made each option, optional [\\#515](https://github.com/feathersjs/authentication/pull/515) ([cranesandcaff](https://github.com/cranesandcaff))\n- Add feathers-authentication-hooks in readme [\\#510](https://github.com/feathersjs/authentication/pull/510) ([bertho-zero](https://github.com/bertho-zero))\n- Update ms to the latest version 🚀 [\\#509](https://github.com/feathersjs/authentication/pull/509) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Fix default authentication config keys [\\#506](https://github.com/feathersjs/authentication/pull/506) ([ekryski](https://github.com/ekryski))\n\n## [v1.2.3](https://github.com/feathersjs/authentication/tree/v1.2.3) (2017-05-10)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.2.2...v1.2.3)\n\n**Closed issues:**\n\n- Validating custom express routes [\\#498](https://github.com/feathersjs/authentication/issues/498)\n- Payload won't include userId when logging in with stored localStorage token [\\#496](https://github.com/feathersjs/authentication/issues/496)\n- How to send oauth token authentication to another client server [\\#493](https://github.com/feathersjs/authentication/issues/493)\n- Unhandled Promise Rejection error. [\\#489](https://github.com/feathersjs/authentication/issues/489)\n- No Auth token on authentication resource [\\#488](https://github.com/feathersjs/authentication/issues/488)\n- How to verify JWT in feathers issued by another feathers instance ? [\\#484](https://github.com/feathersjs/authentication/issues/484)\n- hook.params.user [\\#483](https://github.com/feathersjs/authentication/issues/483)\n- Overriding JWT's expiresIn with a value more than 20d prevents users from signing in [\\#458](https://github.com/feathersjs/authentication/issues/458)\n\n**Merged pull requests:**\n\n- Update feathers-socketio to the latest version 🚀 [\\#503](https://github.com/feathersjs/authentication/pull/503) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update socket.io-client to the latest version 🚀 [\\#501](https://github.com/feathersjs/authentication/pull/501) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Fix issue with very large token timeout. [\\#499](https://github.com/feathersjs/authentication/pull/499) ([asdacap](https://github.com/asdacap))\n- Typo [\\#492](https://github.com/feathersjs/authentication/pull/492) ([wdmtech](https://github.com/wdmtech))\n- Update migrating.md [\\#490](https://github.com/feathersjs/authentication/pull/490) ([MichaelErmer](https://github.com/MichaelErmer))\n- Update semistandard to the latest version 🚀 [\\#487](https://github.com/feathersjs/authentication/pull/487) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update feathers-hooks to the latest version 🚀 [\\#485](https://github.com/feathersjs/authentication/pull/485) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update dependencies to enable Greenkeeper 🌴 [\\#482](https://github.com/feathersjs/authentication/pull/482) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.2.2](https://github.com/feathersjs/authentication/tree/v1.2.2) (2017-04-12)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.2.1...v1.2.2)\n\n**Fixed bugs:**\n\n- accessToken not being used when provided by client over socketio [\\#400](https://github.com/feathersjs/authentication/issues/400)\n\n**Closed issues:**\n\n- Incompatible old client dependency [\\#479](https://github.com/feathersjs/authentication/issues/479)\n- Using feathers-authentication-client for an existing API? [\\#478](https://github.com/feathersjs/authentication/issues/478)\n- app.authenticate error : UnhandledPromiseRejectionWarning: Unhandled promise rejection \\(rejection id: 2\\): \\* Error \\* [\\#476](https://github.com/feathersjs/authentication/issues/476)\n- Make `socket.feathers` data available in authentication hooks [\\#475](https://github.com/feathersjs/authentication/issues/475)\n- Allow the authenticate hook to be called with no parameters [\\#473](https://github.com/feathersjs/authentication/issues/473)\n- Authenticate : How to return more infos ? [\\#471](https://github.com/feathersjs/authentication/issues/471)\n\n**Merged pull requests:**\n\n- Use latest version of feathers-authentication-client [\\#480](https://github.com/feathersjs/authentication/pull/480) ([daffl](https://github.com/daffl))\n- Resolves \\#475 - Socket params are made available to authentication hooks [\\#477](https://github.com/feathersjs/authentication/pull/477) ([thomas-p-wilson](https://github.com/thomas-p-wilson))\n\n## [v1.2.1](https://github.com/feathersjs/authentication/tree/v1.2.1) (2017-04-07)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.2.0...v1.2.1)\n\n**Fixed bugs:**\n\n- failureRedirect is never used when using with oauth2 [\\#387](https://github.com/feathersjs/authentication/issues/387)\n\n**Closed issues:**\n\n- OAuth guides [\\#470](https://github.com/feathersjs/authentication/issues/470)\n- app.authenticate not working [\\#466](https://github.com/feathersjs/authentication/issues/466)\n- how can I logout using local authentication? [\\#465](https://github.com/feathersjs/authentication/issues/465)\n- How to do Socket.io Authentication [\\#462](https://github.com/feathersjs/authentication/issues/462)\n- Add event filtering by default \\(socket.io\\) [\\#460](https://github.com/feathersjs/authentication/issues/460)\n- Add ability to control if socket is marked as authenticated. [\\#448](https://github.com/feathersjs/authentication/issues/448)\n- Auth redirect issue [\\#425](https://github.com/feathersjs/authentication/issues/425)\n- E-mail verification step can be bypassed using Postman or Curl [\\#391](https://github.com/feathersjs/authentication/issues/391)\n- Example app [\\#386](https://github.com/feathersjs/authentication/issues/386)\n\n**Merged pull requests:**\n\n- Allow the cookie to be set if action is not `remove` [\\#474](https://github.com/feathersjs/authentication/pull/474) ([marshallswain](https://github.com/marshallswain))\n\n## [v1.2.0](https://github.com/feathersjs/authentication/tree/v1.2.0) (2017-03-23)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.1.1...v1.2.0)\n\n**Fixed bugs:**\n\n- 1.0 authentication service hooks don't run when client uses feathers-socketio [\\#455](https://github.com/feathersjs/authentication/issues/455)\n- `hook.params.provider` is not set when calling `client.authenticate\\(\\)` [\\#432](https://github.com/feathersjs/authentication/issues/432)\n- remove method failed with JsonWebTokenError: invalid token [\\#388](https://github.com/feathersjs/authentication/issues/388)\n\n**Closed issues:**\n\n- Token creation has side effect [\\#454](https://github.com/feathersjs/authentication/issues/454)\n- Question: When is userId set? [\\#453](https://github.com/feathersjs/authentication/issues/453)\n- How to authenticate SPA? More precisely how does the redirect works? [\\#451](https://github.com/feathersjs/authentication/issues/451)\n- POST to auth/facebook for FacebookTokenStrategy 404? [\\#447](https://github.com/feathersjs/authentication/issues/447)\n- feathers-authentication 1.1.1 `No auth token` [\\#445](https://github.com/feathersjs/authentication/issues/445)\n- Another readme incorrect and maybe docs to [\\#441](https://github.com/feathersjs/authentication/issues/441)\n- Readme incorrect and maybe docs to [\\#440](https://github.com/feathersjs/authentication/issues/440)\n- npm version issue? [\\#439](https://github.com/feathersjs/authentication/issues/439)\n- setCookie express middleware only works inside hooks [\\#438](https://github.com/feathersjs/authentication/issues/438)\n- createJWT throws 'secret must provided' [\\#437](https://github.com/feathersjs/authentication/issues/437)\n- Not useful error message on NotAuthenticated error [\\#436](https://github.com/feathersjs/authentication/issues/436)\n- Passwordfeld in auth.local does not work as expected [\\#435](https://github.com/feathersjs/authentication/issues/435)\n- Authentication via REST returns token without finding user on db [\\#430](https://github.com/feathersjs/authentication/issues/430)\n\n**Merged pull requests:**\n\n- Filter out all events [\\#461](https://github.com/feathersjs/authentication/pull/461) ([daffl](https://github.com/daffl))\n- Fix socket auth [\\#459](https://github.com/feathersjs/authentication/pull/459) ([marshallswain](https://github.com/marshallswain))\n- Fix \\#454 Token create has side effect [\\#456](https://github.com/feathersjs/authentication/pull/456) ([whollacsek](https://github.com/whollacsek))\n- Windows compatible version of the original compile comand with public folder support. [\\#442](https://github.com/feathersjs/authentication/pull/442) ([appurist](https://github.com/appurist))\n- Add client.js back for consistency [\\#433](https://github.com/feathersjs/authentication/pull/433) ([daffl](https://github.com/daffl))\n- add string to authenticate \\(typescript\\) [\\#431](https://github.com/feathersjs/authentication/pull/431) ([superbarne](https://github.com/superbarne))\n- Add support for Bearer scheme in remove method [\\#403](https://github.com/feathersjs/authentication/pull/403) ([boybundit](https://github.com/boybundit))\n\n## [v1.1.1](https://github.com/feathersjs/authentication/tree/v1.1.1) (2017-03-02)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.1.0...v1.1.1)\n\n**Closed issues:**\n\n- Authentication over socket.io never answers [\\#428](https://github.com/feathersjs/authentication/issues/428)\n\n**Merged pull requests:**\n\n- Remove lots of hardcoded values for config, and adds the `authenticate` hook [\\#427](https://github.com/feathersjs/authentication/pull/427) ([myknbani](https://github.com/myknbani))\n\n## [v1.1.0](https://github.com/feathersjs/authentication/tree/v1.1.0) (2017-03-01)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.0.2...v1.1.0)\n\n**Fixed bugs:**\n\n- Mongo update error after logging into Facebook [\\#244](https://github.com/feathersjs/authentication/issues/244)\n\n**Closed issues:**\n\n- Feature Request: Anonymous Authentication Strategy Support [\\#423](https://github.com/feathersjs/authentication/issues/423)\n- Error is not thrown if token that is provided is invalid [\\#421](https://github.com/feathersjs/authentication/issues/421)\n- Request body 'token' parameter disappears [\\#420](https://github.com/feathersjs/authentication/issues/420)\n- Auth2 issue getting JWT token from server when different ports [\\#416](https://github.com/feathersjs/authentication/issues/416)\n- Cookie-based authentication with XHR is not possible [\\#413](https://github.com/feathersjs/authentication/issues/413)\n- JWT Authentication setup failing [\\#411](https://github.com/feathersjs/authentication/issues/411)\n- how to disable service for external usage in version 1.0 [\\#410](https://github.com/feathersjs/authentication/issues/410)\n- v1.0 is removed from npm? [\\#408](https://github.com/feathersjs/authentication/issues/408)\n- Make JWT data more configurable [\\#407](https://github.com/feathersjs/authentication/issues/407)\n- Possible typo [\\#406](https://github.com/feathersjs/authentication/issues/406)\n- Authentication with an existing database with existing hashed \\(md5\\) passwords [\\#398](https://github.com/feathersjs/authentication/issues/398)\n- can modify selected fields only [\\#397](https://github.com/feathersjs/authentication/issues/397)\n- \\[Discussion\\] Migrating to 1.0 - hook changes [\\#396](https://github.com/feathersjs/authentication/issues/396)\n- feathers-authentication 'local' strategy requires token? [\\#394](https://github.com/feathersjs/authentication/issues/394)\n- JWT for local auth. [\\#390](https://github.com/feathersjs/authentication/issues/390)\n- Feathers 'Twitter API' style [\\#385](https://github.com/feathersjs/authentication/issues/385)\n- Missing code in example app [\\#383](https://github.com/feathersjs/authentication/issues/383)\n- feathers-authentication errors with any view error, and redirects to /auth/failure [\\#381](https://github.com/feathersjs/authentication/issues/381)\n- what does app.service\\('authentication'\\).remove\\(...\\) mean? [\\#379](https://github.com/feathersjs/authentication/issues/379)\n- Rest Endpoints. [\\#375](https://github.com/feathersjs/authentication/issues/375)\n- cordova google-plus signUp with id_token [\\#373](https://github.com/feathersjs/authentication/issues/373)\n- How to reconnect socket with cookie after page refresh ? [\\#372](https://github.com/feathersjs/authentication/issues/372)\n- Error: Could not find stored JWT and no authentication strategy was given [\\#367](https://github.com/feathersjs/authentication/issues/367)\n- \"No auth token\" using authenticate strategy: 'jwt' \\(v.1.0.0-beta-2\\) [\\#366](https://github.com/feathersjs/authentication/issues/366)\n- Navigating to /auth/\\<provider\\> twice redirects to /auth/failed [\\#344](https://github.com/feathersjs/authentication/issues/344)\n- Meteor auth migration guide [\\#334](https://github.com/feathersjs/authentication/issues/334)\n- Auth 1.0 [\\#330](https://github.com/feathersjs/authentication/issues/330)\n- RSA token secret [\\#309](https://github.com/feathersjs/authentication/issues/309)\n- Add option to use bcrypt [\\#300](https://github.com/feathersjs/authentication/issues/300)\n- Better example of how to change hashing algorithm? \\[Question\\] [\\#289](https://github.com/feathersjs/authentication/issues/289)\n- issuer doesn't work [\\#284](https://github.com/feathersjs/authentication/issues/284)\n- passport auth question [\\#274](https://github.com/feathersjs/authentication/issues/274)\n- Add support for authenticating active users only [\\#259](https://github.com/feathersjs/authentication/issues/259)\n- 404 response from populateUser\\(\\) hook [\\#258](https://github.com/feathersjs/authentication/issues/258)\n- Responses hang when token.secret is undefined for local authentication [\\#249](https://github.com/feathersjs/authentication/issues/249)\n- Authentication without password [\\#246](https://github.com/feathersjs/authentication/issues/246)\n- Fix successRedirect to not override cookie path [\\#243](https://github.com/feathersjs/authentication/issues/243)\n- Deprecate verifyToken and populateUser hooks in favour of middleware [\\#227](https://github.com/feathersjs/authentication/issues/227)\n- Authenticating and creating [\\#100](https://github.com/feathersjs/authentication/issues/100)\n- Add a password service [\\#83](https://github.com/feathersjs/authentication/issues/83)\n\n**Merged pull requests:**\n\n- Fix JWT options typo [\\#415](https://github.com/feathersjs/authentication/pull/415) ([daffl](https://github.com/daffl))\n- Prevent setCookie from mutating authOptions [\\#414](https://github.com/feathersjs/authentication/pull/414) ([adrien-k](https://github.com/adrien-k))\n- Typescript Definitions [\\#412](https://github.com/feathersjs/authentication/pull/412) ([AbraaoAlves](https://github.com/AbraaoAlves))\n- Docs for migrating to auth.hooks.authenticate hook [\\#399](https://github.com/feathersjs/authentication/pull/399) ([petermikitsh](https://github.com/petermikitsh))\n- Typo 'cookie.enable' should be 'cookie.enabled' [\\#380](https://github.com/feathersjs/authentication/pull/380) ([whollacsek](https://github.com/whollacsek))\n- Docs: Equalize usage of feathers-authenticate [\\#378](https://github.com/feathersjs/authentication/pull/378) ([eikaramba](https://github.com/eikaramba))\n\n## [v1.0.2](https://github.com/feathersjs/authentication/tree/v1.0.2) (2016-12-14)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.0.1...v1.0.2)\n\n**Closed issues:**\n\n- successRedirect not redirecting [\\#364](https://github.com/feathersjs/authentication/issues/364)\n\n## [v1.0.1](https://github.com/feathersjs/authentication/tree/v1.0.1) (2016-12-14)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.0.0...v1.0.1)\n\n## [v1.0.0](https://github.com/feathersjs/authentication/tree/v1.0.0) (2016-12-14)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.12...v1.0.0)\n\n**Fixed bugs:**\n\n- restrictToOwner does not support multi patch, update and remove [\\#228](https://github.com/feathersjs/authentication/issues/228)\n\n**Closed issues:**\n\n- auth.express.authenticate got undefined [\\#363](https://github.com/feathersjs/authentication/issues/363)\n- Non-standard header structure [\\#361](https://github.com/feathersjs/authentication/issues/361)\n- localEndpoint without local strategy [\\#359](https://github.com/feathersjs/authentication/issues/359)\n- Using custom passport strategies [\\#356](https://github.com/feathersjs/authentication/issues/356)\n- Client-side app.on\\('login'\\) [\\#355](https://github.com/feathersjs/authentication/issues/355)\n- Payload limiting on `app.get\\('user'\\)`? [\\#354](https://github.com/feathersjs/authentication/issues/354)\n- Authentication token is missing [\\#352](https://github.com/feathersjs/authentication/issues/352)\n- \\[1.0\\] The entity on the socket should pull from the strategy options. [\\#348](https://github.com/feathersjs/authentication/issues/348)\n- \\[1.0\\] Only the first failure is returned on auth failure when chaining multiple strategies [\\#346](https://github.com/feathersjs/authentication/issues/346)\n- Build 0.7.11 does not contain current code on NPMJS [\\#342](https://github.com/feathersjs/authentication/issues/342)\n- feathers-authentication branch 0.8 did not work with payload \\(tested on socket\\) [\\#264](https://github.com/feathersjs/authentication/issues/264)\n- Add method for updating JWT [\\#260](https://github.com/feathersjs/authentication/issues/260)\n- 1.0 architecture considerations [\\#226](https://github.com/feathersjs/authentication/issues/226)\n- Features/RFC [\\#213](https://github.com/feathersjs/authentication/issues/213)\n- Support access_token based OAuth2 providers [\\#169](https://github.com/feathersjs/authentication/issues/169)\n- Support openID [\\#154](https://github.com/feathersjs/authentication/issues/154)\n- Disable cookie by default if not using OAuth [\\#152](https://github.com/feathersjs/authentication/issues/152)\n- Add token service tests [\\#144](https://github.com/feathersjs/authentication/issues/144)\n- Add local service tests [\\#143](https://github.com/feathersjs/authentication/issues/143)\n- Add OAuth2 service tests [\\#142](https://github.com/feathersjs/authentication/issues/142)\n- Add OAuth2 integration tests [\\#141](https://github.com/feathersjs/authentication/issues/141)\n- Add integration tests for custom redirects [\\#125](https://github.com/feathersjs/authentication/issues/125)\n- Support mobile authentication via OAuth1 [\\#47](https://github.com/feathersjs/authentication/issues/47)\n- Support OAuth1 [\\#42](https://github.com/feathersjs/authentication/issues/42)\n- Password-less Local Auth with Email / SMS [\\#7](https://github.com/feathersjs/authentication/issues/7)\n\n**Merged pull requests:**\n\n- migrating to semistandard [\\#371](https://github.com/feathersjs/authentication/pull/371) ([ekryski](https://github.com/ekryski))\n- Logout should always give a response. [\\#369](https://github.com/feathersjs/authentication/pull/369) ([marshallswain](https://github.com/marshallswain))\n- Clarify that the authenticate hook is required. [\\#368](https://github.com/feathersjs/authentication/pull/368) ([marshallswain](https://github.com/marshallswain))\n- Fix README example [\\#365](https://github.com/feathersjs/authentication/pull/365) ([saiberz](https://github.com/saiberz))\n- Remove additional deprecation notice [\\#362](https://github.com/feathersjs/authentication/pull/362) ([porsager](https://github.com/porsager))\n- fix typo [\\#360](https://github.com/feathersjs/authentication/pull/360) ([osenvosem](https://github.com/osenvosem))\n- Update feathers-primus to version 2.0.0 🚀 [\\#358](https://github.com/feathersjs/authentication/pull/358) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Create .codeclimate.yml [\\#357](https://github.com/feathersjs/authentication/pull/357) ([larkinscott](https://github.com/larkinscott))\n- fixing redirect middleware [\\#353](https://github.com/feathersjs/authentication/pull/353) ([ekryski](https://github.com/ekryski))\n- Remove useless quotes [\\#351](https://github.com/feathersjs/authentication/pull/351) ([bertho-zero](https://github.com/bertho-zero))\n- A bunch of bug fixes [\\#349](https://github.com/feathersjs/authentication/pull/349) ([ekryski](https://github.com/ekryski))\n- fix\\(docs/new-features\\): syntax highlighting [\\#347](https://github.com/feathersjs/authentication/pull/347) ([justingreenberg](https://github.com/justingreenberg))\n- Update superagent to version 3.0.0 🚀 [\\#345](https://github.com/feathersjs/authentication/pull/345) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-memory to version 1.0.0 🚀 [\\#343](https://github.com/feathersjs/authentication/pull/343) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- 1.0 Pre-release [\\#336](https://github.com/feathersjs/authentication/pull/336) ([ekryski](https://github.com/ekryski))\n\n## [v0.7.12](https://github.com/feathersjs/authentication/tree/v0.7.12) (2016-11-11)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.11...v0.7.12)\n\n**Closed issues:**\n\n- App.authenticate uses wrong `this` reference [\\#341](https://github.com/feathersjs/authentication/issues/341)\n- Getting more done in GitHub with ZenHub [\\#331](https://github.com/feathersjs/authentication/issues/331)\n- Need help to use feathers authentication storage in vue vuex [\\#329](https://github.com/feathersjs/authentication/issues/329)\n- How to get user id in hooks? [\\#322](https://github.com/feathersjs/authentication/issues/322)\n- I checked out my new feathersjs app in another machine, created a new user but I can't log in! [\\#320](https://github.com/feathersjs/authentication/issues/320)\n- restrict-to-owner throws error when user id is 0 [\\#319](https://github.com/feathersjs/authentication/issues/319)\n- Not providing sufficient details for an auth provider should not be an error. [\\#318](https://github.com/feathersjs/authentication/issues/318)\n- \\[Question\\] Is there a way to verify a user with password? [\\#316](https://github.com/feathersjs/authentication/issues/316)\n- 0.8.0 beta 1 bug - this is not defined [\\#315](https://github.com/feathersjs/authentication/issues/315)\n- Client: Document getJWT & verifyJWT [\\#313](https://github.com/feathersjs/authentication/issues/313)\n- Socket client should automatically auth on reconnect [\\#310](https://github.com/feathersjs/authentication/issues/310)\n- app.get\\('token'\\) doesn't work after a browser refresh. [\\#303](https://github.com/feathersjs/authentication/issues/303)\n- Problem issuing multiple jwt's for the same user [\\#302](https://github.com/feathersjs/authentication/issues/302)\n- restrict-to-owner does not allow Service.remove\\(null\\) from internal systems [\\#301](https://github.com/feathersjs/authentication/issues/301)\n- How to migrate from restrictToOwner to checkPermissions [\\#299](https://github.com/feathersjs/authentication/issues/299)\n- \"username\" cannot be used as local strategy usernameField [\\#294](https://github.com/feathersjs/authentication/issues/294)\n- Bad Hook API Design: Hooks are inconsistent and impure functions [\\#288](https://github.com/feathersjs/authentication/issues/288)\n- Mutliple 'user' models for authentication [\\#282](https://github.com/feathersjs/authentication/issues/282)\n- Client should ensure socket.io upgrade is complete before authenticating [\\#275](https://github.com/feathersjs/authentication/issues/275)\n- JWT is not sent after socket reconnection [\\#272](https://github.com/feathersjs/authentication/issues/272)\n- 401 after service is moved/refactored [\\#270](https://github.com/feathersjs/authentication/issues/270)\n- Client side auth should subscribe to user updates so that app.get\\('user'\\) is fresh [\\#195](https://github.com/feathersjs/authentication/issues/195)\n- Make oauth2 more general [\\#179](https://github.com/feathersjs/authentication/issues/179)\n- Add integration tests for custom service endpoints [\\#145](https://github.com/feathersjs/authentication/issues/145)\n- Create a `requireAuth` wrapper for `verifyToken`, `populateUser`, `restrictToAuth` [\\#118](https://github.com/feathersjs/authentication/issues/118)\n\n**Merged pull requests:**\n\n- babel-core@6.18.2 breaks build 🚨 [\\#339](https://github.com/feathersjs/authentication/pull/339) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- 👻😱 Node.js 0.10 is unmaintained 😱👻 [\\#337](https://github.com/feathersjs/authentication/pull/337) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- restrictToOwner -Fix check for methodNotAllowed [\\#335](https://github.com/feathersjs/authentication/pull/335) ([daffl](https://github.com/daffl))\n- Implement login and logout events for REST authentication [\\#325](https://github.com/feathersjs/authentication/pull/325) ([daffl](https://github.com/daffl))\n- Socket.io authentication tests and login logout event [\\#324](https://github.com/feathersjs/authentication/pull/324) ([daffl](https://github.com/daffl))\n- Reorganization [\\#321](https://github.com/feathersjs/authentication/pull/321) ([ekryski](https://github.com/ekryski))\n- client: use Authentication class, make `getJWT` and `verifyJWT` async [\\#317](https://github.com/feathersjs/authentication/pull/317) ([marshallswain](https://github.com/marshallswain))\n- 0.8 client decode jwt [\\#314](https://github.com/feathersjs/authentication/pull/314) ([marshallswain](https://github.com/marshallswain))\n- Store config at `app.config` [\\#312](https://github.com/feathersjs/authentication/pull/312) ([marshallswain](https://github.com/marshallswain))\n- Cookies will match jwt expiry by default. [\\#308](https://github.com/feathersjs/authentication/pull/308) ([marshallswain](https://github.com/marshallswain))\n- Remove permissions hooks and middleware [\\#307](https://github.com/feathersjs/authentication/pull/307) ([daffl](https://github.com/daffl))\n- First cut for authentication middleware [\\#305](https://github.com/feathersjs/authentication/pull/305) ([daffl](https://github.com/daffl))\n- 0.8 - OAuth fixes [\\#304](https://github.com/feathersjs/authentication/pull/304) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.7.11](https://github.com/feathersjs/authentication/tree/v0.7.11) (2016-09-28)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.10...v0.7.11)\n\n**Closed issues:**\n\n- Unable to authenticate with passport-google-oauth20 [\\#295](https://github.com/feathersjs/authentication/issues/295)\n- \"Unauthorized\" Response with Hook Data [\\#291](https://github.com/feathersjs/authentication/issues/291)\n- hashPassword in patch [\\#286](https://github.com/feathersjs/authentication/issues/286)\n- Mobile App Facebook Login [\\#276](https://github.com/feathersjs/authentication/issues/276)\n- Socket user should update automatically [\\#266](https://github.com/feathersjs/authentication/issues/266)\n- Get user outside a service [\\#261](https://github.com/feathersjs/authentication/issues/261)\n\n**Merged pull requests:**\n\n- hashPassword fall-through if there's no password [\\#287](https://github.com/feathersjs/authentication/pull/287) ([marshallswain](https://github.com/marshallswain))\n- Update feathers-memory to version 0.8.0 🚀 [\\#285](https://github.com/feathersjs/authentication/pull/285) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Allow multiple username fields for local auth [\\#283](https://github.com/feathersjs/authentication/pull/283) ([sdbondi](https://github.com/sdbondi))\n\n## [v0.7.10](https://github.com/feathersjs/authentication/tree/v0.7.10) (2016-08-31)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.9...v0.7.10)\n\n**Fixed bugs:**\n\n- restrictToOwner should not throw an error on mass deletions [\\#175](https://github.com/feathersjs/authentication/issues/175)\n\n**Closed issues:**\n\n- Duplicate Email should be rejected by Default [\\#281](https://github.com/feathersjs/authentication/issues/281)\n- Auth0 & featherjs authorization only [\\#277](https://github.com/feathersjs/authentication/issues/277)\n- Cannot read property 'scope' of undefined [\\#273](https://github.com/feathersjs/authentication/issues/273)\n- Socker.js | Custom successHandler [\\#271](https://github.com/feathersjs/authentication/issues/271)\n- Use feathers-socketio? and rest&socket share session maybe? [\\#269](https://github.com/feathersjs/authentication/issues/269)\n- Ability to invalidate old token/session when user login with another machine. [\\#267](https://github.com/feathersjs/authentication/issues/267)\n- 0.8 authentication before hooks - only ever getting a 401 Unauthorised [\\#263](https://github.com/feathersjs/authentication/issues/263)\n- REST Middleware breaks local auth [\\#262](https://github.com/feathersjs/authentication/issues/262)\n- 0.8: Token Service errors on token auth using client [\\#254](https://github.com/feathersjs/authentication/issues/254)\n- 0.8: Cookies, turning off feathers-session cookie also turns off feathers-jwt cookie. [\\#253](https://github.com/feathersjs/authentication/issues/253)\n- Any example of how to do refresh token? [\\#248](https://github.com/feathersjs/authentication/issues/248)\n- Custom Authentication Hooks [\\#236](https://github.com/feathersjs/authentication/issues/236)\n- Is there an Authenticated Event [\\#235](https://github.com/feathersjs/authentication/issues/235)\n- Error while using /auth/local [\\#233](https://github.com/feathersjs/authentication/issues/233)\n- Providing token to feathers.authentication doesn't work [\\#230](https://github.com/feathersjs/authentication/issues/230)\n- bundled hooks customize errors [\\#215](https://github.com/feathersjs/authentication/issues/215)\n- Hooks should support a callback for conditionally running [\\#210](https://github.com/feathersjs/authentication/issues/210)\n- restrictToRoles hook: More complex determination of \"owner\". [\\#205](https://github.com/feathersjs/authentication/issues/205)\n- verifyToken hook option to error [\\#200](https://github.com/feathersjs/authentication/issues/200)\n- Allow using restrictToOwner as an after hook [\\#123](https://github.com/feathersjs/authentication/issues/123)\n\n**Merged pull requests:**\n\n- Manually supply an endpoint to the Client authenticate\\(\\) method [\\#278](https://github.com/feathersjs/authentication/pull/278) ([mcnamee](https://github.com/mcnamee))\n- Update mocha to version 3.0.0 🚀 [\\#257](https://github.com/feathersjs/authentication/pull/257) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Don’t mix options when signing tokens [\\#255](https://github.com/feathersjs/authentication/pull/255) ([marshallswain](https://github.com/marshallswain))\n- Attempt to get token right away. [\\#252](https://github.com/feathersjs/authentication/pull/252) ([marshallswain](https://github.com/marshallswain))\n- Update async to version 2.0.0 🚀 [\\#240](https://github.com/feathersjs/authentication/pull/240) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Creates better way or returning data in a familiar format [\\#234](https://github.com/feathersjs/authentication/pull/234) ([codingfriend1](https://github.com/codingfriend1))\n- Throws an error if restriction methods are used outside of a find or get hook [\\#232](https://github.com/feathersjs/authentication/pull/232) ([codingfriend1](https://github.com/codingfriend1))\n- RestrictToOwner now takes an array [\\#231](https://github.com/feathersjs/authentication/pull/231) ([sscaff1](https://github.com/sscaff1))\n- Adds ability to limit queries unless authenticated and authorized [\\#229](https://github.com/feathersjs/authentication/pull/229) ([codingfriend1](https://github.com/codingfriend1))\n\n## [v0.7.9](https://github.com/feathersjs/authentication/tree/v0.7.9) (2016-06-20)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.8...v0.7.9)\n\n**Fixed bugs:**\n\n- Calling logout should revoke/blacklist a JWT [\\#133](https://github.com/feathersjs/authentication/issues/133)\n\n**Closed issues:**\n\n- Query email rather than oauth provider id on /auth/\\<provider\\> [\\#223](https://github.com/feathersjs/authentication/issues/223)\n- Cannot read property \\'service\\' of undefined [\\#222](https://github.com/feathersjs/authentication/issues/222)\n\n**Merged pull requests:**\n\n- added support for hashing passwords when hook.data is an array [\\#225](https://github.com/feathersjs/authentication/pull/225) ([eblin](https://github.com/eblin))\n- jwt ssl warning [\\#214](https://github.com/feathersjs/authentication/pull/214) ([aboutlo](https://github.com/aboutlo))\n\n## [v0.7.8](https://github.com/feathersjs/authentication/tree/v0.7.8) (2016-06-09)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.7...v0.7.8)\n\n**Closed issues:**\n\n- Feathers-authentication assumptions [\\#220](https://github.com/feathersjs/authentication/issues/220)\n- Server-side header option does not accept capital letters [\\#218](https://github.com/feathersjs/authentication/issues/218)\n- How to figure out why redirect to /auth/failure? [\\#217](https://github.com/feathersjs/authentication/issues/217)\n- Getting token via REST is not documented [\\#216](https://github.com/feathersjs/authentication/issues/216)\n- How to use Feathers Client to Authenticate Facebook/Instagram credentials [\\#204](https://github.com/feathersjs/authentication/issues/204)\n- Remove token from localstorage [\\#203](https://github.com/feathersjs/authentication/issues/203)\n- Check user password [\\#193](https://github.com/feathersjs/authentication/issues/193)\n- app.authenticate\\(\\): Warning: a promise was rejected with a non-error: \\[object Object\\] [\\#191](https://github.com/feathersjs/authentication/issues/191)\n- Authentication provider for Facebook Account Kit [\\#189](https://github.com/feathersjs/authentication/issues/189)\n\n**Merged pull requests:**\n\n- Lowercase custom header [\\#219](https://github.com/feathersjs/authentication/pull/219) ([mmwtsn](https://github.com/mmwtsn))\n- mocha@2.5.0 breaks build 🚨 [\\#212](https://github.com/feathersjs/authentication/pull/212) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Small refactoring to simplify structure and remove code duplication [\\#209](https://github.com/feathersjs/authentication/pull/209) ([daffl](https://github.com/daffl))\n- Use removeItem in the storage on logout [\\#208](https://github.com/feathersjs/authentication/pull/208) ([daffl](https://github.com/daffl))\n- Misspelled in a comment [\\#201](https://github.com/feathersjs/authentication/pull/201) ([tryy3](https://github.com/tryy3))\n- Update babel-plugin-add-module-exports to version 0.2.0 🚀 [\\#199](https://github.com/feathersjs/authentication/pull/199) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v0.7.7](https://github.com/feathersjs/authentication/tree/v0.7.7) (2016-05-05)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.6...v0.7.7)\n\n**Fixed bugs:**\n\n- OAuth2 authentication callback failing due to missing property [\\#196](https://github.com/feathersjs/authentication/issues/196)\n\n**Merged pull requests:**\n\n- properly handle optional `\\_json` property [\\#197](https://github.com/feathersjs/authentication/pull/197) ([nyaaao](https://github.com/nyaaao))\n\n## [v0.7.6](https://github.com/feathersjs/authentication/tree/v0.7.6) (2016-05-03)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.5...v0.7.6)\n\n**Fixed bugs:**\n\n- Facebook Authentication should do a patch not an update. [\\#174](https://github.com/feathersjs/authentication/issues/174)\n\n**Closed issues:**\n\n- Authenticated user [\\#192](https://github.com/feathersjs/authentication/issues/192)\n- REST token revoke [\\#185](https://github.com/feathersjs/authentication/issues/185)\n- TypeError: Cannot read property 'service' of undefined [\\#173](https://github.com/feathersjs/authentication/issues/173)\n- Optionally Include password in the params.query object passed to User.find\\(\\) [\\#171](https://github.com/feathersjs/authentication/issues/171)\n- Pass more to local authentication params [\\#165](https://github.com/feathersjs/authentication/issues/165)\n- Support custom authentication strategies [\\#157](https://github.com/feathersjs/authentication/issues/157)\n\n**Merged pull requests:**\n\n- Allow manipulation of params before checking credentials [\\#186](https://github.com/feathersjs/authentication/pull/186) ([saiichihashimoto](https://github.com/saiichihashimoto))\n- Update feathers to version 2.0.1 🚀 [\\#184](https://github.com/feathersjs/authentication/pull/184) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- fix\\(oauth2\\): Use patch to update user in oauthCallback [\\#183](https://github.com/feathersjs/authentication/pull/183) ([beevelop](https://github.com/beevelop))\n\n## [v0.7.5](https://github.com/feathersjs/authentication/tree/v0.7.5) (2016-04-23)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.4...v0.7.5)\n\n**Fixed bugs:**\n\n- restrictToOwner and restrictToRoles have invalid type checking [\\#172](https://github.com/feathersjs/authentication/issues/172)\n\n**Closed issues:**\n\n- user fails to signup with facebook if there is also local auth [\\#168](https://github.com/feathersjs/authentication/issues/168)\n- Unable to authenticate requests when using vanilla Socket.IO [\\#166](https://github.com/feathersjs/authentication/issues/166)\n\n## [v0.7.4](https://github.com/feathersjs/authentication/tree/v0.7.4) (2016-04-18)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.3...v0.7.4)\n\n**Fixed bugs:**\n\n- restrictToOwner and restrictToRoles hooks don't work with nested models [\\#163](https://github.com/feathersjs/authentication/issues/163)\n- Change restrictToOwner error when a request does not contain ID [\\#160](https://github.com/feathersjs/authentication/issues/160)\n\n**Closed issues:**\n\n- authenticate\\(\\) can leak sensetive user data via token service [\\#162](https://github.com/feathersjs/authentication/issues/162)\n- onBeforeLogin Hook [\\#161](https://github.com/feathersjs/authentication/issues/161)\n\n**Merged pull requests:**\n\n- Hook fixes [\\#164](https://github.com/feathersjs/authentication/pull/164) ([ekryski](https://github.com/ekryski))\n\n## [v0.7.3](https://github.com/feathersjs/authentication/tree/v0.7.3) (2016-04-16)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.2...v0.7.3)\n\n## [v0.7.2](https://github.com/feathersjs/authentication/tree/v0.7.2) (2016-04-16)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.1...v0.7.2)\n\n**Closed issues:**\n\n- Auth doesn't work with non default local.userEndpoint [\\#159](https://github.com/feathersjs/authentication/issues/159)\n- Automatically add the hashPassword hook to local.userEndpoint [\\#158](https://github.com/feathersjs/authentication/issues/158)\n- Client authentication\\(\\) storage option not documented [\\#155](https://github.com/feathersjs/authentication/issues/155)\n- restrictToRoles availability inconsistency [\\#153](https://github.com/feathersjs/authentication/issues/153)\n- Does not populate user for other services [\\#150](https://github.com/feathersjs/authentication/issues/150)\n\n**Merged pull requests:**\n\n- Steal Compatibility [\\#156](https://github.com/feathersjs/authentication/pull/156) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.7.1](https://github.com/feathersjs/authentication/tree/v0.7.1) (2016-04-08)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.7.0...v0.7.1)\n\n**Closed issues:**\n\n- Documentation discrepancies [\\#148](https://github.com/feathersjs/authentication/issues/148)\n- bcrypt is hardcoded [\\#146](https://github.com/feathersjs/authentication/issues/146)\n- Update Docs, Guides, Examples for v0.7 [\\#129](https://github.com/feathersjs/authentication/issues/129)\n- populateUser: allow option to populate without db call. [\\#92](https://github.com/feathersjs/authentication/issues/92)\n\n**Merged pull requests:**\n\n- Update feathers-memory to version 0.7.0 🚀 [\\#149](https://github.com/feathersjs/authentication/pull/149) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- fix a typo [\\#147](https://github.com/feathersjs/authentication/pull/147) ([chrjean](https://github.com/chrjean))\n- Fix copy paste typo in queryWithCurrentUser hook. [\\#140](https://github.com/feathersjs/authentication/pull/140) ([juodumas](https://github.com/juodumas))\n\n## [v0.7.0](https://github.com/feathersjs/authentication/tree/v0.7.0) (2016-03-30)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.6.0...v0.7.0)\n\n**Fixed bugs:**\n\n- logout should de-authenticate a socket [\\#136](https://github.com/feathersjs/authentication/issues/136)\n- \\[Security\\] JsonWebToken Lifecycle Concerns; Set HttpOnly = true in JWT cookie [\\#132](https://github.com/feathersjs/authentication/issues/132)\n- restrictToRoles hook needs to throw an error and not scope the query [\\#128](https://github.com/feathersjs/authentication/issues/128)\n- restrictToOwner hook needs to throw an error and not scope the query [\\#127](https://github.com/feathersjs/authentication/issues/127)\n- \\[security\\] Generated tokens are broadcast to all socket clients \\(by default\\) [\\#126](https://github.com/feathersjs/authentication/issues/126)\n- \\[oAuth\\] User profile should be updated every time they are authenticated [\\#124](https://github.com/feathersjs/authentication/issues/124)\n- Logout should clear the cookie [\\#122](https://github.com/feathersjs/authentication/issues/122)\n- Want the default success/fail routes, not the sendFile [\\#121](https://github.com/feathersjs/authentication/issues/121)\n\n**Closed issues:**\n\n- Make all hooks optional if used internally [\\#138](https://github.com/feathersjs/authentication/issues/138)\n- Throw errors for deprecated hooks and update documentation [\\#134](https://github.com/feathersjs/authentication/issues/134)\n- v6.0.0: How can I return the user object along with the token ? [\\#131](https://github.com/feathersjs/authentication/issues/131)\n- user field not getting populated [\\#119](https://github.com/feathersjs/authentication/issues/119)\n- Move to bcryptjs [\\#112](https://github.com/feathersjs/authentication/issues/112)\n- Bundled hooks should pull from auth config to avoid having to pass duplicate props. [\\#93](https://github.com/feathersjs/authentication/issues/93)\n- Customize the JWT payload [\\#78](https://github.com/feathersjs/authentication/issues/78)\n- Needs a test for verifying that a custom tokenEndpoint works. [\\#59](https://github.com/feathersjs/authentication/issues/59)\n- Finish test coverage for existing features. [\\#9](https://github.com/feathersjs/authentication/issues/9)\n\n**Merged pull requests:**\n\n- 0.7 Release [\\#139](https://github.com/feathersjs/authentication/pull/139) ([ekryski](https://github.com/ekryski))\n\n## [v0.6.0](https://github.com/feathersjs/authentication/tree/v0.6.0) (2016-03-24)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.5.1...v0.6.0)\n\n**Fixed bugs:**\n\n- Token encoding is not using the idField option. [\\#107](https://github.com/feathersjs/authentication/issues/107)\n- Logging out breaks in React Native [\\#105](https://github.com/feathersjs/authentication/issues/105)\n- Updating User Attached to Params in Client [\\#102](https://github.com/feathersjs/authentication/issues/102)\n- local auth should not redirect by default [\\#89](https://github.com/feathersjs/authentication/issues/89)\n\n**Closed issues:**\n\n- Id of user can't be 0 for auth [\\#116](https://github.com/feathersjs/authentication/issues/116)\n- how to authenticate user in the socket.io? [\\#111](https://github.com/feathersjs/authentication/issues/111)\n- Wrong Status Error [\\#110](https://github.com/feathersjs/authentication/issues/110)\n- TypeError: Cannot read property 'service' of undefined \\(continued\\) [\\#108](https://github.com/feathersjs/authentication/issues/108)\n- `idField` breaks from `tokenService.create\\(\\)` to `populateUser\\(\\)` after hook [\\#103](https://github.com/feathersjs/authentication/issues/103)\n\n**Merged pull requests:**\n\n- Bcryptjs [\\#137](https://github.com/feathersjs/authentication/pull/137) ([ekryski](https://github.com/ekryski))\n- Allow user.id to be 0. Fixes \\#116 [\\#117](https://github.com/feathersjs/authentication/pull/117) ([marshallswain](https://github.com/marshallswain))\n- client should return a 401 error code when no token is provided [\\#115](https://github.com/feathersjs/authentication/pull/115) ([ccummings](https://github.com/ccummings))\n- v0.6 - Bugs fixes, new hooks, and hook tests [\\#109](https://github.com/feathersjs/authentication/pull/109) ([ekryski](https://github.com/ekryski))\n- primus client connect event is 'open' [\\#106](https://github.com/feathersjs/authentication/pull/106) ([ahdinosaur](https://github.com/ahdinosaur))\n\n## [v0.5.1](https://github.com/feathersjs/authentication/tree/v0.5.1) (2016-03-15)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.5.0...v0.5.1)\n\n## [v0.5.0](https://github.com/feathersjs/authentication/tree/v0.5.0) (2016-03-14)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.4.1...v0.5.0)\n\n**Fixed bugs:**\n\n- Client should store token string and not the token object [\\#95](https://github.com/feathersjs/authentication/issues/95)\n\n**Closed issues:**\n\n- using feathers-rest/client with feathers-authentication/client [\\#94](https://github.com/feathersjs/authentication/issues/94)\n- populateUser can pull defaults from config, if available. [\\#91](https://github.com/feathersjs/authentication/issues/91)\n- App level auth routes for multiple sub-routes [\\#90](https://github.com/feathersjs/authentication/issues/90)\n- POST to /auth/local never gets response [\\#88](https://github.com/feathersjs/authentication/issues/88)\n- populate-user.js do not get settings [\\#86](https://github.com/feathersjs/authentication/issues/86)\n- Add rate limiting [\\#81](https://github.com/feathersjs/authentication/issues/81)\n\n**Merged pull requests:**\n\n- Finalizing client side authentication module [\\#101](https://github.com/feathersjs/authentication/pull/101) ([daffl](https://github.com/daffl))\n- Ten hours is only 36 seconds [\\#99](https://github.com/feathersjs/authentication/pull/99) ([mileswilson](https://github.com/mileswilson))\n- Fix examples [\\#98](https://github.com/feathersjs/authentication/pull/98) ([mastertinner](https://github.com/mastertinner))\n- fix html in templates [\\#97](https://github.com/feathersjs/authentication/pull/97) ([mastertinner](https://github.com/mastertinner))\n- update populateUser\\(\\) hook [\\#87](https://github.com/feathersjs/authentication/pull/87) ([kulakowka](https://github.com/kulakowka))\n- Customize the JWT payload [\\#80](https://github.com/feathersjs/authentication/pull/80) ([enten](https://github.com/enten))\n\n## [v0.4.1](https://github.com/feathersjs/authentication/tree/v0.4.1) (2016-02-28)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.4.0...v0.4.1)\n\n**Fixed bugs:**\n\n- app.logout\\(\\) fails [\\#85](https://github.com/feathersjs/authentication/issues/85)\n\n**Closed issues:**\n\n- Username response ? [\\#84](https://github.com/feathersjs/authentication/issues/84)\n- User doesn't get populated after authentication with databases that don't use \\_id [\\#71](https://github.com/feathersjs/authentication/issues/71)\n- Support client usage in NodeJS [\\#52](https://github.com/feathersjs/authentication/issues/52)\n- Support async storage for React Native [\\#51](https://github.com/feathersjs/authentication/issues/51)\n- RequireAdmin on userService [\\#36](https://github.com/feathersjs/authentication/issues/36)\n- Create test for changing the `usernameField` [\\#1](https://github.com/feathersjs/authentication/issues/1)\n\n## [v0.4.0](https://github.com/feathersjs/authentication/tree/v0.4.0) (2016-02-27)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.3.5...v0.4.0)\n\n**Closed issues:**\n\n- Authentication not worked with hooks.remove\\('password'\\) [\\#82](https://github.com/feathersjs/authentication/issues/82)\n\n**Merged pull requests:**\n\n- Refactoring for storage service [\\#76](https://github.com/feathersjs/authentication/pull/76) ([ekryski](https://github.com/ekryski))\n\n## [v0.3.5](https://github.com/feathersjs/authentication/tree/v0.3.5) (2016-02-25)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.3.4...v0.3.5)\n\n**Merged pull requests:**\n\n- Adding support for OAuth2 token based auth strategies. Closes \\#46. [\\#77](https://github.com/feathersjs/authentication/pull/77) ([ekryski](https://github.com/ekryski))\n\n## [v0.3.4](https://github.com/feathersjs/authentication/tree/v0.3.4) (2016-02-25)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.3.3...v0.3.4)\n\n## [v0.3.3](https://github.com/feathersjs/authentication/tree/v0.3.3) (2016-02-25)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.3.2...v0.3.3)\n\n## [v0.3.2](https://github.com/feathersjs/authentication/tree/v0.3.2) (2016-02-24)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.3.1...v0.3.2)\n\n**Merged pull requests:**\n\n- bumping feathers-errors version [\\#79](https://github.com/feathersjs/authentication/pull/79) ([ekryski](https://github.com/ekryski))\n\n## [v0.3.1](https://github.com/feathersjs/authentication/tree/v0.3.1) (2016-02-23)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.3.0...v0.3.1)\n\n**Closed issues:**\n\n- Fix toLowerCase hook [\\#74](https://github.com/feathersjs/authentication/issues/74)\n- REST auth/local not working if socketio\\(\\) not set [\\#72](https://github.com/feathersjs/authentication/issues/72)\n- Support mobile authentication via OAuth2 [\\#46](https://github.com/feathersjs/authentication/issues/46)\n\n**Merged pull requests:**\n\n- Fix toLowerCase hook [\\#75](https://github.com/feathersjs/authentication/pull/75) ([enten](https://github.com/enten))\n\n## [v0.3.0](https://github.com/feathersjs/authentication/tree/v0.3.0) (2016-02-19)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.2.4...v0.3.0)\n\n**Fixed bugs:**\n\n- Don't register successRedirect route if custom one is passed in [\\#61](https://github.com/feathersjs/authentication/issues/61)\n\n**Closed issues:**\n\n- Specify the secret in one place instead of two [\\#69](https://github.com/feathersjs/authentication/issues/69)\n- support a failRedirect [\\#62](https://github.com/feathersjs/authentication/issues/62)\n- Document authentication updates [\\#50](https://github.com/feathersjs/authentication/issues/50)\n\n**Merged pull requests:**\n\n- Config options [\\#70](https://github.com/feathersjs/authentication/pull/70) ([ekryski](https://github.com/ekryski))\n\n## [v0.2.4](https://github.com/feathersjs/authentication/tree/v0.2.4) (2016-02-17)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.2.3...v0.2.4)\n\n**Closed issues:**\n\n- Find \"query\" is replaced by token [\\#64](https://github.com/feathersjs/authentication/issues/64)\n\n**Merged pull requests:**\n\n- Add module exports Babel module and test CommonJS compatibility [\\#68](https://github.com/feathersjs/authentication/pull/68) ([daffl](https://github.com/daffl))\n\n## [v0.2.3](https://github.com/feathersjs/authentication/tree/v0.2.3) (2016-02-15)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.2.2...v0.2.3)\n\n**Closed issues:**\n\n- How to forbid get and find on the userEndpoint? [\\#66](https://github.com/feathersjs/authentication/issues/66)\n- userEndpoint problem in sub-app [\\#63](https://github.com/feathersjs/authentication/issues/63)\n- How to modify successRedirect in local authentication? [\\#60](https://github.com/feathersjs/authentication/issues/60)\n\n**Merged pull requests:**\n\n- Removing assigning token to params.query for sockets. [\\#67](https://github.com/feathersjs/authentication/pull/67) ([ekryski](https://github.com/ekryski))\n- Fixing client query [\\#65](https://github.com/feathersjs/authentication/pull/65) ([fastlorenzo](https://github.com/fastlorenzo))\n\n## [v0.2.2](https://github.com/feathersjs/authentication/tree/v0.2.2) (2016-02-13)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.2.1...v0.2.2)\n\n**Closed issues:**\n\n- Custom tokenEndpoint failing [\\#57](https://github.com/feathersjs/authentication/issues/57)\n- TypeError: Cannot read property 'service' of undefined [\\#56](https://github.com/feathersjs/authentication/issues/56)\n- Login returns 500: Internal server error [\\#54](https://github.com/feathersjs/authentication/issues/54)\n\n**Merged pull requests:**\n\n- Fixing token endpoint [\\#58](https://github.com/feathersjs/authentication/pull/58) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.2.1](https://github.com/feathersjs/authentication/tree/v0.2.1) (2016-02-12)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.2.0...v0.2.1)\n\n**Closed issues:**\n\n- Custom local options not being respected. [\\#55](https://github.com/feathersjs/authentication/issues/55)\n- node can not require\\(\"feathers-authentication\"\\).default [\\#53](https://github.com/feathersjs/authentication/issues/53)\n\n## [v0.2.0](https://github.com/feathersjs/authentication/tree/v0.2.0) (2016-02-12)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.1.2...v0.2.0)\n\n**Closed issues:**\n\n- Support graceful fallback to cookies [\\#45](https://github.com/feathersjs/authentication/issues/45)\n- Add a client side component for authentication [\\#44](https://github.com/feathersjs/authentication/issues/44)\n- Support OAuth2 [\\#43](https://github.com/feathersjs/authentication/issues/43)\n- Support token based authentication [\\#41](https://github.com/feathersjs/authentication/issues/41)\n- Support local authentication [\\#40](https://github.com/feathersjs/authentication/issues/40)\n- Only sign the JWT with user id. Not the whole user object [\\#38](https://github.com/feathersjs/authentication/issues/38)\n- Discussion: Securing token for socket.io auth [\\#33](https://github.com/feathersjs/authentication/issues/33)\n- Handling expired tokens [\\#25](https://github.com/feathersjs/authentication/issues/25)\n- Support multiple auth providers [\\#6](https://github.com/feathersjs/authentication/issues/6)\n\n**Merged pull requests:**\n\n- Decoupling [\\#49](https://github.com/feathersjs/authentication/pull/49) ([ekryski](https://github.com/ekryski))\n- Adding an auth client [\\#48](https://github.com/feathersjs/authentication/pull/48) ([ekryski](https://github.com/ekryski))\n- Validate if provider [\\#39](https://github.com/feathersjs/authentication/pull/39) ([mastertinner](https://github.com/mastertinner))\n\n## [v0.1.2](https://github.com/feathersjs/authentication/tree/v0.1.2) (2016-02-04)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.1.1...v0.1.2)\n\n**Closed issues:**\n\n- Hooks should support incoming data as arrays of objects. [\\#34](https://github.com/feathersjs/authentication/issues/34)\n- Support authenticating with Username and Password via sockets [\\#32](https://github.com/feathersjs/authentication/issues/32)\n\n**Merged pull requests:**\n\n- Check for params.provider in requireAuth hook [\\#37](https://github.com/feathersjs/authentication/pull/37) ([marshallswain](https://github.com/marshallswain))\n- safety check for data [\\#35](https://github.com/feathersjs/authentication/pull/35) ([deanmcpherson](https://github.com/deanmcpherson))\n\n## [v0.1.1](https://github.com/feathersjs/authentication/tree/v0.1.1) (2016-01-30)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.1.0...v0.1.1)\n\n## [v0.1.0](https://github.com/feathersjs/authentication/tree/v0.1.0) (2016-01-25)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.0.8...v0.1.0)\n\n**Closed issues:**\n\n- Get the Travis build to work. [\\#27](https://github.com/feathersjs/authentication/issues/27)\n- Login not working [\\#24](https://github.com/feathersjs/authentication/issues/24)\n- Hooks should be configurable \\(they should be functions\\) [\\#11](https://github.com/feathersjs/authentication/issues/11)\n- Document the bundled hooks. [\\#10](https://github.com/feathersjs/authentication/issues/10)\n\n**Merged pull requests:**\n\n- Migrate docs to book [\\#31](https://github.com/feathersjs/authentication/pull/31) ([marshallswain](https://github.com/marshallswain))\n- hashPassword: Async bcrypt usage needs a promise [\\#30](https://github.com/feathersjs/authentication/pull/30) ([marshallswain](https://github.com/marshallswain))\n- Removing extras from travis.yml [\\#29](https://github.com/feathersjs/authentication/pull/29) ([marshallswain](https://github.com/marshallswain))\n- Fixing build [\\#28](https://github.com/feathersjs/authentication/pull/28) ([marshallswain](https://github.com/marshallswain))\n- Adding nsp check [\\#26](https://github.com/feathersjs/authentication/pull/26) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.0.8](https://github.com/feathersjs/authentication/tree/v0.0.8) (2016-01-16)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.0.7...v0.0.8)\n\n**Merged pull requests:**\n\n- Support services that use pagination. [\\#23](https://github.com/feathersjs/authentication/pull/23) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.0.7](https://github.com/feathersjs/authentication/tree/v0.0.7) (2016-01-07)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.0.6...v0.0.7)\n\n**Closed issues:**\n\n- Password isn't removed from responses when using a mongoose service for users endpoint [\\#19](https://github.com/feathersjs/authentication/issues/19)\n- next called twice using socket.io and using an unauthenticated service [\\#17](https://github.com/feathersjs/authentication/issues/17)\n- Switch to a callback-based field configuration? [\\#15](https://github.com/feathersjs/authentication/issues/15)\n- Cannot authenticate [\\#14](https://github.com/feathersjs/authentication/issues/14)\n- Allow require without `.default` [\\#13](https://github.com/feathersjs/authentication/issues/13)\n- Login validation [\\#2](https://github.com/feathersjs/authentication/issues/2)\n\n**Merged pull requests:**\n\n- Adding separate route for refreshing a login token. [\\#21](https://github.com/feathersjs/authentication/pull/21) ([corymsmith](https://github.com/corymsmith))\n- Converting user model to object when using mongoose service [\\#20](https://github.com/feathersjs/authentication/pull/20) ([corymsmith](https://github.com/corymsmith))\n- Fixing issue where next is called twice when hitting an unauthenticated service via socket.io [\\#18](https://github.com/feathersjs/authentication/pull/18) ([corymsmith](https://github.com/corymsmith))\n- Fixing usage of mongoose service [\\#16](https://github.com/feathersjs/authentication/pull/16) ([corymsmith](https://github.com/corymsmith))\n\n## [v0.0.6](https://github.com/feathersjs/authentication/tree/v0.0.6) (2015-11-22)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.0.5...v0.0.6)\n\n**Closed issues:**\n\n- Feathers Auth Configuration Error [\\#12](https://github.com/feathersjs/authentication/issues/12)\n- Make sure we're returning proper error responses. [\\#8](https://github.com/feathersjs/authentication/issues/8)\n\n## [v0.0.5](https://github.com/feathersjs/authentication/tree/v0.0.5) (2015-11-19)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.0.4...v0.0.5)\n\n## [v0.0.4](https://github.com/feathersjs/authentication/tree/v0.0.4) (2015-11-19)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v0.0.3...v0.0.4)\n\n## [v0.0.3](https://github.com/feathersjs/authentication/tree/v0.0.3) (2015-11-18)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.0.6...v0.0.3)\n\n**Merged pull requests:**\n\n- allow runtime auth via socket.io [\\#4](https://github.com/feathersjs/authentication/pull/4) ([randomnerd](https://github.com/randomnerd))\n\n## [v1.0.6](https://github.com/feathersjs/authentication/tree/v1.0.6) (2015-11-02)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.0.5...v1.0.6)\n\n## [v1.0.5](https://github.com/feathersjs/authentication/tree/v1.0.5) (2015-11-02)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.0.4...v1.0.5)\n\n## [v1.0.4](https://github.com/feathersjs/authentication/tree/v1.0.4) (2015-11-02)\n\n[Full Changelog](https://github.com/feathersjs/authentication/compare/v1.0.3...v1.0.4)\n\n## [v1.0.3](https://github.com/feathersjs/authentication/tree/v1.0.3) (2015-10-12)\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/authentication/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/authentication/README.md",
    "content": "# @feathersjs/authentication\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/authentication.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/authentication)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Add Authentication to your FeathersJS app.\n\n## Installation\n\n```\nnpm install @feathersjs/authentication --save\n```\n\n## Documentation\n\nRefer to the [Feathers authentication API documentation](https://feathersjs.com/api/authentication/) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/authentication/package.json",
    "content": "{\n  \"name\": \"@feathersjs/authentication\",\n  \"description\": \"Add Authentication to your FeathersJS app.\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/authentication\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@feathersjs/hooks\": \"^0.9.0\",\n    \"@feathersjs/schema\": \"^5.0.42\",\n    \"@feathersjs/transport-commons\": \"^5.0.42\",\n    \"@types/jsonwebtoken\": \"^9.0.10\",\n    \"jsonwebtoken\": \"^9.0.3\",\n    \"lodash\": \"^4.17.23\",\n    \"long-timeout\": \"^0.1.1\",\n    \"uuid\": \"^11.1.0\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/memory\": \"^5.0.42\",\n    \"@types/lodash\": \"^4.17.24\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"@types/uuid\": \"^10.0.0\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/authentication/src/core.ts",
    "content": "import merge from 'lodash/merge'\nimport jsonwebtoken, { SignOptions, Secret, VerifyOptions, Algorithm } from 'jsonwebtoken'\nimport { v4 as uuidv4 } from 'uuid'\nimport { NotAuthenticated } from '@feathersjs/errors'\nimport { createDebug } from '@feathersjs/commons'\nimport { Application, Params } from '@feathersjs/feathers'\nimport { IncomingMessage, ServerResponse } from 'http'\nimport { AuthenticationConfiguration, defaultOptions } from './options'\n\nconst debug = createDebug('@feathersjs/authentication/base')\n\nexport interface AuthenticationResult {\n  [key: string]: any\n}\n\nexport interface AuthenticationRequest {\n  strategy?: string\n  [key: string]: any\n}\n\nexport interface AuthenticationParams extends Params {\n  payload?: { [key: string]: any }\n  jwtOptions?: SignOptions\n  authStrategies?: string[]\n  secret?: string\n  [key: string]: any\n}\n\nexport type ConnectionEvent = 'login' | 'logout' | 'disconnect'\n\nexport interface AuthenticationStrategy {\n  /**\n   * Implement this method to get access to the AuthenticationService\n   *\n   * @param auth The AuthenticationService\n   */\n  setAuthentication?(auth: AuthenticationBase): void\n  /**\n   * Implement this method to get access to the Feathers application\n   *\n   * @param app The Feathers application instance\n   */\n  setApplication?(app: Application): void\n  /**\n   * Implement this method to get access to the strategy name\n   *\n   * @param name The name of the strategy\n   */\n  setName?(name: string): void\n  /**\n   * Implement this method to verify the current configuration\n   * and throw an error if it is invalid.\n   */\n  verifyConfiguration?(): void\n  /**\n   * Implement this method to setup this strategy\n   * @param auth The AuthenticationService\n   * @param name The name of the strategy\n   */\n  setup?(auth: AuthenticationBase, name: string): Promise<void>\n  /**\n   * Authenticate an authentication request with this strategy.\n   * Should throw an error if the strategy did not succeed.\n   *\n   * @param authentication The authentication request\n   * @param params The service call parameters\n   */\n  authenticate?(\n    authentication: AuthenticationRequest,\n    params: AuthenticationParams\n  ): Promise<AuthenticationResult>\n  /**\n   * Update a real-time connection according to this strategy.\n   *\n   * @param connection The real-time connection\n   * @param context The hook context\n   */\n  handleConnection?(event: ConnectionEvent, connection: any, authResult?: AuthenticationResult): Promise<void>\n  /**\n   * Parse a basic HTTP request and response for authentication request information.\n   *\n   * @param req The HTTP request\n   * @param res The HTTP response\n   */\n  parse?(req: IncomingMessage, res: ServerResponse): Promise<AuthenticationRequest | null>\n}\n\nexport interface JwtVerifyOptions extends VerifyOptions {\n  algorithm?: string | string[]\n}\n\n/**\n * A base class for managing authentication strategies and creating and verifying JWTs\n */\nexport class AuthenticationBase {\n  app: Application\n  strategies: { [key: string]: AuthenticationStrategy }\n  configKey: string\n  isReady: boolean\n\n  /**\n   * Create a new authentication service.\n   *\n   * @param app The Feathers application instance\n   * @param configKey The configuration key name in `app.get` (default: `authentication`)\n   * @param options Optional initial options\n   */\n  constructor(app: Application, configKey = 'authentication', options = {}) {\n    if (!app || typeof app.use !== 'function') {\n      throw new Error('An application instance has to be passed to the authentication service')\n    }\n\n    this.app = app\n    this.strategies = {}\n    this.configKey = configKey\n    this.isReady = false\n\n    app.set('defaultAuthentication', app.get('defaultAuthentication') || configKey)\n    app.set(configKey, merge({}, app.get(configKey), options))\n  }\n\n  /**\n   * Return the current configuration from the application\n   */\n  get configuration(): AuthenticationConfiguration {\n    // Always returns a copy of the authentication configuration\n    return Object.assign({}, defaultOptions, this.app.get(this.configKey))\n  }\n\n  /**\n   * A list of all registered strategy names\n   */\n  get strategyNames() {\n    return Object.keys(this.strategies)\n  }\n\n  /**\n   * Register a new authentication strategy under a given name.\n   *\n   * @param name The name to register the strategy under\n   * @param strategy The authentication strategy instance\n   */\n  register(name: string, strategy: AuthenticationStrategy) {\n    // Call the functions a strategy can implement\n    if (typeof strategy.setName === 'function') {\n      strategy.setName(name)\n    }\n\n    if (typeof strategy.setApplication === 'function') {\n      strategy.setApplication(this.app)\n    }\n\n    if (typeof strategy.setAuthentication === 'function') {\n      strategy.setAuthentication(this)\n    }\n\n    if (typeof strategy.verifyConfiguration === 'function') {\n      strategy.verifyConfiguration()\n    }\n\n    // Register strategy as name\n    this.strategies[name] = strategy\n\n    if (this.isReady) {\n      strategy.setup?.(this, name)\n    }\n  }\n\n  /**\n   * Get the registered authentication strategies for a list of names.\n   *\n   * @param names The list or strategy names\n   */\n  getStrategies(...names: string[]) {\n    return names.map((name) => this.strategies[name]).filter((current) => !!current)\n  }\n\n  /**\n   * Returns a single strategy by name\n   *\n   * @param name The strategy name\n   * @returns The authentication strategy or undefined\n   */\n  getStrategy(name: string) {\n    return this.strategies[name]\n  }\n\n  /**\n   * Create a new access token with payload and options.\n   *\n   * @param payload The JWT payload\n   * @param optsOverride The options to extend the defaults (`configuration.jwtOptions`) with\n   * @param secretOverride Use a different secret instead\n   */\n  async createAccessToken(\n    payload: string | Buffer | object,\n    optsOverride?: SignOptions,\n    secretOverride?: Secret\n  ) {\n    const { secret, jwtOptions } = this.configuration\n    // Use configuration by default but allow overriding the secret\n    const jwtSecret = secretOverride || secret\n    // Default jwt options merged with additional options\n    const options = merge({}, jwtOptions, optsOverride)\n\n    if (!options.jwtid) {\n      // Generate a UUID as JWT ID by default\n      options.jwtid = uuidv4()\n    }\n\n    return jsonwebtoken.sign(payload, jwtSecret, options)\n  }\n\n  /**\n   * Verifies an access token.\n   *\n   * @param accessToken The token to verify\n   * @param optsOverride The options to extend the defaults (`configuration.jwtOptions`) with\n   * @param secretOverride Use a different secret instead\n   */\n  async verifyAccessToken(accessToken: string, optsOverride?: JwtVerifyOptions, secretOverride?: Secret) {\n    const { secret, jwtOptions } = this.configuration\n    const jwtSecret = secretOverride || secret\n    const options = merge({}, jwtOptions, optsOverride)\n    const { algorithm } = options\n\n    // Normalize the `algorithm` setting into the algorithms array\n    if (algorithm && !options.algorithms) {\n      options.algorithms = (Array.isArray(algorithm) ? algorithm : [algorithm]) as Algorithm[]\n      delete options.algorithm\n    }\n\n    try {\n      const verified = jsonwebtoken.verify(accessToken, jwtSecret, options)\n\n      return verified as any\n    } catch (error: any) {\n      throw new NotAuthenticated(error.message, error)\n    }\n  }\n\n  /**\n   * Authenticate a given authentication request against a list of strategies.\n   *\n   * @param authentication The authentication request\n   * @param params Service call parameters\n   * @param allowed A list of allowed strategy names\n   */\n  async authenticate(\n    authentication: AuthenticationRequest,\n    params: AuthenticationParams,\n    ...allowed: string[]\n  ) {\n    const { strategy } = authentication || {}\n    const [authStrategy] = this.getStrategies(strategy)\n    const strategyAllowed = allowed.includes(strategy)\n\n    debug('Running authenticate for strategy', strategy, allowed)\n\n    if (!authentication || !authStrategy || !strategyAllowed) {\n      const additionalInfo =\n        (!strategy && ' (no `strategy` set)') ||\n        (!strategyAllowed && ' (strategy not allowed in authStrategies)') ||\n        ''\n\n      // If there are no valid strategies or `authentication` is not an object\n      throw new NotAuthenticated('Invalid authentication information' + additionalInfo)\n    }\n\n    return authStrategy.authenticate(authentication, {\n      ...params,\n      authenticated: true\n    })\n  }\n\n  async handleConnection(event: ConnectionEvent, connection: any, authResult?: AuthenticationResult) {\n    const strategies = this.getStrategies(...Object.keys(this.strategies)).filter(\n      (current) => typeof current.handleConnection === 'function'\n    )\n\n    for (const strategy of strategies) {\n      await strategy.handleConnection(event, connection, authResult)\n    }\n  }\n\n  /**\n   * Parse an HTTP request and response for authentication request information.\n   *\n   * @param req The HTTP request\n   * @param res The HTTP response\n   * @param names A list of strategies to use\n   */\n  async parse(req: IncomingMessage, res: ServerResponse, ...names: string[]) {\n    const strategies = this.getStrategies(...names).filter((current) => typeof current.parse === 'function')\n\n    debug('Strategies parsing HTTP header for authentication information', names)\n\n    for (const authStrategy of strategies) {\n      const value = await authStrategy.parse(req, res)\n\n      if (value !== null) {\n        return value\n      }\n    }\n\n    return null\n  }\n\n  async setup() {\n    this.isReady = true\n\n    for (const name of Object.keys(this.strategies)) {\n      const strategy = this.strategies[name]\n\n      await strategy.setup?.(this, name)\n    }\n  }\n}\n"
  },
  {
    "path": "packages/authentication/src/hooks/authenticate.ts",
    "content": "import { HookContext, NextFunction } from '@feathersjs/feathers'\nimport { NotAuthenticated } from '@feathersjs/errors'\nimport { createDebug } from '@feathersjs/commons'\n\nconst debug = createDebug('@feathersjs/authentication/hooks/authenticate')\n\nexport interface AuthenticateHookSettings {\n  service?: string\n  strategies?: string[]\n}\n\nexport default (originalSettings: string | AuthenticateHookSettings, ...originalStrategies: string[]) => {\n  const settings =\n    typeof originalSettings === 'string'\n      ? { strategies: [originalSettings, ...originalStrategies] }\n      : originalSettings\n\n  if (!originalSettings || settings.strategies.length === 0) {\n    throw new Error('The authenticate hook needs at least one allowed strategy')\n  }\n\n  return async (context: HookContext, _next?: NextFunction) => {\n    const next = typeof _next === 'function' ? _next : async () => context\n    const { app, params, type, path, service } = context\n    const { strategies } = settings\n    const { provider, authentication } = params\n    const authService = app.defaultAuthentication(settings.service)\n\n    debug(`Running authenticate hook on '${path}'`)\n\n    if (type && type !== 'before' && type !== 'around') {\n      throw new NotAuthenticated('The authenticate hook must be used as a before hook')\n    }\n\n    if (!authService || typeof authService.authenticate !== 'function') {\n      throw new NotAuthenticated('Could not find a valid authentication service')\n    }\n\n    if (service === authService) {\n      throw new NotAuthenticated(\n        'The authenticate hook does not need to be used on the authentication service'\n      )\n    }\n\n    if (params.authenticated === true) {\n      return next()\n    }\n\n    if (authentication) {\n      const { provider, authentication, ...authParams } = params\n\n      debug('Authenticating with', authentication, strategies)\n\n      const authResult = await authService.authenticate(authentication, authParams, ...strategies)\n\n      const { accessToken, ...authResultWithoutToken } = authResult\n\n      context.params = {\n        ...params,\n        ...authResultWithoutToken,\n        authenticated: true\n      }\n    } else if (provider) {\n      throw new NotAuthenticated('Not authenticated')\n    }\n\n    return next()\n  }\n}\n"
  },
  {
    "path": "packages/authentication/src/hooks/connection.ts",
    "content": "import { HookContext, NextFunction } from '@feathersjs/feathers'\nimport { AuthenticationBase, ConnectionEvent } from '../core'\n\nexport default (event: ConnectionEvent) => async (context: HookContext, next: NextFunction) => {\n  await next()\n\n  const {\n    result,\n    params: { connection }\n  } = context\n\n  if (connection) {\n    const service = context.service as unknown as AuthenticationBase\n\n    await service.handleConnection(event, connection, result)\n  }\n}\n"
  },
  {
    "path": "packages/authentication/src/hooks/event.ts",
    "content": "import { HookContext, NextFunction } from '@feathersjs/feathers'\nimport { createDebug } from '@feathersjs/commons'\nimport { ConnectionEvent } from '../core'\n\nconst debug = createDebug('@feathersjs/authentication/hooks/connection')\n\nexport default (event: ConnectionEvent) => async (context: HookContext, next: NextFunction) => {\n  await next()\n\n  const { app, result, params } = context\n\n  if (params.provider && result) {\n    debug(`Sending authentication event '${event}'`)\n    app.emit(event, result, params, context)\n  }\n}\n"
  },
  {
    "path": "packages/authentication/src/hooks/index.ts",
    "content": "export { default as authenticate } from './authenticate'\nexport { default as connection } from './connection'\nexport { default as event } from './event'\n"
  },
  {
    "path": "packages/authentication/src/index.ts",
    "content": "export * as hooks from './hooks'\nexport { authenticate } from './hooks'\nexport {\n  AuthenticationBase,\n  AuthenticationRequest,\n  AuthenticationResult,\n  AuthenticationStrategy,\n  AuthenticationParams,\n  ConnectionEvent,\n  JwtVerifyOptions\n} from './core'\nexport { AuthenticationBaseStrategy } from './strategy'\nexport { AuthenticationService } from './service'\nexport { JWTStrategy } from './jwt'\nexport { authenticationSettingsSchema, AuthenticationConfiguration } from './options'\n"
  },
  {
    "path": "packages/authentication/src/jwt.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/ban-ts-comment */\nimport { IncomingMessage } from 'http'\nimport { NotAuthenticated } from '@feathersjs/errors'\nimport { Params } from '@feathersjs/feathers'\nimport { createDebug } from '@feathersjs/commons'\n// @ts-ignore\nimport lt from 'long-timeout'\n\nimport { AuthenticationBaseStrategy } from './strategy'\nimport { AuthenticationParams, AuthenticationRequest, AuthenticationResult, ConnectionEvent } from './core'\n\nconst debug = createDebug('@feathersjs/authentication/jwt')\nconst SPLIT_HEADER = /(\\S+)\\s+(\\S+)/\n\nexport class JWTStrategy extends AuthenticationBaseStrategy {\n  expirationTimers = new WeakMap()\n\n  get configuration() {\n    const authConfig = this.authentication.configuration\n    const config = super.configuration\n\n    return {\n      service: authConfig.service,\n      entity: authConfig.entity,\n      entityId: authConfig.entityId,\n      header: 'Authorization',\n      schemes: ['Bearer', 'JWT'],\n      ...config\n    }\n  }\n\n  async handleConnection(\n    event: ConnectionEvent,\n    connection: any,\n    authResult?: AuthenticationResult\n  ): Promise<void> {\n    const isValidLogout =\n      event === 'logout' &&\n      connection.authentication &&\n      authResult &&\n      connection.authentication.accessToken === authResult.accessToken\n\n    const { accessToken } = authResult || {}\n    const { entity } = this.configuration\n\n    if (accessToken && event === 'login') {\n      debug('Adding authentication information to connection')\n      const { exp } =\n        authResult?.authentication?.payload || (await this.authentication.verifyAccessToken(accessToken))\n      // The time (in ms) until the token expires\n      const duration = exp * 1000 - Date.now()\n      const timer = lt.setTimeout(() => this.app.emit('disconnect', connection), duration)\n\n      debug(`Registering connection expiration timer for ${duration}ms`)\n      lt.clearTimeout(this.expirationTimers.get(connection))\n      this.expirationTimers.set(connection, timer)\n\n      debug('Adding authentication information to connection')\n      connection.authentication = {\n        strategy: this.name,\n        accessToken\n      }\n      connection[entity] = authResult[entity]\n    } else if (event === 'disconnect' || isValidLogout) {\n      debug('Removing authentication information and expiration timer from connection')\n\n      await new Promise((resolve) =>\n        process.nextTick(() => {\n          delete connection[entity]\n          delete connection.authentication\n          resolve(connection)\n        })\n      )\n\n      lt.clearTimeout(this.expirationTimers.get(connection))\n      this.expirationTimers.delete(connection)\n    }\n  }\n\n  verifyConfiguration() {\n    const allowedKeys = ['entity', 'entityId', 'service', 'header', 'schemes']\n\n    for (const key of Object.keys(this.configuration)) {\n      if (!allowedKeys.includes(key)) {\n        throw new Error(\n          `Invalid JwtStrategy option 'authentication.${this.name}.${key}'. Did you mean to set it in 'authentication.jwtOptions'?`\n        )\n      }\n    }\n\n    if (typeof this.configuration.header !== 'string') {\n      throw new Error(`The 'header' option for the ${this.name} strategy must be a string`)\n    }\n  }\n\n  async getEntityQuery(_params: Params) {\n    return {}\n  }\n\n  /**\n   * Return the entity for a given id\n   *\n   * @param id The id to use\n   * @param params Service call parameters\n   */\n  async getEntity(id: string, params: Params) {\n    const entityService = this.entityService\n    const { entity } = this.configuration\n\n    debug('Getting entity', id)\n\n    if (entityService === null) {\n      throw new NotAuthenticated('Could not find entity service')\n    }\n\n    const query = await this.getEntityQuery(params)\n    const { provider, ...paramsWithoutProvider } = params\n    const result = await entityService.get(id, {\n      ...paramsWithoutProvider,\n      query\n    })\n\n    if (!params.provider) {\n      return result\n    }\n\n    return entityService.get(id, { ...params, [entity]: result })\n  }\n\n  async getEntityId(authResult: AuthenticationResult, _params: Params) {\n    return authResult.authentication.payload.sub\n  }\n\n  async authenticate(authentication: AuthenticationRequest, params: AuthenticationParams) {\n    const { accessToken } = authentication\n    const { entity } = this.configuration\n\n    if (!accessToken) {\n      throw new NotAuthenticated('No access token')\n    }\n\n    const payload = await this.authentication.verifyAccessToken(accessToken, params.jwt)\n    const result = {\n      accessToken,\n      authentication: {\n        strategy: 'jwt',\n        accessToken,\n        payload\n      }\n    }\n\n    if (entity === null) {\n      return result\n    }\n\n    const entityId = await this.getEntityId(result, params)\n    const value = await this.getEntity(entityId, params)\n\n    return {\n      ...result,\n      [entity]: value\n    }\n  }\n\n  async parse(req: IncomingMessage): Promise<{\n    strategy: string\n    accessToken: string\n  } | null> {\n    const { header, schemes }: { header: string; schemes: string[] } = this.configuration\n    const headerValue = req.headers && req.headers[header.toLowerCase()]\n\n    if (!headerValue || typeof headerValue !== 'string') {\n      return null\n    }\n\n    debug('Found parsed header value')\n\n    const [, scheme, schemeValue] = headerValue.match(SPLIT_HEADER) || []\n    const hasScheme = scheme && schemes.some((current) => new RegExp(current, 'i').test(scheme))\n\n    if (scheme && !hasScheme) {\n      return null\n    }\n\n    return {\n      strategy: this.name,\n      accessToken: hasScheme ? schemeValue : headerValue\n    }\n  }\n}\n"
  },
  {
    "path": "packages/authentication/src/options.ts",
    "content": "import { FromSchema, authenticationSettingsSchema } from '@feathersjs/schema'\n\nexport const defaultOptions = {\n  authStrategies: [] as string[],\n  jwtOptions: {\n    header: { typ: 'access' }, // by default is an access token but can be any type\n    audience: 'https://yourdomain.com', // The resource server where the token is processed\n    issuer: 'feathers', // The issuing server, application or resource\n    algorithm: 'HS256',\n    expiresIn: '1d'\n  }\n}\n\nexport { authenticationSettingsSchema }\n\nexport type AuthenticationConfiguration = FromSchema<typeof authenticationSettingsSchema>\n"
  },
  {
    "path": "packages/authentication/src/service.ts",
    "content": "import merge from 'lodash/merge'\nimport { NotAuthenticated } from '@feathersjs/errors'\nimport '@feathersjs/transport-commons'\nimport { createDebug } from '@feathersjs/commons'\nimport { ServiceMethods } from '@feathersjs/feathers'\nimport { resolveDispatch } from '@feathersjs/schema'\nimport jsonwebtoken from 'jsonwebtoken'\nimport { hooks } from '@feathersjs/hooks'\n\nimport { AuthenticationBase, AuthenticationResult, AuthenticationRequest, AuthenticationParams } from './core'\nimport { connection, event } from './hooks'\nimport { RealTimeConnection } from '@feathersjs/feathers'\n\nconst debug = createDebug('@feathersjs/authentication/service')\n\ndeclare module '@feathersjs/feathers/lib/declarations' {\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  interface FeathersApplication<Services, Settings> {\n    // eslint-disable-line\n    /**\n     * Returns the default authentication service or the\n     * authentication service for a given path.\n     *\n     * @param location The service path to use (optional)\n     */\n    defaultAuthentication?(location?: string): AuthenticationService\n  }\n\n  interface Params {\n    authenticated?: boolean\n    authentication?: AuthenticationRequest\n  }\n}\n\nexport class AuthenticationService\n  extends AuthenticationBase\n  implements Partial<ServiceMethods<AuthenticationResult, AuthenticationRequest, AuthenticationParams>>\n{\n  constructor(app: any, configKey = 'authentication', options = {}) {\n    super(app, configKey, options)\n\n    hooks(this, {\n      create: [resolveDispatch(), event('login'), connection('login')],\n      remove: [resolveDispatch(), event('logout'), connection('logout')]\n    })\n\n    this.app.on('disconnect', async (connection: RealTimeConnection) => {\n      await this.handleConnection('disconnect', connection)\n    })\n\n    if (typeof app.defaultAuthentication !== 'function') {\n      app.defaultAuthentication = function (location?: string) {\n        const configKey = app.get('defaultAuthentication')\n        const path =\n          location ||\n          Object.keys(this.services).find((current) => this.service(current).configKey === configKey)\n\n        return path ? this.service(path) : null\n      }\n    }\n  }\n  /**\n   * Return the payload for a JWT based on the authentication result.\n   * Called internally by the `create` method.\n   *\n   * @param _authResult The current authentication result\n   * @param params The service call parameters\n   */\n  async getPayload(_authResult: AuthenticationResult, params: AuthenticationParams) {\n    // Uses `params.payload` or returns an empty payload\n    const { payload = {} } = params\n\n    return payload\n  }\n\n  /**\n   * Returns the JWT options based on an authentication result.\n   * By default sets the JWT subject to the entity id.\n   *\n   * @param authResult The authentication result\n   * @param params Service call parameters\n   */\n  async getTokenOptions(authResult: AuthenticationResult, params: AuthenticationParams) {\n    const { service, entity, entityId } = this.configuration\n    const jwtOptions = merge({}, params.jwtOptions, params.jwt)\n    const value = service && entity && authResult[entity]\n\n    // Set the subject to the entity id if it is available\n    if (value && !jwtOptions.subject) {\n      const idProperty = entityId || this.app.service(service).id\n      const subject = value[idProperty]\n\n      if (subject === undefined) {\n        throw new NotAuthenticated(`Can not set subject from ${entity}.${idProperty}`)\n      }\n\n      jwtOptions.subject = `${subject}`\n    }\n\n    return jwtOptions\n  }\n\n  /**\n   * Create and return a new JWT for a given authentication request.\n   * Will trigger the `login` event.\n   *\n   * @param data The authentication request (should include `strategy` key)\n   * @param params Service call parameters\n   */\n  async create(data: AuthenticationRequest, params?: AuthenticationParams) {\n    const authStrategies = params.authStrategies || this.configuration.authStrategies\n\n    if (!authStrategies.length) {\n      throw new NotAuthenticated('No authentication strategies allowed for creating a JWT (`authStrategies`)')\n    }\n\n    const authResult = await this.authenticate(data, params, ...authStrategies)\n\n    debug('Got authentication result', authResult)\n\n    if (authResult.accessToken) {\n      return authResult\n    }\n\n    const [payload, jwtOptions] = await Promise.all([\n      this.getPayload(authResult, params),\n      this.getTokenOptions(authResult, params)\n    ])\n\n    debug('Creating JWT with', payload, jwtOptions)\n\n    const accessToken = await this.createAccessToken(payload, jwtOptions, params.secret)\n\n    return {\n      accessToken,\n      ...authResult,\n      authentication: {\n        ...authResult.authentication,\n        payload: jsonwebtoken.decode(accessToken)\n      }\n    }\n  }\n\n  /**\n   * Mark a JWT as removed. By default only verifies the JWT and returns the result.\n   * Triggers the `logout` event.\n   *\n   * @param id The JWT to remove or null\n   * @param params Service call parameters\n   */\n  async remove(id: string | null, params?: AuthenticationParams) {\n    const { authentication } = params\n    const { authStrategies } = this.configuration\n\n    // When an id is passed it is expected to be the authentication `accessToken`\n    if (id !== null && id !== authentication.accessToken) {\n      throw new NotAuthenticated('Invalid access token')\n    }\n\n    debug('Verifying authentication strategy in remove')\n\n    return this.authenticate(authentication, params, ...authStrategies)\n  }\n\n  /**\n   * Validates the service configuration.\n   */\n  async setup() {\n    await super.setup()\n\n    // The setup method checks for valid settings and registers the\n    // connection and event (login, logout) hooks\n    const { secret, service, entity, entityId } = this.configuration\n\n    if (typeof secret !== 'string') {\n      throw new Error(\"A 'secret' must be provided in your authentication configuration\")\n    }\n\n    if (entity !== null) {\n      if (service === undefined) {\n        throw new Error(\"The 'service' option is not set in the authentication configuration\")\n      }\n\n      if (this.app.service(service) === undefined) {\n        throw new Error(\n          `The '${service}' entity service does not exist (set to 'null' if it is not required)`\n        )\n      }\n\n      if (this.app.service(service).id === undefined && entityId === undefined) {\n        throw new Error(\n          `The '${service}' service does not have an 'id' property and no 'entityId' option is set.`\n        )\n      }\n    }\n\n    const publishable = this as any\n\n    if (typeof publishable.publish === 'function') {\n      publishable.publish((): any => null)\n    }\n  }\n}\n"
  },
  {
    "path": "packages/authentication/src/strategy.ts",
    "content": "import { AuthenticationStrategy, AuthenticationBase } from './core'\nimport { Application, Service } from '@feathersjs/feathers'\n\nexport class AuthenticationBaseStrategy implements AuthenticationStrategy {\n  authentication?: AuthenticationBase\n  app?: Application\n  name?: string\n\n  setAuthentication(auth: AuthenticationBase) {\n    this.authentication = auth\n  }\n\n  setApplication(app: Application) {\n    this.app = app\n  }\n\n  setName(name: string) {\n    this.name = name\n  }\n\n  get configuration(): any {\n    return this.authentication.configuration[this.name]\n  }\n\n  get entityService(): Service {\n    const { service } = this.configuration\n\n    if (!service) {\n      return null\n    }\n\n    return this.app.service(service) || null\n  }\n}\n"
  },
  {
    "path": "packages/authentication/test/core.test.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport assert from 'assert'\nimport { feathers, Application } from '@feathersjs/feathers'\nimport jwt from 'jsonwebtoken'\nimport { Infer, schema } from '@feathersjs/schema'\n\nimport { AuthenticationBase, AuthenticationRequest } from '../src/core'\nimport { authenticationSettingsSchema } from '../src/options'\nimport { Strategy1, Strategy2, MockRequest } from './fixtures'\nimport { ServerResponse } from 'http'\n\nconst UUID = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/\n\ndescribe('authentication/core', () => {\n  let app: Application\n  let auth: AuthenticationBase\n\n  beforeEach(() => {\n    app = feathers()\n    auth = new AuthenticationBase(app, 'authentication', {\n      entity: 'user',\n      service: 'users',\n      secret: 'supersecret',\n      first: { hello: 'test' }\n    })\n\n    auth.register('first', new Strategy1())\n    auth.register('second', new Strategy2())\n    auth.register('dummy', {\n      async authenticate(data: AuthenticationRequest) {\n        return data\n      }\n    })\n  })\n\n  describe('configuration', () => {\n    it('infers configuration from settings schema', async () => {\n      const settingsSchema = schema({\n        $id: 'AuthSettingsSchema',\n        ...authenticationSettingsSchema\n      } as const)\n      type Settings = Infer<typeof settingsSchema>\n      const config: Settings = {\n        entity: 'user',\n        secret: 'supersecret',\n        authStrategies: ['some', 'thing']\n      }\n\n      await settingsSchema.validate(config)\n    })\n\n    it('throws an error when app is not provided', () => {\n      try {\n        // @ts-ignore\n        const otherAuth = new AuthenticationBase()\n        assert.fail('Should never get here')\n        assert.ok(otherAuth)\n      } catch (error: any) {\n        assert.strictEqual(\n          error.message,\n          'An application instance has to be passed to the authentication service'\n        )\n      }\n    })\n\n    it('sets defaults', () => {\n      // Getting configuration twice returns a copy\n      assert.notStrictEqual(auth.configuration, auth.configuration)\n      assert.strictEqual(auth.configuration.entity, 'user')\n    })\n\n    it('allows to override jwtOptions, does not merge', () => {\n      const { jwtOptions } = auth.configuration\n      const auth2options = {\n        jwtOptions: {\n          expiresIn: '1w'\n        }\n      }\n\n      app.set('auth2', auth2options)\n\n      const auth2 = new AuthenticationBase(app, 'auth2')\n\n      assert.ok(jwtOptions)\n      assert.strictEqual(jwtOptions.expiresIn, '1d')\n      assert.strictEqual(jwtOptions.issuer, 'feathers')\n\n      assert.deepStrictEqual(auth2.configuration.jwtOptions, auth2options.jwtOptions)\n    })\n\n    it('sets configKey and defaultAuthentication', () => {\n      assert.strictEqual(app.get('defaultAuthentication'), 'authentication')\n    })\n\n    it('uses default configKey', () => {\n      const otherApp = feathers()\n      const otherAuth = new AuthenticationBase(otherApp)\n\n      assert.ok(otherAuth)\n      assert.strictEqual(otherApp.get('defaultAuthentication'), 'authentication')\n      assert.deepStrictEqual(otherApp.get('authentication'), {})\n    })\n  })\n\n  describe('strategies', () => {\n    it('strategyNames', () => {\n      assert.deepStrictEqual(auth.strategyNames, ['first', 'second', 'dummy'])\n    })\n\n    it('getStrategies', () => {\n      const first = auth.getStrategies('first')\n      const invalid = auth.getStrategies('first', 'invalid', 'second')\n\n      assert.strictEqual(first.length, 1)\n      assert.strictEqual(invalid.length, 2, 'Filtered out invalid strategies')\n    })\n\n    it('getStrategy', () => {\n      const first = auth.getStrategy('first')\n\n      assert.ok(first)\n    })\n\n    it('calls setName, setApplication and setAuthentication if available', () => {\n      const [first] = auth.getStrategies('first') as [Strategy1]\n\n      assert.strictEqual(first.name, 'first')\n      assert.strictEqual(first.app, app)\n      assert.strictEqual(first.authentication, auth)\n    })\n\n    it('strategy configuration getter', () => {\n      const [first] = auth.getStrategies('first') as [Strategy1]\n\n      assert.deepStrictEqual(first.configuration, { hello: 'test' })\n    })\n\n    it('strategy configuration getter', () => {\n      const [first] = auth.getStrategies('first') as [Strategy1]\n      const oldService = auth.configuration.service\n\n      delete auth.configuration.service\n\n      assert.strictEqual(first.entityService, null)\n\n      auth.configuration.service = oldService\n    })\n  })\n\n  describe('authenticate', () => {\n    describe('with strategy set in params', () => {\n      it('returns first success', async () => {\n        const result = await auth.authenticate(\n          {\n            strategy: 'first',\n            username: 'David'\n          },\n          {},\n          'first',\n          'second'\n        )\n\n        assert.deepStrictEqual(result, Strategy1.result)\n      })\n\n      it('returns error when failed', async () => {\n        try {\n          await auth.authenticate(\n            {\n              strategy: 'first',\n              username: 'Steve'\n            },\n            {},\n            'first',\n            'second'\n          )\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotAuthenticated')\n          assert.strictEqual(error.message, 'Invalid Dave')\n        }\n      })\n\n      it('returns second success', async () => {\n        const authentication = {\n          strategy: 'second',\n          v2: true,\n          password: 'supersecret'\n        }\n\n        const result = await auth.authenticate(authentication, {}, 'first', 'second')\n\n        assert.deepStrictEqual(\n          result,\n          Object.assign({}, Strategy2.result, {\n            authentication,\n            params: { authenticated: true }\n          })\n        )\n      })\n\n      it('passes params', async () => {\n        const params = {\n          some: 'thing'\n        }\n        const authentication = {\n          strategy: 'second',\n          v2: true,\n          password: 'supersecret'\n        }\n\n        const result = await auth.authenticate(authentication, params, 'first', 'second')\n\n        assert.deepStrictEqual(\n          result,\n          Object.assign(\n            {\n              params: Object.assign(params, {\n                authenticated: true\n              }),\n              authentication\n            },\n            Strategy2.result\n          )\n        )\n      })\n\n      it('throws error when allowed and passed strategy does not match', async () => {\n        try {\n          await auth.authenticate(\n            {\n              strategy: 'first',\n              username: 'Dummy'\n            },\n            {},\n            'second'\n          )\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotAuthenticated')\n          assert.strictEqual(\n            error.message,\n            'Invalid authentication information (strategy not allowed in authStrategies)'\n          )\n        }\n      })\n\n      it('throws error when strategy is not set', async () => {\n        try {\n          await auth.authenticate(\n            {\n              username: 'Dummy'\n            },\n            {},\n            'second'\n          )\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.message, 'Invalid authentication information (no `strategy` set)')\n        }\n      })\n    })\n  })\n\n  describe('parse', () => {\n    const res = {} as ServerResponse\n\n    it('returns null when no names are given', async () => {\n      const req = {} as MockRequest\n\n      assert.strictEqual(await auth.parse(req, res), null)\n    })\n\n    it('successfully parses a request (first)', async () => {\n      const req = { isDave: true } as MockRequest\n\n      const result = await auth.parse(req, res, 'first', 'second')\n\n      assert.deepStrictEqual(result, Strategy1.result)\n    })\n\n    it('successfully parses a request (second)', async () => {\n      const req = { isV2: true } as MockRequest\n\n      const result = await auth.parse(req, res, 'first', 'second')\n\n      assert.deepStrictEqual(result, Strategy2.result)\n    })\n\n    it('null when no success', async () => {\n      const req = {} as MockRequest\n\n      const result = await auth.parse(req, res, 'first', 'second')\n\n      assert.strictEqual(result, null)\n    })\n  })\n\n  describe('jwt', () => {\n    const message = 'Some payload'\n\n    describe('createAccessToken', () => {\n      // it('errors with no payload', () => {\n      //   try {\n      //     // @ts-ignore\n      //     await auth.createAccessToken();\n      //     assert.fail('Should never get here');\n      //   } catch (error: any) {\n      //     assert.strictEqual(error.message, 'payload is required');\n      //   }\n      // });\n\n      it('with default options', async () => {\n        const msg = 'Some payload'\n\n        const accessToken = await auth.createAccessToken({ message: msg })\n        const decoded = jwt.decode(accessToken)\n        const settings = auth.configuration.jwtOptions\n\n        if (decoded === null || typeof decoded === 'string') {\n          throw new Error('Not encoded properly')\n        }\n\n        assert.ok(typeof accessToken === 'string')\n        assert.strictEqual(decoded.message, msg, 'Set payload')\n        assert.ok(UUID.test(decoded.jti), 'Set `jti` to default UUID')\n        assert.strictEqual(decoded.aud, settings.audience)\n        assert.strictEqual(decoded.iss, settings.issuer)\n      })\n\n      it('with default and overriden options', async () => {\n        const overrides = {\n          issuer: 'someoneelse',\n          audience: 'people',\n          jwtid: 'something'\n        }\n\n        const accessToken = await auth.createAccessToken({ message }, overrides)\n\n        assert.ok(typeof accessToken === 'string')\n\n        const decoded = jwt.decode(accessToken)\n\n        if (decoded === null || typeof decoded === 'string') {\n          throw new Error('Not encoded properly')\n        }\n\n        assert.strictEqual(decoded.message, message, 'Set payload')\n        assert.strictEqual(decoded.jti, 'something')\n        assert.strictEqual(decoded.aud, overrides.audience)\n        assert.strictEqual(decoded.iss, overrides.issuer)\n      })\n\n      it('errors with invalid options', async () => {\n        const overrides = {\n          algorithm: 'fdjsklfsndkl'\n        }\n\n        try {\n          // @ts-ignore\n          await auth.createAccessToken({}, overrides)\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.message, '\"algorithm\" must be a valid string enum value')\n        }\n      })\n    })\n\n    describe('verifyAccessToken', () => {\n      let validToken: string\n      let expiredToken: string\n\n      beforeEach(async () => {\n        validToken = await auth.createAccessToken({ message })\n        expiredToken = await auth.createAccessToken(\n          {},\n          {\n            expiresIn: '1ms'\n          }\n        )\n      })\n\n      it('returns payload when token is valid', async () => {\n        const payload = await auth.verifyAccessToken(validToken)\n\n        assert.strictEqual(payload.message, message)\n      })\n\n      it('errors when custom algorithm property does not match', async () => {\n        try {\n          await auth.verifyAccessToken(validToken, {\n            algorithm: ['HS512']\n          })\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.message, 'invalid algorithm')\n        }\n      })\n\n      it('errors when algorithms property does not match', async () => {\n        try {\n          await auth.verifyAccessToken(validToken, {\n            algorithms: ['HS512']\n          })\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.message, 'invalid algorithm')\n        }\n      })\n\n      it('errors when secret is different', async () => {\n        try {\n          await auth.verifyAccessToken(validToken, {}, 'fdjskl')\n\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.message, 'invalid signature')\n        }\n      })\n\n      it('errors when other custom options do not match', async () => {\n        try {\n          await auth.verifyAccessToken(validToken, { issuer: 'someonelse' })\n\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotAuthenticated')\n          assert.ok(/jwt issuer invalid/.test(error.message))\n        }\n      })\n\n      it('errors when token is expired', async () => {\n        try {\n          await auth.verifyAccessToken(expiredToken)\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.strictEqual(error.name, 'NotAuthenticated')\n          assert.strictEqual(error.message, 'jwt expired')\n          assert.strictEqual(error.data.name, 'TokenExpiredError')\n          assert.ok(error.data.expiredAt)\n        }\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "packages/authentication/test/fixtures.ts",
    "content": "import { NotAuthenticated } from '@feathersjs/errors'\nimport { Params } from '@feathersjs/feathers'\n\nimport { AuthenticationRequest } from '../src/core'\nimport { IncomingMessage } from 'http'\nimport { AuthenticationBaseStrategy } from '../src/strategy'\n\nexport interface MockRequest extends IncomingMessage {\n  isDave?: boolean\n  isV2?: boolean\n}\n\nexport class Strategy1 extends AuthenticationBaseStrategy {\n  static result = {\n    user: {\n      id: 123,\n      name: 'Dave'\n    },\n    authenticated: true\n  }\n\n  async authenticate(authentication: AuthenticationRequest) {\n    if (authentication.username === 'David' || authentication.both) {\n      return { ...Strategy1.result }\n    }\n\n    throw new NotAuthenticated('Invalid Dave')\n  }\n\n  async parse(req: MockRequest) {\n    if (req.isDave) {\n      return { ...Strategy1.result }\n    }\n\n    return null\n  }\n}\n\nexport class Strategy2 extends AuthenticationBaseStrategy {\n  static result = {\n    user: {\n      name: 'V2',\n      version: 2\n    },\n    authenticated: true\n  }\n\n  authenticate(authentication: AuthenticationRequest, params: Params) {\n    const isV2 = authentication.v2 === true && authentication.password === 'supersecret'\n\n    if (isV2 || authentication.both) {\n      return Promise.resolve(Object.assign({ params, authentication }, Strategy2.result))\n    }\n\n    return Promise.reject(new NotAuthenticated('Invalid v2 user'))\n  }\n\n  async parse(req: MockRequest) {\n    if (req.isV2) {\n      return Strategy2.result\n    }\n\n    return null\n  }\n}\n"
  },
  {
    "path": "packages/authentication/test/hooks/authenticate.test.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport assert from 'assert'\nimport { feathers, Application, Params, ServiceMethods } from '@feathersjs/feathers'\n\nimport { Strategy1, Strategy2 } from '../fixtures'\nimport { AuthenticationService, hooks } from '../../src'\n\nconst { authenticate } = hooks\n\ndescribe('authentication/hooks/authenticate', () => {\n  let app: Application<{\n    authentication: AuthenticationService\n    'auth-v2': AuthenticationService\n    users: Partial<ServiceMethods> & { id: string }\n  }>\n\n  beforeEach(() => {\n    app = feathers()\n    app.use(\n      'authentication',\n      new AuthenticationService(app, 'authentication', {\n        entity: 'user',\n        service: 'users',\n        secret: 'supersecret',\n        authStrategies: ['first']\n      })\n    )\n    app.use(\n      'auth-v2',\n      new AuthenticationService(app, 'auth-v2', {\n        entity: 'user',\n        service: 'users',\n        secret: 'supersecret',\n        authStrategies: ['test']\n      })\n    )\n    app.use('users', {\n      id: 'id',\n\n      async find() {\n        return []\n      },\n\n      async get(_id: string | number, params: Params) {\n        return params\n      }\n    })\n\n    const service = app.service('authentication')\n\n    service.register('first', new Strategy1())\n    service.register('second', new Strategy2())\n\n    app.service('auth-v2').register('test', new Strategy1())\n\n    app.service('users').hooks({\n      get: [authenticate('first', 'second')]\n    })\n\n    app.service('users').id = 'name'\n    app.setup()\n  })\n\n  it('throws an error when no strategies are passed', () => {\n    try {\n      // @ts-ignore\n      authenticate()\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.message, 'The authenticate hook needs at least one allowed strategy')\n    }\n  })\n\n  it('throws an error when not a before hook', async () => {\n    const users = app.service('users')\n\n    users.hooks({\n      after: {\n        all: [authenticate('first')]\n      }\n    })\n\n    try {\n      await users.find()\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.name, 'NotAuthenticated')\n      assert.strictEqual(error.message, 'The authenticate hook must be used as a before hook')\n    }\n  })\n\n  it('throws an error if authentication service is gone', async () => {\n    delete app.services.authentication\n\n    try {\n      await app.service('users').get(1, {\n        authentication: {\n          some: 'thing'\n        }\n      })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.name, 'NotAuthenticated')\n      assert.strictEqual(error.message, 'Could not find a valid authentication service')\n    }\n  })\n\n  it('authenticates with first strategy, merges params', async () => {\n    const params = {\n      authentication: {\n        strategy: 'first',\n        username: 'David'\n      }\n    }\n\n    const result = await app.service('users').get(1, params)\n\n    assert.deepStrictEqual(result, Object.assign({}, params, Strategy1.result))\n  })\n\n  it('authenticates with first strategy, keeps references alive (#1629)', async () => {\n    const connection = {}\n    const params = {\n      connection,\n      authentication: {\n        strategy: 'first',\n        username: 'David'\n      }\n    }\n\n    app.service('users').hooks({\n      after: {\n        get: (context) => {\n          context.result.params = context.params\n        }\n      }\n    })\n\n    const result = await app.service('users').get(1, params)\n\n    assert.ok(result.params.connection === connection)\n  })\n\n  it('authenticates with different authentication service', async () => {\n    const params = {\n      authentication: {\n        strategy: 'test',\n        username: 'David'\n      }\n    }\n\n    app.service('users').hooks({\n      before: {\n        find: [\n          authenticate({\n            service: 'auth-v2',\n            strategies: ['test']\n          })\n        ]\n      }\n    })\n\n    const result = await app.service('users').find(params)\n\n    assert.deepStrictEqual(result, [])\n  })\n\n  it('authenticates with second strategy', async () => {\n    const params = {\n      authentication: {\n        strategy: 'second',\n        v2: true,\n        password: 'supersecret'\n      }\n    }\n\n    const result = await app.service('users').get(1, params)\n\n    assert.deepStrictEqual(\n      result,\n      Object.assign(\n        {\n          authentication: params.authentication,\n          params: { authenticated: true }\n        },\n        Strategy2.result\n      )\n    )\n  })\n\n  it('passes for internal calls without authentication', async () => {\n    const result = await app.service('users').get(1)\n\n    assert.deepStrictEqual(result, {})\n  })\n\n  it('fails for invalid params.authentication', async () => {\n    try {\n      await app.service('users').get(1, {\n        authentication: {\n          strategy: 'first',\n          some: 'thing'\n        }\n      })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.name, 'NotAuthenticated')\n      assert.strictEqual(error.message, 'Invalid Dave')\n    }\n  })\n\n  it('fails for external calls without authentication', async () => {\n    try {\n      await app.service('users').get(1, {\n        provider: 'rest'\n      })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.name, 'NotAuthenticated')\n      assert.strictEqual(error.message, 'Not authenticated')\n    }\n  })\n\n  it('passes with authenticated: true but external call', async () => {\n    const params = {\n      provider: 'rest',\n      authenticated: true\n    }\n    const result = await app.service('users').get(1, params)\n\n    assert.deepStrictEqual(result, params)\n  })\n\n  it('errors when used on the authentication service', async () => {\n    const auth = app.service('authentication')\n\n    auth.hooks({\n      before: {\n        create: authenticate('first')\n      }\n    })\n\n    try {\n      await auth.create({\n        strategy: 'first',\n        username: 'David'\n      })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(\n        error.message,\n        'The authenticate hook does not need to be used on the authentication service'\n      )\n    }\n  })\n})\n"
  },
  {
    "path": "packages/authentication/test/hooks/event.test.ts",
    "content": "import assert from 'assert'\nimport { feathers, HookContext } from '@feathersjs/feathers'\n\nimport hook from '../../src/hooks/event'\nimport { AuthenticationParams, AuthenticationRequest, AuthenticationResult } from '../../src/core'\n\ndescribe('authentication/hooks/events', () => {\n  const app = feathers().use('authentication', {\n    async create(data: AuthenticationRequest) {\n      return data\n    },\n\n    async remove(id: string) {\n      return { id }\n    }\n  })\n\n  const service = app.service('authentication')\n\n  service.hooks({\n    create: [hook('login')],\n    remove: [hook('logout')]\n  })\n\n  it('login', (done) => {\n    const data = {\n      message: 'test'\n    }\n\n    app.once('login', (result: AuthenticationResult, params: AuthenticationParams, context: HookContext) => {\n      try {\n        assert.deepStrictEqual(result, data)\n        assert.ok(params.testParam)\n        assert.ok(context.method, 'create')\n        done()\n      } catch (error: any) {\n        done(error)\n      }\n    })\n\n    service.create(data, {\n      testParam: true,\n      provider: 'test'\n    } as any)\n  })\n\n  it('logout', (done) => {\n    app.once('logout', (result: AuthenticationResult, params: AuthenticationParams, context: HookContext) => {\n      try {\n        assert.deepStrictEqual(result, {\n          id: 'test'\n        })\n        assert.ok(params.testParam)\n        assert.ok(context.method, 'remove')\n        done()\n      } catch (error: any) {\n        done(error)\n      }\n    })\n\n    service.remove('test', {\n      testParam: true,\n      provider: 'test'\n    } as any)\n  })\n\n  it('does nothing when provider is not set', (done) => {\n    const handler = () => {\n      done(new Error('Should never get here'))\n    }\n\n    app.on('logout', handler)\n    service.once('removed', (result: AuthenticationResult) => {\n      app.removeListener('logout', handler)\n      assert.deepStrictEqual(result, {\n        id: 'test'\n      })\n      done()\n    })\n\n    service.remove('test')\n  })\n})\n"
  },
  {
    "path": "packages/authentication/test/jwt.test.ts",
    "content": "import assert from 'assert'\nimport merge from 'lodash/merge'\nimport { feathers, Application, Service } from '@feathersjs/feathers'\nimport { memory } from '@feathersjs/memory'\nimport { getDispatch, resolve, resolveDispatch } from '@feathersjs/schema'\n\nimport { AuthenticationService, JWTStrategy, hooks } from '../src'\nimport { ServerResponse } from 'http'\nimport { MockRequest } from './fixtures'\n\nconst { authenticate } = hooks\n\ndescribe('authentication/jwt', () => {\n  let app: Application<{\n    authentication: AuthenticationService\n    users: Partial<Service>\n    protected: Partial<Service>\n  }>\n  let user: any\n  let accessToken: string\n  let payload: any\n\n  const userDispatchResolver = resolve<any, any>({\n    converter: async () => {\n      return {\n        dispatch: true,\n        message: 'Hello world'\n      }\n    },\n    properties: {}\n  })\n\n  beforeEach(async () => {\n    app = feathers()\n\n    const authService = new AuthenticationService(app, 'authentication', {\n      entity: 'user',\n      service: 'users',\n      secret: 'supersecret',\n      authStrategies: ['jwt']\n    })\n\n    authService.register('jwt', new JWTStrategy())\n\n    app.use('users', memory())\n    app.use('protected', {\n      async get(id, params) {\n        return {\n          id,\n          params\n        }\n      }\n    })\n    app.use('authentication', authService)\n\n    const service = app.service('authentication')\n\n    app.service('protected').hooks({\n      before: {\n        all: [authenticate('jwt')]\n      }\n    })\n\n    app.service('users').hooks({\n      around: {\n        all: [resolveDispatch(userDispatchResolver)]\n      },\n      after: {\n        get: [\n          (context) => {\n            if (context.params.provider) {\n              context.result.isExternal = true\n            }\n\n            return context\n          }\n        ]\n      }\n    })\n\n    user = await app.service('users').create({\n      name: 'David'\n    })\n\n    accessToken = await service.createAccessToken(\n      {},\n      {\n        subject: `${user.id}`\n      }\n    )\n\n    payload = await service.verifyAccessToken(accessToken)\n    app.setup()\n  })\n\n  it('getEntity', async () => {\n    const [strategy] = app.service('authentication').getStrategies('jwt') as JWTStrategy[]\n\n    let entity = await strategy.getEntity(user.id, {\n      query: {\n        name: 'Dave'\n      }\n    })\n\n    assert.deepStrictEqual(entity, user)\n\n    entity = await strategy.getEntity(user.id, {\n      provider: 'rest'\n    })\n\n    assert.deepStrictEqual(entity, {\n      ...user,\n      isExternal: true\n    })\n  })\n\n  describe('handleConnection', () => {\n    it('adds entity and authentication information on create', async () => {\n      const connection: any = {}\n\n      await app.service('authentication').create(\n        {\n          strategy: 'jwt',\n          accessToken\n        },\n        { connection }\n      )\n\n      assert.deepStrictEqual(connection.user, user)\n      assert.deepStrictEqual(connection.authentication, {\n        strategy: 'jwt',\n        accessToken\n      })\n    })\n\n    it('login event connection has authentication information (#2908)', async () => {\n      const connection: any = {}\n      const onLogin = new Promise((resolve, reject) =>\n        app.once('login', (data, { connection }) => {\n          try {\n            assert.deepStrictEqual(connection.user, {\n              ...user,\n              isExternal: true\n            })\n            resolve(data)\n          } catch (error) {\n            reject(error)\n          }\n        })\n      )\n\n      await app.service('authentication').create(\n        {\n          strategy: 'jwt',\n          accessToken\n        },\n        { connection, provider: 'test' }\n      )\n\n      await onLogin\n    })\n\n    it('resolves safe dispatch data in authentication result', async () => {\n      const authResult = await app.service('authentication').create({\n        strategy: 'jwt',\n        accessToken\n      })\n\n      const dispatch = getDispatch(authResult)\n\n      assert.deepStrictEqual(dispatch.user, { dispatch: true, message: 'Hello world' })\n    })\n\n    it('sends disconnect event when connection token expires and removes all connection information', async () => {\n      const connection: any = {}\n      const token: string = await app.service('authentication').createAccessToken(\n        {},\n        {\n          subject: `${user.id}`,\n          expiresIn: '1s'\n        }\n      )\n\n      const result = await app.service('authentication').create(\n        {\n          strategy: 'jwt',\n          accessToken: token\n        },\n        { connection }\n      )\n\n      assert.ok(connection.authentication)\n\n      assert.strictEqual(result.accessToken, token)\n\n      const disconnection = await new Promise((resolve) => app.once('disconnect', resolve))\n\n      assert.strictEqual(disconnection, connection)\n\n      assert.ok(!connection.authentication)\n      assert.ok(!connection.user)\n      assert.strictEqual(Object.keys(connection).length, 0)\n    })\n\n    it('deletes authentication information on remove', async () => {\n      const connection: any = {}\n\n      await app.service('authentication').create(\n        {\n          strategy: 'jwt',\n          accessToken\n        },\n        { connection }\n      )\n\n      assert.ok(connection.authentication)\n\n      await app.service('authentication').remove(null, {\n        authentication: connection.authentication,\n        connection\n      })\n\n      assert.ok(!connection.authentication)\n      assert.ok(!connection.user)\n    })\n\n    it('deletes authentication information on disconnect but maintains it in event handler', async () => {\n      const connection: any = {}\n\n      await app.service('authentication').create(\n        {\n          strategy: 'jwt',\n          accessToken\n        },\n        { connection }\n      )\n\n      assert.ok(connection.authentication)\n      assert.ok(connection.user)\n\n      const disconnectPromise = new Promise((resolve, reject) =>\n        app.once('disconnect', (connection) => {\n          try {\n            assert.ok(connection.authentication)\n            assert.ok(connection.user)\n            resolve(connection)\n          } catch (error) {\n            reject(error)\n          }\n        })\n      )\n      app.emit('disconnect', connection)\n\n      await disconnectPromise\n      await new Promise((resolve) => process.nextTick(resolve))\n\n      assert.ok(!connection.authentication)\n      assert.ok(!connection.user)\n    })\n\n    it('does not remove if accessToken does not match', async () => {\n      const connection: any = {}\n\n      await app.service('authentication').create(\n        {\n          strategy: 'jwt',\n          accessToken\n        },\n        { connection }\n      )\n\n      assert.ok(connection.authentication)\n\n      await app.service('authentication').remove(null, {\n        authentication: {\n          strategy: 'jwt',\n          accessToken: await app.service('authentication').createAccessToken(\n            {},\n            {\n              subject: `${user.id}`\n            }\n          )\n        },\n        connection\n      })\n\n      assert.ok(connection.authentication)\n    })\n  })\n\n  describe('with authenticate hook', () => {\n    it('fails for protected service and external call when not set', async () => {\n      try {\n        await app.service('protected').get('test', {\n          provider: 'rest'\n        })\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.name, 'NotAuthenticated')\n        assert.strictEqual(error.message, 'Not authenticated')\n      }\n    })\n\n    it('fails for protected service and external call when not strategy', async () => {\n      try {\n        await app.service('protected').get('test', {\n          provider: 'rest',\n          authentication: {\n            username: 'Dave'\n          }\n        })\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.name, 'NotAuthenticated')\n        assert.strictEqual(error.message, 'Invalid authentication information (no `strategy` set)')\n      }\n    })\n\n    it('fails when entity service was not found', async () => {\n      delete app.services.users\n\n      await assert.rejects(\n        () =>\n          app.service('protected').get('test', {\n            provider: 'rest',\n            authentication: {\n              strategy: 'jwt',\n              accessToken\n            }\n          }),\n        {\n          message: \"Can not find service 'users'\"\n        }\n      )\n    })\n\n    it('fails when accessToken is not set', async () => {\n      try {\n        await app.service('protected').get('test', {\n          provider: 'rest',\n          authentication: {\n            strategy: 'jwt'\n          }\n        })\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.name, 'NotAuthenticated')\n        assert.strictEqual(error.message, 'No access token')\n      }\n    })\n\n    it('passes when authentication is set and merges params', async () => {\n      const params = {\n        provider: 'rest',\n        authentication: {\n          strategy: 'jwt',\n          accessToken\n        }\n      }\n\n      const result = await app.service('protected').get('test', params)\n\n      assert.strictEqual(Object.keys(result.params).length, 4)\n      assert.ok(!result.params.accessToken, 'Did not merge accessToken')\n      assert.deepStrictEqual(result, {\n        id: 'test',\n        params: merge({}, params, {\n          user,\n          authentication: { payload },\n          authenticated: true\n        })\n      })\n    })\n\n    it('works with entity set to null', async () => {\n      const params = {\n        provider: 'rest',\n        authentication: {\n          strategy: 'jwt',\n          accessToken\n        }\n      }\n\n      app.get('authentication').entity = null\n\n      const result = await app.service('protected').get('test', params)\n\n      assert.strictEqual(Object.keys(result.params).length, 3)\n      assert.ok(!result.params.accessToken, 'Did not merge accessToken')\n      assert.deepStrictEqual(result, {\n        id: 'test',\n        params: merge({}, params, {\n          authentication: { payload },\n          authenticated: true\n        })\n      })\n    })\n  })\n\n  describe('on authentication service', () => {\n    it('authenticates but does not return a new accessToken', async () => {\n      const authResult = await app.service('authentication').create({\n        strategy: 'jwt',\n        accessToken\n      })\n\n      assert.strictEqual(authResult.accessToken, accessToken)\n      assert.deepStrictEqual(authResult.user, user)\n      assert.deepStrictEqual(authResult.authentication.payload, payload)\n    })\n\n    it('errors when trying to set invalid option', () => {\n      app.get('authentication').otherJwt = {\n        expiresIn: 'something'\n      }\n\n      try {\n        app.service('authentication').register('otherJwt', new JWTStrategy())\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(\n          error.message,\n          \"Invalid JwtStrategy option 'authentication.otherJwt.expiresIn'. Did you mean to set it in 'authentication.jwtOptions'?\"\n        )\n      }\n    })\n\n    it('errors when `header` option is an object`', () => {\n      app.get('authentication').otherJwt = {\n        header: { message: 'This is wrong' }\n      }\n\n      assert.throws(() => app.service('authentication').register('otherJwt', new JWTStrategy()), {\n        message: \"The 'header' option for the otherJwt strategy must be a string\"\n      })\n    })\n  })\n\n  describe('parse', () => {\n    const res = {} as ServerResponse\n\n    it('returns null when header not set', async () => {\n      const req = {} as MockRequest\n\n      const result = await app.service('authentication').parse(req, res, 'jwt')\n\n      assert.strictEqual(result, null)\n    })\n\n    it('parses plain Authorization header', async () => {\n      const req = {\n        headers: {\n          authorization: accessToken\n        }\n      } as MockRequest\n\n      const result = await app.service('authentication').parse(req, res, 'jwt')\n\n      assert.deepStrictEqual(result, {\n        strategy: 'jwt',\n        accessToken\n      })\n    })\n\n    it('parses Authorization header with Bearer scheme', async () => {\n      const req = {\n        headers: {\n          authorization: ` Bearer ${accessToken} `\n        }\n      } as MockRequest\n\n      const result = await app.service('authentication').parse(req, res, 'jwt')\n\n      assert.deepStrictEqual(result, {\n        strategy: 'jwt',\n        accessToken\n      })\n    })\n\n    it('return null when scheme does not match', async () => {\n      const req = {\n        headers: {\n          authorization: ' Basic something'\n        }\n      } as MockRequest\n\n      const result = await app.service('authentication').parse(req, res, 'jwt')\n\n      assert.strictEqual(result, null)\n    })\n  })\n})\n"
  },
  {
    "path": "packages/authentication/test/service.test.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport assert from 'assert'\nimport omit from 'lodash/omit'\nimport jwt from 'jsonwebtoken'\nimport { feathers, Application } from '@feathersjs/feathers'\nimport { memory, MemoryService } from '@feathersjs/memory'\n\nimport { defaultOptions } from '../src/options'\nimport { AuthenticationService } from '../src'\n\nimport { Strategy1 } from './fixtures'\n\nconst UUID = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/\n\ndescribe('authentication/service', () => {\n  const message = 'Some payload'\n\n  let app: Application<{\n    authentication: AuthenticationService\n    users: MemoryService\n  }>\n\n  beforeEach(() => {\n    app = feathers()\n    app.use(\n      'authentication',\n      new AuthenticationService(app, 'authentication', {\n        entity: 'user',\n        service: 'users',\n        secret: 'supersecret',\n        authStrategies: ['first']\n      })\n    )\n    app.use('users', memory())\n\n    app.service('authentication').register('first', new Strategy1())\n  })\n\n  it('settings returns authentication options', () => {\n    assert.deepStrictEqual(\n      app.service('authentication').configuration,\n      Object.assign({}, defaultOptions, app.get('authentication'))\n    )\n  })\n\n  it('app.defaultAuthentication()', () => {\n    assert.strictEqual(app.defaultAuthentication(), app.service('authentication'))\n    assert.throws(() => app.defaultAuthentication('dummy'), {\n      message: \"Can not find service 'dummy'\"\n    })\n  })\n\n  describe('create', () => {\n    it('creates a valid accessToken and includes strategy result', async () => {\n      const service = app.service('authentication')\n      const result = await service.create({\n        strategy: 'first',\n        username: 'David'\n      })\n\n      const settings = service.configuration.jwtOptions\n      const decoded = jwt.decode(result.accessToken)\n\n      if (typeof decoded === 'string') {\n        throw new Error('Unexpected decoded JWT type')\n      }\n\n      assert.ok(result.accessToken)\n      assert.deepStrictEqual(omit(result, 'accessToken', 'authentication'), Strategy1.result)\n      assert.deepStrictEqual(result.authentication.payload, decoded)\n      assert.ok(UUID.test(decoded.jti), 'Set `jti` to default UUID')\n      assert.strictEqual(decoded.aud, settings.audience)\n      assert.strictEqual(decoded.iss, settings.issuer)\n    })\n\n    it('fails when strategy fails', async () => {\n      try {\n        await app.service('authentication').create({\n          strategy: 'first',\n          username: 'Dave'\n        })\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.name, 'NotAuthenticated')\n        assert.strictEqual(error.message, 'Invalid Dave')\n      }\n    })\n\n    it('creates a valid accessToken with strategy and params.payload', async () => {\n      const result = await app.service('authentication').create(\n        {\n          strategy: 'first',\n          username: 'David'\n        },\n        {\n          payload: { message }\n        }\n      )\n\n      const decoded = jwt.decode(result.accessToken)\n\n      if (typeof decoded === 'string') {\n        throw new Error('Unexpected decoded JWT type')\n      }\n\n      assert.strictEqual(decoded.message, message)\n    })\n\n    it('sets the subject authResult[entity][entityService.id]', async () => {\n      const { accessToken } = await app.service('authentication').create({\n        strategy: 'first',\n        username: 'David'\n      })\n\n      const decoded = jwt.decode(accessToken)\n\n      assert.strictEqual(decoded.sub, Strategy1.result.user.id.toString())\n    })\n\n    it('sets the subject authResult[entity][entityId]', async () => {\n      app.get('authentication').entityId = 'name'\n\n      const { accessToken } = await app.service('authentication').create({\n        strategy: 'first',\n        username: 'David'\n      })\n\n      const decoded = jwt.decode(accessToken)\n\n      assert.strictEqual(decoded.sub, Strategy1.result.user.name.toString())\n    })\n\n    it('does not override the subject if already set', async () => {\n      const subject = 'Davester'\n\n      const { accessToken } = await app.service('authentication').create(\n        {\n          strategy: 'first',\n          username: 'David'\n        },\n        {\n          jwt: { subject }\n        }\n      )\n\n      const decoded = jwt.decode(accessToken)\n\n      assert.strictEqual(decoded.sub, subject)\n    })\n\n    it('errors when subject can not be found', async () => {\n      // @ts-ignore\n      app.service('users').options.id = 'somethingElse'\n\n      try {\n        await app.service('authentication').create({\n          strategy: 'first',\n          username: 'David'\n        })\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.name, 'NotAuthenticated')\n        assert.strictEqual(error.message, 'Can not set subject from user.somethingElse')\n      }\n    })\n\n    it('errors when no allowed strategies are set', async () => {\n      const service = app.service('authentication')\n      const configuration = service.configuration\n\n      delete configuration.authStrategies\n\n      app.set('authentication', configuration)\n\n      try {\n        await service.create({\n          strategy: 'first',\n          username: 'Dave'\n        })\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.name, 'NotAuthenticated')\n        assert.strictEqual(\n          error.message,\n          'No authentication strategies allowed for creating a JWT (`authStrategies`)'\n        )\n      }\n    })\n  })\n\n  describe('remove', () => {\n    it('can remove with authentication strategy set', async () => {\n      const authResult = await app.service('authentication').remove(null, {\n        authentication: {\n          strategy: 'first',\n          username: 'David'\n        }\n      })\n\n      assert.deepStrictEqual(authResult, Strategy1.result)\n    })\n\n    it('passes when id is set and matches accessToken', async () => {\n      const authResult = await app.service('authentication').remove('test', {\n        authentication: {\n          strategy: 'first',\n          username: 'David',\n          accessToken: 'test'\n        }\n      })\n\n      assert.deepStrictEqual(authResult, Strategy1.result)\n    })\n\n    it('fails when id is set and does not match accessToken', async () => {\n      await assert.rejects(\n        () =>\n          app.service('authentication').remove('test', {\n            authentication: {\n              strategy: 'first',\n              username: 'David',\n              accessToken: 'testing'\n            }\n          }),\n        {\n          name: 'NotAuthenticated',\n          message: 'Invalid access token'\n        }\n      )\n    })\n\n    it('errors when trying to remove with nothing', async () => {\n      try {\n        await app.service('authentication').remove(null)\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.message, 'Invalid authentication information (no `strategy` set)')\n      }\n    })\n  })\n\n  describe('setup', () => {\n    it('errors when there is no secret', async () => {\n      delete app.get('authentication').secret\n\n      await assert.rejects(() => app.setup(), {\n        message: \"A 'secret' must be provided in your authentication configuration\"\n      })\n    })\n\n    it('throws an error if service name is not set', async () => {\n      const otherApp = feathers()\n\n      otherApp.use(\n        '/authentication',\n        new AuthenticationService(otherApp, 'authentication', {\n          secret: 'supersecret',\n          authStrategies: ['first']\n        })\n      )\n\n      await assert.rejects(() => otherApp.setup(), {\n        message: \"The 'service' option is not set in the authentication configuration\"\n      })\n    })\n\n    it('throws an error if entity service does not exist', async () => {\n      const otherApp = feathers()\n\n      otherApp.use(\n        '/authentication',\n        new AuthenticationService(otherApp, 'authentication', {\n          entity: 'user',\n          service: 'users',\n          secret: 'supersecret',\n          authStrategies: ['first']\n        })\n      )\n\n      await assert.rejects(() => otherApp.setup(), {\n        message: \"Can not find service 'users'\"\n      })\n    })\n\n    it('throws an error if entity service exists but has no `id`', async () => {\n      const otherApp = feathers()\n\n      otherApp.use(\n        '/authentication',\n        new AuthenticationService(otherApp, 'authentication', {\n          entity: 'user',\n          service: 'users',\n          secret: 'supersecret',\n          strategies: ['first']\n        })\n      )\n\n      otherApp.use('/users', {\n        async get() {\n          return {}\n        }\n      })\n\n      await assert.rejects(() => otherApp.setup(), {\n        message: \"The 'users' service does not have an 'id' property and no 'entityId' option is set.\"\n      })\n    })\n\n    it('passes when entity service exists and `entityId` property is set', () => {\n      app.get('authentication').entityId = 'id'\n      app.use('users', memory())\n\n      app.setup()\n    })\n\n    it('does nothing when `entity` is explicitly `null`', () => {\n      app.get('authentication').entity = null\n\n      app.setup()\n    })\n  })\n})\n"
  },
  {
    "path": "packages/authentication/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/authentication-client/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n### Bug Fixes\n\n- **authentication-client:** Allow to abort fetch ([#3310](https://github.com/feathersjs/feathers/issues/3310)) ([ff3e104](https://github.com/feathersjs/feathers/commit/ff3e104b62d02d45261a293aff4e9491241f486f))\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n### Bug Fixes\n\n- **authentication-client:** Do not trigger storage methods if storage not defined ([#3210](https://github.com/feathersjs/feathers/issues/3210)) ([261acbc](https://github.com/feathersjs/feathers/commit/261acbcde387db731e434cb106a27b49dcb64a9a))\n- **authentication-client:** removeAccessToken throws error if storage not defined ([#3195](https://github.com/feathersjs/feathers/issues/3195)) ([b8e2769](https://github.com/feathersjs/feathers/commit/b8e27698f7958a91fe9a4ee64ec5591d23194c44))\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.2](https://github.com/feathersjs/feathers/compare/v5.0.1...v5.0.2) (2023-03-23)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **authentication-client:** Do not cache authentication errors ([#2892](https://github.com/feathersjs/feathers/issues/2892)) ([cc4e767](https://github.com/feathersjs/feathers/commit/cc4e76726fce1ac73252cfd92e22570d4bdeca20))\n- **authentication-client:** Improve socket reauthentication handling ([#2895](https://github.com/feathersjs/feathers/issues/2895)) ([9db5e7a](https://github.com/feathersjs/feathers/commit/9db5e7adb0f6aea43d607f530d8258ade98b7362))\n- **authentication-client:** Remove access token for fatal 400 errors ([#2894](https://github.com/feathersjs/feathers/issues/2894)) ([cfc6c7a](https://github.com/feathersjs/feathers/commit/cfc6c7a6b9dbc7fb60816e2b7f15897c38deb98d))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n### Features\n\n- **cli:** Add authentication client to generated client ([#2801](https://github.com/feathersjs/feathers/issues/2801)) ([bd59f91](https://github.com/feathersjs/feathers/commit/bd59f91b45a01c2eea0c4386e567f4de5aa6ad99))\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **authentication-client:** Properly handle missing token error ([#2700](https://github.com/feathersjs/feathers/issues/2700)) ([160746e](https://github.com/feathersjs/feathers/commit/160746e2bceb465fd1b6a003415f8ab38daba521))\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n### Bug Fixes\n\n- **authentication-client:** Ensure reAuthenticate works in parallel with other requests ([#2690](https://github.com/feathersjs/feathers/issues/2690)) ([41b3761](https://github.com/feathersjs/feathers/commit/41b376106b47e2f40a8914db7a5ed2935e070c08))\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- **hooks:** Migrate built-in hooks and allow backwards compatibility ([#2358](https://github.com/feathersjs/feathers/issues/2358)) ([759c5a1](https://github.com/feathersjs/feathers/commit/759c5a19327a731af965c3604119393b3d09a406))\n- **koa:** Use extended query parser for compatibility ([#2397](https://github.com/feathersjs/feathers/issues/2397)) ([b2944ba](https://github.com/feathersjs/feathers/commit/b2944bac3ec6d5ecc80dc518cd4e58093692db74))\n\n### Features\n\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n### Features\n\n- **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n### Features\n\n- Application service types default to any ([#1566](https://github.com/feathersjs/feathers/issues/1566)) ([d93ba9a](https://github.com/feathersjs/feathers/commit/d93ba9a17edd20d3397bb00f4f6e82e804e42ed6))\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n- **authentication-client:** Throw separate OauthError in authentication client ([#2189](https://github.com/feathersjs/feathers/issues/2189)) ([fa45ec5](https://github.com/feathersjs/feathers/commit/fa45ec520b21834e103e6fe4200b06dced56c0e6))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### chore\n\n- **package:** Remove @feathersjs/primus packages from core ([#1919](https://github.com/feathersjs/feathers/issues/1919)) ([d20b7d5](https://github.com/feathersjs/feathers/commit/d20b7d5a70f4d3306e294696156e8aa0337c35e9)), closes [#1899](https://github.com/feathersjs/feathers/issues/1899)\n\n### BREAKING CHANGES\n\n- **package:** Remove primus packages to be moved into the ecosystem.\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### chore\n\n- **package:** Remove @feathersjs/primus packages from core ([#1919](https://github.com/feathersjs/feathers/issues/1919)) ([d20b7d5](https://github.com/feathersjs/feathers/commit/d20b7d5a70f4d3306e294696156e8aa0337c35e9)), closes [#1899](https://github.com/feathersjs/feathers/issues/1899)\n\n### BREAKING CHANGES\n\n- **package:** Remove primus packages to be moved into the ecosystem.\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n### Bug Fixes\n\n- **authentication-client:** Allow reAuthentication using specific strategy ([#2140](https://github.com/feathersjs/feathers/issues/2140)) ([2a2bbf7](https://github.com/feathersjs/feathers/commit/2a2bbf7f8ee6d32b9fac8afab3421286b06e6443))\n- **socketio-client:** Throw an error and show a warning if someone tries to use socket.io-client v3 ([#2135](https://github.com/feathersjs/feathers/issues/2135)) ([cc3521c](https://github.com/feathersjs/feathers/commit/cc3521c935a1cbd690e29b7057998e3898f282db))\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n### Bug Fixes\n\n- **authentication-client:** Fix storage type so it works with all supported interfaces ([#2041](https://github.com/feathersjs/feathers/issues/2041)) ([6ee0e78](https://github.com/feathersjs/feathers/commit/6ee0e78d55cf1214f61458f386b94c350eec32af))\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.5.6](https://github.com/feathersjs/feathers/compare/v4.5.5...v4.5.6) (2020-07-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.5.4](https://github.com/feathersjs/feathers/compare/v4.5.3...v4.5.4) (2020-04-29)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n### Bug Fixes\n\n- **authentication-client:** Reset authentication promise on socket disconnect ([#1696](https://github.com/feathersjs/feathers/issues/1696)) ([3951626](https://github.com/feathersjs/feathers/commit/395162633ff22e95833a3c2900cb9464bb5b056f))\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n### Bug Fixes\n\n- Improve authentication client default storage initialization ([#1613](https://github.com/feathersjs/feathers/issues/1613)) ([d7f5107](https://github.com/feathersjs/feathers/commit/d7f5107ef76297b4ca6db580afc5e2b372f5ee4d))\n\n## [4.3.5](https://github.com/feathersjs/feathers/compare/v4.3.4...v4.3.5) (2019-10-07)\n\n### Bug Fixes\n\n- Authentication type improvements and timeout fix ([#1605](https://github.com/feathersjs/feathers/issues/1605)) ([19854d3](https://github.com/feathersjs/feathers/commit/19854d3))\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n### Bug Fixes\n\n- Typing improvements ([#1580](https://github.com/feathersjs/feathers/issues/1580)) ([7818aec](https://github.com/feathersjs/feathers/commit/7818aec))\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n### Bug Fixes\n\n- Small improvements in dependencies and code sturcture ([#1562](https://github.com/feathersjs/feathers/issues/1562)) ([42c13e2](https://github.com/feathersjs/feathers/commit/42c13e2))\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n### Bug Fixes\n\n- Only remove token on NotAuthenticated error in authentication client and handle error better ([#1525](https://github.com/feathersjs/feathers/issues/1525)) ([13a8758](https://github.com/feathersjs/feathers/commit/13a8758))\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))\n\n### Features\n\n- Let strategies handle the connection ([#1510](https://github.com/feathersjs/feathers/issues/1510)) ([4329feb](https://github.com/feathersjs/feathers/commit/4329feb))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n### Bug Fixes\n\n- Do not error in authentication client on logout ([#1473](https://github.com/feathersjs/feathers/issues/1473)) ([8211b98](https://github.com/feathersjs/feathers/commit/8211b98))\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Make oAuth paths more consistent and improve authentication client ([#1377](https://github.com/feathersjs/feathers/issues/1377)) ([adb2543](https://github.com/feathersjs/feathers/commit/adb2543))\n- Typings fix and improvements. ([#1364](https://github.com/feathersjs/feathers/issues/1364)) ([515b916](https://github.com/feathersjs/feathers/commit/515b916))\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n### Bug Fixes\n\n- Guard against null in client side logout function ([#1319](https://github.com/feathersjs/feathers/issues/1319)) ([fa7f057](https://github.com/feathersjs/feathers/commit/fa7f057))\n- Handle error oAuth redirect in authentication client ([#1307](https://github.com/feathersjs/feathers/issues/1307)) ([12d48ee](https://github.com/feathersjs/feathers/commit/12d48ee))\n- Merge httpStrategies and authStrategies option ([#1308](https://github.com/feathersjs/feathers/issues/1308)) ([afa4d55](https://github.com/feathersjs/feathers/commit/afa4d55))\n- Rename jwtStrategies option to authStrategies ([#1305](https://github.com/feathersjs/feathers/issues/1305)) ([4aee151](https://github.com/feathersjs/feathers/commit/4aee151))\n- Update version number check ([53575c5](https://github.com/feathersjs/feathers/commit/53575c5))\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Authentication core improvements ([#1260](https://github.com/feathersjs/feathers/issues/1260)) ([c5dc7a2](https://github.com/feathersjs/feathers/commit/c5dc7a2))\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n- **package:** update debug to version 3.0.0 ([#61](https://github.com/feathersjs/feathers/issues/61)) ([6f5009c](https://github.com/feathersjs/feathers/commit/6f5009c))\n\n### Features\n\n- @feathersjs/authentication-oauth ([#1299](https://github.com/feathersjs/feathers/issues/1299)) ([656bae7](https://github.com/feathersjs/feathers/commit/656bae7))\n- Add authentication through oAuth redirect to authentication client ([#1301](https://github.com/feathersjs/feathers/issues/1301)) ([35d8043](https://github.com/feathersjs/feathers/commit/35d8043))\n- Add AuthenticationBaseStrategy and make authentication option handling more explicit ([#1284](https://github.com/feathersjs/feathers/issues/1284)) ([2667d92](https://github.com/feathersjs/feathers/commit/2667d92))\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Authentication v3 client ([#1240](https://github.com/feathersjs/feathers/issues/1240)) ([65b43bd](https://github.com/feathersjs/feathers/commit/65b43bd))\n- Authentication v3 core server implementation ([#1205](https://github.com/feathersjs/feathers/issues/1205)) ([1bd7591](https://github.com/feathersjs/feathers/commit/1bd7591))\n\n### BREAKING CHANGES\n\n- Rewrite for authentication v3\n\n## [1.0.11](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-client@1.0.10...@feathersjs/authentication-client@1.0.11) (2019-01-26)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n## [1.0.10](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-client@1.0.9...@feathersjs/authentication-client@1.0.10) (2019-01-02)\n\n### Bug Fixes\n\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n\n<a name=\"1.0.9\"></a>\n\n## [1.0.9](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-client@1.0.8...@feathersjs/authentication-client@1.0.9) (2018-12-16)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n<a name=\"1.0.8\"></a>\n\n## [1.0.8](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-client@1.0.7...@feathersjs/authentication-client@1.0.8) (2018-10-26)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n<a name=\"1.0.7\"></a>\n\n## [1.0.7](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-client@1.0.6...@feathersjs/authentication-client@1.0.7) (2018-10-25)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n\n<a name=\"1.0.6\"></a>\n\n## [1.0.6](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-client@1.0.5...@feathersjs/authentication-client@1.0.6) (2018-09-21)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n<a name=\"1.0.5\"></a>\n\n## [1.0.5](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-client@1.0.4...@feathersjs/authentication-client@1.0.5) (2018-09-17)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n<a name=\"1.0.4\"></a>\n\n## [1.0.4](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-client@1.0.3...@feathersjs/authentication-client@1.0.4) (2018-09-02)\n\n**Note:** Version bump only for package @feathersjs/authentication-client\n\n<a name=\"1.0.3\"></a>\n\n## 1.0.3\n\n- Migrate to Monorepo ([feathers#462](https://github.com/feathersjs/feathers/issues/462))\n\n## [v1.0.2](https://github.com/feathersjs/authentication-client/tree/v1.0.2) (2018-01-03)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v1.0.1...v1.0.2)\n\n**Closed issues:**\n\n- No Auth header added when sending 1st request [\\#80](https://github.com/feathersjs/authentication-client/issues/80)\n\n**Merged pull requests:**\n\n- Update to correspond with latest release [\\#84](https://github.com/feathersjs/authentication-client/pull/84) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#83](https://github.com/feathersjs/authentication-client/pull/83) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update feathers-memory to the latest version 🚀 [\\#82](https://github.com/feathersjs/authentication-client/pull/82) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.1](https://github.com/feathersjs/authentication-client/tree/v1.0.1) (2017-11-16)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v1.0.0...v1.0.1)\n\n**Merged pull requests:**\n\n- Add default export for better ES module \\(TypeScript\\) compatibility [\\#81](https://github.com/feathersjs/authentication-client/pull/81) ([daffl](https://github.com/daffl))\n- Update @feathersjs/authentication to the latest version 🚀 [\\#79](https://github.com/feathersjs/authentication-client/pull/79) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.0](https://github.com/feathersjs/authentication-client/tree/v1.0.0) (2017-11-01)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v1.0.0-pre.1...v1.0.0)\n\n**Merged pull requests:**\n\n- Update dependencies for release [\\#78](https://github.com/feathersjs/authentication-client/pull/78) ([daffl](https://github.com/daffl))\n\n## [v1.0.0-pre.1](https://github.com/feathersjs/authentication-client/tree/v1.0.0-pre.1) (2017-10-25)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.3.3...v1.0.0-pre.1)\n\n**Closed issues:**\n\n- Error authenticating! Error: Token provided to verifyJWT is missing or not a string ? [\\#73](https://github.com/feathersjs/authentication-client/issues/73)\n- Authorization Header not sent!! [\\#69](https://github.com/feathersjs/authentication-client/issues/69)\n- users.get\\(id\\) failed \\(Not authenticated\\) after successful login. [\\#66](https://github.com/feathersjs/authentication-client/issues/66)\n\n**Merged pull requests:**\n\n- Updates for Feathers v3 [\\#77](https://github.com/feathersjs/authentication-client/pull/77) ([daffl](https://github.com/daffl))\n- Update Codeclimate token and badges [\\#76](https://github.com/feathersjs/authentication-client/pull/76) ([daffl](https://github.com/daffl))\n- Rename repository and use npm scope [\\#75](https://github.com/feathersjs/authentication-client/pull/75) ([daffl](https://github.com/daffl))\n- Update to new plugin infrastructure [\\#74](https://github.com/feathersjs/authentication-client/pull/74) ([daffl](https://github.com/daffl))\n- Update mocha to the latest version 🚀 [\\#72](https://github.com/feathersjs/authentication-client/pull/72) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Add babel-polyfill and package-lock.json [\\#68](https://github.com/feathersjs/authentication-client/pull/68) ([daffl](https://github.com/daffl))\n- Passport.verifyJWT should return Promise\\<any\\>, not Promise\\<string\\> [\\#65](https://github.com/feathersjs/authentication-client/pull/65) ([zxh19890103](https://github.com/zxh19890103))\n- Update debug to the latest version 🚀 [\\#61](https://github.com/feathersjs/authentication-client/pull/61) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update ws to the latest version 🚀 [\\#60](https://github.com/feathersjs/authentication-client/pull/60) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v0.3.3](https://github.com/feathersjs/authentication-client/tree/v0.3.3) (2017-07-18)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.3.2...v0.3.3)\n\n**Closed issues:**\n\n- An in-range update of feathers is breaking the build 🚨 [\\#59](https://github.com/feathersjs/authentication-client/issues/59)\n- An in-range update of feathers is breaking the build 🚨 [\\#58](https://github.com/feathersjs/authentication-client/issues/58)\n\n**Merged pull requests:**\n\n- typings: add auth methods to feathers.Application interface [\\#57](https://github.com/feathersjs/authentication-client/pull/57) ([j2L4e](https://github.com/j2L4e))\n- Update feathers-authentication-local to the latest version 🚀 [\\#55](https://github.com/feathersjs/authentication-client/pull/55) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update chai to the latest version 🚀 [\\#54](https://github.com/feathersjs/authentication-client/pull/54) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update feathers-socketio to the latest version 🚀 [\\#50](https://github.com/feathersjs/authentication-client/pull/50) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update socket.io-client to the latest version 🚀 [\\#49](https://github.com/feathersjs/authentication-client/pull/49) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update README.md [\\#47](https://github.com/feathersjs/authentication-client/pull/47) ([bertho-zero](https://github.com/bertho-zero))\n\n## [v0.3.2](https://github.com/feathersjs/authentication-client/tree/v0.3.2) (2017-04-30)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.3.1...v0.3.2)\n\n**Closed issues:**\n\n- An in-range update of feathers-errors is breaking the build 🚨 [\\#45](https://github.com/feathersjs/authentication-client/issues/45)\n- Proper way to save jwt in cookies [\\#41](https://github.com/feathersjs/authentication-client/issues/41)\n- Allow customizing the `tokenField` [\\#38](https://github.com/feathersjs/authentication-client/issues/38)\n- Show blank page in safari@iOS 8.3 [\\#37](https://github.com/feathersjs/authentication-client/issues/37)\n\n**Merged pull requests:**\n\n- Catch getJWT promise errors [\\#46](https://github.com/feathersjs/authentication-client/pull/46) ([NikitaVlaznev](https://github.com/NikitaVlaznev))\n- Update semistandard to the latest version 🚀 [\\#43](https://github.com/feathersjs/authentication-client/pull/43) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update feathers-hooks to the latest version 🚀 [\\#42](https://github.com/feathersjs/authentication-client/pull/42) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update dependencies to enable Greenkeeper 🌴 [\\#40](https://github.com/feathersjs/authentication-client/pull/40) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Note that auth must be configured after rest/socket clients [\\#36](https://github.com/feathersjs/authentication-client/pull/36) ([hubgit](https://github.com/hubgit))\n\n## [v0.3.1](https://github.com/feathersjs/authentication-client/tree/v0.3.1) (2017-03-10)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.3.0...v0.3.1)\n\n**Closed issues:**\n\n- The latest tag on NPM is wrong [\\#35](https://github.com/feathersjs/authentication-client/issues/35)\n- exp claim should be optional [\\#33](https://github.com/feathersjs/authentication-client/issues/33)\n\n**Merged pull requests:**\n\n- Fix \\#33 exp claim should be optional [\\#34](https://github.com/feathersjs/authentication-client/pull/34) ([whollacsek](https://github.com/whollacsek))\n\n## [v0.3.0](https://github.com/feathersjs/authentication-client/tree/v0.3.0) (2017-03-08)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.2.0...v0.3.0)\n\n## [v0.2.0](https://github.com/feathersjs/authentication-client/tree/v0.2.0) (2017-03-07)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.1.10...v0.2.0)\n\n**Closed issues:**\n\n- Support `authenticated` and `logout` client side events [\\#29](https://github.com/feathersjs/authentication-client/issues/29)\n- The default header mismatches the default feathers-authentication header [\\#23](https://github.com/feathersjs/authentication-client/issues/23)\n- Re-authenticating fails when passing options [\\#22](https://github.com/feathersjs/authentication-client/issues/22)\n- Socket.io timeout does nothing when there is JWT token available [\\#19](https://github.com/feathersjs/authentication-client/issues/19)\n\n**Merged pull requests:**\n\n- Fix header casing [\\#32](https://github.com/feathersjs/authentication-client/pull/32) ([daffl](https://github.com/daffl))\n- Add client side `authenticated` and `logout` events [\\#31](https://github.com/feathersjs/authentication-client/pull/31) ([daffl](https://github.com/daffl))\n- Add support for socket timeouts and some refactoring [\\#30](https://github.com/feathersjs/authentication-client/pull/30) ([daffl](https://github.com/daffl))\n\n## [v0.1.10](https://github.com/feathersjs/authentication-client/tree/v0.1.10) (2017-03-03)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.1.9...v0.1.10)\n\n**Merged pull requests:**\n\n- Remove hardcoded values for Config and Credentials typings [\\#28](https://github.com/feathersjs/authentication-client/pull/28) ([myknbani](https://github.com/myknbani))\n\n## [v0.1.9](https://github.com/feathersjs/authentication-client/tree/v0.1.9) (2017-03-01)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.1.8...v0.1.9)\n\n**Merged pull requests:**\n\n- Typescript Definitions [\\#25](https://github.com/feathersjs/authentication-client/pull/25) ([AbraaoAlves](https://github.com/AbraaoAlves))\n\n## [v0.1.8](https://github.com/feathersjs/authentication-client/tree/v0.1.8) (2017-02-05)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.1.7...v0.1.8)\n\n**Closed issues:**\n\n- Uncaught TypeError: Cannot read property 'options' of undefined [\\#26](https://github.com/feathersjs/authentication-client/issues/26)\n- Browser Version [\\#24](https://github.com/feathersjs/authentication-client/issues/24)\n\n**Merged pull requests:**\n\n- Hoist upgrade handler into current scope by using an arrow function [\\#27](https://github.com/feathersjs/authentication-client/pull/27) ([daffl](https://github.com/daffl))\n\n## [v0.1.7](https://github.com/feathersjs/authentication-client/tree/v0.1.7) (2017-01-29)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.1.6...v0.1.7)\n\n**Closed issues:**\n\n- \\[Webpack\\] TypeError: \\_this4.storage.getItem is not a function [\\#18](https://github.com/feathersjs/authentication-client/issues/18)\n- \\[Feature request\\] Signup via socket [\\#17](https://github.com/feathersjs/authentication-client/issues/17)\n- Missing auth token when used with feathers-rest in comparison to feathers-socketio [\\#16](https://github.com/feathersjs/authentication-client/issues/16)\n- Cannot read property 'on' of undefined - feathers-authentication-client [\\#12](https://github.com/feathersjs/authentication-client/issues/12)\n\n**Merged pull requests:**\n\n- Update passport.js [\\#20](https://github.com/feathersjs/authentication-client/pull/20) ([bertho-zero](https://github.com/bertho-zero))\n\n## [v0.1.6](https://github.com/feathersjs/authentication-client/tree/v0.1.6) (2016-12-14)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.1.5...v0.1.6)\n\n**Closed issues:**\n\n- `logout\\(\\)` doesn't resolve [\\#10](https://github.com/feathersjs/authentication-client/issues/10)\n\n**Merged pull requests:**\n\n- Fix linting [\\#13](https://github.com/feathersjs/authentication-client/pull/13) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.1.5](https://github.com/feathersjs/authentication-client/tree/v0.1.5) (2016-12-13)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.1.4...v0.1.5)\n\n## [v0.1.4](https://github.com/feathersjs/authentication-client/tree/v0.1.4) (2016-12-13)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.1.3...v0.1.4)\n\n**Closed issues:**\n\n- populateAccessToken tries to access non-existent property [\\#11](https://github.com/feathersjs/authentication-client/issues/11)\n- Socket client should automatically auth on reconnect [\\#2](https://github.com/feathersjs/authentication-client/issues/2)\n\n**Merged pull requests:**\n\n- More specific imports for StealJS [\\#14](https://github.com/feathersjs/authentication-client/pull/14) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.1.3](https://github.com/feathersjs/authentication-client/tree/v0.1.3) (2016-11-23)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.1.2...v0.1.3)\n\n**Closed issues:**\n\n- Client should ensure socket.io upgrade is complete before authenticating [\\#4](https://github.com/feathersjs/authentication-client/issues/4)\n\n**Merged pull requests:**\n\n- Socket reconnect [\\#9](https://github.com/feathersjs/authentication-client/pull/9) ([ekryski](https://github.com/ekryski))\n\n## [v0.1.2](https://github.com/feathersjs/authentication-client/tree/v0.1.2) (2016-11-22)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.1.1...v0.1.2)\n\n**Merged pull requests:**\n\n- Custom jwt strategy names [\\#8](https://github.com/feathersjs/authentication-client/pull/8) ([ekryski](https://github.com/ekryski))\n\n## [v0.1.1](https://github.com/feathersjs/authentication-client/tree/v0.1.1) (2016-11-21)\n\n[Full Changelog](https://github.com/feathersjs/authentication-client/compare/v0.1.0...v0.1.1)\n\n**Merged pull requests:**\n\n- Socket reconnect upgrade auth [\\#3](https://github.com/feathersjs/authentication-client/pull/3) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.1.0](https://github.com/feathersjs/authentication-client/tree/v0.1.0) (2016-11-18)\n\n**Closed issues:**\n\n- Relation with feathers-authentication [\\#6](https://github.com/feathersjs/authentication-client/issues/6)\n- Client: Docs for getJWT & verifyJWT [\\#1](https://github.com/feathersjs/authentication-client/issues/1)\n\n**Merged pull requests:**\n\n- Feathers authentication 1.0 compatible client [\\#7](https://github.com/feathersjs/authentication-client/pull/7) ([ekryski](https://github.com/ekryski))\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/authentication-client/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/authentication-client/README.md",
    "content": "# @feathersjs/authentication-client\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/authentication-client.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/authentication-client)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Feathers authentication client\n\n## Installation\n\n```\nnpm install @feathersjs/authentication-client --save\n```\n\n## Documentation\n\nRefer to the [Feathers authentication client API documentation](https://feathersjs.com/api/authentication/client.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/authentication-client/package.json",
    "content": "{\n  \"name\": \"@feathersjs/authentication-client\",\n  \"description\": \"The authentication plugin for feathers-client\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/authentication-client\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/authentication\": \"^5.0.42\",\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/authentication-local\": \"^5.0.42\",\n    \"@feathersjs/express\": \"^5.0.42\",\n    \"@feathersjs/memory\": \"^5.0.42\",\n    \"@feathersjs/rest-client\": \"^5.0.42\",\n    \"@feathersjs/socketio\": \"^5.0.42\",\n    \"@feathersjs/socketio-client\": \"^5.0.42\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"axios\": \"^1.13.6\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/authentication-client/src/core.ts",
    "content": "import { NotAuthenticated, FeathersError } from '@feathersjs/errors'\nimport { Application, Params } from '@feathersjs/feathers'\nimport { AuthenticationRequest, AuthenticationResult } from '@feathersjs/authentication'\nimport { Storage, StorageWrapper } from './storage'\n\nclass OauthError extends FeathersError {\n  constructor(message: string, data?: any) {\n    super(message, 'OauthError', 401, 'oauth-error', data)\n  }\n}\n\nconst getMatch = (location: Location, key: string): [string, RegExp] => {\n  const regex = new RegExp(`(?:\\&?)${key}=([^&]*)`)\n  const match = location.hash ? location.hash.match(regex) : null\n\n  if (match !== null) {\n    const [, value] = match\n\n    return [value, regex]\n  }\n\n  return [null, regex]\n}\n\nexport type ClientConstructor = new (\n  app: Application,\n  options: AuthenticationClientOptions\n) => AuthenticationClient\n\nexport interface AuthenticationClientOptions {\n  storage: Storage\n  header: string\n  scheme: string\n  storageKey: string\n  locationKey: string\n  locationErrorKey: string\n  jwtStrategy: string\n  path: string\n  Authentication: ClientConstructor\n}\n\nexport class AuthenticationClient {\n  app: Application\n  authenticated: boolean\n  options: AuthenticationClientOptions\n\n  constructor(app: Application, options: AuthenticationClientOptions) {\n    const socket = app.io\n    const storage = new StorageWrapper(app.get('storage') || options.storage)\n\n    this.app = app\n    this.options = options\n    this.authenticated = false\n    this.app.set('storage', storage)\n\n    if (socket) {\n      this.handleSocket(socket)\n    }\n  }\n\n  get service() {\n    return this.app.service(this.options.path)\n  }\n\n  get storage() {\n    return this.app.get('storage') as Storage\n  }\n\n  handleSocket(socket: any) {\n    // When the socket disconnects and we are still authenticated, try to reauthenticate right away\n    // the websocket connection will handle timeouts and retries\n    socket.on('disconnect', () => {\n      if (this.authenticated) {\n        this.reAuthenticate(true)\n      }\n    })\n  }\n\n  /**\n   * Parse the access token or authentication error from the window location hash. Will remove it from the hash\n   * if found.\n   *\n   * @param location The window location\n   * @returns The access token if available, will throw an error if found, otherwise null\n   */\n  getFromLocation(location: Location) {\n    const [accessToken, tokenRegex] = getMatch(location, this.options.locationKey)\n\n    if (accessToken !== null) {\n      location.hash = location.hash.replace(tokenRegex, '')\n\n      return Promise.resolve(accessToken)\n    }\n\n    const [message, errorRegex] = getMatch(location, this.options.locationErrorKey)\n\n    if (message !== null) {\n      location.hash = location.hash.replace(errorRegex, '')\n\n      return Promise.reject(new OauthError(decodeURIComponent(message)))\n    }\n\n    return Promise.resolve(null)\n  }\n\n  /**\n   * Set the access token in storage.\n   *\n   * @param accessToken The access token to set\n   * @returns\n   */\n  setAccessToken(accessToken: string) {\n    return this.storage.setItem(this.options.storageKey, accessToken)\n  }\n\n  /**\n   * Returns the access token from storage or the window location hash.\n   *\n   * @returns The access token from storage or location hash\n   */\n  getAccessToken(): Promise<string | null> {\n    return this.storage.getItem(this.options.storageKey).then((accessToken: string) => {\n      if (!accessToken && typeof window !== 'undefined' && window.location) {\n        return this.getFromLocation(window.location)\n      }\n\n      return accessToken || null\n    })\n  }\n\n  /**\n   * Remove the access token from storage\n   * @returns The removed access token\n   */\n  removeAccessToken() {\n    return this.storage.removeItem(this.options.storageKey)\n  }\n\n  /**\n   * Reset the internal authentication state. Usually not necessary to call directly.\n   *\n   * @returns null\n   */\n  reset() {\n    this.app.set('authentication', null)\n    this.authenticated = false\n\n    return Promise.resolve(null)\n  }\n\n  handleError(error: FeathersError, type: 'authenticate' | 'logout') {\n    // For NotAuthenticated, PaymentError, Forbidden, NotFound, MethodNotAllowed, NotAcceptable\n    // errors, remove the access token\n    if (error.code > 400 && error.code < 408) {\n      const promise = this.removeAccessToken().then(() => this.reset())\n\n      return type === 'logout' ? promise : promise.then(() => Promise.reject(error))\n    }\n\n    return this.reset().then(() => Promise.reject(error))\n  }\n\n  /**\n   * Try to reauthenticate using the token from storage. Will do nothing if already authenticated unless\n   * `force` is true.\n   *\n   * @param force force reauthentication with the server\n   * @param strategy The name of the strategy to use. Defaults to `options.jwtStrategy`\n   * @param authParams Additional authentication parameters\n   * @returns The reauthentication result\n   */\n  reAuthenticate(force = false, strategy?: string, authParams?: Params): Promise<AuthenticationResult> {\n    // Either returns the authentication state or\n    // tries to re-authenticate with the stored JWT and strategy\n    let authPromise = this.app.get('authentication')\n\n    if (!authPromise || force === true) {\n      authPromise = this.getAccessToken().then((accessToken) => {\n        if (!accessToken) {\n          return this.handleError(new NotAuthenticated('No accessToken found in storage'), 'authenticate')\n        }\n\n        return this.authenticate(\n          {\n            strategy: strategy || this.options.jwtStrategy,\n            accessToken\n          },\n          authParams\n        )\n      })\n      this.app.set('authentication', authPromise)\n    }\n\n    return authPromise\n  }\n\n  /**\n   * Authenticate using a specific strategy and data.\n   *\n   * @param authentication The authentication data\n   * @param params Additional parameters\n   * @returns The authentication result\n   */\n  authenticate(authentication?: AuthenticationRequest, params?: Params): Promise<AuthenticationResult> {\n    if (!authentication) {\n      return this.reAuthenticate()\n    }\n\n    const promise = this.service\n      .create(authentication, params)\n      .then((authResult: AuthenticationResult) => {\n        const { accessToken } = authResult\n\n        this.authenticated = true\n        this.app.emit('login', authResult)\n        this.app.emit('authenticated', authResult)\n\n        return this.setAccessToken(accessToken).then(() => authResult)\n      })\n      .catch((error: FeathersError) => this.handleError(error, 'authenticate'))\n\n    this.app.set('authentication', promise)\n\n    return promise\n  }\n\n  /**\n   * Log out the current user and remove their token. Will do nothing\n   * if not authenticated.\n   *\n   * @returns The log out result.\n   */\n  logout(): Promise<AuthenticationResult | null> {\n    return Promise.resolve(this.app.get('authentication'))\n      .then(() =>\n        this.service.remove(null).then((authResult: AuthenticationResult) =>\n          this.removeAccessToken()\n            .then(() => this.reset())\n            .then(() => {\n              this.app.emit('logout', authResult)\n\n              return authResult\n            })\n        )\n      )\n      .catch((error: FeathersError) => this.handleError(error, 'logout'))\n  }\n}\n"
  },
  {
    "path": "packages/authentication-client/src/hooks/authentication.ts",
    "content": "import { HookContext, NextFunction } from '@feathersjs/feathers'\nimport { stripSlashes } from '@feathersjs/commons'\n\nexport const authentication = () => {\n  return (context: HookContext, next: NextFunction) => {\n    const {\n      app,\n      params,\n      path,\n      method,\n      app: { authentication: service }\n    } = context\n\n    if (stripSlashes(service.options.path) === path && method === 'create') {\n      return next()\n    }\n\n    return Promise.resolve(app.get('authentication'))\n      .then((authResult) => {\n        if (authResult) {\n          context.params = Object.assign({}, authResult, params)\n        }\n      })\n      .then(next)\n  }\n}\n"
  },
  {
    "path": "packages/authentication-client/src/hooks/index.ts",
    "content": "export { authentication } from './authentication'\nexport { populateHeader } from './populate-header'\n"
  },
  {
    "path": "packages/authentication-client/src/hooks/populate-header.ts",
    "content": "import { HookContext, NextFunction } from '@feathersjs/feathers'\n\nexport const populateHeader = () => {\n  return (context: HookContext, next: NextFunction) => {\n    const {\n      app,\n      params: { accessToken }\n    } = context\n    const authentication = app.authentication\n\n    // Set REST header if necessary\n    if (app.rest && accessToken) {\n      const { scheme, header } = authentication.options\n      const authHeader = `${scheme} ${accessToken}`\n\n      context.params.headers = Object.assign(\n        {},\n        {\n          [header]: authHeader\n        },\n        context.params.headers\n      )\n    }\n\n    return next()\n  }\n}\n"
  },
  {
    "path": "packages/authentication-client/src/index.ts",
    "content": "import { AuthenticationClient, AuthenticationClientOptions } from './core'\nimport * as hooks from './hooks'\nimport { Application } from '@feathersjs/feathers'\nimport { Storage, MemoryStorage, StorageWrapper } from './storage'\n\ndeclare module '@feathersjs/feathers/lib/declarations' {\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  interface Application<Services, Settings> {\n    // eslint-disable-line\n    io: any\n    rest?: any\n    authentication: AuthenticationClient\n    authenticate: AuthenticationClient['authenticate']\n    reAuthenticate: AuthenticationClient['reAuthenticate']\n    logout: AuthenticationClient['logout']\n  }\n}\n\nexport const getDefaultStorage = () => {\n  try {\n    return new StorageWrapper(window.localStorage)\n  } catch (error: any) {}\n\n  return new MemoryStorage()\n}\n\nexport { AuthenticationClient, AuthenticationClientOptions, Storage, MemoryStorage, hooks }\n\nexport type ClientConstructor = new (\n  app: Application,\n  options: AuthenticationClientOptions\n) => AuthenticationClient\n\nexport const defaultStorage: Storage = getDefaultStorage()\n\nexport const defaults: AuthenticationClientOptions = {\n  header: 'Authorization',\n  scheme: 'Bearer',\n  storageKey: 'feathers-jwt',\n  locationKey: 'access_token',\n  locationErrorKey: 'error',\n  jwtStrategy: 'jwt',\n  path: '/authentication',\n  Authentication: AuthenticationClient,\n  storage: defaultStorage\n}\n\nconst init = (_options: Partial<AuthenticationClientOptions> = {}) => {\n  const options: AuthenticationClientOptions = Object.assign({}, defaults, _options)\n  const { Authentication } = options\n\n  return (app: Application) => {\n    const authentication = new Authentication(app, options)\n\n    app.authentication = authentication\n    app.authenticate = authentication.authenticate.bind(authentication)\n    app.reAuthenticate = authentication.reAuthenticate.bind(authentication)\n    app.logout = authentication.logout.bind(authentication)\n\n    app.hooks([hooks.authentication(), hooks.populateHeader()])\n  }\n}\n\nexport default init\n\nif (typeof module !== 'undefined') {\n  module.exports = Object.assign(init, module.exports)\n}\n"
  },
  {
    "path": "packages/authentication-client/src/storage.ts",
    "content": "export interface Storage {\n  getItem(key: string): any\n  setItem?(key: string, value: any): any\n  removeItem?(key: string): any\n}\n\nexport class MemoryStorage implements Storage {\n  store: { [key: string]: any }\n\n  constructor() {\n    this.store = {}\n  }\n\n  getItem(key: string) {\n    return Promise.resolve(this.store[key])\n  }\n\n  setItem(key: string, value: any) {\n    return Promise.resolve((this.store[key] = value))\n  }\n\n  removeItem(key: string) {\n    const value = this.store[key]\n\n    delete this.store[key]\n\n    return Promise.resolve(value)\n  }\n}\n\nexport class StorageWrapper implements Storage {\n  storage: any\n\n  constructor(storage: any) {\n    this.storage = storage\n  }\n\n  getItem(key: string) {\n    return Promise.resolve(this.storage?.getItem(key))\n  }\n\n  setItem(key: string, value: any) {\n    return Promise.resolve(this.storage?.setItem(key, value))\n  }\n\n  removeItem(key: string) {\n    return Promise.resolve(this.storage?.removeItem(key))\n  }\n}\n"
  },
  {
    "path": "packages/authentication-client/test/index.test.ts",
    "content": "import assert from 'assert'\nimport { feathers, Application } from '@feathersjs/feathers'\n\nimport client from '../src'\nimport { AuthenticationClient } from '../src'\nimport { NotAuthenticated } from '@feathersjs/errors'\n\ndescribe('@feathersjs/authentication-client', () => {\n  const accessToken = 'testing'\n  const user = {\n    name: 'Test User'\n  }\n  let app: Application\n\n  beforeEach(() => {\n    app = feathers()\n\n    app.configure(client())\n    app.use('/authentication', {\n      async create(data: any) {\n        if (data.error) {\n          throw new Error('Did not work')\n        }\n\n        return {\n          accessToken,\n          data,\n          user\n        }\n      },\n\n      async remove(id) {\n        if (!app.get('authentication')) {\n          throw new NotAuthenticated('Not logged in')\n        }\n\n        return { id }\n      }\n    })\n    app.use('dummy', {\n      async find(params) {\n        return params\n      }\n    })\n  })\n\n  it('initializes', () => {\n    assert.ok(app.authentication instanceof AuthenticationClient)\n    assert.strictEqual(app.get('storage'), app.authentication.storage)\n    assert.strictEqual(typeof app.authenticate, 'function')\n    assert.strictEqual(typeof app.logout, 'function')\n  })\n\n  it('setAccessToken, getAccessToken, removeAccessToken', async () => {\n    const auth = app.authentication\n    const token = 'hi'\n\n    await auth.setAccessToken(token)\n\n    const res = await auth.getAccessToken()\n\n    assert.strictEqual(res, token)\n\n    await auth.removeAccessToken()\n    assert.strictEqual(await auth.getAccessToken(), null)\n  })\n\n  it('getFromLocation', async () => {\n    const auth = app.authentication\n    let dummyLocation = { hash: 'access_token=testing' } as Location\n\n    let token = await auth.getFromLocation(dummyLocation)\n\n    assert.strictEqual(token, 'testing')\n    assert.strictEqual(dummyLocation.hash, '')\n\n    dummyLocation.hash = 'a=b&access_token=otherTest&c=d'\n    token = await auth.getFromLocation(dummyLocation)\n\n    assert.strictEqual(token, 'otherTest')\n    assert.strictEqual(dummyLocation.hash, 'a=b&c=d')\n\n    dummyLocation = { search: 'access_token=testing' } as Location\n    token = await auth.getFromLocation(dummyLocation)\n\n    assert.strictEqual(await auth.getFromLocation({} as Location), null)\n\n    try {\n      await auth.getFromLocation({\n        hash: 'error=Error Happened&x=y'\n      } as Location)\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.name, 'OauthError')\n      assert.strictEqual(error.message, 'Error Happened')\n    }\n  })\n\n  it('authenticate, authentication hook, login event', async () => {\n    const data = {\n      strategy: 'testing'\n    }\n\n    const promise = new Promise((resolve) => {\n      app.once('login', resolve)\n    })\n\n    app.authenticate(data)\n\n    const result = await promise\n\n    assert.deepStrictEqual(result, {\n      accessToken,\n      data,\n      user\n    })\n\n    let at = await app.authentication.getAccessToken()\n\n    assert.strictEqual(at, accessToken, 'Set accessToken in storage')\n\n    at = await Promise.resolve(app.get('storage').getItem('feathers-jwt'))\n\n    assert.strictEqual(at, accessToken, 'Set accessToken in storage')\n\n    const found = await app.service('dummy').find()\n    assert.deepStrictEqual(found.accessToken, accessToken)\n    assert.deepStrictEqual(found.user, user)\n  })\n\n  it('logout event', async () => {\n    const promise = new Promise((resolve) => app.once('logout', resolve))\n\n    app.authenticate({ strategy: 'testing' }).then(() => app.logout())\n\n    const result = await promise\n\n    assert.deepStrictEqual(result, { id: null })\n  })\n\n  it('does not remove AccessToken on other errors', async () => {\n    await app.authenticate({ strategy: 'testing' })\n    await app.authenticate({ strategy: 'testing' })\n\n    const at = await app.authentication.getAccessToken()\n\n    assert.strictEqual(at, accessToken)\n  })\n\n  it('resets after any error (#1947)', async () => {\n    await assert.rejects(() => app.authenticate({ strategy: 'testing', error: true }), {\n      message: 'Did not work'\n    })\n\n    const found = await app.service('dummy').find()\n\n    assert.deepStrictEqual(found, {})\n  })\n\n  it('logout when not logged in without error', async () => {\n    const result = await app.logout()\n\n    assert.strictEqual(result, null)\n  })\n\n  describe('reauthenticate', () => {\n    it('fails when no token in storage and resets authentication state', async () => {\n      await assert.rejects(() => app.authentication.reAuthenticate(), {\n        message: 'No accessToken found in storage'\n      })\n      assert.ok(!app.get('authentication'), 'Reset authentication')\n    })\n\n    it('reauthenticates when token is in storage', async () => {\n      const data = {\n        strategy: 'testing'\n      }\n\n      const result = await app.authenticate(data)\n\n      assert.deepStrictEqual(result, {\n        accessToken,\n        data,\n        user\n      })\n      await app.authentication.reAuthenticate()\n      await app.authentication.reset()\n\n      let at = await Promise.resolve(app.get('storage').getItem('feathers-jwt'))\n\n      assert.strictEqual(at, accessToken, 'Set accessToken in storage')\n\n      at = await app.authentication.reAuthenticate()\n\n      assert.deepStrictEqual(at, {\n        accessToken,\n        data: { strategy: 'jwt', accessToken: 'testing' },\n        user\n      })\n\n      await app.logout()\n\n      at = await Promise.resolve(app.get('storage').getItem('feathers-jwt'))\n      assert.ok(!at)\n      assert.ok(!app.get('authentication'))\n    })\n\n    it('reAuthenticate works with parallel requests', async () => {\n      const data = {\n        strategy: 'testing'\n      }\n\n      await app.authenticate(data)\n      await app.reAuthenticate()\n      await app.authentication.reset()\n\n      app.reAuthenticate()\n\n      const found = await app.service('dummy').find()\n\n      assert.deepStrictEqual(found.accessToken, accessToken)\n      assert.deepStrictEqual(found.user, user)\n    })\n\n    it('reauthenticates using different strategy', async () => {\n      app.configure(client({ jwtStrategy: 'any' }))\n\n      const data = {\n        strategy: 'testing'\n      }\n\n      let result = await app.authenticate(data)\n      assert.deepStrictEqual(result, {\n        accessToken,\n        data,\n        user\n      })\n\n      result = await app.authentication.reAuthenticate(false, 'jwt')\n      assert.deepStrictEqual(result, {\n        accessToken,\n        data,\n        user\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "packages/authentication-client/test/integration/commons.ts",
    "content": "import assert from 'assert'\nimport { Application } from '@feathersjs/feathers'\nimport '../../src'\n\nexport default (\n  getApp: () => Application,\n  getClient: () => Application,\n  { provider, email, password }: { provider: string; email: string; password: string }\n) => {\n  describe('common tests', () => {\n    let client: Application\n    let user: any\n\n    before(\n      async () =>\n        (user = await getApp().service('users').create({\n          email,\n          password\n        }))\n    )\n\n    beforeEach(() => {\n      client = getClient()\n    })\n\n    after(async () => {\n      await getApp().service('users').remove(user.id)\n    })\n\n    it('authenticates with local strategy', async () => {\n      const result = await client.authenticate({\n        strategy: 'local',\n        email,\n        password\n      })\n\n      assert.ok(result.accessToken)\n      assert.strictEqual(result.authentication.strategy, 'local')\n      assert.strictEqual(result.user.email, email)\n    })\n\n    it('authentication with wrong credentials fails, does not maintain state', async () => {\n      await assert.rejects(\n        () =>\n          client.authenticate({\n            strategy: 'local',\n            email,\n            password: 'blabla'\n          }),\n        {\n          name: 'NotAuthenticated',\n          message: 'Invalid login'\n        }\n      )\n      assert.ok(!client.get('authentication'), 'Reset client state')\n    })\n\n    it('errors when not authenticated', async () => {\n      await assert.rejects(() => client.service('dummy').find(), {\n        name: 'NotAuthenticated',\n        code: 401,\n        message: 'Not authenticated'\n      })\n    })\n\n    it('authenticates and allows access', async () => {\n      await client.authenticate({\n        strategy: 'local',\n        email,\n        password\n      })\n      const result = await client.service('dummy').find()\n\n      assert.strictEqual(result.provider, provider)\n      assert.ok(result.authentication)\n      assert.ok(result.authentication.payload)\n      assert.strictEqual(result.user.email, user.email)\n      assert.strictEqual(result.user.id, user.id)\n    })\n\n    it('re-authenticates', async () => {\n      await client.authenticate({\n        strategy: 'local',\n        email,\n        password\n      })\n\n      client.authentication.reset()\n      client.authenticate()\n      const result = await client.service('dummy').find()\n\n      assert.strictEqual(result.provider, provider)\n      assert.ok(result.authentication)\n      assert.ok(result.authentication.payload)\n      assert.strictEqual(result.user.email, user.email)\n      assert.strictEqual(result.user.id, user.id)\n    })\n\n    it('after logout does not allow subsequent access', async () => {\n      await client.authenticate({\n        strategy: 'local',\n        email,\n        password\n      })\n\n      const result = await client.logout()\n\n      assert.ok(result!.accessToken)\n      assert.ok(result!.user)\n\n      assert.rejects(() => client.service('dummy').find(), {\n        name: 'NotAuthenticated',\n        code: 401,\n        message: 'Not authenticated'\n      })\n    })\n  })\n}\n"
  },
  {
    "path": "packages/authentication-client/test/integration/express.test.ts",
    "content": "import axios from 'axios'\nimport { Server } from 'http'\nimport { feathers, Application as FeathersApplication } from '@feathersjs/feathers'\nimport * as express from '@feathersjs/express'\nimport rest from '@feathersjs/rest-client'\n\nimport authClient from '../../src'\nimport getApp from './fixture'\nimport commonTests from './commons'\n\ndescribe('@feathersjs/authentication-client Express integration', () => {\n  let app: express.Application\n  let server: Server\n\n  before(async () => {\n    const restApp = express\n      .default(feathers())\n      .use(express.json())\n      .configure(express.rest())\n      .use(express.parseAuthentication())\n    app = getApp(restApp as unknown as FeathersApplication) as express.Application\n    app.use(express.errorHandler())\n\n    server = await app.listen(9776)\n  })\n\n  after((done) => server.close(() => done()))\n\n  commonTests(\n    () => app,\n    () => {\n      return feathers().configure(rest('http://localhost:9776').axios(axios)).configure(authClient())\n    },\n    {\n      email: 'expressauth@feathersjs.com',\n      password: 'secret',\n      provider: 'rest'\n    }\n  )\n})\n"
  },
  {
    "path": "packages/authentication-client/test/integration/fixture.ts",
    "content": "import { authenticate } from '@feathersjs/authentication'\nimport { HookContext, Application } from '@feathersjs/feathers'\nimport { memory } from '@feathersjs/memory'\nimport { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'\nimport { LocalStrategy, hooks } from '@feathersjs/authentication-local'\n\nconst { hashPassword, protect } = hooks\n\nexport default (app: Application) => {\n  const authentication = new AuthenticationService(app)\n\n  app.set('authentication', {\n    entity: 'user',\n    service: 'users',\n    secret: 'supersecret',\n    authStrategies: ['local', 'jwt'],\n    local: {\n      usernameField: 'email',\n      passwordField: 'password'\n    }\n  })\n\n  authentication.register('jwt', new JWTStrategy())\n  authentication.register('local', new LocalStrategy())\n\n  app.use('/authentication', authentication)\n  app.use(\n    '/users',\n    memory({\n      paginate: {\n        default: 10,\n        max: 20\n      }\n    })\n  )\n\n  app.service('users').hooks({\n    before: {\n      create: hashPassword('password')\n    },\n    after: protect('password')\n  })\n\n  app.use('/dummy', {\n    find(params) {\n      return Promise.resolve(params)\n    }\n  })\n\n  app.service('dummy').hooks({\n    before: authenticate('jwt')\n  })\n\n  app.service('users').hooks({\n    before(context: HookContext) {\n      if (context.id !== undefined && context.id !== null) {\n        context.id = parseInt(context.id as string, 10)\n      }\n\n      return context\n    }\n  })\n\n  return app\n}\n"
  },
  {
    "path": "packages/authentication-client/test/integration/socketio.test.ts",
    "content": "import { io } from 'socket.io-client'\nimport assert from 'assert'\nimport { feathers, Application } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio'\nimport socketioClient from '@feathersjs/socketio-client'\n\nimport authClient from '../../src'\nimport getApp from './fixture'\nimport commonTests from './commons'\nimport { AuthenticationResult } from '@feathersjs/authentication/lib'\n\ndescribe('@feathersjs/authentication-client Socket.io integration', () => {\n  let app: Application\n\n  before(async () => {\n    app = getApp(feathers().configure(socketio()))\n\n    await app.listen(9777)\n  })\n\n  after((done) => {\n    app.io.close(() => done())\n  })\n\n  it('allows to authenticate with handshake headers and sends login event', async () => {\n    const user = { email: 'authtest@example.com', password: 'alsosecret' }\n\n    await app.service('users').create(user)\n\n    const { accessToken } = await app.service('authentication').create({\n      strategy: 'local',\n      ...user\n    })\n\n    const socket = io('http://localhost:9777', {\n      transports: ['websocket'],\n      transportOptions: {\n        websocket: {\n          extraHeaders: {\n            Authorization: `Bearer ${accessToken}`\n          }\n        }\n      }\n    })\n    const authResult: any = await new Promise((resolve) => app.once('login', (res) => resolve(res)))\n\n    assert.strictEqual(authResult.accessToken, accessToken)\n\n    const dummy: any = await new Promise((resolve, reject) => {\n      socket.emit('find', 'dummy', {}, (error: Error, page: any) => (error ? reject(error) : resolve(page)))\n    })\n\n    assert.strictEqual(dummy.user.email, user.email)\n    assert.strictEqual(dummy.authentication.accessToken, accessToken)\n    assert.strictEqual(dummy.headers.authorization, `Bearer ${accessToken}`)\n  })\n\n  it('reconnects after socket disconnection', async () => {\n    const user = { email: 'disconnecttest@example.com', password: 'alsosecret' }\n    const socket = io('http://localhost:9777', {\n      timeout: 500,\n      reconnection: true,\n      reconnectionDelay: 100\n    })\n    const client = feathers().configure(socketioClient(socket)).configure(authClient())\n\n    await app.service('users').create(user)\n    await client.authenticate({\n      strategy: 'local',\n      ...user\n    })\n\n    const onLogin = new Promise<AuthenticationResult>((resolve) => app.once('login', (data) => resolve(data)))\n\n    socket.once('disconnect', () => socket.connect())\n    socket.disconnect()\n\n    const {\n      authentication: { strategy }\n    } = await onLogin\n    const dummy = await client.service('dummy').find()\n\n    assert.strictEqual(strategy, 'jwt')\n    assert.strictEqual(dummy.user.email, user.email)\n  })\n\n  commonTests(\n    () => app,\n    () => {\n      return feathers()\n        .configure(socketioClient(io('http://localhost:9777')))\n        .configure(authClient())\n    },\n    {\n      email: 'socketioauth@feathersjs.com',\n      password: 'secretive',\n      provider: 'socketio'\n    }\n  )\n})\n"
  },
  {
    "path": "packages/authentication-client/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/authentication-local/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n### Bug Fixes\n\n- Reduce usage of lodash ([#3455](https://github.com/feathersjs/feathers/issues/3455)) ([8ce807a](https://github.com/feathersjs/feathers/commit/8ce807a5ca53ff5b8d5107a0656c6329404e6e6c))\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n### Bug Fixes\n\n- **authentication-local:** Local Auth - Nested username & Password fields ([#3091](https://github.com/feathersjs/feathers/issues/3091)) ([d135526](https://github.com/feathersjs/feathers/commit/d135526da18ecf2dc620b82820e1d09d8af5c0b5))\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n### Features\n\n- **authentication-oauth:** Koa and transport independent oAuth authentication ([#2737](https://github.com/feathersjs/feathers/issues/2737)) ([9231525](https://github.com/feathersjs/feathers/commit/9231525a24bb790ba9c5d940f2867a9c727691c9))\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Features\n\n- **authentication-local:** Add passwordHash property resolver ([#2660](https://github.com/feathersjs/feathers/issues/2660)) ([b41279b](https://github.com/feathersjs/feathers/commit/b41279b55eea3771a6fa4983a37be2413287bbc6))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Features\n\n- **typescript:** Improve adapter typings ([#2605](https://github.com/feathersjs/feathers/issues/2605)) ([3b2ca0a](https://github.com/feathersjs/feathers/commit/3b2ca0a6a8e03e8390272c4d7e930b4bffdaacf5))\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n### Bug Fixes\n\n- **hooks:** Allow all built-in hooks to be used the async and regular way ([#2559](https://github.com/feathersjs/feathers/issues/2559)) ([8f9f631](https://github.com/feathersjs/feathers/commit/8f9f631e0ce89de349207db72def84e7ab496a4a))\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n### Bug Fixes\n\n- **authentication-local:** adds error handling for undefined/null password field ([#2444](https://github.com/feathersjs/feathers/issues/2444)) ([4323f98](https://github.com/feathersjs/feathers/commit/4323f9859a66a7fe3f7f15d81476bd81b735c226))\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- **hooks:** Migrate built-in hooks and allow backwards compatibility ([#2358](https://github.com/feathersjs/feathers/issues/2358)) ([759c5a1](https://github.com/feathersjs/feathers/commit/759c5a19327a731af965c3604119393b3d09a406))\n- **koa:** Use extended query parser for compatibility ([#2397](https://github.com/feathersjs/feathers/issues/2397)) ([b2944ba](https://github.com/feathersjs/feathers/commit/b2944bac3ec6d5ecc80dc518cd4e58093692db74))\n\n### Features\n\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n### Features\n\n- **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n### Features\n\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n### Bug Fixes\n\n- **authentication:** Add JWT getEntityQuery ([#2013](https://github.com/feathersjs/feathers/issues/2013)) ([e0e7fb5](https://github.com/feathersjs/feathers/commit/e0e7fb5162940fe776731283b40026c61d9c8a33))\n\n## [4.5.6](https://github.com/feathersjs/feathers/compare/v4.5.5...v4.5.6) (2020-07-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.5.4](https://github.com/feathersjs/feathers/compare/v4.5.3...v4.5.4) (2020-04-29)\n\n### Bug Fixes\n\n- **authentication-local:** Allow to hash passwords in array data ([#1936](https://github.com/feathersjs/feathers/issues/1936)) ([64705f5](https://github.com/feathersjs/feathers/commit/64705f5d9d4dc27f799da3a074efaf74379a3398))\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n### Bug Fixes\n\n- **test:** typo in password ([#1797](https://github.com/feathersjs/feathers/issues/1797)) ([dfba6ec](https://github.com/feathersjs/feathers/commit/dfba6ec2f21adf3aa739218cf870eaaaa5df6e9c))\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n### Features\n\n- **authentication:** Add parseStrategies to allow separate strategies for creating JWTs and parsing headers ([#1708](https://github.com/feathersjs/feathers/issues/1708)) ([5e65629](https://github.com/feathersjs/feathers/commit/5e65629b924724c3e81d7c81df047e123d1c8bd7))\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.3.5](https://github.com/feathersjs/feathers/compare/v4.3.4...v4.3.5) (2019-10-07)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n### Bug Fixes\n\n- Small improvements in dependencies and code sturcture ([#1562](https://github.com/feathersjs/feathers/issues/1562)) ([42c13e2](https://github.com/feathersjs/feathers/commit/42c13e2))\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n### Bug Fixes\n\n- LocalStrategy authenticates without username ([#1560](https://github.com/feathersjs/feathers/issues/1560)) ([2b258fd](https://github.com/feathersjs/feathers/commit/2b258fd)), closes [#1559](https://github.com/feathersjs/feathers/issues/1559)\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n### Bug Fixes\n\n- Add method to reliably get default authentication service ([#1470](https://github.com/feathersjs/feathers/issues/1470)) ([e542cb3](https://github.com/feathersjs/feathers/commit/e542cb3))\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n### Bug Fixes\n\n- Always require strategy parameter in authentication ([#1327](https://github.com/feathersjs/feathers/issues/1327)) ([d4a8021](https://github.com/feathersjs/feathers/commit/d4a8021))\n- Improve authentication parameter handling ([#1333](https://github.com/feathersjs/feathers/issues/1333)) ([6e77204](https://github.com/feathersjs/feathers/commit/6e77204))\n- Merge httpStrategies and authStrategies option ([#1308](https://github.com/feathersjs/feathers/issues/1308)) ([afa4d55](https://github.com/feathersjs/feathers/commit/afa4d55))\n- Rename jwtStrategies option to authStrategies ([#1305](https://github.com/feathersjs/feathers/issues/1305)) ([4aee151](https://github.com/feathersjs/feathers/commit/4aee151))\n\n### Features\n\n- Change and *JWT methods to *accessToken ([#1304](https://github.com/feathersjs/feathers/issues/1304)) ([5ac826b](https://github.com/feathersjs/feathers/commit/5ac826b))\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Authentication core improvements ([#1260](https://github.com/feathersjs/feathers/issues/1260)) ([c5dc7a2](https://github.com/feathersjs/feathers/commit/c5dc7a2))\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n- **package:** update debug to version 3.0.0 ([#31](https://github.com/feathersjs/feathers/issues/31)) ([f23d617](https://github.com/feathersjs/feathers/commit/f23d617))\n\n### Features\n\n- @feathersjs/authentication-oauth ([#1299](https://github.com/feathersjs/feathers/issues/1299)) ([656bae7](https://github.com/feathersjs/feathers/commit/656bae7))\n- Add AuthenticationBaseStrategy and make authentication option handling more explicit ([#1284](https://github.com/feathersjs/feathers/issues/1284)) ([2667d92](https://github.com/feathersjs/feathers/commit/2667d92))\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Authentication v3 core server implementation ([#1205](https://github.com/feathersjs/feathers/issues/1205)) ([1bd7591](https://github.com/feathersjs/feathers/commit/1bd7591))\n- Authentication v3 local authentication ([#1211](https://github.com/feathersjs/feathers/issues/1211)) ([0fa5f7c](https://github.com/feathersjs/feathers/commit/0fa5f7c))\n\n### BREAKING CHANGES\n\n- Update authentication strategies for @feathersjs/authentication v3\n\n## [1.2.9](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-local@1.2.8...@feathersjs/authentication-local@1.2.9) (2019-01-02)\n\n### Bug Fixes\n\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n\n<a name=\"1.2.8\"></a>\n\n## [1.2.8](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-local@1.2.7...@feathersjs/authentication-local@1.2.8) (2018-12-16)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n<a name=\"1.2.7\"></a>\n\n## [1.2.7](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-local@1.2.6...@feathersjs/authentication-local@1.2.7) (2018-10-26)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n<a name=\"1.2.6\"></a>\n\n## [1.2.6](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-local@1.2.5...@feathersjs/authentication-local@1.2.6) (2018-10-25)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n\n<a name=\"1.2.5\"></a>\n\n## [1.2.5](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-local@1.2.4...@feathersjs/authentication-local@1.2.5) (2018-09-21)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n<a name=\"1.2.4\"></a>\n\n## [1.2.4](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-local@1.2.3...@feathersjs/authentication-local@1.2.4) (2018-09-17)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n<a name=\"1.2.3\"></a>\n\n## [1.2.3](https://github.com/feathersjs/feathers/compare/@feathersjs/authentication-local@1.2.2...@feathersjs/authentication-local@1.2.3) (2018-09-02)\n\n**Note:** Version bump only for package @feathersjs/authentication-local\n\n<a name=\"1.2.2\"></a>\n\n## 1.2.2\n\n- Migrate to Monorepo ([feathers#462](https://github.com/feathersjs/feathers/issues/462))\n\n## [v1.2.1](https://github.com/feathersjs/authentication-local/tree/v1.2.1) (2018-05-02)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v1.2.0...v1.2.1)\n\n**Merged pull requests:**\n\n- Make sure the original object is not modified [\\#65](https://github.com/feathersjs/authentication-local/pull/65) ([daffl](https://github.com/daffl))\n\n## [v1.2.0](https://github.com/feathersjs/authentication-local/tree/v1.2.0) (2018-05-02)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v1.1.3...v1.2.0)\n\n**Merged pull requests:**\n\n- added support for nested password fields option in hash password hook [\\#64](https://github.com/feathersjs/authentication-local/pull/64) ([ThePesta](https://github.com/ThePesta))\n\n## [v1.1.3](https://github.com/feathersjs/authentication-local/tree/v1.1.3) (2018-04-20)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v1.1.2...v1.1.3)\n\n**Merged pull requests:**\n\n- Adding tests and calling to hasOwnProperty on Object.prototype instead of assuming valid prototype [\\#63](https://github.com/feathersjs/authentication-local/pull/63) ([pmabres](https://github.com/pmabres))\n\n## [v1.1.2](https://github.com/feathersjs/authentication-local/tree/v1.1.2) (2018-04-15)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v1.1.1...v1.1.2)\n\n**Closed issues:**\n\n- Protect hooks does not support dot notation [\\#61](https://github.com/feathersjs/authentication-local/issues/61)\n\n**Merged pull requests:**\n\n- Use latest version of Lodash [\\#62](https://github.com/feathersjs/authentication-local/pull/62) ([daffl](https://github.com/daffl))\n\n## [v1.1.1](https://github.com/feathersjs/authentication-local/tree/v1.1.1) (2018-03-25)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v1.1.0...v1.1.1)\n\n**Closed issues:**\n\n- hash-password hook will skip users if they are missing password [\\#58](https://github.com/feathersjs/authentication-local/issues/58)\n- User service create method gets called upon each validation [\\#56](https://github.com/feathersjs/authentication-local/issues/56)\n\n**Merged pull requests:**\n\n- Do not skip users that have no password [\\#60](https://github.com/feathersjs/authentication-local/pull/60) ([daffl](https://github.com/daffl))\n- Update sinon to the latest version 🚀 [\\#59](https://github.com/feathersjs/authentication-local/pull/59) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update sinon-chai to the latest version 🚀 [\\#57](https://github.com/feathersjs/authentication-local/pull/57) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.1.0](https://github.com/feathersjs/authentication-local/tree/v1.1.0) (2018-01-23)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v1.0.4...v1.1.0)\n\n**Closed issues:**\n\n- protect hook attempts to map through 'result.data' on all service methods. [\\#53](https://github.com/feathersjs/authentication-local/issues/53)\n- Protect hook should check for toJSON [\\#48](https://github.com/feathersjs/authentication-local/issues/48)\n\n**Merged pull requests:**\n\n- Use .toJSON if available [\\#55](https://github.com/feathersjs/authentication-local/pull/55) ([daffl](https://github.com/daffl))\n- Only map data for find method [\\#54](https://github.com/feathersjs/authentication-local/pull/54) ([daffl](https://github.com/daffl))\n- Update @feathersjs/authentication-jwt to the latest version 🚀 [\\#52](https://github.com/feathersjs/authentication-local/pull/52) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update mocha to the latest version 🚀 [\\#51](https://github.com/feathersjs/authentication-local/pull/51) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.4](https://github.com/feathersjs/authentication-local/tree/v1.0.4) (2018-01-03)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v1.0.3...v1.0.4)\n\n## [v1.0.3](https://github.com/feathersjs/authentication-local/tree/v1.0.3) (2018-01-03)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v1.0.2...v1.0.3)\n\n**Closed issues:**\n\n- local authentication bug with users as sequelize service [\\#47](https://github.com/feathersjs/authentication-local/issues/47)\n\n**Merged pull requests:**\n\n- Update documentation to correspond with latest release [\\#50](https://github.com/feathersjs/authentication-local/pull/50) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#49](https://github.com/feathersjs/authentication-local/pull/49) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.2](https://github.com/feathersjs/authentication-local/tree/v1.0.2) (2017-12-06)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v1.0.1...v1.0.2)\n\n**Closed issues:**\n\n- why is the password send as plain text instead of encrypting it on client side? [\\#44](https://github.com/feathersjs/authentication-local/issues/44)\n\n**Merged pull requests:**\n\n- Update hook.result if an external provider is set [\\#46](https://github.com/feathersjs/authentication-local/pull/46) ([daffl](https://github.com/daffl))\n- Update feathers-memory to the latest version 🚀 [\\#45](https://github.com/feathersjs/authentication-local/pull/45) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.1](https://github.com/feathersjs/authentication-local/tree/v1.0.1) (2017-11-16)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v1.0.0...v1.0.1)\n\n**Merged pull requests:**\n\n- Add default export for better ES module \\(TypeScript\\) compatibility [\\#43](https://github.com/feathersjs/authentication-local/pull/43) ([daffl](https://github.com/daffl))\n- Update @feathersjs/authentication to the latest version 🚀 [\\#42](https://github.com/feathersjs/authentication-local/pull/42) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.0](https://github.com/feathersjs/authentication-local/tree/v1.0.0) (2017-11-01)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v1.0.0-pre.2...v1.0.0)\n\n**Merged pull requests:**\n\n- Update dependencies for release [\\#41](https://github.com/feathersjs/authentication-local/pull/41) ([daffl](https://github.com/daffl))\n\n## [v1.0.0-pre.2](https://github.com/feathersjs/authentication-local/tree/v1.0.0-pre.2) (2017-10-27)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v1.0.0-pre.1...v1.0.0-pre.2)\n\n**Merged pull requests:**\n\n- Safely dispatch without password [\\#40](https://github.com/feathersjs/authentication-local/pull/40) ([daffl](https://github.com/daffl))\n\n## [v1.0.0-pre.1](https://github.com/feathersjs/authentication-local/tree/v1.0.0-pre.1) (2017-10-25)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v0.4.4...v1.0.0-pre.1)\n\n**Closed issues:**\n\n- How configure local strategy to feathers-authentication? [\\#36](https://github.com/feathersjs/authentication-local/issues/36)\n- An in-range update of feathers is breaking the build 🚨 [\\#32](https://github.com/feathersjs/authentication-local/issues/32)\n\n**Merged pull requests:**\n\n- Update to Feathers v3 [\\#39](https://github.com/feathersjs/authentication-local/pull/39) ([daffl](https://github.com/daffl))\n- Rename repository and use npm scope [\\#38](https://github.com/feathersjs/authentication-local/pull/38) ([daffl](https://github.com/daffl))\n- Update to new plugin infrastructure [\\#37](https://github.com/feathersjs/authentication-local/pull/37) ([daffl](https://github.com/daffl))\n- Update mocha to the latest version 🚀 [\\#35](https://github.com/feathersjs/authentication-local/pull/35) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update sinon to the latest version 🚀 [\\#34](https://github.com/feathersjs/authentication-local/pull/34) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Add babel-polyfill and package-lock.json [\\#33](https://github.com/feathersjs/authentication-local/pull/33) ([daffl](https://github.com/daffl))\n- Update sinon to the latest version 🚀 [\\#29](https://github.com/feathersjs/authentication-local/pull/29) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v0.4.4](https://github.com/feathersjs/authentication-local/tree/v0.4.4) (2017-08-11)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v0.4.3...v0.4.4)\n\n**Closed issues:**\n\n- i18n support [\\#28](https://github.com/feathersjs/authentication-local/issues/28)\n- Couldn't store jwt token in cookies [\\#17](https://github.com/feathersjs/authentication-local/issues/17)\n- Strategy for subapp [\\#9](https://github.com/feathersjs/authentication-local/issues/9)\n\n**Merged pull requests:**\n\n- Update debug to the latest version 🚀 [\\#31](https://github.com/feathersjs/authentication-local/pull/31) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Increase bcrypt cost factor, add future cost factor auto-optimization [\\#30](https://github.com/feathersjs/authentication-local/pull/30) ([micaksica2](https://github.com/micaksica2))\n\n## [v0.4.3](https://github.com/feathersjs/authentication-local/tree/v0.4.3) (2017-06-22)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v0.4.2...v0.4.3)\n\n**Closed issues:**\n\n- Log a warning if service.id is undefined or null [\\#19](https://github.com/feathersjs/authentication-local/issues/19)\n\n**Merged pull requests:**\n\n- throw error if service.id is missing [\\#27](https://github.com/feathersjs/authentication-local/pull/27) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.4.2](https://github.com/feathersjs/authentication-local/tree/v0.4.2) (2017-06-22)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v0.4.1...v0.4.2)\n\n## [v0.4.1](https://github.com/feathersjs/authentication-local/tree/v0.4.1) (2017-06-22)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v0.4.0...v0.4.1)\n\n**Merged pull requests:**\n\n- Resolves \\#14 - Passes Feathers params to service hooks [\\#15](https://github.com/feathersjs/authentication-local/pull/15) ([thomas-p-wilson](https://github.com/thomas-p-wilson))\n\n## [v0.4.0](https://github.com/feathersjs/authentication-local/tree/v0.4.0) (2017-06-22)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v0.3.4...v0.4.0)\n\n**Closed issues:**\n\n- Module is using the wrong default config key [\\#21](https://github.com/feathersjs/authentication-local/issues/21)\n- Feathers params not available to user service hooks [\\#14](https://github.com/feathersjs/authentication-local/issues/14)\n- Bad error message is returned for invalid credentials [\\#10](https://github.com/feathersjs/authentication-local/issues/10)\n\n**Merged pull requests:**\n\n- Greenkeeper/chai 4.0.2 [\\#26](https://github.com/feathersjs/authentication-local/pull/26) ([daffl](https://github.com/daffl))\n- Return Invalid login message when user doesn’t exist [\\#25](https://github.com/feathersjs/authentication-local/pull/25) ([marshallswain](https://github.com/marshallswain))\n- Adding separate entity username and password fields [\\#23](https://github.com/feathersjs/authentication-local/pull/23) ([adamvr](https://github.com/adamvr))\n- use the correct default config key. Closes \\#21 [\\#22](https://github.com/feathersjs/authentication-local/pull/22) ([ekryski](https://github.com/ekryski))\n- Update feathers-socketio to the latest version 🚀 [\\#20](https://github.com/feathersjs/authentication-local/pull/20) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update semistandard to the latest version 🚀 [\\#18](https://github.com/feathersjs/authentication-local/pull/18) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update feathers-hooks to the latest version 🚀 [\\#16](https://github.com/feathersjs/authentication-local/pull/16) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update dependencies to enable Greenkeeper 🌴 [\\#13](https://github.com/feathersjs/authentication-local/pull/13) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v0.3.4](https://github.com/feathersjs/authentication-local/tree/v0.3.4) (2017-03-28)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v0.3.3...v0.3.4)\n\n**Closed issues:**\n\n- Shouldn't it be `authentication` instead of the old `auth` there? [\\#11](https://github.com/feathersjs/authentication-local/issues/11)\n\n**Merged pull requests:**\n\n- Fix default authentication config name [\\#12](https://github.com/feathersjs/authentication-local/pull/12) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.3.3](https://github.com/feathersjs/authentication-local/tree/v0.3.3) (2017-01-27)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v0.3.2...v0.3.3)\n\n**Closed issues:**\n\n- Support dot notation [\\#7](https://github.com/feathersjs/authentication-local/issues/7)\n- Automatically register the authenticate hook with 'local' [\\#4](https://github.com/feathersjs/authentication-local/issues/4)\n\n**Merged pull requests:**\n\n- Add support for dot notation, fix some whitespace [\\#8](https://github.com/feathersjs/authentication-local/pull/8) ([elfey](https://github.com/elfey))\n\n## [v0.3.2](https://github.com/feathersjs/authentication-local/tree/v0.3.2) (2016-12-14)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v0.3.1...v0.3.2)\n\n## [v0.3.1](https://github.com/feathersjs/authentication-local/tree/v0.3.1) (2016-12-14)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v0.3.0...v0.3.1)\n\n**Closed issues:**\n\n- Add docs section on expected request params. [\\#5](https://github.com/feathersjs/authentication-local/issues/5)\n\n**Merged pull requests:**\n\n- Document expected request data [\\#6](https://github.com/feathersjs/authentication-local/pull/6) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.3.0](https://github.com/feathersjs/authentication-local/tree/v0.3.0) (2016-11-23)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v0.2.0...v0.3.0)\n\n**Closed issues:**\n\n- Doesn't pull configuration from `auth.local` by default [\\#2](https://github.com/feathersjs/authentication-local/issues/2)\n- Does not pull from global auth config when strategy has a custom name [\\#1](https://github.com/feathersjs/authentication-local/issues/1)\n\n**Merged pull requests:**\n\n- Payload support [\\#3](https://github.com/feathersjs/authentication-local/pull/3) ([ekryski](https://github.com/ekryski))\n\n## [v0.2.0](https://github.com/feathersjs/authentication-local/tree/v0.2.0) (2016-11-16)\n\n[Full Changelog](https://github.com/feathersjs/authentication-local/compare/v0.1.0...v0.2.0)\n\n## [v0.1.0](https://github.com/feathersjs/authentication-local/tree/v0.1.0) (2016-11-09)\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/authentication-local/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/authentication-local/README.md",
    "content": "# @feathersjs/authentication-local\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/authentication-local.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/authentication-local)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Local username and password authentication strategy for Feathers authentication\n\n## Installation\n\n```\nnpm install @feathersjs/authentication-local --save\n```\n\n## Documentation\n\nRefer to the [Feathers local authentication API documentation](https://feathersjs.com/api/authentication/local.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/authentication-local/package.json",
    "content": "{\n  \"name\": \"@feathersjs/authentication-local\",\n  \"description\": \"Local authentication strategy for @feathers/authentication\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/authentication-local\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/authentication\": \"^5.0.42\",\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"bcryptjs\": \"^3.0.3\",\n    \"lodash\": \"^4.17.23\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/memory\": \"^5.0.42\",\n    \"@feathersjs/schema\": \"^5.0.42\",\n    \"@types/bcryptjs\": \"^2.4.6\",\n    \"@types/lodash\": \"^4.17.24\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/authentication-local/src/hooks/hash-password.ts",
    "content": "import get from 'lodash/get'\nimport set from 'lodash/set'\nimport cloneDeep from 'lodash/cloneDeep'\nimport { BadRequest } from '@feathersjs/errors'\nimport { createDebug } from '@feathersjs/commons'\nimport { HookContext, NextFunction } from '@feathersjs/feathers'\nimport { LocalStrategy } from '../strategy'\n\nconst debug = createDebug('@feathersjs/authentication-local/hooks/hash-password')\n\nexport interface HashPasswordOptions {\n  authentication?: string\n  strategy?: string\n}\n\n/**\n * @deprecated Use Feathers schema resolvers and the `passwordHash` resolver instead\n * @param field\n * @param options\n * @returns\n * @see https://dove.feathersjs.com/api/authentication/local.html#passwordhash\n */\nexport default function hashPassword(field: string, options: HashPasswordOptions = {}) {\n  if (!field) {\n    throw new Error('The hashPassword hook requires a field name option')\n  }\n\n  return async (context: HookContext, next?: NextFunction) => {\n    const { app, data, params } = context\n\n    if (data !== undefined) {\n      const authService = app.defaultAuthentication(options.authentication)\n      const { strategy = 'local' } = options\n\n      if (!authService || typeof authService.getStrategies !== 'function') {\n        throw new BadRequest('Could not find an authentication service to hash password')\n      }\n\n      const [localStrategy] = authService.getStrategies(strategy) as LocalStrategy[]\n\n      if (!localStrategy || typeof localStrategy.hashPassword !== 'function') {\n        throw new BadRequest(`Could not find '${strategy}' strategy to hash password`)\n      }\n\n      const addHashedPassword = async (data: any) => {\n        const password = get(data, field)\n\n        if (password === undefined) {\n          debug(`hook.data.${field} is undefined, not hashing password`)\n          return data\n        }\n\n        const hashedPassword: string = await localStrategy.hashPassword(password, params)\n\n        return set(cloneDeep(data), field, hashedPassword)\n      }\n\n      context.data = Array.isArray(data)\n        ? await Promise.all(data.map(addHashedPassword))\n        : await addHashedPassword(data)\n    }\n\n    if (typeof next === 'function') {\n      return next()\n    }\n  }\n}\n"
  },
  {
    "path": "packages/authentication-local/src/hooks/protect.ts",
    "content": "import omit from 'lodash/omit'\nimport { HookContext, NextFunction } from '@feathersjs/feathers'\n\n/**\n * @deprecated For reliable safe data representations use Feathers schema dispatch resolvers.\n * @see https://dove.feathersjs.comapi/authentication/local.html#protecting-fields\n */\nexport default (...fields: string[]) => {\n  const o = (current: any) => {\n    if (typeof current === 'object' && !Array.isArray(current)) {\n      const data = typeof current.toJSON === 'function' ? current.toJSON() : current\n\n      return omit(data, fields)\n    }\n\n    return current\n  }\n\n  return async (context: HookContext, next?: NextFunction) => {\n    if (typeof next === 'function') {\n      await next()\n    }\n\n    const result = context.dispatch || context.result\n\n    if (result) {\n      if (Array.isArray(result)) {\n        context.dispatch = result.map(o)\n      } else if (result.data && context.method === 'find') {\n        context.dispatch = Object.assign({}, result, {\n          data: result.data.map(o)\n        })\n      } else {\n        context.dispatch = o(result)\n      }\n\n      if (context.params && context.params.provider) {\n        context.result = context.dispatch\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "packages/authentication-local/src/index.ts",
    "content": "import { HookContext } from '@feathersjs/feathers'\nimport hashPassword from './hooks/hash-password'\nimport protect from './hooks/protect'\nimport { LocalStrategy } from './strategy'\n\nexport const hooks = { hashPassword, protect }\nexport { LocalStrategy }\n\n/**\n * Returns as property resolver that hashes a given plain text password using a Local\n * authentication strategy.\n *\n * @param options The authentication `service` and `strategy` name\n * @returns\n */\nexport const passwordHash =\n  (options: { service?: string; strategy: string }) =>\n  async <H extends HookContext<any, any>>(value: string | undefined, _data: any, context: H) => {\n    if (value === undefined) {\n      return value\n    }\n\n    const { app, params } = context\n    const authService = app.defaultAuthentication(options.service)\n    const localStrategy = authService.getStrategy(options.strategy) as LocalStrategy\n\n    return localStrategy.hashPassword(value, params)\n  }\n"
  },
  {
    "path": "packages/authentication-local/src/strategy.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unused-vars */\nimport bcrypt from 'bcryptjs'\nimport get from 'lodash/get'\nimport { NotAuthenticated } from '@feathersjs/errors'\nimport { Query, Params } from '@feathersjs/feathers'\nimport { AuthenticationRequest, AuthenticationBaseStrategy } from '@feathersjs/authentication'\nimport { createDebug } from '@feathersjs/commons'\n\nconst debug = createDebug('@feathersjs/authentication-local/strategy')\n\nexport class LocalStrategy extends AuthenticationBaseStrategy {\n  verifyConfiguration() {\n    const config = this.configuration\n\n    ;['usernameField', 'passwordField'].forEach((prop) => {\n      if (typeof config[prop] !== 'string') {\n        throw new Error(`'${this.name}' authentication strategy requires a '${prop}' setting`)\n      }\n    })\n  }\n\n  get configuration() {\n    const authConfig = this.authentication.configuration\n    const config = super.configuration || {}\n\n    return {\n      hashSize: 10,\n      service: authConfig.service,\n      entity: authConfig.entity,\n      entityId: authConfig.entityId,\n      errorMessage: 'Invalid login',\n      entityPasswordField: config.passwordField,\n      entityUsernameField: config.usernameField,\n      ...config\n    }\n  }\n\n  async getEntityQuery(query: Query, _params: Params) {\n    return {\n      $limit: 1,\n      ...query\n    }\n  }\n\n  async findEntity(username: string, params: Params) {\n    const { entityUsernameField, errorMessage } = this.configuration\n    if (!username) {\n      // don't query for users without any condition set.\n      throw new NotAuthenticated(errorMessage)\n    }\n\n    const query = await this.getEntityQuery(\n      {\n        [entityUsernameField]: username\n      },\n      params\n    )\n\n    const findParams = Object.assign({}, params, { query })\n    const entityService = this.entityService\n\n    debug('Finding entity with query', params.query)\n\n    const result = await entityService.find(findParams)\n    const list = Array.isArray(result) ? result : result.data\n\n    if (!Array.isArray(list) || list.length === 0) {\n      debug('No entity found')\n\n      throw new NotAuthenticated(errorMessage)\n    }\n\n    const [entity] = list\n\n    return entity\n  }\n\n  async getEntity(result: any, params: Params) {\n    const entityService = this.entityService\n    const { entityId = (entityService as any).id, entity } = this.configuration\n\n    if (!entityId || result[entityId] === undefined) {\n      throw new NotAuthenticated('Could not get local entity')\n    }\n\n    if (!params.provider) {\n      return result\n    }\n\n    return entityService.get(result[entityId], {\n      ...params,\n      [entity]: result\n    })\n  }\n\n  async comparePassword(entity: any, password: string) {\n    const { entityPasswordField, errorMessage } = this.configuration\n    // find password in entity, this allows for dot notation\n    const hash = get(entity, entityPasswordField)\n\n    if (!hash) {\n      debug(`Record is missing the '${entityPasswordField}' password field`)\n\n      throw new NotAuthenticated(errorMessage)\n    }\n\n    debug('Verifying password')\n\n    const result = await bcrypt.compare(password, hash)\n\n    if (result) {\n      return entity\n    }\n\n    throw new NotAuthenticated(errorMessage)\n  }\n\n  async hashPassword(password: string, _params: Params) {\n    return bcrypt.hash(password, this.configuration.hashSize)\n  }\n\n  async authenticate(data: AuthenticationRequest, params: Params) {\n    const { passwordField, usernameField, entity, errorMessage } = this.configuration\n    const username = get(data, usernameField)\n    const password = get(data, passwordField)\n\n    if (!password) {\n      // exit early if there is no password\n      throw new NotAuthenticated(errorMessage)\n    }\n\n    const { provider, ...paramsWithoutProvider } = params\n\n    const result = await this.findEntity(username, paramsWithoutProvider)\n    await this.comparePassword(result, password)\n\n    return {\n      authentication: { strategy: this.name },\n      [entity]: await this.getEntity(result, params)\n    }\n  }\n}\n"
  },
  {
    "path": "packages/authentication-local/test/fixture.ts",
    "content": "import { feathers } from '@feathersjs/feathers'\nimport { memory, MemoryService } from '@feathersjs/memory'\nimport { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'\n\nimport { LocalStrategy, hooks } from '../src'\nconst { hashPassword, protect } = hooks\n\nexport type ServiceTypes = {\n  authentication: AuthenticationService\n  users: MemoryService\n}\n\nexport function createApplication(\n  app = feathers<ServiceTypes>(),\n  authOptionOverrides: Record<string, unknown> = {}\n) {\n  const authentication = new AuthenticationService(app)\n\n  const authConfig = {\n    entity: 'user',\n    service: 'users',\n    secret: 'supersecret',\n    authStrategies: ['local', 'jwt'],\n    parseStrategies: ['jwt'],\n    local: {\n      usernameField: 'email',\n      passwordField: 'password'\n    },\n    ...authOptionOverrides\n  }\n  app.set('authentication', authConfig)\n\n  authentication.register('jwt', new JWTStrategy())\n  authentication.register('local', new LocalStrategy())\n\n  app.use('authentication', authentication)\n  app.use(\n    'users',\n    memory({\n      multi: ['create'],\n      paginate: {\n        default: 10,\n        max: 20\n      }\n    })\n  )\n\n  app.service('users').hooks([protect(authConfig.local.passwordField)])\n  app.service('users').hooks({\n    create: [hashPassword(authConfig.local.passwordField)],\n    get: [\n      async (context, next) => {\n        await next()\n\n        if (context.params.provider) {\n          context.result.fromGet = true\n        }\n      }\n    ]\n  })\n\n  return app\n}\n"
  },
  {
    "path": "packages/authentication-local/test/hooks/hash-password.test.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport assert from 'assert'\nimport { Application } from '@feathersjs/feathers'\n\nimport { hooks } from '../../src'\nimport { createApplication, ServiceTypes } from '../fixture'\n\nconst { hashPassword } = hooks\n\ndescribe('@feathersjs/authentication-local/hooks/hash-password', () => {\n  let app: Application<ServiceTypes>\n\n  beforeEach(() => {\n    app = createApplication()\n  })\n\n  it('throws error when no field provided', () => {\n    try {\n      // @ts-ignore\n      hashPassword()\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.message, 'The hashPassword hook requires a field name option')\n    }\n  })\n\n  it('errors when authentication service does not exist', async () => {\n    delete app.services.authentication\n\n    try {\n      await app.service('users').create({\n        email: 'dave@hashpassword.com',\n        password: 'supersecret'\n      })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.message, 'Could not find an authentication service to hash password')\n    }\n  })\n\n  it('errors when authentication strategy does not exist', async () => {\n    delete app.services.authentication.strategies.local\n\n    try {\n      await app.service('users').create({\n        email: 'dave@hashpassword.com',\n        password: 'supersecret'\n      })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.message, \"Could not find 'local' strategy to hash password\")\n    }\n  })\n\n  it('hashes password on field', async () => {\n    const password = 'supersecret'\n\n    const user = await app.service('users').create({\n      email: 'dave@hashpassword.com',\n      password\n    })\n\n    assert.notStrictEqual(user.password, password)\n  })\n\n  it('hashes password on array data', async () => {\n    const password = 'supersecret'\n\n    const users = await app.service('users').create([\n      {\n        email: 'dave@hashpassword.com',\n        password\n      },\n      {\n        email: 'dave2@hashpassword.com',\n        password: 'secret2'\n      }\n    ])\n\n    assert.notStrictEqual(users[0].password, password)\n    assert.notStrictEqual(users[1].password, 'secret2')\n  })\n\n  it('does nothing when field is not present', async () => {\n    const user = await app.service('users').create({\n      email: 'dave@hashpassword.com'\n    })\n\n    assert.strictEqual(user.password, undefined)\n  })\n})\n"
  },
  {
    "path": "packages/authentication-local/test/hooks/protect.test.ts",
    "content": "import assert from 'assert'\nimport { HookContext } from '@feathersjs/feathers'\nimport { hooks } from '../../src'\n\nconst { protect } = hooks\n\nfunction testOmit(title: string, property: string) {\n  describe(title, () => {\n    const fn = protect('password')\n\n    it('omits from object', async () => {\n      const data = {\n        email: 'test@user.com',\n        password: 'supersecret'\n      }\n      const context = {\n        [property]: data\n      } as unknown as HookContext\n\n      await fn(context)\n\n      assert.deepStrictEqual(context, {\n        [property]: data,\n        dispatch: { email: 'test@user.com' }\n      })\n    })\n\n    it('omits from nested object', async () => {\n      const hook = protect('user.password')\n      const data = {\n        user: {\n          email: 'test@user.com',\n          password: 'supersecret'\n        }\n      }\n      const context = {\n        [property]: data\n      } as unknown as HookContext\n\n      await hook(context)\n\n      assert.deepStrictEqual(context, {\n        [property]: data,\n        dispatch: { user: { email: 'test@user.com' } }\n      })\n    })\n\n    it('handles `data` property only for find', async () => {\n      const data = {\n        email: 'test@user.com',\n        password: 'supersecret',\n        data: 'yes'\n      }\n      const context = {\n        [property]: data\n      } as unknown as HookContext\n\n      await fn(context)\n\n      assert.deepStrictEqual(context, {\n        [property]: data,\n        dispatch: { email: 'test@user.com', data: 'yes' }\n      })\n    })\n\n    it('uses .toJSON (#48)', async () => {\n      class MyUser {\n        toJSON() {\n          return {\n            email: 'test@user.com',\n            password: 'supersecret'\n          }\n        }\n      }\n\n      const data = new MyUser()\n      const context = {\n        [property]: data\n      } as unknown as HookContext\n\n      await fn(context)\n\n      assert.deepStrictEqual(context, {\n        [property]: data,\n        dispatch: { email: 'test@user.com' }\n      })\n    })\n\n    it('omits from array but only objects (#2053)', async () => {\n      const data = [\n        {\n          email: 'test1@user.com',\n          password: 'supersecret'\n        },\n        {\n          email: 'test2@user.com',\n          password: 'othersecret'\n        },\n        ['one', 'two', 'three'],\n        'test'\n      ]\n      const context = {\n        [property]: data\n      } as unknown as HookContext\n\n      await fn(context)\n\n      assert.deepStrictEqual(context, {\n        [property]: data,\n        dispatch: [{ email: 'test1@user.com' }, { email: 'test2@user.com' }, ['one', 'two', 'three'], 'test']\n      })\n    })\n\n    it('omits from pagination object', async () => {\n      const data = {\n        total: 2,\n        data: [\n          {\n            email: 'test1@user.com',\n            password: 'supersecret'\n          },\n          {\n            email: 'test2@user.com',\n            password: 'othersecret'\n          }\n        ]\n      }\n      const context = {\n        method: 'find',\n        [property]: data\n      } as unknown as HookContext\n\n      await fn(context)\n\n      assert.deepStrictEqual(context, {\n        method: 'find',\n        [property]: data,\n        dispatch: {\n          total: 2,\n          data: [{ email: 'test1@user.com' }, { email: 'test2@user.com' }]\n        }\n      })\n    })\n\n    it('updates result if params.provider is set', async () => {\n      const data = [\n        {\n          email: 'test1@user.com',\n          password: 'supersecret'\n        },\n        {\n          email: 'test2@user.com',\n          password: 'othersecret'\n        }\n      ]\n      const params = { provider: 'test' }\n      const context = {\n        [property]: data,\n        params\n      } as unknown as HookContext\n\n      await fn(context)\n\n      assert.deepStrictEqual(context, {\n        [property]: data,\n        params,\n        result: [{ email: 'test1@user.com' }, { email: 'test2@user.com' }],\n        dispatch: [{ email: 'test1@user.com' }, { email: 'test2@user.com' }]\n      })\n    })\n  })\n}\n\ndescribe('@feathersjs/authentication-local/hooks/protect', () => {\n  it('does nothing when called with no result', async () => {\n    const fn = protect()\n\n    assert.deepStrictEqual(await fn({} as any), undefined)\n  })\n\n  testOmit('with hook.result', 'result')\n  testOmit('with hook.dispatch already set', 'dispatch')\n})\n"
  },
  {
    "path": "packages/authentication-local/test/strategy.test.ts",
    "content": "import assert from 'assert'\nimport omit from 'lodash/omit'\nimport { Application, HookContext } from '@feathersjs/feathers'\nimport { resolve } from '@feathersjs/schema'\n\nimport { LocalStrategy, passwordHash } from '../src'\nimport { createApplication, ServiceTypes } from './fixture'\n\ndescribe('@feathersjs/authentication-local/strategy', () => {\n  const password = 'localsecret'\n  const email = 'localtester@feathersjs.com'\n\n  let app: Application<ServiceTypes>\n  let user: any\n\n  beforeEach(async () => {\n    app = createApplication()\n    user = await app.service('users').create({ email, password })\n  })\n\n  it('throw error when configuration is not set', () => {\n    const auth = app.service('authentication')\n\n    try {\n      auth.register('something', new LocalStrategy())\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(\n        error.message,\n        \"'something' authentication strategy requires a 'usernameField' setting\"\n      )\n    }\n  })\n\n  it('fails when entity not found', async () => {\n    const authService = app.service('authentication')\n\n    try {\n      await authService.create({\n        strategy: 'local',\n        email: 'not in database',\n        password\n      })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.name, 'NotAuthenticated')\n      assert.strictEqual(error.message, 'Invalid login')\n    }\n  })\n\n  it('getEntity', async () => {\n    const [strategy] = app.service('authentication').getStrategies('local') as [LocalStrategy]\n    let entity = await strategy.getEntity(user, {})\n\n    assert.deepStrictEqual(entity, user)\n\n    entity = await strategy.getEntity(user, {\n      provider: 'testing'\n    })\n\n    assert.deepStrictEqual(entity, {\n      ...omit(user, 'password'),\n      fromGet: true\n    })\n\n    try {\n      await strategy.getEntity({}, {})\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.message, 'Could not get local entity')\n    }\n  })\n\n  it('strategy fails when strategy is different', async () => {\n    const [local] = app.service('authentication').getStrategies('local')\n\n    await assert.rejects(\n      () =>\n        local.authenticate(\n          {\n            strategy: 'not-me',\n            password: 'dummy',\n            email\n          },\n          {}\n        ),\n      {\n        name: 'NotAuthenticated',\n        message: 'Invalid login'\n      }\n    )\n  })\n\n  it('fails when password is wrong', async () => {\n    const authService = app.service('authentication')\n    try {\n      await authService.create({\n        strategy: 'local',\n        email,\n        password: 'dummy'\n      })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.name, 'NotAuthenticated')\n      assert.strictEqual(error.message, 'Invalid login')\n    }\n  })\n\n  it('fails when password is not provided', async () => {\n    const authService = app.service('authentication')\n    try {\n      await authService.create({\n        strategy: 'local',\n        email\n      })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.name, 'NotAuthenticated')\n      assert.strictEqual(error.message, 'Invalid login')\n    }\n  })\n\n  it('fails when password field is not available', async () => {\n    const userEmail = 'someuser@localtest.com'\n    const authService = app.service('authentication')\n\n    try {\n      await app.service('users').create({\n        email: userEmail\n      })\n      await authService.create({\n        strategy: 'local',\n        password: 'dummy',\n        email: userEmail\n      })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.name, 'NotAuthenticated')\n      assert.strictEqual(error.message, 'Invalid login')\n    }\n  })\n\n  it('authenticates an existing user', async () => {\n    const authService = app.service('authentication')\n    const authResult = await authService.create({\n      strategy: 'local',\n      email,\n      password\n    })\n    const { accessToken } = authResult\n\n    assert.ok(accessToken)\n    assert.strictEqual(authResult.user.email, email)\n\n    const decoded = await authService.verifyAccessToken(accessToken)\n\n    assert.strictEqual(decoded.sub, `${user.id}`)\n  })\n\n  it('returns safe result when params.provider is set, works without pagination', async () => {\n    const authService = app.service('authentication')\n    const authResult = await authService.create(\n      {\n        strategy: 'local',\n        email,\n        password\n      },\n      {\n        provider: 'rest',\n        paginate: false\n      }\n    )\n    const { accessToken } = authResult\n\n    assert.ok(accessToken)\n    assert.strictEqual(authResult.user.email, email)\n    assert.strictEqual(authResult.user.password, undefined)\n    assert.ok(authResult.user.fromGet)\n\n    const decoded = await authService.verifyAccessToken(accessToken)\n\n    assert.strictEqual(decoded.sub, `${user.id}`)\n  })\n\n  it('passwordHash property resolver', async () => {\n    const userResolver = resolve<{ password: string }, HookContext>({\n      properties: {\n        password: passwordHash({\n          strategy: 'local'\n        })\n      }\n    })\n\n    const resolvedData = await userResolver.resolve({ password: 'supersecret' }, { app } as HookContext)\n\n    assert.notStrictEqual(resolvedData.password, 'supersecret')\n  })\n  it('should allow for nested values in the usernameField', async () => {\n    const appWithNestedFieldOverride = createApplication(undefined, {\n      local: {\n        usernameField: 'auth.email',\n        passwordField: 'auth.password'\n      }\n    })\n    const nestedUser = await appWithNestedFieldOverride.service('users').create({ auth: { email, password } })\n    const authService = appWithNestedFieldOverride.service('authentication')\n    const authResult = await authService.create({\n      strategy: 'local',\n      auth: {\n        email,\n        password\n      }\n    })\n    const { accessToken } = authResult\n\n    assert.ok(accessToken)\n    assert.strictEqual(authResult.user.auth.email, email)\n\n    const decoded = await authService.verifyAccessToken(accessToken)\n\n    assert.strictEqual(decoded.sub, `${nestedUser.id}`)\n    //\n  })\n})\n"
  },
  {
    "path": "packages/authentication-local/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/authentication-oauth/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- **authentication-oauth:** Fix OAuth Callback Account Takeover ([#3663](https://github.com/feathersjs/feathers/issues/3663)) ([d6b0b5c](https://github.com/feathersjs/feathers/commit/d6b0b5cfbaf6f86a63662027c25616c28e54ede1))\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n### Bug Fixes\n\n- **oauth:** Patch open redirect and origin validation ([#3653](https://github.com/feathersjs/feathers/issues/3653)) ([ee19a0a](https://github.com/feathersjs/feathers/commit/ee19a0ae9bc2ebf23b1fe598a1f7361981b65401))\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n### Bug Fixes\n\n- **authentication-oauth:** Allow POST oauth callbacks ([#3497](https://github.com/feathersjs/feathers/issues/3497)) ([ffcc90b](https://github.com/feathersjs/feathers/commit/ffcc90bb95329cbb4b8f310e37024d417c216d8c))\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n### Bug Fixes\n\n- **oauth:** Export OAuthService type ([#3479](https://github.com/feathersjs/feathers/issues/3479)) ([e7185cd](https://github.com/feathersjs/feathers/commit/e7185cde63990a0d24a7180c63b61dbc8ef6cd5b))\n- Reduce usage of lodash ([#3455](https://github.com/feathersjs/feathers/issues/3455)) ([8ce807a](https://github.com/feathersjs/feathers/commit/8ce807a5ca53ff5b8d5107a0656c6329404e6e6c))\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n### Bug Fixes\n\n- **authentication-oauth:** Move Grant error handling to the correct spot ([#3297](https://github.com/feathersjs/feathers/issues/3297)) ([e9c0828](https://github.com/feathersjs/feathers/commit/e9c0828937453c3f0a1bd16010089b825185eab6))\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n### Bug Fixes\n\n- **authentication-oauth:** Properly handle all oAuth errors ([#3284](https://github.com/feathersjs/feathers/issues/3284)) ([148a9a3](https://github.com/feathersjs/feathers/commit/148a9a319b8e29138fda82d6c03bb489a7b4a6e1))\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n### Bug Fixes\n\n- **authentication-oauth:** Update OAuth redirect to handle user requested redirect paths ([#3186](https://github.com/feathersjs/feathers/issues/3186)) ([3742028](https://github.com/feathersjs/feathers/commit/37420283c17bb8129c6ffdde841ce2034109cc6b))\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- **authentication-oauth:** Use original headers in oauth flow ([#3025](https://github.com/feathersjs/feathers/issues/3025)) ([fb3d8cc](https://github.com/feathersjs/feathers/commit/fb3d8cca123d68a77b096bc92e49baa55424afe0))\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **core:** Improve service option usage and method option typings ([#2902](https://github.com/feathersjs/feathers/issues/2902)) ([164d75c](https://github.com/feathersjs/feathers/commit/164d75c0f11139a316baa91f1762de8f8eb7da2d))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Bug Fixes\n\n- **authentication-oauth:** Fix regression with prefix handling in OAuth ([#2773](https://github.com/feathersjs/feathers/issues/2773)) ([b1844b1](https://github.com/feathersjs/feathers/commit/b1844b1f27feeb7e66920ec9e318872857711834))\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n### Bug Fixes\n\n- **authentication-oauth:** Fix oAuth origin and error handling ([#2752](https://github.com/feathersjs/feathers/issues/2752)) ([f7e1c33](https://github.com/feathersjs/feathers/commit/f7e1c33de1b7af0672a302d2ba6e15d997f0aa83))\n\n### Features\n\n- Add CORS support to oAuth, Express, Koa and generated application ([#2744](https://github.com/feathersjs/feathers/issues/2744)) ([fd218f2](https://github.com/feathersjs/feathers/commit/fd218f289f8ca4c101e9938e8683e2efef6e8131))\n- **authentication-oauth:** Koa and transport independent oAuth authentication ([#2737](https://github.com/feathersjs/feathers/issues/2737)) ([9231525](https://github.com/feathersjs/feathers/commit/9231525a24bb790ba9c5d940f2867a9c727691c9))\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Bug Fixes\n\n- **authentication-oauth:** Fix bug and properly set Grant defaults ([#2659](https://github.com/feathersjs/feathers/issues/2659)) ([cb93bb9](https://github.com/feathersjs/feathers/commit/cb93bb911fd92282424da2db805cd685b7e4a45b))\n\n### Features\n\n- **cli:** Add typed client to a generated app ([#2669](https://github.com/feathersjs/feathers/issues/2669)) ([5b801b5](https://github.com/feathersjs/feathers/commit/5b801b5017ddc3eaa95622b539f51d605916bc86))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n### Bug Fixes\n\n- **authentication-oauth:** Fix regression using incorrect callback and redirect_uri ([#2631](https://github.com/feathersjs/feathers/issues/2631)) ([43d8a08](https://github.com/feathersjs/feathers/commit/43d8a082d7e1807f8a431c44a1dbd9b04c3af0d2))\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **authentication-oauth:** Don't send origins in Grant's config, as it will be considered another provider ([#2617](https://github.com/feathersjs/feathers/issues/2617)) ([ae3dddd](https://github.com/feathersjs/feathers/commit/ae3dddd8a654924465512d56b4651413912c6932))\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Bug Fixes\n\n- **authentication-oauth:** Fix issue with overriding the default Grant configuration ([#2615](https://github.com/feathersjs/feathers/issues/2615)) ([b345857](https://github.com/feathersjs/feathers/commit/b3458578532f9750de2940aeb8afdc75cb0b46f2))\n- **authentication-oauth:** Make oAuth authentication work with cookie-session ([#2614](https://github.com/feathersjs/feathers/issues/2614)) ([9f10bfc](https://github.com/feathersjs/feathers/commit/9f10bfc75083d5bcabea77cfb385aa3965cdf6d6))\n\n### Features\n\n- **typescript:** Improve params and query typeability ([#2600](https://github.com/feathersjs/feathers/issues/2600)) ([df28b76](https://github.com/feathersjs/feathers/commit/df28b7619161f1df5e700326f52cca1a92dc5d28))\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n### Bug Fixes\n\n- **authentication-oauth:** OAuth redirect lost sometimes due to session store race ([#2514](https://github.com/feathersjs/feathers/issues/2514)) ([#2515](https://github.com/feathersjs/feathers/issues/2515)) ([6109c44](https://github.com/feathersjs/feathers/commit/6109c44428c6b8f6bb4e089be760ea1a4ef3d01e))\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Features\n\n- **authentication-oauth:** Allow dynamic oAuth redirect ([#2469](https://github.com/feathersjs/feathers/issues/2469)) ([b7143d4](https://github.com/feathersjs/feathers/commit/b7143d4c0fbe961e714f79512be04449b9bbd7d9))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- **authentication-oauth:** Omit query from internal calls ([#2398](https://github.com/feathersjs/feathers/issues/2398)) ([04c7c83](https://github.com/feathersjs/feathers/commit/04c7c83eeaa6a7466c84b958071b468ed42f0b0f))\n- **koa:** Use extended query parser for compatibility ([#2397](https://github.com/feathersjs/feathers/issues/2397)) ([b2944ba](https://github.com/feathersjs/feathers/commit/b2944bac3ec6d5ecc80dc518cd4e58093692db74))\n\n### Features\n\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n### Features\n\n- **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n### Features\n\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n### Bug Fixes\n\n- **authentication-oauth:** Always end session after oAuth flows are finished ([#2087](https://github.com/feathersjs/feathers/issues/2087)) ([d219d0d](https://github.com/feathersjs/feathers/commit/d219d0d89c5e45aa289dd67cb0c8bdc05044c846))\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n### Bug Fixes\n\n- **typescript:** Revert add overload types for `find` service methods ([#1972](https://github.com/feathersjs/feathers/issues/1972))\" ([#2025](https://github.com/feathersjs/feathers/issues/2025)) ([a9501ac](https://github.com/feathersjs/feathers/commit/a9501acb4d3ef58dfb87d62c57a9bf76569da281))\n\n## [4.5.6](https://github.com/feathersjs/feathers/compare/v4.5.5...v4.5.6) (2020-07-12)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n### Bug Fixes\n\n- **authentication-oauth:** Updated typings for projects with strictNullChecks ([#1941](https://github.com/feathersjs/feathers/issues/1941)) ([be91206](https://github.com/feathersjs/feathers/commit/be91206e3dba1e65a81412b7aa636bece3ab4aa2))\n- **typescript:** add overload types for `find` service methods ([#1972](https://github.com/feathersjs/feathers/issues/1972)) ([ef55af0](https://github.com/feathersjs/feathers/commit/ef55af088d05d9d36aba9d9f8d6c2c908a4f20dd))\n\n## [4.5.4](https://github.com/feathersjs/feathers/compare/v4.5.3...v4.5.4) (2020-04-29)\n\n### Bug Fixes\n\n- **authentication-oauth:** Add getEntity method to oAuth authentication and remove provider field for other calls ([#1935](https://github.com/feathersjs/feathers/issues/1935)) ([d925c1b](https://github.com/feathersjs/feathers/commit/d925c1bd193b5c19cb23a246f04fc46d0429fc75))\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n### Bug Fixes\n\n- **authentication-oauth:** Allow req.feathers to be used in oAuth authentication requests ([#1886](https://github.com/feathersjs/feathers/issues/1886)) ([854c9ca](https://github.com/feathersjs/feathers/commit/854c9cac9a9a5f8f89054a90feb24ab5c4766f5f))\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n### Bug Fixes\n\n- **package:** update grant-profile to version 0.0.11 ([#1841](https://github.com/feathersjs/feathers/issues/1841)) ([5dcd2aa](https://github.com/feathersjs/feathers/commit/5dcd2aa3483059cc7a2546b145dd72b4705fe2fe))\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n### Features\n\n- **authentication-oauth:** Set oAuth redirect URL dynamically and pass query the service ([#1737](https://github.com/feathersjs/feathers/issues/1737)) ([0b05f0b](https://github.com/feathersjs/feathers/commit/0b05f0b58a257820fa61d695a36f36455209f6a1))\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n### Features\n\n- **authentication-oauth:** Set oAuth redirect URL dynamically ([#1608](https://github.com/feathersjs/feathers/issues/1608)) ([1293e08](https://github.com/feathersjs/feathers/commit/1293e088abbb3d23f4a44680836645a8049ceaae))\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n### Bug Fixes\n\n- **authentication-oauth:** Allow hash based redirects ([#1676](https://github.com/feathersjs/feathers/issues/1676)) ([ffe7cf3](https://github.com/feathersjs/feathers/commit/ffe7cf3fbb4e62d7689065cf7b61f25f602ce8cf))\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n### Bug Fixes\n\n- Only initialize default Express session if oAuth is actually used ([#1648](https://github.com/feathersjs/feathers/issues/1648)) ([9b9b43f](https://github.com/feathersjs/feathers/commit/9b9b43ff09af1080e4aaa537064bac37b881c9a2))\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [4.3.5](https://github.com/feathersjs/feathers/compare/v4.3.4...v4.3.5) (2019-10-07)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n### Bug Fixes\n\n- Small improvements in dependencies and code sturcture ([#1562](https://github.com/feathersjs/feathers/issues/1562)) ([42c13e2](https://github.com/feathersjs/feathers/commit/42c13e2))\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n### Bug Fixes\n\n- Omit standard protocol ports from the default hostname ([#1543](https://github.com/feathersjs/feathers/issues/1543)) ([ef16d29](https://github.com/feathersjs/feathers/commit/ef16d29))\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))\n- Use WeakMap to connect socket to connection ([#1509](https://github.com/feathersjs/feathers/issues/1509)) ([64807e3](https://github.com/feathersjs/feathers/commit/64807e3))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n### Bug Fixes\n\n- Add method to reliably get default authentication service ([#1470](https://github.com/feathersjs/feathers/issues/1470)) ([e542cb3](https://github.com/feathersjs/feathers/commit/e542cb3))\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n**Note:** Version bump only for package @feathersjs/authentication-oauth\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Make oAuth paths more consistent and improve authentication client ([#1377](https://github.com/feathersjs/feathers/issues/1377)) ([adb2543](https://github.com/feathersjs/feathers/commit/adb2543))\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n### Bug Fixes\n\n- Correctly read the oauth strategy config ([#1349](https://github.com/feathersjs/feathers/issues/1349)) ([9abf314](https://github.com/feathersjs/feathers/commit/9abf314))\n\n### Features\n\n- Add global disconnect event ([#1355](https://github.com/feathersjs/feathers/issues/1355)) ([85afcca](https://github.com/feathersjs/feathers/commit/85afcca))\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n### Bug Fixes\n\n- Always require strategy parameter in authentication ([#1327](https://github.com/feathersjs/feathers/issues/1327)) ([d4a8021](https://github.com/feathersjs/feathers/commit/d4a8021))\n- Improve authentication parameter handling ([#1333](https://github.com/feathersjs/feathers/issues/1333)) ([6e77204](https://github.com/feathersjs/feathers/commit/6e77204))\n- Improve oAuth option handling and usability ([#1335](https://github.com/feathersjs/feathers/issues/1335)) ([adb137d](https://github.com/feathersjs/feathers/commit/adb137d))\n- Merge httpStrategies and authStrategies option ([#1308](https://github.com/feathersjs/feathers/issues/1308)) ([afa4d55](https://github.com/feathersjs/feathers/commit/afa4d55))\n- Rename jwtStrategies option to authStrategies ([#1305](https://github.com/feathersjs/feathers/issues/1305)) ([4aee151](https://github.com/feathersjs/feathers/commit/4aee151))\n\n### Features\n\n- Change and *JWT methods to *accessToken ([#1304](https://github.com/feathersjs/feathers/issues/1304)) ([5ac826b](https://github.com/feathersjs/feathers/commit/5ac826b))\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Features\n\n- @feathersjs/authentication-oauth ([#1299](https://github.com/feathersjs/feathers/issues/1299)) ([656bae7](https://github.com/feathersjs/feathers/commit/656bae7))\n"
  },
  {
    "path": "packages/authentication-oauth/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/authentication-oauth/README.md",
    "content": "# @feathersjs/authentication-oauth\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/authentication-oauth.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/authentication-oauth)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> OAuth 1 and 2 authentication for Feathers. Powered by Grant.\n\n## Installation\n\n```\nnpm install @feathersjs/authentication-oauth --save\n```\n\n## Documentation\n\nRefer to the [Feathers oAuth authentication API documentation](https://feathersjs.com/api/authentication/oauth.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/authentication-oauth/package.json",
    "content": "{\n  \"name\": \"@feathersjs/authentication-oauth\",\n  \"description\": \"oAuth 1 and 2 authentication for Feathers. Powered by Grant.\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/authentication-oauth\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"start\": \"ts-node test/app\",\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/authentication\": \"^5.0.42\",\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/express\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@feathersjs/koa\": \"^5.0.42\",\n    \"@feathersjs/schema\": \"^5.0.42\",\n    \"cookie-session\": \"^2.1.1\",\n    \"grant\": \"^5.4.24\",\n    \"koa-session\": \"^7.0.2\",\n    \"qs\": \"^6.15.0\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/memory\": \"^5.0.42\",\n    \"@types/cookie-session\": \"^2.0.49\",\n    \"@types/express\": \"^4.17.21\",\n    \"@types/koa-session\": \"^6.4.5\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"@types/tough-cookie\": \"^4.0.5\",\n    \"axios\": \"^1.13.6\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"tough-cookie\": \"^6.0.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/authentication-oauth/src/index.ts",
    "content": "import { Application } from '@feathersjs/feathers'\nimport { createDebug } from '@feathersjs/commons'\nimport { resolveDispatch } from '@feathersjs/schema'\n\nimport { OAuthStrategy, OAuthProfile } from './strategy'\nimport { redirectHook, OAuthService, OAuthCallbackService } from './service'\nimport { getGrantConfig, authenticationServiceOptions, OauthSetupSettings } from './utils'\n\nconst debug = createDebug('@feathersjs/authentication-oauth')\n\nexport { OauthSetupSettings, OAuthStrategy, OAuthProfile, OAuthService }\n\nexport const oauth =\n  (settings: Partial<OauthSetupSettings> = {}) =>\n  (app: Application) => {\n    const authService = app.defaultAuthentication ? app.defaultAuthentication(settings.authService) : null\n\n    if (!authService) {\n      throw new Error(\n        'An authentication service must exist before registering @feathersjs/authentication-oauth'\n      )\n    }\n\n    if (!authService.configuration.oauth) {\n      debug('No oauth configuration found in authentication configuration. Skipping oAuth setup.')\n      return\n    }\n\n    const oauthOptions = {\n      linkStrategy: 'jwt',\n      ...settings\n    }\n\n    const grantConfig = getGrantConfig(authService)\n    const serviceOptions = authenticationServiceOptions(authService, oauthOptions)\n    const servicePath = `${grantConfig.defaults.prefix || 'oauth'}/:provider`\n    const callbackServicePath = `${servicePath}/callback`\n    const oauthService = new OAuthService(authService, oauthOptions)\n\n    app.use(servicePath, oauthService, serviceOptions)\n    app.use(callbackServicePath, new OAuthCallbackService(oauthService), serviceOptions)\n    app.service(servicePath).hooks({\n      around: { all: [resolveDispatch(), redirectHook()] }\n    })\n    app.service(callbackServicePath).hooks({\n      around: { all: [resolveDispatch(), redirectHook()] }\n    })\n\n    if (typeof app.service(servicePath).publish === 'function') {\n      app.service(servicePath).publish(() => null)\n    }\n\n    if (typeof app.service(callbackServicePath).publish === 'function') {\n      app.service(callbackServicePath).publish(() => null)\n    }\n  }\n"
  },
  {
    "path": "packages/authentication-oauth/src/service.ts",
    "content": "import { createDebug } from '@feathersjs/commons'\nimport { HookContext, NextFunction, Params } from '@feathersjs/feathers'\nimport { FeathersError, GeneralError, NotAuthenticated } from '@feathersjs/errors'\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n//@ts-ignore\nimport Grant from 'grant/lib/grant'\nimport { AuthenticationService } from '@feathersjs/authentication'\nimport { OAuthStrategy } from './strategy'\nimport { getGrantConfig, OauthSetupSettings } from './utils'\n\nconst debug = createDebug('@feathersjs/authentication-oauth/services')\n\nexport type GrantResponse = {\n  location: string\n  session: any\n  state: any\n}\n\nexport type OAuthParams = Omit<Params, 'route'> & {\n  session: any\n  state: Record<string, any>\n  route: {\n    provider: string\n  }\n}\n\nexport class OAuthError extends FeathersError {\n  constructor(\n    message: string,\n    data: any,\n    public location: string\n  ) {\n    super(message, 'NotAuthenticated', 401, 'not-authenticated', data)\n  }\n}\n\nexport const redirectHook = () => async (context: HookContext, next: NextFunction) => {\n  try {\n    await next()\n\n    const { location } = context.result\n\n    debug(`oAuth redirect to ${location}`)\n\n    if (location) {\n      context.http = {\n        ...context.http,\n        location\n      }\n    }\n  } catch (error: any) {\n    if (error.location) {\n      context.http = {\n        ...context.http,\n        location: error.location\n      }\n      context.result = typeof error.toJSON === 'function' ? error.toJSON() : error\n    } else {\n      throw error\n    }\n  }\n}\n\nexport class OAuthService {\n  grant: any\n\n  constructor(\n    public service: AuthenticationService,\n    public settings: OauthSetupSettings\n  ) {\n    const config = getGrantConfig(service)\n\n    this.grant = Grant({ config })\n  }\n\n  async handler(method: string, params: OAuthParams, body?: any, override?: string): Promise<GrantResponse> {\n    const {\n      session,\n      state,\n      query,\n      route: { provider }\n    } = params\n\n    const result: GrantResponse = await this.grant({\n      params: { provider, override },\n      state: state.grant,\n      session: session.grant,\n      query,\n      method,\n      body\n    })\n\n    session.grant = result.session\n    state.grant = result.state\n\n    return result\n  }\n\n  async authenticate(params: OAuthParams, result: GrantResponse) {\n    const name = params.route.provider\n    const { linkStrategy, authService } = this.settings\n    const { accessToken, grant, headers, query = {}, redirect } = params.session\n    const strategy = this.service.getStrategy(name) as OAuthStrategy\n    const authParams = {\n      ...params,\n      headers,\n      authStrategies: [name],\n      authentication: accessToken\n        ? {\n            strategy: linkStrategy,\n            accessToken\n          }\n        : null,\n      query,\n      redirect\n    }\n\n    const payload = grant?.response || result?.session?.response || result?.state?.response\n\n    if (!payload) {\n      throw new NotAuthenticated(\n        'No valid oAuth response. You must initiate the oAuth flow from the authorize endpoint.'\n      )\n    }\n    const authentication = {\n      strategy: name,\n      ...payload\n    }\n\n    try {\n      if (payload.error) {\n        throw new GeneralError(payload.error_description || payload.error, payload)\n      }\n\n      debug(`Calling ${authService}.create authentication with strategy ${name}`)\n\n      const authResult = await this.service.create(authentication, authParams)\n\n      debug('Successful oAuth authentication, sending response')\n\n      const location = await strategy.getRedirect(authResult, authParams)\n\n      if (typeof params.session.destroy === 'function') {\n        await params.session.destroy()\n      }\n\n      return {\n        ...authResult,\n        location\n      }\n    } catch (error: any) {\n      const location = await strategy.getRedirect(error, authParams)\n      const e = new OAuthError(error.message, error.data, location)\n\n      if (typeof params.session.destroy === 'function') {\n        await params.session.destroy()\n      }\n\n      e.stack = error.stack\n      throw e\n    }\n  }\n\n  async find(params: OAuthParams) {\n    const { session, query, headers } = params\n    const { feathers_token, redirect, ...restQuery } = query\n    const handlerParams = {\n      ...params,\n      query: restQuery\n    }\n\n    if (feathers_token) {\n      debug('Got feathers_token query parameter to link accounts', feathers_token)\n      session.accessToken = feathers_token\n    }\n\n    session.redirect = redirect\n    session.query = restQuery\n    // Only store the referer header needed for origin validation\n    session.headers = {\n      referer: headers?.referer\n    }\n\n    return this.handler('GET', handlerParams, {})\n  }\n\n  async get(override: string, params: OAuthParams) {\n    const result = await this.handler('GET', params, {}, override)\n\n    return result\n  }\n\n  async create(data: any, params: OAuthParams) {\n    return this.handler('POST', params, data)\n  }\n}\n\nexport class OAuthCallbackService {\n  constructor(public service: OAuthService) {}\n\n  async find(params: OAuthParams) {\n    const result = await this.service.handler('GET', params, {}, 'callback')\n\n    return this.service.authenticate(params, result)\n  }\n\n  async create(data: any, params: OAuthParams) {\n    const result = await this.service.handler('POST', params, data, 'callback')\n\n    return this.service.authenticate(params, result)\n  }\n}\n"
  },
  {
    "path": "packages/authentication-oauth/src/strategy.ts",
    "content": "import {\n  AuthenticationRequest,\n  AuthenticationBaseStrategy,\n  AuthenticationResult,\n  AuthenticationParams\n} from '@feathersjs/authentication'\nimport { Params } from '@feathersjs/feathers'\nimport { NotAuthenticated } from '@feathersjs/errors'\nimport { createDebug, _ } from '@feathersjs/commons'\nimport qs from 'qs'\n\nconst debug = createDebug('@feathersjs/authentication-oauth/strategy')\n\nexport interface OAuthProfile {\n  id?: string | number\n  [key: string]: any\n}\n\nexport class OAuthStrategy extends AuthenticationBaseStrategy {\n  get configuration() {\n    const { entity, service, entityId, oauth } = this.authentication.configuration\n    const config = oauth[this.name] as any\n\n    return {\n      entity,\n      service,\n      entityId,\n      ...config\n    }\n  }\n\n  get entityId(): string {\n    const { entityService } = this\n\n    return this.configuration.entityId || (entityService && (entityService as any).id)\n  }\n\n  async getEntityQuery(profile: OAuthProfile, _params: Params) {\n    return {\n      [`${this.name}Id`]: profile.sub || profile.id\n    }\n  }\n\n  async getEntityData(profile: OAuthProfile, _existingEntity: any, _params: Params) {\n    return {\n      [`${this.name}Id`]: profile.sub || profile.id\n    }\n  }\n\n  async getProfile(data: AuthenticationRequest, _params: Params) {\n    return data.profile\n  }\n\n  async getCurrentEntity(params: Params) {\n    const { authentication } = params\n    const { entity } = this.configuration\n\n    if (authentication && authentication.strategy) {\n      debug('getCurrentEntity with authentication', authentication)\n\n      const { strategy } = authentication\n      const authResult = await this.authentication.authenticate(authentication, params, strategy)\n\n      return authResult[entity]\n    }\n\n    return null\n  }\n\n  async getAllowedOrigin(params?: Params) {\n    const { redirect, origins = this.app.get('origins') } = this.authentication.configuration.oauth\n\n    if (Array.isArray(origins)) {\n      const referer = params?.headers?.referer || origins[0]\n\n      // Parse the referer to get its origin for proper comparison\n      let refererOrigin: string\n      try {\n        refererOrigin = new URL(referer).origin\n      } catch {\n        throw new NotAuthenticated(`Invalid referer \"${referer}\".`)\n      }\n\n      // Compare full origins\n      const allowedOrigin = origins.find((current) => refererOrigin.toLowerCase() === current.toLowerCase())\n\n      if (!allowedOrigin) {\n        throw new NotAuthenticated(`Referer \"${referer}\" is not allowed.`)\n      }\n\n      return allowedOrigin\n    }\n\n    return redirect\n  }\n\n  async getRedirect(\n    data: AuthenticationResult | Error,\n    params?: AuthenticationParams\n  ): Promise<string | null> {\n    const queryRedirect = (params && params.redirect) || ''\n    const redirect = await this.getAllowedOrigin(params)\n\n    if (!redirect) {\n      return null\n    }\n\n    // Validate redirect parameter to prevent open redirect via URL authority injection\n    // Only allow relative paths starting with / to prevent:\n    // - @attacker.com -> https://target.com@attacker.com (authority injection)\n    // - .attacker.com -> https://target.com.attacker.com (domain suffix attack)\n    // - -attacker.com -> https://target.com-attacker.com (domain suffix attack)\n    // - //attacker.com -> protocol-relative redirect\n    // - \\attacker.com -> backslash redirect\n    if (queryRedirect && (!/^\\//.test(queryRedirect) || /[@\\\\]|\\/\\//.test(queryRedirect))) {\n      throw new NotAuthenticated('Invalid redirect path.')\n    }\n\n    const redirectUrl = `${redirect}${queryRedirect}`\n    const separator = redirectUrl.endsWith('?') ? '' : redirect.indexOf('#') !== -1 ? '?' : '#'\n    const authResult: AuthenticationResult = data\n    const query = authResult.accessToken\n      ? { access_token: authResult.accessToken }\n      : { error: data.message || 'OAuth Authentication not successful' }\n\n    return `${redirectUrl}${separator}${qs.stringify(query)}`\n  }\n\n  async findEntity(profile: OAuthProfile, params: Params) {\n    const query = await this.getEntityQuery(profile, params)\n\n    debug('findEntity with query', query)\n\n    const result = await this.entityService.find({\n      ...params,\n      query\n    })\n    const [entity = null] = result.data ? result.data : result\n\n    debug('findEntity returning', entity)\n\n    return entity\n  }\n\n  async createEntity(profile: OAuthProfile, params: Params) {\n    const data = await this.getEntityData(profile, null, params)\n\n    debug('createEntity with data', data)\n\n    return this.entityService.create(data, _.omit(params, 'query'))\n  }\n\n  async updateEntity(entity: any, profile: OAuthProfile, params: Params) {\n    const id = entity[this.entityId]\n    const data = await this.getEntityData(profile, entity, params)\n\n    debug(`updateEntity with id ${id} and data`, data)\n\n    return this.entityService.patch(id, data, _.omit(params, 'query'))\n  }\n\n  async getEntity(result: any, params: Params) {\n    const { entityService } = this\n    const { entityId = (entityService as any).id, entity } = this.configuration\n\n    if (!entityId || result[entityId] === undefined) {\n      throw new NotAuthenticated('Could not get oAuth entity')\n    }\n\n    if (!params.provider) {\n      return result\n    }\n\n    return entityService.get(result[entityId], {\n      ..._.omit(params, 'query'),\n      [entity]: result\n    })\n  }\n\n  async authenticate(authentication: AuthenticationRequest, originalParams: AuthenticationParams) {\n    const entity: string = this.configuration.entity\n    const { provider, ...params } = originalParams\n    const profile = await this.getProfile(authentication, params)\n    const existingEntity = (await this.findEntity(profile, params)) || (await this.getCurrentEntity(params))\n\n    debug('authenticate with (existing) entity', existingEntity)\n\n    const authEntity = !existingEntity\n      ? await this.createEntity(profile, params)\n      : await this.updateEntity(existingEntity, profile, params)\n\n    return {\n      authentication: { strategy: this.name },\n      [entity]: await this.getEntity(authEntity, originalParams)\n    }\n  }\n}\n"
  },
  {
    "path": "packages/authentication-oauth/src/utils.ts",
    "content": "import type { RequestHandler } from 'express'\nimport type { Middleware, Application as KoaApplication } from '@feathersjs/koa'\n\nimport type { ServiceOptions } from '@feathersjs/feathers'\n\nimport '@feathersjs/koa'\nimport '@feathersjs/express'\nimport expressCookieSession from 'cookie-session'\nimport koaCookieSession from 'koa-session'\n\nimport { AuthenticationService } from '@feathersjs/authentication'\nimport { GrantConfig } from 'grant'\n\nexport interface OauthSetupSettings {\n  linkStrategy: string\n  authService?: string\n  expressSession?: RequestHandler\n  koaSession?: Middleware\n}\n\nexport const getGrantConfig = (service: AuthenticationService): GrantConfig => {\n  const {\n    app,\n    configuration: { oauth }\n  } = service\n  // Set up all the defaults\n  const port = app.get('port')\n  let host = app.get('host')\n  let protocol = 'https'\n\n  // Development environments commonly run on HTTP with an extended port\n  if (process.env.NODE_ENV !== 'production') {\n    protocol = 'http'\n    if (String(port) !== '80') {\n      host += `:${port}`\n    }\n  }\n\n  // omit 'redirect' and 'origins' from oauth\n  const { redirect, origins, ...oauthConfig } = oauth\n\n  const grant: GrantConfig = {\n    ...oauthConfig,\n    defaults: {\n      prefix: '/oauth',\n      origin: `${protocol}://${host}`,\n      transport: 'state',\n      response: ['tokens', 'raw', 'profile'],\n      ...oauthConfig.defaults\n    }\n  }\n\n  const getUrl = (url: string) => {\n    const { defaults } = grant\n    return `${defaults.origin}${defaults.prefix}/${url}`\n  }\n\n  // iterate over grant object with key and value\n  for (const [name, value] of Object.entries(grant)) {\n    if (name !== 'defaults') {\n      value.redirect_uri = value.redirect_uri || getUrl(`${name}/callback`)\n    }\n  }\n\n  return grant\n}\n\nexport const setExpressParams: RequestHandler = (req, res, next) => {\n  req.session.destroy ||= () => {\n    req.session = null\n  }\n\n  req.feathers = {\n    ...req.feathers,\n    session: req.session,\n    state: res.locals\n  }\n\n  next()\n}\n\nexport const setKoaParams: Middleware = async (ctx, next) => {\n  ctx.session.destroy ||= () => {\n    ctx.session = null\n  }\n\n  ctx.feathers = {\n    ...ctx.feathers,\n    session: ctx.session,\n    state: ctx.state\n  } as any\n\n  await next()\n}\n\nexport const authenticationServiceOptions = (\n  service: AuthenticationService,\n  settings: OauthSetupSettings\n): ServiceOptions => {\n  const { secret } = service.configuration\n  const koaApp = service.app as KoaApplication\n\n  if (koaApp.context) {\n    koaApp.keys = [secret]\n\n    const { koaSession = koaCookieSession({ key: 'feathers.oauth' }, koaApp as any) } = settings\n\n    return {\n      koa: {\n        before: [koaSession, setKoaParams]\n      }\n    }\n  }\n\n  const {\n    expressSession = expressCookieSession({\n      name: 'feathers.oauth',\n      keys: [secret]\n    })\n  } = settings\n\n  return {\n    express: {\n      before: [expressSession, setExpressParams]\n    }\n  }\n}\n"
  },
  {
    "path": "packages/authentication-oauth/test/index.test.ts",
    "content": "import { strict as assert } from 'assert'\nimport { feathers } from '@feathersjs/feathers'\nimport { oauth, OauthSetupSettings } from '../src'\nimport { AuthenticationService } from '@feathersjs/authentication'\n\ndescribe('@feathersjs/authentication-oauth', () => {\n  describe('setup', () => {\n    it('errors when service does not exist', () => {\n      const app = feathers()\n\n      assert.throws(\n        () => {\n          app.configure(oauth({ authService: 'something' } as OauthSetupSettings))\n        },\n        {\n          message: 'An authentication service must exist before registering @feathersjs/authentication-oauth'\n        }\n      )\n    })\n\n    it('does not error when service is configured', () => {\n      const app = feathers()\n\n      app.use('/authentication', new AuthenticationService(app))\n\n      app.configure(oauth())\n    })\n  })\n})\n"
  },
  {
    "path": "packages/authentication-oauth/test/service.test.ts",
    "content": "import { strict as assert } from 'assert'\nimport axios, { AxiosResponse } from 'axios'\nimport { CookieJar } from 'tough-cookie'\nimport { expressFixture } from './utils/fixture'\n\ndescribe('@feathersjs/authentication-oauth service security', () => {\n  const port = 9780\n  const req = axios.create({\n    withCredentials: true,\n    maxRedirects: 0\n  })\n  let app: Awaited<ReturnType<typeof expressFixture>>\n\n  const fetchErrorResponse = async (\n    url: string,\n    headers?: Record<string, string>\n  ): Promise<AxiosResponse> => {\n    try {\n      await req.get(url, { headers })\n    } catch (error: any) {\n      return error.response\n    }\n    assert.fail('Should never get here')\n  }\n\n  before(async () => {\n    app = await expressFixture(port, 5117)\n  })\n\n  after(async () => {\n    await app.teardown()\n  })\n\n  describe('internal headers exposure via session cookie', () => {\n    it('should not store sensitive internal headers in session cookie', async () => {\n      const host = `http://localhost:${port}`\n      const location = `${host}/oauth/github`\n\n      // Make request with internal/sensitive headers that might be added by proxies\n      const oauthResponse = await fetchErrorResponse(location, {\n        'x-forwarded-for': '10.0.0.1',\n        'x-internal-api-key': 'sk_live_secret123',\n        'x-real-ip': '192.168.1.1'\n      })\n\n      assert.equal(oauthResponse.status, 303)\n\n      // Get the session cookie\n      const cookies = oauthResponse.headers['set-cookie']\n      assert.ok(cookies, 'Should have set-cookie header')\n\n      // Find the oauth session cookie (express cookie-session uses 'feathers.oauth')\n      const oauthCookie = cookies.find((c: string) => c.startsWith('feathers.oauth='))\n      assert.ok(oauthCookie, 'Should have feathers.oauth session cookie')\n\n      // Extract the cookie value and decode it\n      const match = oauthCookie.match(/feathers\\.oauth=([^;]+)/)\n      assert.ok(match, 'Should be able to extract cookie value')\n\n      const cookieValue = decodeURIComponent(match[1])\n      // Cookie session uses base64 encoding\n      const decoded = Buffer.from(cookieValue, 'base64').toString('utf-8')\n      const sessionData = JSON.parse(decoded)\n\n      // The vulnerability: all headers are stored in session.headers\n      // This test should FAIL if headers object contains sensitive internal headers\n      assert.ok(sessionData.headers, 'Session should have headers stored')\n\n      // These assertions verify the FIX is in place - they should FAIL currently\n      // because the vulnerable code stores ALL headers\n      const storedHeaderKeys = Object.keys(sessionData.headers).map((k) => k.toLowerCase())\n\n      // Only 'referer' should be stored (if needed for origin validation)\n      // Any other headers being stored is a security issue\n      const sensitiveHeaders = [\n        'x-forwarded-for',\n        'x-internal-api-key',\n        'x-real-ip',\n        'authorization',\n        'cookie'\n      ]\n      const exposedSensitiveHeaders = sensitiveHeaders.filter((h) => storedHeaderKeys.includes(h))\n\n      assert.deepEqual(\n        exposedSensitiveHeaders,\n        [],\n        `Sensitive headers should not be stored in session cookie, but found: ${exposedSensitiveHeaders.join(', ')}`\n      )\n    })\n  })\n})\n\ndescribe('Account Takeover via OAuth Callback Query Parameter Forgery', () => {\n  const port = 9781\n  const req = axios.create({\n    withCredentials: true,\n    maxRedirects: 0\n  })\n  let app: Awaited<ReturnType<typeof expressFixture>>\n\n  const fetchResponse = async (url: string, headers?: Record<string, string>): Promise<AxiosResponse> => {\n    try {\n      return await req.get(url, { headers })\n    } catch (error: any) {\n      return error.response\n    }\n  }\n\n  before(async () => {\n    app = await expressFixture(port, 5118)\n    // Create an existing user to demonstrate account takeover\n    await app.service('users').create({ email: 'admin@example.com' })\n  })\n\n  after(async () => {\n    await app.teardown()\n  })\n\n  it('should not authenticate when calling callback directly with forged query parameters', async () => {\n    const host = `http://localhost:${port}`\n    // Attack: directly hit the callback endpoint with a forged profile in query params\n    // Without a valid OAuth session, Grant returns no response, so the payload\n    // falls back to params.query which the attacker controls\n    const attackUrl = `${host}/oauth/github/callback?profile[foo]=bar&code=fake&state=fake`\n\n    const response = await fetchResponse(attackUrl)\n\n    // The forged request must NOT return a valid access token.\n    // Currently the vulnerable code falls back to params.query as the auth payload,\n    // allowing the attacker to forge authentication and receive a JWT.\n    const hasAccessToken =\n      response.data?.accessToken ||\n      (response.headers.location && response.headers.location.includes('access_token'))\n\n    assert.ok(!hasAccessToken, `Forged callback request should not return an access token but got one`)\n  })\n\n  it('should not authenticate when callback is called with a targeted profile id', async () => {\n    const host = `http://localhost:${port}`\n    // Attack: forge a specific profile ID to target a known user\n    const attackUrl = `${host}/oauth/github/callback?profile[id]=12345&code=fake&state=fake`\n\n    const response = await fetchResponse(attackUrl)\n\n    const hasAccessToken =\n      response.data?.accessToken ||\n      (response.headers.location && response.headers.location.includes('access_token'))\n\n    assert.ok(\n      !hasAccessToken,\n      `Forged callback request with targeted profile ID should not return an access token`\n    )\n  })\n})\n\ndescribe('@feathersjs/authentication-oauth service', () => {\n  const port = 9778\n  const req = axios.create({\n    withCredentials: true,\n    maxRedirects: 0\n  })\n  const cookie = new CookieJar()\n  let app: Awaited<ReturnType<typeof expressFixture>>\n\n  const fetchErrorResponse = async (url: string): Promise<AxiosResponse> => {\n    try {\n      await req.get(url)\n    } catch (error: any) {\n      return error.response\n    }\n    assert.fail('Should never get here')\n  }\n\n  before(async () => {\n    app = await expressFixture(port, 5115)\n  })\n\n  after(async () => {\n    await app.teardown()\n  })\n\n  it('runs through the oAuth flow', async () => {\n    const host = `http://localhost:${port}`\n    let location = `${host}/oauth/github`\n\n    const oauthResponse = await fetchErrorResponse(location)\n    assert.equal(oauthResponse.status, 303)\n\n    oauthResponse.headers['set-cookie']?.forEach((value) => cookie.setCookie(value, host))\n\n    location = oauthResponse.data.location\n\n    const providerResponse = await fetchErrorResponse(location)\n    assert.equal(providerResponse.status, 302)\n\n    location = providerResponse.headers.location\n\n    const { data } = await req.get(location, {\n      headers: {\n        cookie: await cookie.getCookieString(host)\n      }\n    })\n\n    assert.ok(data.accessToken)\n    assert.equal(data.authentication.strategy, 'github')\n  })\n})\n"
  },
  {
    "path": "packages/authentication-oauth/test/strategy.test.ts",
    "content": "import { strict as assert } from 'assert'\nimport { expressFixture, TestOAuthStrategy } from './utils/fixture'\nimport { AuthenticationService } from '@feathersjs/authentication'\n\ndescribe('@feathersjs/authentication-oauth/strategy security', () => {\n  let app: Awaited<ReturnType<typeof expressFixture>>\n  let authService: AuthenticationService\n  let strategy: TestOAuthStrategy\n\n  before(async () => {\n    app = await expressFixture(9779, 5116)\n    authService = app.service('authentication')\n    strategy = authService.getStrategy('github') as TestOAuthStrategy\n  })\n\n  after(async () => {\n    await app.teardown()\n  })\n\n  describe('open redirect via URL authority injection', () => {\n    beforeEach(() => {\n      app.get('authentication').oauth.origins = ['https://target.com']\n    })\n\n    afterEach(() => {\n      delete app.get('authentication').oauth.origins\n    })\n\n    it('should reject redirect parameter containing @ character', async () => {\n      // Attack: ?redirect=@attacker.com would result in https://target.com@attacker.com\n      // which browsers parse as username \"target.com\" and host \"attacker.com\"\n      await assert.rejects(\n        () =>\n          strategy.getRedirect(\n            { accessToken: 'testing' },\n            {\n              redirect: '@attacker.com',\n              headers: {\n                referer: 'https://target.com/login'\n              }\n            }\n          ),\n        {\n          name: 'NotAuthenticated'\n        }\n      )\n    })\n\n    it('should reject redirect parameter containing // for protocol-relative URLs', async () => {\n      // Attack: ?redirect=//attacker.com would result in https://target.com//attacker.com\n      // which some parsers might interpret as protocol-relative URL\n      await assert.rejects(\n        () =>\n          strategy.getRedirect(\n            { accessToken: 'testing' },\n            {\n              redirect: '//attacker.com',\n              headers: {\n                referer: 'https://target.com/login'\n              }\n            }\n          ),\n        {\n          name: 'NotAuthenticated'\n        }\n      )\n    })\n\n    it('should reject redirect with backslash characters', async () => {\n      // Some browsers treat backslash as forward slash\n      await assert.rejects(\n        () =>\n          strategy.getRedirect(\n            { accessToken: 'testing' },\n            {\n              redirect: '\\\\\\\\attacker.com',\n              headers: {\n                referer: 'https://target.com/login'\n              }\n            }\n          ),\n        {\n          name: 'NotAuthenticated'\n        }\n      )\n    })\n  })\n\n  describe('open redirect via domain suffix attack', () => {\n    beforeEach(() => {\n      app.get('authentication').oauth.origins = ['https://target.com']\n    })\n\n    afterEach(() => {\n      delete app.get('authentication').oauth.origins\n    })\n\n    it('should reject redirect starting with dot (domain suffix attack)', async () => {\n      // Attack: ?redirect=.attacker.com -> https://target.com.attacker.com\n      await assert.rejects(\n        () =>\n          strategy.getRedirect(\n            { accessToken: 'testing' },\n            {\n              redirect: '.attacker.com',\n              headers: {\n                referer: 'https://target.com/login'\n              }\n            }\n          ),\n        {\n          name: 'NotAuthenticated'\n        }\n      )\n    })\n\n    it('should reject redirect starting with hyphen (domain suffix attack)', async () => {\n      // Attack: ?redirect=-attacker.com -> https://target.com-attacker.com\n      await assert.rejects(\n        () =>\n          strategy.getRedirect(\n            { accessToken: 'testing' },\n            {\n              redirect: '-attacker.com',\n              headers: {\n                referer: 'https://target.com/login'\n              }\n            }\n          ),\n        {\n          name: 'NotAuthenticated'\n        }\n      )\n    })\n\n    it('should reject redirect with bare domain', async () => {\n      // Attack: ?redirect=attacker.com -> https://target.comattacker.com\n      await assert.rejects(\n        () =>\n          strategy.getRedirect(\n            { accessToken: 'testing' },\n            {\n              redirect: 'attacker.com',\n              headers: {\n                referer: 'https://target.com/login'\n              }\n            }\n          ),\n        {\n          name: 'NotAuthenticated'\n        }\n      )\n    })\n\n    it('should allow valid relative path redirect', async () => {\n      const redirect = await strategy.getRedirect(\n        { accessToken: 'testing' },\n        {\n          redirect: '/dashboard',\n          headers: {\n            referer: 'https://target.com/login'\n          }\n        }\n      )\n      assert.equal(redirect, 'https://target.com/dashboard#access_token=testing')\n    })\n\n    it('should allow relative path with query string', async () => {\n      const redirect = await strategy.getRedirect(\n        { accessToken: 'testing' },\n        {\n          redirect: '/callback?state=abc',\n          headers: {\n            referer: 'https://target.com/login'\n          }\n        }\n      )\n      assert.ok(redirect!.startsWith('https://target.com/callback?state=abc'))\n    })\n  })\n\n  describe('origin validation bypass via startsWith', () => {\n    beforeEach(() => {\n      app.get('authentication').oauth.origins = ['https://target.com']\n    })\n\n    afterEach(() => {\n      delete app.get('authentication').oauth.origins\n    })\n\n    it('should reject referer from domain that shares prefix with allowed origin', async () => {\n      // Attack: attacker registers target.com.attacker.com\n      // startsWith('https://target.com') would incorrectly return true\n      await assert.rejects(\n        () =>\n          strategy.getRedirect(\n            { accessToken: 'testing' },\n            {\n              headers: {\n                referer: 'https://target.com.attacker.com/login'\n              }\n            }\n          ),\n        {\n          message: 'Referer \"https://target.com.attacker.com/login\" is not allowed.'\n        }\n      )\n    })\n\n    it('should reject referer with extra subdomain-like prefix', async () => {\n      // Another variant: target.com-evil.attacker.com\n      await assert.rejects(\n        () =>\n          strategy.getRedirect(\n            { accessToken: 'testing' },\n            {\n              headers: {\n                referer: 'https://target.com-evil.attacker.com/login'\n              }\n            }\n          ),\n        {\n          message: 'Referer \"https://target.com-evil.attacker.com/login\" is not allowed.'\n        }\n      )\n    })\n\n    it('should accept exact origin match with path', async () => {\n      // Legitimate use case should still work\n      const redirect = await strategy.getRedirect(\n        { accessToken: 'testing' },\n        {\n          headers: {\n            referer: 'https://target.com/some/path'\n          }\n        }\n      )\n      assert.equal(redirect, 'https://target.com#access_token=testing')\n    })\n  })\n})\n\ndescribe('@feathersjs/authentication-oauth/strategy', () => {\n  let app: Awaited<ReturnType<typeof expressFixture>>\n  let authService: AuthenticationService\n  let strategy: TestOAuthStrategy\n\n  before(async () => {\n    app = await expressFixture(9778, 5115)\n    authService = app.service('authentication')\n    strategy = authService.getStrategy('github') as TestOAuthStrategy\n  })\n\n  after(async () => {\n    await app.teardown()\n  })\n\n  it('initializes, has .entityId and configuration', () => {\n    assert.ok(strategy)\n    assert.strictEqual(strategy.entityId, 'id')\n    assert.ok(strategy.configuration.entity)\n  })\n\n  it('reads configuration from the oauth key', () => {\n    const testConfigValue = Math.random()\n    app.get('authentication').oauth.github.hello = testConfigValue\n    assert.strictEqual(strategy.configuration.hello, testConfigValue)\n  })\n\n  it('getRedirect', async () => {\n    app.get('authentication').oauth.redirect = '/home'\n\n    let redirect = await strategy.getRedirect({ accessToken: 'testing' })\n    assert.equal(redirect, '/home#access_token=testing')\n\n    redirect = await strategy.getRedirect(\n      { accessToken: 'testing' },\n      {\n        redirect: '/hi-there'\n      }\n    )\n    assert.strictEqual('/home/hi-there#access_token=testing', redirect)\n\n    redirect = await strategy.getRedirect(\n      { accessToken: 'testing' },\n      {\n        redirect: '/hi-there?'\n      }\n    )\n    assert.equal(redirect, '/home/hi-there?access_token=testing')\n\n    redirect = await strategy.getRedirect(new Error('something went wrong'))\n    assert.equal(redirect, '/home#error=something%20went%20wrong')\n\n    redirect = await strategy.getRedirect(new Error())\n    assert.equal(redirect, '/home#error=OAuth%20Authentication%20not%20successful')\n\n    app.get('authentication').oauth.redirect = '/home?'\n\n    redirect = await strategy.getRedirect({ accessToken: 'testing' })\n    assert.equal(redirect, '/home?access_token=testing')\n\n    delete app.get('authentication').oauth.redirect\n\n    redirect = await strategy.getRedirect({ accessToken: 'testing' })\n    assert.equal(redirect, null)\n\n    app.get('authentication').oauth.redirect = '/#dashboard'\n\n    redirect = await strategy.getRedirect({ accessToken: 'testing' })\n    assert.equal(redirect, '/#dashboard?access_token=testing')\n  })\n\n  it('getRedirect with referrer and allowed origins (#2430)', async () => {\n    app.get('authentication').oauth.origins = ['https://feathersjs.com', 'https://feathers.cloud']\n\n    let redirect = await strategy.getRedirect(\n      { accessToken: 'testing' },\n      {\n        headers: {\n          referer: 'https://feathersjs.com/somewhere'\n        }\n      }\n    )\n    assert.equal(redirect, 'https://feathersjs.com#access_token=testing')\n\n    redirect = await strategy.getRedirect({ accessToken: 'testing' }, {})\n    assert.equal(redirect, 'https://feathersjs.com#access_token=testing')\n\n    redirect = await strategy.getRedirect(\n      { accessToken: 'testing' },\n      {\n        headers: {\n          referer: 'HTTPS://feathers.CLOUD'\n        }\n      }\n    )\n    assert.equal(redirect, 'https://feathers.cloud#access_token=testing')\n\n    redirect = await strategy.getRedirect(\n      { accessToken: 'testing' },\n      {\n        redirect: '/home',\n        headers: {\n          referer: 'https://feathersjs.com/somewhere'\n        }\n      }\n    )\n    assert.equal(redirect, 'https://feathersjs.com/home#access_token=testing')\n\n    await assert.rejects(\n      () =>\n        strategy.getRedirect(\n          { accessToken: 'testing' },\n          {\n            headers: {\n              referer: 'https://example.com'\n            }\n          }\n        ),\n      {\n        message: 'Referer \"https://example.com\" is not allowed.'\n      }\n    )\n  })\n\n  describe('authenticate', () => {\n    it('with new user', async () => {\n      const authResult = await strategy.authenticate(\n        {\n          strategy: 'test',\n          profile: {\n            id: 'newEntity'\n          }\n        },\n        {}\n      )\n\n      assert.deepEqual(authResult, {\n        authentication: { strategy: 'github' },\n        user: { githubId: 'newEntity', id: authResult.user.id }\n      })\n    })\n\n    it('with existing user and already linked strategy', async () => {\n      const existingUser = await app.service('users').create({\n        githubId: 'existingEntity',\n        name: 'David'\n      })\n      const authResult = await strategy.authenticate(\n        {\n          strategy: 'test',\n          profile: {\n            id: 'existingEntity'\n          }\n        },\n        {}\n      )\n\n      assert.deepEqual(authResult, {\n        authentication: { strategy: 'github' },\n        user: existingUser\n      })\n    })\n\n    it('links user with existing authentication', async () => {\n      const user = await app.service('users').create({\n        name: 'David'\n      })\n      const jwt = await authService.createAccessToken(\n        {},\n        {\n          subject: `${user.id}`\n        }\n      )\n\n      const authResult = await strategy.authenticate(\n        {\n          strategy: 'test',\n          profile: {\n            id: 'linkedEntity'\n          }\n        },\n        {\n          authentication: {\n            strategy: 'jwt',\n            accessToken: jwt\n          }\n        }\n      )\n\n      assert.deepEqual(authResult, {\n        authentication: { strategy: 'github' },\n        user: { id: user.id, name: user.name, githubId: 'linkedEntity' }\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "packages/authentication-oauth/test/utils/fixture.ts",
    "content": "import { Application, feathers, NextFunction } from '@feathersjs/feathers'\nimport express, { rest, errorHandler } from '@feathersjs/express'\nimport { memory, MemoryService } from '@feathersjs/memory'\nimport {\n  AuthenticationService,\n  JWTStrategy,\n  AuthenticationRequest,\n  AuthenticationParams\n} from '@feathersjs/authentication'\nimport { provider } from './provider'\nimport { oauth, OAuthStrategy } from '../../src'\n\nexport interface ServiceTypes {\n  authentication: AuthenticationService\n  users: MemoryService\n}\n\nexport class TestOAuthStrategy extends OAuthStrategy {\n  async authenticate(data: AuthenticationRequest, params: AuthenticationParams) {\n    const { fromMiddleware } = params\n    const authResult = await super.authenticate(data, params)\n\n    if (fromMiddleware) {\n      authResult.fromMiddleware = fromMiddleware\n    }\n\n    return authResult\n  }\n}\n\nexport const fixtureConfig =\n  (port: number, providerInstance: Awaited<ReturnType<typeof provider>>) => (app: Application) => {\n    app.set('host', '127.0.0.1')\n    app.set('port', port)\n    app.set('authentication', {\n      secret: 'supersecret',\n      entity: 'user',\n      service: 'users',\n      authStrategies: ['jwt'],\n      oauth: {\n        github: {\n          key: 'some-key',\n          secret: 'a secret secret',\n          authorize_url: providerInstance.url(`/github/authorize_url`),\n          access_url: providerInstance.url(`/github/access_url`),\n          dynamic: true\n        }\n      }\n    })\n\n    return app\n  }\n\nexport const expressFixture = async (serverPort: number, providerPort: number) => {\n  const providerInstance = await provider({ flow: 'oauth2', port: providerPort })\n  const app = express<ServiceTypes>(feathers())\n  const auth = new AuthenticationService(app)\n\n  auth.register('jwt', new JWTStrategy())\n  auth.register('github', new TestOAuthStrategy())\n\n  app.configure(rest())\n  app.configure(fixtureConfig(serverPort, providerInstance))\n\n  app.use((req, _res, next) => {\n    req.feathers = { fromMiddleware: 'testing' }\n    next()\n  })\n  app.use('authentication', auth)\n  app.use('users', memory())\n\n  app.configure(oauth())\n  app.use(errorHandler({ logger: false }))\n  app.hooks({\n    teardown: [\n      async (_context: any, next: NextFunction) => {\n        await providerInstance.close()\n        await next()\n      }\n    ]\n  })\n  app.hooks({\n    error: {\n      all: [\n        async (context) => {\n          console.error(context.error)\n        }\n      ]\n    }\n  })\n\n  await app.listen(serverPort)\n\n  return app\n}\n"
  },
  {
    "path": "packages/authentication-oauth/test/utils/provider.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/no-empty-function */\n// Ported from https://github.com/simov/grant/blob/master/test/util/provider.js\nimport http from 'http'\nimport _url from 'url'\nimport qs from 'qs'\n\nconst buffer = (req: http.IncomingMessage, done: any) => {\n  let data = ''\n  req.on('data', (chunk: any) => (data += chunk))\n  req.on('end', () => done(/^{.*}$/.test(data) ? JSON.parse(data) : qs.parse(data)))\n}\nconst _query = (req: http.IncomingMessage) => {\n  const parsed = _url.parse(req.url as string, false)\n  const query = qs.parse(parsed.query as any)\n  return query\n}\nconst _oauth = (req: http.IncomingMessage) =>\n  qs.parse((req.headers.authorization || '').replace('OAuth ', '').replace(/\"/g, '').replace(/,/g, '&'))\n\nconst sign = (...args: any[]) =>\n  args\n    .map((arg, index) =>\n      index < 2\n        ? Buffer.from(JSON.stringify(arg))\n            .toString('base64')\n            .replace(/=/g, '')\n            .replace(/\\+/g, '-')\n            .replace(/\\//g, '_')\n        : arg\n    )\n    .join('.')\n\nexport const provider = async ({ flow, port = 5000 }: { flow: 'oauth2' | 'oauth1'; port: number }) => {\n  const server = await (flow === 'oauth2' ? oauth2(port) : oauth1(port))\n  return {\n    oauth1,\n    oauth2,\n    on,\n    server,\n    url: (path: string) => `http://localhost:${port}${path}`,\n    close: () => new Promise((resolve) => server.close(resolve))\n  }\n}\n\nconst oauth1 = (port: number) =>\n  new Promise<http.Server>((resolve) => {\n    let callback: any\n    const server = http.createServer()\n    server.on('request', (req, res) => {\n      const method = req.method\n      const url = req.url as string\n      const headers = req.headers\n      const oauth = _oauth(req)\n      const query = _query(req)\n      const provider = /^\\/(.*)\\/.*/.exec(url) && /^\\/(.*)\\/.*/.exec(url)![1]\n\n      if (/request_url/.test(url)) {\n        callback = oauth.oauth_callback\n        buffer(req, (form: any) => {\n          if (provider === 'getpocket') {\n            callback = form.redirect_uri\n          }\n          on.request({ url, headers, query, form, oauth })\n          provider === 'sellsy'\n            ? res.writeHead(200, { 'content-type': 'application/json' })\n            : res.writeHead(200, { 'content-type': 'application/x-www-form-urlencoded' })\n          provider === 'getpocket'\n            ? res.end(qs.stringify({ code: 'code' }))\n            : provider === 'sellsy'\n              ? res.end(\n                  'authentification_url=https://apifeed.sellsy.com/0/login.php&oauth_token=token&oauth_token_secret=secret&oauth_callback_confirmed=true'\n                )\n              : res.end(qs.stringify({ oauth_token: 'token', oauth_token_secret: 'secret' }))\n        })\n      } else if (/authorize_url/.test(url)) {\n        const location = callback + '?' + qs.stringify({ oauth_token: 'token', oauth_verifier: 'verifier' })\n        on.authorize({ url, headers, query })\n        res.writeHead(302, { location })\n        res.end()\n      } else if (/access_url/.test(url)) {\n        buffer(req, (form: any) => {\n          on.access({ url, headers, query, form, oauth })\n          res.writeHead(200, { 'content-type': 'application/json' })\n          provider === 'getpocket'\n            ? res.end(JSON.stringify({ access_token: 'token' }))\n            : res.end(\n                JSON.stringify({\n                  oauth_token: 'token',\n                  oauth_token_secret: 'secret',\n                  user_id: provider === 'twitter' ? 'id' : undefined\n                })\n              )\n        })\n      } else if (/request_error_message/.test(url)) {\n        callback = oauth.oauth_callback\n        buffer(req, (form: any) => {\n          on.request({ url, headers, query, form, oauth })\n          res.writeHead(200, { 'content-type': 'application/x-www-form-urlencoded' })\n          res.end(qs.stringify({ error: { message: 'invalid' } }))\n        })\n      } else if (/request_error_token/.test(url)) {\n        callback = oauth.oauth_callback\n        buffer(req, (form: any) => {\n          on.request({ url, headers, query, form, oauth })\n          res.writeHead(200, { 'content-type': 'application/x-www-form-urlencoded' })\n          res.end()\n        })\n      } else if (/request_error_status/.test(url)) {\n        callback = oauth.oauth_callback\n        buffer(req, (form: any) => {\n          on.request({ url, headers, query, form, oauth })\n          res.writeHead(500, { 'content-type': 'application/x-www-form-urlencoded' })\n          res.end(qs.stringify({ invalid: 'request_url' }))\n        })\n      } else if (/authorize_error_message/.test(url)) {\n        const location = callback + '?' + qs.stringify({ error: { message: 'invalid' } })\n        on.authorize({ url, headers, query })\n        res.writeHead(302, { location })\n        res.end()\n      } else if (/authorize_error_token/.test(url)) {\n        const location = callback as string\n        on.authorize({ url, headers, query })\n        res.writeHead(302, { location })\n        res.end()\n      } else if (/access_error_status/.test(url)) {\n        buffer(req, (form: any) => {\n          on.access({ url, headers, query, form, oauth })\n          res.writeHead(500, { 'content-type': 'application/json' })\n          res.end(JSON.stringify({ invalid: 'access_url' }))\n        })\n      } else if (/profile_url/.test(url)) {\n        on.profile({ method, url, query, headers })\n        res.writeHead(200, { 'content-type': 'application/json' })\n        provider === 'flickr'\n          ? res.end('callback({\"user\": \"simov\"})')\n          : res.end(JSON.stringify({ user: 'simov' }))\n      }\n    })\n    server.listen(port, () => resolve(server))\n  })\n\nconst oauth2 = (port: number) =>\n  new Promise<http.Server>((resolve) => {\n    const server = http.createServer()\n    let openid: any\n    server.on('request', (req, res) => {\n      const method = req.method\n      const url = req.url as string\n      const headers = req.headers\n      const query = _query(req) as any\n      const provider = /^\\/(.*)\\/.*/.exec(url) && /^\\/(.*)\\/.*/.exec(url)![1]\n\n      if (/authorize_url/.test(url)) {\n        openid = (query.scope || []).includes('openid')\n        on.authorize({ provider, method, url, headers, query })\n        if (query.response_mode === 'form_post') {\n          provider === 'apple'\n            ? res.end(\n                qs.stringify({\n                  code: 'code',\n                  user: { name: { firstName: 'jon', lastName: 'doe' }, email: 'jon@doe.com' }\n                })\n              )\n            : res.end('code')\n          return\n        }\n        const location =\n          query.redirect_uri +\n          '?' +\n          (provider === 'intuit'\n            ? qs.stringify({ code: 'code', realmId: '123' })\n            : qs.stringify({ code: 'code' }))\n        res.writeHead(302, { location })\n        res.end()\n      } else if (/access_url/.test(url)) {\n        buffer(req, (form: any) => {\n          on.access({ provider, method, url, headers, query, form })\n          res.writeHead(200, { 'content-type': 'application/json' })\n          provider === 'concur'\n            ? res.end(' <Token>token</Token> <Refresh_Token>refresh</Refresh_Token> ')\n            : provider === 'withings'\n              ? res.end(\n                  JSON.stringify({\n                    body: {\n                      access_token: 'token',\n                      refresh_token: 'refresh',\n                      expires_in: 3600\n                    }\n                  })\n                )\n              : res.end(\n                  JSON.stringify({\n                    access_token: 'token',\n                    refresh_token: 'refresh',\n                    expires_in: 3600,\n                    id_token: openid ? sign({ typ: 'JWT' }, { nonce: 'whatever' }, 'signature') : undefined,\n                    open_id: provider === 'tiktok' ? 'id' : undefined,\n                    uid: provider === 'weibo' ? 'id' : undefined,\n                    openid: provider === 'wechat' ? 'openid' : undefined\n                  })\n                )\n        })\n      } else if (/authorize_error_message/.test(url)) {\n        on.authorize({ url, query, headers })\n        const location = query.redirect_uri + '?' + qs.stringify({ error: { message: 'invalid' } })\n        res.writeHead(302, { location })\n        res.end()\n      } else if (/authorize_error_code/.test(url)) {\n        on.authorize({ url, query, headers })\n        const location = query.redirect_uri as string\n        res.writeHead(302, { location })\n        res.end()\n      } else if (/authorize_error_state_mismatch/.test(url)) {\n        on.authorize({ url, query, headers })\n        const location = query.redirect_uri + '?' + qs.stringify({ code: 'code', state: 'whatever' })\n        res.writeHead(302, { location })\n        res.end()\n      } else if (/authorize_error_state_missing/.test(url)) {\n        on.authorize({ url, query, headers })\n        const location = query.redirect_uri + '?' + qs.stringify({ code: 'code' })\n        res.writeHead(302, { location })\n        res.end()\n      } else if (/access_error_nonce_mismatch/.test(url)) {\n        buffer(req, (form: any) => {\n          on.access({ method, url, query, headers, form })\n          res.writeHead(200, { 'content-type': 'application/json' })\n          res.end(\n            JSON.stringify({\n              id_token: sign({ typ: 'JWT' }, { nonce: 'whatever' }, 'signature')\n            })\n          )\n        })\n      } else if (/access_error_nonce_missing/.test(url)) {\n        buffer(req, (form: any) => {\n          on.access({ method, url, query, headers, form })\n          res.writeHead(200, { 'content-type': 'application/json' })\n          res.end(\n            JSON.stringify({\n              id_token: sign({ typ: 'JWT' }, {}, 'signature')\n            })\n          )\n        })\n      } else if (/access_error_message/.test(url)) {\n        buffer(req, (form: any) => {\n          on.access({ method, url, query, headers, form })\n          res.writeHead(200, { 'content-type': 'application/json' })\n          res.end(JSON.stringify({ error: { message: 'invalid' } }))\n        })\n      } else if (/access_error_status/.test(url)) {\n        buffer(req, (form: any) => {\n          on.access({ method, url, query, headers, form })\n          res.writeHead(500, { 'content-type': 'application/json' })\n          res.end(JSON.stringify({ invalid: 'access_url' }))\n        })\n      } else if (/profile_url/.test(url)) {\n        if (method === 'POST') {\n          buffer(req, (form: any) => {\n            on.profile({ method, url, query, headers, form })\n            res.writeHead(200, { 'content-type': 'application/json' })\n            res.end(JSON.stringify({ id: 'test', user: 'simov' }))\n          })\n        } else {\n          on.profile({ method, url, query, headers })\n          res.writeHead(200, { 'content-type': 'application/json' })\n          res.end(JSON.stringify({ id: 'test', user: 'simov' }))\n        }\n      } else if (/profile_error/.test(url)) {\n        on.profile({ method, url, query, headers })\n        res.writeHead(400, { 'content-type': 'application/json' })\n        res.end(JSON.stringify({ error: { message: 'Not Found' } }))\n      }\n    })\n    server.listen(port, () => resolve(server))\n  })\n\nconst on = {\n  request: (_opts: any) => {},\n  authorize: (_opts: any) => {},\n  access: (_opts: any) => {},\n  profile: (_opts: any) => {}\n}\n"
  },
  {
    "path": "packages/authentication-oauth/test/utils.test.ts",
    "content": "import { AuthenticationService } from '@feathersjs/authentication/lib'\nimport { feathers } from '@feathersjs/feathers/lib'\nimport { strict as assert } from 'assert'\nimport { getGrantConfig } from '../src/utils'\n\ndescribe('@feathersjs/authentication-oauth/utils', () => {\n  it('getGrantConfig initialises Grant defaults', () => {\n    const app = feathers<{ authentication: AuthenticationService }>()\n    const auth = new AuthenticationService(app)\n\n    app.set('host', '127.0.0.1')\n    app.set('port', '8877')\n    app.set('authentication', {\n      secret: 'supersecret',\n      entity: 'user',\n      service: 'users',\n      authStrategies: ['jwt'],\n      oauth: {\n        github: {\n          key: 'some-key',\n          secret: 'a secret secret',\n          authorize_url: '/github/authorize_url',\n          access_url: '/github/access_url',\n          dynamic: true\n        }\n      }\n    })\n    const { defaults } = getGrantConfig(auth)\n\n    assert.deepStrictEqual(defaults, {\n      prefix: '/oauth',\n      origin: 'http://127.0.0.1:8877',\n      transport: 'state',\n      response: ['tokens', 'raw', 'profile']\n    })\n  })\n\n  it('getGrantConfig uses Grant defaults when set', () => {\n    const app = feathers<{ authentication: AuthenticationService }>()\n    const auth = new AuthenticationService(app)\n\n    app.set('host', '127.0.0.1')\n    app.set('port', '8877')\n    app.set('authentication', {\n      secret: 'supersecret',\n      entity: 'user',\n      service: 'users',\n      authStrategies: ['jwt'],\n      oauth: {\n        defaults: {\n          prefix: '/auth',\n          origin: 'https://localhost:3344'\n        },\n        github: {\n          key: 'some-key',\n          secret: 'a secret secret',\n          authorize_url: '/github/authorize_url',\n          access_url: '/github/access_url',\n          dynamic: true\n        }\n      }\n    })\n    const { defaults, github } = getGrantConfig(auth)\n\n    assert.deepStrictEqual(defaults, {\n      prefix: '/auth',\n      origin: 'https://localhost:3344',\n      transport: 'state',\n      response: ['tokens', 'raw', 'profile']\n    })\n    assert.strictEqual(github?.redirect_uri, 'https://localhost:3344/auth/github/callback')\n  })\n})\n"
  },
  {
    "path": "packages/authentication-oauth/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/cli/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n### Bug Fixes\n\n- **cli:** Add JS extension to binaries ([#3398](https://github.com/feathersjs/feathers/issues/3398)) ([aaf181d](https://github.com/feathersjs/feathers/commit/aaf181d924d0cb67c7792a54197082c59109264d))\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n### Bug Fixes\n\n- **cli:** Fix another ES module issue ([#3395](https://github.com/feathersjs/feathers/issues/3395)) ([8e39884](https://github.com/feathersjs/feathers/commit/8e39884a23d0e7868546dce4f7a3ee6e954c2b31))\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n### Bug Fixes\n\n- **generators:** Move generators and CLI to featherscloud/pinion ([#3386](https://github.com/feathersjs/feathers/issues/3386)) ([eb87c99](https://github.com/feathersjs/feathers/commit/eb87c9922db56c5610e5b808f3ffe033c830e2b2))\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.2](https://github.com/feathersjs/feathers/compare/v5.0.1...v5.0.2) (2023-03-23)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n### Features\n\n- **generators:** Final tweaks to the generators ([#3060](https://github.com/feathersjs/feathers/issues/3060)) ([1bf1544](https://github.com/feathersjs/feathers/commit/1bf1544fa8deeaa44ba354fb539dc3f1fd187767))\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/cli\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Bug Fixes\n\n- **cli:** Add unhandledRejection handler to generated index file ([#2932](https://github.com/feathersjs/feathers/issues/2932)) ([e3cedc8](https://github.com/feathersjs/feathers/commit/e3cedc8e00f52d892f21fd6a3eb4ca4fe40a903c))\n- **cli:** Minor generated app improvements ([#2936](https://github.com/feathersjs/feathers/issues/2936)) ([ba1a550](https://github.com/feathersjs/feathers/commit/ba1a5500a8a5ea4ab44da44ac509e48c723d7efd))\n- **cli:** Properly log validation errors in log-error hook ([54c883c](https://github.com/feathersjs/feathers/commit/54c883c2bb5c35c02b1a2081b2f17554550aa1d4))\n- **cli:** Use correct package manager when installing an app ([#2973](https://github.com/feathersjs/feathers/issues/2973)) ([99c2a70](https://github.com/feathersjs/feathers/commit/99c2a70b77f0b68698a66180b69a56cb20c2ca0d))\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **cli:** mongodb connection string for node 17+ ([#2875](https://github.com/feathersjs/feathers/issues/2875)) ([7fa2012](https://github.com/feathersjs/feathers/commit/7fa2012897d8429b522fbca72211fc9be1c25f7e))\n\n### Features\n\n- **adapter:** Add patch data type to adapters and refactor AdapterBase usage ([#2906](https://github.com/feathersjs/feathers/issues/2906)) ([9ddc2e6](https://github.com/feathersjs/feathers/commit/9ddc2e6b028f026f939d6af68125847e5c6734b4))\n- **cli:** Use separate patch schema and types ([#2916](https://github.com/feathersjs/feathers/issues/2916)) ([7088af6](https://github.com/feathersjs/feathers/commit/7088af64a539dc7f1a016d832b77b98aaaf92603))\n- **docs:** CLI and application structure guide ([#2818](https://github.com/feathersjs/feathers/issues/2818)) ([142914f](https://github.com/feathersjs/feathers/commit/142914fc001a8420056dd56db992c1c4f1bd312c))\n- **schema:** Split resolver options and property resolvers ([#2889](https://github.com/feathersjs/feathers/issues/2889)) ([4822c94](https://github.com/feathersjs/feathers/commit/4822c949812e5a1dceff3c62b2f9de4781b4d601))\n- **schema:** Virtual property resolvers ([#2900](https://github.com/feathersjs/feathers/issues/2900)) ([7d03b57](https://github.com/feathersjs/feathers/commit/7d03b57ae2f633bdd4a368e0d5955011fbd6c329))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n### Bug Fixes\n\n- **cli:** Fix MongoDB connection database name parsing ([#2845](https://github.com/feathersjs/feathers/issues/2845)) ([50e7463](https://github.com/feathersjs/feathers/commit/50e7463971ef95cb98358b70a721e67554d92eb5))\n- **cli:** Use proper MSSQL client ([#2853](https://github.com/feathersjs/feathers/issues/2853)) ([bae5176](https://github.com/feathersjs/feathers/commit/bae5176488b46fc377e53719d20e0036e087aa16))\n- **docs:** Add JavaScript web app frontend guide ([#2834](https://github.com/feathersjs/feathers/issues/2834)) ([68cf03f](https://github.com/feathersjs/feathers/commit/68cf03f092da38ccbec5e9fd42b95d00f5a0a9f2))\n\n### Features\n\n- **mongodb:** Add ObjectId resolvers and MongoDB option in the guide ([#2847](https://github.com/feathersjs/feathers/issues/2847)) ([c5c1fba](https://github.com/feathersjs/feathers/commit/c5c1fba5718a63412075cd3838b86b889eb0bd48))\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n### Bug Fixes\n\n- **cli:** Ensure code injection points are not code style dependent ([#2832](https://github.com/feathersjs/feathers/issues/2832)) ([0776e26](https://github.com/feathersjs/feathers/commit/0776e26bfe4c1df9d2786499941bd3faba1715c0))\n- **cli:** Only generate authentication setup when selected ([#2823](https://github.com/feathersjs/feathers/issues/2823)) ([7d219d9](https://github.com/feathersjs/feathers/commit/7d219d9c5269267b50f3ce99a5653d645f9927c1))\n- **docs:** Review transport API docs and update Express middleware setup ([#2811](https://github.com/feathersjs/feathers/issues/2811)) ([1b97f14](https://github.com/feathersjs/feathers/commit/1b97f14d474f5613482f259eeaa585c24fcfab43))\n- **transports:** Add remaining middleware for generated apps to Koa and Express ([#2796](https://github.com/feathersjs/feathers/issues/2796)) ([0d5781a](https://github.com/feathersjs/feathers/commit/0d5781a5c72a0cbb2ec8211bfa099f0aefe115a2))\n\n### Features\n\n- **cli:** Add authentication client to generated client ([#2801](https://github.com/feathersjs/feathers/issues/2801)) ([bd59f91](https://github.com/feathersjs/feathers/commit/bd59f91b45a01c2eea0c4386e567f4de5aa6ad99))\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n### Features\n\n- **cli:** Generate full client test suite and improve typed client ([#2788](https://github.com/feathersjs/feathers/issues/2788)) ([57119b6](https://github.com/feathersjs/feathers/commit/57119b6bb2797f7297cf054268a248c093ecd538))\n- **cli:** Improve generated schema definitions ([#2783](https://github.com/feathersjs/feathers/issues/2783)) ([474a9fd](https://github.com/feathersjs/feathers/commit/474a9fda2107e9bcf357746320a8e00cda8182b6))\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Bug Fixes\n\n- **core:** Ensure setup and teardown can be overriden and maintain hook functionality ([#2779](https://github.com/feathersjs/feathers/issues/2779)) ([ab580cb](https://github.com/feathersjs/feathers/commit/ab580cbcaa68d19144d86798c13bf564f9d424a6))\n\n### Features\n\n- **cli:** Add ability to `npm init feathers` ([#2755](https://github.com/feathersjs/feathers/issues/2755)) ([d734931](https://github.com/feathersjs/feathers/commit/d734931ffd4f983a05d9e771ce0e43b696c2bc0e))\n- **cli:** Improve CLI interface ([#2753](https://github.com/feathersjs/feathers/issues/2753)) ([c7e1b7e](https://github.com/feathersjs/feathers/commit/c7e1b7e80aacb84441908c3d73512d9cf7557f7e))\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n- **schema:** Make schemas validation library independent and add TypeBox support ([#2772](https://github.com/feathersjs/feathers/issues/2772)) ([44172d9](https://github.com/feathersjs/feathers/commit/44172d99b566d11d9ceda04f1d0bf72b6d05ce76))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n### Features\n\n- Add CORS support to oAuth, Express, Koa and generated application ([#2744](https://github.com/feathersjs/feathers/issues/2744)) ([fd218f2](https://github.com/feathersjs/feathers/commit/fd218f289f8ca4c101e9938e8683e2efef6e8131))\n- **authentication-oauth:** Koa and transport independent oAuth authentication ([#2737](https://github.com/feathersjs/feathers/issues/2737)) ([9231525](https://github.com/feathersjs/feathers/commit/9231525a24bb790ba9c5d940f2867a9c727691c9))\n- **cli:** Add custom environment variable support to generated application ([#2751](https://github.com/feathersjs/feathers/issues/2751)) ([c7bf80d](https://github.com/feathersjs/feathers/commit/c7bf80d82c28c190e3f0136d51af5b7de1bc4868))\n- **cli:** Adding ClientService to CLI ([#2750](https://github.com/feathersjs/feathers/issues/2750)) ([1d45427](https://github.com/feathersjs/feathers/commit/1d45427988521ac028755cbe128685fcdf34f636))\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n### Bug Fixes\n\n- **cli:** Fix flaky authentication migration and SQL id schema types ([#2676](https://github.com/feathersjs/feathers/issues/2676)) ([04ce9a5](https://github.com/feathersjs/feathers/commit/04ce9a53f4226cd6283f9dc241876e90ddf48618))\n\n### Features\n\n- **cli:** Add support for Prettier ([#2684](https://github.com/feathersjs/feathers/issues/2684)) ([83aa8f9](https://github.com/feathersjs/feathers/commit/83aa8f9f212cb122d831dca8858852b0ac9b4da8))\n- **cli:** Improve generated application folder structure ([#2678](https://github.com/feathersjs/feathers/issues/2678)) ([d114557](https://github.com/feathersjs/feathers/commit/d114557721e73d6302aa88c11e3726dbcbd5c92b))\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n### Bug Fixes\n\n- **cli:** Fix compilation folders that got mixed up ([fc4cb74](https://github.com/feathersjs/feathers/commit/fc4cb742f7f9164096d9319b13dfaaa5f54686a6))\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n### Bug Fixes\n\n- **cli:** Generator fixes to work with the new guide ([#2674](https://github.com/feathersjs/feathers/issues/2674)) ([b773fa5](https://github.com/feathersjs/feathers/commit/b773fa5dbd7ff450cfb2f7b93e64882592262712))\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Features\n\n- **cli:** Add generators for new Knex SQL database adapter ([#2673](https://github.com/feathersjs/feathers/issues/2673)) ([0fb2c0f](https://github.com/feathersjs/feathers/commit/0fb2c0f629116f71184b8698c383af8cfd149688))\n- **cli:** Add hook generator ([#2667](https://github.com/feathersjs/feathers/issues/2667)) ([24e4bc0](https://github.com/feathersjs/feathers/commit/24e4bc04a67fadee0e6a96a8389d788faba5c305))\n- **cli:** Add support for JavaScript to the new CLI ([#2668](https://github.com/feathersjs/feathers/issues/2668)) ([ebac587](https://github.com/feathersjs/feathers/commit/ebac587f7d00dc7607c3f546352d79f79b89a5d4))\n- **cli:** Add typed client to a generated app ([#2669](https://github.com/feathersjs/feathers/issues/2669)) ([5b801b5](https://github.com/feathersjs/feathers/commit/5b801b5017ddc3eaa95622b539f51d605916bc86))\n- **cli:** Initial Feathers v5 CLI and Pinion generator ([#2578](https://github.com/feathersjs/feathers/issues/2578)) ([7f59ae7](https://github.com/feathersjs/feathers/commit/7f59ae7f1471895ba8a82aa4702f1a23f71b7682))\n"
  },
  {
    "path": "packages/cli/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/cli/README.md",
    "content": "# @feathersjs/cli\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/cli.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/cli)\n\n> The command line interface for creating Feathers applications\n\n## Installation\n\n```\nnpm install @feathersjs/cli --save-dev\n```\n\n## Usage\n\n```\n$ npx feathers help\n```\n\n## Documentation\n\nRefer to the [Feathers CLI guide](https://feathersjs.com/guides/cli/) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/cli/bin/feathers.js",
    "content": "#!/usr/bin/env node\n'use strict'\n\nimport { program } from '../lib/index.js'\n\nprogram.parse()\n"
  },
  {
    "path": "packages/cli/package.json",
    "content": "{\n  \"name\": \"@feathersjs/cli\",\n  \"description\": \"The command line interface for creating Feathers applications\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/index.js\",\n  \"type\": \"module\",\n  \"bin\": {\n    \"feathers\": \"./bin/feathers.js\"\n  },\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 14\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"lib/**\",\n    \"lib/app/static/.gitignore\",\n    \"bin/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"compile\": \"shx rm -rf lib/ && tsc\",\n    \"mocha\": \"mocha --timeout 60000 --config ../../.mocharc.json --require tsx --recursive test/**.test.ts test/**/*.test.ts\",\n    \"test\": \"npm run compile && npm run mocha && bin/feathers.js --help\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/generators\": \"^5.0.42\",\n    \"chalk\": \"^5.6.2\",\n    \"commander\": \"^13.1.0\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/adapter-commons\": \"^5.0.42\",\n    \"@feathersjs/authentication\": \"^5.0.42\",\n    \"@feathersjs/authentication-client\": \"^5.0.42\",\n    \"@feathersjs/authentication-local\": \"^5.0.42\",\n    \"@feathersjs/authentication-oauth\": \"^5.0.42\",\n    \"@feathersjs/configuration\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/express\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@feathersjs/knex\": \"^5.0.42\",\n    \"@feathersjs/koa\": \"^5.0.42\",\n    \"@feathersjs/mongodb\": \"^5.0.42\",\n    \"@feathersjs/rest-client\": \"^5.0.42\",\n    \"@feathersjs/schema\": \"^5.0.42\",\n    \"@feathersjs/socketio\": \"^5.0.42\",\n    \"@feathersjs/transport-commons\": \"^5.0.42\",\n    \"@feathersjs/typebox\": \"^5.0.42\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"@types/prettier\": \"^2.7.3\",\n    \"axios\": \"^1.13.6\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"type-fest\": \"^5.4.4\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/cli/src/index.ts",
    "content": "import chalk from 'chalk'\nimport { Command } from 'commander'\nimport { dirname } from 'path'\nimport { runGenerator, getContext, FeathersBaseContext, version } from '@feathersjs/generators'\nimport { createRequire } from 'node:module'\n\nexport * from 'commander'\nexport { chalk }\n\nconst require = createRequire(import.meta.url)\n\nexport const commandRunner = (name: string) => async (options: any) => {\n  const folder = dirname(require.resolve('@feathersjs/generators'))\n  const ctx = getContext<FeathersBaseContext>({\n    ...options\n  })\n\n  await Promise.resolve(ctx)\n    .then(runGenerator(folder, name, 'index.js'))\n    .catch((error) => {\n      const { logger } = ctx.pinion\n\n      logger.error(`Error: ${chalk.white(error.message)}`)\n    })\n}\n\nexport const program = new Command()\n\nprogram\n  .name('feathers')\n  .description('The Feathers command line interface 🕊️')\n  .version(version)\n  .showHelpAfterError()\n\nconst generate = program.command('generate').alias('g')\n\ngenerate\n  .command('app')\n  .description('Generate a new application')\n  .option('--name <name>', 'The name of the application')\n  .action(commandRunner('app'))\n\ngenerate\n  .command('service')\n  .description('Generate a new service')\n  .option('--name <name>', 'The service name')\n  .option('--path <path>', 'The path to register the service on')\n  .option('--type <type>', 'The service type (knex, mongodb, custom)')\n  .action(commandRunner('service'))\n\ngenerate\n  .command('hook')\n  .description('Generate a hook')\n  .option('--name <name>', 'The name of the hook')\n  .option('--type <type>', 'The hook type (around or regular)')\n  .action(commandRunner('hook'))\n\ngenerate\n  .command('connection')\n  .description('Add a new database connection')\n  .action(commandRunner('connection'))\n\ngenerate\n  .command('authentication')\n  .description('Add authentication to the application')\n  .action(commandRunner('authentication'))\n\ngenerate.description(\n  `Run a generator. Currently available: \\n  ${generate.commands\n    .map((cmd) => `${chalk.blue(cmd.name())}: ${cmd.description()} `)\n    .join('\\n  ')}`\n)\n"
  },
  {
    "path": "packages/cli/test/cli.test.ts",
    "content": "import { strict } from 'assert'\nimport { program } from '../src'\n\ndescribe('cli tests', () => {\n  it('exports the program', async () => {\n    strict.ok(program)\n  })\n})\n"
  },
  {
    "path": "packages/cli/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\"\n  }\n}\n"
  },
  {
    "path": "packages/client/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.2](https://github.com/feathersjs/feathers/compare/v5.0.1...v5.0.2) (2023-03-23)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Bug Fixes\n\n- **client:** Fix @feathersjs/client types field ([#2596](https://github.com/feathersjs/feathers/issues/2596)) ([d719f54](https://github.com/feathersjs/feathers/commit/d719f54daee63daf9ed5cc762626ca15131086de))\n\n### Features\n\n- **typescript:** Improve adapter typings ([#2605](https://github.com/feathersjs/feathers/issues/2605)) ([3b2ca0a](https://github.com/feathersjs/feathers/commit/3b2ca0a6a8e03e8390272c4d7e930b4bffdaacf5))\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n### Features\n\n- **express, koa:** make transports similar ([#2486](https://github.com/feathersjs/feathers/issues/2486)) ([26aa937](https://github.com/feathersjs/feathers/commit/26aa937c114fb8596dfefc599b1f53cead69c159))\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Features\n\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n### Features\n\n- **koa:** KoaJS transport adapter ([#2315](https://github.com/feathersjs/feathers/issues/2315)) ([2554b57](https://github.com/feathersjs/feathers/commit/2554b57cf05731df58feeba9c12faab18e442107))\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n### Bug Fixes\n\n- **dependencies:** Fix transport-commons dependency and update other dependencies ([#2284](https://github.com/feathersjs/feathers/issues/2284)) ([05b03b2](https://github.com/feathersjs/feathers/commit/05b03b27b40604d956047e3021d8053c3a137616))\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n### Features\n\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### chore\n\n- **package:** Remove @feathersjs/primus packages from core ([#1919](https://github.com/feathersjs/feathers/issues/1919)) ([d20b7d5](https://github.com/feathersjs/feathers/commit/d20b7d5a70f4d3306e294696156e8aa0337c35e9)), closes [#1899](https://github.com/feathersjs/feathers/issues/1899)\n\n### Features\n\n- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))\n\n### BREAKING CHANGES\n\n- **package:** Remove primus packages to be moved into the ecosystem.\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### chore\n\n- **package:** Remove @feathersjs/primus packages from core ([#1919](https://github.com/feathersjs/feathers/issues/1919)) ([d20b7d5](https://github.com/feathersjs/feathers/commit/d20b7d5a70f4d3306e294696156e8aa0337c35e9)), closes [#1899](https://github.com/feathersjs/feathers/issues/1899)\n\n### Features\n\n- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))\n\n### BREAKING CHANGES\n\n- **package:** Remove primus packages to be moved into the ecosystem.\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n### Bug Fixes\n\n- **package:** Fix clean script in non Unix environments ([#2110](https://github.com/feathersjs/feathers/issues/2110)) ([09b62c0](https://github.com/feathersjs/feathers/commit/09b62c0c7e636caf620904ba87d61f168a020f05))\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.5.6](https://github.com/feathersjs/feathers/compare/v4.5.5...v4.5.6) (2020-07-12)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.5.4](https://github.com/feathersjs/feathers/compare/v4.5.3...v4.5.4) (2020-04-29)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.3.5](https://github.com/feathersjs/feathers/compare/v4.3.4...v4.3.5) (2019-10-07)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n### Bug Fixes\n\n- Fix feathers-memory dependency that did not get updated ([9422b13](https://github.com/feathersjs/feathers/commit/9422b13))\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n### Bug Fixes\n\n- Use `export =` in TypeScript definitions ([#1285](https://github.com/feathersjs/feathers/issues/1285)) ([12d0f4b](https://github.com/feathersjs/feathers/commit/12d0f4b))\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n### Bug Fixes\n\n- Improve authentication parameter handling ([#1333](https://github.com/feathersjs/feathers/issues/1333)) ([6e77204](https://github.com/feathersjs/feathers/commit/6e77204))\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n- **chore:** Properly configure and run code linter ([#1092](https://github.com/feathersjs/feathers/issues/1092)) ([fd3fc34](https://github.com/feathersjs/feathers/commit/fd3fc34))\n\n### Features\n\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Authentication v3 core server implementation ([#1205](https://github.com/feathersjs/feathers/issues/1205)) ([1bd7591](https://github.com/feathersjs/feathers/commit/1bd7591))\n\n## [3.7.8](https://github.com/feathersjs/feathers/compare/@feathersjs/client@3.7.7...@feathersjs/client@3.7.8) (2019-01-26)\n\n**Note:** Version bump only for package @feathersjs/client\n\n## [3.7.7](https://github.com/feathersjs/feathers/compare/@feathersjs/client@3.7.6...@feathersjs/client@3.7.7) (2019-01-02)\n\n### Bug Fixes\n\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n\n<a name=\"3.7.6\"></a>\n\n## [3.7.6](https://github.com/feathersjs/feathers/compare/@feathersjs/client@3.7.5...@feathersjs/client@3.7.6) (2018-12-16)\n\n### Bug Fixes\n\n- **chore:** Properly configure and run code linter ([#1092](https://github.com/feathersjs/feathers/issues/1092)) ([fd3fc34](https://github.com/feathersjs/feathers/commit/fd3fc34))\n\n<a name=\"3.7.5\"></a>\n\n## [3.7.5](https://github.com/feathersjs/feathers/compare/@feathersjs/client@3.7.4...@feathersjs/client@3.7.5) (2018-10-26)\n\n**Note:** Version bump only for package @feathersjs/client\n\n<a name=\"3.7.4\"></a>\n\n## [3.7.4](https://github.com/feathersjs/feathers/compare/@feathersjs/client@3.7.3...@feathersjs/client@3.7.4) (2018-10-25)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n\n<a name=\"3.7.3\"></a>\n\n## [3.7.3](https://github.com/feathersjs/feathers/compare/@feathersjs/client@3.7.2...@feathersjs/client@3.7.3) (2018-09-24)\n\n**Note:** Version bump only for package @feathersjs/client\n\n<a name=\"3.7.2\"></a>\n\n## 3.7.2 (2018-09-21)\n\n**Note:** Version bump only for package @feathersjs/client\n\n# Change Log\n\n## [v3.7.1](https://github.com/feathersjs/client/tree/v3.7.1) (2018-09-21)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.7.0...v3.7.1)\n\n## [v3.7.0](https://github.com/feathersjs/client/tree/v3.7.0) (2018-09-18)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.6.0...v3.7.0)\n\n**Closed issues:**\n\n- Cannot patch multiple items [\\#267](https://github.com/feathersjs/client/issues/267)\n\n**Merged pull requests:**\n\n- Update all dependencies and build to Babel 8 [\\#294](https://github.com/feathersjs/client/pull/294) ([daffl](https://github.com/daffl))\n- Update uglifyjs-webpack-plugin to the latest version 🚀 [\\#287](https://github.com/feathersjs/client/pull/287) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.6.0](https://github.com/feathersjs/client/tree/v3.6.0) (2018-09-03)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.5.6...v3.6.0)\n\n**Merged pull requests:**\n\n- Update all dependencies [\\#285](https://github.com/feathersjs/client/pull/285) ([daffl](https://github.com/daffl))\n- Update all dependencies [\\#278](https://github.com/feathersjs/client/pull/278) ([daffl](https://github.com/daffl))\n- Update @feathersjs/errors to the latest version 🚀 [\\#272](https://github.com/feathersjs/client/pull/272) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.5.6](https://github.com/feathersjs/client/tree/v3.5.6) (2018-08-13)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.5.5...v3.5.6)\n\n## [v3.5.5](https://github.com/feathersjs/client/tree/v3.5.5) (2018-08-02)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.5.4...v3.5.5)\n\n**Closed issues:**\n\n- IE11: TypeError: Object doesn't support property or method 'from' [\\#270](https://github.com/feathersjs/client/issues/270)\n\n**Merged pull requests:**\n\n- Update ws to the latest version 🚀 [\\#269](https://github.com/feathersjs/client/pull/269) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.5.4](https://github.com/feathersjs/client/tree/v3.5.4) (2018-07-19)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.5.3...v3.5.4)\n\n**Merged pull requests:**\n\n- Update all dependencies to latest [\\#268](https://github.com/feathersjs/client/pull/268) ([daffl](https://github.com/daffl))\n\n## [v3.5.3](https://github.com/feathersjs/client/tree/v3.5.3) (2018-06-28)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.5.2...v3.5.3)\n\n**Merged pull requests:**\n\n- Update @feathersjs/rest-client to the latest version 🚀 [\\#266](https://github.com/feathersjs/client/pull/266) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.5.2](https://github.com/feathersjs/client/tree/v3.5.2) (2018-06-16)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.5.1...v3.5.2)\n\n**Closed issues:**\n\n- service times out when sending any request to the server, not on localhost [\\#264](https://github.com/feathersjs/client/issues/264)\n\n**Merged pull requests:**\n\n- Update @feathersjs/feathers to the latest version 🚀 [\\#265](https://github.com/feathersjs/client/pull/265) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update shx to the latest version 🚀 [\\#263](https://github.com/feathersjs/client/pull/263) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.5.1](https://github.com/feathersjs/client/tree/v3.5.1) (2018-06-03)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.5.0...v3.5.1)\n\n**Closed issues:**\n\n- 'exports' is undefined [\\#261](https://github.com/feathersjs/client/issues/261)\n- I got error from NuxtJS when I use FeathersJS client V3 [\\#260](https://github.com/feathersjs/client/issues/260)\n\n**Merged pull requests:**\n\n- Update @feathersjs/feathers to the latest version 🚀 [\\#262](https://github.com/feathersjs/client/pull/262) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.5.0](https://github.com/feathersjs/client/tree/v3.5.0) (2018-05-17)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.4.5...v3.5.0)\n\n**Merged pull requests:**\n\n- Update @feathersjs/rest-client to the latest version 🚀 [\\#259](https://github.com/feathersjs/client/pull/259) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.4.5](https://github.com/feathersjs/client/tree/v3.4.5) (2018-05-04)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.4.4...v3.4.5)\n\n**Merged pull requests:**\n\n- Update @feathersjs/feathers to the latest version 🚀 [\\#258](https://github.com/feathersjs/client/pull/258) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.4.4](https://github.com/feathersjs/client/tree/v3.4.4) (2018-03-27)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.4.3...v3.4.4)\n\n**Merged pull requests:**\n\n- Update @feathersjs/feathers to the latest version 🚀 [\\#257](https://github.com/feathersjs/client/pull/257) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/rest-client to the latest version 🚀 [\\#256](https://github.com/feathersjs/client/pull/256) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.4.3](https://github.com/feathersjs/client/tree/v3.4.3) (2018-03-07)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.4.2...v3.4.3)\n\n**Closed issues:**\n\n- Can't capture event on client side [\\#253](https://github.com/feathersjs/client/issues/253)\n\n**Merged pull requests:**\n\n- Update ws to the latest version 🚀 [\\#255](https://github.com/feathersjs/client/pull/255) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update webpack to the latest version 🚀 [\\#254](https://github.com/feathersjs/client/pull/254) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.4.2](https://github.com/feathersjs/client/tree/v3.4.2) (2018-02-16)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.4.1...v3.4.2)\n\n**Closed issues:**\n\n- Feathers client now working with HTTPS self signed certs [\\#250](https://github.com/feathersjs/client/issues/250)\n\n**Merged pull requests:**\n\n- Update @feathersjs/feathers to the latest version 🚀 [\\#252](https://github.com/feathersjs/client/pull/252) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/errors to the latest version 🚀 [\\#251](https://github.com/feathersjs/client/pull/251) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.4.1](https://github.com/feathersjs/client/tree/v3.4.1) (2018-02-10)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.4.0...v3.4.1)\n\n**Merged pull requests:**\n\n- Update @feathersjs/feathers to the latest version 🚀 [\\#249](https://github.com/feathersjs/client/pull/249) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.4.0](https://github.com/feathersjs/client/tree/v3.4.0) (2018-02-09)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.3.2...v3.4.0)\n\n**Merged pull requests:**\n\n- Update @feathersjs/primus-client to the latest version 🚀 [\\#248](https://github.com/feathersjs/client/pull/248) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/socketio-client to the latest version 🚀 [\\#247](https://github.com/feathersjs/client/pull/247) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.3.2](https://github.com/feathersjs/client/tree/v3.3.2) (2018-02-09)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.3.1...v3.3.2)\n\n**Merged pull requests:**\n\n- Update @feathersjs/feathers to the latest version 🚀 [\\#246](https://github.com/feathersjs/client/pull/246) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- delete slack link [\\#245](https://github.com/feathersjs/client/pull/245) ([vodniciarv](https://github.com/vodniciarv))\n\n## [v3.3.1](https://github.com/feathersjs/client/tree/v3.3.1) (2018-02-05)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.3.0...v3.3.1)\n\n**Merged pull requests:**\n\n- Update @feathersjs/socketio-client to the latest version 🚀 [\\#244](https://github.com/feathersjs/client/pull/244) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/primus-client to the latest version 🚀 [\\#243](https://github.com/feathersjs/client/pull/243) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update node-fetch to the latest version 🚀 [\\#242](https://github.com/feathersjs/client/pull/242) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.3.0](https://github.com/feathersjs/client/tree/v3.3.0) (2018-01-26)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.2.0...v3.3.0)\n\n**Merged pull requests:**\n\n- Update @feathersjs/feathers to the latest version 🚀 [\\#241](https://github.com/feathersjs/client/pull/241) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.2.0](https://github.com/feathersjs/client/tree/v3.2.0) (2018-01-24)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.1.2...v3.2.0)\n\n**Closed issues:**\n\n- Index.d.ts has a lack of return-type annotation [\\#238](https://github.com/feathersjs/client/issues/238)\n- feathers rest client call get but server execute find [\\#237](https://github.com/feathersjs/client/issues/237)\n- EventEmitter memory leak detected [\\#236](https://github.com/feathersjs/client/issues/236)\n\n**Merged pull requests:**\n\n- Update @feathersjs/errors to the latest version 🚀 [\\#240](https://github.com/feathersjs/client/pull/240) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update mocha to the latest version 🚀 [\\#239](https://github.com/feathersjs/client/pull/239) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update ws to the latest version 🚀 [\\#235](https://github.com/feathersjs/client/pull/235) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/feathers to the latest version 🚀 [\\#234](https://github.com/feathersjs/client/pull/234) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/rest-client to the latest version 🚀 [\\#233](https://github.com/feathersjs/client/pull/233) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/feathers to the latest version 🚀 [\\#232](https://github.com/feathersjs/client/pull/232) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/authentication-client to the latest version 🚀 [\\#231](https://github.com/feathersjs/client/pull/231) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/socketio-client to the latest version 🚀 [\\#230](https://github.com/feathersjs/client/pull/230) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/primus-client to the latest version 🚀 [\\#229](https://github.com/feathersjs/client/pull/229) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/errors to the latest version 🚀 [\\#228](https://github.com/feathersjs/client/pull/228) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.1.2](https://github.com/feathersjs/client/tree/v3.1.2) (2018-01-02)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.1.1...v3.1.2)\n\n**Closed issues:**\n\n- Socket.io on iOS and Firefox don't work [\\#225](https://github.com/feathersjs/client/issues/225)\n\n**Merged pull requests:**\n\n- Update @feathersjs/feathers to the latest version 🚀 [\\#227](https://github.com/feathersjs/client/pull/227) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update semistandard to the latest version 🚀 [\\#226](https://github.com/feathersjs/client/pull/226) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.1.1](https://github.com/feathersjs/client/tree/v3.1.1) (2017-12-05)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.1.0...v3.1.1)\n\n**Merged pull requests:**\n\n- Update @feathersjs/feathers to the latest version 🚀 [\\#224](https://github.com/feathersjs/client/pull/224) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-memory to the latest version 🚀 [\\#223](https://github.com/feathersjs/client/pull/223) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/errors to the latest version 🚀 [\\#222](https://github.com/feathersjs/client/pull/222) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update @feathersjs/errors to the latest version 🚀 [\\#221](https://github.com/feathersjs/client/pull/221) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v3.1.0](https://github.com/feathersjs/client/tree/v3.1.0) (2017-11-16)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.0.0...v3.1.0)\n\n**Merged pull requests:**\n\n- Link client packages directly to builds and update all dependencies [\\#219](https://github.com/feathersjs/client/pull/219) ([daffl](https://github.com/daffl))\n- Update @feathersjs/feathers to the latest version 🚀 [\\#217](https://github.com/feathersjs/client/pull/217) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update package.json [\\#215](https://github.com/feathersjs/client/pull/215) ([frank-dspeed](https://github.com/frank-dspeed))\n\n## [v3.0.0](https://github.com/feathersjs/client/tree/v3.0.0) (2017-11-01)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v3.0.0-pre.1...v3.0.0)\n\n**Merged pull requests:**\n\n- Update dependencies for release [\\#214](https://github.com/feathersjs/client/pull/214) ([daffl](https://github.com/daffl))\n\n## [v3.0.0-pre.1](https://github.com/feathersjs/client/tree/v3.0.0-pre.1) (2017-10-30)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v2.4.0...v3.0.0-pre.1)\n\n**Closed issues:**\n\n- help data - angularjs [\\#210](https://github.com/feathersjs/client/issues/210)\n- npm packages are installed even if they already exist when creating a new sequelize mysql service [\\#209](https://github.com/feathersjs/client/issues/209)\n- Do you need feathers setup on the server to use feathers on the client? [\\#196](https://github.com/feathersjs/client/issues/196)\n- Reorganization of client-side repositories [\\#137](https://github.com/feathersjs/client/issues/137)\n\n**Merged pull requests:**\n\n- Upgrade to Feathers v3 \\(Buzzard\\) and new builds [\\#213](https://github.com/feathersjs/client/pull/213) ([daffl](https://github.com/daffl))\n- Update dependencies to enable Greenkeeper 🌴 [\\#212](https://github.com/feathersjs/client/pull/212) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-hooks to the latest version 🚀 [\\#208](https://github.com/feathersjs/client/pull/208) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers to the latest version 🚀 [\\#207](https://github.com/feathersjs/client/pull/207) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update mocha to the latest version 🚀 [\\#206](https://github.com/feathersjs/client/pull/206) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- update script src deps example [\\#205](https://github.com/feathersjs/client/pull/205) ([crobinson42](https://github.com/crobinson42))\n- Update feathers to the latest version 🚀 [\\#204](https://github.com/feathersjs/client/pull/204) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-hooks to the latest version 🚀 [\\#203](https://github.com/feathersjs/client/pull/203) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-hooks to the latest version 🚀 [\\#202](https://github.com/feathersjs/client/pull/202) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers to the latest version 🚀 [\\#201](https://github.com/feathersjs/client/pull/201) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-hooks to the latest version 🚀 [\\#200](https://github.com/feathersjs/client/pull/200) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update TypeScript definition for service.patch [\\#199](https://github.com/feathersjs/client/pull/199) ([kfatehi](https://github.com/kfatehi))\n- Update feathers-errors to the latest version 🚀 [\\#197](https://github.com/feathersjs/client/pull/197) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v2.4.0](https://github.com/feathersjs/client/tree/v2.4.0) (2017-09-02)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v2.3.0...v2.4.0)\n\n**Closed issues:**\n\n- Feathers Authentication returning NotFound: Page not found [\\#188](https://github.com/feathersjs/client/issues/188)\n- Typescript import build error [\\#179](https://github.com/feathersjs/client/issues/179)\n\n**Merged pull requests:**\n\n- Update feathers to the latest version 🚀 [\\#195](https://github.com/feathersjs/client/pull/195) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Add default export to TypeScript definition [\\#194](https://github.com/feathersjs/client/pull/194) ([jonlambert](https://github.com/jonlambert))\n- Update ws to the latest version 🚀 [\\#193](https://github.com/feathersjs/client/pull/193) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-errors to the latest version 🚀 [\\#192](https://github.com/feathersjs/client/pull/192) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-errors to the latest version 🚀 [\\#191](https://github.com/feathersjs/client/pull/191) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- fix\\(package\\): update feathers to version 2.1.7 [\\#190](https://github.com/feathersjs/client/pull/190) ([daffl](https://github.com/daffl))\n- Update feathers-hooks to the latest version 🚀 [\\#187](https://github.com/feathersjs/client/pull/187) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-errors to the latest version 🚀 [\\#186](https://github.com/feathersjs/client/pull/186) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v2.3.0](https://github.com/feathersjs/client/tree/v2.3.0) (2017-07-04)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v2.2.0...v2.3.0)\n\n**Closed issues:**\n\n- An in-range update of socket.io-client is breaking the build 🚨 [\\#181](https://github.com/feathersjs/client/issues/181)\n- Drop socket.io [\\#177](https://github.com/feathersjs/client/issues/177)\n- Providing client connection metadata for service event filtering purpose [\\#172](https://github.com/feathersjs/client/issues/172)\n- Support offline mode [\\#29](https://github.com/feathersjs/client/issues/29)\n\n**Merged pull requests:**\n\n- Update feathers-rest to the latest version 🚀 [\\#185](https://github.com/feathersjs/client/pull/185) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-rest to the latest version 🚀 [\\#184](https://github.com/feathersjs/client/pull/184) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Remove IE edge again since it does not seem to be running on Saucelabs [\\#183](https://github.com/feathersjs/client/pull/183) ([daffl](https://github.com/daffl))\n- Update feathers to the latest version 🚀 [\\#182](https://github.com/feathersjs/client/pull/182) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-rest to the latest version 🚀 [\\#180](https://github.com/feathersjs/client/pull/180) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-errors to the latest version 🚀 [\\#178](https://github.com/feathersjs/client/pull/178) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers to the latest version 🚀 [\\#176](https://github.com/feathersjs/client/pull/176) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-primus to the latest version 🚀 [\\#175](https://github.com/feathersjs/client/pull/175) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-socketio to the latest version 🚀 [\\#173](https://github.com/feathersjs/client/pull/173) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers to the latest version 🚀 [\\#171](https://github.com/feathersjs/client/pull/171) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update socket.io-client to the latest version 🚀 [\\#170](https://github.com/feathersjs/client/pull/170) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-errors to the latest version 🚀 [\\#169](https://github.com/feathersjs/client/pull/169) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-errors to the latest version 🚀 [\\#168](https://github.com/feathersjs/client/pull/168) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update feathers-hooks to the latest version 🚀 [\\#167](https://github.com/feathersjs/client/pull/167) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Add IE Edge instead of IE 9 [\\#166](https://github.com/feathersjs/client/pull/166) ([daffl](https://github.com/daffl))\n\n## [v2.2.0](https://github.com/feathersjs/client/tree/v2.2.0) (2017-04-25)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v2.1.0...v2.2.0)\n\n**Merged pull requests:**\n\n- Update feathers-errors to the latest version 🚀 [\\#165](https://github.com/feathersjs/client/pull/165) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Add feathers-errors test [\\#164](https://github.com/feathersjs/client/pull/164) ([christopherjbaker](https://github.com/christopherjbaker))\n- Update semistandard to the latest version 🚀 [\\#163](https://github.com/feathersjs/client/pull/163) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n\n## [v2.1.0](https://github.com/feathersjs/client/tree/v2.1.0) (2017-04-18)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v2.0.0...v2.1.0)\n\n**Closed issues:**\n\n- implementation of feathers client in angular-2 [\\#135](https://github.com/feathersjs/client/issues/135)\n\n**Merged pull requests:**\n\n- Update feathers-hooks to the latest version 🚀 [\\#162](https://github.com/feathersjs/client/pull/162) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Update dependencies to enable Greenkeeper 🌴 [\\#161](https://github.com/feathersjs/client/pull/161) ([greenkeeper[bot]](https://github.com/marketplace/greenkeeper))\n- Added generics to typescript definition. [\\#158](https://github.com/feathersjs/client/pull/158) ([noah79](https://github.com/noah79))\n\n## [v2.0.0](https://github.com/feathersjs/client/tree/v2.0.0) (2017-04-11)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v2.0.0-pre.2...v2.0.0)\n\n**Closed issues:**\n\n- Bundled feathers.js - Socket Authentication with Local Strategy Always Times Out [\\#155](https://github.com/feathersjs/client/issues/155)\n\n**Merged pull requests:**\n\n- Update feathers-rest to version 1.7.2 🚀 [\\#160](https://github.com/feathersjs/client/pull/160) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v2.0.0-pre.2](https://github.com/feathersjs/client/tree/v2.0.0-pre.2) (2017-03-08)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v2.0.0-pre.1...v2.0.0-pre.2)\n\n**Closed issues:**\n\n- Authentication should be removed [\\#136](https://github.com/feathersjs/client/issues/136)\n\n**Merged pull requests:**\n\n- Lock package.json versions [\\#153](https://github.com/feathersjs/client/pull/153) ([daffl](https://github.com/daffl))\n- Add feathers-errors to the client export [\\#152](https://github.com/feathersjs/client/pull/152) ([daffl](https://github.com/daffl))\n- Update feathers to version 2.1.1 🚀 [\\#151](https://github.com/feathersjs/client/pull/151) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-socketio to version 1.5.2 🚀 [\\#150](https://github.com/feathersjs/client/pull/150) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-hooks to version 1.8.1 🚀 [\\#149](https://github.com/feathersjs/client/pull/149) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-rest to version 1.7.1 🚀 [\\#148](https://github.com/feathersjs/client/pull/148) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-socketio to version 1.5.1 🚀 [\\#147](https://github.com/feathersjs/client/pull/147) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-socketio to version 1.5.0 🚀 [\\#146](https://github.com/feathersjs/client/pull/146) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-rest to version 1.7.0 🚀 [\\#145](https://github.com/feathersjs/client/pull/145) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-primus to version 2.1.0 🚀 [\\#144](https://github.com/feathersjs/client/pull/144) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-hooks to version 1.8.0 🚀 [\\#143](https://github.com/feathersjs/client/pull/143) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers to version 2.1.0 🚀 [\\#142](https://github.com/feathersjs/client/pull/142) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-socketio to version 1.4.3 🚀 [\\#141](https://github.com/feathersjs/client/pull/141) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update browserify to version 14.1.0 🚀 [\\#140](https://github.com/feathersjs/client/pull/140) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update ws to version 2.0.0 🚀 [\\#139](https://github.com/feathersjs/client/pull/139) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v2.0.0-pre.1](https://github.com/feathersjs/client/tree/v2.0.0-pre.1) (2017-01-11)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.9.0...v2.0.0-pre.1)\n\n**Closed issues:**\n\n- Socket.io timeout does nothing when there is JWT token available [\\#129](https://github.com/feathersjs/client/issues/129)\n\n**Merged pull requests:**\n\n- Feathers Auth Update [\\#131](https://github.com/feathersjs/client/pull/131) ([flyboarder](https://github.com/flyboarder))\n\n## [v1.9.0](https://github.com/feathersjs/client/tree/v1.9.0) (2016-12-31)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.8.0...v1.9.0)\n\n**Closed issues:**\n\n- Typings don't include configure method [\\#130](https://github.com/feathersjs/client/issues/130)\n\n**Merged pull requests:**\n\n- Add .configure method to TypeScript definitions [\\#134](https://github.com/feathersjs/client/pull/134) ([daffl](https://github.com/daffl))\n- Update feathers-rest to version 1.6.0 🚀 [\\#133](https://github.com/feathersjs/client/pull/133) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-rest to version 1.5.3 🚀 [\\#132](https://github.com/feathersjs/client/pull/132) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-hooks to version 1.7.1 🚀 [\\#128](https://github.com/feathersjs/client/pull/128) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- socket.io-client@1.7.2 breaks build 🚨 [\\#126](https://github.com/feathersjs/client/pull/126) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers to version 2.0.3 🚀 [\\#125](https://github.com/feathersjs/client/pull/125) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Typings changes. [\\#124](https://github.com/feathersjs/client/pull/124) ([ninachaubal](https://github.com/ninachaubal))\n- Update feathers-primus to version 2.0.0 🚀 [\\#123](https://github.com/feathersjs/client/pull/123) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- feathers-commons@0.8.7 breaks build 🚨 [\\#122](https://github.com/feathersjs/client/pull/122) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- superagent@3.1.0 breaks build 🚨 [\\#121](https://github.com/feathersjs/client/pull/121) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.8.0](https://github.com/feathersjs/client/tree/v1.8.0) (2016-11-26)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.7.2...v1.8.0)\n\n**Closed issues:**\n\n- How to get `hooks` `socketio` etc from `feathers` object [\\#118](https://github.com/feathersjs/client/issues/118)\n- send back to server additional fields in 'params' besides 'query' [\\#115](https://github.com/feathersjs/client/issues/115)\n\n**Merged pull requests:**\n\n- Update feathers-hooks to version 1.7.0 🚀 [\\#120](https://github.com/feathersjs/client/pull/120) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Remove reference to typings/index.d.ts [\\#119](https://github.com/feathersjs/client/pull/119) ([ninachaubal](https://github.com/ninachaubal))\n- Update superagent to version 3.0.0 🚀 [\\#116](https://github.com/feathersjs/client/pull/116) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Add TypeScript type definitions. [\\#114](https://github.com/feathersjs/client/pull/114) ([ninachaubal](https://github.com/ninachaubal))\n- Update feathers-memory to version 1.0.0 🚀 [\\#113](https://github.com/feathersjs/client/pull/113) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-authentication to version 0.7.12 🚀 [\\#112](https://github.com/feathersjs/client/pull/112) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-commons to version 0.8.0 🚀 [\\#111](https://github.com/feathersjs/client/pull/111) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.7.2](https://github.com/feathersjs/client/tree/v1.7.2) (2016-11-08)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.7.1...v1.7.2)\n\n**Merged pull requests:**\n\n- Update feathers-rest to version 1.5.2 🚀 [\\#110](https://github.com/feathersjs/client/pull/110) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-socketio to version 1.4.2 🚀 [\\#109](https://github.com/feathersjs/client/pull/109) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.7.1](https://github.com/feathersjs/client/tree/v1.7.1) (2016-11-02)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.7.0...v1.7.1)\n\n**Closed issues:**\n\n- Bower: Version mismatch [\\#104](https://github.com/feathersjs/client/issues/104)\n\n**Merged pull requests:**\n\n- Update feathers-hooks to version 1.6.1 🚀 [\\#108](https://github.com/feathersjs/client/pull/108) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Make sure Bower and NPM version are in sync [\\#107](https://github.com/feathersjs/client/pull/107) ([daffl](https://github.com/daffl))\n\n## [v1.7.0](https://github.com/feathersjs/client/tree/v1.7.0) (2016-11-02)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.6.2...v1.7.0)\n\n**Closed issues:**\n\n- How to access feathers-client [\\#102](https://github.com/feathersjs/client/issues/102)\n- Set up Saucelabs [\\#97](https://github.com/feathersjs/client/issues/97)\n\n**Merged pull requests:**\n\n- 👻😱 Node.js 0.10 is unmaintained 😱👻 [\\#106](https://github.com/feathersjs/client/pull/106) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-hooks to version 1.6.0 🚀 [\\#105](https://github.com/feathersjs/client/pull/105) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Change variable naming from \"app\" to \"feathersClient\" [\\#103](https://github.com/feathersjs/client/pull/103) ([nicoknoll](https://github.com/nicoknoll))\n- jshint —\\> semistandard [\\#101](https://github.com/feathersjs/client/pull/101) ([corymsmith](https://github.com/corymsmith))\n- Cross browser testing in Saucelabs [\\#100](https://github.com/feathersjs/client/pull/100) ([daffl](https://github.com/daffl))\n\n## [v1.6.2](https://github.com/feathersjs/client/tree/v1.6.2) (2016-10-22)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.6.1...v1.6.2)\n\n**Closed issues:**\n\n- Browser Support [\\#96](https://github.com/feathersjs/client/issues/96)\n- How to destroy feathers and socketio client? [\\#95](https://github.com/feathersjs/client/issues/95)\n- Use tests from feathers-commons [\\#26](https://github.com/feathersjs/client/issues/26)\n\n**Merged pull requests:**\n\n- Update feathers-rest to version 1.5.1 🚀 [\\#99](https://github.com/feathersjs/client/pull/99) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Use tests from feathers-commons [\\#98](https://github.com/feathersjs/client/pull/98) ([daffl](https://github.com/daffl))\n- Update feathers-authentication to version 0.7.11 🚀 [\\#92](https://github.com/feathersjs/client/pull/92) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-hooks to version 1.5.8 🚀 [\\#91](https://github.com/feathersjs/client/pull/91) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.6.1](https://github.com/feathersjs/client/tree/v1.6.1) (2016-09-15)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.6.0...v1.6.1)\n\n**Closed issues:**\n\n- documentation on how to build client [\\#87](https://github.com/feathersjs/client/issues/87)\n\n**Merged pull requests:**\n\n- Update feathers to version 2.0.2 🚀 [\\#90](https://github.com/feathersjs/client/pull/90) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.6.0](https://github.com/feathersjs/client/tree/v1.6.0) (2016-09-09)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.5.3...v1.6.0)\n\n**Closed issues:**\n\n- How to declare the app in a static way? [\\#86](https://github.com/feathersjs/client/issues/86)\n- feathers client and requireJS [\\#85](https://github.com/feathersjs/client/issues/85)\n- SocketIO timeout based on service [\\#84](https://github.com/feathersjs/client/issues/84)\n\n**Merged pull requests:**\n\n- Update feathers-rest to version 1.5.0 🚀 [\\#89](https://github.com/feathersjs/client/pull/89) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-memory to version 0.8.0 🚀 [\\#88](https://github.com/feathersjs/client/pull/88) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.5.3](https://github.com/feathersjs/client/tree/v1.5.3) (2016-08-31)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.5.2...v1.5.3)\n\n**Closed issues:**\n\n- Use of feathers-client with es6 \\(JSPM\\) [\\#78](https://github.com/feathersjs/client/issues/78)\n\n**Merged pull requests:**\n\n- Update feathers-authentication to version 0.7.10 🚀 [\\#82](https://github.com/feathersjs/client/pull/82) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-hooks to version 1.5.7 🚀 [\\#77](https://github.com/feathersjs/client/pull/77) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-rest to version 1.4.4 🚀 [\\#76](https://github.com/feathersjs/client/pull/76) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-hooks to version 1.5.6 🚀 [\\#75](https://github.com/feathersjs/client/pull/75) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.5.2](https://github.com/feathersjs/client/tree/v1.5.2) (2016-08-12)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.5.1...v1.5.2)\n\n**Closed issues:**\n\n- \\[Question\\] Large client-side bundle filesize when requiring feathers client [\\#71](https://github.com/feathersjs/client/issues/71)\n\n**Merged pull requests:**\n\n- Update feathers-hooks to version 1.5.5 🚀 [\\#73](https://github.com/feathersjs/client/pull/73) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update mocha to version 3.0.0 🚀 [\\#72](https://github.com/feathersjs/client/pull/72) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.5.1](https://github.com/feathersjs/client/tree/v1.5.1) (2016-07-14)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.5.0...v1.5.1)\n\n**Merged pull requests:**\n\n- Update feathers-rest to version 1.4.3 🚀 [\\#70](https://github.com/feathersjs/client/pull/70) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.5.0](https://github.com/feathersjs/client/tree/v1.5.0) (2016-07-05)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.4.1...v1.5.0)\n\n**Closed issues:**\n\n- Refresh browser [\\#68](https://github.com/feathersjs/client/issues/68)\n\n## [v1.4.1](https://github.com/feathersjs/client/tree/v1.4.1) (2016-06-27)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.4.0...v1.4.1)\n\n## [v1.4.0](https://github.com/feathersjs/client/tree/v1.4.0) (2016-06-24)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.3.2...v1.4.0)\n\n**Closed issues:**\n\n- feathers.min.js? [\\#64](https://github.com/feathersjs/client/issues/64)\n- Facebook login [\\#62](https://github.com/feathersjs/client/issues/62)\n\n**Merged pull requests:**\n\n- Add dist/feathers.min.js [\\#65](https://github.com/feathersjs/client/pull/65) ([daffl](https://github.com/daffl))\n- Update feathers-authentication to version 0.7.9 🚀 [\\#63](https://github.com/feathersjs/client/pull/63) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.3.2](https://github.com/feathersjs/client/tree/v1.3.2) (2016-06-09)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.3.1...v1.3.2)\n\n**Merged pull requests:**\n\n- Update feathers-authentication to version 0.7.8 🚀 [\\#61](https://github.com/feathersjs/client/pull/61) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.3.1](https://github.com/feathersjs/client/tree/v1.3.1) (2016-06-04)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.3.0...v1.3.1)\n\n**Merged pull requests:**\n\n- Update feathers-rest to version 1.4.2 🚀 [\\#60](https://github.com/feathersjs/client/pull/60) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.3.0](https://github.com/feathersjs/client/tree/v1.3.0) (2016-05-30)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.2.1...v1.3.0)\n\n**Merged pull requests:**\n\n- Update feathers-rest to version 1.4.1 🚀 [\\#59](https://github.com/feathersjs/client/pull/59) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-hooks to version 1.5.4 🚀 [\\#57](https://github.com/feathersjs/client/pull/57) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update superagent to version 2.0.0 🚀 [\\#56](https://github.com/feathersjs/client/pull/56) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-socketio to version 1.4.1 🚀 [\\#53](https://github.com/feathersjs/client/pull/53) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-primus to version 1.4.1 🚀 [\\#52](https://github.com/feathersjs/client/pull/52) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.2.1](https://github.com/feathersjs/client/tree/v1.2.1) (2016-05-19)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.2.0...v1.2.1)\n\n**Closed issues:**\n\n- Feathers-client not return correct error object. [\\#44](https://github.com/feathersjs/client/issues/44)\n\n**Merged pull requests:**\n\n- Lock versions for Greenkeeper to make a PR for every release [\\#50](https://github.com/feathersjs/client/pull/50) ([daffl](https://github.com/daffl))\n- Update babel-plugin-add-module-exports to version 0.2.0 🚀 [\\#46](https://github.com/feathersjs/client/pull/46) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.2.0](https://github.com/feathersjs/client/tree/v1.2.0) (2016-04-29)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.1.0...v1.2.0)\n\n**Closed issues:**\n\n- Socket.io timeouts? [\\#42](https://github.com/feathersjs/client/issues/42)\n- Add batch support [\\#4](https://github.com/feathersjs/client/issues/4)\n\n**Merged pull requests:**\n\n- nsp@2.3.2 breaks build 🚨 [\\#41](https://github.com/feathersjs/client/pull/41) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Fixing url for link in readme to feathers-authentication [\\#39](https://github.com/feathersjs/client/pull/39) ([xiplias](https://github.com/xiplias))\n- feathers-primus@1.3.3 breaks build 🚨 [\\#38](https://github.com/feathersjs/client/pull/38) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- ws@1.1.0 breaks build 🚨 [\\#36](https://github.com/feathersjs/client/pull/36) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-memory to version 0.7.0 🚀 [\\#33](https://github.com/feathersjs/client/pull/33) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.1.0](https://github.com/feathersjs/client/tree/v1.1.0) (2016-04-03)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.0.0...v1.1.0)\n\n**Merged pull requests:**\n\n- Update all dependencies 🌴 [\\#31](https://github.com/feathersjs/client/pull/31) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.0.0](https://github.com/feathersjs/client/tree/v1.0.0) (2016-03-14)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.0.0-pre.3...v1.0.0)\n\n**Merged pull requests:**\n\n- Use a gcc version that can build bcrypt [\\#30](https://github.com/feathersjs/client/pull/30) ([daffl](https://github.com/daffl))\n\n## [v1.0.0-pre.3](https://github.com/feathersjs/client/tree/v1.0.0-pre.3) (2016-03-14)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.0.0-pre.2...v1.0.0-pre.3)\n\n## [v1.0.0-pre.2](https://github.com/feathersjs/client/tree/v1.0.0-pre.2) (2016-03-04)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.5.3...v1.0.0-pre.2)\n\n**Closed issues:**\n\n- Can't get $regex to work in find function with feathers-nedb in the background [\\#28](https://github.com/feathersjs/client/issues/28)\n- feathers.fetch is undefined [\\#27](https://github.com/feathersjs/client/issues/27)\n- Add documentation for using in React Native [\\#10](https://github.com/feathersjs/client/issues/10)\n\n## [v0.5.3](https://github.com/feathersjs/client/tree/v0.5.3) (2016-02-12)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v1.0.0-pre.1...v0.5.3)\n\n## [v1.0.0-pre.1](https://github.com/feathersjs/client/tree/v1.0.0-pre.1) (2016-02-11)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.5.2...v1.0.0-pre.1)\n\n## [v0.5.2](https://github.com/feathersjs/client/tree/v0.5.2) (2016-02-09)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.5.1...v0.5.2)\n\n**Merged pull requests:**\n\n- Universal feathers [\\#25](https://github.com/feathersjs/client/pull/25) ([daffl](https://github.com/daffl))\n- Adding nsp check [\\#24](https://github.com/feathersjs/client/pull/24) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.5.1](https://github.com/feathersjs/client/tree/v0.5.1) (2016-01-15)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.5.0...v0.5.1)\n\n**Closed issues:**\n\n- REST base.js missing ${options.base} leads to broken relative url [\\#21](https://github.com/feathersjs/client/issues/21)\n- Add hook support [\\#20](https://github.com/feathersjs/client/issues/20)\n- $sort does not work for find\\(\\) [\\#19](https://github.com/feathersjs/client/issues/19)\n\n**Merged pull requests:**\n\n- fix issue \\#21 [\\#22](https://github.com/feathersjs/client/pull/22) ([wuyuanyi135](https://github.com/wuyuanyi135))\n\n## [v0.5.0](https://github.com/feathersjs/client/tree/v0.5.0) (2016-01-05)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.4.0...v0.5.0)\n\n**Closed issues:**\n\n- how to use in typescript [\\#17](https://github.com/feathersjs/client/issues/17)\n\n**Merged pull requests:**\n\n- Added fetch support [\\#18](https://github.com/feathersjs/client/pull/18) ([corymsmith](https://github.com/corymsmith))\n- Adding events and querystring dependencies. [\\#16](https://github.com/feathersjs/client/pull/16) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.4.0](https://github.com/feathersjs/client/tree/v0.4.0) (2015-12-11)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.3.3...v0.4.0)\n\n**Fixed bugs:**\n\n- Importing in ES6 is broken [\\#14](https://github.com/feathersjs/client/issues/14)\n\n**Closed issues:**\n\n- .babelrc messes with react-native [\\#15](https://github.com/feathersjs/client/issues/15)\n\n## [v0.3.3](https://github.com/feathersjs/client/tree/v0.3.3) (2015-11-27)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.3.2...v0.3.3)\n\n**Closed issues:**\n\n- npm package is broken. [\\#12](https://github.com/feathersjs/client/issues/12)\n\n**Merged pull requests:**\n\n- Fix es6 build and add Steal compatibility. [\\#13](https://github.com/feathersjs/client/pull/13) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.3.2](https://github.com/feathersjs/client/tree/v0.3.2) (2015-11-26)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.3.1...v0.3.2)\n\n**Closed issues:**\n\n- Update lodash [\\#11](https://github.com/feathersjs/client/issues/11)\n\n## [v0.3.1](https://github.com/feathersjs/client/tree/v0.3.1) (2015-11-26)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.3.0...v0.3.1)\n\n**Closed issues:**\n\n- Working with can-connect [\\#8](https://github.com/feathersjs/client/issues/8)\n\n## [v0.3.0](https://github.com/feathersjs/client/tree/v0.3.0) (2015-11-15)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.2.1...v0.3.0)\n\n**Closed issues:**\n\n- Use Promises [\\#7](https://github.com/feathersjs/client/issues/7)\n\n**Merged pull requests:**\n\n- Migration to ES6 and using Promises [\\#9](https://github.com/feathersjs/client/pull/9) ([daffl](https://github.com/daffl))\n\n## [v0.2.1](https://github.com/feathersjs/client/tree/v0.2.1) (2015-10-06)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.2.0...v0.2.1)\n\n**Merged pull requests:**\n\n- Make client depend on feathers-commons, remove arguments.js [\\#6](https://github.com/feathersjs/client/pull/6) ([daffl](https://github.com/daffl))\n\n## [v0.2.0](https://github.com/feathersjs/client/tree/v0.2.0) (2015-07-18)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.1.3...v0.2.0)\n\n## [v0.1.3](https://github.com/feathersjs/client/tree/v0.1.3) (2015-07-06)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.1.2...v0.1.3)\n\n**Merged pull requests:**\n\n- Fixing requires and missing deps. [\\#5](https://github.com/feathersjs/client/pull/5) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.1.2](https://github.com/feathersjs/client/tree/v0.1.2) (2015-06-22)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.1.1...v0.1.2)\n\n**Closed issues:**\n\n- Publish to NPM and Bower [\\#1](https://github.com/feathersjs/client/issues/1)\n\n## [v0.1.1](https://github.com/feathersjs/client/tree/v0.1.1) (2015-06-21)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.0.1...v0.1.1)\n\n## [v0.0.1](https://github.com/feathersjs/client/tree/v0.0.1) (2015-06-21)\n\n[Full Changelog](https://github.com/feathersjs/client/compare/v0.1.0...v0.0.1)\n\n## [v0.1.0](https://github.com/feathersjs/client/tree/v0.1.0) (2015-06-06)\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/client/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Feathers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/client/README.md",
    "content": "# @feathersjs/client\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/client.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/client)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> A client build for FeathersJS\n\n## Installation\n\n```\nnpm install @feathersjs/client --save\n```\n\n## Documentation\n\nRefer to the [Feathers client API documentation](https://docs.feathersjs.com/api/client.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/client/core.js",
    "content": "module.exports = require('./dist/core');\n"
  },
  {
    "path": "packages/client/package.json",
    "content": "{\n  \"name\": \"@feathersjs/client\",\n  \"description\": \"A module that consolidates Feathers client modules for REST (jQuery, Request, Superagent) and Websocket (Socket.io, Primus) connections\",\n  \"version\": \"5.0.42\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/client\"\n  },\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"homepage\": \"https://github.com/feathersjs/client\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"author\": \"Feathers contributors\",\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"main\": \"dist/feathers\",\n  \"types\": \"dist/feathers\",\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"dist/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"compile\": \"tsc\",\n    \"version\": \"npm run build\",\n    \"clean\": \"shx rm -rf dist/ && shx mkdir -p dist\",\n    \"build\": \"npm run clean && npm run compile && npm run webpack\",\n    \"mocha\": \"mocha --config ../../.mocharc.json --recursive test/**/*.test.ts\",\n    \"test\": \"npm run build && npm run mocha\",\n    \"webpack\": \"webpack --config webpack/feathers.js && webpack --config webpack/feathers.min.js && webpack --config webpack/core.js && webpack --config webpack/core.min.js\"\n  },\n  \"browserslist\": [\n    \"last 2 versions\",\n    \"IE 11\"\n  ],\n  \"dependencies\": {\n    \"@feathersjs/authentication-client\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@feathersjs/rest-client\": \"^5.0.42\",\n    \"@feathersjs/socketio-client\": \"^5.0.42\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.29.0\",\n    \"@babel/preset-env\": \"^7.29.0\",\n    \"@feathersjs/express\": \"^5.0.42\",\n    \"@feathersjs/memory\": \"^5.0.42\",\n    \"@feathersjs/socketio\": \"^5.0.42\",\n    \"@feathersjs/tests\": \"^5.0.42\",\n    \"babel-loader\": \"^10.0.0\",\n    \"mocha\": \"^11.7.5\",\n    \"node-fetch\": \"^2.6.1\",\n    \"shx\": \"^0.4.0\",\n    \"socket.io-client\": \"^4.8.3\",\n    \"superagent\": \"^10.3.0\",\n    \"ts-loader\": \"^9.5.4\",\n    \"typescript\": \"^5.9.3\",\n    \"webpack\": \"^5.105.4\",\n    \"webpack-cli\": \"^6.0.1\",\n    \"webpack-merge\": \"^6.0.1\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/client/src/core.ts",
    "content": "export * from '@feathersjs/feathers'\n"
  },
  {
    "path": "packages/client/src/feathers.ts",
    "content": "import { feathers } from '@feathersjs/feathers'\nimport authentication from '@feathersjs/authentication-client'\nimport rest from '@feathersjs/rest-client'\nimport socketio from '@feathersjs/socketio-client'\n\nexport * from '@feathersjs/feathers'\nexport * as errors from '@feathersjs/errors'\nexport { authentication, rest, socketio }\nexport default feathers\n\nif (typeof module !== 'undefined') {\n  module.exports = Object.assign(feathers, module.exports)\n}\n"
  },
  {
    "path": "packages/client/test/fetch.test.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\n// @ts-ignore\nimport fetch from 'node-fetch'\nimport { Server } from 'http'\nimport { clientTests } from '@feathersjs/tests'\n\nimport * as feathers from '../dist/feathers'\nimport app from './fixture'\n\ndescribe('fetch REST connector', function () {\n  let server: Server\n  const rest = feathers.rest('http://localhost:8889')\n  const client = feathers.default().configure(rest.fetch(fetch))\n\n  before(async () => {\n    server = await app().listen(8889)\n  })\n\n  after(function (done) {\n    server.close(done)\n  })\n\n  clientTests(client, 'todos')\n})\n"
  },
  {
    "path": "packages/client/test/fixture.ts",
    "content": "import { feathers, Application, HookContext, Id, Params } from '@feathersjs/feathers'\nimport * as express from '@feathersjs/express'\nimport { MemoryService } from '@feathersjs/memory'\n\n// eslint-disable-next-line no-extend-native\nObject.defineProperty(Error.prototype, 'toJSON', {\n  value() {\n    const alt: any = {}\n\n    Object.getOwnPropertyNames(this).forEach((key: string) => {\n      alt[key] = this[key]\n    })\n\n    return alt\n  },\n  configurable: true\n})\n\n// Create an in-memory CRUD service for our Todos\nclass TodoService extends MemoryService {\n  async get(id: Id, params: Params) {\n    if (params.query.error) {\n      throw new Error('Something went wrong')\n    }\n\n    return super.get(id).then((data) => Object.assign({ query: params.query }, data))\n  }\n}\n\nexport default (configurer?: (app: Application) => void) => {\n  const app = express\n    .default(feathers())\n    // Parse HTTP bodies\n    .use(express.json())\n    .use(express.urlencoded({ extended: true }))\n    // Host the current directory (for index.html)\n    .use(express.static(process.cwd()))\n    .configure(express.rest())\n\n  if (typeof configurer === 'function') {\n    configurer.call(app, app)\n  }\n\n  app\n    // Host our Todos service on the /todos path\n    .use(\n      '/todos',\n      new TodoService({\n        multi: true\n      })\n    )\n    .use(express.errorHandler())\n\n  const testTodo = {\n    text: 'some todo',\n    complete: false\n  }\n  const service: any = app.service('todos')\n\n  service.create(testTodo)\n  service.hooks({\n    after: {\n      remove(hook: HookContext<any, any>) {\n        if (hook.id === null) {\n          service._uId = 0\n          return service.create(testTodo).then(() => hook)\n        }\n      }\n    }\n  })\n\n  app.on('connection', (connection) => (app as any).channel('general').join(connection))\n\n  if (service.publish) {\n    service.publish(() => app.channel('general'))\n  }\n\n  return app\n}\n"
  },
  {
    "path": "packages/client/test/socketio.test.ts",
    "content": "import { io } from 'socket.io-client'\nimport socketio from '@feathersjs/socketio'\nimport { Server } from 'http'\nimport { clientTests } from '@feathersjs/tests'\n\nimport * as feathers from '../dist/feathers'\nimport app from './fixture'\n\ndescribe('Socket.io connector', function () {\n  let server: Server\n  const socket = io('http://localhost:9988')\n  const client = feathers.default().configure(feathers.socketio(socket))\n\n  before(async () => {\n    server = await app((app) => app.configure(socketio())).listen(9988)\n  })\n\n  after(function (done) {\n    socket.once('disconnect', () => {\n      server.close()\n      done()\n    })\n    socket.disconnect()\n  })\n\n  clientTests(client, 'todos')\n})\n"
  },
  {
    "path": "packages/client/test/superagent.test.ts",
    "content": "import superagent from 'superagent'\nimport { clientTests } from '@feathersjs/tests'\nimport { Server } from 'http'\n\nimport * as feathers from '../dist/feathers'\nimport app from './fixture'\n\ndescribe('Superagent REST connector', function () {\n  let server: Server\n  const rest = feathers.rest('http://localhost:8889')\n  const client = feathers.default().configure(rest.superagent(superagent))\n\n  before(async () => {\n    server = await app().listen(8889)\n  })\n\n  after(function (done) {\n    server.close(done)\n  })\n\n  clientTests(client, 'todos')\n})\n"
  },
  {
    "path": "packages/client/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"sourceMap\": false,\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"dist/\"    \n  }\n}\n"
  },
  {
    "path": "packages/client/webpack/core.js",
    "content": "const createConfig = require('./create-config');\n\nmodule.exports = createConfig('core');"
  },
  {
    "path": "packages/client/webpack/create-config.js",
    "content": "const path = require('path');\nconst webpack = require('webpack');\nconst { merge } = require('webpack-merge');\n\nmodule.exports = function createConfig (output, isProduction = false) {\n  const commons = {\n    entry: [\n      `./src/${output}.ts`\n    ],\n    output: {\n      library: 'feathers',\n      libraryTarget: 'umd',\n      globalObject: 'this',\n      path: path.resolve(__dirname, '..', 'dist'),\n      filename: `${output}.js`\n    },\n    resolve: {\n      extensions: [ '.tsx', '.ts', '.js' ]\n    },\n    module: {\n      rules: [{\n        test: /\\.tsx?$/,\n        use: 'ts-loader',\n        exclude: /node_modules/\n      }, {\n        test: /\\.js/,\n        exclude: /node_modules\\/(?!(@feathersjs|debug))/,\n        loader: 'babel-loader',\n        options: {\n          presets: ['@babel/preset-env']\n          // plugins: ['@babel/plugin-transform-classes']\n        }\n      }]\n    }\n  };\n\n  const dev = {\n    mode: 'development',\n    devtool: 'source-map'\n  };\n  const production = {\n    mode: 'production',\n    output: {\n      filename: `${output}.min.js`\n    },\n    plugins: [\n      new webpack.DefinePlugin({\n        'process.env.NODE_ENV': JSON.stringify('production')\n      })\n    ]\n  };\n\n  return merge(commons, isProduction ? production : dev);\n}\n"
  },
  {
    "path": "packages/client/webpack/feathers.js",
    "content": "const createConfig = require('./create-config');\n\nmodule.exports = createConfig('feathers');"
  },
  {
    "path": "packages/commons/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n### Bug Fixes\n\n- **core:** Use Symbol.for to instantiate shared symbols ([#3087](https://github.com/feathersjs/feathers/issues/3087)) ([7f3fc21](https://github.com/feathersjs/feathers/commit/7f3fc2167576f228f8183568eb52b077160e8d65))\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n### Features\n\n- **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Features\n\n- **core:** Migrate @feathersjs/feathers to TypeScript ([#1963](https://github.com/feathersjs/feathers/issues/1963)) ([7812529](https://github.com/feathersjs/feathers/commit/7812529ff0f1008e21211f1d01efbc49795dbe55))\n- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Features\n\n- **core:** Migrate @feathersjs/feathers to TypeScript ([#1963](https://github.com/feathersjs/feathers/issues/1963)) ([7812529](https://github.com/feathersjs/feathers/commit/7812529ff0f1008e21211f1d01efbc49795dbe55))\n- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n### Bug Fixes\n\n- make \\_\\_hooks writable and configurable ([#1520](https://github.com/feathersjs/feathers/issues/1520)) ([1c6c374](https://github.com/feathersjs/feathers/commit/1c6c3742ecf1cb813be56074da89e6736d03ffe8))\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n**Note:** Version bump only for package @feathersjs/commons\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n- use minimal RegExp matching for better performance ([#977](https://github.com/feathersjs/feathers/issues/977)) ([3ca7e97](https://github.com/feathersjs/feathers/commit/3ca7e97))\n\n### Features\n\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Common database adapter utilities and test suite ([#1130](https://github.com/feathersjs/feathers/issues/1130)) ([17b3dc8](https://github.com/feathersjs/feathers/commit/17b3dc8))\n- Remove (hook, next) signature and SKIP support ([#1269](https://github.com/feathersjs/feathers/issues/1269)) ([211c0f8](https://github.com/feathersjs/feathers/commit/211c0f8))\n\n### BREAKING CHANGES\n\n- Move database adapter utilities from @feathersjs/commons into its own module\n\n<a name=\"4.0.0\"></a>\n\n# [4.0.0](https://github.com/feathersjs/feathers/compare/@feathersjs/commons@3.0.1...@feathersjs/commons@4.0.0) (2018-12-16)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n\n### Features\n\n- Common database adapter utilities and test suite ([#1130](https://github.com/feathersjs/feathers/issues/1130)) ([17b3dc8](https://github.com/feathersjs/feathers/commit/17b3dc8))\n\n### BREAKING CHANGES\n\n- Move database adapter utilities from @feathersjs/commons into its own module\n\n<a name=\"3.0.1\"></a>\n\n## [3.0.1](https://github.com/feathersjs/feathers/compare/@feathersjs/commons@3.0.0...@feathersjs/commons@3.0.1) (2018-09-17)\n\n### Bug Fixes\n\n- use minimal RegExp matching for better performance ([#977](https://github.com/feathersjs/feathers/issues/977)) ([3ca7e97](https://github.com/feathersjs/feathers/commit/3ca7e97))\n\n# Change Log\n\n## [v3.0.0-pre.1](https://github.com/feathersjs/commons/tree/v3.0.0-pre.1) (2018-08-13)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v2.0.0...v3.0.0-pre.1)\n\n**Merged pull requests:**\n\n- Remove argument verification and add further utilities [\\#81](https://github.com/feathersjs/commons/pull/81) ([daffl](https://github.com/daffl))\n\n## [v2.0.0](https://github.com/feathersjs/commons/tree/v2.0.0) (2018-08-03)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.4.4...v2.0.0)\n\n**Merged pull requests:**\n\n- Merge major with latest changes [\\#80](https://github.com/feathersjs/commons/pull/80) ([daffl](https://github.com/daffl))\n- Ability to specify custom filters in filterQuery [\\#73](https://github.com/feathersjs/commons/pull/73) ([vonagam](https://github.com/vonagam))\n\n## [v1.4.4](https://github.com/feathersjs/commons/tree/v1.4.4) (2018-08-01)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.4.3...v1.4.4)\n\n## [v1.4.3](https://github.com/feathersjs/commons/tree/v1.4.3) (2018-07-25)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.4.2...v1.4.3)\n\n**Merged pull requests:**\n\n- Revert breaking change from 78d780de91ae8333f3843be153beb5deea55c792 [\\#78](https://github.com/feathersjs/commons/pull/78) ([daffl](https://github.com/daffl))\n\n## [v1.4.2](https://github.com/feathersjs/commons/tree/v1.4.2) (2018-07-25)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.4.1...v1.4.2)\n\n**Closed issues:**\n\n- Sort error on multiple fields [\\#74](https://github.com/feathersjs/commons/issues/74)\n- Cannot build with create-react-app \\(again\\) [\\#71](https://github.com/feathersjs/commons/issues/71)\n\n**Merged pull requests:**\n\n- Update all dependencies [\\#77](https://github.com/feathersjs/commons/pull/77) ([daffl](https://github.com/daffl))\n- Use sorting algorithm from NeDB [\\#76](https://github.com/feathersjs/commons/pull/76) ([daffl](https://github.com/daffl))\n- Open hook workflow to custom methods [\\#72](https://github.com/feathersjs/commons/pull/72) ([bertho-zero](https://github.com/bertho-zero))\n\n## [v1.4.1](https://github.com/feathersjs/commons/tree/v1.4.1) (2018-04-12)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.4.0...v1.4.1)\n\n**Closed issues:**\n\n- Uncaught ReferenceError: convertGetOrRemove is not defined [\\#69](https://github.com/feathersjs/commons/issues/69)\n- Cannot build with create-react-app [\\#68](https://github.com/feathersjs/commons/issues/68)\n\n**Merged pull requests:**\n\n- Make conversion functions more concise [\\#70](https://github.com/feathersjs/commons/pull/70) ([daffl](https://github.com/daffl))\n- Update mocha to the latest version 🚀 [\\#67](https://github.com/feathersjs/commons/pull/67) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.4.0](https://github.com/feathersjs/commons/tree/v1.4.0) (2018-01-17)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.3.1...v1.4.0)\n\n**Merged pull requests:**\n\n- Add ability to skip all following hooks [\\#65](https://github.com/feathersjs/commons/pull/65) ([sylvainlap](https://github.com/sylvainlap))\n\n## [v1.3.1](https://github.com/feathersjs/commons/tree/v1.3.1) (2018-01-12)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.3.0...v1.3.1)\n\n**Merged pull requests:**\n\n- Allow array for sorting [\\#66](https://github.com/feathersjs/commons/pull/66) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#64](https://github.com/feathersjs/commons/pull/64) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.3.0](https://github.com/feathersjs/commons/tree/v1.3.0) (2017-11-20)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.2.0...v1.3.0)\n\n**Merged pull requests:**\n\n- Add a toJSON method to the hook context [\\#63](https://github.com/feathersjs/commons/pull/63) ([daffl](https://github.com/daffl))\n- updating contributing guide and issue template [\\#61](https://github.com/feathersjs/commons/pull/61) ([ekryski](https://github.com/ekryski))\n\n## [v1.2.0](https://github.com/feathersjs/commons/tree/v1.2.0) (2017-10-25)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.1.0...v1.2.0)\n\n**Merged pull requests:**\n\n- Bring back makeUrl [\\#62](https://github.com/feathersjs/commons/pull/62) ([daffl](https://github.com/daffl))\n- adding codeclimate config [\\#60](https://github.com/feathersjs/commons/pull/60) ([ekryski](https://github.com/ekryski))\n\n## [v1.1.0](https://github.com/feathersjs/commons/tree/v1.1.0) (2017-10-23)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.0.0...v1.1.0)\n\n**Merged pull requests:**\n\n- Remove unused utilities and add some inline documentation [\\#59](https://github.com/feathersjs/commons/pull/59) ([daffl](https://github.com/daffl))\n- Add feathers-query-filters [\\#58](https://github.com/feathersjs/commons/pull/58) ([daffl](https://github.com/daffl))\n\n## [v1.0.0](https://github.com/feathersjs/commons/tree/v1.0.0) (2017-10-19)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.0.0-pre.3...v1.0.0)\n\n**Merged pull requests:**\n\n- Rename repository and add to npm scope [\\#57](https://github.com/feathersjs/commons/pull/57) ([daffl](https://github.com/daffl))\n- Updates for Feathers v3 \\(Buzzard\\) [\\#56](https://github.com/feathersjs/commons/pull/56) ([daffl](https://github.com/daffl))\n\n## [v1.0.0-pre.3](https://github.com/feathersjs/commons/tree/v1.0.0-pre.3) (2017-10-18)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.0.0-pre.2...v1.0.0-pre.3)\n\n**Merged pull requests:**\n\n- Update the client test suite [\\#55](https://github.com/feathersjs/commons/pull/55) ([daffl](https://github.com/daffl))\n- Update mocha to the latest version 🚀 [\\#54](https://github.com/feathersjs/commons/pull/54) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.0-pre.2](https://github.com/feathersjs/commons/tree/v1.0.0-pre.2) (2017-07-11)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v1.0.0-pre.1...v1.0.0-pre.2)\n\n**Merged pull requests:**\n\n- Update to new plugin infrastructure [\\#53](https://github.com/feathersjs/commons/pull/53) ([daffl](https://github.com/daffl))\n\n## [v1.0.0-pre.1](https://github.com/feathersjs/commons/tree/v1.0.0-pre.1) (2017-06-28)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.8.7...v1.0.0-pre.1)\n\n**Merged pull requests:**\n\n- Commons for Feathers v3 [\\#52](https://github.com/feathersjs/commons/pull/52) ([daffl](https://github.com/daffl))\n- Update chai to the latest version 🚀 [\\#51](https://github.com/feathersjs/commons/pull/51) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update semistandard to the latest version 🚀 [\\#50](https://github.com/feathersjs/commons/pull/50) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update dependencies to enable Greenkeeper 🌴 [\\#49](https://github.com/feathersjs/commons/pull/49) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v0.8.7](https://github.com/feathersjs/commons/tree/v0.8.7) (2016-11-30)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.8.6...v0.8.7)\n\n**Closed issues:**\n\n- Matcher function blows up with null values [\\#46](https://github.com/feathersjs/commons/issues/46)\n\n**Merged pull requests:**\n\n- matcher now doesn't blow up with null values. Closes \\#46 [\\#47](https://github.com/feathersjs/commons/pull/47) ([ekryski](https://github.com/ekryski))\n\n## [v0.8.6](https://github.com/feathersjs/commons/tree/v0.8.6) (2016-11-25)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.8.5...v0.8.6)\n\n**Merged pull requests:**\n\n- Allow to pass an object to hook object [\\#45](https://github.com/feathersjs/commons/pull/45) ([daffl](https://github.com/daffl))\n\n## [v0.8.5](https://github.com/feathersjs/commons/tree/v0.8.5) (2016-11-19)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.8.4...v0.8.5)\n\n**Merged pull requests:**\n\n- Deep merge and toObject [\\#44](https://github.com/feathersjs/commons/pull/44) ([ekryski](https://github.com/ekryski))\n- Expose lodash functions [\\#43](https://github.com/feathersjs/commons/pull/43) ([ekryski](https://github.com/ekryski))\n- Make url [\\#42](https://github.com/feathersjs/commons/pull/42) ([ekryski](https://github.com/ekryski))\n- Expect syntax [\\#41](https://github.com/feathersjs/commons/pull/41) ([ekryski](https://github.com/ekryski))\n\n## [v0.8.4](https://github.com/feathersjs/commons/tree/v0.8.4) (2016-11-11)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.8.3...v0.8.4)\n\n## [v0.8.3](https://github.com/feathersjs/commons/tree/v0.8.3) (2016-11-11)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.8.2...v0.8.3)\n\n## [v0.8.2](https://github.com/feathersjs/commons/tree/v0.8.2) (2016-11-11)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.8.1...v0.8.2)\n\n**Merged pull requests:**\n\n- One more fix for select on arrays [\\#40](https://github.com/feathersjs/commons/pull/40) ([daffl](https://github.com/daffl))\n\n## [v0.8.1](https://github.com/feathersjs/commons/tree/v0.8.1) (2016-11-11)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.8.0...v0.8.1)\n\n**Merged pull requests:**\n\n- Fixing select utility methods to work with query selector [\\#39](https://github.com/feathersjs/commons/pull/39) ([daffl](https://github.com/daffl))\n\n## [v0.8.0](https://github.com/feathersjs/commons/tree/v0.8.0) (2016-11-09)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.7.8...v0.8.0)\n\n**Merged pull requests:**\n\n- Implementing lodash utilities and helpers for selecting [\\#38](https://github.com/feathersjs/commons/pull/38) ([daffl](https://github.com/daffl))\n- jshint —\\> semistandard [\\#37](https://github.com/feathersjs/commons/pull/37) ([corymsmith](https://github.com/corymsmith))\n\n## [v0.7.8](https://github.com/feathersjs/commons/tree/v0.7.8) (2016-10-21)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.7.7...v0.7.8)\n\n**Merged pull requests:**\n\n- Make getting the service in base test dynamic [\\#36](https://github.com/feathersjs/commons/pull/36) ([daffl](https://github.com/daffl))\n\n## [v0.7.7](https://github.com/feathersjs/commons/tree/v0.7.7) (2016-10-21)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.7.6...v0.7.7)\n\n**Merged pull requests:**\n\n- Allow app in hookObject [\\#35](https://github.com/feathersjs/commons/pull/35) ([daffl](https://github.com/daffl))\n\n## [v0.7.6](https://github.com/feathersjs/commons/tree/v0.7.6) (2016-10-20)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.7.5...v0.7.6)\n\n**Merged pull requests:**\n\n- Add test for matching and increase code coverage [\\#34](https://github.com/feathersjs/commons/pull/34) ([daffl](https://github.com/daffl))\n- omit '$select' in matcher [\\#33](https://github.com/feathersjs/commons/pull/33) ([beeplin](https://github.com/beeplin))\n- adding code coverage [\\#32](https://github.com/feathersjs/commons/pull/32) ([ekryski](https://github.com/ekryski))\n\n## [v0.7.5](https://github.com/feathersjs/commons/tree/v0.7.5) (2016-09-05)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.7.4...v0.7.5)\n\n**Closed issues:**\n\n- Feathers should accept other type of data beside only the object type. [\\#26](https://github.com/feathersjs/commons/issues/26)\n- Send better error messages for method normalization [\\#12](https://github.com/feathersjs/commons/issues/12)\n\n**Merged pull requests:**\n\n- Allow matching nested $or queries [\\#29](https://github.com/feathersjs/commons/pull/29) ([daffl](https://github.com/daffl))\n- Add default export to `hooks.js` [\\#28](https://github.com/feathersjs/commons/pull/28) ([KenanY](https://github.com/KenanY))\n- Update mocha to version 3.0.0 🚀 [\\#27](https://github.com/feathersjs/commons/pull/27) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v0.7.4](https://github.com/feathersjs/commons/tree/v0.7.4) (2016-05-29)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.7.3...v0.7.4)\n\n**Merged pull requests:**\n\n- Use forEach instead of ES6 'for of' loop [\\#25](https://github.com/feathersjs/commons/pull/25) ([lopezjurip](https://github.com/lopezjurip))\n- mocha@2.5.0 breaks build 🚨 [\\#24](https://github.com/feathersjs/commons/pull/24) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update babel-plugin-add-module-exports to version 0.2.0 🚀 [\\#23](https://github.com/feathersjs/commons/pull/23) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v0.7.3](https://github.com/feathersjs/commons/tree/v0.7.3) (2016-05-05)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.7.2...v0.7.3)\n\n**Merged pull requests:**\n\n- Make sure arguments from hook objects are created properly for known … [\\#22](https://github.com/feathersjs/commons/pull/22) ([daffl](https://github.com/daffl))\n\n## [v0.7.2](https://github.com/feathersjs/commons/tree/v0.7.2) (2016-04-26)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.7.1...v0.7.2)\n\n**Merged pull requests:**\n\n- Update test fixture to use promises and add error cases [\\#19](https://github.com/feathersjs/commons/pull/19) ([daffl](https://github.com/daffl))\n\n## [v0.7.1](https://github.com/feathersjs/commons/tree/v0.7.1) (2016-04-04)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.6.2...v0.7.1)\n\n**Merged pull requests:**\n\n- Adding functionality and tests for shared query and list handling [\\#17](https://github.com/feathersjs/commons/pull/17) ([daffl](https://github.com/daffl))\n\n## [v0.6.2](https://github.com/feathersjs/commons/tree/v0.6.2) (2016-02-09)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.7.0...v0.6.2)\n\n## [v0.7.0](https://github.com/feathersjs/commons/tree/v0.7.0) (2016-02-08)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.6.1...v0.7.0)\n\n## [v0.6.1](https://github.com/feathersjs/commons/tree/v0.6.1) (2016-02-08)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.6.0...v0.6.1)\n\n**Merged pull requests:**\n\n- Add NSP check to test script. [\\#16](https://github.com/feathersjs/commons/pull/16) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.6.0](https://github.com/feathersjs/commons/tree/v0.6.0) (2016-01-21)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.5.0...v0.6.0)\n\n**Closed issues:**\n\n- Rename hooks to hookUtils to make room for common hooks. [\\#13](https://github.com/feathersjs/commons/issues/13)\n\n**Merged pull requests:**\n\n- Remove shared socket functionality [\\#15](https://github.com/feathersjs/commons/pull/15) ([daffl](https://github.com/daffl))\n- Support socket routes with apps mounted on a path [\\#14](https://github.com/feathersjs/commons/pull/14) ([daffl](https://github.com/daffl))\n\n## [v0.5.0](https://github.com/feathersjs/commons/tree/v0.5.0) (2016-01-10)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.4.0...v0.5.0)\n\n## [v0.4.0](https://github.com/feathersjs/commons/tree/v0.4.0) (2016-01-10)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.3.4...v0.4.0)\n\n## [v0.3.4](https://github.com/feathersjs/commons/tree/v0.3.4) (2016-01-06)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.3.3...v0.3.4)\n\n**Merged pull requests:**\n\n- Fix SocketIO client iteration for all cases [\\#11](https://github.com/feathersjs/commons/pull/11) ([daffl](https://github.com/daffl))\n\n## [v0.3.3](https://github.com/feathersjs/commons/tree/v0.3.3) (2016-01-06)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.3.2...v0.3.3)\n\n**Closed issues:**\n\n- Socket.io 1.4.0 broke feathers [\\#10](https://github.com/feathersjs/commons/issues/10)\n\n## [v0.3.2](https://github.com/feathersjs/commons/tree/v0.3.2) (2016-01-06)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.3.1...v0.3.2)\n\n## [v0.3.1](https://github.com/feathersjs/commons/tree/v0.3.1) (2016-01-06)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.3.0...v0.3.1)\n\n## [v0.3.0](https://github.com/feathersjs/commons/tree/v0.3.0) (2015-12-11)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.2.11...v0.3.0)\n\n**Closed issues:**\n\n- babel inside package.json breaks react-native [\\#9](https://github.com/feathersjs/commons/issues/9)\n\n## [v0.2.11](https://github.com/feathersjs/commons/tree/v0.2.11) (2015-11-30)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.2.10...v0.2.11)\n\n**Merged pull requests:**\n\n- getOrRemove did not check id property type [\\#8](https://github.com/feathersjs/commons/pull/8) ([daffl](https://github.com/daffl))\n\n## [v0.2.10](https://github.com/feathersjs/commons/tree/v0.2.10) (2015-11-28)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.2.9...v0.2.10)\n\n**Closed issues:**\n\n- Remove dependency on lodash [\\#6](https://github.com/feathersjs/commons/issues/6)\n\n**Merged pull requests:**\n\n- Migrate to Babel 6 and remove Lodash dependency [\\#7](https://github.com/feathersjs/commons/pull/7) ([daffl](https://github.com/daffl))\n\n## [v0.2.9](https://github.com/feathersjs/commons/tree/v0.2.9) (2015-11-17)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.2.8...v0.2.9)\n\n**Closed issues:**\n\n- Event dispatcher context is not being set to the service [\\#5](https://github.com/feathersjs/commons/issues/5)\n- .create with no callback throws error [\\#4](https://github.com/feathersjs/commons/issues/4)\n\n## [v0.2.8](https://github.com/feathersjs/commons/tree/v0.2.8) (2015-10-06)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.2.7...v0.2.8)\n\n**Closed issues:**\n\n- getArguments not exporting correctly [\\#1](https://github.com/feathersjs/commons/issues/1)\n\n**Merged pull requests:**\n\n- Add hookObject utilities and remove Lodash dependency from arguments.js [\\#3](https://github.com/feathersjs/commons/pull/3) ([daffl](https://github.com/daffl))\n\n## [v0.2.7](https://github.com/feathersjs/commons/tree/v0.2.7) (2015-03-07)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.2.6...v0.2.7)\n\n## [v0.2.6](https://github.com/feathersjs/commons/tree/v0.2.6) (2015-03-06)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/v0.2.5...v0.2.6)\n\n## [v0.2.5](https://github.com/feathersjs/commons/tree/v0.2.5) (2015-03-06)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/0.2.3...v0.2.5)\n\n## [0.2.3](https://github.com/feathersjs/commons/tree/0.2.3) (2015-03-06)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/0.2.2...0.2.3)\n\n## [0.2.2](https://github.com/feathersjs/commons/tree/0.2.2) (2015-03-06)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/0.2.1...0.2.2)\n\n## [0.2.1](https://github.com/feathersjs/commons/tree/0.2.1) (2015-03-06)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/0.2.0...0.2.1)\n\n## [0.2.0](https://github.com/feathersjs/commons/tree/0.2.0) (2015-03-06)\n\n[Full Changelog](https://github.com/feathersjs/commons/compare/0.1.0...0.2.0)\n\n## [0.1.0](https://github.com/feathersjs/commons/tree/0.1.0) (2015-03-06)\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/commons/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/commons/README.md",
    "content": "# Feathers Commons\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/commons.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/commons)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Shared Feathers utility functions\n\n## Installation\n\n```\nnpm install @feathersjs/commons --save\n```\n\n## Documentation\n\nRefer to the [Feathers API](https://feathersjs.com/api) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/commons/package.json",
    "content": "{\n  \"name\": \"@feathersjs/commons\",\n  \"version\": \"5.0.42\",\n  \"description\": \"Shared Feathers utility functions\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"keywords\": [\n    \"feathers\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/commons\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributor\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"devDependencies\": {\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/commons/src/debug.ts",
    "content": "/* eslint-disable @typescript-eslint/no-empty-function */\nexport type DebugFunction = (...args: any[]) => void\nexport type DebugInitializer = (name: string) => DebugFunction\n\nconst debuggers: { [key: string]: DebugFunction } = {}\n\nexport function noopDebug(): DebugFunction {\n  return function () {}\n}\n\nlet defaultInitializer: DebugInitializer = noopDebug\n\nexport function setDebug(debug: DebugInitializer) {\n  defaultInitializer = debug\n\n  Object.keys(debuggers).forEach((name) => {\n    debuggers[name] = debug(name)\n  })\n}\n\nexport function createDebug(name: string) {\n  if (!debuggers[name]) {\n    debuggers[name] = defaultInitializer(name)\n  }\n\n  return (...args: any[]) => debuggers[name](...args)\n}\n"
  },
  {
    "path": "packages/commons/src/index.ts",
    "content": "// Removes all leading and trailing slashes from a path\nexport function stripSlashes(name: string) {\n  return name.replace(/^(\\/+)|(\\/+)$/g, '')\n}\n\nexport type KeyValueCallback<T> = (value: any, key: string) => T\n\n// A set of lodash-y utility functions that use ES6\nexport const _ = {\n  each(obj: any, callback: KeyValueCallback<void>) {\n    if (obj && typeof obj.forEach === 'function') {\n      obj.forEach(callback)\n    } else if (_.isObject(obj)) {\n      Object.keys(obj).forEach((key) => callback(obj[key], key))\n    }\n  },\n\n  some(value: any, callback: KeyValueCallback<boolean>) {\n    return Object.keys(value)\n      .map((key) => [value[key], key])\n      .some(([val, key]) => callback(val, key))\n  },\n\n  every(value: any, callback: KeyValueCallback<boolean>) {\n    return Object.keys(value)\n      .map((key) => [value[key], key])\n      .every(([val, key]) => callback(val, key))\n  },\n\n  keys(obj: any) {\n    return Object.keys(obj)\n  },\n\n  values(obj: any) {\n    return _.keys(obj).map((key) => obj[key])\n  },\n\n  isMatch(obj: any, item: any) {\n    return _.keys(item).every((key) => obj[key] === item[key])\n  },\n\n  isEmpty(obj: any) {\n    return _.keys(obj).length === 0\n  },\n\n  isObject(item: any) {\n    return typeof item === 'object' && !Array.isArray(item) && item !== null\n  },\n\n  isObjectOrArray(value: any) {\n    return typeof value === 'object' && value !== null\n  },\n\n  extend(first: any, ...rest: any[]) {\n    return Object.assign(first, ...rest)\n  },\n\n  omit(obj: any, ...keys: string[]) {\n    const result = _.extend({}, obj)\n    keys.forEach((key) => delete result[key])\n    return result\n  },\n\n  pick(source: any, ...keys: string[]) {\n    return keys.reduce((result: { [key: string]: any }, key) => {\n      if (source[key] !== undefined) {\n        result[key] = source[key]\n      }\n\n      return result\n    }, {})\n  },\n\n  // Recursively merge the source object into the target object\n  merge(target: any, source: any) {\n    if (_.isObject(target) && _.isObject(source)) {\n      Object.keys(source).forEach((key) => {\n        if (_.isObject(source[key])) {\n          if (!target[key]) {\n            Object.assign(target, { [key]: {} })\n          }\n\n          _.merge(target[key], source[key])\n        } else {\n          Object.assign(target, { [key]: source[key] })\n        }\n      })\n    }\n    return target\n  }\n}\n\n// Duck-checks if an object looks like a promise\nexport function isPromise(result: any) {\n  return _.isObject(result) && typeof result.then === 'function'\n}\n\nexport function createSymbol(name: string) {\n  return typeof Symbol !== 'undefined' ? Symbol.for(name) : name\n}\n\nexport * from './debug'\n"
  },
  {
    "path": "packages/commons/test/debug.test.ts",
    "content": "import { strict as assert } from 'assert'\nimport { createDebug, setDebug, noopDebug } from '../src'\n\nconst myDebug = createDebug('hello test')\n\ndescribe('debug', () => {\n  it('default debug does nothing', () => {\n    assert.equal(myDebug('hi', 'there'), undefined)\n  })\n\n  it('can set custom debug later', () => {\n    let call\n\n    const customDebug =\n      (name: string) =>\n      (...args: any[]) => {\n        call = [name].concat(args)\n      }\n\n    setDebug(customDebug)\n\n    assert.equal(myDebug('hi', 'there'), undefined)\n    assert.deepEqual(call, ['hello test', 'hi', 'there'])\n\n    const newDebug = createDebug('other test')\n\n    assert.equal(newDebug('other', 'there'), undefined)\n    assert.deepEqual(call, ['other test', 'other', 'there'])\n\n    setDebug(noopDebug)\n  })\n})\n"
  },
  {
    "path": "packages/commons/test/module.test.ts",
    "content": "import { strict as assert } from 'assert'\nimport { _ } from '../src'\n\ndescribe('module', () => {\n  it('is commonjs compatible', () => {\n    // eslint-disable-next-line\n    const commons = require('../lib')\n\n    assert.equal(typeof commons, 'object')\n    assert.equal(typeof commons.stripSlashes, 'function')\n    assert.equal(typeof commons._, 'object')\n  })\n\n  it('exposes lodash methods under _', () => {\n    assert.equal(typeof _.each, 'function')\n    assert.equal(typeof _.some, 'function')\n    assert.equal(typeof _.every, 'function')\n    assert.equal(typeof _.keys, 'function')\n    assert.equal(typeof _.values, 'function')\n    assert.equal(typeof _.isMatch, 'function')\n    assert.equal(typeof _.isEmpty, 'function')\n    assert.equal(typeof _.isObject, 'function')\n    assert.equal(typeof _.extend, 'function')\n    assert.equal(typeof _.omit, 'function')\n    assert.equal(typeof _.pick, 'function')\n    assert.equal(typeof _.merge, 'function')\n  })\n})\n"
  },
  {
    "path": "packages/commons/test/utils.test.ts",
    "content": "/* tslint:disable:no-unused-expression */\nimport { strict as assert } from 'assert'\nimport { _, stripSlashes, isPromise, createSymbol } from '../src'\n\ndescribe('@feathersjs/commons utils', () => {\n  it('stripSlashes', () => {\n    assert.equal(stripSlashes('some/thing'), 'some/thing')\n    assert.equal(stripSlashes('/some/thing'), 'some/thing')\n    assert.equal(stripSlashes('some/thing/'), 'some/thing')\n    assert.equal(stripSlashes('/some/thing/'), 'some/thing')\n    assert.equal(stripSlashes('//some/thing/'), 'some/thing')\n    assert.equal(stripSlashes('//some//thing////'), 'some//thing')\n  })\n\n  it('isPromise', () => {\n    assert.equal(isPromise(Promise.resolve()), true)\n    assert.ok(\n      isPromise({\n        then() {\n          return true\n        }\n      })\n    )\n    assert.equal(isPromise(null), false)\n  })\n\n  it('createSymbol', () => {\n    assert.equal(typeof createSymbol('a test'), 'symbol')\n  })\n\n  describe('_', () => {\n    it('isObject', () => {\n      assert.equal(_.isObject({}), true)\n      assert.equal(_.isObject([]), false)\n      assert.equal(_.isObject(null), false)\n    })\n\n    it('isObjectOrArray', () => {\n      assert.equal(_.isObjectOrArray({}), true)\n      assert.equal(_.isObjectOrArray([]), true)\n      assert.equal(_.isObjectOrArray(null), false)\n    })\n\n    it('each', () => {\n      _.each({ hi: 'there' }, (value, key) => {\n        assert.equal(key, 'hi')\n        assert.equal(value, 'there')\n      })\n\n      _.each(['hi'], (value, key) => {\n        assert.equal(key, 0)\n        assert.equal(value, 'hi')\n      })\n\n      _.each('moo', () => assert.fail('Should never get here'))\n    })\n\n    it('some', () => {\n      assert.ok(_.some(['a', 'b'], (current) => current === 'a'))\n      assert.ok(!_.some(['a', 'b'], (current) => current === 'c'))\n    })\n\n    it('every', () => {\n      assert.ok(_.every(['a', 'a'], (current) => current === 'a'))\n      assert.ok(!_.every(['a', 'b'], (current) => current === 'a'))\n    })\n\n    it('keys', () => {\n      const data = { hi: 'there', name: 'David' }\n      assert.deepEqual(_.keys(data), ['hi', 'name'])\n    })\n\n    it('values', () => {\n      const data = { hi: 'there', name: 'David' }\n      assert.deepEqual(_.values(data), ['there', 'David'])\n    })\n\n    it('isMatch', () => {\n      assert.ok(\n        _.isMatch(\n          {\n            test: 'me',\n            hi: 'you',\n            more: true\n          },\n          {\n            test: 'me',\n            hi: 'you'\n          }\n        )\n      )\n\n      assert.ok(\n        !_.isMatch(\n          {\n            test: 'me',\n            hi: 'you',\n            more: true\n          },\n          {\n            test: 'me',\n            hi: 'there'\n          }\n        )\n      )\n    })\n\n    it('isEmpty', () => {\n      assert.ok(_.isEmpty({}))\n      assert.ok(!_.isEmpty({ name: 'David' }))\n    })\n\n    it('extend', () => {\n      assert.deepEqual(_.extend({ hi: 'there' }, { name: 'david' }), {\n        hi: 'there',\n        name: 'david'\n      })\n    })\n\n    it('omit', () => {\n      assert.deepEqual(\n        _.omit(\n          {\n            name: 'David',\n            first: 1,\n            second: 2\n          },\n          'first',\n          'second'\n        ),\n        {\n          name: 'David'\n        }\n      )\n    })\n\n    it('pick', () => {\n      assert.deepEqual(\n        _.pick(\n          {\n            name: 'David',\n            first: 1,\n            second: 2\n          },\n          'first',\n          'second'\n        ),\n        {\n          first: 1,\n          second: 2\n        }\n      )\n\n      assert.deepEqual(\n        _.pick(\n          {\n            name: 'David',\n            first: 1\n          },\n          'first',\n          'second'\n        ),\n        {\n          first: 1\n        }\n      )\n    })\n\n    it('merge', () => {\n      assert.deepEqual(_.merge({ hi: 'there' }, { name: 'david' }), {\n        hi: 'there',\n        name: 'david'\n      })\n\n      assert.deepEqual(\n        _.merge(\n          {},\n          {\n            name: 'david',\n            nested: { obj: true }\n          }\n        ),\n        {\n          name: 'david',\n          nested: { obj: true }\n        }\n      )\n\n      assert.deepEqual(_.merge({ name: 'david' }, {}), {\n        name: 'david'\n      })\n\n      assert.deepEqual(\n        _.merge(\n          {\n            hi: 'there',\n            my: {\n              name: { is: 'david' },\n              number: { is: 1 }\n            }\n          },\n          { my: { name: { is: 'eric' } } }\n        ),\n        {\n          hi: 'there',\n          my: {\n            number: { is: 1 },\n            name: { is: 'eric' }\n          }\n        }\n      )\n\n      assert.equal(_.merge('hello', {}), 'hello')\n    })\n  })\n})\n"
  },
  {
    "path": "packages/commons/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/configuration/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n- **schema:** Make schemas validation library independent and add TypeBox support ([#2772](https://github.com/feathersjs/feathers/issues/2772)) ([44172d9](https://github.com/feathersjs/feathers/commit/44172d99b566d11d9ceda04f1d0bf72b6d05ce76))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **configuration:** Only validate the initial configuration against the schema ([#2622](https://github.com/feathersjs/feathers/issues/2622)) ([386c5e2](https://github.com/feathersjs/feathers/commit/386c5e2e67bfad4fb4333f2e3e17f7d7e09ac27e))\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n### Features\n\n- **configuration:** Allow app configuration to be validated against a schema ([#2590](https://github.com/feathersjs/feathers/issues/2590)) ([a268f86](https://github.com/feathersjs/feathers/commit/a268f86da92a8ada14ed11ab456aac0a4bba5bb0))\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- **koa:** Use extended query parser for compatibility ([#2397](https://github.com/feathersjs/feathers/issues/2397)) ([b2944ba](https://github.com/feathersjs/feathers/commit/b2944bac3ec6d5ecc80dc518cd4e58093692db74))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n### Features\n\n- **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n### Features\n\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### chore\n\n- **configuration:** Remove environment variable substitution ([#1942](https://github.com/feathersjs/feathers/issues/1942)) ([caaa21f](https://github.com/feathersjs/feathers/commit/caaa21ffdc6a8dcac82fb403c91d9d4b781a6c0a))\n\n### BREAKING CHANGES\n\n- **configuration:** Falls back to node-config instead of adding additional\n  functionality like path replacements and automatic environment variable insertion.\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### chore\n\n- **configuration:** Remove environment variable substitution ([#1942](https://github.com/feathersjs/feathers/issues/1942)) ([caaa21f](https://github.com/feathersjs/feathers/commit/caaa21ffdc6a8dcac82fb403c91d9d4b781a6c0a))\n\n### BREAKING CHANGES\n\n- **configuration:** Falls back to node-config instead of adding additional\n  functionality like path replacements and automatic environment variable insertion.\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n### Bug Fixes\n\n- **configuration:** Fix handling of config values that start with . or .. but are not actually relative paths; e.g. \".foo\" or \"..bar\" ([#2065](https://github.com/feathersjs/feathers/issues/2065)) ([d07bf59](https://github.com/feathersjs/feathers/commit/d07bf5902e9c8c606f16b9523472972d3d2e9b49))\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n### Bug Fixes\n\n- Small improvements in dependencies and code sturcture ([#1562](https://github.com/feathersjs/feathers/issues/1562)) ([42c13e2](https://github.com/feathersjs/feathers/commit/42c13e2))\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n- **package:** update config to version 3.0.0 ([#1100](https://github.com/feathersjs/feathers/issues/1100)) ([c9f4b42](https://github.com/feathersjs/feathers/commit/c9f4b42))\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- **package:** update debug to version 3.0.0 ([#45](https://github.com/feathersjs/feathers/issues/45)) ([2391434](https://github.com/feathersjs/feathers/commit/2391434))\n- **package:** update debug to version 3.0.1 ([#46](https://github.com/feathersjs/feathers/issues/46)) ([f8ada69](https://github.com/feathersjs/feathers/commit/f8ada69))\n\n### Features\n\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n\n## [2.0.6](https://github.com/feathersjs/feathers/compare/@feathersjs/configuration@2.0.5...@feathersjs/configuration@2.0.6) (2019-01-02)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n<a name=\"2.0.5\"></a>\n\n## [2.0.5](https://github.com/feathersjs/feathers/compare/@feathersjs/configuration@2.0.4...@feathersjs/configuration@2.0.5) (2018-12-16)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- **package:** update config to version 3.0.0 ([#1100](https://github.com/feathersjs/feathers/issues/1100)) ([c9f4b42](https://github.com/feathersjs/feathers/commit/c9f4b42))\n\n<a name=\"2.0.4\"></a>\n\n## [2.0.4](https://github.com/feathersjs/feathers/compare/@feathersjs/configuration@2.0.3...@feathersjs/configuration@2.0.4) (2018-09-21)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n<a name=\"2.0.3\"></a>\n\n## [2.0.3](https://github.com/feathersjs/feathers/compare/@feathersjs/configuration@2.0.2...@feathersjs/configuration@2.0.3) (2018-09-17)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n<a name=\"2.0.2\"></a>\n\n## [2.0.2](https://github.com/feathersjs/feathers/compare/@feathersjs/configuration@2.0.1...@feathersjs/configuration@2.0.2) (2018-09-02)\n\n**Note:** Version bump only for package @feathersjs/configuration\n\n<a name=\"2.0.1\"></a>\n\n## 2.0.1\n\n- Migrate to Monorepo ([feathers#462](https://github.com/feathersjs/feathers/issues/462))\n\n## [v2.0.0](https://github.com/feathersjs/configuration/tree/v2.0.0) (2018-07-30)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v1.0.2...v2.0.0)\n\n**Closed issues:**\n\n- Config adding a value of userName in runtime its overwritten to the OS name [\\#58](https://github.com/feathersjs/configuration/issues/58)\n- Configuration Management [\\#26](https://github.com/feathersjs/configuration/issues/26)\n\n**Merged pull requests:**\n\n- Update config to the latest version 🚀 [\\#59](https://github.com/feathersjs/configuration/pull/59) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- misspelling [\\#57](https://github.com/feathersjs/configuration/pull/57) ([chaintng](https://github.com/chaintng))\n- Update mocha to the latest version 🚀 [\\#56](https://github.com/feathersjs/configuration/pull/56) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.2](https://github.com/feathersjs/configuration/tree/v1.0.2) (2018-01-02)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v1.0.1...v1.0.2)\n\n**Merged pull requests:**\n\n- Remove example and update Readme to point directly to the Feathers docs [\\#55](https://github.com/feathersjs/configuration/pull/55) ([daffl](https://github.com/daffl))\n\n## [v1.0.1](https://github.com/feathersjs/configuration/tree/v1.0.1) (2017-11-16)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v1.0.0...v1.0.1)\n\n**Merged pull requests:**\n\n- Add default export for better ES module \\(TypeScript\\) compatibility [\\#53](https://github.com/feathersjs/configuration/pull/53) ([daffl](https://github.com/daffl))\n- Update nsp to the latest version 🚀 [\\#52](https://github.com/feathersjs/configuration/pull/52) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.0](https://github.com/feathersjs/configuration/tree/v1.0.0) (2017-11-01)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v1.0.0-pre.1...v1.0.0)\n\n## [v1.0.0-pre.1](https://github.com/feathersjs/configuration/tree/v1.0.0-pre.1) (2017-10-23)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.4.2...v1.0.0-pre.1)\n\n**Closed issues:**\n\n- Move config options to app.config instead of the Express app object. [\\#31](https://github.com/feathersjs/configuration/issues/31)\n\n**Merged pull requests:**\n\n- Update to new plugin infrastructure and npm scopes [\\#51](https://github.com/feathersjs/configuration/pull/51) ([daffl](https://github.com/daffl))\n\n## [v0.4.2](https://github.com/feathersjs/configuration/tree/v0.4.2) (2017-10-15)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.4.1...v0.4.2)\n\n**Closed issues:**\n\n- Missing TypeScript declaration file [\\#48](https://github.com/feathersjs/configuration/issues/48)\n- Feathers writing in typescript fails to boot on configuration [\\#47](https://github.com/feathersjs/configuration/issues/47)\n- Prevent automatic expansion of environment variables [\\#42](https://github.com/feathersjs/configuration/issues/42)\n- Getting Env name [\\#41](https://github.com/feathersjs/configuration/issues/41)\n- Nested configuration [\\#38](https://github.com/feathersjs/configuration/issues/38)\n- Stuck in configuration loophole... [\\#37](https://github.com/feathersjs/configuration/issues/37)\n- Docs are wrong [\\#36](https://github.com/feathersjs/configuration/issues/36)\n- Why use \"NODE_ENV=development\" with default.json? [\\#33](https://github.com/feathersjs/configuration/issues/33)\n\n**Merged pull requests:**\n\n- Create TypeScript definitions [\\#50](https://github.com/feathersjs/configuration/pull/50) ([jhanschoo](https://github.com/jhanschoo))\n- Update mocha to the latest version 🚀 [\\#49](https://github.com/feathersjs/configuration/pull/49) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update debug to the latest version 🚀 [\\#46](https://github.com/feathersjs/configuration/pull/46) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update debug to the latest version 🚀 [\\#45](https://github.com/feathersjs/configuration/pull/45) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Grammatical change [\\#44](https://github.com/feathersjs/configuration/pull/44) ([eugeniaguerrero](https://github.com/eugeniaguerrero))\n- More documentation on using and escaping environment variables [\\#43](https://github.com/feathersjs/configuration/pull/43) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#40](https://github.com/feathersjs/configuration/pull/40) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update dependencies to enable Greenkeeper 🌴 [\\#39](https://github.com/feathersjs/configuration/pull/39) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Fix first example [\\#35](https://github.com/feathersjs/configuration/pull/35) ([elfey](https://github.com/elfey))\n- 👻😱 Node.js 0.10 is unmaintained 😱👻 [\\#30](https://github.com/feathersjs/configuration/pull/30) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v0.4.1](https://github.com/feathersjs/configuration/tree/v0.4.1) (2016-10-24)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.4.0...v0.4.1)\n\n**Closed issues:**\n\n- Investigate node-config [\\#8](https://github.com/feathersjs/configuration/issues/8)\n\n**Merged pull requests:**\n\n- update readme [\\#29](https://github.com/feathersjs/configuration/pull/29) ([slajax](https://github.com/slajax))\n- jshint —\\> semistandard [\\#28](https://github.com/feathersjs/configuration/pull/28) ([corymsmith](https://github.com/corymsmith))\n\n## [v0.4.0](https://github.com/feathersjs/configuration/tree/v0.4.0) (2016-10-22)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.3.3...v0.4.0)\n\n**Implemented enhancements:**\n\n- implement node-config [\\#27](https://github.com/feathersjs/configuration/pull/27) ([slajax](https://github.com/slajax))\n\n**Closed issues:**\n\n- Deprecate v1 in favour of node-config [\\#25](https://github.com/feathersjs/configuration/issues/25)\n- Make this repo more about managing configuration [\\#24](https://github.com/feathersjs/configuration/issues/24)\n\n## [v0.3.3](https://github.com/feathersjs/configuration/tree/v0.3.3) (2016-09-12)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.3.2...v0.3.3)\n\n## [v0.3.2](https://github.com/feathersjs/configuration/tree/v0.3.2) (2016-09-12)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.3.1...v0.3.2)\n\n**Closed issues:**\n\n- A way to have local override [\\#20](https://github.com/feathersjs/configuration/issues/20)\n\n**Merged pull requests:**\n\n- Remove check for development mode [\\#21](https://github.com/feathersjs/configuration/pull/21) ([daffl](https://github.com/daffl))\n\n## [v0.3.1](https://github.com/feathersjs/configuration/tree/v0.3.1) (2016-08-15)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.3.0...v0.3.1)\n\n**Merged pull requests:**\n\n- Support `null` values [\\#19](https://github.com/feathersjs/configuration/pull/19) ([KenanY](https://github.com/KenanY))\n- Update mocha to version 3.0.0 🚀 [\\#18](https://github.com/feathersjs/configuration/pull/18) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v0.3.0](https://github.com/feathersjs/configuration/tree/v0.3.0) (2016-05-22)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.2.3...v0.3.0)\n\n**Closed issues:**\n\n- \\<NODE_ENV\\>.json config need deep merge options [\\#16](https://github.com/feathersjs/configuration/issues/16)\n\n**Merged pull requests:**\n\n- Add functionality for deeply extending configuration [\\#17](https://github.com/feathersjs/configuration/pull/17) ([daffl](https://github.com/daffl))\n\n## [v0.2.3](https://github.com/feathersjs/configuration/tree/v0.2.3) (2016-04-24)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.2.2...v0.2.3)\n\n**Closed issues:**\n\n- PR: Support modules in config [\\#12](https://github.com/feathersjs/configuration/issues/12)\n\n**Merged pull requests:**\n\n- Support modules as configuration files. [\\#13](https://github.com/feathersjs/configuration/pull/13) ([wkw](https://github.com/wkw))\n- Update all dependencies 🌴 [\\#10](https://github.com/feathersjs/configuration/pull/10) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v0.2.2](https://github.com/feathersjs/configuration/tree/v0.2.2) (2016-03-27)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.2.1...v0.2.2)\n\n**Merged pull requests:**\n\n- Expanding environment variables in \\<env\\>.json [\\#9](https://github.com/feathersjs/configuration/pull/9) ([derek-watson](https://github.com/derek-watson))\n\n## [v0.2.1](https://github.com/feathersjs/configuration/tree/v0.2.1) (2016-03-12)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.2.0...v0.2.1)\n\n**Merged pull requests:**\n\n- Makes sure that arrays get converted properly [\\#7](https://github.com/feathersjs/configuration/pull/7) ([daffl](https://github.com/daffl))\n\n## [v0.2.0](https://github.com/feathersjs/configuration/tree/v0.2.0) (2016-03-09)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.1.1...v0.2.0)\n\n**Closed issues:**\n\n- Needs an escape character [\\#4](https://github.com/feathersjs/configuration/issues/4)\n\n**Merged pull requests:**\n\n- Implement an escape character [\\#6](https://github.com/feathersjs/configuration/pull/6) ([daffl](https://github.com/daffl))\n\n## [v0.1.1](https://github.com/feathersjs/configuration/tree/v0.1.1) (2016-03-09)\n\n[Full Changelog](https://github.com/feathersjs/configuration/compare/v0.1.0...v0.1.1)\n\n**Closed issues:**\n\n- Configuration should recursively go through the values [\\#2](https://github.com/feathersjs/configuration/issues/2)\n\n**Merged pull requests:**\n\n- Replace slashes in paths with the separator [\\#5](https://github.com/feathersjs/configuration/pull/5) ([daffl](https://github.com/daffl))\n- Allow to convert deeply nested environment variables [\\#3](https://github.com/feathersjs/configuration/pull/3) ([daffl](https://github.com/daffl))\n- Adding nsp check [\\#1](https://github.com/feathersjs/configuration/pull/1) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.1.0](https://github.com/feathersjs/configuration/tree/v0.1.0) (2015-11-14)\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/configuration/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/configuration/README.md",
    "content": "# @feathersjs/configuration\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/configuration.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/configuration)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> A small configuration module for your Feathers application.\n\n## Installation\n\n```\nnpm install @feathersjs/configuration --save\n```\n\n## Documentation\n\nRefer to the [Feathers configuration API documentation](https://feathersjs.com/api/configuration.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/configuration/package.json",
    "content": "{\n  \"name\": \"@feathersjs/configuration\",\n  \"description\": \"A small configuration module for your Feathers application.\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/configuration\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"NODE_CONFIG_DIR=./test/config mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"semistandard\": {\n    \"env\": [\n      \"mocha\"\n    ]\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@feathersjs/schema\": \"^5.0.42\",\n    \"@types/config\": \"^3.3.5\",\n    \"config\": \"^4.4.1\"\n  },\n  \"devDependencies\": {\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/configuration/src/index.ts",
    "content": "import { Application, ApplicationHookContext, NextFunction } from '@feathersjs/feathers'\nimport { createDebug } from '@feathersjs/commons'\nimport { Schema, Validator } from '@feathersjs/schema'\nimport config from 'config'\n\nconst debug = createDebug('@feathersjs/configuration')\n\nexport = function init(schema?: Schema<any> | Validator): (app?: Application) => Record<string, any> {\n  const validator: Validator = typeof schema === 'function' ? schema : schema?.validate.bind(schema)\n\n  return (app?: Application) => {\n    if (!app) {\n      return config\n    }\n\n    const configuration: { [key: string]: unknown } = { ...config }\n\n    debug(`Initializing configuration for ${config.util.getEnv('NODE_ENV')} environment`)\n\n    Object.keys(configuration).forEach((name) => {\n      const value = configuration[name]\n      debug(`Setting ${name} configuration value to`, value)\n      app.set(name, value)\n    })\n\n    if (validator) {\n      app.hooks({\n        setup: [\n          async (_context: ApplicationHookContext, next: NextFunction) => {\n            await validator(configuration)\n            await next()\n          }\n        ]\n      })\n    }\n\n    return config\n  }\n}\n"
  },
  {
    "path": "packages/configuration/test/config/default.json",
    "content": "{\n  \"port\": 3030,\n  \"array\": [\"one\", \"two\", \"three\"],\n  \"deep\": { \"base\": false },\n  \"nullish\": null\n}\n"
  },
  {
    "path": "packages/configuration/test/index.test.ts",
    "content": "import { strict as assert } from 'assert'\nimport { feathers, Application } from '@feathersjs/feathers'\nimport { Ajv, schema } from '@feathersjs/schema'\nimport configuration from '../src'\n\ndescribe('@feathersjs/configuration', () => {\n  const app: Application = feathers().configure(configuration())\n\n  it('initialized app with default.json', () => {\n    assert.equal(app.get('port'), 3030)\n    assert.deepEqual(app.get('array'), ['one', 'two', 'three'])\n    assert.deepEqual(app.get('deep'), { base: false })\n    assert.deepEqual(app.get('nullish'), null)\n  })\n\n  it('works when called directly', () => {\n    const fn = configuration()\n    const conf = fn() as any\n\n    assert.strictEqual(conf.port, 3030)\n  })\n\n  it('errors on .setup when a schema is passed and the configuration is invalid', async () => {\n    const configurationSchema = schema(\n      {\n        $id: 'ConfigurationSchema',\n        additionalProperties: false,\n        type: 'object',\n        properties: {\n          port: { type: 'number' },\n          deep: {\n            type: 'object',\n            properties: {\n              base: {\n                type: 'boolean'\n              }\n            }\n          },\n          array: {\n            type: 'array',\n            items: { type: 'string' }\n          },\n          nullish: {\n            type: 'string'\n          }\n        }\n      } as const,\n      new Ajv()\n    )\n\n    const schemaApp = feathers().configure(configuration(configurationSchema))\n\n    await assert.rejects(() => schemaApp.setup(), {\n      data: [\n        {\n          instancePath: '/nullish',\n          keyword: 'type',\n          message: 'must be string',\n          params: {\n            type: 'string'\n          },\n          schemaPath: '#/properties/nullish/type'\n        }\n      ]\n    })\n  })\n})\n"
  },
  {
    "path": "packages/configuration/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/create-feathers/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n### Bug Fixes\n\n- **cli:** Add JS extension to binaries ([#3398](https://github.com/feathersjs/feathers/issues/3398)) ([aaf181d](https://github.com/feathersjs/feathers/commit/aaf181d924d0cb67c7792a54197082c59109264d))\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n### Bug Fixes\n\n- Update npm create feathers to ES module ([#3393](https://github.com/feathersjs/feathers/issues/3393)) ([314ce70](https://github.com/feathersjs/feathers/commit/314ce707332eadbea4505e5e7560397632da6205))\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.2](https://github.com/feathersjs/feathers/compare/v5.0.1...v5.0.2) (2023-03-23)\n\n**Note:** Version bump only for package create-feathers\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package create-feathers\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package create-feathers\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n### Features\n\n- **generators:** Final tweaks to the generators ([#3060](https://github.com/feathersjs/feathers/issues/3060)) ([1bf1544](https://github.com/feathersjs/feathers/commit/1bf1544fa8deeaa44ba354fb539dc3f1fd187767))\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package create-feathers\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n**Note:** Version bump only for package create-feathers\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n**Note:** Version bump only for package create-feathers\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n**Note:** Version bump only for package create-feathers\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package create-feathers\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package create-feathers\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package create-feathers\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **cli:** Add ability to `npm init feathers` ([#2755](https://github.com/feathersjs/feathers/issues/2755)) ([d734931](https://github.com/feathersjs/feathers/commit/d734931ffd4f983a05d9e771ce0e43b696c2bc0e))\n"
  },
  {
    "path": "packages/create-feathers/README.md",
    "content": "# create-feathers\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/configuration.svg?style=flat-square)](https://www.npmjs.com/package/create-feathers)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Generate a Feathers application through the CLI\n\n## Usage\n\n```\nnpm create feathers my-app\n```\n\n## Documentation\n\nRefer to the [Feathers guides](https://feathersjs.com/guides/) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/create-feathers/bin/create-feathers.js",
    "content": "#!/usr/bin/env node\n'use strict';\n\nimport path from 'path'\nimport { existsSync } from 'fs'\nimport { mkdir } from 'fs/promises'\nimport { Command, commandRunner, chalk } from '@feathersjs/cli'\n\nconst program = new Command()\nconst generateApp = commandRunner('app')\n\nprogram\n  .name('npm init feathers')\n  .description(`Create a new Feathers application 🕊️\n\n${chalk.grey('npm init feathers myapp')}\n`)\n  .argument('<name>', 'The name of your new application')\n  // .version(version)\n  .showHelpAfterError()\n  .action(async (name, options) => {\n    try {\n      const cwd = path.join(process.cwd(), name)\n\n      if (existsSync(cwd)) {\n        throw new Error(`Can not create Feathers application, the folder \"${name}\" already exists`)\n      }\n\n      await mkdir(cwd)\n\n      await generateApp({\n        name,\n        cwd,\n        ...options\n      })\n\n      console.log(`\n\n${chalk.green('Hooray')}! Your Feathers app is ready to go! 🚀\nGo to the ${chalk.grey(name)} folder to get started.\n\nTo learn more visit ${chalk.grey('https://feathersjs.com/guides')}\n`)\n    } catch (error) {\n      console.error(`${chalk.red('Error')}: ${error.message}`)\n      process.exit(1)\n    }\n  })\n\nprogram.parse()\n"
  },
  {
    "path": "packages/create-feathers/package.json",
    "content": "{\n  \"name\": \"create-feathers\",\n  \"description\": \"Create a new Feathers application\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"bin\": {\n    \"create-feathers\": \"./bin/create-feathers.js\"\n  },\n  \"type\": \"module\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 18\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"lib/**\",\n    \"bin/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"test\": \"bin/create-feathers.js --help\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/cli\": \"^5.0.42\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/errors/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n### Bug Fixes\n\n- **errors:** Allows to pass no error message ([#2794](https://github.com/feathersjs/feathers/issues/2794)) ([f3ddab6](https://github.com/feathersjs/feathers/commit/f3ddab637e269e67e852ffce07b060bab2b085c0))\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Bug Fixes\n\n- **errors:** Format package.json with spaces ([cbd31c1](https://github.com/feathersjs/feathers/commit/cbd31c10c2c574de63d6ca5e55dbfb73a5fdd758))\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Bug Fixes\n\n- **errors:** Format package.json with spaces ([cbd31c1](https://github.com/feathersjs/feathers/commit/cbd31c10c2c574de63d6ca5e55dbfb73a5fdd758))\n- **typescript:** Fix `data` property definition in @feathersjs/errors ([#2018](https://github.com/feathersjs/feathers/issues/2018)) ([ef1398c](https://github.com/feathersjs/feathers/commit/ef1398cd5b19efa50929e8c9511ca5684a18997f))\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n### Bug Fixes\n\n- **errors:** Add 410 Gone to errors ([#1849](https://github.com/feathersjs/feathers/issues/1849)) ([6801428](https://github.com/feathersjs/feathers/commit/6801428f8fd17dbfebcdb6f1b0cd01433a4033dc))\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n### Bug Fixes\n\n- Small type improvements ([#1624](https://github.com/feathersjs/feathers/issues/1624)) ([50162c6](https://github.com/feathersjs/feathers/commit/50162c6e562f0a47c6a280c4f01fff7c3afee293))\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n### Bug Fixes\n\n- Use `export =` in TypeScript definitions ([#1285](https://github.com/feathersjs/feathers/issues/1285)) ([12d0f4b](https://github.com/feathersjs/feathers/commit/12d0f4b))\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n### Bug Fixes\n\n- Do not log as errors below a 500 response ([#1256](https://github.com/feathersjs/feathers/issues/1256)) ([33fd0e4](https://github.com/feathersjs/feathers/commit/33fd0e4))\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Update 401.html ([#983](https://github.com/feathersjs/feathers/issues/983)) ([cec6bae](https://github.com/feathersjs/feathers/commit/cec6bae))\n- Update 404.html ([#984](https://github.com/feathersjs/feathers/issues/984)) ([72132d1](https://github.com/feathersjs/feathers/commit/72132d1))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n- **compile-task:** on windows machine ([#60](https://github.com/feathersjs/feathers/issues/60)) ([617e0a4](https://github.com/feathersjs/feathers/commit/617e0a4))\n- **package:** update debug to version 3.0.0 ([#86](https://github.com/feathersjs/feathers/issues/86)) ([fd1bb6b](https://github.com/feathersjs/feathers/commit/fd1bb6b))\n\n### Features\n\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Authentication v3 core server implementation ([#1205](https://github.com/feathersjs/feathers/issues/1205)) ([1bd7591](https://github.com/feathersjs/feathers/commit/1bd7591))\n\n## [3.3.6](https://github.com/feathersjs/feathers/compare/@feathersjs/errors@3.3.5...@feathersjs/errors@3.3.6) (2019-01-02)\n\n### Bug Fixes\n\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n\n<a name=\"3.3.5\"></a>\n\n## [3.3.5](https://github.com/feathersjs/feathers/compare/@feathersjs/errors@3.3.4...@feathersjs/errors@3.3.5) (2018-12-16)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n\n<a name=\"3.3.4\"></a>\n\n## [3.3.4](https://github.com/feathersjs/feathers/compare/@feathersjs/errors@3.3.3...@feathersjs/errors@3.3.4) (2018-09-21)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n<a name=\"3.3.3\"></a>\n\n## [3.3.3](https://github.com/feathersjs/feathers/compare/@feathersjs/errors@3.3.2...@feathersjs/errors@3.3.3) (2018-09-17)\n\n### Bug Fixes\n\n- Update 401.html ([#983](https://github.com/feathersjs/feathers/issues/983)) ([cec6bae](https://github.com/feathersjs/feathers/commit/cec6bae))\n- Update 404.html ([#984](https://github.com/feathersjs/feathers/issues/984)) ([72132d1](https://github.com/feathersjs/feathers/commit/72132d1))\n\n<a name=\"3.3.2\"></a>\n\n## [3.3.2](https://github.com/feathersjs/feathers/compare/@feathersjs/errors@3.3.1...@feathersjs/errors@3.3.2) (2018-09-02)\n\n**Note:** Version bump only for package @feathersjs/errors\n\n<a name=\"3.3.1\"></a>\n\n## 3.3.1\n\n- Migrate to Monorepo ([feathers#462](https://github.com/feathersjs/feathers/issues/462))\n\n## [v3.3.0](https://github.com/feathersjs/errors/tree/v3.3.0) (2018-02-12)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v3.2.2...v3.3.0)\n\n**Closed issues:**\n\n- How to handling error from Hook function when I use Aync/Await in Hook function [\\#106](https://github.com/feathersjs/errors/issues/106)\n\n**Merged pull requests:**\n\n- Add a verbose flag to notFound handler [\\#107](https://github.com/feathersjs/errors/pull/107) ([daffl](https://github.com/daffl))\n- Add req.url to notFound handler message [\\#105](https://github.com/feathersjs/errors/pull/105) ([FreeLineTM](https://github.com/FreeLineTM))\n\n## [v3.2.2](https://github.com/feathersjs/errors/tree/v3.2.2) (2018-01-23)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v3.2.1...v3.2.2)\n\n**Closed issues:**\n\n- Handling Status Codes [\\#103](https://github.com/feathersjs/errors/issues/103)\n- Override default error page [\\#102](https://github.com/feathersjs/errors/issues/102)\n- wrong npm package in Installation instructions [\\#100](https://github.com/feathersjs/errors/issues/100)\n\n**Merged pull requests:**\n\n- Fix instanceof and prototypical inheritance [\\#104](https://github.com/feathersjs/errors/pull/104) ([nikaspran](https://github.com/nikaspran))\n- Update mocha to the latest version 🚀 [\\#101](https://github.com/feathersjs/errors/pull/101) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- fix installation declaration [\\#99](https://github.com/feathersjs/errors/pull/99) ([jasonmacgowan](https://github.com/jasonmacgowan))\n\n## [v3.2.1](https://github.com/feathersjs/errors/tree/v3.2.1) (2018-01-03)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v3.2.0...v3.2.1)\n\n**Closed issues:**\n\n- Error handler usage/setup is mis-documented [\\#96](https://github.com/feathersjs/errors/issues/96)\n\n**Merged pull requests:**\n\n- Update readme to correspond with latest release [\\#98](https://github.com/feathersjs/errors/pull/98) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#97](https://github.com/feathersjs/errors/pull/97) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.2.0](https://github.com/feathersjs/errors/tree/v3.2.0) (2017-11-19)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v3.1.0...v3.2.0)\n\n**Merged pull requests:**\n\n- Allow ability to log middleware errors [\\#95](https://github.com/feathersjs/errors/pull/95) ([daffl](https://github.com/daffl))\n\n## [v3.1.0](https://github.com/feathersjs/errors/tree/v3.1.0) (2017-11-18)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v3.0.0...v3.1.0)\n\n**Closed issues:**\n\n- feature: allow for mixed files/functions for error-handler options [\\#91](https://github.com/feathersjs/errors/issues/91)\n\n**Merged pull requests:**\n\n- 91 allow mixed config [\\#94](https://github.com/feathersjs/errors/pull/94) ([DesignByOnyx](https://github.com/DesignByOnyx))\n\n## [v3.0.0](https://github.com/feathersjs/errors/tree/v3.0.0) (2017-11-01)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v3.0.0-pre.1...v3.0.0)\n\n**Merged pull requests:**\n\n- Update to Buzzard infrastructure [\\#93](https://github.com/feathersjs/errors/pull/93) ([daffl](https://github.com/daffl))\n\n## [v3.0.0-pre.1](https://github.com/feathersjs/errors/tree/v3.0.0-pre.1) (2017-10-21)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.9.2...v3.0.0-pre.1)\n\n**Closed issues:**\n\n- \\[Proposal\\] use verror [\\#88](https://github.com/feathersjs/errors/issues/88)\n\n**Merged pull requests:**\n\n- Update to new plugin infrastructure and npm scope [\\#92](https://github.com/feathersjs/errors/pull/92) ([daffl](https://github.com/daffl))\n- Update mocha to the latest version 🚀 [\\#90](https://github.com/feathersjs/errors/pull/90) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update sinon to the latest version 🚀 [\\#89](https://github.com/feathersjs/errors/pull/89) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.9.2](https://github.com/feathersjs/errors/tree/v2.9.2) (2017-09-05)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.9.1...v2.9.2)\n\n**Closed issues:**\n\n- Getting 500 status code when attempting to throw non 500 style errors \\(401\\) [\\#85](https://github.com/feathersjs/errors/issues/85)\n\n**Merged pull requests:**\n\n- fix typings [\\#87](https://github.com/feathersjs/errors/pull/87) ([j2L4e](https://github.com/j2L4e))\n- Update debug to the latest version 🚀 [\\#86](https://github.com/feathersjs/errors/pull/86) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update sinon to the latest version 🚀 [\\#84](https://github.com/feathersjs/errors/pull/84) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.9.1](https://github.com/feathersjs/errors/tree/v2.9.1) (2017-07-21)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.9.0...v2.9.1)\n\n**Merged pull requests:**\n\n- Add back default error message [\\#83](https://github.com/feathersjs/errors/pull/83) ([daffl](https://github.com/daffl))\n\n## [v2.9.0](https://github.com/feathersjs/errors/tree/v2.9.0) (2017-07-20)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.8.2...v2.9.0)\n\n**Closed issues:**\n\n- Wrong stack for errors [\\#78](https://github.com/feathersjs/errors/issues/78)\n\n**Merged pull requests:**\n\n- Capture proper stack trace and error messages [\\#82](https://github.com/feathersjs/errors/pull/82) ([daffl](https://github.com/daffl))\n- Update chai to the latest version 🚀 [\\#81](https://github.com/feathersjs/errors/pull/81) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.8.2](https://github.com/feathersjs/errors/tree/v2.8.2) (2017-07-05)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.8.1...v2.8.2)\n\n**Merged pull requests:**\n\n- Fix wildcard import on ES2015+ [\\#80](https://github.com/feathersjs/errors/pull/80) ([coreh](https://github.com/coreh))\n- Add more information to error debug [\\#79](https://github.com/feathersjs/errors/pull/79) ([kamzil](https://github.com/kamzil))\n\n## [v2.8.1](https://github.com/feathersjs/errors/tree/v2.8.1) (2017-05-30)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.8.0...v2.8.1)\n\n**Merged pull requests:**\n\n- Fix errors property being lost when cloning [\\#76](https://github.com/feathersjs/errors/pull/76) ([0x6431346e](https://github.com/0x6431346e))\n\n## [v2.8.0](https://github.com/feathersjs/errors/tree/v2.8.0) (2017-05-08)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.7.1...v2.8.0)\n\n**Closed issues:**\n\n- Support array objects as data [\\#64](https://github.com/feathersjs/errors/issues/64)\n\n**Merged pull requests:**\n\n- Allow data to be an array [\\#75](https://github.com/feathersjs/errors/pull/75) ([0x6431346e](https://github.com/0x6431346e))\n\n## [v2.7.1](https://github.com/feathersjs/errors/tree/v2.7.1) (2017-04-28)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.7.0...v2.7.1)\n\n**Closed issues:**\n\n- Object.setPrototypeOf in IE 10 [\\#70](https://github.com/feathersjs/errors/issues/70)\n\n**Merged pull requests:**\n\n- Define property toJSON because just assigning it throws an error in N… [\\#74](https://github.com/feathersjs/errors/pull/74) ([daffl](https://github.com/daffl))\n\n## [v2.7.0](https://github.com/feathersjs/errors/tree/v2.7.0) (2017-04-25)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.6.3...v2.7.0)\n\n**Merged pull requests:**\n\n- Change back to old Error inheritance [\\#73](https://github.com/feathersjs/errors/pull/73) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#72](https://github.com/feathersjs/errors/pull/72) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update dependencies to enable Greenkeeper 🌴 [\\#71](https://github.com/feathersjs/errors/pull/71) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.6.3](https://github.com/feathersjs/errors/tree/v2.6.3) (2017-04-08)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.6.2...v2.6.3)\n\n**Closed issues:**\n\n- Make options the same as res.format [\\#37](https://github.com/feathersjs/errors/issues/37)\n\n**Merged pull requests:**\n\n- fix typescript definitions with noImplicitAny [\\#69](https://github.com/feathersjs/errors/pull/69) ([JVirant](https://github.com/JVirant))\n\n## [v2.6.2](https://github.com/feathersjs/errors/tree/v2.6.2) (2017-03-16)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.6.1...v2.6.2)\n\n**Closed issues:**\n\n- Create a TokenExpired error type [\\#53](https://github.com/feathersjs/errors/issues/53)\n\n**Merged pull requests:**\n\n- Fix declarations for index.d.ts [\\#66](https://github.com/feathersjs/errors/pull/66) ([ghost](https://github.com/ghost))\n\n## [v2.6.1](https://github.com/feathersjs/errors/tree/v2.6.1) (2017-03-06)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.6.0...v2.6.1)\n\n**Merged pull requests:**\n\n- fix pull request \\#62 [\\#63](https://github.com/feathersjs/errors/pull/63) ([superbarne](https://github.com/superbarne))\n\n## [v2.6.0](https://github.com/feathersjs/errors/tree/v2.6.0) (2017-03-04)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.5.0...v2.6.0)\n\n**Closed issues:**\n\n- Full Validation Error Object not passed to client promise [\\#61](https://github.com/feathersjs/errors/issues/61)\n- More HTTP Statuses [\\#48](https://github.com/feathersjs/errors/issues/48)\n\n**Merged pull requests:**\n\n- add typescript definitions [\\#62](https://github.com/feathersjs/errors/pull/62) ([superbarne](https://github.com/superbarne))\n- Fix compile npm task on Windows [\\#60](https://github.com/feathersjs/errors/pull/60) ([AbraaoAlves](https://github.com/AbraaoAlves))\n\n## [v2.5.0](https://github.com/feathersjs/errors/tree/v2.5.0) (2016-11-04)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.4.0...v2.5.0)\n\n**Closed issues:**\n\n- Possible issue with Node 4 [\\#51](https://github.com/feathersjs/errors/issues/51)\n- Consider using restify/errors as base [\\#31](https://github.com/feathersjs/errors/issues/31)\n\n**Merged pull requests:**\n\n- Adding more error types [\\#55](https://github.com/feathersjs/errors/pull/55) ([franciscofsales](https://github.com/franciscofsales))\n- 👻😱 Node.js 0.10 is unmaintained 😱👻 [\\#54](https://github.com/feathersjs/errors/pull/54) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- jshint —\\> semistandard [\\#52](https://github.com/feathersjs/errors/pull/52) ([corymsmith](https://github.com/corymsmith))\n- Update mocha to version 3.0.0 🚀 [\\#47](https://github.com/feathersjs/errors/pull/47) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v2.4.0](https://github.com/feathersjs/errors/tree/v2.4.0) (2016-07-17)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.3.0...v2.4.0)\n\n**Merged pull requests:**\n\n- adding ability to get a feathers error by http status code [\\#46](https://github.com/feathersjs/errors/pull/46) ([ekryski](https://github.com/ekryski))\n\n## [v2.3.0](https://github.com/feathersjs/errors/tree/v2.3.0) (2016-07-10)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.2.0...v2.3.0)\n\n**Closed issues:**\n\n- Heroku error Reflect.construct [\\#44](https://github.com/feathersjs/errors/issues/44)\n\n**Merged pull requests:**\n\n- Not found [\\#45](https://github.com/feathersjs/errors/pull/45) ([ekryski](https://github.com/ekryski))\n\n## [v2.2.0](https://github.com/feathersjs/errors/tree/v2.2.0) (2016-05-27)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.1.0...v2.2.0)\n\n**Closed issues:**\n\n- Can not format error to json [\\#35](https://github.com/feathersjs/errors/issues/35)\n\n**Merged pull requests:**\n\n- Add an error conversion method [\\#43](https://github.com/feathersjs/errors/pull/43) ([daffl](https://github.com/daffl))\n- mocha@2.5.0 breaks build 🚨 [\\#42](https://github.com/feathersjs/errors/pull/42) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update babel-plugin-add-module-exports to version 0.2.0 🚀 [\\#41](https://github.com/feathersjs/errors/pull/41) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v2.1.0](https://github.com/feathersjs/errors/tree/v2.1.0) (2016-04-03)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.0.2...v2.1.0)\n\n**Closed issues:**\n\n- Support passing a custom html format function [\\#32](https://github.com/feathersjs/errors/issues/32)\n\n**Merged pull requests:**\n\n- Custom handlers [\\#36](https://github.com/feathersjs/errors/pull/36) ([ekryski](https://github.com/ekryski))\n- Update all dependencies 🌴 [\\#34](https://github.com/feathersjs/errors/pull/34) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v2.0.2](https://github.com/feathersjs/errors/tree/v2.0.2) (2016-03-23)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.0.1...v2.0.2)\n\n**Closed issues:**\n\n- ReferenceError: Reflect is not defined [\\#29](https://github.com/feathersjs/errors/issues/29)\n- Make error pages opt-in [\\#24](https://github.com/feathersjs/errors/issues/24)\n\n**Merged pull requests:**\n\n- Update package.json [\\#33](https://github.com/feathersjs/errors/pull/33) ([marshallswain](https://github.com/marshallswain))\n- Fixed typo [\\#30](https://github.com/feathersjs/errors/pull/30) ([kulakowka](https://github.com/kulakowka))\n\n## [v2.0.1](https://github.com/feathersjs/errors/tree/v2.0.1) (2016-02-24)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v2.0.0...v2.0.1)\n\n**Closed issues:**\n\n- Error handler is wrapping errors as GeneralErrors [\\#27](https://github.com/feathersjs/errors/issues/27)\n\n**Merged pull requests:**\n\n- adding an explicit error type [\\#28](https://github.com/feathersjs/errors/pull/28) ([ekryski](https://github.com/ekryski))\n\n## [v2.0.0](https://github.com/feathersjs/errors/tree/v2.0.0) (2016-02-24)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.2.4...v2.0.0)\n\n**Merged pull requests:**\n\n- move error handler out of index [\\#26](https://github.com/feathersjs/errors/pull/26) ([ekryski](https://github.com/ekryski))\n\n## [v1.2.4](https://github.com/feathersjs/errors/tree/v1.2.4) (2016-02-24)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.2.3...v1.2.4)\n\n## [v1.2.3](https://github.com/feathersjs/errors/tree/v1.2.3) (2016-02-21)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.2.2...v1.2.3)\n\n**Merged pull requests:**\n\n- Adding default error page and make HTML formatting optional [\\#25](https://github.com/feathersjs/errors/pull/25) ([daffl](https://github.com/daffl))\n\n## [v1.2.2](https://github.com/feathersjs/errors/tree/v1.2.2) (2016-02-18)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.2.1...v1.2.2)\n\n**Closed issues:**\n\n- Add error handler back [\\#21](https://github.com/feathersjs/errors/issues/21)\n\n**Merged pull requests:**\n\n- Make fully CommonJS compatible and add error middleware tests [\\#23](https://github.com/feathersjs/errors/pull/23) ([daffl](https://github.com/daffl))\n\n## [v1.2.1](https://github.com/feathersjs/errors/tree/v1.2.1) (2016-02-16)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.2.0...v1.2.1)\n\n## [v1.2.0](https://github.com/feathersjs/errors/tree/v1.2.0) (2016-02-15)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.1.6...v1.2.0)\n\n**Closed issues:**\n\n- Check to make sure that errors propagate via web sockets [\\#1](https://github.com/feathersjs/errors/issues/1)\n\n**Merged pull requests:**\n\n- adding error handler back [\\#22](https://github.com/feathersjs/errors/pull/22) ([ekryski](https://github.com/ekryski))\n\n## [v1.1.6](https://github.com/feathersjs/errors/tree/v1.1.6) (2016-01-12)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.1.5...v1.1.6)\n\n**Closed issues:**\n\n- stacktraces are incorrect when used in an ES6 app [\\#20](https://github.com/feathersjs/errors/issues/20)\n- We shouldn't mutate the error object passed in. [\\#19](https://github.com/feathersjs/errors/issues/19)\n- only one instance of babel-polyfill is allowed [\\#17](https://github.com/feathersjs/errors/issues/17)\n\n## [v1.1.5](https://github.com/feathersjs/errors/tree/v1.1.5) (2015-12-18)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.1.4...v1.1.5)\n\n## [v1.1.4](https://github.com/feathersjs/errors/tree/v1.1.4) (2015-12-15)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.1.3...v1.1.4)\n\n**Closed issues:**\n\n- no method 'setPrototypeOf' in Node 0.10 [\\#16](https://github.com/feathersjs/errors/issues/16)\n\n## [v1.1.3](https://github.com/feathersjs/errors/tree/v1.1.3) (2015-12-15)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.1.2...v1.1.3)\n\n## [v1.1.2](https://github.com/feathersjs/errors/tree/v1.1.2) (2015-12-15)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.1.1...v1.1.2)\n\n**Closed issues:**\n\n- Passing errors as second argument [\\#9](https://github.com/feathersjs/errors/issues/9)\n\n## [v1.1.1](https://github.com/feathersjs/errors/tree/v1.1.1) (2015-12-14)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.1.0...v1.1.1)\n\n**Closed issues:**\n\n- Subclassing Errors using babel don't behave as expected [\\#14](https://github.com/feathersjs/errors/issues/14)\n\n**Merged pull requests:**\n\n- Es6 class fix [\\#15](https://github.com/feathersjs/errors/pull/15) ([ekryski](https://github.com/ekryski))\n\n## [v1.1.0](https://github.com/feathersjs/errors/tree/v1.1.0) (2015-12-12)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v1.0.0...v1.1.0)\n\n## [v1.0.0](https://github.com/feathersjs/errors/tree/v1.0.0) (2015-12-12)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.2.5...v1.0.0)\n\n**Closed issues:**\n\n- Convert to ES6 [\\#12](https://github.com/feathersjs/errors/issues/12)\n- Drop the error handlers: Breaking Change [\\#11](https://github.com/feathersjs/errors/issues/11)\n- Remove Lodash dependency [\\#10](https://github.com/feathersjs/errors/issues/10)\n- Logging only unhandled errors [\\#8](https://github.com/feathersjs/errors/issues/8)\n\n**Merged pull requests:**\n\n- complete rewrite. Closes \\#11 and \\#12. [\\#13](https://github.com/feathersjs/errors/pull/13) ([ekryski](https://github.com/ekryski))\n\n## [0.2.5](https://github.com/feathersjs/errors/tree/0.2.5) (2015-02-05)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.2.4...0.2.5)\n\n## [0.2.4](https://github.com/feathersjs/errors/tree/0.2.4) (2015-02-05)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.2.3...0.2.4)\n\n## [0.2.3](https://github.com/feathersjs/errors/tree/0.2.3) (2015-01-29)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.2.2...0.2.3)\n\n## [0.2.2](https://github.com/feathersjs/errors/tree/0.2.2) (2015-01-29)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.2.1...0.2.2)\n\n## [0.2.1](https://github.com/feathersjs/errors/tree/0.2.1) (2014-09-03)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.2.0...0.2.1)\n\n## [0.2.0](https://github.com/feathersjs/errors/tree/0.2.0) (2014-07-17)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.1.7...0.2.0)\n\n**Implemented enhancements:**\n\n- Handle error objects with an 'errors' object [\\#5](https://github.com/feathersjs/errors/issues/5)\n\n## [0.1.7](https://github.com/feathersjs/errors/tree/0.1.7) (2014-07-06)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.1.6...0.1.7)\n\n## [0.1.6](https://github.com/feathersjs/errors/tree/0.1.6) (2014-07-05)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.1.5...0.1.6)\n\n## [0.1.5](https://github.com/feathersjs/errors/tree/0.1.5) (2014-06-13)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.1.4...0.1.5)\n\n## [0.1.4](https://github.com/feathersjs/errors/tree/0.1.4) (2014-06-13)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.1.3...0.1.4)\n\n**Closed issues:**\n\n- Move errors into core [\\#2](https://github.com/feathersjs/errors/issues/2)\n\n**Merged pull requests:**\n\n- Core compatible [\\#4](https://github.com/feathersjs/errors/pull/4) ([ekryski](https://github.com/ekryski))\n\n## [0.1.3](https://github.com/feathersjs/errors/tree/0.1.3) (2014-06-09)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.1.2...0.1.3)\n\n**Merged pull requests:**\n\n- Adding a default error page [\\#3](https://github.com/feathersjs/errors/pull/3) ([ekryski](https://github.com/ekryski))\n\n## [0.1.2](https://github.com/feathersjs/errors/tree/0.1.2) (2014-06-05)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/0.1.1...0.1.2)\n\n## [0.1.1](https://github.com/feathersjs/errors/tree/0.1.1) (2014-06-04)\n\n[Full Changelog](https://github.com/feathersjs/errors/compare/v0.1.0...0.1.1)\n\n## [v0.1.0](https://github.com/feathersjs/errors/tree/v0.1.0) (2014-06-04)\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/errors/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/errors/README.md",
    "content": "# @feathersjs/errors\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/errors.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/errors)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Common error types for feathers apps\n\n## Installation\n\n```\nnpm install @feathersjs/errors --save\n```\n\n## Documentation\n\nRefer to the [Feathers errors API documentation](https://feathersjs.com/api/errors.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/errors/package.json",
    "content": "{\n  \"name\": \"@feathersjs/errors\",\n  \"description\": \"Common error types for Feathers apps\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/errors\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"devDependencies\": {\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/errors/src/index.ts",
    "content": "export interface FeathersErrorJSON {\n  name: string\n  message: string\n  code: number\n  className: string\n  data?: any\n  errors?: any\n}\n\nexport type DynamicError = Error & { [key: string]: any }\nexport type ErrorMessage = null | string | DynamicError | { [key: string]: any } | any[]\n\ninterface ErrorProperties extends Omit<FeathersErrorJSON, 'message'> {\n  type: string\n}\n\nexport class FeathersError extends Error {\n  readonly type: string\n  readonly code: number\n  readonly className: string\n  readonly data: any\n  readonly errors: any\n\n  constructor(err: ErrorMessage, name: string, code: number, className: string, _data: any) {\n    let msg = typeof err === 'string' ? err : 'Error'\n    const properties: ErrorProperties = {\n      name,\n      code,\n      className,\n      type: 'FeathersError'\n    }\n\n    if (Array.isArray(_data)) {\n      properties.data = _data\n    } else if (typeof err === 'object' || _data !== undefined) {\n      const { message, errors, ...rest } = err !== null && typeof err === 'object' ? err : _data\n\n      msg = message || msg\n      properties.errors = errors\n      properties.data = rest\n    }\n\n    super(msg)\n    Object.assign(this, properties)\n  }\n\n  toJSON() {\n    const result: FeathersErrorJSON = {\n      name: this.name,\n      message: this.message,\n      code: this.code,\n      className: this.className\n    }\n\n    if (this.data !== undefined) {\n      result.data = this.data\n    }\n\n    if (this.errors !== undefined) {\n      result.errors = this.errors\n    }\n\n    return result\n  }\n}\n\nexport class BadRequest extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'BadRequest', 400, 'bad-request', data)\n  }\n}\n\n// 401 - Not Authenticated\nexport class NotAuthenticated extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'NotAuthenticated', 401, 'not-authenticated', data)\n  }\n}\n\n// 402 - Payment Error\nexport class PaymentError extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'PaymentError', 402, 'payment-error', data)\n  }\n}\n\n// 403 - Forbidden\nexport class Forbidden extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'Forbidden', 403, 'forbidden', data)\n  }\n}\n\n// 404 - Not Found\nexport class NotFound extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'NotFound', 404, 'not-found', data)\n  }\n}\n\n// 405 - Method Not Allowed\nexport class MethodNotAllowed extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'MethodNotAllowed', 405, 'method-not-allowed', data)\n  }\n}\n\n// 406 - Not Acceptable\nexport class NotAcceptable extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'NotAcceptable', 406, 'not-acceptable', data)\n  }\n}\n\n// 408 - Timeout\nexport class Timeout extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'Timeout', 408, 'timeout', data)\n  }\n}\n\n// 409 - Conflict\nexport class Conflict extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'Conflict', 409, 'conflict', data)\n  }\n}\n\n// 410 - Gone\nexport class Gone extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'Gone', 410, 'gone', data)\n  }\n}\n\n// 411 - Length Required\nexport class LengthRequired extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'LengthRequired', 411, 'length-required', data)\n  }\n}\n\n// 422 Unprocessable\nexport class Unprocessable extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'Unprocessable', 422, 'unprocessable', data)\n  }\n}\n\n// 429 Too Many Requests\nexport class TooManyRequests extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'TooManyRequests', 429, 'too-many-requests', data)\n  }\n}\n\n// 500 - General Error\nexport class GeneralError extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'GeneralError', 500, 'general-error', data)\n  }\n}\n\n// 501 - Not Implemented\nexport class NotImplemented extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'NotImplemented', 501, 'not-implemented', data)\n  }\n}\n\n// 502 - Bad Gateway\nexport class BadGateway extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'BadGateway', 502, 'bad-gateway', data)\n  }\n}\n\n// 503 - Unavailable\nexport class Unavailable extends FeathersError {\n  constructor(message?: ErrorMessage, data?: any) {\n    super(message, 'Unavailable', 503, 'unavailable', data)\n  }\n}\n\nexport interface Errors {\n  FeathersError: FeathersError\n  BadRequest: BadRequest\n  NotAuthenticated: NotAuthenticated\n  PaymentError: PaymentError\n  Forbidden: Forbidden\n  NotFound: NotFound\n  MethodNotAllowed: MethodNotAllowed\n  NotAcceptable: NotAcceptable\n  Timeout: Timeout\n  Conflict: Conflict\n  LengthRequired: LengthRequired\n  Unprocessable: Unprocessable\n  TooManyRequests: TooManyRequests\n  GeneralError: GeneralError\n  NotImplemented: NotImplemented\n  BadGateway: BadGateway\n  Unavailable: Unavailable\n  400: BadRequest\n  401: NotAuthenticated\n  402: PaymentError\n  403: Forbidden\n  404: NotFound\n  405: MethodNotAllowed\n  406: NotAcceptable\n  408: Timeout\n  409: Conflict\n  411: LengthRequired\n  422: Unprocessable\n  429: TooManyRequests\n  500: GeneralError\n  501: NotImplemented\n  502: BadGateway\n  503: Unavailable\n}\n\nexport const errors = {\n  FeathersError,\n  BadRequest,\n  NotAuthenticated,\n  PaymentError,\n  Forbidden,\n  NotFound,\n  MethodNotAllowed,\n  NotAcceptable,\n  Timeout,\n  Conflict,\n  LengthRequired,\n  Unprocessable,\n  TooManyRequests,\n  GeneralError,\n  NotImplemented,\n  BadGateway,\n  Unavailable,\n  400: BadRequest,\n  401: NotAuthenticated,\n  402: PaymentError,\n  403: Forbidden,\n  404: NotFound,\n  405: MethodNotAllowed,\n  406: NotAcceptable,\n  408: Timeout,\n  409: Conflict,\n  410: Gone,\n  411: LengthRequired,\n  422: Unprocessable,\n  429: TooManyRequests,\n  500: GeneralError,\n  501: NotImplemented,\n  502: BadGateway,\n  503: Unavailable\n}\n\nexport function convert(error: any) {\n  if (!error) {\n    return error\n  }\n\n  const FeathersError = (errors as any)[error.name]\n  const result = FeathersError\n    ? new FeathersError(error.message, error.data)\n    : new Error(error.message || error)\n\n  if (typeof error === 'object') {\n    Object.assign(result, error)\n  }\n\n  return result\n}\n"
  },
  {
    "path": "packages/errors/test/index.test.ts",
    "content": "import assert from 'assert'\nimport * as errors from '../src'\n\nconst { convert } = errors\n\ndescribe('@feathersjs/errors', () => {\n  describe('errors.convert', () => {\n    it('converts objects to feathers errors', () => {\n      const error = convert({\n        name: 'BadRequest',\n        message: 'Hi',\n        expando: 'Me'\n      })\n\n      assert.strictEqual(error.message, 'Hi')\n      assert.strictEqual(error.expando, 'Me')\n      assert.ok(error instanceof errors.BadRequest)\n    })\n\n    it('converts other object to error', () => {\n      let error = convert({\n        message: 'Something went wrong'\n      })\n\n      assert.ok(error instanceof Error)\n      assert.strictEqual(error.message, 'Something went wrong')\n\n      error = convert('Something went wrong')\n\n      assert.ok(error instanceof Error)\n      assert.strictEqual(error.message, 'Something went wrong')\n    })\n\n    it('converts nothing', () => assert.strictEqual(convert(null), null))\n  })\n\n  describe('error types', () => {\n    it('Bad Request', () => {\n      assert.notStrictEqual(typeof errors.BadRequest, 'undefined', 'has BadRequest')\n    })\n\n    it('Not Authenticated', () => {\n      assert.notStrictEqual(typeof errors.NotAuthenticated, 'undefined', 'has NotAuthenticated')\n    })\n\n    it('Payment Error', () => {\n      assert.notStrictEqual(typeof errors.PaymentError, 'undefined', 'has PaymentError')\n    })\n\n    it('Forbidden', () => {\n      assert.notStrictEqual(typeof errors.Forbidden, 'undefined', 'has Forbidden')\n    })\n\n    it('Not Found', () => {\n      assert.notStrictEqual(typeof errors.NotFound, 'undefined', 'has NotFound')\n    })\n\n    it('Method Not Allowed', () => {\n      assert.notStrictEqual(typeof errors.MethodNotAllowed, 'undefined', 'has MethodNotAllowed')\n    })\n\n    it('Not Acceptable', () => {\n      assert.notStrictEqual(typeof errors.NotAcceptable, 'undefined', 'has NotAcceptable')\n    })\n\n    it('Timeout', () => {\n      assert.notStrictEqual(typeof errors.Timeout, 'undefined', 'has Timeout')\n    })\n\n    it('Conflict', () => {\n      assert.notStrictEqual(typeof errors.Conflict, 'undefined', 'has Conflict')\n    })\n\n    it('Gone', () => {\n      assert.notStrictEqual(typeof errors.Gone, 'undefined', 'has Gone')\n    })\n\n    it('Length Required', () => {\n      assert.notStrictEqual(typeof errors.LengthRequired, 'undefined', 'has LengthRequired')\n    })\n\n    it('Unprocessable', () => {\n      assert.notStrictEqual(typeof errors.Unprocessable, 'undefined', 'has Unprocessable')\n    })\n\n    it('Too Many Requests', () => {\n      assert.notStrictEqual(typeof errors.TooManyRequests, 'undefined', 'has TooManyRequests')\n    })\n\n    it('General Error', () => {\n      assert.notStrictEqual(typeof errors.GeneralError, 'undefined', 'has GeneralError')\n    })\n\n    it('Not Implemented', () => {\n      assert.notStrictEqual(typeof errors.NotImplemented, 'undefined', 'has NotImplemented')\n    })\n\n    it('Bad Gateway', () => {\n      assert.notStrictEqual(typeof errors.BadGateway, 'undefined', 'has BadGateway')\n    })\n\n    it('Unavailable', () => {\n      assert.notStrictEqual(typeof errors.Unavailable, 'undefined', 'has Unavailable')\n    })\n\n    it('400', () => {\n      assert.notStrictEqual(typeof errors.errors[400], 'undefined', 'has BadRequest alias')\n    })\n\n    it('401', () => {\n      assert.notStrictEqual(typeof errors.errors[401], 'undefined', 'has NotAuthenticated alias')\n    })\n\n    it('402', () => {\n      assert.notStrictEqual(typeof errors.errors[402], 'undefined', 'has PaymentError alias')\n    })\n\n    it('403', () => {\n      assert.notStrictEqual(typeof errors.errors[403], 'undefined', 'has Forbidden alias')\n    })\n\n    it('404', () => {\n      assert.notStrictEqual(typeof errors.errors[404], 'undefined', 'has NotFound alias')\n    })\n\n    it('405', () => {\n      assert.notStrictEqual(typeof errors.errors[405], 'undefined', 'has MethodNotAllowed alias')\n    })\n\n    it('406', () => {\n      assert.notStrictEqual(typeof errors.errors[406], 'undefined', 'has NotAcceptable alias')\n    })\n\n    it('408', () => {\n      assert.notStrictEqual(typeof errors.errors[408], 'undefined', 'has Timeout alias')\n    })\n\n    it('409', () => {\n      assert.notStrictEqual(typeof errors.errors[409], 'undefined', 'has Conflict alias')\n    })\n\n    it('410', () => {\n      assert.notStrictEqual(typeof errors.errors[410], 'undefined', 'has Gone alias')\n    })\n\n    it('411', () => {\n      assert.notStrictEqual(typeof errors.errors[411], 'undefined', 'has LengthRequired alias')\n    })\n\n    it('422', () => {\n      assert.notStrictEqual(typeof errors.errors[422], 'undefined', 'has Unprocessable alias')\n    })\n\n    it('429', () => {\n      assert.notStrictEqual(typeof errors.errors[429], 'undefined', 'has TooManyRequests alias')\n    })\n\n    it('500', () => {\n      assert.notStrictEqual(typeof errors.errors[500], 'undefined', 'has GeneralError alias')\n    })\n\n    it('501', () => {\n      assert.notStrictEqual(typeof errors.errors[501], 'undefined', 'has NotImplemented alias')\n    })\n\n    it('502', () => {\n      assert.notStrictEqual(typeof errors.errors[502], 'undefined', 'has BadGateway alias')\n    })\n\n    it('503', () => {\n      assert.notStrictEqual(typeof errors.errors[503], 'undefined', 'has Unavailable alias')\n    })\n\n    it('instantiates every error', () => {\n      const index: any = errors.errors\n\n      Object.keys(index).forEach((name) => {\n        const E = index[name]\n\n        if (E) {\n          // tslint:disable-next-line\n          new E('Something went wrong')\n        }\n      })\n    })\n  })\n\n  describe('inheritance', () => {\n    it('instanceof differentiates between error types', () => {\n      const error = new errors.MethodNotAllowed()\n      assert.ok(!(error instanceof errors.BadRequest))\n    })\n\n    it('follows the prototypical inheritance chain', () => {\n      const error = new errors.MethodNotAllowed()\n      assert.ok(error instanceof Error)\n      assert.ok(error instanceof errors.FeathersError)\n    })\n\n    it('has the correct constructors', () => {\n      const error = new errors.NotFound()\n      assert.ok(error.constructor === errors.NotFound)\n      assert.ok(error.constructor.name === 'NotFound')\n    })\n  })\n\n  describe('successful error creation', () => {\n    describe('without custom message', () => {\n      it('default error', () => {\n        const error = new errors.GeneralError()\n        assert.strictEqual(error.code, 500)\n        assert.strictEqual(error.className, 'general-error')\n        assert.strictEqual(error.message, 'Error')\n        assert.strictEqual(error.data, undefined)\n        assert.strictEqual(error.errors, undefined)\n        assert.notStrictEqual(error.stack, undefined)\n        assert.strictEqual(error instanceof errors.GeneralError, true)\n        assert.strictEqual(error instanceof errors.FeathersError, true)\n      })\n\n      it('can wrap an existing error', () => {\n        const error = new errors.BadRequest(new Error())\n        assert.strictEqual(error.code, 400)\n        assert.strictEqual(error.message, 'Error')\n      })\n\n      it('with multiple errors', () => {\n        const data = {\n          errors: {\n            email: 'Email Taken',\n            password: 'Invalid Password'\n          },\n          foo: 'bar'\n        }\n\n        const error = new errors.BadRequest(data)\n        assert.strictEqual(error.code, 400)\n        assert.strictEqual(error.message, 'Error')\n        assert.deepStrictEqual(error.errors, {\n          email: 'Email Taken',\n          password: 'Invalid Password'\n        })\n        assert.deepStrictEqual(error.data, { foo: 'bar' })\n      })\n\n      it('with data', () => {\n        const data = {\n          email: 'Email Taken',\n          password: 'Invalid Password'\n        }\n\n        const error = new errors.GeneralError(data)\n        assert.strictEqual(error.code, 500)\n        assert.strictEqual(error.message, 'Error')\n        assert.deepStrictEqual(error.data, data)\n      })\n    })\n\n    describe('with custom message', () => {\n      it('contains our message', () => {\n        const error = new errors.BadRequest('Invalid Password')\n        assert.strictEqual(error.code, 400)\n        assert.strictEqual(error.message, 'Invalid Password')\n      })\n\n      it('can wrap an existing error', () => {\n        const error = new errors.BadRequest(new Error('Invalid Password'))\n        assert.strictEqual(error.code, 400)\n        assert.strictEqual(error.message, 'Invalid Password')\n      })\n\n      it('with data', () => {\n        const data = {\n          email: 'Email Taken',\n          password: 'Invalid Password'\n        }\n\n        const error = new errors.GeneralError('Custom Error', data)\n        assert.strictEqual(error.code, 500)\n        assert.strictEqual(error.message, 'Custom Error')\n        assert.deepStrictEqual(error.data, data)\n      })\n\n      it('with multiple errors', () => {\n        const data = {\n          errors: {\n            email: 'Email Taken',\n            password: 'Invalid Password'\n          },\n          foo: 'bar'\n        }\n\n        const error = new errors.BadRequest(data)\n\n        assert.strictEqual(error.code, 400)\n        assert.strictEqual(error.message, 'Error')\n        assert.deepStrictEqual(error.errors, {\n          email: 'Email Taken',\n          password: 'Invalid Password'\n        })\n        assert.deepStrictEqual(error.data, { foo: 'bar' })\n      })\n    })\n\n    it('can return JSON', () => {\n      const data = {\n        errors: {\n          email: 'Email Taken',\n          password: 'Invalid Password'\n        },\n        foo: 'bar'\n      }\n\n      const expected =\n        '{\"name\":\"GeneralError\",\"message\":\"Custom Error\",\"code\":500,\"className\":\"general-error\",\"data\":{\"foo\":\"bar\"},\"errors\":{\"email\":\"Email Taken\",\"password\":\"Invalid Password\"}}'\n\n      const error = new errors.GeneralError('Custom Error', data)\n      assert.strictEqual(JSON.stringify(error), expected)\n    })\n\n    it('can handle immutable data', () => {\n      const data = {\n        errors: {\n          email: 'Email Taken',\n          password: 'Invalid Password'\n        },\n        foo: 'bar'\n      }\n\n      const error = new errors.GeneralError('Custom Error', Object.freeze(data))\n      assert.strictEqual(error.data.errors, undefined)\n      assert.deepStrictEqual(error.data, { foo: 'bar' })\n    })\n\n    it('allows arrays as data', () => {\n      const data = [\n        {\n          hello: 'world'\n        }\n      ]\n\n      const error = new errors.GeneralError('Custom Error', data)\n      assert.strictEqual(error.data.errors, undefined)\n      assert.ok(Array.isArray(error.data))\n      assert.deepStrictEqual(error.data, [{ hello: 'world' }])\n    })\n\n    it('can be instantiated with `null` (#2789)', () => {\n      const err = new errors.BadRequest(null, {})\n      assert.strictEqual(err.message, 'Error')\n    })\n\n    it('has proper stack trace (#78)', () => {\n      try {\n        throw new errors.NotFound('Not the error you are looking for')\n      } catch (e: any) {\n        const text = 'NotFound: Not the error you are looking for'\n\n        assert.strictEqual(e.stack.indexOf(text), 0)\n\n        assert.ok(e.stack.indexOf('index.test.ts') !== -1)\n\n        const oldCST = Error.captureStackTrace\n\n        delete Error.captureStackTrace\n\n        try {\n          throw new errors.NotFound('Not the error you are looking for')\n        } catch (e: any) {\n          assert.ok(e)\n          Error.captureStackTrace = oldCST\n        }\n      }\n    })\n  })\n})\n"
  },
  {
    "path": "packages/errors/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/express/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n- **express:** Update express to version 4.21.1 ([#3543](https://github.com/feathersjs/feathers/issues/3543)) ([56d6151](https://github.com/feathersjs/feathers/commit/56d6151624f083d6604e76746cf555ed846b6d40))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n### Bug Fixes\n\n- Reduce usage of lodash ([#3455](https://github.com/feathersjs/feathers/issues/3455)) ([8ce807a](https://github.com/feathersjs/feathers/commit/8ce807a5ca53ff5b8d5107a0656c6329404e6e6c))\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n### Bug Fixes\n\n- **express:** Re-export Router ([#3349](https://github.com/feathersjs/feathers/issues/3349)) ([0cbdb03](https://github.com/feathersjs/feathers/commit/0cbdb03a2d810f4855da9b21602c96e4fed7fce5))\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **core:** `context.type` for around hooks ([#2890](https://github.com/feathersjs/feathers/issues/2890)) ([d606ac6](https://github.com/feathersjs/feathers/commit/d606ac660fd5335c95206784fea36530dd2e851a))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n### Bug Fixes\n\n- **docs:** Review transport API docs and update Express middleware setup ([#2811](https://github.com/feathersjs/feathers/issues/2811)) ([1b97f14](https://github.com/feathersjs/feathers/commit/1b97f14d474f5613482f259eeaa585c24fcfab43))\n- **transports:** Add remaining middleware for generated apps to Koa and Express ([#2796](https://github.com/feathersjs/feathers/issues/2796)) ([0d5781a](https://github.com/feathersjs/feathers/commit/0d5781a5c72a0cbb2ec8211bfa099f0aefe115a2))\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Bug Fixes\n\n- **core:** Ensure setup and teardown can be overriden and maintain hook functionality ([#2779](https://github.com/feathersjs/feathers/issues/2779)) ([ab580cb](https://github.com/feathersjs/feathers/commit/ab580cbcaa68d19144d86798c13bf564f9d424a6))\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n### Features\n\n- Add CORS support to oAuth, Express, Koa and generated application ([#2744](https://github.com/feathersjs/feathers/issues/2744)) ([fd218f2](https://github.com/feathersjs/feathers/commit/fd218f289f8ca4c101e9938e8683e2efef6e8131))\n- **authentication-oauth:** Koa and transport independent oAuth authentication ([#2737](https://github.com/feathersjs/feathers/issues/2737)) ([9231525](https://github.com/feathersjs/feathers/commit/9231525a24bb790ba9c5d940f2867a9c727691c9))\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Bug Fixes\n\n- **authentication:** Add safe dispatch data for authentication requests ([#2662](https://github.com/feathersjs/feathers/issues/2662)) ([d8104a1](https://github.com/feathersjs/feathers/commit/d8104a19ee9181e6a5ea81014af29ff9a3c28a8a))\n\n### Features\n\n- **cli:** Add support for JavaScript to the new CLI ([#2668](https://github.com/feathersjs/feathers/issues/2668)) ([ebac587](https://github.com/feathersjs/feathers/commit/ebac587f7d00dc7607c3f546352d79f79b89a5d4))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n### Bug Fixes\n\n- **express:** Ensure Express options can be set before configuring REST transport ([#2655](https://github.com/feathersjs/feathers/issues/2655)) ([c9b8f74](https://github.com/feathersjs/feathers/commit/c9b8f74a0196acb99be44ac5e0fff3f1128288cd))\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Bug Fixes\n\n- **express:** Fix typo in types reference in package.json ([#2613](https://github.com/feathersjs/feathers/issues/2613)) ([eacf1b3](https://github.com/feathersjs/feathers/commit/eacf1b3474e6d9da69b8671244c23a75cff87d95))\n\n### Features\n\n- **typescript:** Improve params and query typeability ([#2600](https://github.com/feathersjs/feathers/issues/2600)) ([df28b76](https://github.com/feathersjs/feathers/commit/df28b7619161f1df5e700326f52cca1a92dc5d28))\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n### Features\n\n- **core:** Add app.teardown functionality ([#2570](https://github.com/feathersjs/feathers/issues/2570)) ([fcdf524](https://github.com/feathersjs/feathers/commit/fcdf524ae1995bb59265d39f12e98b7794bed023))\n- **core:** Finalize app.teardown() functionality ([#2584](https://github.com/feathersjs/feathers/issues/2584)) ([1a166f3](https://github.com/feathersjs/feathers/commit/1a166f3ded811ecacf0ae8cb67880bc9fa2eeafa))\n- **transport-commons:** add `context.http.response` ([#2524](https://github.com/feathersjs/feathers/issues/2524)) ([5bc9d44](https://github.com/feathersjs/feathers/commit/5bc9d447043c2e2b742c73ed28ecf3b3264dd9e5))\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n### Bug Fixes\n\n- **express:** Fix application typings to work with typed configuration ([#2539](https://github.com/feathersjs/feathers/issues/2539)) ([b9dfaee](https://github.com/feathersjs/feathers/commit/b9dfaee834b13864c1ed4f2f6a244eb5bb70395b))\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n### Features\n\n- **express, koa:** make transports similar ([#2486](https://github.com/feathersjs/feathers/issues/2486)) ([26aa937](https://github.com/feathersjs/feathers/commit/26aa937c114fb8596dfefc599b1f53cead69c159))\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- missing express types for Request, Response ([#2498](https://github.com/feathersjs/feathers/issues/2498)) ([ee67131](https://github.com/feathersjs/feathers/commit/ee67131bbaa24c54d3d781bdf8820015759ac488))\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n### Features\n\n- **core:** add `context.http` and move `statusCode` there ([#2496](https://github.com/feathersjs/feathers/issues/2496)) ([b701bf7](https://github.com/feathersjs/feathers/commit/b701bf77fb83048aa1dffa492b3d77dd53f7b72b))\n- **core:** Improve legacy hooks integration ([08c8b40](https://github.com/feathersjs/feathers/commit/08c8b40999bf3889c61a4d4fad97a2c4f78bafc9))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n### Features\n\n- **koa:** KoaJS transport adapter ([#2315](https://github.com/feathersjs/feathers/issues/2315)) ([2554b57](https://github.com/feathersjs/feathers/commit/2554b57cf05731df58feeba9c12faab18e442107))\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n### Features\n\n- **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Resolve some type problems ([#2260](https://github.com/feathersjs/feathers/issues/2260)) ([a3d75fa](https://github.com/feathersjs/feathers/commit/a3d75fa29490e8a19412a12bc993ee7bb573068f))\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n### Features\n\n- **core:** Public custom service methods ([#2270](https://github.com/feathersjs/feathers/issues/2270)) ([e65abfb](https://github.com/feathersjs/feathers/commit/e65abfb5388df6c19a11c565cf1076a29f32668d))\n- Application service types default to any ([#1566](https://github.com/feathersjs/feathers/issues/1566)) ([d93ba9a](https://github.com/feathersjs/feathers/commit/d93ba9a17edd20d3397bb00f4f6e82e804e42ed6))\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n- **core:** Remove Uberproto ([#2178](https://github.com/feathersjs/feathers/issues/2178)) ([ddf8821](https://github.com/feathersjs/feathers/commit/ddf8821f53317e6a378657f7d66acb03a037ee47))\n\n### BREAKING CHANGES\n\n- **core:** Services no longer extend Uberproto objects and\n  `service.mixin()` is no longer available.\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Features\n\n- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Features\n\n- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n### Bug Fixes\n\n- **authentication:** consistent response return between local and jwt strategy ([#2042](https://github.com/feathersjs/feathers/issues/2042)) ([8d25be1](https://github.com/feathersjs/feathers/commit/8d25be101a2593a9e789375c928a07780b9e28cf))\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.5.6](https://github.com/feathersjs/feathers/compare/v4.5.5...v4.5.6) (2020-07-12)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.5.4](https://github.com/feathersjs/feathers/compare/v4.5.3...v4.5.4) (2020-04-29)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n### Bug Fixes\n\n- Updated typings for express middleware ([#1839](https://github.com/feathersjs/feathers/issues/1839)) ([6b8e897](https://github.com/feathersjs/feathers/commit/6b8e8971a9dbb08913edd1be48826624645d9dc1))\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n### Features\n\n- **authentication:** Add parseStrategies to allow separate strategies for creating JWTs and parsing headers ([#1708](https://github.com/feathersjs/feathers/issues/1708)) ([5e65629](https://github.com/feathersjs/feathers/commit/5e65629b924724c3e81d7c81df047e123d1c8bd7))\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n### Bug Fixes\n\n- Small type improvements ([#1624](https://github.com/feathersjs/feathers/issues/1624)) ([50162c6](https://github.com/feathersjs/feathers/commit/50162c6e562f0a47c6a280c4f01fff7c3afee293))\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n### Bug Fixes\n\n- Typings for express request and response properties ([#1609](https://github.com/feathersjs/feathers/issues/1609)) ([38cf8c9](https://github.com/feathersjs/feathers/commit/38cf8c950c1a4fb4a6d78d68d70e7fdd63b71c3c))\n\n## [4.3.5](https://github.com/feathersjs/feathers/compare/v4.3.4...v4.3.5) (2019-10-07)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n**Note:** Version bump only for package @feathersjs/express\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n### Bug Fixes\n\n- Add info to express error handler logger type ([#1557](https://github.com/feathersjs/feathers/issues/1557)) ([3e1d26c](https://github.com/feathersjs/feathers/commit/3e1d26c))\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n### Bug Fixes\n\n- Add method to reliably get default authentication service ([#1470](https://github.com/feathersjs/feathers/issues/1470)) ([e542cb3](https://github.com/feathersjs/feathers/commit/e542cb3))\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/express\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n### Bug Fixes\n\n- Remove unnecessary top level export files in @feathersjs/express ([#1442](https://github.com/feathersjs/feathers/issues/1442)) ([73c3fb2](https://github.com/feathersjs/feathers/commit/73c3fb2))\n\n### Features\n\n- @feathersjs/express allow to pass an existing Express application instance ([#1446](https://github.com/feathersjs/feathers/issues/1446)) ([853a6b0](https://github.com/feathersjs/feathers/commit/853a6b0))\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n### Bug Fixes\n\n- @feathersjs/express: allow middleware arrays ([#1421](https://github.com/feathersjs/feathers/issues/1421)) ([b605ab8](https://github.com/feathersjs/feathers/commit/b605ab8))\n- @feathersjs/express: replace `reduce` with `map` ([#1429](https://github.com/feathersjs/feathers/issues/1429)) ([44542e9](https://github.com/feathersjs/feathers/commit/44542e9))\n- Clean up hooks code ([#1407](https://github.com/feathersjs/feathers/issues/1407)) ([f25c88b](https://github.com/feathersjs/feathers/commit/f25c88b))\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n### Bug Fixes\n\n- Use `export =` in TypeScript definitions ([#1285](https://github.com/feathersjs/feathers/issues/1285)) ([12d0f4b](https://github.com/feathersjs/feathers/commit/12d0f4b))\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n### Bug Fixes\n\n- Always require strategy parameter in authentication ([#1327](https://github.com/feathersjs/feathers/issues/1327)) ([d4a8021](https://github.com/feathersjs/feathers/commit/d4a8021))\n- Merge httpStrategies and authStrategies option ([#1308](https://github.com/feathersjs/feathers/issues/1308)) ([afa4d55](https://github.com/feathersjs/feathers/commit/afa4d55))\n\n### Features\n\n- Add params.headers to all transports when available ([#1303](https://github.com/feathersjs/feathers/issues/1303)) ([ebce79b](https://github.com/feathersjs/feathers/commit/ebce79b))\n- express use service.methods ([#945](https://github.com/feathersjs/feathers/issues/945)) ([3f0b1c3](https://github.com/feathersjs/feathers/commit/3f0b1c3))\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n- **chore:** Properly configure and run code linter ([#1092](https://github.com/feathersjs/feathers/issues/1092)) ([fd3fc34](https://github.com/feathersjs/feathers/commit/fd3fc34))\n- **package:** update @feathersjs/commons to version 2.0.0 ([#31](https://github.com/feathersjs/feathers/issues/31)) ([c1ef5b1](https://github.com/feathersjs/feathers/commit/c1ef5b1))\n- **package:** update debug to version 3.0.0 ([#2](https://github.com/feathersjs/feathers/issues/2)) ([7e19603](https://github.com/feathersjs/feathers/commit/7e19603))\n\n### Features\n\n- @feathersjs/authentication-oauth ([#1299](https://github.com/feathersjs/feathers/issues/1299)) ([656bae7](https://github.com/feathersjs/feathers/commit/656bae7))\n- Add AuthenticationBaseStrategy and make authentication option handling more explicit ([#1284](https://github.com/feathersjs/feathers/issues/1284)) ([2667d92](https://github.com/feathersjs/feathers/commit/2667d92))\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Allow registering a service at the root level ([#1115](https://github.com/feathersjs/feathers/issues/1115)) ([c73d322](https://github.com/feathersjs/feathers/commit/c73d322))\n- Authentication v3 client ([#1240](https://github.com/feathersjs/feathers/issues/1240)) ([65b43bd](https://github.com/feathersjs/feathers/commit/65b43bd))\n- Authentication v3 Express integration ([#1218](https://github.com/feathersjs/feathers/issues/1218)) ([82bcfbe](https://github.com/feathersjs/feathers/commit/82bcfbe))\n\n### BREAKING CHANGES\n\n- Rewrite for authentication v3\n\n## [1.3.1](https://github.com/feathersjs/feathers/compare/@feathersjs/express@1.3.0...@feathersjs/express@1.3.1) (2019-01-02)\n\n### Bug Fixes\n\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n\n<a name=\"1.3.0\"></a>\n\n# [1.3.0](https://github.com/feathersjs/feathers/compare/@feathersjs/express@1.2.7...@feathersjs/express@1.3.0) (2018-12-16)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- **chore:** Properly configure and run code linter ([#1092](https://github.com/feathersjs/feathers/issues/1092)) ([fd3fc34](https://github.com/feathersjs/feathers/commit/fd3fc34))\n\n### Features\n\n- Allow registering a service at the root level ([#1115](https://github.com/feathersjs/feathers/issues/1115)) ([c73d322](https://github.com/feathersjs/feathers/commit/c73d322))\n\n<a name=\"1.2.7\"></a>\n\n## [1.2.7](https://github.com/feathersjs/feathers/compare/@feathersjs/express@1.2.6...@feathersjs/express@1.2.7) (2018-09-21)\n\n**Note:** Version bump only for package @feathersjs/express\n\n<a name=\"1.2.6\"></a>\n\n## [1.2.6](https://github.com/feathersjs/feathers/compare/@feathersjs/express@1.2.5...@feathersjs/express@1.2.6) (2018-09-17)\n\n**Note:** Version bump only for package @feathersjs/express\n\n<a name=\"1.2.5\"></a>\n\n## [1.2.5](https://github.com/feathersjs/feathers/compare/@feathersjs/express@1.2.4...@feathersjs/express@1.2.5) (2018-09-02)\n\n**Note:** Version bump only for package @feathersjs/express\n\n<a name=\"1.2.4\"></a>\n\n## 1.2.4\n\n- Migrate to Monorepo ([feathers#462](https://github.com/feathersjs/feathers/issues/462))\n\n## [v1.2.3](https://github.com/feathersjs/express/tree/v1.2.3) (2018-06-03)\n\n[Full Changelog](https://github.com/feathersjs/express/compare/v1.2.2...v1.2.3)\n\n**Closed issues:**\n\n- Question: How to handle JSON:API [\\#26](https://github.com/feathersjs/express/issues/26)\n- \\[Proposal\\] Allow multiple express middleware functions to be passed into `app.use` [\\#24](https://github.com/feathersjs/express/issues/24)\n\n**Merged pull requests:**\n\n- Update uberproto to the latest version [\\#28](https://github.com/feathersjs/express/pull/28) ([bertho-zero](https://github.com/bertho-zero))\n\n## [v1.2.2](https://github.com/feathersjs/express/tree/v1.2.2) (2018-04-16)\n\n[Full Changelog](https://github.com/feathersjs/express/compare/v1.2.1...v1.2.2)\n\n**Merged pull requests:**\n\n- Allow multiple express middleware functions to be passed into `app.use` [\\#25](https://github.com/feathersjs/express/pull/25) ([eXigentCoder](https://github.com/eXigentCoder))\n\n## [v1.2.1](https://github.com/feathersjs/express/tree/v1.2.1) (2018-03-29)\n\n[Full Changelog](https://github.com/feathersjs/express/compare/v1.2.0...v1.2.1)\n\n**Closed issues:**\n\n- Error in error hook results in unhandled rejection [\\#21](https://github.com/feathersjs/express/issues/21)\n- Error handler in wrapper hides breaks and hides real error [\\#13](https://github.com/feathersjs/express/issues/13)\n\n**Merged pull requests:**\n\n- Allow to set HTTP status code in a hook [\\#23](https://github.com/feathersjs/express/pull/23) ([daffl](https://github.com/daffl))\n- Update axios to the latest version 🚀 [\\#22](https://github.com/feathersjs/express/pull/22) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.2.0](https://github.com/feathersjs/express/tree/v1.2.0) (2018-02-09)\n\n[Full Changelog](https://github.com/feathersjs/express/compare/v1.1.2...v1.2.0)\n\n**Closed issues:**\n\n- Error in `create` method results in unhandled rejection [\\#19](https://github.com/feathersjs/express/issues/19)\n- @feathersjs/express call without paramaters could returns an instance of express [\\#18](https://github.com/feathersjs/express/issues/18)\n- Feathers-express blows up the feathers application version property and the example doesn't work [\\#16](https://github.com/feathersjs/express/issues/16)\n\n**Merged pull requests:**\n\n- Return an instance of the original Express application when nothing i… [\\#20](https://github.com/feathersjs/express/pull/20) ([daffl](https://github.com/daffl))\n- Fix README example [\\#17](https://github.com/feathersjs/express/pull/17) ([bertho-zero](https://github.com/bertho-zero))\n- Update mocha to the latest version 🚀 [\\#15](https://github.com/feathersjs/express/pull/15) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update semistandard to the latest version 🚀 [\\#14](https://github.com/feathersjs/express/pull/14) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.1.2](https://github.com/feathersjs/express/tree/v1.1.2) (2017-11-16)\n\n[Full Changelog](https://github.com/feathersjs/express/compare/v1.1.1...v1.1.2)\n\n**Merged pull requests:**\n\n- Export default and original Express object [\\#12](https://github.com/feathersjs/express/pull/12) ([daffl](https://github.com/daffl))\n\n## [v1.1.1](https://github.com/feathersjs/express/tree/v1.1.1) (2017-11-06)\n\n[Full Changelog](https://github.com/feathersjs/express/compare/v1.1.0...v1.1.1)\n\n**Merged pull requests:**\n\n- Also add notFound to export [\\#11](https://github.com/feathersjs/express/pull/11) ([daffl](https://github.com/daffl))\n\n## [v1.1.0](https://github.com/feathersjs/express/tree/v1.1.0) (2017-11-05)\n\n[Full Changelog](https://github.com/feathersjs/express/compare/v1.0.0...v1.1.0)\n\n**Merged pull requests:**\n\n- Re-export Express error handler [\\#10](https://github.com/feathersjs/express/pull/10) ([daffl](https://github.com/daffl))\n\n## [v1.0.0](https://github.com/feathersjs/express/tree/v1.0.0) (2017-11-01)\n\n[Full Changelog](https://github.com/feathersjs/express/compare/v1.0.0-pre.4...v1.0.0)\n\n## [v1.0.0-pre.4](https://github.com/feathersjs/express/tree/v1.0.0-pre.4) (2017-10-25)\n\n[Full Changelog](https://github.com/feathersjs/express/compare/v1.0.0-pre.3...v1.0.0-pre.4)\n\n**Merged pull requests:**\n\n- Update to better returnHook handling [\\#9](https://github.com/feathersjs/express/pull/9) ([daffl](https://github.com/daffl))\n\n## [v1.0.0-pre.3](https://github.com/feathersjs/express/tree/v1.0.0-pre.3) (2017-10-21)\n\n[Full Changelog](https://github.com/feathersjs/express/compare/v1.0.0-pre.2...v1.0.0-pre.3)\n\n**Merged pull requests:**\n\n- Add REST provider to Express framework bindings [\\#8](https://github.com/feathersjs/express/pull/8) ([daffl](https://github.com/daffl))\n- Update repository name and move to npm scope [\\#7](https://github.com/feathersjs/express/pull/7) ([daffl](https://github.com/daffl))\n- Update axios to the latest version 🚀 [\\#6](https://github.com/feathersjs/express/pull/6) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.0-pre.2](https://github.com/feathersjs/express/tree/v1.0.0-pre.2) (2017-10-18)\n\n[Full Changelog](https://github.com/feathersjs/express/compare/v1.0.0-pre.1...v1.0.0-pre.2)\n\n**Merged pull requests:**\n\n- Also export Express top level functionality [\\#5](https://github.com/feathersjs/express/pull/5) ([daffl](https://github.com/daffl))\n- Update mocha to the latest version 🚀 [\\#4](https://github.com/feathersjs/express/pull/4) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update debug to the latest version 🚀 [\\#2](https://github.com/feathersjs/express/pull/2) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.0-pre.1](https://github.com/feathersjs/express/tree/v1.0.0-pre.1) (2017-07-19)\n\n**Merged pull requests:**\n\n- Update dependencies to enable Greenkeeper 🌴 [\\#1](https://github.com/feathersjs/express/pull/1) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/express/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/express/README.md",
    "content": "# @feathersjs/express\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/express.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/express)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Feathers Express framework bindings and REST provider\n\n## Installation\n\n```\nnpm install @feathersjs/client --save\n```\n\n## Documentation\n\nRefer to the [Feathers Express API documentation](https://feathersjs.com/api/express.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/express/package.json",
    "content": "{\n  \"name\": \"@feathersjs/express\",\n  \"description\": \"Feathers Express framework bindings and REST provider\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/express\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"public/**\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/authentication\": \"^5.0.42\",\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@feathersjs/transport-commons\": \"^5.0.42\",\n    \"@types/compression\": \"^1.8.1\",\n    \"@types/cors\": \"^2.8.19\",\n    \"@types/express\": \"^4.17.21\",\n    \"@types/express-serve-static-core\": \"^4.19.5\",\n    \"compression\": \"^1.8.1\",\n    \"cors\": \"^2.8.6\",\n    \"express\": \"^4.21.2\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/authentication-local\": \"^5.0.42\",\n    \"@feathersjs/tests\": \"^5.0.42\",\n    \"@types/lodash\": \"^4.17.24\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"axios\": \"^1.13.6\",\n    \"lodash\": \"^4.17.23\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/express/public/401.html",
    "content": "<html>\n  <head>\n    <title>Not Authorized</title>\n    <style>\n      * {\n        margin: 0;\n        padding: 0;\n        box-sizing: border-box;\n      }\n\n      html, body {\n        font-family: 'Helvetica Neue', 'Helevetica', 'Arial', 'sans-serif';\n        font-weight: 400;\n        font-size: 16px;\n        color: #333;\n      }\n\n      main {\n        margin-top: 100px;\n        padding: 20px;\n      }\n\n      img.logo {\n        display: inline-block;\n        width: 100px;\n      }\n\n      h1 {\n        font-weight: 100;\n        font-size: 8em;\n        margin-bottom: 10px;\n      }\n\n      h2 {\n        font-size: 2em;\n        font-weight: 100;\n      }\n\n      .center-text {\n        text-align: center;\n      }\n\n      footer {\n        position: absolute;\n        bottom: 0;\n        left: 0;\n        right: 0;\n        padding: 20px;\n      }\n\n      footer p {\n        font-weight: 300;\n        font-size: 20px;\n      }\n    </style>\n  </head>\n  <body>\n    <main class=\"container\">\n      <h1 id=\"error-code\" class=\"center-text\">401</h1>\n      <h2 id=\"error-message\" class=\"center-text\">Not Authorized</h2>\n      \n      <footer>\n        <p class=\"center-text\">Powered by <a href=\"http://feathersjs.com\" target=\"_blank\" alt=\"Powered by Feathers\"><img class=\"logo\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAk4AAABkCAMAAABHL0++AAADAFBMVEUAAAD///+AgIBVVVVAQEAzMzNVVVVJSUlAQEA5OTkzMzNGRkZAQEA7Ozs3NzczMzNAQEA8PDw5OTk2NjYzMzM9PT06Ojo3Nzc1NTUzMzM7Ozs5OTk3Nzc1NTUzMzM6Ojo4ODg2NjY1NTUzMzM5OTk3Nzc2NjY0NDQzMzM4ODg3Nzc1NTU0NDQzMzM3Nzc2NjY1NTU0NDQzMzM3Nzc2NjY1NTU0NDQzMzM3Nzc2NjY1NTU0NDQzMzM2NjY1NTU1NTU0NDQzMzM2NjY1NTU1NTU0NDQzMzM2NjY1NTU0NDQ0NDQzMzM2NjY1NTU0NDQ0NDQzMzM2NjY1NTU0NDQ0NDQzMzM1NTU1NTU0NDQ0NDQzMzM1NTU1NTU0NDQ0NDQzMzM1NTU1NTU0NDQ0NDQzMzM1NTU1NTU0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzN4a/VhAAAA/3RSTlMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7rCNk1AAAYtElEQVR4Ae3de5iN5eL/8c9aM8MY50EO5FBCSaW2HEqhHaUk0m4QJZtd2mQcCoVdUeSgEhHalZxzjhByPkcOQs7kwAwGwxxm1nr/fnvNXDWHtdZzmNaM72Vef8/cfzzP+7rnnvt57uuRaaUe7Txi8rwVW37du+nHOV8P6VCvmP4aZMFc/Z+SxEblCnmo/08xZBK9uNcDztyccnOyonCnJbF4nFszZdywgT16DBw+fuq6KDwuzonIp6yBy2vsGpyb0/8lwU/NiAM4Ounl2kWUTnjdjl+dALg86VGHsgDW6CaQm1NY5CkgYU7HSvKhcueFScCBl0Nyc/IrN6fC/aKAja+Fy68S3bYCx7qE5ub0P0+vWdMkN6dMgrpegqT/VpMJNaYkw6kISbk5/RPa5eaUUZ3tED+2gkyqPCERlptqLzenm06hCW6YWkYWVJgDCYPz5OaUm1NG9x+EfY1k4L6OSufJQ7Clkozl5nRTeT2epHfyyL8aC+FZpRM6yMWlljKQm9NNJd9MOF5X/gUPSPS2J93gNIxyykBuTjePoutgQbhRcj8ASRxSRrcsg1l5c3NKkZtT2d0wQAaClwMXrxOlTJxDYGUhGcjN6eZwxzGSO8nIhwDb4bq86O5mewkpN6fcnMoeI66FjDzhBg4cg3h50yaRbQVzc8rNqehu4hrKSLEzANOABHnVNJHleXJzutlzyreO5BYyNAPg15+Aq/KurZvpztycbvKcZkInGfoHAIMBouVDJAzJzenmzul16C9DRc4AnBgDcEq+DMXdNDenmzmn++NZIGPjAOh3AeCwfHGuILpcbk43b06FDnE8XIbqugGudAZgj3wqdZZ1wbk53bQ5TSCprgw5tgAw5kcAv9fmMRd9cnO6WXOq4+YdGWuHR2MXAEvlxxCuVcjN6ebMKWg7+/LIUNjvAKx8E48Z8iPfUebm5nRz5tQVGslYakZtd+ExTv48A0/ldE55CgUpy4IKBgU+J0dBp7LIUSBMfwmnn3FCCuWTkcKXmCpjBaIAuFwLj0MGBS7ggDPHcqrxxoR1Z+OBuPP75n3YvqqdjGr1nrJky+EYN8SeObBsVKd6+WWok9Wcgh/sOXvDgahkXFH71s4Z8HCIrCvU/MN5B664ITnm5PqJPZvYzCr8iYGLdx05f529XhK7/59jlu655AISow5tWzai9R0O+dCP+DIy9jYeXwyEI7MGt3i8lfy6PYmInMnpkUlnyODw6L87ZMFtPRdeJqO42S94KapKlzSmwNdd0qviO6fQV36MJb1rS3sXlxXFuq1PIr34Jd1KyZ88Xbo0VXo1P/+NVJlzavzVeTKJWfZyfnkRFsVYGQs9j0e93UDSORcz5d837HJkf075uh/Ew3V0y8qFyzbsiibFvn/lk0n3TkvGw3XpyPb/P8jan0+78bj2WVFl0Bb/2vnKqcyg83gkHtiyYuHqPWcS8bg2qpzMqjkjAY/Lu9Yt+X7VtkNJeCR8da98KwwL0xXwymY8Lu1dPnPW7E+VVvCLO0lxYeeGFd//sGHPySukuDKhrjKJJKmCjL2Cx/GqpPpA/lVz0Ty7c8rzxhmA05M7VM+rVMXqdV1wFeB8R4dMqLcIIHnH2PZVnH8OXDnikz0AURkHedFeTnk/SAQ4Nr5VlWCluq39F7+6gYSJJWVGjbkASevfe6yUUoVUfXbUXgDmVjSZk6PzBYB9w1qWVmYdTwAc/OKl6vn1hxKP955yDIDFFZVe8Cn+KxNSGx0RSaoIGZjFxmzO6cHdwPXJj2XKJqTZYhewqaaMBA91Awe6FVZm9358HVhdWGlVeCGN8TDmhfQqeM2p1l4gfnJtZXTH6Fjg9MPyzxNkErCnZ+b0yr97GrjeP4+ZnGqsB+LHPihvwucCcePrKDPHw19cAq69Gay0noZqMlabFHV/JFUVGfgb3JmdOQUNcUHcqFLy6ra5QEJX+VduHfBDY4e8KzXODdvCs/yfXf9k4Lsy8qZI7wuQ1EMG7tsP7Ggur4I7RAGbyxvnNDAJWHi7vGrwO7jGlZUPoa/HAD+XUBoz2CgTRuJxskA8KS44ZGQ3H2ZjTkWXAfPLyqdnTwIz8suPx6Ihpq38ePQE7CyRtZwcnwC/N5cvt64Bo5d8nr8GF15yyJfiXwEXnjDIKWgicLCpvGsQD7sflB+lZwE7w9MMHcdrMuY4icfop0n1gwz15oQz23KqeBAuvSB/Cn7igvWF5NMDsfBTeflV+mdY7chKTs6J4B5bSL4FveuC4fLjHWBeSfnT8DdIau03p9C54B6YR97dGwPT8sm/FxLh5yJKpU4khMtYNVI0+4hUA2WojItG2ZVThaOwr4oM1L8MW8Plw62n4UunDITvh85ZyWksuP8l/553Qwf5NADcAxzyL+9UcL3sJyfHInB1lA+lT8N4GXouCdY4lGoJc2RCWzwSC2wg1WMytowx2ZRT2aOwupAM1b4M6/PIq0K7YF6QDFWJJ6a0/ZwiwP2qjPSGhIfkQz9IfF6GgqaAu5nvnN6EpDbyZSIsc8rYC8nQRilCYukoEz7AY3VoAimS8svYG+zLnpxCt8Lq/JK5nibKq69gVahMGALTbedU+Qru12Tsczjuo/tWkNRSMtfTlbt85VQ7iQTfw1R3cbm8TLZxNK88HoJKMqEbHm8/TKrNMqEGlMmWnCbDzvyS2Z5elRc1XEQVlRkFz5Jc3mZOzm0QaSqFTfC6vLknFtpJZns6VNB7TmFHoLV8mgf/kin5T0IvefTnqEwIqpYMwN96kGqITHCcp2125NQJYqvJpMYQW1GZLfJkZkpPeN9mThHwo0x5BE6FKrN8B2GSTApaA2O85xQJs+RT4USiQmROBEQH6X9+YpJMqN9nKsBF5zRSNZAZM5iUDTmVuwwvybQvYZkyeRR+CZI5d8AOezkF7eNaJZmzyPs8NgL2hsmsKnG463vLKfQ0UbfIpxfgU5m1Derpfy7zskwYeunBBOAHHSbFxWCZ8W92ZENOi+EbmVf0DEQooyXQUGYdwl3SVk7tIFIm3ePiXObA67i4frfM6wN7nV5y6goR8u0beERm9YX/SFIpqC0TdjB5MDCwGKm+kSmPEesIeE5Pw/4CsuA5+C0o8+R+SKaNgaa2cvqZTU6ZtRDqKgPHVugkC4K3Q3svOR1hrvzYiquAzLobNqTO8EVkrJgbRv0GTZ4kVQuZUg5uDXROzl3QVJbMgVeUXmv4UKb9G3rayakCPC7TXoWByqAVbJElNZM4HJIpp5pwn/w4zWGZd5TkIpI6c04mNAc4gLvou6S4FiZTHLH8PdA5tYOtsuZOOOhQOjOhpkxrBuPs5NSdQw6ZVgnWK72g/fC0rJkO7TLl9D6b5YfTxRqZ9zk8JGmEuV8agsd+LSPFdzJpO68HOqdf4RlZtJoMmYdc5ZDMuwdm2clpNb1lwQGSCmdaIW+XRQ1gXaac9tJB/rjYYG2B1lzSZKbIhNSKvnJcIkWETJrPu/ILdtSyIZ9S6e+wQ1a1zphDVZgq80rBchs5JboTisuCTzNNRevgWVm1H+7OkFM8l/LJn8vslnkdoaOkeYyTCWfxeL0yHmfmFJBJ3zJSfmFPdaXSAmgpq/JGkVhEaTSF/8i8grDRRk4wRVa0hy5KqybsdMiqSBiWISf4RH4dJ1rmNYO3JK1gmIzlJ0WDCGB9r9dayLTPmRDYnMq62O+QZR9B6wxr67YyL8huTs/JiqYwQGmNgzayLDyOA5lyaiC/lkNZmVYnJdgtDJCxO0lR/CNOzF1xDbeV2zZdfsHvw20omaaDAbLuTpiqNEZBLZkX7LaZUxlZ8WCGvUTnOWLDZN0MqJohp+T88mu0pfRvGT68laR9RMpYLTzO6Xs8Tsq0/nwf2KX4SqgiG85zyak/vfD++wVk3q3Yy+mYLLkNpimN+jBNNnSByAw5bZd//4DvZNVeeshYPTxW6ggei2XaABYGNKfiyeyUHfOhumyrZzOnqbKkEPyoND6GlrKhJnyXIacx8q9wIvGVZNEmBspYeTw+zefCo49MG8bUgObUEkbKjj7wimyLsJlTV1mTyDalsRNXUdkQFMvJDDm9KAMzYaEs+pHhMuaIAuBf95Cilkwbx/iA5jQEnpEdj8IXsm2+zZxqy5qr7NCf8iezQ7b8BGXS51RFBu4FRsuaOYw3k1MfAB5pgcdZh0ybwvCA5vQT7qKyIyyJDbKrqttmThWylNOj8LFsGQyN0+dUQEY+sd7T10yVsYjavwBU6IXHOJm3gIGBzMlxlaOyZyfnZVPIAmzmVDBLOfWGl2RLC+iSLqcEGcq7BZhRVhYMYZ2MvXm0/mVIDh6LRwOZ9wudA5lTGfhe9iyDQrIlbDE2c0pUlnL6AmrJlnowMl1OZ2SsyCYgtn8+mdaBKBkbxPYOCRzXYgAOOmSa4xqPBjKnuvCR7JkO98gG53O/QIy9nM5mLaeluAvIlmowJ11Oe2VC2HiA00OqW6g2XIbeg+iZrjXaDUB3mVceSgYypwjoLHvGQkNZFfxAr8PAqaqJtnL6NWs57ee07LkFVqfLaY1MabIDgO09q8qMYlBXhp4F4FvFAJwNk3mPE6NA5vQWPCN7BkFLCx2Vrf1ct+GrrgGw4XbZy2lT1nK6zg7ZEwy70uX0vcxxtFjuBuDIZ08VkKFoOspQ0GGAwQXB6lOnN9gc0Jw+gNqypwd0lG/BZR5o2vpfbw7+7NuFa3efvMofXKsaSzZz2pilnPLAEtl0hZMZjx6YdcdHJ/BI2jCoUaj8WsxXMlb/GvBqVS6s/qyZrPiOzwKa08fwZA17+kMXeVO6SY9Jm8668ObI9PYlpJzJyVNBDZtOc95eTh61PtxHiviVb9cNlk+9OCETbp8NLRtwt6xxRNMyoDmNJyteU0bOuoN3klnc2QNrpwzp0qCIPHIop9Jkhf2cPMr/c8YFUlxZ2LWqvHsAKsuMV3i4NcVlzX24wwOa02Sy4lWlF9rjDCkSDqyaNrLP6y+1bFy3RsXieZRRjuR0O1lxzjgnA877IudfIsWx8S0LKzPnRTrLjHbc0T3RIWt6sEMBzelr+HqMbQ8rreDOvwPEL+3bvEqQDORETpXg1zG2fWguJwPO+yPnXcAjaV3/6spoDgtkRneKfHBaFv3E8MDm9Cncpb9Gqa1A4n+bhclYzuQUDjNln/mcDDju6frdeTy29yitdCJIKiETBiU7Jv4ia8q7eTCwOb0PD+svcdcxcH19m4zlWE5BsCLnc0p1V9cfEwGSJ5VTGvku000mfB6luctlTT/2K7A59YLm+is8GgMH75Zu5JwUy47A52RekTZzk4G4YUX1p0lslQkz9mvNTFmzj34BzqkTdNBfoGQUbCyuGzyn3zkR0Jysu33MdeD4/eneeqghY8s3atcXsqQu7vIBzukf0Et/gYWwKJ9u9Jz2EhvgnKwrMRa4/qJSyXGAKTK2famOjJQl81miAOfUBD5Q1v0TTofrhs9pA+QNdE7WPXEKiFQqvUxyZRk6OkvnBsmKGm4eCXROtWCSsqz4VWgmK0LJiZwWwa03Xk4KXw7Jf1eqkGNMkKGYSbraT1ZMY60CnVNBN1uUZX1hsiwpnyM5DYOnbsCclH8jRFdUqi4kVpABh+tTubrLgmoungh4TjpIXLCy6gTuKrKkVo7k1AbeuRFzUtHdsEKpQk8xRwYKMjSU12TBUrYo8DnNhLtlR1B4eJhS1IDlsubpHMnpLpgtWwqGhzsCmJNui4OGShUBT8q/0vynKB1k3vO462RDTv2gnexoDm8qRQ+IlDUdcySnoOsckS07uOq0kNMX27Y6LO8nfyulWs6hUIP86FeaNjKtwO9MUDbk9CSMlB1DoZFSTIV7Zc3IHMlJm6GwbCiQzBpZyGkehMuSMsnEhChVtQQGya87efM2npNpHxNdLDtyKg0/yY61uIsoxRaSgmXN3pzJaRw0kA2PwSgrOX0Jd8ialWm3LweT3ED+1KBHdZrJrKZuOio7ctIZ4ovIujxxHFSqixyWNeXImZw6w1DZ0B/aWslpGNSRNR9AaylVni2cvkV+3EfP+2kik8pFM0fZk9NX0FHW1YZpSuGEVbKmYw7lVBFOOGTdD1DNSk59re9ItIbe+kOlSyxz+s2pVz0ayZzgdRwpkk05tYAVsq4v9FSKgvC9rJmZQzlpJ9SXZaExXHZayakzvCRrGsN7+lNLGCLf7qZfQ+rJnM9IqKVsyil/HK7SsspxCFcFpSgJM2VJ+NWcyuk9+FyWtYNJspJTMxgta+pkOPE4Ct6QT1V5twkPyJR3oKuyKydNg0hZ1RiWKFURmC9LBpFTOVWF6BBZtQHqWsop3M2vsqYBDFAazlm428iX0gx/huoyoxMMV/bl9Ahsl1VzoJWUKt7ibS56mRXJOZOTVkJzWXQP7JGlnLQDSsuSZ6G70sq7ksSm8iGUCa24XSa0SuYbRzbmpL0QIWvKJnM+REp1nMOy4l1omJhDOT0Pe4JlzVjobjGnkdBWlvSGlkqn0HYSfQ4SPbcNxWSsUzKLgpWdOXWAE2GyZAwM0x+2kFxI5hWNYY9859Q+oDkFH4SusqRCLPHFLObUDL6VJTOgstIrsQ13pLzbvOlld5AMvQ2LwpStOQXtg/dkRX030bekuxLNZJpjPnT2ldPL0CWgOakNXCwmK5bB+7KYU+EkEm+XBXkucsGpDAouh6FOefPp+U4xMhL8GXwTrOzNSa0grqLMy/db+jmkPYySaW/DtiBfObWAfoHNybETPpcFHWFfXqs5aaLF6ek5+NJLZDNgRUl58STv7pKBcutguEPZnZOWwjyZNwyWKo3wJM6FyaTGLpLula+cGsKwwOakh124asm0MjG4H5LlnCom4rrb2meWHldmziFuzj6mzJxH130p/56KJqGrlP05lb8C/WRWy+SMX9tcAT1lTsVo+EA+c7oPZgQ4J30MJ0rKpPxrYYys56RxsNghsyJhi7xqGo1rSD5l0iKpofwpMMrNkVrKiZzUEdwtZM7zSbg7KJ3WcK6gzKh5En4I8Z1TaCJnA51T2H7YkE+mFFgLuwvayenWePhYJjVJxt3Iz5+so88ok0Ly5/nfYU4R5UxOGg0Jz8mMiCR4XRmsgEVBMtYiFjbnl++ctBXuCnBOuuMCrDKVf6H1sPcW2clJbwFvy5S7YuB9+RLc5xosuF0WVFsK0R2lnMopaAkkd5Sx15KhmzKqEm9qfdvHDfuL63/i2SFvRsGYQOekhomw+RYZKr8J9pWUvZw0BugiE2oex/8D3wrzIOmbajKpxjQX7gnFlHM5Kf8S4Msw+VdpORCpzHoDY0PlV8XvgJXF5XGWKHlTzU3i7YHOSU9fhzON5J/jtSuwv5Ts5uScA8woISOd4+B4cfn11AFwzfqbTKg73w1b6kg5mZNCpgP7GskPZ7dYuNRG3vQBdt4p38JHJAAjgpRiK9SUN/NhT9FA56T6MeAaUVh+VF4FLLxFtnNS6CogKkJ+lZ4CbCtn2GbELmB37zLyq3y/fcDaJ6QczknOtxKBeT6TKNhlL7CkrLzr4oZrg26Rd6G9LwHREVKqIbChiLwodwp21Ql0Tqr6M3D+1bzyodZ/4+DyK1k7yRL8TgKw/LkQ+VJudBzwbaiMOZpvBFzL3qjhkFeO+3qsdIN7ySNSzuck/W0/wPKWIcqsxpgrQOyr8umpo0Dc55WV2f0fnwcSR6bpp/x1OPn2kzXLVKx5n9KpeR7cGz/s1v6Zp5q3atN1RGByUsjQZOD8kNuUWdhLWwBWVsjywah7tgOc+6iKvCjYanICcLm7TLrzw5MA52f8+7Fy6ZpylH/8je+iAfb3Ky/dGDkppGsUQOyiyLrF9IfQh3rNOQsQM+JW+RE6MA7g4IQX0/xY6F0vfXkEwD2vitJqGU+qlUqv5HzSuBqgnKTqCwHYP7pFlZA0nb/wydYkgPWtHMpyTgp+8zgAJ+a83STNNXXc9nSfpQkA14YWk3nORmP34RG7ff63n3/Uf8Cwcd8u+OUaAO4dwx+UFPicTCvU5xApLm5buWDatKVbDl1w4XGwawEZqDjsNB6xJ3eumjt59pL1J9x4nHivkjKoNPKy95yk2tOvZENOUv1ZCXgkHVy3ZPa381bv/v06HolTa/1VxzadT85OIsWVE7vXLZo644cNe6+R4uSIUrKqTNtJO2LJIGbzZy3DlXV9+76ov5KjwcTDZJS4YWhjp0wIemLqeTJw/zrxCae8yF/r+V59+/Zto8yCarX+d9+3er72j3rl9Ie3+raXRb36viJ/SvRYcZ2MTk3vUlb+5O3b93lZUPKNaQfdZLL7/b/JJsetf3/93ZETpn+/cOr44QM7P1pKN7Bybd6bvO7YuZj4xHO/rp3/Zf+G+WRBuWf+M3v1L0cuJF48vHXZ9P88UUQ3tDwPRY5euOf0hdikK0d/Xjbt05dvUyAUbtj7y9nLt/52Lv7amf1bfhj1z7qFlNH/A4tNaQdBINQrAAAAAElFTkSuQmCC\" alt=\"Feathers Logo\"></a></p>\n      </footer>\n    </main>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/express/public/404.html",
    "content": "<html>\n  <head>\n    <title>Page Not Found</title>\n    <style>\n      * {\n        margin: 0;\n        padding: 0;\n        box-sizing: border-box;\n      }\n\n      html, body {\n        font-family: 'Helvetica Neue', 'Helevetica', 'Arial', 'sans-serif';\n        font-weight: 400;\n        font-size: 16px;\n        color: #333;\n      }\n\n      main {\n        margin-top: 100px;\n        padding: 20px;\n      }\n\n      img.logo {\n        display: inline-block;\n        width: 100px;\n      }\n\n      h1 {\n        font-weight: 100;\n        font-size: 8em;\n        margin-bottom: 10px;\n      }\n\n      h2 {\n        font-size: 2em;\n        font-weight: 100;\n      }\n\n      .center-text {\n        text-align: center;\n      }\n\n      footer {\n        position: absolute;\n        bottom: 0;\n        left: 0;\n        right: 0;\n        padding: 20px;\n      }\n\n      footer p {\n        font-weight: 300;\n        font-size: 20px;\n      }\n    </style>\n  </head>\n  <body>\n    <main class=\"container\">\n      <h1 id=\"error-code\" class=\"center-text\">404</h1>\n      <h2 id=\"error-message\" class=\"center-text\">Page Not Found</h2>\n      <footer>\n        <p class=\"center-text\">Powered by <a href=\"http://feathersjs.com\" target=\"_blank\" alt=\"Powered by Feathers\"><img class=\"logo\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAk4AAABkCAMAAABHL0++AAADAFBMVEUAAAD///+AgIBVVVVAQEAzMzNVVVVJSUlAQEA5OTkzMzNGRkZAQEA7Ozs3NzczMzNAQEA8PDw5OTk2NjYzMzM9PT06Ojo3Nzc1NTUzMzM7Ozs5OTk3Nzc1NTUzMzM6Ojo4ODg2NjY1NTUzMzM5OTk3Nzc2NjY0NDQzMzM4ODg3Nzc1NTU0NDQzMzM3Nzc2NjY1NTU0NDQzMzM3Nzc2NjY1NTU0NDQzMzM3Nzc2NjY1NTU0NDQzMzM2NjY1NTU1NTU0NDQzMzM2NjY1NTU1NTU0NDQzMzM2NjY1NTU0NDQ0NDQzMzM2NjY1NTU0NDQ0NDQzMzM2NjY1NTU0NDQ0NDQzMzM1NTU1NTU0NDQ0NDQzMzM1NTU1NTU0NDQ0NDQzMzM1NTU1NTU0NDQ0NDQzMzM1NTU1NTU0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzN4a/VhAAAA/3RSTlMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7rCNk1AAAYtElEQVR4Ae3de5iN5eL/8c9aM8MY50EO5FBCSaW2HEqhHaUk0m4QJZtd2mQcCoVdUeSgEhHalZxzjhByPkcOQs7kwAwGwxxm1nr/fnvNXDWHtdZzmNaM72Vef8/cfzzP+7rnnvt57uuRaaUe7Txi8rwVW37du+nHOV8P6VCvmP4aZMFc/Z+SxEblCnmo/08xZBK9uNcDztyccnOyonCnJbF4nFszZdywgT16DBw+fuq6KDwuzonIp6yBy2vsGpyb0/8lwU/NiAM4Ounl2kWUTnjdjl+dALg86VGHsgDW6CaQm1NY5CkgYU7HSvKhcueFScCBl0Nyc/IrN6fC/aKAja+Fy68S3bYCx7qE5ub0P0+vWdMkN6dMgrpegqT/VpMJNaYkw6kISbk5/RPa5eaUUZ3tED+2gkyqPCERlptqLzenm06hCW6YWkYWVJgDCYPz5OaUm1NG9x+EfY1k4L6OSufJQ7Clkozl5nRTeT2epHfyyL8aC+FZpRM6yMWlljKQm9NNJd9MOF5X/gUPSPS2J93gNIxyykBuTjePoutgQbhRcj8ASRxSRrcsg1l5c3NKkZtT2d0wQAaClwMXrxOlTJxDYGUhGcjN6eZwxzGSO8nIhwDb4bq86O5mewkpN6fcnMoeI66FjDzhBg4cg3h50yaRbQVzc8rNqehu4hrKSLEzANOABHnVNJHleXJzutlzyreO5BYyNAPg15+Aq/KurZvpztycbvKcZkInGfoHAIMBouVDJAzJzenmzul16C9DRc4AnBgDcEq+DMXdNDenmzmn++NZIGPjAOh3AeCwfHGuILpcbk43b06FDnE8XIbqugGudAZgj3wqdZZ1wbk53bQ5TSCprgw5tgAw5kcAv9fmMRd9cnO6WXOq4+YdGWuHR2MXAEvlxxCuVcjN6ebMKWg7+/LIUNjvAKx8E48Z8iPfUebm5nRz5tQVGslYakZtd+ExTv48A0/ldE55CgUpy4IKBgU+J0dBp7LIUSBMfwmnn3FCCuWTkcKXmCpjBaIAuFwLj0MGBS7ggDPHcqrxxoR1Z+OBuPP75n3YvqqdjGr1nrJky+EYN8SeObBsVKd6+WWok9Wcgh/sOXvDgahkXFH71s4Z8HCIrCvU/MN5B664ITnm5PqJPZvYzCr8iYGLdx05f529XhK7/59jlu655AISow5tWzai9R0O+dCP+DIy9jYeXwyEI7MGt3i8lfy6PYmInMnpkUlnyODw6L87ZMFtPRdeJqO42S94KapKlzSmwNdd0qviO6fQV36MJb1rS3sXlxXFuq1PIr34Jd1KyZ88Xbo0VXo1P/+NVJlzavzVeTKJWfZyfnkRFsVYGQs9j0e93UDSORcz5d837HJkf075uh/Ew3V0y8qFyzbsiibFvn/lk0n3TkvGw3XpyPb/P8jan0+78bj2WVFl0Bb/2vnKqcyg83gkHtiyYuHqPWcS8bg2qpzMqjkjAY/Lu9Yt+X7VtkNJeCR8da98KwwL0xXwymY8Lu1dPnPW7E+VVvCLO0lxYeeGFd//sGHPySukuDKhrjKJJKmCjL2Cx/GqpPpA/lVz0Ty7c8rzxhmA05M7VM+rVMXqdV1wFeB8R4dMqLcIIHnH2PZVnH8OXDnikz0AURkHedFeTnk/SAQ4Nr5VlWCluq39F7+6gYSJJWVGjbkASevfe6yUUoVUfXbUXgDmVjSZk6PzBYB9w1qWVmYdTwAc/OKl6vn1hxKP955yDIDFFZVe8Cn+KxNSGx0RSaoIGZjFxmzO6cHdwPXJj2XKJqTZYhewqaaMBA91Awe6FVZm9358HVhdWGlVeCGN8TDmhfQqeM2p1l4gfnJtZXTH6Fjg9MPyzxNkErCnZ+b0yr97GrjeP4+ZnGqsB+LHPihvwucCcePrKDPHw19cAq69Gay0noZqMlabFHV/JFUVGfgb3JmdOQUNcUHcqFLy6ra5QEJX+VduHfBDY4e8KzXODdvCs/yfXf9k4Lsy8qZI7wuQ1EMG7tsP7Ggur4I7RAGbyxvnNDAJWHi7vGrwO7jGlZUPoa/HAD+XUBoz2CgTRuJxskA8KS44ZGQ3H2ZjTkWXAfPLyqdnTwIz8suPx6Ihpq38ePQE7CyRtZwcnwC/N5cvt64Bo5d8nr8GF15yyJfiXwEXnjDIKWgicLCpvGsQD7sflB+lZwE7w9MMHcdrMuY4icfop0n1gwz15oQz23KqeBAuvSB/Cn7igvWF5NMDsfBTeflV+mdY7chKTs6J4B5bSL4FveuC4fLjHWBeSfnT8DdIau03p9C54B6YR97dGwPT8sm/FxLh5yJKpU4khMtYNVI0+4hUA2WojItG2ZVThaOwr4oM1L8MW8Plw62n4UunDITvh85ZyWksuP8l/553Qwf5NADcAxzyL+9UcL3sJyfHInB1lA+lT8N4GXouCdY4lGoJc2RCWzwSC2wg1WMytowx2ZRT2aOwupAM1b4M6/PIq0K7YF6QDFWJJ6a0/ZwiwP2qjPSGhIfkQz9IfF6GgqaAu5nvnN6EpDbyZSIsc8rYC8nQRilCYukoEz7AY3VoAimS8svYG+zLnpxCt8Lq/JK5nibKq69gVahMGALTbedU+Qru12Tsczjuo/tWkNRSMtfTlbt85VQ7iQTfw1R3cbm8TLZxNK88HoJKMqEbHm8/TKrNMqEGlMmWnCbDzvyS2Z5elRc1XEQVlRkFz5Jc3mZOzm0QaSqFTfC6vLknFtpJZns6VNB7TmFHoLV8mgf/kin5T0IvefTnqEwIqpYMwN96kGqITHCcp2125NQJYqvJpMYQW1GZLfJkZkpPeN9mThHwo0x5BE6FKrN8B2GSTApaA2O85xQJs+RT4USiQmROBEQH6X9+YpJMqN9nKsBF5zRSNZAZM5iUDTmVuwwvybQvYZkyeRR+CZI5d8AOezkF7eNaJZmzyPs8NgL2hsmsKnG463vLKfQ0UbfIpxfgU5m1Derpfy7zskwYeunBBOAHHSbFxWCZ8W92ZENOi+EbmVf0DEQooyXQUGYdwl3SVk7tIFIm3ePiXObA67i4frfM6wN7nV5y6goR8u0beERm9YX/SFIpqC0TdjB5MDCwGKm+kSmPEesIeE5Pw/4CsuA5+C0o8+R+SKaNgaa2cvqZTU6ZtRDqKgPHVugkC4K3Q3svOR1hrvzYiquAzLobNqTO8EVkrJgbRv0GTZ4kVQuZUg5uDXROzl3QVJbMgVeUXmv4UKb9G3rayakCPC7TXoWByqAVbJElNZM4HJIpp5pwn/w4zWGZd5TkIpI6c04mNAc4gLvou6S4FiZTHLH8PdA5tYOtsuZOOOhQOjOhpkxrBuPs5NSdQw6ZVgnWK72g/fC0rJkO7TLl9D6b5YfTxRqZ9zk8JGmEuV8agsd+LSPFdzJpO68HOqdf4RlZtJoMmYdc5ZDMuwdm2clpNb1lwQGSCmdaIW+XRQ1gXaac9tJB/rjYYG2B1lzSZKbIhNSKvnJcIkWETJrPu/ILdtSyIZ9S6e+wQ1a1zphDVZgq80rBchs5JboTisuCTzNNRevgWVm1H+7OkFM8l/LJn8vslnkdoaOkeYyTCWfxeL0yHmfmFJBJ3zJSfmFPdaXSAmgpq/JGkVhEaTSF/8i8grDRRk4wRVa0hy5KqybsdMiqSBiWISf4RH4dJ1rmNYO3JK1gmIzlJ0WDCGB9r9dayLTPmRDYnMq62O+QZR9B6wxr67YyL8huTs/JiqYwQGmNgzayLDyOA5lyaiC/lkNZmVYnJdgtDJCxO0lR/CNOzF1xDbeV2zZdfsHvw20omaaDAbLuTpiqNEZBLZkX7LaZUxlZ8WCGvUTnOWLDZN0MqJohp+T88mu0pfRvGT68laR9RMpYLTzO6Xs8Tsq0/nwf2KX4SqgiG85zyak/vfD++wVk3q3Yy+mYLLkNpimN+jBNNnSByAw5bZd//4DvZNVeeshYPTxW6ggei2XaABYGNKfiyeyUHfOhumyrZzOnqbKkEPyoND6GlrKhJnyXIacx8q9wIvGVZNEmBspYeTw+zefCo49MG8bUgObUEkbKjj7wimyLsJlTV1mTyDalsRNXUdkQFMvJDDm9KAMzYaEs+pHhMuaIAuBf95Cilkwbx/iA5jQEnpEdj8IXsm2+zZxqy5qr7NCf8iezQ7b8BGXS51RFBu4FRsuaOYw3k1MfAB5pgcdZh0ybwvCA5vQT7qKyIyyJDbKrqttmThWylNOj8LFsGQyN0+dUQEY+sd7T10yVsYjavwBU6IXHOJm3gIGBzMlxlaOyZyfnZVPIAmzmVDBLOfWGl2RLC+iSLqcEGcq7BZhRVhYMYZ2MvXm0/mVIDh6LRwOZ9wudA5lTGfhe9iyDQrIlbDE2c0pUlnL6AmrJlnowMl1OZ2SsyCYgtn8+mdaBKBkbxPYOCRzXYgAOOmSa4xqPBjKnuvCR7JkO98gG53O/QIy9nM5mLaeluAvIlmowJ11Oe2VC2HiA00OqW6g2XIbeg+iZrjXaDUB3mVceSgYypwjoLHvGQkNZFfxAr8PAqaqJtnL6NWs57ee07LkFVqfLaY1MabIDgO09q8qMYlBXhp4F4FvFAJwNk3mPE6NA5vQWPCN7BkFLCx2Vrf1ct+GrrgGw4XbZy2lT1nK6zg7ZEwy70uX0vcxxtFjuBuDIZ08VkKFoOspQ0GGAwQXB6lOnN9gc0Jw+gNqypwd0lG/BZR5o2vpfbw7+7NuFa3efvMofXKsaSzZz2pilnPLAEtl0hZMZjx6YdcdHJ/BI2jCoUaj8WsxXMlb/GvBqVS6s/qyZrPiOzwKa08fwZA17+kMXeVO6SY9Jm8668ObI9PYlpJzJyVNBDZtOc95eTh61PtxHiviVb9cNlk+9OCETbp8NLRtwt6xxRNMyoDmNJyteU0bOuoN3klnc2QNrpwzp0qCIPHIop9Jkhf2cPMr/c8YFUlxZ2LWqvHsAKsuMV3i4NcVlzX24wwOa02Sy4lWlF9rjDCkSDqyaNrLP6y+1bFy3RsXieZRRjuR0O1lxzjgnA877IudfIsWx8S0LKzPnRTrLjHbc0T3RIWt6sEMBzelr+HqMbQ8rreDOvwPEL+3bvEqQDORETpXg1zG2fWguJwPO+yPnXcAjaV3/6spoDgtkRneKfHBaFv3E8MDm9Cncpb9Gqa1A4n+bhclYzuQUDjNln/mcDDju6frdeTy29yitdCJIKiETBiU7Jv4ia8q7eTCwOb0PD+svcdcxcH19m4zlWE5BsCLnc0p1V9cfEwGSJ5VTGvku000mfB6luctlTT/2K7A59YLm+is8GgMH75Zu5JwUy47A52RekTZzk4G4YUX1p0lslQkz9mvNTFmzj34BzqkTdNBfoGQUbCyuGzyn3zkR0Jysu33MdeD4/eneeqghY8s3atcXsqQu7vIBzukf0Et/gYWwKJ9u9Jz2EhvgnKwrMRa4/qJSyXGAKTK2famOjJQl81miAOfUBD5Q1v0TTofrhs9pA+QNdE7WPXEKiFQqvUxyZRk6OkvnBsmKGm4eCXROtWCSsqz4VWgmK0LJiZwWwa03Xk4KXw7Jf1eqkGNMkKGYSbraT1ZMY60CnVNBN1uUZX1hsiwpnyM5DYOnbsCclH8jRFdUqi4kVpABh+tTubrLgmoungh4TjpIXLCy6gTuKrKkVo7k1AbeuRFzUtHdsEKpQk8xRwYKMjSU12TBUrYo8DnNhLtlR1B4eJhS1IDlsubpHMnpLpgtWwqGhzsCmJNui4OGShUBT8q/0vynKB1k3vO462RDTv2gnexoDm8qRQ+IlDUdcySnoOsckS07uOq0kNMX27Y6LO8nfyulWs6hUIP86FeaNjKtwO9MUDbk9CSMlB1DoZFSTIV7Zc3IHMlJm6GwbCiQzBpZyGkehMuSMsnEhChVtQQGya87efM2npNpHxNdLDtyKg0/yY61uIsoxRaSgmXN3pzJaRw0kA2PwSgrOX0Jd8ialWm3LweT3ED+1KBHdZrJrKZuOio7ctIZ4ovIujxxHFSqixyWNeXImZw6w1DZ0B/aWslpGNSRNR9AaylVni2cvkV+3EfP+2kik8pFM0fZk9NX0FHW1YZpSuGEVbKmYw7lVBFOOGTdD1DNSk59re9ItIbe+kOlSyxz+s2pVz0ayZzgdRwpkk05tYAVsq4v9FSKgvC9rJmZQzlpJ9SXZaExXHZayakzvCRrGsN7+lNLGCLf7qZfQ+rJnM9IqKVsyil/HK7SsspxCFcFpSgJM2VJ+NWcyuk9+FyWtYNJspJTMxgta+pkOPE4Ct6QT1V5twkPyJR3oKuyKydNg0hZ1RiWKFURmC9LBpFTOVWF6BBZtQHqWsop3M2vsqYBDFAazlm428iX0gx/huoyoxMMV/bl9Ahsl1VzoJWUKt7ibS56mRXJOZOTVkJzWXQP7JGlnLQDSsuSZ6G70sq7ksSm8iGUCa24XSa0SuYbRzbmpL0QIWvKJnM+REp1nMOy4l1omJhDOT0Pe4JlzVjobjGnkdBWlvSGlkqn0HYSfQ4SPbcNxWSsUzKLgpWdOXWAE2GyZAwM0x+2kFxI5hWNYY9859Q+oDkFH4SusqRCLPHFLObUDL6VJTOgstIrsQ13pLzbvOlld5AMvQ2LwpStOQXtg/dkRX030bekuxLNZJpjPnT2ldPL0CWgOakNXCwmK5bB+7KYU+EkEm+XBXkucsGpDAouh6FOefPp+U4xMhL8GXwTrOzNSa0grqLMy/db+jmkPYySaW/DtiBfObWAfoHNybETPpcFHWFfXqs5aaLF6ek5+NJLZDNgRUl58STv7pKBcutguEPZnZOWwjyZNwyWKo3wJM6FyaTGLpLula+cGsKwwOakh124asm0MjG4H5LlnCom4rrb2meWHldmziFuzj6mzJxH130p/56KJqGrlP05lb8C/WRWy+SMX9tcAT1lTsVo+EA+c7oPZgQ4J30MJ0rKpPxrYYys56RxsNghsyJhi7xqGo1rSD5l0iKpofwpMMrNkVrKiZzUEdwtZM7zSbg7KJ3WcK6gzKh5En4I8Z1TaCJnA51T2H7YkE+mFFgLuwvayenWePhYJjVJxt3Iz5+so88ok0Ly5/nfYU4R5UxOGg0Jz8mMiCR4XRmsgEVBMtYiFjbnl++ctBXuCnBOuuMCrDKVf6H1sPcW2clJbwFvy5S7YuB9+RLc5xosuF0WVFsK0R2lnMopaAkkd5Sx15KhmzKqEm9qfdvHDfuL63/i2SFvRsGYQOekhomw+RYZKr8J9pWUvZw0BugiE2oex/8D3wrzIOmbajKpxjQX7gnFlHM5Kf8S4Msw+VdpORCpzHoDY0PlV8XvgJXF5XGWKHlTzU3i7YHOSU9fhzON5J/jtSuwv5Ts5uScA8woISOd4+B4cfn11AFwzfqbTKg73w1b6kg5mZNCpgP7GskPZ7dYuNRG3vQBdt4p38JHJAAjgpRiK9SUN/NhT9FA56T6MeAaUVh+VF4FLLxFtnNS6CogKkJ+lZ4CbCtn2GbELmB37zLyq3y/fcDaJ6QczknOtxKBeT6TKNhlL7CkrLzr4oZrg26Rd6G9LwHREVKqIbChiLwodwp21Ql0Tqr6M3D+1bzyodZ/4+DyK1k7yRL8TgKw/LkQ+VJudBzwbaiMOZpvBFzL3qjhkFeO+3qsdIN7ySNSzuck/W0/wPKWIcqsxpgrQOyr8umpo0Dc55WV2f0fnwcSR6bpp/x1OPn2kzXLVKx5n9KpeR7cGz/s1v6Zp5q3atN1RGByUsjQZOD8kNuUWdhLWwBWVsjywah7tgOc+6iKvCjYanICcLm7TLrzw5MA52f8+7Fy6ZpylH/8je+iAfb3Ky/dGDkppGsUQOyiyLrF9IfQh3rNOQsQM+JW+RE6MA7g4IQX0/xY6F0vfXkEwD2vitJqGU+qlUqv5HzSuBqgnKTqCwHYP7pFlZA0nb/wydYkgPWtHMpyTgp+8zgAJ+a83STNNXXc9nSfpQkA14YWk3nORmP34RG7ff63n3/Uf8Cwcd8u+OUaAO4dwx+UFPicTCvU5xApLm5buWDatKVbDl1w4XGwawEZqDjsNB6xJ3eumjt59pL1J9x4nHivkjKoNPKy95yk2tOvZENOUv1ZCXgkHVy3ZPa381bv/v06HolTa/1VxzadT85OIsWVE7vXLZo644cNe6+R4uSIUrKqTNtJO2LJIGbzZy3DlXV9+76ov5KjwcTDZJS4YWhjp0wIemLqeTJw/zrxCae8yF/r+V59+/Zto8yCarX+d9+3er72j3rl9Ie3+raXRb36viJ/SvRYcZ2MTk3vUlb+5O3b93lZUPKNaQfdZLL7/b/JJsetf3/93ZETpn+/cOr44QM7P1pKN7Bybd6bvO7YuZj4xHO/rp3/Zf+G+WRBuWf+M3v1L0cuJF48vHXZ9P88UUQ3tDwPRY5euOf0hdikK0d/Xjbt05dvUyAUbtj7y9nLt/52Lv7amf1bfhj1z7qFlNH/A4tNaQdBINQrAAAAAElFTkSuQmCC\" alt=\"Feathers Logo\"></a></p>\n      </footer>\n    </main>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/express/public/default.html",
    "content": "<html>\n  <head>\n    <title>Internal Server Error</title>\n    <style>\n      * {\n        margin: 0;\n        padding: 0;\n        box-sizing: border-box;\n      }\n\n      html, body {\n        font-family: 'Helvetica Neue', 'Helevetica', 'Arial', 'sans-serif';\n        font-weight: 400;\n        font-size: 16px;\n        color: #333;\n      }\n\n      main {\n        margin-top: 100px;\n        padding: 20px;\n      }\n\n      img.logo {\n        display: inline-block;\n        width: 100px;\n      }\n\n      h1 {\n        font-weight: 100;\n        font-size: 8em;\n        margin-bottom: 10px;\n      }\n\n      h2 {\n        font-size: 2em;\n        font-weight: 100;\n      }\n\n      .center-text {\n        text-align: center;\n      }\n\n      footer {\n        position: absolute;\n        bottom: 0;\n        left: 0;\n        right: 0;\n        padding: 20px;\n      }\n\n      footer p {\n        font-weight: 300;\n        font-size: 20px;\n      }\n    </style>\n  </head>\n  <body>\n    <main class=\"container\">\n      <h1 id=\"error-code\" class=\"center-text\">Oh no!</h1>\n      <h2 id=\"error-message\" class=\"center-text\">Something went wrong</h2>\n      <footer>\n        <p class=\"center-text\">Powered by <a href=\"http://feathersjs.com\" target=\"_blank\" alt=\"Powered by Feathers\"><img class=\"logo\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAk4AAABkCAMAAABHL0++AAADAFBMVEUAAAD///+AgIBVVVVAQEAzMzNVVVVJSUlAQEA5OTkzMzNGRkZAQEA7Ozs3NzczMzNAQEA8PDw5OTk2NjYzMzM9PT06Ojo3Nzc1NTUzMzM7Ozs5OTk3Nzc1NTUzMzM6Ojo4ODg2NjY1NTUzMzM5OTk3Nzc2NjY0NDQzMzM4ODg3Nzc1NTU0NDQzMzM3Nzc2NjY1NTU0NDQzMzM3Nzc2NjY1NTU0NDQzMzM3Nzc2NjY1NTU0NDQzMzM2NjY1NTU1NTU0NDQzMzM2NjY1NTU1NTU0NDQzMzM2NjY1NTU0NDQ0NDQzMzM2NjY1NTU0NDQ0NDQzMzM2NjY1NTU0NDQ0NDQzMzM1NTU1NTU0NDQ0NDQzMzM1NTU1NTU0NDQ0NDQzMzM1NTU1NTU0NDQ0NDQzMzM1NTU1NTU0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM1NTU0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQ0NDQzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzM0NDQ0NDQzMzMzMzMzMzN4a/VhAAAA/3RSTlMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7rCNk1AAAYtElEQVR4Ae3de5iN5eL/8c9aM8MY50EO5FBCSaW2HEqhHaUk0m4QJZtd2mQcCoVdUeSgEhHalZxzjhByPkcOQs7kwAwGwxxm1nr/fnvNXDWHtdZzmNaM72Vef8/cfzzP+7rnnvt57uuRaaUe7Txi8rwVW37du+nHOV8P6VCvmP4aZMFc/Z+SxEblCnmo/08xZBK9uNcDztyccnOyonCnJbF4nFszZdywgT16DBw+fuq6KDwuzonIp6yBy2vsGpyb0/8lwU/NiAM4Ounl2kWUTnjdjl+dALg86VGHsgDW6CaQm1NY5CkgYU7HSvKhcueFScCBl0Nyc/IrN6fC/aKAja+Fy68S3bYCx7qE5ub0P0+vWdMkN6dMgrpegqT/VpMJNaYkw6kISbk5/RPa5eaUUZ3tED+2gkyqPCERlptqLzenm06hCW6YWkYWVJgDCYPz5OaUm1NG9x+EfY1k4L6OSufJQ7Clkozl5nRTeT2epHfyyL8aC+FZpRM6yMWlljKQm9NNJd9MOF5X/gUPSPS2J93gNIxyykBuTjePoutgQbhRcj8ASRxSRrcsg1l5c3NKkZtT2d0wQAaClwMXrxOlTJxDYGUhGcjN6eZwxzGSO8nIhwDb4bq86O5mewkpN6fcnMoeI66FjDzhBg4cg3h50yaRbQVzc8rNqehu4hrKSLEzANOABHnVNJHleXJzutlzyreO5BYyNAPg15+Aq/KurZvpztycbvKcZkInGfoHAIMBouVDJAzJzenmzul16C9DRc4AnBgDcEq+DMXdNDenmzmn++NZIGPjAOh3AeCwfHGuILpcbk43b06FDnE8XIbqugGudAZgj3wqdZZ1wbk53bQ5TSCprgw5tgAw5kcAv9fmMRd9cnO6WXOq4+YdGWuHR2MXAEvlxxCuVcjN6ebMKWg7+/LIUNjvAKx8E48Z8iPfUebm5nRz5tQVGslYakZtd+ExTv48A0/ldE55CgUpy4IKBgU+J0dBp7LIUSBMfwmnn3FCCuWTkcKXmCpjBaIAuFwLj0MGBS7ggDPHcqrxxoR1Z+OBuPP75n3YvqqdjGr1nrJky+EYN8SeObBsVKd6+WWok9Wcgh/sOXvDgahkXFH71s4Z8HCIrCvU/MN5B664ITnm5PqJPZvYzCr8iYGLdx05f529XhK7/59jlu655AISow5tWzai9R0O+dCP+DIy9jYeXwyEI7MGt3i8lfy6PYmInMnpkUlnyODw6L87ZMFtPRdeJqO42S94KapKlzSmwNdd0qviO6fQV36MJb1rS3sXlxXFuq1PIr34Jd1KyZ88Xbo0VXo1P/+NVJlzavzVeTKJWfZyfnkRFsVYGQs9j0e93UDSORcz5d837HJkf075uh/Ew3V0y8qFyzbsiibFvn/lk0n3TkvGw3XpyPb/P8jan0+78bj2WVFl0Bb/2vnKqcyg83gkHtiyYuHqPWcS8bg2qpzMqjkjAY/Lu9Yt+X7VtkNJeCR8da98KwwL0xXwymY8Lu1dPnPW7E+VVvCLO0lxYeeGFd//sGHPySukuDKhrjKJJKmCjL2Cx/GqpPpA/lVz0Ty7c8rzxhmA05M7VM+rVMXqdV1wFeB8R4dMqLcIIHnH2PZVnH8OXDnikz0AURkHedFeTnk/SAQ4Nr5VlWCluq39F7+6gYSJJWVGjbkASevfe6yUUoVUfXbUXgDmVjSZk6PzBYB9w1qWVmYdTwAc/OKl6vn1hxKP955yDIDFFZVe8Cn+KxNSGx0RSaoIGZjFxmzO6cHdwPXJj2XKJqTZYhewqaaMBA91Awe6FVZm9358HVhdWGlVeCGN8TDmhfQqeM2p1l4gfnJtZXTH6Fjg9MPyzxNkErCnZ+b0yr97GrjeP4+ZnGqsB+LHPihvwucCcePrKDPHw19cAq69Gay0noZqMlabFHV/JFUVGfgb3JmdOQUNcUHcqFLy6ra5QEJX+VduHfBDY4e8KzXODdvCs/yfXf9k4Lsy8qZI7wuQ1EMG7tsP7Ggur4I7RAGbyxvnNDAJWHi7vGrwO7jGlZUPoa/HAD+XUBoz2CgTRuJxskA8KS44ZGQ3H2ZjTkWXAfPLyqdnTwIz8suPx6Ihpq38ePQE7CyRtZwcnwC/N5cvt64Bo5d8nr8GF15yyJfiXwEXnjDIKWgicLCpvGsQD7sflB+lZwE7w9MMHcdrMuY4icfop0n1gwz15oQz23KqeBAuvSB/Cn7igvWF5NMDsfBTeflV+mdY7chKTs6J4B5bSL4FveuC4fLjHWBeSfnT8DdIau03p9C54B6YR97dGwPT8sm/FxLh5yJKpU4khMtYNVI0+4hUA2WojItG2ZVThaOwr4oM1L8MW8Plw62n4UunDITvh85ZyWksuP8l/553Qwf5NADcAxzyL+9UcL3sJyfHInB1lA+lT8N4GXouCdY4lGoJc2RCWzwSC2wg1WMytowx2ZRT2aOwupAM1b4M6/PIq0K7YF6QDFWJJ6a0/ZwiwP2qjPSGhIfkQz9IfF6GgqaAu5nvnN6EpDbyZSIsc8rYC8nQRilCYukoEz7AY3VoAimS8svYG+zLnpxCt8Lq/JK5nibKq69gVahMGALTbedU+Qru12Tsczjuo/tWkNRSMtfTlbt85VQ7iQTfw1R3cbm8TLZxNK88HoJKMqEbHm8/TKrNMqEGlMmWnCbDzvyS2Z5elRc1XEQVlRkFz5Jc3mZOzm0QaSqFTfC6vLknFtpJZns6VNB7TmFHoLV8mgf/kin5T0IvefTnqEwIqpYMwN96kGqITHCcp2125NQJYqvJpMYQW1GZLfJkZkpPeN9mThHwo0x5BE6FKrN8B2GSTApaA2O85xQJs+RT4USiQmROBEQH6X9+YpJMqN9nKsBF5zRSNZAZM5iUDTmVuwwvybQvYZkyeRR+CZI5d8AOezkF7eNaJZmzyPs8NgL2hsmsKnG463vLKfQ0UbfIpxfgU5m1Derpfy7zskwYeunBBOAHHSbFxWCZ8W92ZENOi+EbmVf0DEQooyXQUGYdwl3SVk7tIFIm3ePiXObA67i4frfM6wN7nV5y6goR8u0beERm9YX/SFIpqC0TdjB5MDCwGKm+kSmPEesIeE5Pw/4CsuA5+C0o8+R+SKaNgaa2cvqZTU6ZtRDqKgPHVugkC4K3Q3svOR1hrvzYiquAzLobNqTO8EVkrJgbRv0GTZ4kVQuZUg5uDXROzl3QVJbMgVeUXmv4UKb9G3rayakCPC7TXoWByqAVbJElNZM4HJIpp5pwn/w4zWGZd5TkIpI6c04mNAc4gLvou6S4FiZTHLH8PdA5tYOtsuZOOOhQOjOhpkxrBuPs5NSdQw6ZVgnWK72g/fC0rJkO7TLl9D6b5YfTxRqZ9zk8JGmEuV8agsd+LSPFdzJpO68HOqdf4RlZtJoMmYdc5ZDMuwdm2clpNb1lwQGSCmdaIW+XRQ1gXaac9tJB/rjYYG2B1lzSZKbIhNSKvnJcIkWETJrPu/ILdtSyIZ9S6e+wQ1a1zphDVZgq80rBchs5JboTisuCTzNNRevgWVm1H+7OkFM8l/LJn8vslnkdoaOkeYyTCWfxeL0yHmfmFJBJ3zJSfmFPdaXSAmgpq/JGkVhEaTSF/8i8grDRRk4wRVa0hy5KqybsdMiqSBiWISf4RH4dJ1rmNYO3JK1gmIzlJ0WDCGB9r9dayLTPmRDYnMq62O+QZR9B6wxr67YyL8huTs/JiqYwQGmNgzayLDyOA5lyaiC/lkNZmVYnJdgtDJCxO0lR/CNOzF1xDbeV2zZdfsHvw20omaaDAbLuTpiqNEZBLZkX7LaZUxlZ8WCGvUTnOWLDZN0MqJohp+T88mu0pfRvGT68laR9RMpYLTzO6Xs8Tsq0/nwf2KX4SqgiG85zyak/vfD++wVk3q3Yy+mYLLkNpimN+jBNNnSByAw5bZd//4DvZNVeeshYPTxW6ggei2XaABYGNKfiyeyUHfOhumyrZzOnqbKkEPyoND6GlrKhJnyXIacx8q9wIvGVZNEmBspYeTw+zefCo49MG8bUgObUEkbKjj7wimyLsJlTV1mTyDalsRNXUdkQFMvJDDm9KAMzYaEs+pHhMuaIAuBf95Cilkwbx/iA5jQEnpEdj8IXsm2+zZxqy5qr7NCf8iezQ7b8BGXS51RFBu4FRsuaOYw3k1MfAB5pgcdZh0ybwvCA5vQT7qKyIyyJDbKrqttmThWylNOj8LFsGQyN0+dUQEY+sd7T10yVsYjavwBU6IXHOJm3gIGBzMlxlaOyZyfnZVPIAmzmVDBLOfWGl2RLC+iSLqcEGcq7BZhRVhYMYZ2MvXm0/mVIDh6LRwOZ9wudA5lTGfhe9iyDQrIlbDE2c0pUlnL6AmrJlnowMl1OZ2SsyCYgtn8+mdaBKBkbxPYOCRzXYgAOOmSa4xqPBjKnuvCR7JkO98gG53O/QIy9nM5mLaeluAvIlmowJ11Oe2VC2HiA00OqW6g2XIbeg+iZrjXaDUB3mVceSgYypwjoLHvGQkNZFfxAr8PAqaqJtnL6NWs57ee07LkFVqfLaY1MabIDgO09q8qMYlBXhp4F4FvFAJwNk3mPE6NA5vQWPCN7BkFLCx2Vrf1ct+GrrgGw4XbZy2lT1nK6zg7ZEwy70uX0vcxxtFjuBuDIZ08VkKFoOspQ0GGAwQXB6lOnN9gc0Jw+gNqypwd0lG/BZR5o2vpfbw7+7NuFa3efvMofXKsaSzZz2pilnPLAEtl0hZMZjx6YdcdHJ/BI2jCoUaj8WsxXMlb/GvBqVS6s/qyZrPiOzwKa08fwZA17+kMXeVO6SY9Jm8668ObI9PYlpJzJyVNBDZtOc95eTh61PtxHiviVb9cNlk+9OCETbp8NLRtwt6xxRNMyoDmNJyteU0bOuoN3klnc2QNrpwzp0qCIPHIop9Jkhf2cPMr/c8YFUlxZ2LWqvHsAKsuMV3i4NcVlzX24wwOa02Sy4lWlF9rjDCkSDqyaNrLP6y+1bFy3RsXieZRRjuR0O1lxzjgnA877IudfIsWx8S0LKzPnRTrLjHbc0T3RIWt6sEMBzelr+HqMbQ8rreDOvwPEL+3bvEqQDORETpXg1zG2fWguJwPO+yPnXcAjaV3/6spoDgtkRneKfHBaFv3E8MDm9Cncpb9Gqa1A4n+bhclYzuQUDjNln/mcDDju6frdeTy29yitdCJIKiETBiU7Jv4ia8q7eTCwOb0PD+svcdcxcH19m4zlWE5BsCLnc0p1V9cfEwGSJ5VTGvku000mfB6luctlTT/2K7A59YLm+is8GgMH75Zu5JwUy47A52RekTZzk4G4YUX1p0lslQkz9mvNTFmzj34BzqkTdNBfoGQUbCyuGzyn3zkR0Jysu33MdeD4/eneeqghY8s3atcXsqQu7vIBzukf0Et/gYWwKJ9u9Jz2EhvgnKwrMRa4/qJSyXGAKTK2famOjJQl81miAOfUBD5Q1v0TTofrhs9pA+QNdE7WPXEKiFQqvUxyZRk6OkvnBsmKGm4eCXROtWCSsqz4VWgmK0LJiZwWwa03Xk4KXw7Jf1eqkGNMkKGYSbraT1ZMY60CnVNBN1uUZX1hsiwpnyM5DYOnbsCclH8jRFdUqi4kVpABh+tTubrLgmoungh4TjpIXLCy6gTuKrKkVo7k1AbeuRFzUtHdsEKpQk8xRwYKMjSU12TBUrYo8DnNhLtlR1B4eJhS1IDlsubpHMnpLpgtWwqGhzsCmJNui4OGShUBT8q/0vynKB1k3vO462RDTv2gnexoDm8qRQ+IlDUdcySnoOsckS07uOq0kNMX27Y6LO8nfyulWs6hUIP86FeaNjKtwO9MUDbk9CSMlB1DoZFSTIV7Zc3IHMlJm6GwbCiQzBpZyGkehMuSMsnEhChVtQQGya87efM2npNpHxNdLDtyKg0/yY61uIsoxRaSgmXN3pzJaRw0kA2PwSgrOX0Jd8ialWm3LweT3ED+1KBHdZrJrKZuOio7ctIZ4ovIujxxHFSqixyWNeXImZw6w1DZ0B/aWslpGNSRNR9AaylVni2cvkV+3EfP+2kik8pFM0fZk9NX0FHW1YZpSuGEVbKmYw7lVBFOOGTdD1DNSk59re9ItIbe+kOlSyxz+s2pVz0ayZzgdRwpkk05tYAVsq4v9FSKgvC9rJmZQzlpJ9SXZaExXHZayakzvCRrGsN7+lNLGCLf7qZfQ+rJnM9IqKVsyil/HK7SsspxCFcFpSgJM2VJ+NWcyuk9+FyWtYNJspJTMxgta+pkOPE4Ct6QT1V5twkPyJR3oKuyKydNg0hZ1RiWKFURmC9LBpFTOVWF6BBZtQHqWsop3M2vsqYBDFAazlm428iX0gx/huoyoxMMV/bl9Ahsl1VzoJWUKt7ibS56mRXJOZOTVkJzWXQP7JGlnLQDSsuSZ6G70sq7ksSm8iGUCa24XSa0SuYbRzbmpL0QIWvKJnM+REp1nMOy4l1omJhDOT0Pe4JlzVjobjGnkdBWlvSGlkqn0HYSfQ4SPbcNxWSsUzKLgpWdOXWAE2GyZAwM0x+2kFxI5hWNYY9859Q+oDkFH4SusqRCLPHFLObUDL6VJTOgstIrsQ13pLzbvOlld5AMvQ2LwpStOQXtg/dkRX030bekuxLNZJpjPnT2ldPL0CWgOakNXCwmK5bB+7KYU+EkEm+XBXkucsGpDAouh6FOefPp+U4xMhL8GXwTrOzNSa0grqLMy/db+jmkPYySaW/DtiBfObWAfoHNybETPpcFHWFfXqs5aaLF6ek5+NJLZDNgRUl58STv7pKBcutguEPZnZOWwjyZNwyWKo3wJM6FyaTGLpLula+cGsKwwOakh124asm0MjG4H5LlnCom4rrb2meWHldmziFuzj6mzJxH130p/56KJqGrlP05lb8C/WRWy+SMX9tcAT1lTsVo+EA+c7oPZgQ4J30MJ0rKpPxrYYys56RxsNghsyJhi7xqGo1rSD5l0iKpofwpMMrNkVrKiZzUEdwtZM7zSbg7KJ3WcK6gzKh5En4I8Z1TaCJnA51T2H7YkE+mFFgLuwvayenWePhYJjVJxt3Iz5+so88ok0Ly5/nfYU4R5UxOGg0Jz8mMiCR4XRmsgEVBMtYiFjbnl++ctBXuCnBOuuMCrDKVf6H1sPcW2clJbwFvy5S7YuB9+RLc5xosuF0WVFsK0R2lnMopaAkkd5Sx15KhmzKqEm9qfdvHDfuL63/i2SFvRsGYQOekhomw+RYZKr8J9pWUvZw0BugiE2oex/8D3wrzIOmbajKpxjQX7gnFlHM5Kf8S4Msw+VdpORCpzHoDY0PlV8XvgJXF5XGWKHlTzU3i7YHOSU9fhzON5J/jtSuwv5Ts5uScA8woISOd4+B4cfn11AFwzfqbTKg73w1b6kg5mZNCpgP7GskPZ7dYuNRG3vQBdt4p38JHJAAjgpRiK9SUN/NhT9FA56T6MeAaUVh+VF4FLLxFtnNS6CogKkJ+lZ4CbCtn2GbELmB37zLyq3y/fcDaJ6QczknOtxKBeT6TKNhlL7CkrLzr4oZrg26Rd6G9LwHREVKqIbChiLwodwp21Ql0Tqr6M3D+1bzyodZ/4+DyK1k7yRL8TgKw/LkQ+VJudBzwbaiMOZpvBFzL3qjhkFeO+3qsdIN7ySNSzuck/W0/wPKWIcqsxpgrQOyr8umpo0Dc55WV2f0fnwcSR6bpp/x1OPn2kzXLVKx5n9KpeR7cGz/s1v6Zp5q3atN1RGByUsjQZOD8kNuUWdhLWwBWVsjywah7tgOc+6iKvCjYanICcLm7TLrzw5MA52f8+7Fy6ZpylH/8je+iAfb3Ky/dGDkppGsUQOyiyLrF9IfQh3rNOQsQM+JW+RE6MA7g4IQX0/xY6F0vfXkEwD2vitJqGU+qlUqv5HzSuBqgnKTqCwHYP7pFlZA0nb/wydYkgPWtHMpyTgp+8zgAJ+a83STNNXXc9nSfpQkA14YWk3nORmP34RG7ff63n3/Uf8Cwcd8u+OUaAO4dwx+UFPicTCvU5xApLm5buWDatKVbDl1w4XGwawEZqDjsNB6xJ3eumjt59pL1J9x4nHivkjKoNPKy95yk2tOvZENOUv1ZCXgkHVy3ZPa381bv/v06HolTa/1VxzadT85OIsWVE7vXLZo644cNe6+R4uSIUrKqTNtJO2LJIGbzZy3DlXV9+76ov5KjwcTDZJS4YWhjp0wIemLqeTJw/zrxCae8yF/r+V59+/Zto8yCarX+d9+3er72j3rl9Ie3+raXRb36viJ/SvRYcZ2MTk3vUlb+5O3b93lZUPKNaQfdZLL7/b/JJsetf3/93ZETpn+/cOr44QM7P1pKN7Bybd6bvO7YuZj4xHO/rp3/Zf+G+WRBuWf+M3v1L0cuJF48vHXZ9P88UUQ3tDwPRY5euOf0hdikK0d/Xjbt05dvUyAUbtj7y9nLt/52Lv7amf1bfhj1z7qFlNH/A4tNaQdBINQrAAAAAElFTkSuQmCC\" alt=\"Feathers Logo\"></a></p>\n      </footer>\n    </main>\n  </body>\n</html>\n"
  },
  {
    "path": "packages/express/src/authentication.ts",
    "content": "import { RequestHandler, Request, Response } from 'express'\nimport { HookContext } from '@feathersjs/feathers'\nimport { createDebug } from '@feathersjs/commons'\nimport { authenticate as AuthenticateHook } from '@feathersjs/authentication'\n\nimport { Application } from './declarations'\n\nconst debug = createDebug('@feathersjs/express/authentication')\n\nconst toHandler = (\n  func: (req: Request, res: Response, next: () => void) => Promise<void>\n): RequestHandler => {\n  return (req, res, next) => func(req, res, next).catch((error) => next(error))\n}\n\nexport type AuthenticationSettings = {\n  service?: string\n  strategies?: string[]\n}\n\nexport function parseAuthentication(settings: AuthenticationSettings = {}): RequestHandler {\n  return toHandler(async (req, res, next) => {\n    const app = req.app as any as Application\n    const service = app.defaultAuthentication?.(settings.service)\n\n    if (!service) {\n      return next()\n    }\n\n    const config = service.configuration\n    const authStrategies = settings.strategies || config.parseStrategies || config.authStrategies || []\n\n    if (authStrategies.length === 0) {\n      debug('No `authStrategies` or `parseStrategies` found in authentication configuration')\n      return next()\n    }\n\n    const authentication = await service.parse(req, res, ...authStrategies)\n\n    if (authentication) {\n      debug('Parsed authentication from HTTP header', authentication)\n      req.feathers = { ...req.feathers, authentication }\n    }\n\n    return next()\n  })\n}\n\nexport function authenticate(\n  settings: string | AuthenticationSettings,\n  ...strategies: string[]\n): RequestHandler {\n  const hook = AuthenticateHook(settings, ...strategies)\n\n  return toHandler(async (req, _res, next) => {\n    const app = req.app as any as Application\n    const params = req.feathers\n    const context = { app, params } as any as HookContext\n\n    await hook(context)\n\n    req.feathers = context.params\n\n    return next()\n  })\n}\n"
  },
  {
    "path": "packages/express/src/declarations.ts",
    "content": "import http from 'http'\nimport express, { Express } from 'express'\nimport {\n  Application as FeathersApplication,\n  Params as FeathersParams,\n  HookContext,\n  ServiceMethods,\n  ServiceInterface,\n  RouteLookup\n} from '@feathersjs/feathers'\n\ninterface ExpressUseHandler<T, Services> {\n  <L extends keyof Services & string>(\n    path: L,\n    ...middlewareOrService: (\n      | Express\n      | express.RequestHandler\n      | express.RequestHandler[]\n      | (keyof any extends keyof Services ? ServiceInterface : Services[L])\n    )[]\n  ): T\n  (path: string | RegExp, ...expressHandlers: express.RequestHandler[]): T\n  (...expressHandlers: express.RequestHandler[]): T\n  (handler: Express | express.ErrorRequestHandler): T\n}\n\nexport interface ExpressOverrides<Services> {\n  listen(port: number, hostname: string, backlog: number, callback?: () => void): Promise<http.Server>\n  listen(port: number, hostname: string, callback?: () => void): Promise<http.Server>\n  listen(port: number | string | any, callback?: () => void): Promise<http.Server>\n  listen(callback?: () => void): Promise<http.Server>\n  use: ExpressUseHandler<this, Services>\n  server?: http.Server\n}\n\nexport type Application<Services = any, Settings = any> = Omit<Express, 'listen' | 'use' | 'get' | 'set'> &\n  FeathersApplication<Services, Settings> &\n  ExpressOverrides<Services>\n\ndeclare module '@feathersjs/feathers/lib/declarations' {\n  interface ServiceOptions {\n    express?: {\n      before?: express.RequestHandler[]\n      after?: express.RequestHandler[]\n      composed?: express.RequestHandler\n    }\n  }\n}\n\ndeclare module 'express-serve-static-core' {\n  interface Request {\n    feathers: Partial<FeathersParams> & { [key: string]: any }\n    lookup?: RouteLookup\n  }\n\n  interface Response {\n    data?: any\n    hook?: HookContext\n  }\n\n  interface IRouterMatcher<T> {\n    // eslint-disable-next-line\n    <P extends Params = ParamsDictionary, ResBody = any, ReqBody = any>(\n      path: PathParams,\n      ...handlers: (RequestHandler<P, ResBody, ReqBody> | Partial<ServiceMethods> | Application)[]\n    ): T\n  }\n}\n"
  },
  {
    "path": "packages/express/src/handlers.ts",
    "content": "import path from 'path'\nimport { NotFound, GeneralError } from '@feathersjs/errors'\nimport { Request, Response, NextFunction, ErrorRequestHandler, RequestHandler } from 'express'\n\nconst defaults = {\n  public: path.resolve(__dirname, '..', 'public'),\n  logger: console\n}\nconst defaultHtmlError = path.resolve(defaults.public, 'default.html')\n\nexport function notFound({ verbose = false } = {}): RequestHandler {\n  return function (req: Request, _res: Response, next: NextFunction) {\n    const url = `${req.url}`\n    const message = `Page not found${verbose ? ': ' + url : ''}`\n\n    next(new NotFound(message, { url }))\n  }\n}\n\nexport type ErrorHandlerOptions = {\n  public?: string\n  logger?: boolean | { error?: (msg: any) => void; info?: (msg: any) => void }\n  html?: any\n  json?: any\n}\n\nexport function errorHandler(_options: ErrorHandlerOptions = {}): ErrorRequestHandler {\n  const options = Object.assign({}, defaults, _options)\n\n  if (typeof options.html === 'undefined') {\n    options.html = {\n      401: path.resolve(options.public, '401.html'),\n      404: path.resolve(options.public, '404.html'),\n      default: defaultHtmlError\n    }\n  }\n\n  if (typeof options.json === 'undefined') {\n    options.json = {}\n  }\n\n  return function (error: any, req: Request, res: Response, next: NextFunction) {\n    // Set the error code for HTTP processing semantics\n    error.code = !isNaN(parseInt(error.code, 10)) ? parseInt(error.code, 10) : 500\n\n    // Log the error if it didn't come from a service method call\n    if (options.logger && typeof options.logger.error === 'function' && !res.hook) {\n      if (error.code >= 500) {\n        options.logger.error(error)\n      } else {\n        options.logger.info(error)\n      }\n    }\n\n    if (error.type !== 'FeathersError') {\n      const oldError = error\n\n      error = oldError.errors\n        ? new GeneralError(oldError.message, {\n            errors: oldError.errors\n          })\n        : new GeneralError(oldError.message)\n\n      if (oldError.stack) {\n        error.stack = oldError.stack\n      }\n    }\n\n    const formatter: { [key: string]: any } = {}\n\n    // If the developer passed a custom function for ALL html errors\n    if (typeof options.html === 'function') {\n      formatter['text/html'] = options.html\n    } else {\n      let file = options.html[error.code]\n      if (!file) {\n        file = options.html.default || defaultHtmlError\n      }\n      // If the developer passed a custom function for individual html errors\n      if (typeof file === 'function') {\n        formatter['text/html'] = file\n      } else {\n        formatter['text/html'] = function () {\n          res.set('Content-Type', 'text/html')\n          res.sendFile(file)\n        }\n      }\n    }\n\n    // If the developer passed a custom function for ALL json errors\n    if (typeof options.json === 'function') {\n      formatter['application/json'] = options.json\n    } else {\n      const handler = options.json[error.code] || options.json.default\n      // If the developer passed a custom function for individual json errors\n      if (typeof handler === 'function') {\n        formatter['application/json'] = handler\n      } else {\n        // Don't show stack trace if it is a 404 error\n        if (error.code === 404) {\n          error.stack = null\n        }\n\n        formatter['application/json'] = function () {\n          const output = Object.assign({}, error.toJSON())\n\n          if (process.env.NODE_ENV === 'production') {\n            delete output.stack\n          }\n\n          res.set('Content-Type', 'application/json')\n          res.json(output)\n        }\n      }\n    }\n\n    res.status(error.code)\n\n    const contentType = req.headers['content-type'] || ''\n    const accepts = req.headers.accept || ''\n\n    // by default just send back json\n    if (contentType.indexOf('json') !== -1 || accepts.indexOf('json') !== -1) {\n      formatter['application/json'](error, req, res, next)\n    } else if (options.html && (contentType.indexOf('html') !== -1 || accepts.indexOf('html') !== -1)) {\n      formatter['text/html'](error, req, res, next)\n    } else {\n      // TODO (EK): Maybe just return plain text\n      formatter['application/json'](error, req, res, next)\n    }\n  }\n}\n"
  },
  {
    "path": "packages/express/src/index.ts",
    "content": "import express, { Express } from 'express'\nimport { Application as FeathersApplication, defaultServiceMethods } from '@feathersjs/feathers'\nimport { routing } from '@feathersjs/transport-commons'\nimport { createDebug } from '@feathersjs/commons'\nimport cors from 'cors'\nimport compression from 'compression'\n\nimport { rest, RestOptions, formatter } from './rest'\nimport { errorHandler, notFound, ErrorHandlerOptions } from './handlers'\nimport { Application, ExpressOverrides } from './declarations'\nimport { AuthenticationSettings, authenticate, parseAuthentication } from './authentication'\nimport {\n  default as original,\n  static as serveStatic,\n  json,\n  raw,\n  text,\n  urlencoded,\n  query,\n  Router\n} from 'express'\n\nexport {\n  original,\n  serveStatic,\n  serveStatic as static,\n  json,\n  raw,\n  text,\n  urlencoded,\n  query,\n  rest,\n  Router,\n  RestOptions,\n  formatter,\n  errorHandler,\n  notFound,\n  Application,\n  ErrorHandlerOptions,\n  ExpressOverrides,\n  AuthenticationSettings,\n  parseAuthentication,\n  authenticate,\n  cors,\n  compression\n}\n\nconst debug = createDebug('@feathersjs/express')\n\nexport default function feathersExpress<S = any, C = any>(\n  feathersApp?: FeathersApplication<S, C>,\n  expressApp: Express = express()\n): Application<S, C> {\n  if (!feathersApp) {\n    return expressApp as any\n  }\n\n  if (typeof feathersApp.setup !== 'function') {\n    throw new Error('@feathersjs/express requires a valid Feathers application instance')\n  }\n\n  const app = expressApp as any as Application<S, C>\n  const { use: expressUse, listen: expressListen } = expressApp as any\n  const { use: feathersUse, teardown: feathersTeardown } = feathersApp\n\n  Object.assign(app, {\n    use(location: string & keyof S, ...rest: any[]) {\n      let service: any\n      let options = {}\n\n      const middleware = rest.reduce(\n        function (middleware, arg) {\n          if (typeof arg === 'function' || Array.isArray(arg)) {\n            middleware[service ? 'after' : 'before'].push(arg)\n          } else if (!service) {\n            service = arg\n          } else if (arg.methods || arg.events || arg.express || arg.koa) {\n            options = arg\n          } else {\n            throw new Error('Invalid options passed to app.use')\n          }\n          return middleware\n        },\n        {\n          before: [],\n          after: []\n        }\n      )\n\n      const hasMethod = (methods: string[]) =>\n        methods.some((name) => service && typeof service[name] === 'function')\n\n      // Check for service (any object with at least one service method)\n      if (hasMethod(['handle', 'set']) || !hasMethod(defaultServiceMethods)) {\n        debug('Passing app.use call to Express app')\n        return expressUse.call(this, location, ...rest)\n      }\n\n      debug('Registering service with middleware', middleware)\n      // Since this is a service, call Feathers `.use`\n      feathersUse.call(this, location, service, {\n        express: middleware,\n        ...options\n      })\n\n      return this\n    },\n\n    async listen(...args: any[]) {\n      const server = expressListen.call(this, ...args)\n\n      this.server = server\n      await this.setup(server)\n      debug('Feathers application listening')\n\n      return server\n    }\n  } as Application<S, C>)\n\n  const appDescriptors = {\n    ...Object.getOwnPropertyDescriptors(Object.getPrototypeOf(app)),\n    ...Object.getOwnPropertyDescriptors(app)\n  }\n  const newDescriptors = {\n    ...Object.getOwnPropertyDescriptors(Object.getPrototypeOf(feathersApp)),\n    ...Object.getOwnPropertyDescriptors(feathersApp)\n  }\n\n  // Copy all non-existing properties (including non-enumerables)\n  // that don't already exist on the Express app\n  Object.keys(newDescriptors).forEach((prop) => {\n    const appProp = appDescriptors[prop]\n    const newProp = newDescriptors[prop]\n\n    if (appProp === undefined && newProp !== undefined) {\n      Object.defineProperty(expressApp, prop, newProp)\n    }\n  })\n\n  // Assign teardown and setup which will also make sure that hooks are initialized\n  app.setup = feathersApp.setup as any\n  app.teardown = async function teardown(server?: any) {\n    return feathersTeardown.call(this, server).then(\n      () =>\n        new Promise((resolve, reject) => {\n          if (this.server) {\n            this.server.close((e) => (e ? reject(e) : resolve(this)))\n          } else {\n            resolve(this)\n          }\n        })\n    )\n  }\n\n  app.configure(routing() as any)\n  app.use((req, _res, next) => {\n    req.feathers = { ...req.feathers, provider: 'rest' }\n    return next()\n  })\n\n  return app\n}\n\nif (typeof module !== 'undefined') {\n  module.exports = Object.assign(feathersExpress, module.exports)\n}\n"
  },
  {
    "path": "packages/express/src/rest.ts",
    "content": "import { Request, Response, RequestHandler, Router } from 'express'\nimport { MethodNotAllowed } from '@feathersjs/errors'\nimport { createDebug } from '@feathersjs/commons'\nimport { http } from '@feathersjs/transport-commons'\nimport { createContext, defaultServiceMethods, getServiceOptions } from '@feathersjs/feathers'\n\nimport { AuthenticationSettings, parseAuthentication } from './authentication'\nimport { Application } from './declarations'\n\nconst debug = createDebug('@feathersjs/express/rest')\n\nconst toHandler = (\n  func: (req: Request, res: Response, next: () => void) => Promise<void>\n): RequestHandler => {\n  return (req, res, next) => func(req, res, next).catch((error) => next(error))\n}\n\nconst serviceMiddleware = (): RequestHandler => {\n  return toHandler(async (req, res, next) => {\n    const { query, headers, path, body: data, method: httpMethod } = req\n    const methodOverride = req.headers[http.METHOD_HEADER] as string | undefined\n\n    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n    const { service, params: { __id: id = null, ...route } = {} } = req.lookup!\n    const method = http.getServiceMethod(httpMethod, id, methodOverride)\n    const { methods } = getServiceOptions(service)\n\n    debug(`Found service for path ${path}, attempting to run '${method}' service method`)\n\n    if (!methods.includes(method) || defaultServiceMethods.includes(methodOverride)) {\n      const error = new MethodNotAllowed(`Method \\`${method}\\` is not supported by this endpoint.`)\n      res.statusCode = error.code\n      throw error\n    }\n\n    const createArguments = http.argumentsFor[method as 'get'] || http.argumentsFor.default\n    const params = { query, headers, route, ...req.feathers }\n    const args = createArguments({ id, data, params })\n    const contextBase = createContext(service, method, { http: {} })\n    res.hook = contextBase\n\n    const context = await (service as any)[method](...args, contextBase)\n    res.hook = context\n\n    const response = http.getResponse(context)\n    res.statusCode = response.status\n    res.set(response.headers)\n    res.data = response.body\n\n    return next()\n  })\n}\n\nconst servicesMiddleware = (): RequestHandler => {\n  return toHandler(async (req, res, next) => {\n    const app = req.app as any as Application\n    const lookup = app.lookup(req.path)\n\n    if (!lookup) {\n      return next()\n    }\n\n    req.lookup = lookup\n\n    const options = getServiceOptions(lookup.service)\n    const middleware = options.express.composed\n\n    return middleware(req, res, next)\n  })\n}\n\nexport const formatter: RequestHandler = (_req, res, next) => {\n  if (res.data === undefined) {\n    return next()\n  }\n\n  res.format({\n    'application/json'() {\n      res.json(res.data)\n    }\n  })\n}\n\nexport type RestOptions = {\n  formatter?: RequestHandler\n  authentication?: AuthenticationSettings\n}\n\nexport const rest = (options?: RestOptions | RequestHandler) => {\n  options = typeof options === 'function' ? { formatter: options } : options || {}\n\n  const formatterMiddleware = options.formatter || formatter\n  const authenticationOptions = options.authentication\n\n  return (app: Application) => {\n    if (typeof app.route !== 'function') {\n      throw new Error('@feathersjs/express/rest needs an Express compatible app.')\n    }\n\n    app.use(parseAuthentication(authenticationOptions))\n    app.use(servicesMiddleware())\n\n    app.mixins.push((_service, _path, options) => {\n      const { express: { before = [], after = [] } = {} } = options\n\n      const middlewares = [].concat(before, serviceMiddleware(), after, formatterMiddleware)\n      const middleware = Router().use(middlewares)\n\n      options.express ||= {}\n      options.express.composed = middleware\n    })\n  }\n}\n"
  },
  {
    "path": "packages/express/test/authentication.test.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport omit from 'lodash/omit'\nimport { strict as assert } from 'assert'\nimport { default as _axios } from 'axios'\nimport { feathers } from '@feathersjs/feathers'\nimport { createApplication } from '@feathersjs/authentication-local/test/fixture'\nimport { authenticate, AuthenticationResult } from '@feathersjs/authentication'\nimport * as express from '../src'\n\nconst expressify = express.default\nconst axios = _axios.create({\n  baseURL: 'http://localhost:9876/'\n})\n\ndescribe('@feathersjs/express/authentication', () => {\n  const email = 'expresstest@authentication.com'\n  const password = 'superexpress'\n\n  let app: express.Application\n  let user: any\n  let authResult: AuthenticationResult\n\n  before(async () => {\n    const expressApp = expressify(feathers()).use(express.json()).configure(express.rest())\n\n    app = createApplication(expressApp as any) as unknown as express.Application\n\n    await app.listen(9876)\n\n    app.use('/dummy', {\n      get(id, params) {\n        return Promise.resolve({ id, params })\n      }\n    })\n\n    // @ts-ignore\n    app.use('/protected', express.authenticate('jwt'), (req, res) => {\n      res.json(req.feathers.user)\n    })\n\n    app.use(\n      express.errorHandler({\n        logger: false\n      })\n    )\n\n    app.service('dummy').hooks({\n      before: [authenticate('jwt')]\n    })\n\n    const result = await app.service('users').create({ email, password })\n\n    user = result\n\n    const res = await axios.post<any>('/authentication', {\n      strategy: 'local',\n      password,\n      email\n    })\n\n    authResult = res.data\n  })\n\n  after(() => app.teardown())\n\n  describe('service authentication', () => {\n    it('successful local authentication', () => {\n      assert.ok(authResult.accessToken)\n      assert.deepStrictEqual(omit(authResult.authentication, 'payload'), {\n        strategy: 'local'\n      })\n      assert.strictEqual(authResult.user.email, email)\n      assert.strictEqual(authResult.user.password, undefined)\n    })\n\n    it('local authentication with wrong password fails', async () => {\n      try {\n        await axios.post<any>('/authentication', {\n          strategy: 'local',\n          password: 'wrong',\n          email\n        })\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        const { data } = error.response\n        assert.strictEqual(data.name, 'NotAuthenticated')\n        assert.strictEqual(data.message, 'Invalid login')\n      }\n    })\n\n    it('authenticating with JWT works but returns same accessToken', async () => {\n      const { accessToken } = authResult\n      const { data } = await axios.post<any>('/authentication', {\n        strategy: 'jwt',\n        accessToken\n      })\n\n      assert.strictEqual(data.accessToken, accessToken)\n      assert.strictEqual(data.authentication.strategy, 'jwt')\n      assert.strictEqual(data.authentication.payload.sub, user.id.toString())\n      assert.strictEqual(data.user.email, email)\n    })\n\n    it('can make a protected request with Authorization header', async () => {\n      const { accessToken } = authResult\n\n      const {\n        data,\n        data: { params }\n      } = await axios.get<any>('/dummy/dave', {\n        headers: {\n          Authorization: accessToken\n        }\n      })\n\n      assert.strictEqual(data.id, 'dave')\n      assert.deepStrictEqual(params.user, user)\n      assert.strictEqual(params.authentication.accessToken, accessToken)\n    })\n\n    it('errors when there are no authStrategies and parseStrategies', async () => {\n      const { accessToken } = authResult\n      app.get('authentication').authStrategies = []\n      delete app.get('authentication').parseStrategies\n\n      try {\n        await axios.get<any>('/dummy/dave', {\n          headers: {\n            Authorization: accessToken\n          }\n        })\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.response.data.name, 'NotAuthenticated')\n        app.get('authentication').authStrategies = ['jwt', 'local']\n      }\n    })\n\n    it('can make a protected request with Authorization header and bearer scheme', async () => {\n      const { accessToken } = authResult\n\n      const {\n        data,\n        data: { params }\n      } = await axios.get<any>('/dummy/dave', {\n        headers: {\n          Authorization: ` Bearer: ${accessToken}`\n        }\n      })\n\n      assert.strictEqual(data.id, 'dave')\n      assert.deepStrictEqual(params.user, user)\n      assert.strictEqual(params.authentication.accessToken, accessToken)\n    })\n  })\n\n  describe('authenticate middleware', () => {\n    it('errors without valid strategies', () => {\n      try {\n        // @ts-ignore\n        authenticate()\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.message, 'The authenticate hook needs at least one allowed strategy')\n      }\n    })\n\n    it('protected endpoint fails when JWT is not present', () => {\n      return axios\n        .get<any>('/protected')\n        .then(() => {\n          assert.fail('Should never get here')\n        })\n        .catch((error) => {\n          const { data } = error.response\n\n          assert.strictEqual(data.name, 'NotAuthenticated')\n          assert.strictEqual(data.message, 'Not authenticated')\n        })\n    })\n\n    it.skip('protected endpoint fails with invalid Authorization header', async () => {\n      try {\n        await axios.get<any>('/protected', {\n          headers: {\n            Authorization: 'Bearer: something wrong'\n          }\n        })\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        const { data } = error.response\n\n        assert.strictEqual(data.name, 'NotAuthenticated')\n        assert.strictEqual(data.message, 'Not authenticated')\n      }\n    })\n\n    it('can request protected endpoint with JWT present', async () => {\n      const { data } = await axios.get<any>('/protected', {\n        headers: {\n          Authorization: `Bearer ${authResult.accessToken}`\n        }\n      })\n\n      assert.strictEqual(data.email, user.email)\n      assert.strictEqual(data.id, user.id)\n      assert.strictEqual(data.password, user.password)\n    })\n  })\n})\n"
  },
  {
    "path": "packages/express/test/error-handler.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function */\nimport { strict as assert } from 'assert'\nimport express, { Request, Response, NextFunction } from 'express'\nimport axios from 'axios'\nimport fs from 'fs'\nimport { join } from 'path'\nimport { BadRequest, NotAcceptable, NotAuthenticated, NotFound, PaymentError } from '@feathersjs/errors'\n\nimport { errorHandler } from '../src'\n\nconst content = '<html><head></head><body>Error</body></html>'\n\nconst htmlHandler = function (_error: Error, _req: Request, res: Response, _next: NextFunction) {\n  res.send(content)\n}\n\nconst jsonHandler = function (error: Error, _req: Request, res: Response, _next: NextFunction) {\n  res.json(error)\n}\n\ndescribe('error-handler', () => {\n  describe('supports catch-all custom handlers', function () {\n    before(function () {\n      this.app = express()\n        .get('/error', function (_req: Request, _res: Response, next: NextFunction) {\n          next(new Error('Something went wrong'))\n        })\n        .use(\n          errorHandler({\n            html: htmlHandler,\n            json: jsonHandler\n          })\n        )\n\n      this.server = this.app.listen(5050)\n    })\n\n    after(function (done) {\n      this.server.close(done)\n    })\n\n    describe('JSON handler', () => {\n      const options = {\n        url: 'http://localhost:5050/error',\n        headers: {\n          'Content-Type': 'application/json',\n          Accept: 'application/json'\n        }\n      }\n\n      it('can send a custom response', async () => {\n        try {\n          await axios(options)\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.deepEqual(error.response.data, {\n            name: 'GeneralError',\n            message: 'Something went wrong',\n            code: 500,\n            className: 'general-error'\n          })\n        }\n      })\n    })\n  })\n\n  describe('supports error-code specific custom handlers', () => {\n    describe('HTML handler', () => {\n      const req = {\n        headers: { 'content-type': 'text/html' }\n      }\n      const makeRes = (errCode: number, props?: any) => {\n        return Object.assign(\n          {\n            set() {},\n            status(code: number) {\n              assert.equal(code, errCode)\n            }\n          },\n          props\n        )\n      }\n\n      it('if the value is a string, calls res.sendFile', (done) => {\n        const err = new NotAuthenticated()\n        const middleware = errorHandler({\n          logger: null,\n          html: { 401: 'path/to/401.html' }\n        })\n        const res = makeRes(401, {\n          sendFile(f: any) {\n            assert.equal(f, 'path/to/401.html')\n            done()\n          }\n        })\n        ;(middleware as any)(err, req, res)\n      })\n\n      it('if the value is a function, calls as middleware ', (done) => {\n        const err = new PaymentError()\n        const res = makeRes(402)\n        const middleware = errorHandler({\n          logger: null,\n          html: {\n            402: (_err: any, _req: any, _res: any) => {\n              assert.equal(_err, err)\n              assert.equal(_req, req)\n              assert.equal(_res, res)\n              done()\n            }\n          }\n        })\n        ;(middleware as any)(err, req, res)\n      })\n\n      it('falls back to default if error code config is available', (done) => {\n        const err = new NotAcceptable()\n        const res = makeRes(406)\n        const middleware = errorHandler({\n          logger: null,\n          html: {\n            default: (_err: any, _req: any, _res: any) => {\n              assert.equal(_err, err)\n              assert.equal(_req, req)\n              assert.equal(_res, res)\n              done()\n            }\n          }\n        })\n        ;(middleware as any)(err, req, res)\n      })\n    })\n\n    describe('JSON handler', () => {\n      const req = {\n        headers: { 'content-type': 'application/json' }\n      }\n      const makeRes = (errCode: number, props?: any) => {\n        return Object.assign(\n          {\n            set() {},\n            status(code: number) {\n              assert.equal(code, errCode)\n            }\n          },\n          props\n        )\n      }\n\n      it('calls res.json by default', (done) => {\n        const err = new NotAuthenticated()\n        const middleware = errorHandler({\n          logger: null,\n          json: {}\n        })\n        const res = makeRes(401, {\n          json(obj: any) {\n            assert.deepEqual(obj, err.toJSON())\n            done()\n          }\n        })\n        ;(middleware as any)(err, req, res)\n      })\n\n      it('if the value is a function, calls as middleware ', (done) => {\n        const err = new PaymentError()\n        const res = makeRes(402)\n        const middleware = errorHandler({\n          logger: null,\n          json: {\n            402: (_err: any, _req: any, _res: any) => {\n              assert.equal(_err, err)\n              assert.equal(_req, req)\n              assert.equal(_res, res)\n              done()\n            }\n          }\n        })\n        ;(middleware as any)(err, req, res)\n      })\n\n      it('falls back to default if error code config is available', (done) => {\n        const err = new NotAcceptable()\n        const res = makeRes(406)\n        const middleware = errorHandler({\n          logger: null,\n          json: {\n            default: (_err: any, _req: any, _res: any) => {\n              assert.equal(_err, err)\n              assert.equal(_req, req)\n              assert.equal(_res, res)\n              done()\n            }\n          }\n        })\n        ;(middleware as any)(err, req, res)\n      })\n    })\n  })\n\n  describe('use as app error handler', function () {\n    before(function () {\n      this.app = express()\n        .get('/error', function (_req: Request, _res: Response, next: NextFunction) {\n          next(new Error('Something went wrong'))\n        })\n        .get('/string-error', function (_req: Request, _res: Response, next: NextFunction) {\n          const e: any = new Error('Something was not found')\n          e.code = '404'\n\n          next(e)\n        })\n        .get('/bad-request', function (_req: Request, _res: Response, next: NextFunction) {\n          next(\n            new BadRequest({\n              message: 'Invalid Password',\n              errors: [\n                {\n                  path: 'password',\n                  value: null,\n                  message: \"'password' cannot be 'null'\"\n                }\n              ]\n            })\n          )\n        })\n        .use(function (_req: Request, _res: Response, next: NextFunction) {\n          next(new NotFound('File not found'))\n        })\n        .use(\n          errorHandler({\n            logger: null\n          })\n        )\n\n      this.server = this.app.listen(5050)\n    })\n\n    after(function (done) {\n      this.server.close(done)\n    })\n\n    describe('converts an non-feathers error', () => {\n      it('is an instance of GeneralError', async () => {\n        try {\n          await axios({\n            url: 'http://localhost:5050/error',\n            responseType: 'json'\n          })\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.equal(error.response.status, 500)\n          assert.deepEqual(error.response.data, {\n            name: 'GeneralError',\n            message: 'Something went wrong',\n            code: 500,\n            className: 'general-error'\n          })\n        }\n      })\n    })\n\n    describe('text/html format', () => {\n      it('serves a 404.html', (done) => {\n        fs.readFile(join(__dirname, '..', 'public', '404.html'), async function (_err, html) {\n          try {\n            await axios({\n              url: 'http://localhost:5050/path/to/nowhere',\n              headers: {\n                'Content-Type': 'text/html',\n                Accept: 'text/html'\n              }\n            })\n            assert.fail('Should never get here')\n          } catch (error: any) {\n            assert.equal(error.response.status, 404)\n            assert.equal(error.response.data, html.toString())\n            done()\n          }\n        })\n      })\n\n      it('serves a 500.html', (done) => {\n        fs.readFile(join(__dirname, '..', 'public', 'default.html'), async function (_err, html) {\n          try {\n            await axios({\n              url: 'http://localhost:5050/error',\n              headers: {\n                'Content-Type': 'text/html',\n                Accept: 'text/html'\n              }\n            })\n            assert.fail('Should never get here')\n          } catch (error: any) {\n            assert.equal(error.response.status, 500)\n            assert.equal(error.response.data, html.toString())\n            done()\n          }\n        })\n      })\n    })\n\n    describe('application/json format', () => {\n      it('500', async () => {\n        try {\n          await axios({\n            url: 'http://localhost:5050/error',\n            headers: {\n              'Content-Type': 'application/json',\n              Accept: 'application/json'\n            }\n          })\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.equal(error.response.status, 500)\n          assert.deepEqual(error.response.data, {\n            name: 'GeneralError',\n            message: 'Something went wrong',\n            code: 500,\n            className: 'general-error'\n          })\n        }\n      })\n\n      it('404', async () => {\n        try {\n          await axios({\n            url: 'http://localhost:5050/path/to/nowhere',\n            headers: {\n              'Content-Type': 'application/json',\n              Accept: 'application/json'\n            }\n          })\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.equal(error.response.status, 404)\n          assert.deepEqual(error.response.data, {\n            name: 'NotFound',\n            message: 'File not found',\n            code: 404,\n            className: 'not-found'\n          })\n        }\n      })\n\n      it('400', async () => {\n        try {\n          await axios({\n            url: 'http://localhost:5050/bad-request',\n            headers: {\n              'Content-Type': 'application/json',\n              Accept: 'application/json'\n            }\n          })\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          assert.equal(error.response.status, 400)\n          assert.deepEqual(error.response.data, {\n            name: 'BadRequest',\n            message: 'Invalid Password',\n            code: 400,\n            className: 'bad-request',\n            data: {},\n            errors: [\n              {\n                path: 'password',\n                value: null,\n                message: \"'password' cannot be 'null'\"\n              }\n            ]\n          })\n        }\n      })\n    })\n\n    it('returns JSON by default', async () => {\n      try {\n        await axios('http://localhost:5050/bad-request')\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.equal(error.response.status, 400)\n        assert.deepEqual(error.response.data, {\n          name: 'BadRequest',\n          message: 'Invalid Password',\n          code: 400,\n          className: 'bad-request',\n          data: {},\n          errors: [\n            {\n              path: 'password',\n              value: null,\n              message: \"'password' cannot be 'null'\"\n            }\n          ]\n        })\n      }\n    })\n  })\n})\n"
  },
  {
    "path": "packages/express/test/index.test.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport { strict as assert } from 'assert'\nimport express, { Request, Response, NextFunction } from 'express'\nimport axios from 'axios'\nimport fs from 'fs'\nimport path from 'path'\nimport https from 'https'\nimport { feathers, HookContext, Id } from '@feathersjs/feathers'\n\nimport { default as feathersExpress, rest, notFound, errorHandler, original, serveStatic } from '../src'\nimport { RequestListener } from 'http'\n\ndescribe('@feathersjs/express', () => {\n  const service = {\n    async get(id: Id) {\n      return { id }\n    }\n  }\n\n  it('exports .default, .original .rest, .notFound and .errorHandler', () => {\n    assert.strictEqual(original, express)\n    assert.strictEqual(typeof rest, 'function')\n    assert.ok(notFound)\n    assert.ok(errorHandler)\n  })\n\n  it('returns an Express application, keeps Feathers service and configuration typings typings', () => {\n    type Config = {\n      hostname: string\n      port: number\n    }\n\n    const app = feathersExpress<Record<string, any>, Config>(feathers())\n\n    app.set('hostname', 'test.com')\n\n    const hostname = app.get('hostname')\n\n    assert.strictEqual(hostname, 'test.com')\n    assert.strictEqual(typeof app, 'function')\n  })\n\n  it('allows to use an existing Express instance', () => {\n    const expressApp = express()\n    const app = feathersExpress(feathers(), expressApp)\n\n    assert.strictEqual(app, expressApp)\n  })\n\n  it('exports `express.rest`', () => {\n    assert.ok(typeof rest === 'function')\n  })\n\n  it('returns a plain express app when no app is provided', () => {\n    const app = feathersExpress()\n\n    assert.strictEqual(typeof app.use, 'function')\n    assert.strictEqual(typeof app.service, 'undefined')\n    assert.strictEqual(typeof app.services, 'undefined')\n  })\n\n  it('errors when app with wrong version is provided', () => {\n    try {\n      // @ts-ignore\n      feathersExpress({})\n    } catch (e: any) {\n      assert.strictEqual(e.message, '@feathersjs/express requires a valid Feathers application instance')\n    }\n\n    try {\n      const app = feathers()\n      app.version = '2.9.9'\n\n      feathersExpress(app)\n    } catch (e: any) {\n      assert.strictEqual(\n        e.message,\n        '@feathersjs/express requires an instance of a Feathers application version 3.x or later (got 2.9.9)'\n      )\n    }\n\n    try {\n      const app = feathers()\n      delete app.version\n\n      feathersExpress(app)\n    } catch (e: any) {\n      assert.strictEqual(\n        e.message,\n        '@feathersjs/express requires an instance of a Feathers application version 3.x or later (got unknown)'\n      )\n    }\n  })\n\n  it('Can use Express sub-apps', () => {\n    const typedApp = feathers<Record<string, unknown>>()\n    const app = feathersExpress(typedApp)\n    const child = express()\n\n    app.use('/path', child)\n    assert.strictEqual((child as any).parent, app)\n  })\n\n  it('Can use express.static', () => {\n    const app = feathersExpress(feathers())\n\n    app.use('/path', serveStatic(__dirname))\n  })\n\n  it('has Feathers functionality', async () => {\n    const app = feathersExpress(feathers())\n\n    app.use('/myservice', service)\n\n    app.hooks({\n      after: {\n        get(hook: HookContext) {\n          hook.result.fromAppHook = true\n        }\n      }\n    })\n\n    app.service('myservice').hooks({\n      after: {\n        get(hook: HookContext) {\n          hook.result.fromHook = true\n        }\n      }\n    })\n\n    const data = await app.service('myservice').get(10)\n\n    assert.deepStrictEqual(data, {\n      id: 10,\n      fromHook: true,\n      fromAppHook: true\n    })\n  })\n\n  it('can register a service and start an Express server', async () => {\n    const app = feathersExpress(feathers())\n    const response = {\n      message: 'Hello world'\n    }\n\n    app.use('/myservice', service)\n    app.use((_req: Request, res: Response) => res.json(response))\n\n    const server = await app.listen(8787)\n    const data = await app.service('myservice').get(10)\n\n    assert.deepStrictEqual(data, { id: 10 })\n\n    const res = await axios.get<any>('http://localhost:8787')\n    assert.deepStrictEqual(res.data, response)\n\n    await new Promise((resolve) => server.close(() => resolve(server)))\n  })\n\n  it('.listen calls .setup', async () => {\n    const app = feathersExpress(feathers())\n    let called = false\n\n    app.use('/myservice', {\n      async get(id: Id) {\n        return { id }\n      },\n\n      async setup(appParam, path) {\n        assert.strictEqual(appParam, app)\n        assert.strictEqual(path, 'myservice')\n        called = true\n      }\n    })\n\n    const server = await app.listen(8787)\n\n    assert.ok(called)\n    await new Promise((resolve) => server.close(() => resolve(server)))\n  })\n\n  it('.teardown closes http server', async () => {\n    const app = feathersExpress(feathers())\n    let called = false\n\n    const server = await app.listen(8787)\n    server.on('close', () => {\n      called = true\n    })\n\n    await app.teardown()\n    assert.ok(called)\n  })\n\n  it('passes middleware as options', () => {\n    const feathersApp = feathers()\n    const app = feathersExpress(feathersApp)\n    const oldUse = feathersApp.use\n    const a = (_req: Request, _res: Response, next: NextFunction) => next()\n    const b = (_req: Request, _res: Response, next: NextFunction) => next()\n    const c = (_req: Request, _res: Response, next: NextFunction) => next()\n    const service = {\n      async get(id: Id) {\n        return { id }\n      }\n    }\n\n    feathersApp.use = function (path, serviceArg, options) {\n      assert.strictEqual(path, '/myservice')\n      assert.strictEqual(serviceArg, service)\n      assert.deepStrictEqual(options.express, {\n        before: [a, b],\n        after: [c]\n      })\n      // eslint-disable-next-line prefer-rest-params\n      return (oldUse as any).apply(this, arguments)\n    }\n\n    app.use('/myservice', a, b, service, c)\n  })\n\n  it('Express wrapped and context.app are the same', async () => {\n    const app = feathersExpress(feathers())\n\n    app.use('/test', {\n      async get(id: Id) {\n        return { id }\n      }\n    })\n\n    app.service('test').hooks({\n      before: {\n        get: [\n          (context) => {\n            assert.ok(context.app === app)\n          }\n        ]\n      }\n    })\n\n    assert.deepStrictEqual(await app.service('test').get('testing'), {\n      id: 'testing'\n    })\n  })\n\n  it('Works with HTTPS', (done) => {\n    const todoService = {\n      async get(name: Id) {\n        return {\n          id: name,\n          description: `You have to do ${name}!`\n        }\n      }\n    }\n\n    const app = feathersExpress(feathers()).configure(rest())\n\n    app.use('/secureTodos', todoService)\n\n    const httpsServer = https\n      .createServer(\n        {\n          key: fs.readFileSync(path.join(__dirname, '..', '..', 'tests', 'resources', 'privatekey.pem')),\n          cert: fs.readFileSync(path.join(__dirname, '..', '..', 'tests', 'resources', 'certificate.pem')),\n          rejectUnauthorized: false,\n          requestCert: false\n        },\n        app as unknown as RequestListener\n      )\n      .listen(7889)\n\n    app.setup(httpsServer)\n\n    httpsServer.on('listening', function () {\n      const instance = axios.create({\n        httpsAgent: new https.Agent({\n          rejectUnauthorized: false\n        })\n      })\n\n      instance\n        .get<any>('https://localhost:7889/secureTodos/dishes')\n        .then((response) => {\n          assert.ok(response.status === 200, 'Got OK status code')\n          assert.strictEqual(response.data.description, 'You have to do dishes!')\n          httpsServer.close(() => done())\n        })\n        .catch(done)\n    })\n  })\n})\n"
  },
  {
    "path": "packages/express/test/not-found-handler.test.ts",
    "content": "import { strict as assert } from 'assert'\nimport { NotFound } from '@feathersjs/errors'\n\nimport { notFound } from '../src'\n\nconst handler = notFound as any\n\ndescribe('not-found-handler', () => {\n  it('returns NotFound error', (done) => {\n    handler()(\n      {\n        url: 'some/where',\n        headers: {}\n      },\n      {},\n      function (error: any) {\n        assert.ok(error instanceof NotFound)\n        assert.equal(error.message, 'Page not found')\n        assert.deepEqual(error.data, {\n          url: 'some/where'\n        })\n        done()\n      }\n    )\n  })\n\n  it('returns NotFound error with URL when verbose', (done) => {\n    handler({ verbose: true })(\n      {\n        url: 'some/where',\n        headers: {}\n      },\n      {},\n      function (error: any) {\n        assert.ok(error instanceof NotFound)\n        assert.equal(error.message, 'Page not found: some/where')\n        assert.deepEqual(error.data, {\n          url: 'some/where'\n        })\n        done()\n      }\n    )\n  })\n})\n"
  },
  {
    "path": "packages/express/test/rest.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unused-vars */\nimport { strict as assert } from 'assert'\nimport axios, { AxiosRequestConfig } from 'axios'\n\nimport { Server } from 'http'\nimport { Request, Response, NextFunction } from 'express'\nimport { ApplicationHookMap, feathers, HookContext, Id, Params } from '@feathersjs/feathers'\nimport { Service, restTests } from '@feathersjs/tests'\nimport { BadRequest } from '@feathersjs/errors'\n\nimport * as express from '../src'\n\nconst expressify = express.default\nconst { rest } = express\nconst errorHandler = express.errorHandler({\n  logger: false\n})\n\ndescribe('@feathersjs/express/rest provider', () => {\n  describe('base functionality', () => {\n    it('throws an error if you did not expressify', () => {\n      const app = feathers()\n\n      try {\n        app.configure(rest() as any)\n        assert.ok(false, 'Should never get here')\n      } catch (e: any) {\n        assert.strictEqual(e.message, '@feathersjs/express/rest needs an Express compatible app.')\n      }\n    })\n\n    it('lets you set the handler manually', async () => {\n      const app = expressify(feathers())\n\n      app\n        .configure(\n          rest(function (_req, res) {\n            res.format({\n              'text/plain'() {\n                res.end(`The todo is: ${res.data.description}`)\n              }\n            })\n          })\n        )\n        .use('/todo', {\n          async get(id: Id) {\n            return {\n              description: `You have to do ${id}`\n            }\n          }\n        })\n\n      const server = await app.listen(4776)\n\n      const res = await axios.get<any>('http://localhost:4776/todo/dishes')\n\n      assert.strictEqual(res.data, 'The todo is: You have to do dishes')\n      server.close()\n    })\n\n    it('lets you set no handler', async () => {\n      const app = expressify(feathers())\n      const data = { fromHandler: true }\n\n      app\n        .configure(rest(null))\n        .use('/todo', {\n          async get(id: Id) {\n            return {\n              description: `You have to do ${id}`\n            }\n          }\n        })\n        .use((_req: Request, res: Response) => res.json(data))\n\n      const server = await app.listen(5775)\n      const res = await axios.get<any>('http://localhost:5775/todo-handler/dishes')\n\n      assert.deepStrictEqual(res.data, data)\n\n      server.close()\n    })\n  })\n\n  describe('CRUD', () => {\n    let app: express.Application\n\n    before(async () => {\n      app = expressify(feathers())\n        .use(express.cors())\n        .use(express.json())\n        .configure(rest(express.formatter))\n        .use('codes', {\n          async get(id: Id) {\n            return { id }\n          },\n\n          async create(data: any) {\n            return data\n          }\n        })\n        .use('/', new Service())\n        .use('todo', new Service())\n\n      app.hooks({\n        setup: [\n          async (context, next) => {\n            assert.ok(context.app)\n            await next()\n          }\n        ],\n        teardown: [\n          async (context, next) => {\n            assert.ok(context.app)\n            await next()\n          }\n        ]\n      } as ApplicationHookMap<express.Application>)\n\n      await app.listen(4777, () => app.use('tasks', new Service()))\n    })\n\n    after(() => app.teardown())\n\n    restTests('Services', 'todo', 4777)\n    restTests('Root Service', '/', 4777)\n    restTests('Dynamic Services', 'tasks', 4777)\n\n    describe('res.hook', () => {\n      const convertHook = (hook: HookContext) => {\n        const result: any = Object.assign({}, hook.toJSON())\n\n        delete result.self\n        delete result.service\n        delete result.app\n        delete result.error\n\n        return result\n      }\n\n      it('sets the actual hook object in res.hook', async () => {\n        const params = {\n          route: {},\n          query: { test: 'param' },\n          provider: 'rest'\n        }\n\n        app.use(\n          '/hook',\n          {\n            async get(id) {\n              return {\n                description: `You have to do ${id}`\n              }\n            }\n          },\n          function (_req: Request, res: Response, next: NextFunction) {\n            res.data = convertHook(res.hook)\n\n            next()\n          }\n        )\n\n        app.service('hook').hooks({\n          after(hook: HookContext) {\n            hook.addedProperty = true\n          }\n        })\n\n        const res = await axios.get<any>('http://localhost:4777/hook/dishes?test=param')\n        const paramsWithHeaders = {\n          ...params,\n          headers: res.data.params.headers\n        }\n\n        assert.deepStrictEqual(res.data, {\n          id: 'dishes',\n          params: paramsWithHeaders,\n          arguments: ['dishes', paramsWithHeaders],\n          type: 'around',\n          method: 'get',\n          path: 'hook',\n          http: {},\n          event: null,\n          result: { description: 'You have to do dishes' },\n          addedProperty: true\n        })\n      })\n\n      it('can use hook.dispatch', async () => {\n        app.use('/hook-dispatch', {\n          async get() {\n            return {}\n          }\n        })\n\n        app.service('hook-dispatch').hooks({\n          after(hook: HookContext) {\n            hook.dispatch = {\n              id: hook.id,\n              fromDispatch: true\n            }\n          }\n        })\n\n        const res = await axios.get<any>('http://localhost:4777/hook-dispatch/dishes')\n        assert.deepStrictEqual(res.data, {\n          id: 'dishes',\n          fromDispatch: true\n        })\n      })\n\n      it('allows to set statusCode in a hook', async () => {\n        app.use('/hook-status', {\n          async get() {\n            return {}\n          }\n        })\n\n        app.service('hook-status').hooks({\n          after(hook: HookContext) {\n            hook.http.status = 206\n          }\n        })\n\n        const res = await axios.get<any>('http://localhost:4777/hook-status/dishes')\n\n        assert.strictEqual(res.status, 206)\n      })\n\n      it('allows to set response headers in a hook', async () => {\n        app.use('/hook-headers', {\n          async get() {\n            return {}\n          }\n        })\n\n        app.service('hook-headers').hooks({\n          after(hook: HookContext) {\n            hook.http.headers = { foo: 'first', bar: ['second', 'third'] }\n          }\n        })\n\n        const res = await axios.get<any>('http://localhost:4777/hook-headers/dishes')\n\n        assert.strictEqual(res.headers.foo, 'first')\n        assert.strictEqual(res.headers.bar, 'second, third')\n      })\n\n      it('sets the hook object in res.hook on error', async () => {\n        const params = {\n          route: {},\n          query: {},\n          provider: 'rest'\n        }\n\n        app.use('/hook-error', {\n          async get() {\n            throw new Error('I blew up')\n          }\n        })\n        app.use(function (error: Error, _req: Request, res: Response, _next: NextFunction) {\n          res.status(500)\n          res.json({\n            hook: convertHook(res.hook),\n            error: {\n              message: error.message\n            }\n          })\n        })\n\n        try {\n          await axios('http://localhost:4777/hook-error/dishes')\n          assert.fail('Should never get here')\n        } catch (error: any) {\n          const { data } = error.response\n          const paramsWithHeaders = {\n            ...params,\n            headers: data.hook.params.headers\n          }\n          assert.deepStrictEqual(error.response.data, {\n            hook: {\n              id: 'dishes',\n              params: paramsWithHeaders,\n              arguments: ['dishes', paramsWithHeaders],\n              type: 'around',\n              event: null,\n              method: 'get',\n              path: 'hook-error',\n              http: {}\n            },\n            error: { message: 'I blew up' }\n          })\n        }\n      })\n    })\n  })\n\n  describe('middleware', () => {\n    it('sets service parameters and provider type', async () => {\n      const service = {\n        async get(_id: Id, params: Params) {\n          return params\n        }\n      }\n\n      const app = expressify(feathers())\n        .use(function (req: Request, _res: Response, next: NextFunction) {\n          req.feathers.test = 'Happy'\n          next()\n        })\n        .configure(rest(express.formatter))\n        .use('service', service)\n      const server = await app.listen(4778)\n\n      const res = await axios.get<any>('http://localhost:4778/service/bla?some=param&another=thing')\n      const expected = {\n        headers: res.data.headers,\n        test: 'Happy',\n        provider: 'rest',\n        route: {},\n        query: {\n          some: 'param',\n          another: 'thing'\n        }\n      }\n\n      assert.ok(res.status === 200, 'Got OK status code')\n      assert.deepStrictEqual(res.data, expected, 'Got params object back')\n      server.close()\n    })\n\n    it('Lets you configure your own middleware before the handler (#40)', async () => {\n      const data = {\n        description: 'Do dishes!',\n        id: 'dishes'\n      }\n      const app = expressify(feathers())\n\n      app\n        .use(function defaultContentTypeMiddleware(req, _res, next) {\n          req.headers['content-type'] = req.headers['content-type'] || 'application/json'\n          next()\n        })\n        .use(express.json())\n        .configure(rest(express.formatter))\n        .use('/todo', {\n          async create(data: any) {\n            return data\n          }\n        })\n\n      const server = await app.listen(4775)\n      const res = await axios({\n        url: 'http://localhost:4775/todo',\n        method: 'post',\n        data,\n        headers: {\n          'content-type': ''\n        }\n      })\n\n      assert.deepStrictEqual(res.data, data)\n      server.close()\n    })\n\n    it('allows middleware before and after a service', async () => {\n      const app = expressify(feathers())\n\n      app\n        .use(express.json())\n        .configure(rest())\n        .use(\n          '/todo',\n          function (req, _res, next) {\n            req.body.before = ['before first']\n            next()\n          },\n          function (req, _res, next) {\n            req.body.before.push('before second')\n            next()\n          },\n          {\n            async create(data: any) {\n              return data\n            }\n          },\n          function (_req, res, next) {\n            res.data.after = ['after first']\n            next()\n          },\n          function (_req, res, next) {\n            res.data.after.push('after second')\n            next()\n          }\n        )\n\n      const server = await app.listen(4776)\n      const res = await axios.post<any>('http://localhost:4776/todo', {\n        text: 'Do dishes'\n      })\n\n      assert.deepStrictEqual(res.data, {\n        text: 'Do dishes',\n        before: ['before first', 'before second'],\n        after: ['after first', 'after second']\n      })\n\n      server.close()\n    })\n\n    it('allows middleware arrays before and after a service', async () => {\n      const app = expressify(feathers())\n\n      app.use(express.json())\n      app.configure(rest())\n      app.use(\n        '/todo',\n        [\n          function (req: Request, _res: Response, next: NextFunction) {\n            req.body.before = ['before first']\n            next()\n          },\n          function (req: Request, _res: Response, next: NextFunction) {\n            req.body.before.push('before second')\n            next()\n          }\n        ],\n        {\n          async create(data) {\n            return data\n          }\n        },\n        [\n          function (_req: Request, res: Response, next: NextFunction) {\n            res.data.after = ['after first']\n            next()\n          }\n        ],\n        function (_req: Request, res: Response, next: NextFunction) {\n          res.data.after.push('after second')\n          next()\n        }\n      )\n\n      const server = await app.listen(4776)\n      const res = await axios.post<any>('http://localhost:4776/todo', {\n        text: 'Do dishes'\n      })\n\n      assert.deepStrictEqual(res.data, {\n        text: 'Do dishes',\n        before: ['before first', 'before second'],\n        after: ['after first', 'after second']\n      })\n      server.close()\n    })\n\n    it('allows an array of middleware without a service', async () => {\n      const app = expressify(feathers())\n      const middlewareArray = [\n        function (_req: Request, res: Response, next: NextFunction) {\n          res.data = ['first']\n          next()\n        },\n        function (_req: Request, res: Response, next: NextFunction) {\n          res.data.push('second')\n          next()\n        },\n        function (req: Request, res: Response) {\n          res.data.push(req.body.text)\n          res.status(200).json(res.data)\n        }\n      ]\n      app.use(express.json()).configure(rest()).use('/array-middleware', middlewareArray)\n\n      const server = await app.listen(4776)\n      const res = await axios.post<any>('http://localhost:4776/array-middleware', {\n        text: 'Do dishes'\n      })\n\n      assert.deepStrictEqual(res.data, ['first', 'second', 'Do dishes'])\n      server.close()\n    })\n\n    it('formatter does nothing when there is no res.data', async () => {\n      const data = { message: 'It worked' }\n      const app = expressify(feathers()).use('/test', express.formatter, (_req: Request, res: Response) =>\n        res.json(data)\n      )\n\n      const server = await app.listen(7988)\n      const res = await axios.get<any>('http://localhost:7988/test')\n\n      assert.deepStrictEqual(res.data, data)\n      server.close()\n    })\n  })\n\n  describe('HTTP status codes', () => {\n    let app: express.Application\n    let server: Server\n\n    before(async () => {\n      app = expressify(feathers())\n        .configure(rest(express.formatter))\n        .use('todo', {\n          async get(id: Id) {\n            return {\n              description: `You have to do ${id}`\n            }\n          },\n\n          async patch() {\n            throw new Error('Not implemented')\n          },\n\n          async find() {\n            return null\n          }\n        })\n\n      app.use(function (_req, res, next) {\n        if (typeof res.data !== 'undefined') {\n          next(new Error('Should never get here'))\n        } else {\n          next()\n        }\n      })\n\n      // Error handler\n      app.use(function (error: Error, _req: Request, res: Response, _next: NextFunction) {\n        if (res.statusCode < 400) {\n          res.status(500)\n        }\n\n        res.json({ message: error.message })\n      })\n\n      server = await app.listen(4780)\n    })\n\n    after((done) => server.close(done))\n\n    it('throws a 405 for undefined service methods (#99)', async () => {\n      const res = await axios.get<any>('http://localhost:4780/todo/dishes')\n\n      assert.ok(res.status === 200, 'Got OK status code for .get')\n      assert.deepStrictEqual(\n        res.data,\n        {\n          description: 'You have to do dishes'\n        },\n        'Got expected object'\n      )\n\n      try {\n        await axios.post<any>('http://localhost:4780/todo')\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.ok(error.response.status === 405, 'Got 405 for .create')\n        assert.deepStrictEqual(\n          error.response.data,\n          {\n            message: 'Method `create` is not supported by this endpoint.'\n          },\n          'Error serialized as expected'\n        )\n      }\n    })\n\n    it('throws a 404 for undefined route', async () => {\n      try {\n        await axios.get<any>('http://localhost:4780/todo/foo/bar')\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.ok(error.response.status === 404, 'Got Not Found code')\n      }\n    })\n\n    it('empty response sets 204 status codes, does not run other middleware (#391)', async () => {\n      const res = await axios.get<any>('http://localhost:4780/todo')\n\n      assert.ok(res.status === 204, 'Got empty status code')\n    })\n  })\n\n  describe('route parameters', () => {\n    let server: Server\n    let app: express.Application\n\n    before(async () => {\n      app = expressify(feathers())\n        .configure(rest())\n        .use('/:appId/:id/todo', {\n          async get(id: Id, params: Params) {\n            if (params.query.error) {\n              throw new BadRequest('Not good')\n            }\n\n            return {\n              id,\n              route: params.route\n            }\n          }\n        })\n        .use(errorHandler)\n\n      server = await app.listen(6880)\n    })\n\n    after((done) => server.close(done))\n\n    it('adds route params as `params.route` and allows id property (#76, #407)', async () => {\n      const expected = {\n        id: 'dishes',\n        route: {\n          appId: 'theApp',\n          id: 'myId'\n        }\n      }\n\n      const res = await axios.get<any>(`http://localhost:6880/theApp/myId/todo/${expected.id}`)\n\n      assert.ok(res.status === 200, 'Got OK status code')\n      assert.deepStrictEqual(expected, res.data)\n    })\n\n    it('properly serializes error for nested routes (#1096)', async () => {\n      try {\n        await axios.get<any>('http://localhost:6880/theApp/myId/todo/test?error=true')\n        assert.fail('Should never het here')\n      } catch (error: any) {\n        const { response } = error\n\n        assert.strictEqual(response.status, 400)\n        assert.deepStrictEqual(response.data, {\n          name: 'BadRequest',\n          message: 'Not good',\n          code: 400,\n          className: 'bad-request'\n        })\n      }\n    })\n  })\n\n  describe('Custom methods', () => {\n    let server: Server\n    let app: express.Application\n\n    before(async () => {\n      app = expressify(feathers())\n        .use(express.json())\n        .configure(rest())\n        .use('/todo', new Service(), {\n          methods: ['find', 'customMethod']\n        })\n        .use(errorHandler)\n\n      server = await app.listen(4781)\n    })\n\n    after((done) => server.close(done))\n\n    it('calls .customMethod with X-Service-Method header', async () => {\n      const payload = { text: 'Do dishes' }\n      const res = await axios.post<any>('http://localhost:4781/todo', payload, {\n        headers: {\n          'X-Service-Method': 'customMethod'\n        }\n      })\n\n      assert.deepEqual(res.data, {\n        data: payload,\n        method: 'customMethod',\n        provider: 'rest'\n      })\n    })\n\n    it('throws MethodNotImplement for .setup, non option and default methods', async () => {\n      const options: AxiosRequestConfig = {\n        method: 'POST',\n        url: 'http://localhost:4781/todo',\n        data: { text: 'Do dishes' }\n      }\n      const testMethod = (name: string) => {\n        return assert.rejects(\n          () =>\n            axios({\n              ...options,\n              headers: {\n                'X-Service-Method': name\n              }\n            }),\n          (error: any) => {\n            assert.deepEqual(error.response.data, {\n              name: 'MethodNotAllowed',\n              message: `Method \\`${name}\\` is not supported by this endpoint.`,\n              code: 405,\n              className: 'method-not-allowed'\n            })\n\n            return true\n          }\n        )\n      }\n\n      await testMethod('setup')\n      await testMethod('internalMethod')\n      await testMethod('nonExisting')\n      await testMethod('create')\n      await testMethod('find')\n    })\n  })\n})\n"
  },
  {
    "path": "packages/express/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/feathers/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **core:** context.path is now typed correctly ([#3303](https://github.com/feathersjs/feathers/issues/3303)) ([ff18b3f](https://github.com/feathersjs/feathers/commit/ff18b3f8b7c8dbc97be588f699d539226785343a))\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n### Bug Fixes\n\n- **core:** Ensure .service does not access Object properties ([#3235](https://github.com/feathersjs/feathers/issues/3235)) ([c0b670a](https://github.com/feathersjs/feathers/commit/c0b670ac4c7bf145e36b59ea89d1387b5514c237))\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n### Bug Fixes\n\n- **core:** Add PaginationParams to general find method ([#3095](https://github.com/feathersjs/feathers/issues/3095)) ([8ebdcf5](https://github.com/feathersjs/feathers/commit/8ebdcf5107fae5fa23920390052b871033de3a0a))\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- **feathers:** Run after all hooks first, and then after method hooks ([#3004](https://github.com/feathersjs/feathers/issues/3004)) ([3692fd5](https://github.com/feathersjs/feathers/commit/3692fd57f70564492cef8bbaf78d264627a9bf0a))\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **core:** `context.type` for around hooks ([#2890](https://github.com/feathersjs/feathers/issues/2890)) ([d606ac6](https://github.com/feathersjs/feathers/commit/d606ac660fd5335c95206784fea36530dd2e851a))\n- **core:** Allow services with no external methods ([#2921](https://github.com/feathersjs/feathers/issues/2921)) ([df56918](https://github.com/feathersjs/feathers/commit/df569183d1a9ed0a9e0ea5bf8d7dab52d326a33d))\n- **core:** Improve service option usage and method option typings ([#2902](https://github.com/feathersjs/feathers/issues/2902)) ([164d75c](https://github.com/feathersjs/feathers/commit/164d75c0f11139a316baa91f1762de8f8eb7da2d))\n\n### Features\n\n- **adapter:** Add patch data type to adapters and refactor AdapterBase usage ([#2906](https://github.com/feathersjs/feathers/issues/2906)) ([9ddc2e6](https://github.com/feathersjs/feathers/commit/9ddc2e6b028f026f939d6af68125847e5c6734b4))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n### Bug Fixes\n\n- **docs:** Review transport API docs and update Express middleware setup ([#2811](https://github.com/feathersjs/feathers/issues/2811)) ([1b97f14](https://github.com/feathersjs/feathers/commit/1b97f14d474f5613482f259eeaa585c24fcfab43))\n\n### Features\n\n- **docs:** New website and documentation pages ([#2802](https://github.com/feathersjs/feathers/issues/2802)) ([ae85fa2](https://github.com/feathersjs/feathers/commit/ae85fa216f12f7ff5d15e7039640e27a09989ea4))\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n### Features\n\n- **cli:** Generate full client test suite and improve typed client ([#2788](https://github.com/feathersjs/feathers/issues/2788)) ([57119b6](https://github.com/feathersjs/feathers/commit/57119b6bb2797f7297cf054268a248c093ecd538))\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Bug Fixes\n\n- **core:** Ensure setup and teardown can be overriden and maintain hook functionality ([#2779](https://github.com/feathersjs/feathers/issues/2779)) ([ab580cb](https://github.com/feathersjs/feathers/commit/ab580cbcaa68d19144d86798c13bf564f9d424a6))\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n### Features\n\n- **cli:** Adding ClientService to CLI ([#2750](https://github.com/feathersjs/feathers/issues/2750)) ([1d45427](https://github.com/feathersjs/feathers/commit/1d45427988521ac028755cbe128685fcdf34f636))\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n- **core:** Get hooks to work reliably with custom methods ([#2714](https://github.com/feathersjs/feathers/issues/2714)) ([8d7e04a](https://github.com/feathersjs/feathers/commit/8d7e04acd0f0e2af9f4c13efee652d296dd3bc51))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Features\n\n- **authentication-local:** Add passwordHash property resolver ([#2660](https://github.com/feathersjs/feathers/issues/2660)) ([b41279b](https://github.com/feathersjs/feathers/commit/b41279b55eea3771a6fa4983a37be2413287bbc6))\n- **cli:** Add typed client to a generated app ([#2669](https://github.com/feathersjs/feathers/issues/2669)) ([5b801b5](https://github.com/feathersjs/feathers/commit/5b801b5017ddc3eaa95622b539f51d605916bc86))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n### Features\n\n- **client:** Improve client side custom method support ([#2654](https://github.com/feathersjs/feathers/issues/2654)) ([c138acf](https://github.com/feathersjs/feathers/commit/c138acf50affbe6b66177d084d3c7a3e9220f09f))\n- **core:** Rename async hooks to around hooks, allow usual registration format ([#2652](https://github.com/feathersjs/feathers/issues/2652)) ([2a485a0](https://github.com/feathersjs/feathers/commit/2a485a07929184261f27437fc0fdfe5a44694834))\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n### Bug Fixes\n\n- **schema:** Allows resolveData with different resolvers based on method ([#2644](https://github.com/feathersjs/feathers/issues/2644)) ([be71fa2](https://github.com/feathersjs/feathers/commit/be71fa2fe260e05b7dcc0d5f439e33f2e9ec2434))\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n### Bug Fixes\n\n- **core:** Do not throw missing method error for regular hook methods ([#2636](https://github.com/feathersjs/feathers/issues/2636)) ([afe9a3b](https://github.com/feathersjs/feathers/commit/afe9a3b3d49897eff045ee237ca2937a6b975291))\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Features\n\n- **typescript:** Improve adapter typings ([#2605](https://github.com/feathersjs/feathers/issues/2605)) ([3b2ca0a](https://github.com/feathersjs/feathers/commit/3b2ca0a6a8e03e8390272c4d7e930b4bffdaacf5))\n- **typescript:** Improve params and query typeability ([#2600](https://github.com/feathersjs/feathers/issues/2600)) ([df28b76](https://github.com/feathersjs/feathers/commit/df28b7619161f1df5e700326f52cca1a92dc5d28))\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n### Bug Fixes\n\n- **core:** Ensure that dynamically registered services are always set up ([#2593](https://github.com/feathersjs/feathers/issues/2593)) ([27cc7d0](https://github.com/feathersjs/feathers/commit/27cc7d08321861cd69e6b66e1fdfa43c50664820))\n\n### Features\n\n- **authentication:** Add setup method for auth strategies ([#1611](https://github.com/feathersjs/feathers/issues/1611)) ([a3c3581](https://github.com/feathersjs/feathers/commit/a3c35814dccdbbf6de96f04f60b226ce206c6dbe))\n- **core:** Add app.setup and app.teardown hook support ([#2585](https://github.com/feathersjs/feathers/issues/2585)) ([ae4ebee](https://github.com/feathersjs/feathers/commit/ae4ebee5d39957651473007c4d3adb210160e040))\n- **core:** Add app.teardown functionality ([#2570](https://github.com/feathersjs/feathers/issues/2570)) ([fcdf524](https://github.com/feathersjs/feathers/commit/fcdf524ae1995bb59265d39f12e98b7794bed023))\n- **core:** Finalize app.teardown() functionality ([#2584](https://github.com/feathersjs/feathers/issues/2584)) ([1a166f3](https://github.com/feathersjs/feathers/commit/1a166f3ded811ecacf0ae8cb67880bc9fa2eeafa))\n- **transport-commons:** add `context.http.response` ([#2524](https://github.com/feathersjs/feathers/issues/2524)) ([5bc9d44](https://github.com/feathersjs/feathers/commit/5bc9d447043c2e2b742c73ed28ecf3b3264dd9e5))\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n### Features\n\n- **express, koa:** make transports similar ([#2486](https://github.com/feathersjs/feathers/issues/2486)) ([26aa937](https://github.com/feathersjs/feathers/commit/26aa937c114fb8596dfefc599b1f53cead69c159))\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n### Features\n\n- **core:** add `context.http` and move `statusCode` there ([#2496](https://github.com/feathersjs/feathers/issues/2496)) ([b701bf7](https://github.com/feathersjs/feathers/commit/b701bf77fb83048aa1dffa492b3d77dd53f7b72b))\n- **core:** Improve legacy hooks integration ([08c8b40](https://github.com/feathersjs/feathers/commit/08c8b40999bf3889c61a4d4fad97a2c4f78bafc9))\n- **transport-commons:** Ability to register routes with custom params ([#2482](https://github.com/feathersjs/feathers/issues/2482)) ([497990a](https://github.com/feathersjs/feathers/commit/497990ae4a980e5a52a1f0f932db12cd0e6e254a))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n### Bug Fixes\n\n- **core:** Allow to return a new hook context in basic hooks ([#2462](https://github.com/feathersjs/feathers/issues/2462)) ([422b6fc](https://github.com/feathersjs/feathers/commit/422b6fc11cf9e42f4234f0823a0b06a4df50982d))\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n### Bug Fixes\n\n- **core:** Clean up readme ([eb3b4f2](https://github.com/feathersjs/feathers/commit/eb3b4f248c0816c92a2300cceed18a6f2518508a))\n- **core:** Set version back to development ([b328767](https://github.com/feathersjs/feathers/commit/b3287676cd773e164fd646ba4cffbf81983a9157))\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- **core:** Add list of protected methods that can not be used for custom methods ([#2390](https://github.com/feathersjs/feathers/issues/2390)) ([6584a21](https://github.com/feathersjs/feathers/commit/6584a216e5a7d5f2a45822be6bfcb91c35cc2252))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n### Bug Fixes\n\n- **typescript:** Move Paginated type back for better compatibility ([#2350](https://github.com/feathersjs/feathers/issues/2350)) ([2917d05](https://github.com/feathersjs/feathers/commit/2917d05fffb4716d3c4cdaa5ac6a1aee0972e8a6))\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n### Features\n\n- **deno:** Feathers core build for Deno ([#2299](https://github.com/feathersjs/feathers/issues/2299)) ([dece8fb](https://github.com/feathersjs/feathers/commit/dece8fbc0e7601f1505ce8bbb1e4e69cc26e8f98))\n- **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n### Bug Fixes\n\n- **dependencies:** Fix transport-commons dependency and update other dependencies ([#2284](https://github.com/feathersjs/feathers/issues/2284)) ([05b03b2](https://github.com/feathersjs/feathers/commit/05b03b27b40604d956047e3021d8053c3a137616))\n- **feathers:** Always enable hooks on default service methods ([#2275](https://github.com/feathersjs/feathers/issues/2275)) ([827cc9b](https://github.com/feathersjs/feathers/commit/827cc9b752eecdaf63605d7dffd86f531b7e4af3))\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Resolve some type problems ([#2260](https://github.com/feathersjs/feathers/issues/2260)) ([a3d75fa](https://github.com/feathersjs/feathers/commit/a3d75fa29490e8a19412a12bc993ee7bb573068f))\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n### Features\n\n- **core:** Public custom service methods ([#2270](https://github.com/feathersjs/feathers/issues/2270)) ([e65abfb](https://github.com/feathersjs/feathers/commit/e65abfb5388df6c19a11c565cf1076a29f32668d))\n- Application service types default to any ([#1566](https://github.com/feathersjs/feathers/issues/1566)) ([d93ba9a](https://github.com/feathersjs/feathers/commit/d93ba9a17edd20d3397bb00f4f6e82e804e42ed6))\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n- **core:** Remove Uberproto ([#2178](https://github.com/feathersjs/feathers/issues/2178)) ([ddf8821](https://github.com/feathersjs/feathers/commit/ddf8821f53317e6a378657f7d66acb03a037ee47))\n\n### BREAKING CHANGES\n\n- **core:** Services no longer extend Uberproto objects and\n  `service.mixin()` is no longer available.\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Features\n\n- **core:** Migrate @feathersjs/feathers to TypeScript ([#1963](https://github.com/feathersjs/feathers/issues/1963)) ([7812529](https://github.com/feathersjs/feathers/commit/7812529ff0f1008e21211f1d01efbc49795dbe55))\n- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Features\n\n- **core:** Migrate @feathersjs/feathers to TypeScript ([#1963](https://github.com/feathersjs/feathers/issues/1963)) ([7812529](https://github.com/feathersjs/feathers/commit/7812529ff0f1008e21211f1d01efbc49795dbe55))\n- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n### Bug Fixes\n\n- **typescript:** Add user property to the Params. ([#2090](https://github.com/feathersjs/feathers/issues/2090)) ([1e94265](https://github.com/feathersjs/feathers/commit/1e942651fbaaf07fc66c159225fbc992a0174bf4))\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n### Bug Fixes\n\n- **typescript:** Revert add overload types for `find` service methods ([#1972](https://github.com/feathersjs/feathers/issues/1972))\" ([#2025](https://github.com/feathersjs/feathers/issues/2025)) ([a9501ac](https://github.com/feathersjs/feathers/commit/a9501acb4d3ef58dfb87d62c57a9bf76569da281))\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n### Bug Fixes\n\n- **typescript:** add overload types for `find` service methods ([#1972](https://github.com/feathersjs/feathers/issues/1972)) ([ef55af0](https://github.com/feathersjs/feathers/commit/ef55af088d05d9d36aba9d9f8d6c2c908a4f20dd))\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n### Bug Fixes\n\n- **typescript:** Use stricter type for HookContext 'method' prop ([#1896](https://github.com/feathersjs/feathers/issues/1896)) ([24a41b7](https://github.com/feathersjs/feathers/commit/24a41b74486ddadccad18f3ae63afdac5bd373c7))\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n### Bug Fixes\n\n- **typescript:** Make HookMap and HookObject generics. ([#1815](https://github.com/feathersjs/feathers/issues/1815)) ([d10145d](https://github.com/feathersjs/feathers/commit/d10145d91a09aef7bce5af80805a3c0fa9d94f26))\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n### Bug Fixes\n\n- Add `params.authentication` type, remove `hook.connection` type ([#1732](https://github.com/feathersjs/feathers/issues/1732)) ([d46b7b2](https://github.com/feathersjs/feathers/commit/d46b7b2abac8862c0e4dbfce20d71b8b8a96692f))\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n### Bug Fixes\n\n- **core:** Improve hook missing parameter message by adding the service name ([#1703](https://github.com/feathersjs/feathers/issues/1703)) ([2331c2a](https://github.com/feathersjs/feathers/commit/2331c2a3dd70d432db7d62a76ed805d359cbbba5))\n- **typescript:** Allow specific service typings for `Hook` and `HookContext` ([#1688](https://github.com/feathersjs/feathers/issues/1688)) ([f5d0ddd](https://github.com/feathersjs/feathers/commit/f5d0ddd9724bf5778355535d2103d59daaad6294))\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n### Bug Fixes\n\n- Small type improvements ([#1624](https://github.com/feathersjs/feathers/issues/1624)) ([50162c6](https://github.com/feathersjs/feathers/commit/50162c6e562f0a47c6a280c4f01fff7c3afee293))\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n### Bug Fixes\n\n- improve Service and AdapterService types ([#1567](https://github.com/feathersjs/feathers/issues/1567)) ([baad6a2](https://github.com/feathersjs/feathers/commit/baad6a26f0f543b712ccb40359b3933ad3a21392))\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n### Bug Fixes\n\n- Reset version number after every publish ([#1596](https://github.com/feathersjs/feathers/issues/1596)) ([f24f82f](https://github.com/feathersjs/feathers/commit/f24f82f))\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n### Bug Fixes\n\n- Small improvements in dependencies and code sturcture ([#1562](https://github.com/feathersjs/feathers/issues/1562)) ([42c13e2](https://github.com/feathersjs/feathers/commit/42c13e2))\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n### Bug Fixes\n\n- Improve Params typing ([#1474](https://github.com/feathersjs/feathers/issues/1474)) ([54a3aa7](https://github.com/feathersjs/feathers/commit/54a3aa7))\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n### Bug Fixes\n\n- Clean up hooks code ([#1407](https://github.com/feathersjs/feathers/issues/1407)) ([f25c88b](https://github.com/feathersjs/feathers/commit/f25c88b))\n- Fix @feathersjs/feathers typings http import ([abbc07b](https://github.com/feathersjs/feathers/commit/abbc07b))\n- Updated typings for ServiceMethods ([#1409](https://github.com/feathersjs/feathers/issues/1409)) ([b5ee7e2](https://github.com/feathersjs/feathers/commit/b5ee7e2))\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Typings fix and improvements. ([#1364](https://github.com/feathersjs/feathers/issues/1364)) ([515b916](https://github.com/feathersjs/feathers/commit/515b916))\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n### Bug Fixes\n\n- **typescript:** finally should be optional ([#1350](https://github.com/feathersjs/feathers/issues/1350)) ([f439a9e](https://github.com/feathersjs/feathers/commit/f439a9e))\n- Fix versioning tests. Closes [#1346](https://github.com/feathersjs/feathers/issues/1346) ([dd519f6](https://github.com/feathersjs/feathers/commit/dd519f6))\n- Use `export =` in TypeScript definitions ([#1285](https://github.com/feathersjs/feathers/issues/1285)) ([12d0f4b](https://github.com/feathersjs/feathers/commit/12d0f4b))\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n### Bug Fixes\n\n- Update version number check ([53575c5](https://github.com/feathersjs/feathers/commit/53575c5))\n- Updated HooksObject typings ([#1300](https://github.com/feathersjs/feathers/issues/1300)) ([b28058c](https://github.com/feathersjs/feathers/commit/b28058c))\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Do not inherit app object from Object prototype ([#1153](https://github.com/feathersjs/feathers/issues/1153)) ([ed8c2e4](https://github.com/feathersjs/feathers/commit/ed8c2e4))\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Normalize params to object even when it is falsy ([#1012](https://github.com/feathersjs/feathers/issues/1012)) ([af97818](https://github.com/feathersjs/feathers/commit/af97818))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n\n### Features\n\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Allow registering a service at the root level ([#1115](https://github.com/feathersjs/feathers/issues/1115)) ([c73d322](https://github.com/feathersjs/feathers/commit/c73d322))\n- Allow to skip sending service events ([#1270](https://github.com/feathersjs/feathers/issues/1270)) ([b487bbd](https://github.com/feathersjs/feathers/commit/b487bbd))\n- Remove (hook, next) signature and SKIP support ([#1269](https://github.com/feathersjs/feathers/issues/1269)) ([211c0f8](https://github.com/feathersjs/feathers/commit/211c0f8))\n\n## [3.3.1](https://github.com/feathersjs/feathers/compare/@feathersjs/feathers@3.3.0...@feathersjs/feathers@3.3.1) (2019-01-02)\n\n### Bug Fixes\n\n- Do not inherit app object from Object prototype ([#1153](https://github.com/feathersjs/feathers/issues/1153)) ([ed8c2e4](https://github.com/feathersjs/feathers/commit/ed8c2e4))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n\n<a name=\"3.3.0\"></a>\n\n# [3.3.0](https://github.com/feathersjs/feathers/compare/@feathersjs/feathers@3.2.3...@feathersjs/feathers@3.3.0) (2018-12-16)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n\n### Features\n\n- Allow registering a service at the root level ([#1115](https://github.com/feathersjs/feathers/issues/1115)) ([c73d322](https://github.com/feathersjs/feathers/commit/c73d322))\n\n<a name=\"3.2.3\"></a>\n\n## [3.2.3](https://github.com/feathersjs/feathers/compare/@feathersjs/feathers@3.2.2...@feathersjs/feathers@3.2.3) (2018-09-21)\n\n### Bug Fixes\n\n- Normalize params to object even when it is falsy ([#1012](https://github.com/feathersjs/feathers/issues/1012)) ([af97818](https://github.com/feathersjs/feathers/commit/af97818))\n\n<a name=\"3.2.2\"></a>\n\n## [3.2.2](https://github.com/feathersjs/feathers/compare/@feathersjs/feathers@3.2.1...@feathersjs/feathers@3.2.2) (2018-09-17)\n\n**Note:** Version bump only for package @feathersjs/feathers\n\n<a name=\"3.2.1\"></a>\n\n## [3.2.1](https://github.com/feathersjs/feathers/compare/@feathersjs/express@1.2.4...@feathersjs/feather@3.2.1) (2018-09-02)\n\n**Note:** Version bump only for package @feathersjs/express\n\n- Migrate to Monorepo ([feathers#462](https://github.com/feathersjs/feathers/issues/462))\n\n## [v3.2.0](https://github.com/feathersjs/feathers/tree/v3.2.0-pre.1) (2018-08-19)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.1.7...v3.2.0-pre.1)\n\n**Merged pull requests:**\n\n- Add breaking test [\\#931](https://github.com/feathersjs/feathers/pull/931) ([bertho-zero](https://github.com/bertho-zero))\n- Some refactoring for custom method hooks [\\#930](https://github.com/feathersjs/feathers/pull/930) ([daffl](https://github.com/daffl))\n- Allow adding hooks to other service methods [\\#924](https://github.com/feathersjs/feathers/pull/924) ([bertho-zero](https://github.com/bertho-zero))\n\n## [v3.1.7](https://github.com/feathersjs/feathers/tree/v3.1.7) (2018-06-16)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.1.6...v3.1.7)\n\n**Merged pull requests:**\n\n- Update to latest Uberproto and other dependencies [\\#889](https://github.com/feathersjs/feathers/pull/889) ([daffl](https://github.com/daffl))\n\n## [v3.1.6](https://github.com/feathersjs/feathers/tree/v3.1.6) (2018-06-03)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.1.5...v3.1.6)\n\n**Merged pull requests:**\n\n- Update uberproto to the latest version 🚀 [\\#881](https://github.com/feathersjs/feathers/pull/881) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Add 'services conserve Symbols' test [\\#880](https://github.com/feathersjs/feathers/pull/880) ([bertho-zero](https://github.com/bertho-zero))\n- Update events to the latest version 🚀 [\\#872](https://github.com/feathersjs/feathers/pull/872) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Add Greenkeeper badge 🌴 [\\#867](https://github.com/feathersjs/feathers/pull/867) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.1.5](https://github.com/feathersjs/feathers/tree/v3.1.5) (2018-05-04)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.1.4...v3.1.5)\n\n**Merged pull requests:**\n\n- Allow methods to return a null result [\\#865](https://github.com/feathersjs/feathers/pull/865) ([bertho-zero](https://github.com/bertho-zero))\n\n## [v3.1.4](https://github.com/feathersjs/feathers/tree/v3.1.4) (2018-03-26)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.1.3...v3.1.4)\n\n**Merged pull requests:**\n\n- Make sure error hooks always have the original context information [\\#842](https://github.com/feathersjs/feathers/pull/842) ([daffl](https://github.com/daffl))\n\n## [v3.1.3](https://github.com/feathersjs/feathers/tree/v3.1.3) (2018-02-16)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.1.2...v3.1.3)\n\n**Merged pull requests:**\n\n- Update events to the latest version 🚀 [\\#810](https://github.com/feathersjs/feathers/pull/810) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.1.2](https://github.com/feathersjs/feathers/tree/v3.1.2) (2018-02-10)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.1.1...v3.1.2)\n\n**Merged pull requests:**\n\n- Handle errors in error hooks properly [\\#819](https://github.com/feathersjs/feathers/pull/819) ([daffl](https://github.com/daffl))\n\n## [v3.1.1](https://github.com/feathersjs/feathers/tree/v3.1.1) (2018-02-08)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.1.0...v3.1.1)\n\n**Merged pull requests:**\n\n- Turn argument validation into the first hook [\\#818](https://github.com/feathersjs/feathers/pull/818) ([daffl](https://github.com/daffl))\n- Add Russian Telegram community [\\#814](https://github.com/feathersjs/feathers/pull/814) ([vodniciarv](https://github.com/vodniciarv))\n\n## [v3.1.0](https://github.com/feathersjs/feathers/tree/v3.1.0) (2018-01-26)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.0.5...v3.1.0)\n\n**Merged pull requests:**\n\n- Update mocha to the latest version 🚀 [\\#793](https://github.com/feathersjs/feathers/pull/793) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Add ability to skip all following hooks [\\#792](https://github.com/feathersjs/feathers/pull/792) ([sylvainlap](https://github.com/sylvainlap))\n\n## [v3.0.5](https://github.com/feathersjs/feathers/tree/v3.0.5) (2018-01-04)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.2.4...v3.0.5)\n\n**Merged pull requests:**\n\n- Add backers & sponsors from Open Collective [\\#504](https://github.com/feathersjs/feathers/pull/504) ([piamancini](https://github.com/piamancini))\n\n## [v2.2.4](https://github.com/feathersjs/feathers/tree/v2.2.4) (2018-01-04)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.0.4...v2.2.4)\n\n## [v3.0.4](https://github.com/feathersjs/feathers/tree/v3.0.4) (2018-01-03)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.0.3...v3.0.4)\n\n**Merged pull requests:**\n\n- Update Readme to correspond with latest release [\\#772](https://github.com/feathersjs/feathers/pull/772) ([daffl](https://github.com/daffl))\n\n## [v3.0.3](https://github.com/feathersjs/feathers/tree/v3.0.3) (2018-01-02)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.0.2...v3.0.3)\n\n**Merged pull requests:**\n\n- Properly resolve the promise in error hooks if returnHook is set. [\\#769](https://github.com/feathersjs/feathers/pull/769) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#768](https://github.com/feathersjs/feathers/pull/768) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.0.2](https://github.com/feathersjs/feathers/tree/v3.0.2) (2017-12-05)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.0.1...v3.0.2)\n\n**Merged pull requests:**\n\n- Updated to handle array emit for service results. [\\#743](https://github.com/feathersjs/feathers/pull/743) ([superlazycoder](https://github.com/superlazycoder))\n\n## [v3.0.1](https://github.com/feathersjs/feathers/tree/v3.0.1) (2017-11-16)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.0.0...v3.0.1)\n\n**Merged pull requests:**\n\n- Updated readme.md [\\#732](https://github.com/feathersjs/feathers/pull/732) ([andlewis](https://github.com/andlewis))\n- Add default export for better ES module \\(TypeScript\\) compatibility [\\#731](https://github.com/feathersjs/feathers/pull/731) ([daffl](https://github.com/daffl))\n- Throw an error for invalid service paths [\\#729](https://github.com/feathersjs/feathers/pull/729) ([daffl](https://github.com/daffl))\n- Update nsp to the latest version 🚀 [\\#723](https://github.com/feathersjs/feathers/pull/723) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Rename expressify to express [\\#719](https://github.com/feathersjs/feathers/pull/719) ([bertho-zero](https://github.com/bertho-zero))\n\n## [v3.0.0](https://github.com/feathersjs/feathers/tree/v3.0.0) (2017-11-01)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.0.0-pre.3...v3.0.0)\n\n**Merged pull requests:**\n\n- Update dependencies to enable Greenkeeper 🌴 [\\#708](https://github.com/feathersjs/feathers/pull/708) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Feathers v3 core \\(Buzzard\\) [\\#697](https://github.com/feathersjs/feathers/pull/697) ([daffl](https://github.com/daffl))\n\n## [v3.0.0-pre.3](https://github.com/feathersjs/feathers/tree/v3.0.0-pre.3) (2017-10-25)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.0.0-pre.2...v3.0.0-pre.3)\n\n**Merged pull requests:**\n\n- Better logic for returning the hook object from method call [\\#706](https://github.com/feathersjs/feathers/pull/706) ([daffl](https://github.com/daffl))\n- Codeclimate Updates [\\#704](https://github.com/feathersjs/feathers/pull/704) ([ekryski](https://github.com/ekryski))\n- Add more inline documentation [\\#703](https://github.com/feathersjs/feathers/pull/703) ([daffl](https://github.com/daffl))\n\n## [v3.0.0-pre.2](https://github.com/feathersjs/feathers/tree/v3.0.0-pre.2) (2017-10-20)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.2.3...v3.0.0-pre.2)\n\n**Merged pull requests:**\n\n- Move to @feathersjs npm scope [\\#699](https://github.com/feathersjs/feathers/pull/699) ([daffl](https://github.com/daffl))\n- Also pass app object as parameter to configure callbacks [\\#698](https://github.com/feathersjs/feathers/pull/698) ([daffl](https://github.com/daffl))\n\n## [v2.2.3](https://github.com/feathersjs/feathers/tree/v2.2.3) (2017-10-20)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.2.2...v2.2.3)\n\n**Merged pull requests:**\n\n- Move Typescript declaration dependency into devDependencies [\\#696](https://github.com/feathersjs/feathers/pull/696) ([daffl](https://github.com/daffl))\n- Add changelog back [\\#695](https://github.com/feathersjs/feathers/pull/695) ([daffl](https://github.com/daffl))\n- Add support for Feathers v3 sub-apps [\\#694](https://github.com/feathersjs/feathers/pull/694) ([daffl](https://github.com/daffl))\n- Feature/typescript fix [\\#692](https://github.com/feathersjs/feathers/pull/692) ([TimMensch](https://github.com/TimMensch))\n- Update mocha to the latest version 🚀 [\\#685](https://github.com/feathersjs/feathers/pull/685) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.2.2](https://github.com/feathersjs/feathers/tree/v2.2.2) (2017-09-30)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.2.1...v2.2.2)\n\n**Merged pull requests:**\n\n- Update to latest secure dependencies [\\#684](https://github.com/feathersjs/feathers/pull/684) ([daffl](https://github.com/daffl))\n\n## [v2.2.1](https://github.com/feathersjs/feathers/tree/v2.2.1) (2017-09-25)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.2.0...v2.2.1)\n\n**Merged pull requests:**\n\n- \\[typings\\] Make generic type of Service default to any [\\#681](https://github.com/feathersjs/feathers/pull/681) ([j2L4e](https://github.com/j2L4e))\n- Update readme.md [\\#668](https://github.com/feathersjs/feathers/pull/668) ([damosse31](https://github.com/damosse31))\n\n## [v2.2.0](https://github.com/feathersjs/feathers/tree/v2.2.0) (2017-09-01)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v3.0.0-pre.1...v2.2.0)\n\n**Merged pull requests:**\n\n- No longer pollutes the global scope [\\#662](https://github.com/feathersjs/feathers/pull/662) ([bertho-zero](https://github.com/bertho-zero))\n- Update debug to the latest version 🚀 [\\#641](https://github.com/feathersjs/feathers/pull/641) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Examples url is tinny \\(broken\\) [\\#634](https://github.com/feathersjs/feathers/pull/634) ([rayfoss](https://github.com/rayfoss))\n\n## [v3.0.0-pre.1](https://github.com/feathersjs/feathers/tree/v3.0.0-pre.1) (2017-07-19)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.1.7...v3.0.0-pre.1)\n\n**Merged pull requests:**\n\n- Add a missing configure\\(\\) method in typescript definition [\\#624](https://github.com/feathersjs/feathers/pull/624) ([jansel369](https://github.com/jansel369))\n\n## [v2.1.7](https://github.com/feathersjs/feathers/tree/v2.1.7) (2017-07-16)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.1.6...v2.1.7)\n\n## [v2.1.6](https://github.com/feathersjs/feathers/tree/v2.1.6) (2017-07-16)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.1.4...v2.1.6)\n\n**Merged pull requests:**\n\n- Allows error hooks to swallow error by setting the result [\\#621](https://github.com/feathersjs/feathers/pull/621) ([daffl](https://github.com/daffl))\n- typings: properly overload .create\\(\\) [\\#619](https://github.com/feathersjs/feathers/pull/619) ([j2L4e](https://github.com/j2L4e))\n- Update to new plugin infrastructure [\\#614](https://github.com/feathersjs/feathers/pull/614) ([daffl](https://github.com/daffl))\n- Allow flag to return the hook object [\\#607](https://github.com/feathersjs/feathers/pull/607) ([daffl](https://github.com/daffl))\n- Use inline version Babel plugin [\\#606](https://github.com/feathersjs/feathers/pull/606) ([daffl](https://github.com/daffl))\n- Initial changes for Feathers v3 [\\#605](https://github.com/feathersjs/feathers/pull/605) ([daffl](https://github.com/daffl))\n- Update index.d.ts [\\#603](https://github.com/feathersjs/feathers/pull/603) ([j2L4e](https://github.com/j2L4e))\n\n## [v2.1.4](https://github.com/feathersjs/feathers/tree/v2.1.4) (2017-06-26)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.1.3...v2.1.4)\n\n**Merged pull requests:**\n\n- Return types needed [\\#602](https://github.com/feathersjs/feathers/pull/602) ([Creiger](https://github.com/Creiger))\n- Remove TypeScript typings [\\#598](https://github.com/feathersjs/feathers/pull/598) ([daffl](https://github.com/daffl))\n- Remove explicit loading of babel-polyfill [\\#597](https://github.com/feathersjs/feathers/pull/597) ([daffl](https://github.com/daffl))\n- Add feathers-hooks to core [\\#596](https://github.com/feathersjs/feathers/pull/596) ([daffl](https://github.com/daffl))\n- Revert update to security links [\\#590](https://github.com/feathersjs/feathers/pull/590) ([alaycock](https://github.com/alaycock))\n\n## [v2.1.3](https://github.com/feathersjs/feathers/tree/v2.1.3) (2017-05-29)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.1.2...v2.1.3)\n\n**Merged pull requests:**\n\n- Fix typings [\\#587](https://github.com/feathersjs/feathers/pull/587) ([cranesandcaff](https://github.com/cranesandcaff))\n- Update feathers-socketio to the latest version 🚀 [\\#576](https://github.com/feathersjs/feathers/pull/576) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.1.2](https://github.com/feathersjs/feathers/tree/v2.1.2) (2017-05-09)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.1.1...v2.1.2)\n\n**Merged pull requests:**\n\n- Fix typescript defnition of Service. All the service methods should be [\\#573](https://github.com/feathersjs/feathers/pull/573) ([harish2704](https://github.com/harish2704))\n- Update socket.io-client to the latest version 🚀 [\\#572](https://github.com/feathersjs/feathers/pull/572) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update dependencies to enable Greenkeeper 🌴 [\\#551](https://github.com/feathersjs/feathers/pull/551) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Fix pagination type definition. [\\#527](https://github.com/feathersjs/feathers/pull/527) ([asdacap](https://github.com/asdacap))\n\n## [v2.1.1](https://github.com/feathersjs/feathers/tree/v2.1.1) (2017-03-03)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.1.0...v2.1.1)\n\n**Merged pull requests:**\n\n- No Pagination in Typescript \\#520 [\\#522](https://github.com/feathersjs/feathers/pull/522) ([superbarne](https://github.com/superbarne))\n\n## [v2.1.0](https://github.com/feathersjs/feathers/tree/v2.1.0) (2017-03-01)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.0.3...v2.1.0)\n\n**Merged pull requests:**\n\n- Typescript Definitions [\\#507](https://github.com/feathersjs/feathers/pull/507) ([AbraaoAlves](https://github.com/AbraaoAlves))\n- Auto Dependency Updates ... [\\#492](https://github.com/feathersjs/feathers/pull/492) ([lguzzon](https://github.com/lguzzon))\n- debug@2.4.0 breaks build 🚨 [\\#476](https://github.com/feathersjs/feathers/pull/476) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v2.0.3](https://github.com/feathersjs/feathers/tree/v2.0.3) (2016-12-10)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.0.2...v2.0.3)\n\n**Merged pull requests:**\n\n- Update feathers-commons to use latest [\\#473](https://github.com/feathersjs/feathers/pull/473) ([daffl](https://github.com/daffl))\n- Create .codeclimate.yml [\\#468](https://github.com/feathersjs/feathers/pull/468) ([larkinscott](https://github.com/larkinscott))\n- Update feathers-commons to version 0.8.0 🚀 [\\#459](https://github.com/feathersjs/feathers/pull/459) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- adding .github folder and templates [\\#442](https://github.com/feathersjs/feathers/pull/442) ([ekryski](https://github.com/ekryski))\n- Remove .jshintrc [\\#434](https://github.com/feathersjs/feathers/pull/434) ([marshallswain](https://github.com/marshallswain))\n- jshint —\\> semistandard [\\#430](https://github.com/feathersjs/feathers/pull/430) ([marshallswain](https://github.com/marshallswain))\n- Increase code coverage [\\#429](https://github.com/feathersjs/feathers/pull/429) ([daffl](https://github.com/daffl))\n- Remove NPM badges and fix code climate badge [\\#428](https://github.com/feathersjs/feathers/pull/428) ([daffl](https://github.com/daffl))\n- adding code coverage config, badges and LTS section [\\#427](https://github.com/feathersjs/feathers/pull/427) ([ekryski](https://github.com/ekryski))\n\n## [v2.0.2](https://github.com/feathersjs/feathers/tree/v2.0.2) (2016-09-15)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.0.1...v2.0.2)\n\n**Merged pull requests:**\n\n- Create an app reference on service event hook object [\\#406](https://github.com/feathersjs/feathers/pull/406) ([kaiquewdev](https://github.com/kaiquewdev))\n- Update mocha to version 3.0.0 🚀 [\\#375](https://github.com/feathersjs/feathers/pull/375) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update contributing.md [\\#370](https://github.com/feathersjs/feathers/pull/370) ([MichaelErmer](https://github.com/MichaelErmer))\n- mocha@2.5.0 breaks build 🚨 [\\#338](https://github.com/feathersjs/feathers/pull/338) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update babel-plugin-add-module-exports to version 0.2.0 🚀 [\\#326](https://github.com/feathersjs/feathers/pull/326) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- socket.io-client@1.4.6 breaks build 🚨 [\\#322](https://github.com/feathersjs/feathers/pull/322) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Set rejectUnauthorized explicitly [\\#321](https://github.com/feathersjs/feathers/pull/321) ([daffl](https://github.com/daffl))\n\n## [v2.0.1](https://github.com/feathersjs/feathers/tree/v2.0.1) (2016-04-28)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.0.0...v2.0.1)\n\n**Merged pull requests:**\n\n- Test and fix for allowing services with only a setup method [\\#308](https://github.com/feathersjs/feathers/pull/308) ([daffl](https://github.com/daffl))\n- Remove JSON loading from the client version [\\#306](https://github.com/feathersjs/feathers/pull/306) ([daffl](https://github.com/daffl))\n- Update readme.md [\\#302](https://github.com/feathersjs/feathers/pull/302) ([marshallswain](https://github.com/marshallswain))\n- Fix link to docs [\\#268](https://github.com/feathersjs/feathers/pull/268) ([lepiaf](https://github.com/lepiaf))\n- Update feathers-client to version 1.0.0 🚀 [\\#263](https://github.com/feathersjs/feathers/pull/263) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- New site [\\#252](https://github.com/feathersjs/feathers/pull/252) ([ekryski](https://github.com/ekryski))\n\n## [v2.0.0](https://github.com/feathersjs/feathers/tree/v2.0.0) (2016-02-22)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.0.0-pre.4...v2.0.0)\n\n**Merged pull requests:**\n\n- Update feathers-commons to version 0.7.0 🚀 [\\#223](https://github.com/feathersjs/feathers/pull/223) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-commons to version 0.6.0 🚀 [\\#210](https://github.com/feathersjs/feathers/pull/210) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Explicitly import /index files to work with Steal. [\\#208](https://github.com/feathersjs/feathers/pull/208) ([marshallswain](https://github.com/marshallswain))\n- Appending `nsp check` to test script. [\\#205](https://github.com/feathersjs/feathers/pull/205) ([marshallswain](https://github.com/marshallswain))\n\n## [v2.0.0-pre.4](https://github.com/feathersjs/feathers/tree/v2.0.0-pre.4) (2016-01-16)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.0.0-pre.3...v2.0.0-pre.4)\n\n**Merged pull requests:**\n\n- Fixing .npmignore entries [\\#203](https://github.com/feathersjs/feathers/pull/203) ([corymsmith](https://github.com/corymsmith))\n\n## [v2.0.0-pre.3](https://github.com/feathersjs/feathers/tree/v2.0.0-pre.3) (2016-01-16)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.0.0-pre.2...v2.0.0-pre.3)\n\n**Merged pull requests:**\n\n- Reorganizing packages to not load Express [\\#202](https://github.com/feathersjs/feathers/pull/202) ([daffl](https://github.com/daffl))\n- Update feathers-client to version 0.5.1 🚀 [\\#200](https://github.com/feathersjs/feathers/pull/200) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-commons to version 0.5.0 🚀 [\\#198](https://github.com/feathersjs/feathers/pull/198) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v2.0.0-pre.2](https://github.com/feathersjs/feathers/tree/v2.0.0-pre.2) (2016-01-10)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v2.0.0-pre.1...v2.0.0-pre.2)\n\n**Merged pull requests:**\n\n- Make Feathers universal [\\#193](https://github.com/feathersjs/feathers/pull/193) ([daffl](https://github.com/daffl))\n- Remove Lodash [\\#192](https://github.com/feathersjs/feathers/pull/192) ([daffl](https://github.com/daffl))\n\n## [v2.0.0-pre.1](https://github.com/feathersjs/feathers/tree/v2.0.0-pre.1) (2016-01-05)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v1.3.0...v2.0.0-pre.1)\n\n**Merged pull requests:**\n\n- Migration to ES6 and API providers in separate modules [\\#188](https://github.com/feathersjs/feathers/pull/188) ([daffl](https://github.com/daffl))\n\n## [v1.3.0](https://github.com/feathersjs/feathers/tree/v1.3.0) (2015-12-16)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v1.2.1...v1.3.0)\n\n## [v1.2.1](https://github.com/feathersjs/feathers/tree/v1.2.1) (2015-12-12)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v1.2.0...v1.2.1)\n\n**Merged pull requests:**\n\n- Add ability to create, update, patch and remove many [\\#179](https://github.com/feathersjs/feathers/pull/179) ([daffl](https://github.com/daffl))\n- Handle middleware passed after the service to app.use [\\#178](https://github.com/feathersjs/feathers/pull/178) ([dbkaplun](https://github.com/dbkaplun))\n- Adding tests to make sure that dispatcher context is set properly. [\\#172](https://github.com/feathersjs/feathers/pull/172) ([daffl](https://github.com/daffl))\n\n## [v1.2.0](https://github.com/feathersjs/feathers/tree/v1.2.0) (2015-11-07)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v1.1.1...v1.2.0)\n\n**Merged pull requests:**\n\n- Make sure event hookups happens after method normalization [\\#151](https://github.com/feathersjs/feathers/pull/151) ([daffl](https://github.com/daffl))\n- Add rubberduck args to service events parameters [\\#148](https://github.com/feathersjs/feathers/pull/148) ([loris](https://github.com/loris))\n- Debug should be for socket.io instead of primus [\\#147](https://github.com/feathersjs/feathers/pull/147) ([marshallswain](https://github.com/marshallswain))\n\n## [v1.1.1](https://github.com/feathersjs/feathers/tree/v1.1.1) (2015-09-22)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/v1.1.0...v1.1.1)\n\n**Merged pull requests:**\n\n- Fix 404 not being properly thrown by REST provider [\\#146](https://github.com/feathersjs/feathers/pull/146) ([loris](https://github.com/loris))\n\n## [v1.1.0](https://github.com/feathersjs/feathers/tree/v1.1.0) (2015-07-22)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/1.1.0-pre.0...v1.1.0)\n\n**Merged pull requests:**\n\n- New homepage updates [\\#140](https://github.com/feathersjs/feathers/pull/140) ([daffl](https://github.com/daffl))\n- New site [\\#137](https://github.com/feathersjs/feathers/pull/137) ([ekryski](https://github.com/ekryski))\n- Allow to register remote services [\\#136](https://github.com/feathersjs/feathers/pull/136) ([daffl](https://github.com/daffl))\n\n## [1.1.0-pre.0](https://github.com/feathersjs/feathers/tree/1.1.0-pre.0) (2015-04-10)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/1.0.2...1.1.0-pre.0)\n\n**Merged pull requests:**\n\n- Run Socket configurations before service setup \\(\\#131\\) [\\#132](https://github.com/feathersjs/feathers/pull/132) ([daffl](https://github.com/daffl))\n- Allow services to dispatch custom events. [\\#128](https://github.com/feathersjs/feathers/pull/128) ([daffl](https://github.com/daffl))\n- Moving documentation into the main repository. [\\#127](https://github.com/feathersjs/feathers/pull/127) ([daffl](https://github.com/daffl))\n- Adding contributing guidelines and updating build process. [\\#126](https://github.com/feathersjs/feathers/pull/126) ([daffl](https://github.com/daffl))\n- Service method call normalization [\\#124](https://github.com/feathersjs/feathers/pull/124) ([daffl](https://github.com/daffl))\n- Tests for socket message validation and errors. [\\#123](https://github.com/feathersjs/feathers/pull/123) ([daffl](https://github.com/daffl))\n- Migrating shared functionality into the feathers-commons module [\\#122](https://github.com/feathersjs/feathers/pull/122) ([daffl](https://github.com/daffl))\n- Adding debug module and messages. [\\#117](https://github.com/feathersjs/feathers/pull/117) ([daffl](https://github.com/daffl))\n- Fix duplicate events in dynamic services. [\\#115](https://github.com/feathersjs/feathers/pull/115) ([marshallswain](https://github.com/marshallswain))\n- Make sure .setup\\(\\) runs on dynamic services. [\\#110](https://github.com/feathersjs/feathers/pull/110) ([marshallswain](https://github.com/marshallswain))\n- Add a Gitter chat badge to readme.md [\\#109](https://github.com/feathersjs/feathers/pull/109) ([gitter-badger](https://github.com/gitter-badger))\n- Support for registering services dynamically [\\#107](https://github.com/feathersjs/feathers/pull/107) ([marshallswain](https://github.com/marshallswain))\n\n## [1.0.2](https://github.com/feathersjs/feathers/tree/1.0.2) (2015-02-04)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/1.0.1...1.0.2)\n\n**Merged pull requests:**\n\n- Use Uberproto extended instance when creating services [\\#105](https://github.com/feathersjs/feathers/pull/105) ([daffl](https://github.com/daffl))\n- Make sure that mixins are specific to each new app [\\#104](https://github.com/feathersjs/feathers/pull/104) ([daffl](https://github.com/daffl))\n\n## [1.0.1](https://github.com/feathersjs/feathers/tree/1.0.1) (2014-12-31)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/1.0.0...1.0.1)\n\n**Merged pull requests:**\n\n- Rename Uberproto .create to avoid conflicts with service method [\\#100](https://github.com/feathersjs/feathers/pull/100) ([daffl](https://github.com/daffl))\n\n## [1.0.0](https://github.com/feathersjs/feathers/tree/1.0.0) (2014-10-03)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/1.0.0-pre.5...1.0.0)\n\n**Merged pull requests:**\n\n- Version 1.0 homepage [\\#95](https://github.com/feathersjs/feathers/pull/95) ([daffl](https://github.com/daffl))\n- Remove app.lookup and make the functionality available as app.service [\\#94](https://github.com/feathersjs/feathers/pull/94) ([daffl](https://github.com/daffl))\n- Allow not passing parameters in socket calls [\\#92](https://github.com/feathersjs/feathers/pull/92) ([daffl](https://github.com/daffl))\n- Add \\_setup method [\\#91](https://github.com/feathersjs/feathers/pull/91) ([daffl](https://github.com/daffl))\n- Better bodyParser usage, fix typo. [\\#90](https://github.com/feathersjs/feathers/pull/90) ([olegskl](https://github.com/olegskl))\n- Throw an error when registering a service after application start [\\#78](https://github.com/feathersjs/feathers/pull/78) ([daffl](https://github.com/daffl))\n- Use URI parameters as service params and remove bodyParser dependendency [\\#77](https://github.com/feathersjs/feathers/pull/77) ([daffl](https://github.com/daffl))\n- Send socket parameters as params.query [\\#72](https://github.com/feathersjs/feathers/pull/72) ([daffl](https://github.com/daffl))\n- Send HTTP 201 and 204 status codes [\\#71](https://github.com/feathersjs/feathers/pull/71) ([daffl](https://github.com/daffl))\n- Upgrade to SocketIO 1.0 [\\#70](https://github.com/feathersjs/feathers/pull/70) ([daffl](https://github.com/daffl))\n- Allow service methods to return a promise [\\#59](https://github.com/feathersjs/feathers/pull/59) ([daffl](https://github.com/daffl))\n- Allow to register services with custom middleware. [\\#56](https://github.com/feathersjs/feathers/pull/56) ([daffl](https://github.com/daffl))\n- Upgrade to Express 4 [\\#55](https://github.com/feathersjs/feathers/pull/55) ([daffl](https://github.com/daffl))\n\n## [1.0.0-pre.5](https://github.com/feathersjs/feathers/tree/1.0.0-pre.5) (2014-06-13)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/1.0.0-pre.1...1.0.0-pre.5)\n\n**Merged pull requests:**\n\n- requiring feathers-errors in core [\\#81](https://github.com/feathersjs/feathers/pull/81) ([ekryski](https://github.com/ekryski))\n\n## [1.0.0-pre.1](https://github.com/feathersjs/feathers/tree/1.0.0-pre.1) (2014-06-04)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/0.4.0...1.0.0-pre.1)\n\n## [0.4.0](https://github.com/feathersjs/feathers/tree/0.4.0) (2014-04-08)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/0.3.2...0.4.0)\n\n**Merged pull requests:**\n\n- Allow to configure REST handler manually [\\#52](https://github.com/feathersjs/feathers/pull/52) ([daffl](https://github.com/daffl))\n- Event filtering and params extension for Primus [\\#51](https://github.com/feathersjs/feathers/pull/51) ([daffl](https://github.com/daffl))\n- SocketIO event filtering [\\#50](https://github.com/feathersjs/feathers/pull/50) ([daffl](https://github.com/daffl))\n- Adding SocketIO handshake data to service call parameters [\\#49](https://github.com/feathersjs/feathers/pull/49) ([daffl](https://github.com/daffl))\n- Added patch support [\\#47](https://github.com/feathersjs/feathers/pull/47) ([mlaug](https://github.com/mlaug))\n\n## [0.3.2](https://github.com/feathersjs/feathers/tree/0.3.2) (2014-03-28)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/0.3.1...0.3.2)\n\n**Merged pull requests:**\n\n- Use feathers/express apps [\\#46](https://github.com/feathersjs/feathers/pull/46) ([bredele](https://github.com/bredele))\n- Upgrading dependencies and switching to Lodash [\\#42](https://github.com/feathersjs/feathers/pull/42) ([daffl](https://github.com/daffl))\n\n## [0.3.1](https://github.com/feathersjs/feathers/tree/0.3.1) (2014-02-19)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/0.3.0...0.3.1)\n\n**Merged pull requests:**\n\n- Updating REST provider [\\#35](https://github.com/feathersjs/feathers/pull/35) ([daffl](https://github.com/daffl))\n\n## [0.3.0](https://github.com/feathersjs/feathers/tree/0.3.0) (2014-01-06)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/0.2.0...0.3.0)\n\n**Merged pull requests:**\n\n- Primus provider [\\#34](https://github.com/feathersjs/feathers/pull/34) ([daffl](https://github.com/daffl))\n- Add app.setup\\(\\) to support HTTPS [\\#33](https://github.com/feathersjs/feathers/pull/33) ([daffl](https://github.com/daffl))\n- Remove middleware: connect.bodyParser\\(\\) [\\#27](https://github.com/feathersjs/feathers/pull/27) ([sbruchmann](https://github.com/sbruchmann))\n\n## [0.2.0](https://github.com/feathersjs/feathers/tree/0.2.0) (2013-09-27)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/0.1.0...0.2.0)\n\n**Merged pull requests:**\n\n- Allows registering services with slashes [\\#18](https://github.com/feathersjs/feathers/pull/18) ([daffl](https://github.com/daffl))\n- Allows setting service params in middleware [\\#17](https://github.com/feathersjs/feathers/pull/17) ([daffl](https://github.com/daffl))\n\n## [0.1.0](https://github.com/feathersjs/feathers/tree/0.1.0) (2013-08-27)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/0.0.5...0.1.0)\n\n## [0.0.5](https://github.com/feathersjs/feathers/tree/0.0.5) (2013-08-27)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/0.0.4...0.0.5)\n\n## [0.0.4](https://github.com/feathersjs/feathers/tree/0.0.4) (2013-08-27)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/0.0.3...0.0.4)\n\n**Merged pull requests:**\n\n- Major refactoring and simplification [\\#16](https://github.com/feathersjs/feathers/pull/16) ([daffl](https://github.com/daffl))\n\n## [0.0.3](https://github.com/feathersjs/feathers/tree/0.0.3) (2013-08-26)\n\n[Full Changelog](https://github.com/feathersjs/feathers/compare/0.0.2...0.0.3)\n\n**Merged pull requests:**\n\n- Improved Mixin organization, updated tests and examples. [\\#15](https://github.com/feathersjs/feathers/pull/15) ([daffl](https://github.com/daffl))\n\n## [0.0.2](https://github.com/feathersjs/feathers/tree/0.0.2) (2013-07-13)\n\n**Merged pull requests:**\n\n- Added a couple examples. Started to add a mongo adapter. [\\#2](https://github.com/feathersjs/feathers/pull/2) ([ekryski](https://github.com/ekryski))\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/feathers/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/feathers/README.md",
    "content": "<img style=\"width: 100%; max-width: 400px;\" src=\"http://feathersjs.com/img/feathers-logo-wide.png\" alt=\"Feathers logo\">\n\n## The API and real-time application framework\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/feathers.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/feathers)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\nFeathers is a lightweight web-framework for creating APIs and real-time applications using TypeScript or JavaScript.\n\nFeathers can interact with any backend technology, supports many databases out of the box and works with any frontend technology like React, VueJS, Angular, React Native, Android or iOS.\n\n## Getting started\n\nYou can build your first real-time and REST API in just 4 commands:\n\n```bash\n$ npm create feathers my-new-app\n$ cd my-new-app\n$ npm start\n```\n\n## Documentation\n\nTo learn more about Feathers visit the website at [feathersjs.com](http://feathersjs.com) or jump right into [the Feathers guides](http://feathersjs.com/guides).\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/feathers/package.json",
    "content": "{\n  \"name\": \"@feathersjs/feathers\",\n  \"description\": \"A framework for real-time applications and REST API with JavaScript and TypeScript\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"http://feathersjs.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/feathers\"\n  },\n  \"keywords\": [\n    \"feathers\",\n    \"REST\",\n    \"socket.io\",\n    \"realtime\"\n  ],\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"write-version\": \"node -e \\\"console.log('export default \\\\'' + require('./package.json').version + '\\\\'')\\\" > src/version.ts\",\n    \"reset-version\": \"node -e \\\"console.log('export default \\\\'development\\\\'')\\\" > src/version.ts\",\n    \"prepublish\": \"npm run compile\",\n    \"version\": \"npm run write-version\",\n    \"publish\": \"npm run reset-version\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/hooks\": \"^0.9.0\",\n    \"events\": \"^3.3.0\"\n  },\n  \"devDependencies\": {\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/feathers/src/application.ts",
    "content": "import version from './version'\nimport { EventEmitter } from 'events'\nimport { stripSlashes, createDebug } from '@feathersjs/commons'\nimport { HOOKS, hooks, middleware } from '@feathersjs/hooks'\nimport { eventHook, eventMixin } from './events'\nimport { hookMixin } from './hooks'\nimport { wrapService, getServiceOptions, protectedMethods } from './service'\nimport {\n  FeathersApplication,\n  ServiceMixin,\n  Service,\n  ServiceOptions,\n  ServiceInterface,\n  Application,\n  FeathersService,\n  ApplicationHookOptions\n} from './declarations'\nimport { enableHooks } from './hooks'\n\nconst debug = createDebug('@feathersjs/feathers')\n\nexport class Feathers<Services, Settings>\n  extends EventEmitter\n  implements FeathersApplication<Services, Settings>\n{\n  services: Services = {} as Services\n  settings: Settings = {} as Settings\n  mixins: ServiceMixin<Application<Services, Settings>>[] = [hookMixin, eventMixin]\n  version: string = version\n  _isSetup = false\n\n  protected registerHooks: (this: any, allHooks: any) => any\n\n  constructor() {\n    super()\n    this.registerHooks = enableHooks(this)\n    this.registerHooks({\n      around: [eventHook]\n    })\n  }\n\n  get<L extends keyof Settings & string>(name: L): Settings[L] {\n    return this.settings[name]\n  }\n\n  set<L extends keyof Settings & string>(name: L, value: Settings[L]) {\n    this.settings[name] = value\n    return this\n  }\n\n  configure(callback: (this: this, app: this) => void) {\n    callback.call(this, this)\n\n    return this\n  }\n\n  defaultService(location: string): ServiceInterface {\n    throw new Error(`Can not find service '${location}'`)\n  }\n\n  service<L extends keyof Services & string>(\n    location: L\n  ): FeathersService<this, keyof any extends keyof Services ? Service : Services[L]> {\n    const path = (stripSlashes(location) || '/') as L\n    const current = this.services.hasOwnProperty(path) ? this.services[path] : undefined\n\n    if (typeof current === 'undefined') {\n      this.use(path, this.defaultService(path) as any)\n      return this.service(path)\n    }\n\n    return current as any\n  }\n\n  protected _setup() {\n    this._isSetup = true\n\n    return Object.keys(this.services)\n      .reduce(\n        (current, path) =>\n          current.then(() => {\n            const service: any = this.service(path as any)\n\n            if (typeof service.setup === 'function') {\n              debug(`Setting up service for \\`${path}\\``)\n\n              return service.setup(this, path)\n            }\n          }),\n        Promise.resolve()\n      )\n      .then(() => this)\n  }\n\n  get setup() {\n    return this._setup\n  }\n\n  set setup(value) {\n    this._setup = (value as any)[HOOKS]\n      ? value\n      : hooks(\n          value,\n          middleware().params('server').props({\n            app: this\n          })\n        )\n  }\n\n  protected _teardown() {\n    this._isSetup = false\n\n    return Object.keys(this.services)\n      .reduce(\n        (current, path) =>\n          current.then(() => {\n            const service: any = this.service(path as any)\n\n            if (typeof service.teardown === 'function') {\n              debug(`Tearing down service for \\`${path}\\``)\n\n              return service.teardown(this, path)\n            }\n          }),\n        Promise.resolve()\n      )\n      .then(() => this)\n  }\n\n  get teardown() {\n    return this._teardown\n  }\n\n  set teardown(value) {\n    this._teardown = (value as any)[HOOKS]\n      ? value\n      : hooks(\n          value,\n          middleware().params('server').props({\n            app: this\n          })\n        )\n  }\n\n  use<L extends keyof Services & string>(\n    path: L,\n    service: keyof any extends keyof Services ? ServiceInterface | Application : Services[L],\n    options?: ServiceOptions<keyof any extends keyof Services ? string : keyof Services[L]>\n  ): this {\n    if (typeof path !== 'string') {\n      throw new Error(`'${path}' is not a valid service path.`)\n    }\n\n    const location = (stripSlashes(path) || '/') as L\n    const subApp = service as Application\n    const isSubApp = typeof subApp.service === 'function' && subApp.services\n\n    if (isSubApp) {\n      Object.keys(subApp.services).forEach((subPath) =>\n        this.use(`${location}/${subPath}` as any, subApp.service(subPath) as any)\n      )\n\n      return this\n    }\n\n    const protoService = wrapService(location, service, options as ServiceOptions)\n    const serviceOptions = getServiceOptions(protoService)\n\n    for (const name of protectedMethods) {\n      if (serviceOptions.methods.includes(name)) {\n        throw new Error(`'${name}' on service '${location}' is not allowed as a custom method name`)\n      }\n    }\n\n    debug(`Registering new service at \\`${location}\\``)\n\n    // Add all the mixins\n    this.mixins.forEach((fn) => fn.call(this, protoService, location, serviceOptions))\n\n    this.services[location] = protoService\n\n    // If we ran setup already, set this service up explicitly, this will not `await`\n    if (this._isSetup && typeof protoService.setup === 'function') {\n      debug(`Setting up service for \\`${location}\\``)\n      protoService.setup(this, location)\n    }\n\n    return this\n  }\n\n  async unuse<L extends keyof Services & string>(\n    location: L\n  ): Promise<FeathersService<this, keyof any extends keyof Services ? Service : Services[L]>> {\n    const path = (stripSlashes(location) || '/') as L\n    const service = this.services[path] as Service\n\n    if (service && typeof service.teardown === 'function') {\n      await service.teardown(this as any, path)\n    }\n\n    delete this.services[path]\n\n    return service as any\n  }\n\n  hooks(hookMap: ApplicationHookOptions<this>) {\n    const untypedMap = hookMap as any\n\n    if (untypedMap.before || untypedMap.after || untypedMap.error || untypedMap.around) {\n      // regular hooks for all service methods\n      this.registerHooks(untypedMap)\n    } else if (untypedMap.setup || untypedMap.teardown) {\n      // .setup and .teardown application hooks\n      hooks(this, untypedMap)\n    } else {\n      // Other registration formats are just `around` hooks\n      this.registerHooks({\n        around: untypedMap\n      })\n    }\n\n    return this\n  }\n}\n"
  },
  {
    "path": "packages/feathers/src/declarations.ts",
    "content": "import { EventEmitter } from 'events'\nimport { NextFunction, HookContext as BaseHookContext } from '@feathersjs/hooks'\n\ntype SelfOrArray<S> = S | S[]\ntype OptionalPick<T, K extends PropertyKey> = Pick<T, Extract<keyof T, K>>\ntype Entries<T> = {\n  [K in keyof T]: [K, T[K]]\n}[keyof T][]\ntype GetKeyByValue<Obj, Value> = Extract<Entries<Obj>[number], [PropertyKey, Value]>[0]\n\nexport type { NextFunction }\n\n/**\n * The object returned from `.find` call by standard database adapters\n */\nexport interface Paginated<T> {\n  total: number\n  limit: number\n  skip: number\n  data: T[]\n}\n\n/**\n * Options that can be passed when registering a service via `app.use(name, service, options)`\n */\nexport interface ServiceOptions<MethodTypes = string> {\n  /**\n   * A list of custom events that this service emits to clients\n   */\n  events?: string[] | readonly string[]\n  /**\n   * A list of service methods that should be available __externally__ to clients\n   */\n  methods?: MethodTypes[] | readonly MethodTypes[]\n  /**\n   * Provide a full list of events that this service should emit to clients.\n   * Unlike the `events` option, this will not be merged with the default events.\n   */\n  serviceEvents?: string[] | readonly string[]\n  /**\n   * Initial data to always add as route params to this service.\n   */\n  routeParams?: { [key: string]: any }\n}\n\nexport interface ClientService<\n  Result = any,\n  Data = Partial<Result>,\n  PatchData = Data,\n  FindResult = Paginated<Result>,\n  P = Params\n> {\n  find(params?: P): Promise<FindResult>\n\n  get(id: Id, params?: P): Promise<Result>\n\n  create(data: Data[], params?: P): Promise<Result[]>\n  create(data: Data, params?: P): Promise<Result>\n\n  update(id: Id, data: Data, params?: P): Promise<Result>\n  update(id: NullableId, data: Data, params?: P): Promise<Result | Result[]>\n  update(id: null, data: Data, params?: P): Promise<Result[]>\n\n  patch(id: NullableId, data: PatchData, params?: P): Promise<Result | Result[]>\n  patch(id: Id, data: PatchData, params?: P): Promise<Result>\n  patch(id: null, data: PatchData, params?: P): Promise<Result[]>\n\n  remove(id: NullableId, params?: P): Promise<Result | Result[]>\n  remove(id: Id, params?: P): Promise<Result>\n  remove(id: null, params?: P): Promise<Result[]>\n}\n\nexport interface ServiceMethods<\n  Result = any,\n  Data = Partial<Result>,\n  ServiceParams = Params,\n  PatchData = Partial<Data>\n> {\n  find(params?: ServiceParams & { paginate?: PaginationParams }): Promise<Result | Result[]>\n\n  get(id: Id, params?: ServiceParams): Promise<Result>\n\n  create(data: Data, params?: ServiceParams): Promise<Result>\n\n  update(id: NullableId, data: Data, params?: ServiceParams): Promise<Result | Result[]>\n\n  patch(id: NullableId, data: PatchData, params?: ServiceParams): Promise<Result | Result[]>\n\n  remove(id: NullableId, params?: ServiceParams): Promise<Result | Result[]>\n\n  setup?(app: Application, path: string): Promise<void>\n\n  teardown?(app: Application, path: string): Promise<void>\n}\n\nexport interface ServiceOverloads<\n  Result = any,\n  Data = Partial<Result>,\n  ServiceParams = Params,\n  PatchData = Partial<Data>\n> {\n  create?(data: Data[], params?: ServiceParams): Promise<Result[]>\n\n  update?(id: Id, data: Data, params?: ServiceParams): Promise<Result>\n\n  update?(id: null, data: Data, params?: ServiceParams): Promise<Result[]>\n\n  patch?(id: Id, data: PatchData, params?: ServiceParams): Promise<Result>\n\n  patch?(id: null, data: PatchData, params?: ServiceParams): Promise<Result[]>\n\n  remove?(id: Id, params?: ServiceParams): Promise<Result>\n\n  remove?(id: null, params?: ServiceParams): Promise<Result[]>\n}\n\n/**\n * A complete service interface. The `ServiceInterface` type should be preferred for customs service\n * implementations\n */\nexport type Service<\n  Result = any,\n  Data = Partial<Result>,\n  ServiceParams = Params,\n  PatchData = Partial<Data>\n> = ServiceMethods<Result, Data, ServiceParams> & ServiceOverloads<Result, Data, ServiceParams, PatchData>\n\n/**\n * The `Service` service interface but with none of the methods required.\n */\nexport type ServiceInterface<\n  Result = any,\n  Data = Partial<Result>,\n  ServiceParams = Params,\n  PatchData = Partial<Data>\n> = Partial<ServiceMethods<Result, Data, ServiceParams, PatchData>>\n\nexport interface ServiceAddons<A = Application, S = Service> extends EventEmitter {\n  id?: string\n  hooks(options: HookOptions<A, S>): this\n}\n\nexport interface ServiceHookOverloads<S, P = Params> {\n  find(params: P & { paginate?: PaginationParams }, context: HookContext): Promise<HookContext>\n\n  get(id: Id, params: P, context: HookContext): Promise<HookContext>\n\n  create(\n    data: ServiceGenericData<S> | ServiceGenericData<S>[],\n    params: P,\n    context: HookContext\n  ): Promise<HookContext>\n\n  update(id: NullableId, data: ServiceGenericData<S>, params: P, context: HookContext): Promise<HookContext>\n\n  patch(id: NullableId, data: ServiceGenericData<S>, params: P, context: HookContext): Promise<HookContext>\n\n  remove(id: NullableId, params: P, context: HookContext): Promise<HookContext>\n}\n\nexport type FeathersService<A = FeathersApplication, S = Service> = S &\n  ServiceAddons<A, S> &\n  OptionalPick<ServiceHookOverloads<S>, keyof S>\n\nexport type CustomMethods<T extends { [key: string]: [any, any] }> = {\n  [K in keyof T]: (data: T[K][0], params?: Params) => Promise<T[K][1]>\n}\n\n/**\n * An interface usually use by transport clients that represents a e.g. HTTP or websocket\n * connection that can be configured on the application.\n */\nexport type TransportConnection<Services = any> = {\n  (app: Application<Services>): void\n  Service: any\n  service: <L extends keyof Services & string>(\n    name: L\n  ) => keyof any extends keyof Services ? ServiceInterface : Services[L]\n}\n\n/**\n * A real-time connection object\n */\nexport interface RealTimeConnection {\n  [key: string]: any\n}\n\n/**\n * The interface for a custom service method. Can e.g. be used to type client side services.\n */\nexport type CustomMethod<T = any, R = T, P extends Params = Params> = (data: T, params?: P) => Promise<R>\n\nexport type ServiceMixin<A> = (service: FeathersService<A>, path: string, options: ServiceOptions) => void\n\nexport type ServiceGenericType<S> = S extends ServiceInterface<infer T> ? T : any\nexport type ServiceGenericData<S> = S extends ServiceInterface<infer _T, infer D> ? D : any\nexport type ServiceGenericParams<S> = S extends ServiceInterface<infer _T, infer _D, infer P> ? P : any\n\nexport interface FeathersApplication<Services = any, Settings = any> {\n  /**\n   * The Feathers application version\n   */\n  version: string\n\n  /**\n   * A list of callbacks that run when a new service is registered\n   */\n  mixins: ServiceMixin<Application<Services, Settings>>[]\n\n  /**\n   * The index of all services keyed by their path.\n   *\n   * __Important:__ Services should always be retrieved via `app.service('name')`\n   * not via `app.services`.\n   */\n  services: Services\n\n  /**\n   * The application settings that can be used via\n   * `app.get` and `app.set`\n   */\n  settings: Settings\n\n  /**\n   * A private-ish indicator if `app.setup()` has been called already\n   */\n  _isSetup: boolean\n\n  /**\n   * Retrieve an application setting by name\n   *\n   * @param name The setting name\n   */\n  get<L extends keyof Settings & string>(name: L): Settings[L]\n\n  /**\n   * Set an application setting\n   *\n   * @param name The setting name\n   * @param value The setting value\n   */\n  set<L extends keyof Settings & string>(name: L, value: Settings[L]): this\n\n  /**\n   * Runs a callback configure function with the current application instance.\n   *\n   * @param callback The callback `(app: Application) => {}` to run\n   */\n  configure(callback: (this: this, app: this) => void): this\n\n  /**\n   * Returns a fallback service instance that will be registered\n   * when no service was found. Usually throws a `NotFound` error\n   * but also used to instantiate client side services.\n   *\n   * @param location The path of the service\n   */\n  defaultService(location: string): ServiceInterface\n\n  /**\n   * Register a new service or a sub-app. When passed another\n   * Feathers application, all its services will be re-registered\n   * with the `path` prefix.\n   *\n   * @param path The path for the service to register\n   * @param service The service object to register or another\n   * Feathers application to use a sub-app under the `path` prefix.\n   * @param options The options for this service\n   */\n  use<L extends keyof Services & string>(\n    path: L,\n    service: keyof any extends keyof Services ? ServiceInterface | Application : Services[L],\n    options?: ServiceOptions<keyof any extends keyof Services ? string : keyof Services[L]>\n  ): this\n\n  /**\n   * Unregister an existing service.\n   *\n   * @param path The name of the service to unregister\n   */\n  unuse<L extends keyof Services & string>(\n    path: L\n  ): Promise<FeathersService<this, keyof any extends keyof Services ? Service : Services[L]>>\n\n  /**\n   * Get the Feathers service instance for a path. This will\n   * be the service originally registered with Feathers functionality\n   * like hooks and events added.\n   *\n   * @param path The name of the service.\n   */\n  service<L extends keyof Services & string>(\n    path: L\n  ): FeathersService<this, keyof any extends keyof Services ? Service : Services[L]>\n\n  /**\n   * Set up the application and call all services `.setup` method if available.\n   *\n   * @param server A server instance (optional)\n   */\n  setup(server?: any): Promise<this>\n\n  /**\n   * Tear down the application and call all services `.teardown` method if available.\n   *\n   * @param server A server instance (optional)\n   */\n  teardown(server?: any): Promise<this>\n\n  /**\n   * Register application level hooks.\n   *\n   * @param map The application hook settings.\n   */\n  hooks(map: ApplicationHookOptions<this>): this\n}\n\n// This needs to be an interface instead of a type\n// so that the declaration can be extended by other modules\nexport interface Application<Services = any, Settings = any>\n  extends FeathersApplication<Services, Settings>, EventEmitter {}\n\nexport type Id = number | string\nexport type NullableId = Id | null\n\nexport interface Query {\n  [key: string]: any\n}\n\nexport interface Params<Q = Query> {\n  query?: Q\n  provider?: string\n  route?: { [key: string]: any }\n  headers?: { [key: string]: any }\n}\n\nexport interface PaginationOptions {\n  default?: number\n  max?: number\n}\n\nexport type PaginationParams = false | PaginationOptions\n\nexport interface Http {\n  /**\n   * A writeable, optional property with status code override.\n   */\n  status?: number\n  /**\n   * A writeable, optional property with headers.\n   */\n  headers?: { [key: string]: string | string[] }\n  /**\n   * A writeable, optional property with `Location` header's value.\n   */\n  location?: string\n}\n\nexport type HookType = 'before' | 'after' | 'error' | 'around'\n\ntype Serv<FA> = FA extends Application<infer S> ? S : never\n\nexport interface HookContext<A = Application, S = any> extends BaseHookContext<ServiceGenericType<S>> {\n  /**\n   * A read only property that contains the Feathers application object. This can be used to\n   * retrieve other services (via context.app.service('name')) or configuration values.\n   */\n  readonly app: A\n  /**\n   * A read only property with the name of the service method (one of find, get,\n   * create, update, patch, remove).\n   */\n  readonly method: string\n  /**\n   * A read only property and contains the service name (or path) without leading or\n   * trailing slashes.\n   */\n  path: 0 extends 1 & S ? keyof Serv<A> & string : GetKeyByValue<Serv<A>, S> & string\n  /**\n   * A read only property and contains the service this hook currently runs on.\n   */\n  readonly service: S\n  /**\n   * A read only property with the hook type (one of 'around', 'before', 'after' or 'error').\n   */\n  readonly type: HookType\n  /**\n   * The list of method arguments. Should not be modified, modify the\n   * `params`, `data` and `id` properties instead.\n   */\n  readonly arguments: any[]\n  /**\n   * A writeable property containing the data of a create, update and patch service\n   * method call.\n   */\n  data?: ServiceGenericData<S>\n  /**\n   * A writeable property with the error object that was thrown in a failed method call.\n   * It is only available in error hooks.\n   */\n  error?: any\n  /**\n   * A writeable property and the id for a get, remove, update and patch service\n   * method call. For remove, update and patch context.id can also be null when\n   * modifying multiple entries. In all other cases it will be undefined.\n   */\n  id?: Id\n  /**\n   * A writeable property that contains the service method parameters (including\n   * params.query).\n   */\n  params: ServiceGenericParams<S>\n  /**\n   * A writeable property containing the result of the successful service method call.\n   * It is only available in after hooks.\n   *\n   * `context.result` can also be set in\n   *\n   * - A before hook to skip the actual service method (database) call\n   * - An error hook to swallow the error and return a result instead\n   */\n  result?: ServiceGenericType<S>\n  /**\n   * A writeable, optional property and contains a 'safe' version of the data that\n   * should be sent to any client. If context.dispatch has not been set context.result\n   * will be sent to the client instead.\n   */\n  dispatch?: ServiceGenericType<S>\n  /**\n   * A writeable, optional property that allows to override the standard HTTP status\n   * code that should be returned.\n   *\n   * @deprecated Use `http.status` instead.\n   */\n  statusCode?: number\n  /**\n   * A writeable, optional property with options specific to HTTP transports.\n   */\n  http?: Http\n  /**\n   * The event emitted by this method. Can be set to `null` to skip event emitting.\n   */\n  event: string | null\n}\n\n// Regular hook typings\nexport type HookFunction<A = Application, S = Service> = (\n  this: S,\n  context: HookContext<A, S>\n) => Promise<HookContext<Application, S> | void> | HookContext<Application, S> | void\n\nexport type Hook<A = Application, S = Service> = HookFunction<A, S>\n\ntype HookMethodMap<A, S> = {\n  [L in keyof S]?: SelfOrArray<HookFunction<A, S>>\n} & { all?: SelfOrArray<HookFunction<A, S>> }\n\ntype HookTypeMap<A, S> = SelfOrArray<HookFunction<A, S>> | HookMethodMap<A, S>\n\n// New @feathersjs/hook typings\nexport type AroundHookFunction<A = Application, S = Service> = (\n  context: HookContext<A, S>,\n  next: NextFunction\n) => Promise<void>\n\nexport type AroundHookMap<A, S> = {\n  [L in keyof S]?: AroundHookFunction<A, S>[]\n} & { all?: AroundHookFunction<A, S>[] }\n\nexport type HookMap<A, S> = {\n  around?: AroundHookMap<A, S>\n  before?: HookTypeMap<A, S>\n  after?: HookTypeMap<A, S>\n  error?: HookTypeMap<A, S>\n}\n\nexport type HookOptions<A, S> = AroundHookMap<A, S> | AroundHookFunction<A, S>[] | HookMap<A, S>\n\nexport interface ApplicationHookContext<A = Application> extends BaseHookContext {\n  app: A\n  server: any\n}\n\nexport type ApplicationHookFunction<A> = (\n  context: ApplicationHookContext<A>,\n  next: NextFunction\n) => Promise<void>\n\nexport type ApplicationHookMap<A> = {\n  setup?: ApplicationHookFunction<A>[]\n  teardown?: ApplicationHookFunction<A>[]\n}\n\nexport type ApplicationHookOptions<A> = HookOptions<A, any> | ApplicationHookMap<A>\n"
  },
  {
    "path": "packages/feathers/src/events.ts",
    "content": "import { EventEmitter } from 'events'\nimport { NextFunction } from '@feathersjs/hooks'\nimport { HookContext, FeathersService } from './declarations'\nimport { getServiceOptions, defaultEventMap } from './service'\n\nexport function eventHook(context: HookContext, next: NextFunction) {\n  const { events } = getServiceOptions((context as any).self)\n  const defaultEvent = (defaultEventMap as any)[context.method] || null\n\n  context.event = defaultEvent\n\n  return next().then(() => {\n    // Send the event only if the service does not do so already (indicated in the `events` option)\n    // This is used for custom events and for client services receiving event from the server\n    if (typeof context.event === 'string' && !events.includes(context.event)) {\n      const results = Array.isArray(context.result) ? context.result : [context.result]\n\n      results.forEach((element) => (context as any).self.emit(context.event, element, context))\n    }\n  })\n}\n\nexport function eventMixin<A>(service: FeathersService<A>) {\n  const isEmitter = typeof service.on === 'function' && typeof service.emit === 'function'\n\n  if (!isEmitter) {\n    Object.assign(service, EventEmitter.prototype)\n  }\n\n  return service\n}\n"
  },
  {
    "path": "packages/feathers/src/hooks.ts",
    "content": "import {\n  getManager,\n  HookContextData,\n  HookManager,\n  HookMap as BaseHookMap,\n  hooks,\n  Middleware,\n  collect\n} from '@feathersjs/hooks'\nimport {\n  Service,\n  ServiceOptions,\n  HookContext,\n  FeathersService,\n  HookMap,\n  AroundHookFunction,\n  HookFunction,\n  HookType\n} from './declarations'\nimport { defaultServiceArguments, getHookMethods } from './service'\n\ntype ConvertedMap = { [type in HookType]: ReturnType<typeof convertHookData> }\n\ntype HookStore = {\n  around: { [method: string]: AroundHookFunction[] }\n  before: { [method: string]: HookFunction[] }\n  after: { [method: string]: HookFunction[] }\n  error: { [method: string]: HookFunction[] }\n  collected: { [method: string]: AroundHookFunction[] }\n  collectedAll: { before?: AroundHookFunction[]; after?: AroundHookFunction[] }\n}\n\ntype HookEnabled = { __hooks: HookStore }\n\nconst types: HookType[] = ['before', 'after', 'error', 'around']\n\nconst isType = (value: any): value is HookType => types.includes(value)\n\n// Converts different hook registration formats into the\n// same internal format\nexport function convertHookData(input: any) {\n  const result: { [method: string]: HookFunction[] | AroundHookFunction[] } = {}\n\n  if (Array.isArray(input)) {\n    result.all = input\n  } else if (typeof input !== 'object') {\n    result.all = [input]\n  } else {\n    for (const key of Object.keys(input)) {\n      const value = input[key]\n      result[key] = Array.isArray(value) ? value : [value]\n    }\n  }\n\n  return result\n}\n\nexport function collectHooks(target: HookEnabled, method: string) {\n  const { collected, collectedAll, around } = target.__hooks\n\n  return [\n    ...(around.all || []),\n    ...(around[method] || []),\n    ...(collectedAll.before || []),\n    ...(collected[method] || []),\n    ...(collectedAll.after || [])\n  ] as AroundHookFunction[]\n}\n\n// Add `.hooks` functionality to an object\nexport function enableHooks(object: any) {\n  const store: HookStore = {\n    around: {},\n    before: {},\n    after: {},\n    error: {},\n    collected: {},\n    collectedAll: {}\n  }\n\n  Object.defineProperty(object, '__hooks', {\n    configurable: true,\n    value: store,\n    writable: true\n  })\n\n  return function registerHooks(this: HookEnabled, input: HookMap<any, any>) {\n    const store = this.__hooks\n    const map = Object.keys(input).reduce((map, type) => {\n      if (!isType(type)) {\n        throw new Error(`'${type}' is not a valid hook type`)\n      }\n\n      map[type] = convertHookData(input[type])\n\n      return map\n    }, {} as ConvertedMap)\n    const types = Object.keys(map) as HookType[]\n\n    types.forEach((type) =>\n      Object.keys(map[type]).forEach((method) => {\n        const mapHooks = map[type][method]\n        const storeHooks: any[] = (store[type][method] ||= [])\n\n        storeHooks.push(...mapHooks)\n\n        if (method === 'all') {\n          if (store.before[method] || store.error[method]) {\n            const beforeAll = collect({\n              before: store.before[method] || [],\n              error: store.error[method] || []\n            })\n            store.collectedAll.before = [beforeAll]\n          }\n\n          if (store.after[method]) {\n            const afterAll = collect({\n              after: store.after[method] || []\n            })\n            store.collectedAll.after = [afterAll]\n          }\n        } else {\n          if (store.before[method] || store.after[method] || store.error[method]) {\n            const collected = collect({\n              before: store.before[method] || [],\n              after: store.after[method] || [],\n              error: store.error[method] || []\n            })\n\n            store.collected[method] = [collected]\n          }\n        }\n      })\n    )\n\n    return this\n  }\n}\n\nexport function createContext(service: Service, method: string, data: HookContextData = {}) {\n  const createContext = (service as any)[method].createContext\n\n  if (typeof createContext !== 'function') {\n    throw new Error(`Can not create context for method ${method}`)\n  }\n\n  return createContext(data) as HookContext\n}\n\nexport class FeathersHookManager<A> extends HookManager {\n  constructor(\n    public app: A,\n    public method: string\n  ) {\n    super()\n    this._middleware = []\n  }\n\n  collectMiddleware(self: any, args: any[]): Middleware[] {\n    const appHooks = collectHooks(this.app as any as HookEnabled, this.method)\n    const middleware = super.collectMiddleware(self, args)\n    const methodHooks = collectHooks(self, this.method)\n\n    return [...appHooks, ...middleware, ...methodHooks]\n  }\n\n  initializeContext(self: any, args: any[], context: HookContext) {\n    const ctx = super.initializeContext(self, args, context)\n\n    ctx.params = ctx.params || {}\n\n    return ctx\n  }\n\n  middleware(mw: Middleware[]) {\n    this._middleware.push(...mw)\n    return this\n  }\n}\n\nexport function hookMixin<A>(this: A, service: FeathersService<A>, path: string, options: ServiceOptions) {\n  if (typeof service.hooks === 'function') {\n    return service\n  }\n\n  const hookMethods = getHookMethods(service, options)\n\n  const serviceMethodHooks = hookMethods.reduce((res, method) => {\n    const params = (defaultServiceArguments as any)[method] || ['data', 'params']\n\n    res[method] = new FeathersHookManager<A>(this, method).params(...params).props({\n      app: this,\n      path,\n      method,\n      service,\n      event: null,\n      type: 'around',\n      get statusCode() {\n        return this.http?.status\n      },\n      set statusCode(value: number) {\n        this.http = this.http || {}\n        this.http.status = value\n      }\n    })\n\n    return res\n  }, {} as BaseHookMap)\n\n  const registerHooks = enableHooks(service)\n\n  hooks(service, serviceMethodHooks)\n\n  service.hooks = function (this: any, hookOptions: any) {\n    if (hookOptions.before || hookOptions.after || hookOptions.error || hookOptions.around) {\n      return registerHooks.call(this, hookOptions)\n    }\n\n    if (Array.isArray(hookOptions)) {\n      return hooks(this, hookOptions)\n    }\n\n    Object.keys(hookOptions).forEach((method) => {\n      const manager = getManager(this[method])\n\n      if (!(manager instanceof FeathersHookManager)) {\n        throw new Error(`Method ${method} is not a Feathers hooks enabled service method`)\n      }\n\n      manager.middleware(hookOptions[method])\n    })\n\n    return this\n  }\n\n  return service\n}\n"
  },
  {
    "path": "packages/feathers/src/index.ts",
    "content": "import { setDebug } from '@feathersjs/commons'\n\nimport version from './version'\nimport { Feathers } from './application'\nimport { Application } from './declarations'\n\nexport function feathers<T = any, S = any>() {\n  return new Feathers<T, S>() as Application<T, S>\n}\n\nfeathers.setDebug = setDebug\n\nexport { version, Feathers }\nexport * from './hooks'\nexport * from './declarations'\nexport * from './service'\n\nif (typeof module !== 'undefined') {\n  module.exports = Object.assign(feathers, module.exports)\n}\n"
  },
  {
    "path": "packages/feathers/src/service.ts",
    "content": "import { EventEmitter } from 'events'\nimport { createSymbol } from '@feathersjs/commons'\nimport { ServiceOptions } from './declarations'\n\nexport const SERVICE = createSymbol('@feathersjs/service')\n\nexport const defaultServiceArguments = {\n  find: ['params'],\n  get: ['id', 'params'],\n  create: ['data', 'params'],\n  update: ['id', 'data', 'params'],\n  patch: ['id', 'data', 'params'],\n  remove: ['id', 'params']\n}\nexport const defaultServiceMethods = ['find', 'get', 'create', 'update', 'patch', 'remove']\n\nexport const defaultEventMap = {\n  create: 'created',\n  update: 'updated',\n  patch: 'patched',\n  remove: 'removed'\n}\n\nexport const defaultServiceEvents = Object.values(defaultEventMap)\n\nexport const protectedMethods = Object.keys(Object.prototype)\n  .concat(Object.keys(EventEmitter.prototype))\n  .concat(['all', 'around', 'before', 'after', 'error', 'hooks', 'setup', 'teardown', 'publish'])\n\nexport function getHookMethods(service: any, options: ServiceOptions) {\n  const { methods } = options\n\n  return (defaultServiceMethods as any as string[])\n    .filter((m) => typeof service[m] === 'function' && !methods.includes(m))\n    .concat(methods)\n}\n\nexport function getServiceOptions(service: any): ServiceOptions {\n  return service[SERVICE]\n}\n\nexport const normalizeServiceOptions = (service: any, options: ServiceOptions = {}): ServiceOptions => {\n  const {\n    methods = defaultServiceMethods.filter((method) => typeof service[method] === 'function'),\n    events = service.events || []\n  } = options\n  const serviceEvents = options.serviceEvents || defaultServiceEvents.concat(events)\n\n  return {\n    ...options,\n    events,\n    methods,\n    serviceEvents\n  }\n}\n\nexport function wrapService(location: string, service: any, options: ServiceOptions) {\n  // Do nothing if this is already an initialized\n  if (service[SERVICE]) {\n    return service\n  }\n\n  const protoService = Object.create(service)\n  const serviceOptions = normalizeServiceOptions(service, options)\n\n  if (\n    Object.keys(serviceOptions.methods).length === 0 &&\n    ![...defaultServiceMethods, 'setup', 'teardown'].some((method) => typeof service[method] === 'function')\n  ) {\n    throw new Error(`Invalid service object passed for path \\`${location}\\``)\n  }\n\n  Object.defineProperty(protoService, SERVICE, {\n    value: serviceOptions\n  })\n\n  return protoService\n}\n"
  },
  {
    "path": "packages/feathers/src/version.ts",
    "content": "export default 'development'\n"
  },
  {
    "path": "packages/feathers/test/application.test.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-empty-function */\nimport assert from 'assert'\nimport { feathers, Feathers, getServiceOptions, Id, version } from '../src'\n\ndescribe('Feathers application', () => {\n  it('initializes', () => {\n    const app = feathers()\n\n    assert.ok(app instanceof Feathers)\n  })\n\n  it('sets the version on main and app instance', () => {\n    const app = feathers()\n\n    assert.ok(version > '5.0.0')\n    assert.ok(app.version > '5.0.0')\n  })\n\n  it('is an event emitter', (done) => {\n    const app = feathers()\n    const original = { hello: 'world' }\n\n    app.on('test', (data: any) => {\n      assert.deepStrictEqual(original, data)\n      done()\n    })\n\n    app.emit('test', original)\n  })\n\n  it('uses .defaultService if available', async () => {\n    const app = feathers()\n\n    assert.throws(() => app.service('/todos/'), {\n      message: \"Can not find service 'todos'\"\n    })\n\n    app.defaultService = function (location: string) {\n      assert.strictEqual(location, 'todos')\n      return {\n        async get(id: string) {\n          return {\n            id,\n            description: `You have to do ${id}!`\n          }\n        }\n      }\n    }\n\n    const data = await app.service('/todos/').get('dishes')\n\n    assert.deepStrictEqual(data, {\n      id: 'dishes',\n      description: 'You have to do dishes!'\n    })\n  })\n\n  it('additionally passes `app` as .configure parameter (#558)', (done) => {\n    feathers().configure(function (app) {\n      assert.strictEqual(this, app)\n      done()\n    })\n  })\n\n  describe('Services', () => {\n    it('calling .use with invalid path throws', () => {\n      const app = feathers()\n\n      //@ts-ignore\n      assert.throws(() => app.use(null, {}), {\n        message: \"'null' is not a valid service path.\"\n      })\n\n      // @ts-ignore\n      assert.throws(() => app.use({}, {}), {\n        message: \"'[object Object]' is not a valid service path.\"\n      })\n    })\n\n    it('calling .use with a non service object throws', () => {\n      const app = feathers()\n\n      // @ts-ignore\n      assert.throws(() => app.use('/bla', function () {}), {\n        message: 'Invalid service object passed for path `bla`'\n      })\n    })\n\n    it('registers and wraps a new service and can unregister (#2035)', async () => {\n      const dummyService = {\n        async setup(this: any, _app: any, path: string) {\n          this.path = path\n        },\n\n        async teardown(this: any, _app: any, path: string) {\n          this.path = path\n        },\n\n        async create(data: any) {\n          return data\n        }\n      }\n\n      const app = feathers<{ dummy: typeof dummyService }>().use('dummy', dummyService)\n      const wrappedService = app.service('dummy')\n\n      assert.strictEqual(\n        Object.getPrototypeOf(wrappedService),\n        dummyService,\n        'Object points to original service prototype'\n      )\n\n      const data = await wrappedService.create({\n        message: 'Test message'\n      })\n\n      assert.strictEqual(data.message, 'Test message')\n\n      await app.unuse('dummy')\n\n      assert.strictEqual(Object.keys(app.services).length, 0)\n      assert.throws(() => app.service('dummy'), {\n        message: \"Can not find service 'dummy'\"\n      })\n    })\n\n    it('can not register custom methods on a protected methods', async () => {\n      const dummyService = {\n        async create(data: any) {\n          return data\n        },\n        async removeListener(data: any) {\n          return data\n        },\n        async setup() {},\n\n        async teardown() {}\n      }\n\n      assert.throws(\n        () =>\n          feathers().use('/dummy', dummyService, {\n            methods: ['create', 'removeListener']\n          }),\n        {\n          message: \"'removeListener' on service 'dummy' is not allowed as a custom method name\"\n        }\n      )\n      assert.throws(\n        () =>\n          feathers().use('/dummy', dummyService, {\n            methods: ['create', 'setup']\n          }),\n        {\n          message: \"'setup' on service 'dummy' is not allowed as a custom method name\"\n        }\n      )\n      assert.throws(\n        () =>\n          feathers().use('/dummy', dummyService, {\n            methods: ['create', 'teardown']\n          }),\n        {\n          message: \"'teardown' on service 'dummy' is not allowed as a custom method name\"\n        }\n      )\n    })\n\n    it('can register service with no external methods', async () => {\n      const dummyService = {\n        async create(data: any) {\n          return data\n        }\n      }\n\n      feathers().use('dummy', dummyService, {\n        methods: []\n      })\n    })\n\n    it('can use a root level service', async () => {\n      const app = feathers().use('/', {\n        async get(id: string) {\n          return { id }\n        }\n      })\n\n      const result = await app.service('/').get('test')\n\n      assert.deepStrictEqual(result, { id: 'test' })\n    })\n\n    it('services can be re-used (#566)', (done) => {\n      const service = {\n        async create(data: any) {\n          return data\n        }\n      }\n      const app1 = feathers<{ dummy: typeof service; testing: any }>()\n      const app2 = feathers<{ dummy: typeof service; testing: any }>()\n\n      app2.use('dummy', {\n        async create(data: any) {\n          return data\n        }\n      })\n\n      const dummy = app2.service('dummy')\n\n      dummy.hooks({\n        before: {\n          create: [\n            (hook) => {\n              hook.data.fromHook = true\n            }\n          ]\n        }\n      })\n\n      dummy.on('created', (data: any) => {\n        assert.deepStrictEqual(data, {\n          message: 'Hi',\n          fromHook: true\n        })\n        done()\n      })\n\n      app1.use('testing', app2.service('dummy'))\n\n      app1.service('testing').create({ message: 'Hi' })\n    })\n\n    it('async hooks run before regular hooks', async () => {\n      const service = {\n        async create(data: any) {\n          return data\n        }\n      }\n      const app = feathers<{ dummy: typeof service }>()\n\n      app.use('dummy', service)\n\n      const dummy = app.service('dummy')\n\n      dummy.hooks({\n        before: {\n          create(ctx) {\n            ctx.data.order.push('before')\n          }\n        }\n      })\n\n      dummy.hooks([\n        async (ctx: any, next: any) => {\n          ctx.data.order = ['async']\n          await next()\n        }\n      ])\n\n      const result = await dummy.create({\n        message: 'hi'\n      })\n\n      assert.deepStrictEqual(result, {\n        message: 'hi',\n        order: ['async', 'before']\n      })\n    })\n\n    it('services conserve Symbols', () => {\n      const TEST = Symbol('test')\n      const dummyService = {\n        [TEST]: true,\n\n        async setup(this: any, _app: any, path: string) {\n          this.path = path\n        },\n\n        async create(data: any) {\n          return data\n        }\n      }\n\n      const app = feathers().use('/dummy', dummyService)\n      const wrappedService = app.service('dummy')\n\n      assert.ok((wrappedService as any)[TEST])\n    })\n\n    it('methods conserve Symbols', () => {\n      const TEST = Symbol('test')\n      const dummyService = {\n        async setup(this: any, _app: any, path: string) {\n          this.path = path\n        },\n\n        async create(data: any) {\n          return data\n        }\n      }\n\n      ;(dummyService.create as any)[TEST] = true\n\n      const app = feathers().use('/dummy', dummyService)\n      const wrappedService = app.service('dummy')\n\n      assert.ok((wrappedService.create as any)[TEST])\n    })\n\n    it('.service does does not access object properties', async () => {\n      const app = feathers()\n\n      assert.throws(() => app.service('something'), {\n        message: \"Can not find service 'something'\"\n      })\n      assert.throws(() => app.service('__proto__'), {\n        message: \"Can not find service '__proto__'\"\n      })\n      assert.throws(() => app.service('toString'), {\n        message: \"Can not find service 'toString'\"\n      })\n    })\n  })\n\n  describe('Express app options compatibility', function () {\n    describe('.set()', () => {\n      it('should set a value', () => {\n        const app = feathers()\n        app.set('foo', 'bar')\n        assert.strictEqual(app.get('foo'), 'bar')\n      })\n\n      it('should return the app', () => {\n        const app = feathers()\n        assert.strictEqual(app.set('foo', 'bar'), app)\n      })\n\n      it('should return the app when undefined', () => {\n        const app = feathers()\n        assert.strictEqual(app.set('foo', undefined), app)\n      })\n    })\n\n    describe('.get()', () => {\n      it('should return undefined when unset', () => {\n        const app = feathers()\n        assert.strictEqual(app.get('foo'), undefined)\n      })\n\n      it('should otherwise return the value', () => {\n        const app = feathers()\n        app.set('foo', 'bar')\n        assert.strictEqual(app.get('foo'), 'bar')\n      })\n    })\n  })\n\n  describe('.setup and .teardown', () => {\n    it('app.setup and app.teardown calls .setup and .teardown on all services', async () => {\n      const app = feathers()\n      let setupCount = 0\n      let teardownCount = 0\n\n      app.use('/dummy', {\n        async setup(appRef: any, path: any) {\n          setupCount++\n          assert.strictEqual(appRef, app)\n          assert.strictEqual(path, 'dummy')\n        },\n\n        async teardown(appRef: any, path: any) {\n          teardownCount++\n          assert.strictEqual(appRef, app)\n          assert.strictEqual(path, 'dummy')\n        }\n      })\n\n      app.use('/simple', {\n        get(id: string) {\n          return Promise.resolve({ id })\n        }\n      })\n\n      app.use('/dummy2', {\n        async setup(appRef: any, path: any) {\n          setupCount++\n          assert.strictEqual(appRef, app)\n          assert.strictEqual(path, 'dummy2')\n        },\n\n        async teardown(appRef: any, path: any) {\n          teardownCount++\n          assert.strictEqual(appRef, app)\n          assert.strictEqual(path, 'dummy2')\n        }\n      })\n\n      await app.setup()\n\n      assert.ok((app as any)._isSetup)\n      assert.strictEqual(setupCount, 2)\n\n      await app.teardown()\n\n      assert.ok(!(app as any)._isSetup)\n      assert.strictEqual(teardownCount, 2)\n    })\n\n    it('registering app.setup but while still pending will be set up', (done) => {\n      const app = feathers()\n\n      app.setup()\n\n      app.use('/dummy', {\n        async setup(appRef: any, path: any) {\n          assert.ok((app as any)._isSetup)\n          assert.strictEqual(appRef, app)\n          assert.strictEqual(path, 'dummy')\n          done()\n        }\n      })\n    })\n  })\n\n  describe('.teardown', () => {\n    it('app.teardown calls .teardown on all services', async () => {\n      const app = feathers()\n      let teardownCount = 0\n\n      app.use('/dummy', {\n        async setup() {},\n        async teardown(appRef: any, path: any) {\n          teardownCount++\n          assert.strictEqual(appRef, app)\n          assert.strictEqual(path, 'dummy')\n        }\n      })\n\n      app.use('/simple', {\n        get(id: string) {\n          return Promise.resolve({ id })\n        }\n      })\n\n      app.use('/dummy2', {\n        async setup() {},\n        async teardown(appRef: any, path: any) {\n          teardownCount++\n          assert.strictEqual(appRef, app)\n          assert.strictEqual(path, 'dummy2')\n        }\n      })\n\n      await app.setup()\n      await app.teardown()\n\n      assert.equal((app as any)._isSetup, false)\n      assert.strictEqual(teardownCount, 2)\n    })\n  })\n\n  describe('mixins', () => {\n    class Dummy {\n      dummy = true\n      async get(id: Id) {\n        return { id }\n      }\n    }\n\n    it('are getting called with a service and default options', () => {\n      const app = feathers()\n      let mixinRan = false\n\n      app.mixins.push(function (service: any, location: any, options: any) {\n        assert.ok(service.dummy)\n        assert.strictEqual(location, 'dummy')\n        assert.deepStrictEqual(options, getServiceOptions(service))\n        mixinRan = true\n      })\n\n      app.use('/dummy', new Dummy())\n\n      assert.ok(mixinRan)\n\n      app.setup()\n    })\n\n    it('are getting called with a service and service options', () => {\n      const app = feathers()\n      const opts = { events: ['bla'] }\n\n      let mixinRan = false\n\n      app.mixins.push(function (service: any, location: any, options: any) {\n        assert.ok(service.dummy)\n        assert.strictEqual(location, 'dummy')\n        assert.deepStrictEqual(options, getServiceOptions(service))\n        mixinRan = true\n      })\n\n      app.use('/dummy', new Dummy(), opts)\n\n      assert.ok(mixinRan)\n\n      app.setup()\n    })\n  })\n\n  describe('sub apps', () => {\n    it('re-registers sub-app services with prefix', (done) => {\n      const app = feathers()\n      const subApp = feathers()\n\n      subApp\n        .use('/service1', {\n          async get(id: string) {\n            return {\n              id,\n              name: 'service1'\n            }\n          }\n        })\n        .use('/service2', {\n          async get(id: string) {\n            return {\n              id,\n              name: 'service2'\n            }\n          },\n\n          async create(data: any) {\n            return data\n          }\n        })\n\n      app.use('/api/', subApp)\n\n      app.service('/api/service2').once('created', (data: any) => {\n        assert.deepStrictEqual(data, {\n          message: 'This is a test'\n        })\n\n        subApp.service('service2').once('created', (data: any) => {\n          assert.deepStrictEqual(data, {\n            message: 'This is another test'\n          })\n\n          done()\n        })\n\n        app.service('api/service2').create({\n          message: 'This is another test'\n        })\n      })\n      ;(async () => {\n        let data = await app.service('/api/service1').get(10)\n        assert.strictEqual(data.name, 'service1')\n\n        data = await app.service('/api/service2').get(1)\n        assert.strictEqual(data.name, 'service2')\n\n        await subApp.service('service2').create({\n          message: 'This is a test'\n        })\n      })()\n    })\n  })\n})\n"
  },
  {
    "path": "packages/feathers/test/declarations.test.ts",
    "content": "import assert from 'assert'\nimport { hooks } from '@feathersjs/hooks'\nimport { feathers, ServiceInterface, Application, HookContext, NextFunction } from '../src'\n\ninterface Todo {\n  id: number\n  message: string\n  completed: boolean\n}\n\ninterface TodoData {\n  message: string\n  completed?: boolean\n}\n\nclass TodoService implements ServiceInterface<Todo, TodoData> {\n  constructor(public todos: Todo[] = []) {}\n\n  async find() {\n    return this.todos\n  }\n\n  async create(data: TodoData) {\n    const { completed = false } = data\n    const todo: Todo = {\n      id: this.todos.length,\n      completed,\n      message: data.message\n    }\n\n    this.todos.push(todo)\n\n    return todo\n  }\n\n  async setup(app: Application) {\n    assert.ok(app)\n  }\n}\n\ninterface Configuration {\n  port: number\n}\n\ninterface Services {\n  todos: TodoService\n  v2: Application<Record<string, unknown>, Configuration>\n}\n\ntype MainApp = Application<Services, Configuration>\n\nconst myHook = async (context: HookContext<MainApp>, next: NextFunction) => {\n  assert.ok(context.app.service('todos'))\n  await next()\n}\n\nhooks(TodoService.prototype, [\n  async (_ctx: HookContext<MainApp>, next) => {\n    await next()\n  }\n])\n\nhooks(TodoService, {\n  create: [myHook]\n})\n\ndescribe('Feathers typings', () => {\n  it('initializes the app with proper types', async () => {\n    const app: MainApp = feathers<Services, Configuration>()\n    const app2 = feathers<Record<string, unknown>, Configuration>()\n\n    app.set('port', 80)\n    app.use('todos', new TodoService(), {\n      methods: ['find', 'create']\n    })\n    app.use('v2', app2)\n\n    const service = app.service('todos')\n\n    service.on('created', (data) => {\n      assert.ok(data)\n    })\n\n    service.hooks({\n      before: {\n        all: [],\n        create: [\n          async (context) => {\n            const { result, data, service } = context\n\n            assert.ok(service instanceof TodoService)\n            assert.ok(result)\n            assert.ok(data)\n            assert.ok(context.app.service('todos'))\n          }\n        ]\n      }\n    })\n\n    service.hooks({\n      create: [\n        async (context, next) => {\n          assert.ok(context)\n          await next()\n        },\n        async (context, next) => {\n          assert.ok(context)\n          await next()\n        },\n        myHook\n      ]\n    })\n  })\n})\n"
  },
  {
    "path": "packages/feathers/test/events.test.ts",
    "content": "import assert from 'assert'\nimport { EventEmitter } from 'events'\n\nimport { feathers } from '../src'\n\ndescribe('Service events', () => {\n  it('app is an event emitter', (done) => {\n    const app = feathers()\n\n    assert.strictEqual(typeof app.on, 'function')\n\n    app.on('test', (data: any) => {\n      assert.deepStrictEqual(data, { message: 'app' })\n      done()\n    })\n    app.emit('test', { message: 'app' })\n  })\n\n  it('works with service that is already an EventEmitter', (done) => {\n    const app = feathers()\n    const service: any = new EventEmitter()\n\n    service.create = async function (data: any) {\n      return data\n    }\n\n    service.on('created', (data: any) => {\n      assert.deepStrictEqual(data, {\n        message: 'testing'\n      })\n      done()\n    })\n\n    app.use('/emitter', service)\n\n    app.service('emitter').create({\n      message: 'testing'\n    })\n  })\n\n  describe('emits event data on a service', () => {\n    it('.create and created', (done) => {\n      const app = feathers().use('/creator', {\n        async create(data: any) {\n          return data\n        }\n      })\n\n      const service = app.service('creator')\n\n      service.on('created', (data: any) => {\n        assert.deepStrictEqual(data, { message: 'Hello' })\n        done()\n      })\n\n      service.create({ message: 'Hello' })\n    })\n\n    it('allows to skip event emitting', (done) => {\n      const app = feathers().use('/creator', {\n        async create(data: any) {\n          return data\n        }\n      })\n\n      const service = app.service('creator')\n\n      service.hooks({\n        before: {\n          create(context: any) {\n            context.event = null\n\n            return context\n          }\n        }\n      })\n\n      service.on('created', () => {\n        done(new Error('Should never get here'))\n      })\n\n      service.create({ message: 'Hello' }).then(() => done())\n    })\n\n    it('.update and updated', (done) => {\n      const app = feathers().use('/creator', {\n        async update(id: any, data: any) {\n          return Object.assign({ id }, data)\n        }\n      })\n\n      const service = app.service('creator')\n\n      service.on('updated', (data: any) => {\n        assert.deepStrictEqual(data, { id: 10, message: 'Hello' })\n        done()\n      })\n\n      service.update(10, { message: 'Hello' })\n    })\n\n    it('.patch and patched', (done) => {\n      const app = feathers().use('/creator', {\n        async patch(id: any, data: any) {\n          return Object.assign({ id }, data)\n        }\n      })\n\n      const service = app.service('creator')\n\n      service.on('patched', (data: any) => {\n        assert.deepStrictEqual(data, { id: 12, message: 'Hello' })\n        done()\n      })\n\n      service.patch(12, { message: 'Hello' })\n    })\n\n    it('.remove and removed', (done) => {\n      const app = feathers().use('/creator', {\n        async remove(id: any) {\n          return { id }\n        }\n      })\n\n      const service = app.service('creator')\n\n      service.on('removed', (data: any) => {\n        assert.deepStrictEqual(data, { id: 22 })\n        done()\n      })\n\n      service.remove(22)\n    })\n  })\n\n  describe('emits event data arrays on a service', () => {\n    it('.create and created with array', async () => {\n      const app = feathers().use('/creator', {\n        async create(data: any) {\n          if (Array.isArray(data)) {\n            return Promise.all(data.map((current) => (this as any).create(current)))\n          }\n\n          return data\n        }\n      })\n\n      const service = app.service('creator')\n      const createItems = [{ message: 'Hello 0' }, { message: 'Hello 1' }]\n\n      const events = Promise.all(\n        createItems.map((element, index) => {\n          return new Promise<void>((resolve) => {\n            service.on('created', (data: any) => {\n              if (data.message === element.message) {\n                assert.deepStrictEqual(data, { message: `Hello ${index}` })\n                resolve()\n              }\n            })\n          })\n        })\n      )\n\n      await service.create(createItems)\n      await events\n    })\n\n    it('.update and updated with array', async () => {\n      const app = feathers().use('/creator', {\n        async update(id: any, data: any) {\n          if (Array.isArray(data)) {\n            return Promise.all(data.map((current, index) => (this as any).update(index, current)))\n          }\n          return Object.assign({ id }, data)\n        }\n      })\n\n      const service = app.service('creator')\n      const updateItems = [{ message: 'Hello 0' }, { message: 'Hello 1' }]\n\n      const events = Promise.all(\n        updateItems.map((element, index) => {\n          return new Promise<void>((resolve) => {\n            service.on('updated', (data: any) => {\n              if (data.message === element.message) {\n                assert.deepStrictEqual(data, {\n                  id: index,\n                  message: `Hello ${index}`\n                })\n                resolve()\n              }\n            })\n          })\n        })\n      )\n\n      await service.update(null, updateItems)\n      await events\n    })\n\n    it('.patch and patched with array', async () => {\n      const app = feathers().use('/creator', {\n        async patch(id: any, data: any) {\n          if (Array.isArray(data)) {\n            return Promise.all(data.map((current, index) => (this as any).patch(index, current)))\n          }\n          return Object.assign({ id }, data)\n        }\n      })\n\n      const service = app.service('creator')\n      const patchItems = [{ message: 'Hello 0' }, { message: 'Hello 1' }]\n\n      const events = Promise.all(\n        patchItems.map((element, index) => {\n          return new Promise<void>((resolve) => {\n            service.on('patched', (data: any) => {\n              if (data.message === element.message) {\n                assert.deepStrictEqual(data, {\n                  id: index,\n                  message: `Hello ${index}`\n                })\n                resolve()\n              }\n            })\n          })\n        })\n      )\n\n      await service.patch(null, patchItems)\n      await events\n    })\n\n    it('.remove and removed with array', async () => {\n      const removeItems = [{ message: 'Hello 0' }, { message: 'Hello 1' }]\n\n      const app = feathers().use('/creator', {\n        async remove(id: any, data: any) {\n          if (id === null) {\n            return Promise.all(removeItems.map((current, index) => (this as any).remove(index, current)))\n          }\n          return Object.assign({ id }, data)\n        }\n      })\n\n      const service = app.service('creator')\n\n      const events = Promise.all(\n        removeItems.map((element, index) => {\n          return new Promise<void>((resolve) => {\n            service.on('removed', (data: any) => {\n              if (data.message === element.message) {\n                assert.deepStrictEqual(data, {\n                  id: index,\n                  message: `Hello ${index}`\n                })\n                resolve()\n              }\n            })\n          })\n        })\n      )\n\n      await service.remove(null)\n      await events\n    })\n  })\n\n  describe('event format', () => {\n    it('also emits the actual hook object', (done) => {\n      const app = feathers().use('/creator', {\n        async create(data: any) {\n          return data\n        }\n      })\n\n      const service = app.service('creator')\n\n      service.hooks({\n        after(hook: any) {\n          hook.changed = true\n        }\n      })\n\n      service.on('created', (data: any, hook: any) => {\n        try {\n          assert.deepStrictEqual(data, { message: 'Hi' })\n          assert.ok(hook.changed)\n          assert.strictEqual(hook.service, service)\n          assert.strictEqual(hook.method, 'create')\n          assert.strictEqual(hook.type, 'around')\n          done()\n        } catch (error: any) {\n          done(error)\n        }\n      })\n\n      service.create({ message: 'Hi' })\n    })\n\n    it('events indicated by the service are not sent automatically', (done) => {\n      class Creator {\n        events = ['created']\n        async create(data: any) {\n          return data\n        }\n      }\n      const app = feathers().use('/creator', new Creator())\n      const service = app.service('creator')\n\n      service.on('created', (data: any) => {\n        assert.deepStrictEqual(data, { message: 'custom event' })\n        done()\n      })\n\n      service.create({ message: 'hello' })\n      service.emit('created', { message: 'custom event' })\n    })\n  })\n})\n"
  },
  {
    "path": "packages/feathers/test/hooks/after.test.ts",
    "content": "import assert from 'assert'\nimport { feathers, Id } from '../../src'\n\ndescribe('`after` hooks', () => {\n  it('.after hooks can return a promise', async () => {\n    const app = feathers().use('/dummy', {\n      async get(id: Id) {\n        return {\n          id,\n          description: `You have to do ${id}`\n        }\n      },\n\n      async find() {\n        return []\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        async get(hook) {\n          hook.result.ran = true\n          return hook\n        },\n\n        async find() {\n          throw new Error('You can not see this')\n        }\n      }\n    })\n\n    const data = await service.get('laundry', {})\n\n    assert.deepStrictEqual(data, {\n      id: 'laundry',\n      description: 'You have to do laundry',\n      ran: true\n    })\n\n    await assert.rejects(() => service.find({}), {\n      message: 'You can not see this'\n    })\n  })\n\n  it('.after hooks do not need to return anything', async () => {\n    const app = feathers().use('/dummy', {\n      async get(id: Id) {\n        return {\n          id,\n          description: `You have to do ${id}`\n        }\n      },\n\n      async find() {\n        return []\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        get(context) {\n          context.result.ran = true\n        },\n\n        find() {\n          throw new Error('You can not see this')\n        }\n      }\n    })\n\n    const data = await service.get('laundry')\n\n    assert.deepStrictEqual(data, {\n      id: 'laundry',\n      description: 'You have to do laundry',\n      ran: true\n    })\n\n    await assert.rejects(() => service.find(), {\n      message: 'You can not see this'\n    })\n  })\n\n  it('gets mixed into a service and modifies data', async () => {\n    const dummyService = {\n      async create(data: any) {\n        return data\n      }\n    }\n\n    const app = feathers().use('/dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        create(context) {\n          assert.strictEqual(context.type, 'after')\n\n          context.result.some = 'thing'\n\n          return context\n        }\n      }\n    })\n\n    const data = await service.create({ my: 'data' })\n\n    assert.deepStrictEqual({ my: 'data', some: 'thing' }, data, 'Got modified data')\n  })\n\n  it('also makes the app available at hook.app', async () => {\n    const dummyService = {\n      async create(data: any) {\n        return data\n      }\n    }\n\n    const app = feathers().use('/dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        create(context) {\n          context.result.appPresent = typeof context.app !== 'undefined'\n          assert.strictEqual(context.result.appPresent, true)\n\n          return context\n        }\n      }\n    })\n\n    const data = await service.create({ my: 'data' })\n\n    assert.deepStrictEqual({ my: 'data', appPresent: true }, data, 'The app was present in the hook.')\n  })\n\n  it('returns errors', async () => {\n    const dummyService = {\n      async update(_id: any, data: any) {\n        return data\n      }\n    }\n\n    const app = feathers().use('/dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        update() {\n          throw new Error('This did not work')\n        }\n      }\n    })\n\n    await assert.rejects(() => service.update(1, { my: 'data' }), {\n      message: 'This did not work'\n    })\n  })\n\n  it('does not run after hook when there is an error', async () => {\n    const dummyService = {\n      async remove() {\n        throw new Error('Error removing item')\n      }\n    }\n\n    const app = feathers().use('/dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        remove() {\n          assert.ok(false, 'This should never get called')\n        }\n      }\n    })\n\n    await assert.rejects(() => service.remove(1, {}), {\n      message: 'Error removing item'\n    })\n  })\n\n  it('adds .after() and chains multiple hooks for the same method', async () => {\n    const dummyService = {\n      async create(data: any) {\n        return data\n      }\n    }\n\n    const app = feathers().use('/dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        create(context) {\n          context.result.some = 'thing'\n\n          return context\n        }\n      }\n    })\n\n    service.hooks({\n      after: {\n        create(context) {\n          context.result.other = 'stuff'\n        }\n      }\n    })\n\n    const data = await service.create({ my: 'data' })\n\n    assert.deepStrictEqual(\n      {\n        my: 'data',\n        some: 'thing',\n        other: 'stuff'\n      },\n      data,\n      'Got modified data'\n    )\n  })\n\n  it('chains multiple after hooks using array syntax', async () => {\n    const dummyService = {\n      async create(data: any) {\n        return data\n      }\n    }\n\n    const app = feathers().use('/dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        create: [\n          function (context) {\n            context.result.some = 'thing'\n\n            return context\n          },\n          function (context) {\n            context.result.other = 'stuff'\n\n            return context\n          }\n        ]\n      }\n    })\n\n    const data = await service.create({ my: 'data' })\n\n    assert.deepStrictEqual(\n      {\n        my: 'data',\n        some: 'thing',\n        other: 'stuff'\n      },\n      data,\n      'Got modified data'\n    )\n  })\n\n  it('.after hooks run in the correct order (#13)', async () => {\n    const app = feathers().use('/dummy', {\n      async get(id: any) {\n        return { id }\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        get(context) {\n          context.result.items = ['first']\n\n          return context\n        }\n      }\n    })\n\n    service.hooks({\n      after: {\n        get: [\n          function (context) {\n            context.result.items.push('second')\n\n            return context\n          },\n          function (context) {\n            context.result.items.push('third')\n\n            return context\n          }\n        ]\n      }\n    })\n\n    const data = await service.get(10)\n\n    assert.deepStrictEqual(data.items, ['first', 'second', 'third'])\n  })\n\n  it('after all hooks (#11)', async () => {\n    const app = feathers().use('/dummy', {\n      async get(id: any) {\n        const items: any[] = []\n\n        return { id, items }\n      },\n\n      async find() {\n        return []\n      }\n    })\n\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        all(context) {\n          context.result.afterAllObject = true\n\n          return context\n        }\n      }\n    })\n\n    service.hooks({\n      after: [\n        function (context) {\n          context.result.afterAllMethodArray = true\n\n          return context\n        }\n      ]\n    })\n\n    let data = await service.find({})\n\n    assert.ok(data.afterAllObject)\n    assert.ok(data.afterAllMethodArray)\n\n    data = await service.get(1, {})\n\n    assert.ok(data.afterAllObject)\n    assert.ok(data.afterAllMethodArray)\n  })\n\n  it('after hooks have service as context and keep it in service method (#17)', async () => {\n    class Dummy {\n      number = 42\n      async get(id: any) {\n        return {\n          id,\n          number: this.number\n        }\n      }\n    }\n    const app = feathers().use('/dummy', new Dummy())\n\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        get(this: any, hook) {\n          hook.result.test = this.number + 1\n\n          return hook\n        }\n      }\n    })\n\n    const data = await service.get(10)\n\n    assert.deepStrictEqual(data, {\n      id: 10,\n      number: 42,\n      test: 43\n    })\n  })\n\n  it('.after all and method specific hooks run in the correct order (#3002)', async () => {\n    const app = feathers().use('/dummy', {\n      async get(id: any) {\n        return { id, items: [] as any }\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        all(context) {\n          context.result.items.push('first')\n\n          return context\n        },\n        get: [\n          function (context) {\n            context.result.items.push('second')\n\n            return context\n          },\n          function (context) {\n            context.result.items.push('third')\n\n            return context\n          }\n        ]\n      }\n    })\n\n    const data = await service.get(10)\n\n    assert.deepStrictEqual(data.items, ['first', 'second', 'third'])\n  })\n})\n"
  },
  {
    "path": "packages/feathers/test/hooks/app.test.ts",
    "content": "import assert from 'assert'\n\nimport { feathers, Application, ApplicationHookMap, ServiceInterface, Params } from '../../src'\n\ntype Todo = {\n  id?: string\n  params?: TodoParams\n  data?: any\n  test?: string\n  order?: string[]\n}\n\ninterface TodoParams extends Params {\n  order: string[]\n  ran: boolean\n}\n\ntype TodoService = ServiceInterface<Todo, Todo, TodoParams> & {\n  customMethod(data: any, params?: TodoParams): Promise<any>\n}\n\ntype App = Application<{ todos: TodoService }>\n\ndescribe('app.hooks', () => {\n  let app: App\n\n  beforeEach(() => {\n    app = feathers<{ todos: TodoService }>().use(\n      'todos',\n      {\n        async get(id: any, params: any) {\n          if (id === 'error') {\n            throw new Error('Something went wrong')\n          }\n\n          return { id, params }\n        },\n\n        async create(data: any, params: any) {\n          return { data, params }\n        },\n\n        async customMethod(data: any, params: TodoParams) {\n          return { data, params }\n        }\n      },\n      {\n        methods: ['get', 'create', 'customMethod']\n      }\n    )\n  })\n\n  it('app has the .hooks method', () => {\n    assert.strictEqual(typeof app.hooks, 'function')\n  })\n\n  it('.setup and .teardown special hooks', async () => {\n    const app = feathers()\n\n    // Test that setup and teardown can be overwritten\n    const oldSetup = app.setup\n    app.setup = function (arg: any) {\n      return oldSetup.call(this, arg)\n    }\n    const oldTeardown = app.teardown\n    app.teardown = function (arg: any) {\n      return oldTeardown.call(this, arg)\n    }\n\n    const order: string[] = []\n    const hooks: ApplicationHookMap<typeof app> = {\n      setup: [\n        async (context, next) => {\n          assert.strictEqual(context.app, app)\n          order.push('setup 1')\n          await next()\n        },\n        async (_context, next) => {\n          order.push('setup 2')\n          await next()\n          order.push('setup after')\n        }\n      ],\n      teardown: [\n        async (context, next) => {\n          assert.strictEqual(context.app, app)\n          order.push('teardown 1')\n          await next()\n        },\n        async (_context, next) => {\n          order.push('teardown 2')\n          await next()\n        }\n      ]\n    }\n\n    app.hooks(hooks)\n\n    await app.setup()\n    await app.teardown()\n\n    assert.deepStrictEqual(order, ['setup 1', 'setup 2', 'setup after', 'teardown 1', 'teardown 2'])\n  })\n\n  describe('app.hooks([ async ])', () => {\n    it('basic app async hook, works with custom method', async () => {\n      const service = app.service('todos')\n\n      app.hooks([\n        async (context, next) => {\n          assert.strictEqual(context.app, app)\n          await next()\n          context.params.ran = true\n        }\n      ])\n\n      let result = await service.get('test')\n\n      assert.deepStrictEqual(result, {\n        id: 'test',\n        params: { ran: true }\n      })\n\n      const data = { test: 'hi' }\n\n      result = await service.create(data)\n\n      assert.deepStrictEqual(result, {\n        data,\n        params: { ran: true }\n      })\n\n      result = await service.customMethod('custom test')\n\n      assert.deepStrictEqual(result, {\n        data: 'custom test',\n        params: { ran: true }\n      })\n    })\n  })\n\n  describe('app.hooks({ method: [ async ] })', () => {\n    it('basic app async method hook', async () => {\n      const service = app.service('todos')\n\n      app.hooks({\n        get: [\n          async (context, next) => {\n            assert.strictEqual(context.app, app)\n            await next()\n            context.params.ran = true\n          }\n        ]\n      })\n\n      const result = await service.get('test')\n\n      assert.deepStrictEqual(result, {\n        id: 'test',\n        params: { ran: true }\n      })\n    })\n  })\n\n  describe('app.hooks({ before })', () => {\n    it('basic app before hook, works with custom method', async () => {\n      const service = app.service('todos')\n\n      app.hooks({\n        before(context) {\n          assert.strictEqual(context.app, app)\n          context.params.ran = true\n        }\n      })\n\n      let result = await service.get('test')\n\n      assert.deepStrictEqual(result, {\n        id: 'test',\n        params: { ran: true }\n      })\n\n      const data = { test: 'hi' }\n\n      result = await service.create(data)\n\n      assert.deepStrictEqual(result, {\n        data,\n        params: { ran: true }\n      })\n\n      result = await service.customMethod('custom with before')\n\n      assert.deepStrictEqual(result, {\n        data: 'custom with before',\n        params: { ran: true }\n      })\n    })\n\n    it('app before hooks always run first', async () => {\n      app.service('todos').hooks({\n        before(context) {\n          assert.strictEqual(context.app, app)\n          context.params.order.push('service.before')\n        }\n      })\n\n      app.service('todos').hooks({\n        before(context) {\n          assert.strictEqual(context.app, app)\n          context.params.order.push('service.before 1')\n        }\n      })\n\n      app.hooks({\n        before(context) {\n          assert.strictEqual(context.app, app)\n          context.params.order = []\n          context.params.order.push('app.before')\n        }\n      })\n\n      const result = await app.service('todos').get('test')\n\n      assert.deepStrictEqual(result, {\n        id: 'test',\n        params: {\n          order: ['app.before', 'service.before', 'service.before 1']\n        }\n      })\n    })\n  })\n\n  describe('app.hooks({ after })', () => {\n    it('basic app after hook', async () => {\n      app.hooks({\n        after(context) {\n          assert.strictEqual(context.app, app)\n          context.result.ran = true\n        }\n      })\n\n      const result = await app.service('todos').get('test')\n\n      assert.deepStrictEqual(result, {\n        id: 'test',\n        params: {},\n        ran: true\n      })\n    })\n\n    it('app after hooks always run last', async () => {\n      app.hooks({\n        after(context) {\n          assert.strictEqual(context.app, app)\n          context.result.order.push('app.after')\n        }\n      })\n\n      app.service('todos').hooks({\n        after(context) {\n          assert.strictEqual(context.app, app)\n          context.result!.order = []\n          context.result!.order.push('service.after')\n        }\n      })\n\n      app.service('todos').hooks({\n        after(context) {\n          assert.strictEqual(context.app, app)\n          context.result.order.push('service.after 1')\n        }\n      })\n\n      const result = await app.service('todos').get('test')\n\n      assert.deepStrictEqual(result, {\n        id: 'test',\n        params: {},\n        order: ['service.after', 'service.after 1', 'app.after']\n      })\n    })\n  })\n\n  describe('app.hooks({ error })', () => {\n    it('basic app error hook', async () => {\n      app.hooks({\n        error(context) {\n          assert.strictEqual(context.app, app)\n          context.error = new Error('App hook ran')\n        }\n      })\n\n      await assert.rejects(() => app.service('todos').get('error'), {\n        message: 'App hook ran'\n      })\n    })\n\n    it('app error hooks always run last', async () => {\n      app.hooks({\n        error(context) {\n          assert.strictEqual(context.app, app)\n          context.error = new Error(`${context.error.message} app.after`)\n        }\n      })\n\n      app.service('todos').hooks({\n        error(context) {\n          assert.strictEqual(context.app, app)\n          context.error = new Error(`${context.error.message} service.after`)\n        }\n      })\n\n      app.service('todos').hooks({\n        error(context) {\n          assert.strictEqual(context.app, app)\n          context.error = new Error(`${context.error.message} service.after 1`)\n        }\n      })\n\n      await assert.rejects(() => app.service('todos').get('error'), {\n        message: 'Something went wrong service.after service.after 1 app.after'\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "packages/feathers/test/hooks/around.test.ts",
    "content": "import assert from 'assert'\nimport { feathers, Params, ServiceInterface } from '../../src'\n\ndescribe('`around` hooks', () => {\n  it('around hooks can set hook.result which will skip service method', async () => {\n    const app = feathers().use('/dummy', {\n      async get() {\n        assert.ok(false, 'This should never run')\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      get: [\n        async (hook, next) => {\n          hook.result = {\n            id: hook.id,\n            message: 'Set from hook'\n          }\n\n          await next()\n        }\n      ]\n    })\n\n    const data = await service.get(10, {})\n\n    assert.deepStrictEqual(data, {\n      id: 10,\n      message: 'Set from hook'\n    })\n  })\n\n  it('works with traditional registration format, all syntax and app hooks', async () => {\n    const app = feathers().use('/dummy', {\n      async get() {\n        assert.ok(false, 'This should never run')\n      }\n    })\n    const service = app.service('dummy')\n\n    app.hooks([\n      async function (this: any, hook, next) {\n        hook.result = {\n          id: hook.id,\n          app: 'Set from app around all'\n        }\n\n        await next()\n      }\n    ])\n\n    service.hooks({\n      around: {\n        all: [\n          async (hook, next) => {\n            hook.result = {\n              ...hook.result,\n              all: 'Set from around all'\n            }\n\n            await next()\n          }\n        ],\n        get: [\n          async (hook, next) => {\n            hook.result = {\n              ...hook.result,\n              get: 'Set from around get'\n            }\n\n            await next()\n          }\n        ]\n      }\n    })\n\n    const data = await service.get(10, {})\n\n    assert.deepStrictEqual(data, {\n      id: 10,\n      app: 'Set from app around all',\n      all: 'Set from around all',\n      get: 'Set from around get'\n    })\n  })\n\n  it('gets mixed into a service and modifies data', async () => {\n    const dummyService = {\n      async create(data: any, params?: any) {\n        assert.deepStrictEqual(\n          data,\n          {\n            some: 'thing',\n            modified: 'data'\n          },\n          'Data modified'\n        )\n\n        assert.deepStrictEqual(\n          params,\n          {\n            modified: 'params'\n          },\n          'Params modified'\n        )\n\n        return data\n      }\n    }\n    const app = feathers<{ dummy: typeof dummyService }>().use('dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      create: [\n        async (hook, next) => {\n          assert.strictEqual(hook.type, 'around')\n\n          hook.data.modified = 'data'\n\n          Object.assign(hook.params, {\n            modified: 'params'\n          })\n\n          await next()\n        }\n      ]\n    })\n\n    const data = await service.create({ some: 'thing' })\n\n    assert.deepStrictEqual(\n      data,\n      {\n        some: 'thing',\n        modified: 'data'\n      },\n      'Data got modified'\n    )\n  })\n\n  it('contains the app object at hook.app', async () => {\n    const someServiceConfig = {\n      async create(data: any) {\n        return data\n      }\n    }\n    const app = feathers<{ 'some-service': typeof someServiceConfig }>().use(\n      'some-service',\n      someServiceConfig\n    )\n    const someService = app.service('some-service')\n\n    someService.hooks({\n      create: [\n        async (hook, next) => {\n          hook.data.appPresent = typeof hook.app !== 'undefined'\n          assert.strictEqual(hook.data.appPresent, true)\n          return next()\n        }\n      ]\n    })\n\n    const data = await someService.create({ some: 'thing' })\n\n    assert.deepStrictEqual(\n      data,\n      {\n        some: 'thing',\n        appPresent: true\n      },\n      'App object was present'\n    )\n  })\n\n  it('passes errors', async () => {\n    const dummyService = {\n      update() {\n        assert.ok(false, 'Never should be called')\n      }\n    }\n    const app = feathers().use('/dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      update: [\n        async () => {\n          throw new Error('You are not allowed to update')\n        }\n      ]\n    })\n\n    await assert.rejects(() => service.update(1, {}), {\n      message: 'You are not allowed to update'\n    })\n  })\n\n  it('does not run after hook when there is an error', async () => {\n    const dummyService = {\n      async remove() {\n        throw new Error('Error removing item')\n      }\n    }\n    const app = feathers().use('/dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      remove: [\n        async (_context, next) => {\n          await next()\n\n          assert.ok(false, 'This should never get called')\n        }\n      ]\n    })\n\n    await assert.rejects(() => service.remove(1, {}), {\n      message: 'Error removing item'\n    })\n  })\n\n  it('adds .hooks() and chains multiple hooks for the same method', async () => {\n    interface DummyParams extends Params {\n      modified: string\n    }\n\n    class DummyService implements ServiceInterface<any, any, DummyParams> {\n      create(data: any, params?: any) {\n        assert.deepStrictEqual(\n          data,\n          {\n            some: 'thing',\n            modified: 'second data'\n          },\n          'Data modified'\n        )\n\n        assert.deepStrictEqual(\n          params,\n          {\n            modified: 'params'\n          },\n          'Params modified'\n        )\n\n        return Promise.resolve(data)\n      }\n    }\n\n    const app = feathers<{ dummy: DummyService }>().use('dummy', new DummyService())\n    const service = app.service('dummy')\n\n    service.hooks({\n      create: [\n        async (hook, next) => {\n          hook.params.modified = 'params'\n\n          await next()\n        },\n        async (hook, next) => {\n          hook.data.modified = 'second data'\n\n          next()\n        }\n      ]\n    })\n\n    await service.create({ some: 'thing' })\n  })\n\n  it('around hooks run in the correct order', async () => {\n    interface DummyParams extends Params<{ name: string }> {\n      items: string[]\n    }\n\n    class DummyService implements ServiceInterface<any, any, DummyParams> {\n      async get(id: any, params?: DummyParams) {\n        assert.deepStrictEqual(params!.items, ['first', 'second', 'third'])\n\n        return {\n          id,\n          items: [] as string[]\n        }\n      }\n    }\n\n    const app = feathers<{ dummy: DummyService }>().use('dummy', new DummyService())\n    const service = app.service('dummy')\n\n    service.hooks({\n      get: [\n        async (hook, next) => {\n          hook.params.items = ['first']\n          await next()\n        }\n      ]\n    })\n\n    service.hooks({\n      get: [\n        async function (hook, next) {\n          hook.params.items.push('second')\n          next()\n        },\n        async function (hook, next) {\n          hook.params.items.push('third')\n          next()\n        }\n      ]\n    })\n\n    await service.get(10)\n  })\n\n  it('around all hooks (#11)', async () => {\n    interface DummyParams extends Params {\n      asyncAllObject: boolean\n      asyncAllMethodArray: boolean\n    }\n\n    type DummyService = ServiceInterface<any, any, DummyParams>\n\n    const app = feathers<{ dummy: DummyService }>().use('dummy', {\n      async get(id: any, params: any) {\n        assert.ok(params.asyncAllObject)\n        assert.ok(params.asyncAllMethodArray)\n\n        return {\n          id,\n          items: []\n        }\n      },\n\n      async find(params: any) {\n        assert.ok(params.asyncAllObject)\n        assert.ok(params.asyncAllMethodArray)\n\n        return []\n      }\n    })\n\n    const service = app.service('dummy')\n\n    service.hooks([\n      async (hook, next) => {\n        hook.params.asyncAllObject = true\n        next()\n      }\n    ])\n\n    service.hooks([\n      async function (hook, next) {\n        hook.params.asyncAllMethodArray = true\n        next()\n      }\n    ])\n\n    await service.find()\n  })\n\n  it('around hooks have service as context and keep it in service method (#17)', async () => {\n    interface DummyParams extends Params {\n      test: number\n    }\n\n    class Dummy implements ServiceInterface<any, any, DummyParams> {\n      number = 42\n\n      async get(id: any, params?: DummyParams) {\n        return {\n          id,\n          number: (this as any).number,\n          test: params!.test\n        }\n      }\n    }\n\n    const app = feathers<{ dummy: Dummy }>().use('dummy', new Dummy())\n\n    const service = app.service('dummy')\n\n    service.hooks({\n      get: [\n        async function (this: any, hook, next) {\n          hook.params.test = this.number + 2\n\n          await next()\n        }\n      ]\n    })\n\n    const data = await service.get(10)\n\n    assert.deepStrictEqual(data, {\n      id: 10,\n      number: 42,\n      test: 44\n    })\n  })\n})\n"
  },
  {
    "path": "packages/feathers/test/hooks/before.test.ts",
    "content": "import assert from 'assert'\nimport { feathers, Params, ServiceInterface } from '../../src'\n\ndescribe('`before` hooks', () => {\n  it('.before hooks can return a promise', async () => {\n    interface DummyParams extends Params {\n      ran: boolean\n    }\n\n    type DummyService = ServiceInterface<any, any, DummyParams>\n\n    const app = feathers<{ dummy: DummyService }>().use('dummy', {\n      async get(id: any, params: DummyParams) {\n        assert.ok(params.ran, 'Ran through promise hook')\n\n        return {\n          id,\n          description: `You have to do ${id}`\n        }\n      },\n\n      async remove() {\n        assert.ok(false, 'Should never get here')\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        get(context) {\n          return new Promise<void>((resolve) => {\n            context.params.ran = true\n            resolve()\n          })\n        },\n\n        remove() {\n          return new Promise((_resolve, reject) => {\n            reject(new Error('This did not work'))\n          })\n        },\n\n        find: []\n      }\n    })\n\n    await service.get('dishes')\n    await assert.rejects(() => service.remove(10), {\n      message: 'This did not work'\n    })\n  })\n\n  it('.before hooks do not need to return anything', async () => {\n    interface DummyParams extends Params {\n      ran: boolean\n    }\n\n    type DummyService = ServiceInterface<any, any, DummyParams>\n\n    const app = feathers<{ dummy: DummyService }>().use('dummy', {\n      async get(id: any, params: any) {\n        assert.ok(params.ran, 'Ran through promise hook')\n\n        return {\n          id,\n          description: `You have to do ${id}`\n        }\n      },\n\n      async remove() {\n        assert.ok(false, 'Should never get here')\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        get(context) {\n          context.params.ran = true\n        },\n\n        remove() {\n          throw new Error('This did not work')\n        }\n      }\n    })\n\n    await service.get('dishes')\n    await assert.rejects(() => service.remove(10), {\n      message: 'This did not work'\n    })\n  })\n\n  it('.before hooks can set context.result which will skip service method', async () => {\n    const app = feathers().use('/dummy', {\n      async get() {\n        assert.ok(false, 'This should never run')\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        get(context) {\n          context.result = {\n            id: context.id,\n            message: 'Set from hook'\n          }\n        }\n      }\n    })\n\n    const data = await service.get(10, {})\n\n    assert.deepStrictEqual(data, {\n      id: 10,\n      message: 'Set from hook'\n    })\n  })\n\n  it('gets mixed into a service and modifies data', async () => {\n    const dummyService = {\n      async create(data: any, params?: any) {\n        assert.deepStrictEqual(\n          data,\n          {\n            some: 'thing',\n            modified: 'data'\n          },\n          'Data modified'\n        )\n\n        assert.deepStrictEqual(\n          params,\n          {\n            modified: 'params'\n          },\n          'Params modified'\n        )\n\n        return data\n      }\n    }\n    const app = feathers<{ dummy: typeof dummyService }>().use('dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        create(context) {\n          assert.strictEqual(context.type, 'before')\n\n          context.data.modified = 'data'\n\n          Object.assign(context.params, {\n            modified: 'params'\n          })\n\n          return context\n        }\n      }\n    })\n\n    const data = await service.create({ some: 'thing' })\n\n    assert.deepStrictEqual(\n      data,\n      {\n        some: 'thing',\n        modified: 'data'\n      },\n      'Data got modified'\n    )\n  })\n\n  it('contains the app object at context.app', async () => {\n    const someServiceConfig = {\n      async create(data: any) {\n        return data\n      }\n    }\n    const app = feathers<{ 'some-service': typeof someServiceConfig }>().use(\n      'some-service',\n      someServiceConfig\n    )\n    const someService = app.service('some-service')\n\n    someService.hooks({\n      before: {\n        create(context) {\n          context.data.appPresent = typeof context.app !== 'undefined'\n          assert.strictEqual(context.data.appPresent, true)\n\n          return context\n        }\n      }\n    })\n\n    const data = await someService.create({ some: 'thing' })\n\n    assert.deepStrictEqual(\n      data,\n      {\n        some: 'thing',\n        appPresent: true\n      },\n      'App object was present'\n    )\n  })\n\n  it('passes errors', async () => {\n    const dummyService = {\n      update() {\n        assert.ok(false, 'Never should be called')\n      }\n    }\n\n    const app = feathers().use('/dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        update() {\n          throw new Error('You are not allowed to update')\n        }\n      }\n    })\n\n    await assert.rejects(() => service.update(1, {}), {\n      message: 'You are not allowed to update'\n    })\n  })\n\n  it('calling back with no arguments uses the old ones', async () => {\n    interface DummyParams extends Params {\n      my: string\n    }\n\n    type DummyService = ServiceInterface<any, any, DummyParams>\n\n    const dummyService = {\n      async remove(id: any, params: any) {\n        assert.strictEqual(id, 1, 'Got id')\n        assert.deepStrictEqual(params, { my: 'param' })\n\n        return { id }\n      }\n    }\n    const app = feathers<{ dummy: DummyService }>().use('dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        remove(context) {\n          return context\n        }\n      }\n    })\n\n    await service.remove(1, { my: 'param' })\n  })\n\n  it('adds .hooks() and chains multiple hooks for the same method', async () => {\n    interface DummyParams extends Params {\n      modified: string\n    }\n\n    type DummyService = ServiceInterface<any, any, DummyParams>\n\n    const dummyService = {\n      async create(data: any, params: any) {\n        assert.deepStrictEqual(\n          data,\n          {\n            some: 'thing',\n            modified: 'second data'\n          },\n          'Data modified'\n        )\n\n        assert.deepStrictEqual(\n          params,\n          {\n            modified: 'params'\n          },\n          'Params modified'\n        )\n\n        return data\n      }\n    }\n    const app = feathers<{ dummy: DummyService }>().use('dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        create(context) {\n          context.params.modified = 'params'\n\n          return context\n        }\n      }\n    })\n\n    service.hooks({\n      before: {\n        create(context) {\n          context.data.modified = 'second data'\n\n          return context\n        }\n      }\n    })\n\n    await service.create({ some: 'thing' })\n  })\n\n  it('chains multiple before hooks using array syntax', async () => {\n    interface DummyParams extends Params {\n      modified: string\n    }\n\n    type DummyService = ServiceInterface<any, any, DummyParams>\n\n    const dummyService = {\n      async create(data: any, params: any) {\n        assert.deepStrictEqual(\n          data,\n          {\n            some: 'thing',\n            modified: 'second data'\n          },\n          'Data modified'\n        )\n\n        assert.deepStrictEqual(\n          params,\n          {\n            modified: 'params'\n          },\n          'Params modified'\n        )\n\n        return data\n      }\n    }\n\n    const app = feathers<{ dummy: DummyService }>().use('dummy', dummyService)\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        create: [\n          function (context) {\n            context.params.modified = 'params'\n\n            return context\n          },\n          function (context) {\n            context.data.modified = 'second data'\n\n            return context\n          }\n        ]\n      }\n    })\n\n    await service.create({ some: 'thing' })\n  })\n\n  it('.before hooks run in the correct order (#13)', async () => {\n    interface DummyParams extends Params {\n      items: string[]\n    }\n\n    type DummyService = ServiceInterface<any, any, DummyParams>\n\n    const app = feathers<{ dummy: DummyService }>().use('dummy', {\n      async get(id: any, params: any) {\n        assert.deepStrictEqual(params.items, ['first', 'second', 'third'])\n\n        return {\n          id,\n          items: []\n        }\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        get(context) {\n          context.params.items = ['first']\n\n          return context\n        }\n      }\n    })\n\n    service.hooks({\n      before: {\n        get: [\n          function (context) {\n            context.params.items.push('second')\n\n            return context\n          },\n          function (context) {\n            context.params.items.push('third')\n\n            return context\n          }\n        ]\n      }\n    })\n\n    await service.get(10)\n  })\n\n  it('before all hooks (#11)', async () => {\n    interface DummyParams extends Params {\n      beforeAllObject: boolean\n      beforeAllMethodArray: boolean\n    }\n\n    type DummyService = ServiceInterface<any, any, DummyParams>\n\n    const app = feathers<{ dummy: DummyService }>().use('dummy', {\n      async get(id: any, params: any) {\n        assert.ok(params.beforeAllObject)\n        assert.ok(params.beforeAllMethodArray)\n\n        return {\n          id,\n          items: []\n        }\n      },\n\n      async find(params: any) {\n        assert.ok(params.beforeAllObject)\n        assert.ok(params.beforeAllMethodArray)\n\n        return []\n      }\n    })\n\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        all(context) {\n          context.params.beforeAllObject = true\n\n          return context\n        }\n      }\n    })\n\n    service.hooks({\n      before: [\n        function (context) {\n          context.params.beforeAllMethodArray = true\n\n          return context\n        }\n      ]\n    })\n\n    await service.find()\n  })\n\n  it('before hooks have service as context and keep it in service method (#17)', async () => {\n    interface DummyParams extends Params {\n      test: number\n    }\n\n    class Dummy implements ServiceInterface<any, any, DummyParams> {\n      number = 42\n\n      async get(id: any, params?: DummyParams) {\n        return {\n          id,\n          number: this.number,\n          test: params.test\n        }\n      }\n    }\n\n    const app = feathers<{ dummy: Dummy }>().use('dummy', new Dummy())\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        get(this: any, context) {\n          context.params.test = this.number + 2\n\n          return context\n        }\n      }\n    })\n\n    const data = await service.get(10)\n\n    assert.deepStrictEqual(data, {\n      id: 10,\n      number: 42,\n      test: 44\n    })\n  })\n})\n"
  },
  {
    "path": "packages/feathers/test/hooks/error.test.ts",
    "content": "import assert from 'assert'\nimport { feathers, Application, FeathersService } from '../../src'\n\ndescribe('`error` hooks', () => {\n  describe('on direct service method errors', () => {\n    const errorMessage = 'Something else went wrong'\n    const app = feathers().use('/dummy', {\n      async get() {\n        throw new Error('Something went wrong')\n      }\n    })\n    const service = app.service('dummy')\n\n    afterEach(() => {\n      const s = service as any\n\n      s.__hooks.error.get = undefined\n      s.__hooks.collected.get = []\n    })\n\n    it('basic error hook', async () => {\n      service.hooks({\n        error: {\n          get(context) {\n            assert.strictEqual(context.type, 'error')\n            assert.strictEqual(context.id, 'test')\n            assert.strictEqual(context.method, 'get')\n            assert.strictEqual(context.app, app)\n            assert.strictEqual(context.error.message, 'Something went wrong')\n          }\n        }\n      })\n\n      await assert.rejects(() => service.get('test'), {\n        message: 'Something went wrong'\n      })\n    })\n\n    it('can change the error', async () => {\n      service.hooks({\n        error: {\n          get(context) {\n            context.error = new Error(errorMessage)\n          }\n        }\n      })\n\n      await assert.rejects(() => service.get('test'), {\n        message: errorMessage\n      })\n    })\n\n    it('throwing an error', async () => {\n      service.hooks({\n        error: {\n          get() {\n            throw new Error(errorMessage)\n          }\n        }\n      })\n\n      await assert.rejects(() => service.get('test'), {\n        message: errorMessage\n      })\n    })\n\n    it('rejecting a promise', async () => {\n      service.hooks({\n        error: {\n          async get() {\n            throw new Error(errorMessage)\n          }\n        }\n      })\n\n      await assert.rejects(() => service.get('test'), {\n        message: errorMessage\n      })\n    })\n\n    it('can chain multiple hooks', async () => {\n      service.hooks({\n        error: {\n          get: [\n            function (context) {\n              context.error = new Error(errorMessage)\n              context.error.first = true\n            },\n\n            function (context) {\n              context.error.second = true\n\n              return Promise.resolve(context)\n            },\n\n            function (context) {\n              context.error.third = true\n\n              return context\n            }\n          ]\n        }\n      })\n\n      await assert.rejects(() => service.get('test'), {\n        message: errorMessage,\n        first: true,\n        second: true,\n        third: true\n      })\n    })\n\n    it('setting `context.result` will return result', async () => {\n      const data = {\n        message: 'It worked'\n      }\n\n      service.hooks({\n        error: {\n          get(context) {\n            context.result = data\n          }\n        }\n      })\n\n      const result = await service.get(10)\n\n      assert.deepStrictEqual(result, data)\n    })\n\n    it('allows to set `context.result = null` in error hooks (#865)', async () => {\n      const app = feathers().use('/dummy', {\n        async get() {\n          throw new Error('Damnit')\n        }\n      })\n\n      app.service('dummy').hooks({\n        error: {\n          get(context: any) {\n            context.result = null\n          }\n        }\n      })\n\n      const result = await app.service('dummy').get(1)\n\n      assert.strictEqual(result, null)\n    })\n\n    it('uses the current hook object if thrown in a service method', async () => {\n      const app = feathers().use('/dummy', {\n        async get() {\n          throw new Error('Something went wrong')\n        }\n      })\n      const service = app.service('dummy')\n\n      service.hooks({\n        before(context) {\n          context.id = 42\n        },\n        error(context) {\n          assert.strictEqual(context.id, 42)\n        }\n      })\n\n      await assert.rejects(() => service.get(1), {\n        message: 'Something went wrong'\n      })\n    })\n  })\n\n  describe('error in hooks', () => {\n    const errorMessage = 'before hook broke'\n\n    let app: Application\n    let service: FeathersService\n\n    beforeEach(() => {\n      app = feathers().use('/dummy', {\n        async get(id: any) {\n          return {\n            id,\n            text: `You have to do ${id}`\n          }\n        }\n      })\n\n      service = app.service('dummy')\n    })\n\n    it('in before hook', async () => {\n      service\n        .hooks({\n          before() {\n            throw new Error(errorMessage)\n          }\n        })\n        .hooks({\n          error(context) {\n            assert.strictEqual(context.original.type, 'before', 'Original hook still set')\n            assert.strictEqual(context.id, 'dishes')\n            assert.strictEqual(context.error.message, errorMessage)\n          }\n        })\n\n      await assert.rejects(() => service.get('dishes'), {\n        message: errorMessage\n      })\n    })\n\n    it('in after hook', async () => {\n      service.hooks({\n        after() {\n          throw new Error(errorMessage)\n        },\n\n        error(context) {\n          assert.strictEqual(context.original.type, 'after', 'Original hook still set')\n          assert.strictEqual(context.id, 'dishes')\n          assert.deepStrictEqual(context.original.result, {\n            id: 'dishes',\n            text: 'You have to do dishes'\n          })\n          assert.strictEqual(context.error.message, errorMessage)\n        }\n      })\n\n      await assert.rejects(() => service.get('dishes'), {\n        message: errorMessage\n      })\n    })\n\n    it('uses the current hook object if thrown in a hook and sets context.original', async () => {\n      service.hooks({\n        after(context) {\n          context.modified = true\n\n          throw new Error(errorMessage)\n        },\n\n        error(context) {\n          assert.ok(context.modified)\n          assert.strictEqual(context.original.type, 'after')\n        }\n      })\n\n      await assert.rejects(() => service.get('laundry'), {\n        message: errorMessage\n      })\n    })\n  })\n\n  it('Error in before hook causes inter-service calls to have wrong hook context (#841)', async () => {\n    const app = feathers()\n\n    let service1Params: any\n    let service2Params: any\n\n    app.use('/service1', {\n      async find() {\n        return { message: 'service1 success' }\n      }\n    })\n\n    app.service('service1').hooks({\n      before(context: any) {\n        service1Params = context.params\n        throw new Error('Error in service1 before hook')\n      }\n    })\n\n    app.use('/service2', {\n      async find() {\n        await app.service('/service1').find({})\n\n        return { message: 'service2 success' }\n      }\n    })\n\n    app.service('service2').hooks({\n      before(context: any) {\n        service2Params = context.params\n        context.params.foo = 'bar'\n      },\n      error(context: any) {\n        assert.ok(service1Params !== context.params)\n        assert.ok(service2Params === context.params)\n        assert.strictEqual(context.path, 'service2')\n        assert.strictEqual(context.params.foo, 'bar')\n      }\n    })\n\n    await assert.rejects(() => app.service('/service2').find(), {\n      message: 'Error in service1 before hook'\n    })\n  })\n})\n"
  },
  {
    "path": "packages/feathers/test/hooks/hooks.test.ts",
    "content": "import assert from 'assert'\nimport { hooks, NextFunction } from '@feathersjs/hooks'\nimport { HookContext, createContext, feathers, Id, Params, ServiceInterface } from '../../src'\n\ndescribe('hooks basics', () => {\n  it('mix @feathersjs/hooks and .hooks', async () => {\n    interface SimpleParams extends Params {\n      chain: string[]\n    }\n    class SimpleService {\n      async get(id: Id, params: SimpleParams) {\n        return { id, chain: params.chain }\n      }\n    }\n\n    hooks(SimpleService.prototype, [\n      async (ctx: HookContext, next: NextFunction) => {\n        ctx.params.chain.push('@hooks all before')\n        await next()\n        ctx.params.chain.push('@hooks all after')\n      }\n    ])\n\n    hooks(SimpleService, {\n      get: [\n        async (ctx: HookContext, next: NextFunction) => {\n          assert.ok(ctx.app)\n          assert.ok(ctx.service)\n          ctx.params.chain.push('@hooks get before')\n          await next()\n          ctx.params.chain.push('@hooks get after')\n        }\n      ]\n    })\n\n    const app = feathers().use('/dummy', new SimpleService())\n    const service = app.service('dummy')\n\n    app.hooks([\n      async function appHook(ctx: HookContext, next: NextFunction) {\n        assert.ok(ctx.app)\n        assert.ok(ctx.service)\n\n        ctx.params.chain = ['app.hooks before']\n        await next()\n        ctx.params.chain.push('app.hooks after')\n      }\n    ])\n\n    app.hooks({\n      before: [\n        (ctx: HookContext) => {\n          ctx.params.chain.push('app.hooks regular before')\n        }\n      ],\n      after: [\n        (ctx: HookContext) => {\n          ctx.params.chain.push('app.hooks regular after')\n        }\n      ]\n    })\n\n    service.hooks({\n      before: {\n        get: (ctx: HookContext) => {\n          ctx.params.chain.push('service.hooks regular before')\n        }\n      },\n      after: {\n        get: (ctx: HookContext) => {\n          ctx.params.chain.push('service.hooks regular after')\n        }\n      }\n    })\n\n    service.hooks({\n      get: [\n        async (ctx: HookContext, next: NextFunction) => {\n          ctx.params.chain.push('service.hooks get before')\n          await next()\n          ctx.params.chain.push('service.hooks get after')\n        }\n      ]\n    })\n\n    service.hooks({\n      before: {\n        get: (ctx: HookContext) => {\n          ctx.params.chain.push('service.hooks 2 regular before')\n        }\n      },\n      after: {\n        get: (ctx: HookContext) => {\n          ctx.params.chain.push('service.hooks 2 regular after')\n        }\n      }\n    })\n\n    const { chain } = await service.get(1, {})\n\n    assert.deepStrictEqual(chain, [\n      'app.hooks before',\n      'app.hooks regular before',\n      '@hooks all before',\n      '@hooks get before',\n      'service.hooks get before',\n      'service.hooks regular before',\n      'service.hooks 2 regular before',\n      'service.hooks regular after',\n      'service.hooks 2 regular after',\n      'service.hooks get after',\n      '@hooks get after',\n      '@hooks all after',\n      'app.hooks regular after',\n      'app.hooks after'\n    ])\n  })\n\n  // it('validates arguments', async () => {\n  //   const app = feathers().use('/dummy', {\n  //     async get (id: any, params: any) {\n  //       return { id, user: params.user };\n  //     },\n\n  //     async create (data: any) {\n  //       return data;\n  //     }\n  //   });\n\n  //   await assert.rejects(() => app.service('dummy').get(), {\n  //     message: 'An id must be provided to the \\'dummy.get\\' method'\n  //   });\n  //   await assert.rejects(() => app.service('dummy').create(), {\n  //     message: 'A data object must be provided to the \\'dummy.create\\' method'\n  //   });\n  // });\n\n  it('works with services that return a promise (feathers-hooks#28)', async () => {\n    interface DummyParams extends Params {\n      user: string\n    }\n\n    const app = feathers<{ dummy: ServiceInterface<any, any, DummyParams> }>().use('dummy', {\n      async get(id: any, params: any) {\n        return { id, user: params.user }\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        get(context) {\n          context.params.user = 'David'\n        }\n      },\n      after: {\n        get(context) {\n          context.result.after = true\n        }\n      }\n    })\n\n    const data = await service.get(10)\n\n    assert.deepStrictEqual(data, { id: 10, user: 'David', after: true })\n  })\n\n  it('has context.app, context.service and context.path', async () => {\n    const app = feathers().use('/dummy', {\n      async get(id: any) {\n        return { id }\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      before(context) {\n        assert.strictEqual(this, service)\n        assert.strictEqual(context.service, service)\n        assert.strictEqual(context.app, app)\n        assert.strictEqual(context.path, 'dummy')\n      }\n    })\n\n    await service.get('test')\n  })\n\n  it('does not error when result is null', async () => {\n    const app = feathers().use('/dummy', {\n      async get(id: any) {\n        return { id }\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      after: {\n        get: [\n          function (context) {\n            context.result = null\n            return context\n          }\n        ]\n      }\n    })\n\n    const result = await service.get(1)\n\n    assert.strictEqual(result, null)\n  })\n\n  it('registering an already hooked service works (#154)', () => {\n    const app = feathers().use('/dummy', {\n      async get(id: any, params: any) {\n        return { id, params }\n      }\n    })\n\n    app.use('/dummy2', app.service('dummy'))\n  })\n\n  describe('returns the context when passing it as last parameter', () => {\n    it('on normal method call', async () => {\n      const app = feathers().use('/dummy', {\n        async get(id: any, params: any) {\n          return { id, params }\n        }\n      })\n      const service = app.service('dummy')\n      const context = createContext(service, 'get')\n      const returnedContext = await app.service('dummy').get(10, {}, context)\n\n      assert.strictEqual(returnedContext.service, app.service('dummy'))\n      assert.strictEqual(returnedContext.type, 'around')\n      assert.strictEqual(returnedContext.path, 'dummy')\n      assert.deepStrictEqual(returnedContext.result, {\n        id: 10,\n        params: {}\n      })\n    })\n\n    it.skip('on error', async () => {\n      const app = feathers().use('/dummy', {\n        get() {\n          throw new Error('Something went wrong')\n        }\n      })\n\n      const service = app.service('dummy')\n      const context = createContext(service, 'get')\n\n      await assert.rejects(() => service.get(10, {}, context), {\n        service: app.service('dummy'),\n        type: null,\n        path: 'dummy'\n      })\n    })\n\n    // it('on argument validation error (https://github.com/feathersjs/express/issues/19)', async () => {\n    //   const app = feathers().use('/dummy', {\n    //     async get (id: string) {\n    //       return { id };\n    //     }\n    //   });\n\n    //   await assert.rejects(() => app.service('dummy').get(undefined, {}, true), context => {\n    //     assert.strictEqual(context.service, app.service('dummy'));\n    //     assert.strictEqual(context.type, 'error');\n    //     assert.strictEqual(context.path, 'dummy');\n    //     assert.strictEqual(context.error.message, 'An id must be provided to the \\'dummy.get\\' method');\n\n    //     return true;\n    //   });\n    // });\n\n    // it('on error in error hook (https://github.com/feathersjs/express/issues/21)', async () => {\n    //   const app = feathers().use('/dummy', {\n    //     async get () {\n    //       throw new Error('Nope');\n    //     }\n    //   });\n\n    //   app.service('dummy').hooks({\n    //     error: {\n    //       get () {\n    //         throw new Error('Error in error hook');\n    //       }\n    //     }\n    //   });\n\n    //   await assert.rejects(() => app.service('dummy').get(10, {}, true), context => {\n    //     assert.strictEqual(context.service, app.service('dummy'));\n    //     assert.strictEqual(context.type, 'error');\n    //     assert.strictEqual(context.path, 'dummy');\n    //     assert.strictEqual(context.error.message, 'Error in error hook');\n\n    //     return true;\n    //   });\n    // });\n\n    it('still swallows error if context.result is set', async () => {\n      const result = { message: 'this is a test' }\n      const app = feathers().use('/dummy', {\n        async get() {\n          throw new Error('Something went wrong')\n        }\n      })\n\n      app.service('dummy').hooks({\n        error(context: any) {\n          context.result = result\n        }\n      })\n\n      const service = app.service('dummy')\n      const context = createContext(service, 'get')\n      const returnedContext = await service.get(10, {}, context)\n\n      assert.ok(returnedContext.error)\n      assert.deepStrictEqual(returnedContext.result, result)\n    })\n  })\n\n  it('can register hooks on a custom method, still adds hooks to default methods', async () => {\n    class Dummy {\n      async get(id: Id) {\n        return { id }\n      }\n\n      async create(data: any) {\n        return data\n      }\n\n      async custom(data: any) {\n        return data\n      }\n    }\n\n    const app = feathers<{\n      dummy: Dummy\n    }>().use('dummy', new Dummy(), {\n      methods: ['get', 'custom']\n    })\n\n    app.service('dummy').hooks({\n      custom: [\n        async (context, next) => {\n          context.data.fromHook = true\n          await next()\n        }\n      ],\n      create: [async (_context, next) => next()]\n    })\n\n    assert.deepStrictEqual(\n      await app.service('dummy').custom({\n        message: 'testing'\n      }),\n      {\n        message: 'testing',\n        fromHook: true\n      }\n    )\n  })\n\n  it('normalizes params to object even when it is falsy (#1001)', async () => {\n    const app = feathers().use('/dummy', {\n      async get(id: Id, params: Params) {\n        return { id, params }\n      }\n    })\n\n    const result = await app.service('dummy').get('test', null)\n\n    assert.deepStrictEqual(result, {\n      id: 'test',\n      params: {}\n    })\n  })\n\n  it('allows to return new context in basic hooks (#2451)', async () => {\n    const app = feathers().use('/dummy', {\n      async get() {\n        return {}\n      }\n    })\n    const service = app.service('dummy')\n\n    service.hooks({\n      before: {\n        get: [\n          (context) => {\n            return {\n              ...context,\n              value: 'something'\n            }\n          },\n          (context) => {\n            assert.strictEqual(context.value, 'something')\n          }\n        ]\n      },\n      after: {\n        get: [\n          (context) => {\n            context.result = {\n              value: context.value\n            }\n          }\n        ]\n      }\n    })\n\n    const data = await service.get(10)\n\n    assert.deepStrictEqual(data, {\n      value: 'something'\n    })\n  })\n})\n"
  },
  {
    "path": "packages/feathers/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"\n  }\n}\n"
  },
  {
    "path": "packages/generators/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n- **generators:** typebox generated schema resolver generic ([#3622](https://github.com/feathersjs/feathers/issues/3622)) ([55a4a9b](https://github.com/feathersjs/feathers/commit/55a4a9b6bb021c369fb65b50fa13869311587c3f))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n### Bug Fixes\n\n- **generators:** Add FeathersGeneratorError ([#3556](https://github.com/feathersjs/feathers/issues/3556)) ([2a81a20](https://github.com/feathersjs/feathers/commit/2a81a204eb55c95d20fc45bf091c0131eff5a25d))\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n### Bug Fixes\n\n- **generators:** Fix generating of gitignore ([#3514](https://github.com/feathersjs/feathers/issues/3514)) ([cabc397](https://github.com/feathersjs/feathers/commit/cabc397d2e4378c4bce79a60f2d196713cce4d8c))\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n### Bug Fixes\n\n- **generators:** Fix migrate:make script in generated app ([#3490](https://github.com/feathersjs/feathers/issues/3490)) ([c7b0111](https://github.com/feathersjs/feathers/commit/c7b011150152e62a35f3f8ab04d6dde6d6727583))\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n### Bug Fixes\n\n- **generators:** better types for enabled methods ([#3474](https://github.com/feathersjs/feathers/issues/3474)) ([bdb3d3a](https://github.com/feathersjs/feathers/commit/bdb3d3a308322bfed3caa4214e4b6a72f1a84944))\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n### Bug Fixes\n\n- **generators:** Use module format for JS Knex migrations ([#3444](https://github.com/feathersjs/feathers/issues/3444)) ([3feaa71](https://github.com/feathersjs/feathers/commit/3feaa719443aa30b1121d928ba5b7b8f43837ffb))\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n### Bug Fixes\n\n- **generators:** Use cross-platform ES module \\_\\_dirname ([#3402](https://github.com/feathersjs/feathers/issues/3402)) ([0ac4882](https://github.com/feathersjs/feathers/commit/0ac4882663bb6a78622be0d903ae6508ecb516ad))\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n### Bug Fixes\n\n- **cli:** Another fix for CLI ES module loading ([#3397](https://github.com/feathersjs/feathers/issues/3397)) ([3cb3bc9](https://github.com/feathersjs/feathers/commit/3cb3bc9a32602d82193b781b583ed0f37044e778))\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n### Bug Fixes\n\n- **generators:** Move generators and CLI to featherscloud/pinion ([#3386](https://github.com/feathersjs/feathers/issues/3386)) ([eb87c99](https://github.com/feathersjs/feathers/commit/eb87c9922db56c5610e5b808f3ffe033c830e2b2))\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n### Bug Fixes\n\n- **generators:** Harden mongodb.js to reliably extract database from any connection string ([#3264](https://github.com/feathersjs/feathers/issues/3264)) ([7b0f82c](https://github.com/feathersjs/feathers/commit/7b0f82c631ff5549cdc9a8e0ffcc705d067c2157))\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n### Bug Fixes\n\n- **generators:** use `export type` vs `export` ([#3246](https://github.com/feathersjs/feathers/issues/3246)) ([82d30fd](https://github.com/feathersjs/feathers/commit/82d30fd37914e61935e068e89fc389f6bf47aaad))\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n- **schema:** HookContext is now typed in schema ([#3306](https://github.com/feathersjs/feathers/issues/3306)) ([65fab86](https://github.com/feathersjs/feathers/commit/65fab86407b813122f24db928a59986c7286f270))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n### Bug Fixes\n\n- **generators:** Fix configure channels when not real-time app ([#3271](https://github.com/feathersjs/feathers/issues/3271)) ([c619ab2](https://github.com/feathersjs/feathers/commit/c619ab2c57f692c419fee610c269c1502b124852))\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n### Bug Fixes\n\n- **generators:** Fix channel/service configuration order for Koa based apps ([580344e](https://github.com/feathersjs/feathers/commit/580344e96fe8a2f17fd53476af5a0c7ddefac0b6))\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/generators\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n### Bug Fixes\n\n- **generators:** Add sourceMap to tsconfig.json template ([#3166](https://github.com/feathersjs/feathers/issues/3166)) ([3049b7a](https://github.com/feathersjs/feathers/commit/3049b7a425d01cdd3058442c7183307a06cfc87a))\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n- **generators:** Properly log unhandled rejection ([#3149](https://github.com/feathersjs/feathers/issues/3149)) ([eda8f78](https://github.com/feathersjs/feathers/commit/eda8f78fa5084c3247ad10b051610b3c51a13d24))\n\n## [5.0.2](https://github.com/feathersjs/feathers/compare/v5.0.1...v5.0.2) (2023-03-23)\n\n### Bug Fixes\n\n- **generators:** Make sure TypeScript version in generated app matches ([#3122](https://github.com/feathersjs/feathers/issues/3122)) ([f0acfdf](https://github.com/feathersjs/feathers/commit/f0acfdf9d33337bf40ca12126c2550f56e31fa3b))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n### Bug Fixes\n\n- **generators:** Conditionally import channels in Express app ([#3106](https://github.com/feathersjs/feathers/issues/3106)) ([c2dbaaa](https://github.com/feathersjs/feathers/commit/c2dbaaa4d1d5a5675b5812a7ed2317076ac414fe))\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n### Bug Fixes\n\n- **generators:** Fix typo in service client generator ([#3068](https://github.com/feathersjs/feathers/issues/3068)) ([612032e](https://github.com/feathersjs/feathers/commit/612032eced24ecbcf255d51ff0d537d74227cfd7))\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n### Features\n\n- **generators:** Final tweaks to the generators ([#3060](https://github.com/feathersjs/feathers/issues/3060)) ([1bf1544](https://github.com/feathersjs/feathers/commit/1bf1544fa8deeaa44ba354fb539dc3f1fd187767))\n- **schema:** Add schema helper for handling Object ids ([#3058](https://github.com/feathersjs/feathers/issues/3058)) ([1393bed](https://github.com/feathersjs/feathers/commit/1393bed81a9ee814de6aab0e537af83e667591a2))\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n### Bug Fixes\n\n- **generators:** Add schema selection to CI test matrix ([#3035](https://github.com/feathersjs/feathers/issues/3035)) ([7484b16](https://github.com/feathersjs/feathers/commit/7484b164fba4ac2ee379dc5c6363f964f45e94d3))\n- **generators:** Fix Knex migration generated filename ([#3033](https://github.com/feathersjs/feathers/issues/3033)) ([1ac18a7](https://github.com/feathersjs/feathers/commit/1ac18a7143173d973af982772678834f7a7334f7))\n- **generators:** Generated app does not start when choosing JSON schema ([#3034](https://github.com/feathersjs/feathers/issues/3034)) ([7b8250b](https://github.com/feathersjs/feathers/commit/7b8250bd535c3c5ec7429a65139335ad43616ae0))\n\n### Features\n\n- **mongodb:** Add Object ID keyword converter and update MongoDB CLI & docs ([#3041](https://github.com/feathersjs/feathers/issues/3041)) ([ca0994e](https://github.com/feathersjs/feathers/commit/ca0994eaecb5a31f310bc980d106834e11f24f41))\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- **generators:** Add main schema to all validators ([#2997](https://github.com/feathersjs/feathers/issues/2997)) ([5854dea](https://github.com/feathersjs/feathers/commit/5854dea7f610262121a49623ec5bbd474dcd3ef3))\n- **generators:** Add TypeScript as normal instead of dev dependency ([#3011](https://github.com/feathersjs/feathers/issues/3011)) ([2f67398](https://github.com/feathersjs/feathers/commit/2f673987f38b199e75aff629b7cdfcaebfd69c4c))\n- **generators:** Do not removeAdditional in queries ([#3000](https://github.com/feathersjs/feathers/issues/3000)) ([ef501bc](https://github.com/feathersjs/feathers/commit/ef501bcfa528119168787e9d857f1bb90e0c3114))\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n### Features\n\n- **generators:** Add service file for shared information ([#3008](https://github.com/feathersjs/feathers/issues/3008)) ([0a1665d](https://github.com/feathersjs/feathers/commit/0a1665d23e002afadb40ed99bf0168f0fceb0054))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n"
  },
  {
    "path": "packages/generators/README.md",
    "content": "# @feathersjs/generators\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/generators.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/cli)\n\n> Feathers core code generators used by the CLI powered by [Pinion](https://github.com/feathershq/pinion/)\n\n## Installation\n\n```\nnpm install @feathersjs/generators --save-dev\n```\n\n## Documentation\n\nRefer to the [Feathers CLI guide](https://feathersjs.com/guides/cli/) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/generators/package.json",
    "content": "{\n  \"name\": \"@feathersjs/generators\",\n  \"version\": \"5.0.42\",\n  \"description\": \"Feathers CLI core generators, powered by Pinion\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"keywords\": [\n    \"feathers\",\n    \"pinion\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/commons\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributor\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 16\"\n  },\n  \"main\": \"lib/index.js\",\n  \"types\": \"lib/\",\n  \"type\": \"module\",\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"compile\": \"shx rm -rf lib/ && tsc\",\n    \"test\": \"npm run compile && mocha --config ../../.mocharc.json --require tsx --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@featherscloud/pinion\": \"^0.5.5\",\n    \"chalk\": \"^5.6.2\",\n    \"lodash\": \"^4.17.23\",\n    \"prettier\": \"^3.8.1\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/adapter-commons\": \"^5.0.42\",\n    \"@feathersjs/authentication\": \"^5.0.42\",\n    \"@feathersjs/authentication-client\": \"^5.0.42\",\n    \"@feathersjs/authentication-local\": \"^5.0.42\",\n    \"@feathersjs/authentication-oauth\": \"^5.0.42\",\n    \"@feathersjs/configuration\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/express\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@feathersjs/knex\": \"^5.0.42\",\n    \"@feathersjs/koa\": \"^5.0.42\",\n    \"@feathersjs/mongodb\": \"^5.0.42\",\n    \"@feathersjs/rest-client\": \"^5.0.42\",\n    \"@feathersjs/schema\": \"^5.0.42\",\n    \"@feathersjs/socketio\": \"^5.0.42\",\n    \"@feathersjs/transport-commons\": \"^5.0.42\",\n    \"@feathersjs/typebox\": \"^5.0.42\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"@types/prettier\": \"^2.7.3\",\n    \"axios\": \"^1.13.6\",\n    \"knex\": \"^3.1.0\",\n    \"mocha\": \"^11.7.5\",\n    \"mongodb\": \"^6.19.0\",\n    \"mssql\": \"^12.2.0\",\n    \"mysql\": \"^2.18.1\",\n    \"pg\": \"^8.19.0\",\n    \"shx\": \"^0.4.0\",\n    \"sqlite3\": \"^5.1.7\",\n    \"tsx\": \"^4.21.0\",\n    \"type-fest\": \"^5.4.4\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/generators/src/app/index.ts",
    "content": "import { sep, dirname } from 'path'\nimport chalk from 'chalk'\nimport { prompt, runGenerators } from '@featherscloud/pinion'\nimport { fileURLToPath } from 'url'\nimport {\n  FeathersBaseContext,\n  FeathersAppInfo,\n  initializeBaseContext,\n  addVersions,\n  install\n} from '../commons.js'\nimport { generate as connectionGenerator, prompts as connectionPrompts } from '../connection/index.js'\n\n// Set __dirname in es module\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nexport interface AppGeneratorData extends FeathersAppInfo {\n  /**\n   * The application name\n   */\n  name: string\n  /**\n   * A short description of the app\n   */\n  description: string\n  /**\n   * The database connection string\n   */\n  connectionString: string\n  /**\n   * The source folder where files are put\n   */\n  lib: string\n  /**\n   * Generate a client\n   */\n  client: boolean\n}\n\nexport type AppGeneratorContext = FeathersBaseContext &\n  AppGeneratorData & {\n    dependencies: string[]\n    devDependencies: string[]\n  }\n\nexport type AppGeneratorArguments = FeathersBaseContext & Partial<AppGeneratorData>\n\nexport const generate = (ctx: AppGeneratorArguments) =>\n  Promise.resolve(ctx)\n    .then(initializeBaseContext())\n    .then((ctx) => ({\n      ...ctx,\n      dependencies: [] as string[],\n      devDependencies: [] as string[]\n    }))\n    .then(\n      prompt((ctx) => [\n        {\n          name: 'language',\n          type: 'list',\n          message: 'Do you want to use JavaScript or TypeScript?',\n          when: !ctx.language,\n          choices: [\n            { name: 'TypeScript', value: 'ts' },\n            { name: 'JavaScript', value: 'js' }\n          ]\n        },\n        {\n          name: 'name',\n          type: 'input',\n          when: !ctx.name,\n          message: 'What is the name of your application?',\n          default: ctx.cwd.split(sep).pop(),\n          validate: (input) => {\n            if (ctx.dependencyVersions[input]) {\n              return `Application can not have the same name as a dependency`\n            }\n\n            return true\n          }\n        },\n        {\n          name: 'description',\n          type: 'input',\n          when: !ctx.description,\n          message: 'Write a short description'\n        },\n        {\n          type: 'list',\n          name: 'framework',\n          when: !ctx.framework,\n          message: 'Which HTTP framework do you want to use?',\n          choices: [\n            { value: 'koa', name: `KoaJS ${chalk.grey('(recommended)')}` },\n            { value: 'express', name: 'Express' }\n          ]\n        },\n        {\n          type: 'checkbox',\n          name: 'transports',\n          when: !ctx.transports,\n          message: 'What APIs do you want to offer?',\n          choices: [\n            { value: 'rest', name: 'HTTP (REST)', checked: true },\n            { value: 'websockets', name: 'Real-time', checked: true }\n          ]\n        },\n        {\n          name: 'packager',\n          type: 'list',\n          when: !ctx.packager,\n          message: 'Which package manager are you using?',\n          choices: [\n            { value: 'npm', name: 'npm' },\n            { value: 'yarn', name: 'Yarn' },\n            { value: 'pnpm', name: 'pnpm' }\n          ]\n        },\n        {\n          name: 'client',\n          type: 'confirm',\n          when: ctx.client === undefined,\n          message: (answers) => `Generate ${answers.language === 'ts' ? 'end-to-end typed ' : ''}client?`,\n          suffix: chalk.grey(' Can be used with React, Angular, Vue, React Native, Node.js etc.')\n        },\n        {\n          type: 'list',\n          name: 'schema',\n          when: !ctx.schema,\n          message: 'What is your preferred schema (model) definition format?',\n          suffix: chalk.grey(\n            ' Schemas allow to type, validate, secure and populate your data and configuration'\n          ),\n          choices: [\n            { value: 'typebox', name: `TypeBox ${chalk.grey('(recommended)')}` },\n            { value: 'json', name: 'JSON schema' },\n            { value: false, name: `No schema ${chalk.grey('(not recommended)')}` }\n          ]\n        },\n        ...connectionPrompts(ctx)\n      ])\n    )\n    .then(runGenerators(__dirname, 'templates'))\n    .then(initializeBaseContext())\n    .then(async (ctx) => {\n      const { dependencies } = await connectionGenerator(ctx)\n\n      return {\n        ...ctx,\n        dependencies\n      }\n    })\n    .then(\n      install(\n        ({ transports, framework, dependencyVersions, dependencies, schema }) => {\n          const hasSocketio = transports.includes('websockets')\n\n          dependencies.push(\n            '@feathersjs/feathers',\n            '@feathersjs/errors',\n            '@feathersjs/schema',\n            '@feathersjs/configuration',\n            '@feathersjs/transport-commons',\n            '@feathersjs/adapter-commons',\n            '@feathersjs/authentication',\n            '@feathersjs/authentication-client',\n            'winston'\n          )\n\n          if (hasSocketio) {\n            dependencies.push('@feathersjs/socketio')\n          }\n\n          if (framework === 'koa') {\n            dependencies.push('@feathersjs/koa')\n          }\n\n          if (framework === 'express') {\n            dependencies.push('@feathersjs/express', 'compression')\n          }\n\n          if (schema === 'typebox') {\n            dependencies.push('@feathersjs/typebox')\n          }\n\n          return addVersions(dependencies, dependencyVersions)\n        },\n        false,\n        ({ packager }) => packager\n      )\n    )\n    .then(\n      install(\n        ({ language, devDependencies, dependencyVersions }) => {\n          devDependencies.push(\n            'nodemon',\n            'axios',\n            'mocha',\n            'cross-env',\n            'prettier',\n            '@feathersjs/cli',\n            '@feathersjs/rest-client'\n          )\n\n          if (language === 'ts') {\n            devDependencies.push('@types/mocha', '@types/node', 'nodemon', 'ts-node', 'typescript', 'shx')\n          }\n\n          return addVersions(devDependencies, dependencyVersions)\n        },\n        true,\n        ({ packager }) => packager\n      )\n    )\n"
  },
  {
    "path": "packages/generators/src/app/templates/app.test.tpl.ts",
    "content": "import { toFile } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { AppGeneratorContext } from '../index.js'\n\nconst template = ({\n  lib\n}: AppGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/app.test.html\nimport assert from 'assert'\nimport axios from 'axios'\nimport type { Server } from 'http'\nimport { app } from '../${lib}/app'\n\nconst port = app.get('port')\nconst appUrl = \\`http://\\${app.get('host')}:\\${port}\\`\n\ndescribe('Feathers application tests', () => {\n  let server: Server\n\n  before(async () => {\n    server = await app.listen(port)\n  })\n\n  after(async () => {\n    await app.teardown()\n  })\n\n  it('starts and shows the index page', async () => {\n    const { data } = await axios.get<string>(appUrl)\n\n    assert.ok(data.indexOf('<html lang=\"en\">') !== -1)\n  })\n\n  it('shows a 404 JSON error', async () => {\n    try {\n      await axios.get(\\`\\${appUrl}/path/to/nowhere\\`, {\n        responseType: 'json'\n      })\n      assert.fail('should never get here')\n    } catch (error: any) {\n      const { response } = error\n      assert.strictEqual(response?.status, 404)\n      assert.strictEqual(response?.data?.code, 404)\n      assert.strictEqual(response?.data?.name, 'NotFound')\n    }\n  })\n})\n`\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(renderSource(template, toFile('test', 'app.test')))\n"
  },
  {
    "path": "packages/generators/src/app/templates/app.tpl.ts",
    "content": "import { toFile } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { AppGeneratorContext } from '../index.js'\n\nconst tsKoaApp = ({\n  transports,\n  schema\n}: AppGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/application.html\nimport { feathers } from '@feathersjs/feathers'\nimport configuration from '@feathersjs/configuration'\nimport {\n  koa, rest, bodyParser, errorHandler, parseAuthentication, cors, serveStatic\n} from '@feathersjs/koa'\n${transports.includes('websockets') ? \"import socketio from '@feathersjs/socketio'\" : ''}\n\n${schema !== false ? `import { configurationValidator } from './configuration'` : ''}\nimport type { Application } from './declarations'\nimport { logError } from './hooks/log-error'\nimport { services } from './services/index'\n${transports.includes('websockets') ? `import { channels } from './channels'` : ''}\n\nconst app: Application = koa(feathers())\n\n// Load our app configuration (see config/ folder)\napp.configure(configuration(${schema !== false ? 'configurationValidator' : ''}))\n\n// Set up Koa middleware\napp.use(cors())\napp.use(serveStatic(app.get('public')))\napp.use(errorHandler())\napp.use(parseAuthentication())\napp.use(bodyParser())\n\n// Configure services and transports\napp.configure(rest())\n${\n  transports.includes('websockets')\n    ? `app.configure(socketio({\n  cors: {\n    origin: app.get('origins')\n  }\n}))`\n    : ''\n}\napp.configure(services)\n${transports.includes('websockets') ? 'app.configure(channels)' : ''}\n\n\n// Register hooks that run on all service methods\napp.hooks({\n  around: {\n    all: [ logError ]\n  },\n  before: {},\n  after: {},\n  error: {}\n})\n// Register application setup and teardown hooks here\napp.hooks({\n  setup: [],\n  teardown: []\n})\n\nexport { app }\n`\n\nconst tsExpressApp = ({\n  transports,\n  schema\n}: AppGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/application.html\nimport { feathers } from '@feathersjs/feathers'\nimport express, {\n  rest, json, urlencoded, cors,\n  serveStatic, notFound, errorHandler\n} from '@feathersjs/express'\nimport configuration from '@feathersjs/configuration'\n${transports.includes('websockets') ? \"import socketio from '@feathersjs/socketio'\" : ''}\n\nimport type { Application } from './declarations'\n${schema !== false ? `import { configurationValidator } from './configuration'` : ''}\nimport { logger } from './logger'\nimport { logError } from './hooks/log-error'\nimport { services } from './services/index'\n${transports.includes('websockets') ? `import { channels } from './channels'` : ''}\n\nconst app: Application = express(feathers())\n\n// Load app configuration\napp.configure(configuration(${schema !== false ? 'configurationValidator' : ''}))\napp.use(cors())\napp.use(json())\napp.use(urlencoded({ extended: true }))\n// Host the public folder\napp.use('/', serveStatic(app.get('public')))\n\n// Configure services and real-time functionality\napp.configure(rest())\n${\n  transports.includes('websockets')\n    ? `app.configure(socketio({\n  cors: {\n    origin: app.get('origins')\n  }\n}))`\n    : ''\n}\napp.configure(services)\n${transports.includes('websockets') ? 'app.configure(channels)' : ''}\n\n// Configure a middleware for 404s and the error handler\napp.use(notFound())\napp.use(errorHandler({ logger }))\n\n// Register hooks that run on all service methods\napp.hooks({\n  around: {\n    all: [ logError ]\n  },\n  before: {},\n  after: {},\n  error: {}\n})\n// Register application setup and teardown hooks here\napp.hooks({\n  setup: [],\n  teardown: []\n})\n\nexport { app }\n`\n\nconst template = (ctx: AppGeneratorContext) =>\n  ctx.framework === 'express' ? tsExpressApp(ctx) : tsKoaApp(ctx)\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    renderSource(\n      template,\n      toFile<AppGeneratorContext>(({ lib }) => lib, 'app')\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/app/templates/channels.tpl.ts",
    "content": "import { toFile, when } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { AppGeneratorContext } from '../index.js'\n\nconst template = ({\n  language\n}: AppGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/channels.html\nimport type { RealTimeConnection, Params } from '@feathersjs/feathers'\nimport type { AuthenticationResult } from '@feathersjs/authentication'\nimport '@feathersjs/transport-commons'\nimport type { Application, HookContext } from './declarations'\nimport { logger } from './logger'\n\nexport const channels = (app: Application) => {\n  logger.warn('Publishing all events to all authenticated users. See \\`channels.${language}\\` and https://dove.feathersjs.com/api/channels.html for more information.')\n\n  app.on('connection', (connection: RealTimeConnection) => {\n    // On a new real-time connection, add it to the anonymous channel\n    app.channel('anonymous').join(connection)\n  })\n\n  app.on('login', (authResult: AuthenticationResult, { connection }: Params) => {\n    // connection can be undefined if there is no\n    // real-time connection, e.g. when logging in via REST\n    if(connection) {\n      // The connection is no longer anonymous, remove it\n      app.channel('anonymous').leave(connection)\n\n      // Add it to the authenticated user channel\n      app.channel('authenticated').join(connection)\n    }\n  })\n\n  // eslint-disable-next-line no-unused-vars\n  app.publish((data: any, context: HookContext) => {\n    // Here you can add event publishers to channels set up in \\`channels.js\\`\n    // To publish only for a specific event use \\`app.publish(eventname, () => {})\\`\n\n    // e.g. to publish all service events to all authenticated users use\n    return app.channel('authenticated')\n  })\n}\n`\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    when<AppGeneratorContext>(\n      ({ transports }) => transports.includes('websockets'),\n      renderSource(\n        template,\n        toFile<AppGeneratorContext>(({ lib }) => lib, 'channels')\n      )\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/app/templates/client.test.tpl.ts",
    "content": "import { toFile, when } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { AppGeneratorContext } from '../index.js'\n\nconst template = ({ lib }: AppGeneratorContext) => /* ts */ `import assert from 'assert'\nimport axios from 'axios'\nimport type { Server } from 'http'\nimport { app } from '../${lib}/app'\nimport { createClient } from '../${lib}/client' \n\nimport rest from '@feathersjs/rest-client'\n\nconst port = app.get('port')\nconst appUrl = \\`http://\\${app.get('host')}:\\${port}\\`\n\ndescribe('client tests', () => {\n  const client = createClient(rest(appUrl).axios(axios))\n\n  it('initialized the client', () => {\n    assert.ok(client)\n  })\n})\n`\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    when<AppGeneratorContext>((ctx) => ctx.client, renderSource(template, toFile('test', 'client.test')))\n  )\n"
  },
  {
    "path": "packages/generators/src/app/templates/client.tpl.ts",
    "content": "import { toFile, when } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { AppGeneratorContext } from '../index.js'\n\nconst template = ({\n  name,\n  language\n}: AppGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/client.html\nimport { feathers } from '@feathersjs/feathers'\nimport type { TransportConnection, Application } from '@feathersjs/feathers'\nimport authenticationClient from '@feathersjs/authentication-client'\nimport type { AuthenticationClientOptions } from '@feathersjs/authentication-client'\n\nexport interface Configuration {\n  connection: TransportConnection<ServiceTypes>\n}\n\nexport interface ServiceTypes {}\n\nexport type ClientApplication = Application<ServiceTypes, Configuration>\n\n/**\n * Returns a ${language === 'ts' ? 'typed' : ''} client for the ${name} app.\n * \n * @param connection The REST or Socket.io Feathers client connection\n * @param authenticationOptions Additional settings for the authentication client\n * @see https://dove.feathersjs.com/api/client.html\n * @returns The Feathers client application\n */\nexport const createClient = <Configuration = any> (\n  connection: TransportConnection<ServiceTypes>,\n  authenticationOptions: Partial<AuthenticationClientOptions> = {}\n) => {\n  const client: ClientApplication = feathers()\n\n  client.configure(connection)\n  client.configure(authenticationClient(authenticationOptions))\n  client.set('connection', connection)\n\n  return client\n}\n`\n\nexport const generate = async (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    when<AppGeneratorContext>(\n      (ctx) => ctx.client,\n      renderSource(\n        template,\n        toFile<AppGeneratorContext>(({ lib }) => lib, 'client')\n      )\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/app/templates/configuration.tpl.ts",
    "content": "import { toFile, when, writeJSON } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { AppGeneratorContext } from '../index.js'\n\nconst defaultConfig = ({}: AppGeneratorContext) => ({\n  host: 'localhost',\n  port: 3030,\n  public: './public/',\n  origins: ['http://localhost:3030'],\n  paginate: {\n    default: 10,\n    max: 50\n  }\n})\n\nconst customEnvironment = {\n  port: {\n    __name: 'PORT',\n    __format: 'number'\n  },\n  host: 'HOSTNAME',\n  authentication: {\n    secret: 'FEATHERS_SECRET'\n  }\n}\n\nconst testConfig = {\n  port: 8998\n}\n\nconst configurationJsonTemplate =\n  ({}: AppGeneratorContext) => `import { defaultAppSettings, getValidator } from '@feathersjs/schema'\nimport type { FromSchema } from '@feathersjs/schema'\n\nimport { dataValidator } from './validators'\n\nexport const configurationSchema = {\n  $id: 'configuration',\n  type: 'object',\n  additionalProperties: false,\n  required: [ 'host', 'port', 'public' ],\n  properties: {\n    ...defaultAppSettings,\n    host: { type: 'string' },\n    port: { type: 'number' },\n    public: { type: 'string' }\n  }\n} as const\n\nexport const configurationValidator = getValidator(configurationSchema, dataValidator)\n\nexport type ApplicationConfiguration = FromSchema<typeof configurationSchema>\n`\n\nconst configurationTypeboxTemplate =\n  ({}: AppGeneratorContext) => `import { Type, getValidator, defaultAppConfiguration } from '@feathersjs/typebox'\nimport type { Static } from '@feathersjs/typebox'\n\nimport { dataValidator } from './validators'\n\nexport const configurationSchema = Type.Intersect([\n  defaultAppConfiguration,\n  Type.Object({\n    host: Type.String(),\n    port: Type.Number(),\n    public: Type.String()\n  })\n])\n\nexport type ApplicationConfiguration = Static<typeof configurationSchema>\n\nexport const configurationValidator = getValidator(configurationSchema, dataValidator)\n`\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx)\n    .then(writeJSON(defaultConfig, toFile('config', 'default.json')))\n    .then(writeJSON(testConfig, toFile('config', 'test.json')))\n    .then(writeJSON(customEnvironment, toFile('config', 'custom-environment-variables.json')))\n    .then(\n      when<AppGeneratorContext>(\n        (ctx) => ctx.schema !== false,\n        renderSource(\n          async (ctx) =>\n            ctx.schema === 'typebox' ? configurationTypeboxTemplate(ctx) : configurationJsonTemplate(ctx),\n          toFile<AppGeneratorContext>(({ lib }) => lib, 'configuration')\n        )\n      )\n    )\n"
  },
  {
    "path": "packages/generators/src/app/templates/declarations.tpl.ts",
    "content": "import { toFile, when, renderTemplate } from '@featherscloud/pinion'\nimport { AppGeneratorContext } from '../index.js'\n\nconst template = ({\n  framework,\n  schema\n}: AppGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/typescript.html\nimport { HookContext as FeathersHookContext, NextFunction } from '@feathersjs/feathers'\nimport { Application as FeathersApplication } from '@feathersjs/${framework}'\n${\n  schema === false\n    ? `type ApplicationConfiguration = any`\n    : `import { ApplicationConfiguration } from './configuration'`\n}\n\nexport type { NextFunction }\n\n// The types for app.get(name) and app.set(name)\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface Configuration extends ApplicationConfiguration {}\n\n// A mapping of service names to types. Will be extended in service files.\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface ServiceTypes {}\n\n// The application instance type that will be used everywhere else\nexport type Application = FeathersApplication<ServiceTypes, Configuration>\n\n// The context for hook functions - can be typed with a service class\nexport type HookContext<S = any> = FeathersHookContext<Application, S>\n`\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    when<AppGeneratorContext>(\n      ({ language }) => language === 'ts',\n      renderTemplate(\n        template,\n        toFile<AppGeneratorContext>(({ lib }) => lib, 'declarations.ts')\n      )\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/app/templates/gitignore.tpl.ts",
    "content": "import { renderTemplate, toFile } from '@featherscloud/pinion'\nimport { AppGeneratorContext } from '..'\n\nconst template = `# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n.pnpm-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n.env.test\n.env.production\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# yarn v2\n.yarn/cache\n.yarn/unplugged\n.yarn/build-state.yml\n.yarn/install-state.gz\n.pnp.*\n.sqlite\n\nlib/\n`\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(renderTemplate(template, toFile('.gitignore')))\n"
  },
  {
    "path": "packages/generators/src/app/templates/index.html.tpl.ts",
    "content": "import { renderTemplate, toFile } from '@featherscloud/pinion'\nimport { AppGeneratorContext } from '../index.js'\n\nconst template = ({ name, description }: AppGeneratorContext) => /* html */ `<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <title>${name}</title>\n    <meta name=\"description\" content=\"${description}\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <style>\n      * {\n        margin: 0;\n        padding: 0;\n        box-sizing: border-box;\n      }\n\n      html {\n        height: 100%;\n      }\n\n      body {\n        min-height: 100%;\n        display: flex;\n        align-items: center;\n      }\n\n      img.logo {\n        display: block;\n        margin: auto auto;\n        width: 30%;\n        max-width: 100%;\n        max-height: 100%;\n      }\n    </style>\n  </head>\n  <body>\n    <img class=\"logo\" src=\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwMCIgaGVpZ2h0PSIyNTAwIiB2aWV3Qm94PSIwIDAgMjU2IDI1NiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWlkWU1pZCI+PHBhdGggZD0iTTEyOCA5LjEwMmM2NS42NjUgMCAxMTguODk4IDUzLjIzMyAxMTguODk4IDExOC44OTggMCA2NS42NjUtNTMuMjMzIDExOC44OTgtMTE4Ljg5OCAxMTguODk4QzYyLjMzNSAyNDYuODk4IDkuMTAyIDE5My42NjUgOS4xMDIgMTI4IDkuMTAyIDYyLjMzNSA2Mi4zMzUgOS4xMDIgMTI4IDkuMTAyTTEyOCAwQzU3LjQyMSAwIDAgNTcuNDIxIDAgMTI4YzAgNzAuNTc5IDU3LjQyMSAxMjggMTI4IDEyOCA3MC41NzkgMCAxMjgtNTcuNDIxIDEyOC0xMjhDMjU2IDU3LjQyMSAxOTguNTc5IDAgMTI4IDBtMjAuODMgMjUuNTI0Yy0xMC40My0xLjg5Ni0zNS42NTEgMzYuNDA5LTQzLjk5NCA1OS43MzQtLjYzNCAxLjc2OS0yLjA4NiA4LjI0OS0yLjA4NiA5Ljk1NSAwIDAgNi41MzEgMTQuMDU1IDguMzQzIDE3LjM1MS0zLjAzNC0xLjU4LTkuMzIzLTEzLjc1Ni05LjMyMy0xMy43NTYtMy4wMzQgNS43ODQtNS45NDIgMzIuMzQtNC45OTQgMzcuMjcxIDAgMCA2Ljc2MiAxMC4wNjIgOS4zODcgMTIuNTc4LTMuNjAzLTEuMjAxLTkuNjcxLTkuMzU1LTkuNjcxLTkuMzU1LTEuMTM4IDMuNTA4LS45MTYgMTAuODA3LS4zNzkgMTMuMjc0IDQuNTUxIDYuNjM3IDEwLjYxOSA3LjM5NiAxMC42MTkgNy4zOTZzLTYuNjM3IDY2LjE4MSAzLjQxMyA3MS4xMTFjNi4yNTgtMS4zMjcgNy43NzUtNzMuOTU2IDcuNzc1LTczLjk1NnM3LjU4NS41NjkgOS4yOTItMS4zMjdjMy44NTYtMi42NTUgMTIuODI2LTMwLjIyNCAxMi45NTgtMzQuMjAyIDAgMC0xMC40MSAxLjk1Mi0xNS40ODcgMy45MjQgMy44MjYtMy44IDE2LjA0OS02LjM1MiAxNi4wNDktNi4zNTIgMy4zMTUtMy45NzkgMTAuMjkxLTMxLjA0NyAxMC45OTQtMzkuMzkxLjE3Ni0yLjA5My41ODMtNC42NTcuMjY4LTguMzk4IDAgMC05Ljk0MSAyLjE3Ny0xMi4wMTQgMS40MjQgMi4xMDQtLjIzNyAxMi4yNjMtNC4xNCAxMi4yNjMtNC4xNCAxLjgwMS0xNi4yMTMgMi4zNTgtNDIuMDkxLTMuNDEzLTQzLjE0MXptLTM2LjM4IDE3MS42OTFjLS43OTUgMTkuNDk2LTEuMjk0IDI1LjAwNC0yLjExNSAyOS42MDEtLjM3OS44NTctLjc1OC45OTctMS4xMzgtLjA5NS0zLjQ3Ny0xNS45OTItMy4yMjQtMTM2LjQzOCAzNi40MDktMTkxLjI0MS0yMy4wNSA0Mi4wOTItMzMuNTM1IDEyMi44NjEtMzMuMTU2IDE2MS43MzV6IiBmaWxsPSIjMzMzIi8+PC9zdmc+\" />\n  </body>\n</html>\n\n`\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(renderTemplate(template, toFile('public', 'index.html')))\n"
  },
  {
    "path": "packages/generators/src/app/templates/index.tpl.ts",
    "content": "import { toFile } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { AppGeneratorContext } from '../index.js'\n\nconst template = ({}: AppGeneratorContext) => /* ts */ `import { app } from './app'\nimport { logger } from './logger'\n\nconst port = app.get('port')\nconst host = app.get('host')\n\nprocess.on('unhandledRejection', (reason) =>\n  logger.error('Unhandled Rejection %O', reason)\n)\n\napp.listen(port).then(() => {\n  logger.info(\\`Feathers app listening on http://\\${host}:\\${port}\\`)\n})\n`\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    renderSource(\n      template,\n      toFile<AppGeneratorContext>(({ lib }) => lib, 'index')\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/app/templates/logger.tpl.ts",
    "content": "import { toFile } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { AppGeneratorContext } from '../index.js'\n\nconst template =\n  ({}: AppGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/logging.html\nimport { createLogger, format, transports } from 'winston'\n\n// Configure the Winston logger. For the complete documentation see https://github.com/winstonjs/winston\nexport const logger = createLogger({\n  // To see more detailed errors, change this to 'debug'\n  level: 'info',\n  format: format.combine(\n    format.splat(),\n    format.simple()\n  ),\n  transports: [\n    new transports.Console()\n  ]\n})\n`\n\nexport const logErrorTemplate = /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/log-error.html\nimport type { HookContext, NextFunction } from '../declarations'\nimport { logger } from '../logger'\n\nexport const logError = async (context: HookContext, next: NextFunction) => {\n  try {\n    await next()\n  } catch (error: any) {\n    logger.error(error.stack)\n    \n    // Log validation errors\n    if (error.data) {\n      logger.error('Data: %O', error.data)\n    }\n\n    throw error\n  }\n}\n`\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx)\n    .then(\n      renderSource(\n        template,\n        toFile<AppGeneratorContext>(({ lib }) => lib, 'logger')\n      )\n    )\n    .then(\n      renderSource(\n        logErrorTemplate,\n        toFile<AppGeneratorContext>(({ lib }) => lib, 'hooks', 'log-error')\n      )\n    )\n"
  },
  {
    "path": "packages/generators/src/app/templates/package.json.tpl.ts",
    "content": "import { toFile, writeJSON } from '@featherscloud/pinion'\nimport { AppGeneratorContext } from '../index.js'\n\nconst jsPackageJson = (lib: string) => ({\n  type: 'module',\n  scripts: {\n    start: `node ${lib}`,\n    dev: `nodemon ${lib}/`,\n    prettier: 'npx prettier \"**/*.js\" --write',\n    mocha: 'cross-env NODE_ENV=test mocha test/ --recursive --exit',\n    test: 'npm run mocha',\n    'bundle:client': 'npm pack --pack-destination ./public'\n  }\n})\n\nconst tsPackageJson = (lib: string) => ({\n  scripts: {\n    dev: `nodemon -x ts-node ${lib}/index.ts`,\n    compile: 'shx rm -rf lib/ && tsc',\n    start: 'node lib/',\n    prettier: 'npx prettier \"**/*.ts\" --write',\n    mocha:\n      'cross-env NODE_ENV=test mocha test/ --require ts-node/register --recursive --extension .ts --exit',\n    test: 'npm run mocha',\n    'bundle:client': 'npm run compile && npm pack --pack-destination ./public'\n  }\n})\n\nconst packageJson = ({\n  name,\n  description,\n  client,\n  language,\n  packager,\n  database,\n  framework,\n  transports,\n  lib,\n  test,\n  schema\n}: AppGeneratorContext) => ({\n  name,\n  description,\n  version: '0.0.0',\n  homepage: '',\n  private: true,\n  keywords: ['feathers'],\n  author: {},\n  contributors: [] as string[],\n  bugs: {},\n  engines: {\n    node: `>= ${process.version.substring(1)}`\n  },\n  feathers: {\n    language,\n    packager,\n    database,\n    framework,\n    transports,\n    schema\n  },\n  directories: {\n    lib,\n    test\n  },\n  ...(client\n    ? {\n        files: ['lib/client.js', 'lib/**/*.d.ts', 'lib/**/*.shared.js'],\n        main: language === 'ts' ? 'lib/client' : `${lib}/client`\n      }\n    : {\n        main: 'lib/index'\n      }),\n  ...(language === 'ts' ? tsPackageJson(lib) : jsPackageJson(lib))\n})\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(writeJSON(packageJson, toFile('package.json')))\n"
  },
  {
    "path": "packages/generators/src/app/templates/prettierrc.tpl.ts",
    "content": "import { toFile, writeJSON } from '@featherscloud/pinion'\nimport { AppGeneratorContext } from '../index.js'\nimport { PRETTIERRC } from '../../commons.js'\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    writeJSON<AppGeneratorContext>(\n      (ctx) => ({\n        ...PRETTIERRC,\n        parser: ctx.language === 'ts' ? 'typescript' : 'babel'\n      }),\n      toFile('.prettierrc')\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/app/templates/readme.md.tpl.ts",
    "content": "import { renderTemplate, toFile } from '@featherscloud/pinion'\nimport { AppGeneratorContext } from '../index.js'\n\nconst template = ({ name, description, language, database }: AppGeneratorContext) => /* md */ `# ${name}\n\n> ${description}\n\n## About\n\nThis project uses [Feathers](http://feathersjs.com). An open source framework for building APIs and real-time applications.\n\n## Getting Started\n\n1. Make sure you have [NodeJS](https://nodejs.org/) and [npm](https://www.npmjs.com/) installed.\n2. Install your dependencies\n\n    \\`\\`\\`\n    cd path/to/${name}\n    npm install\n    \\`\\`\\`\n\n3. Start your app\n\n    \\`\\`\\`${\n      language === 'ts'\n        ? `\n    npm run compile # Compile TypeScript source`\n        : ''\n    }${\n      database !== 'mongodb'\n        ? `\n    npm run migrate # Run migrations to set up the database`\n        : ''\n    }\n    npm start\n    \\`\\`\\`\n\n## Testing\n\nRun \\`npm test\\` and all your tests in the \\`test/\\` directory will be run.\n\n## Scaffolding\n\nThis app comes with a powerful command line interface for Feathers. Here are a few things it can do:\n\n\\`\\`\\`\n$ npx feathers help                           # Show all commands\n$ npx feathers generate service               # Generate a new Service\n\\`\\`\\`\n\n## Help\n\nFor more information on all the things you can do with Feathers visit [docs.feathersjs.com](http://docs.feathersjs.com).\n`\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(renderTemplate(template, toFile('readme.md')))\n"
  },
  {
    "path": "packages/generators/src/app/templates/services.tpl.ts",
    "content": "import { toFile } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { AppGeneratorContext } from '../index.js'\n\nconst template =\n  ({}: AppGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/application.html#configure-functions\nimport type { Application } from '../declarations'\n\nexport const services = (app: Application) => {\n  // All services will be registered here\n}\n`\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    renderSource(\n      template,\n      toFile<AppGeneratorContext>(({ lib }) => lib, 'services', 'index')\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/app/templates/tsconfig.json.tpl.ts",
    "content": "import { toFile, when, writeJSON } from '@featherscloud/pinion'\nimport { AppGeneratorContext } from '../index.js'\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    when<AppGeneratorContext>(\n      (ctx) => ctx.language === 'ts',\n      writeJSON<AppGeneratorContext>(\n        ({ lib }) => ({\n          'ts-node': {\n            files: true\n          },\n          compilerOptions: {\n            target: 'es2020',\n            module: 'commonjs',\n            outDir: './lib',\n            rootDir: `./${lib}`,\n            declaration: true,\n            strict: true,\n            esModuleInterop: true,\n            sourceMap: true,\n            skipLibCheck: true\n          },\n          include: [lib],\n          exclude: ['test']\n        }),\n        toFile('tsconfig.json')\n      )\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/app/templates/validators.tpl.ts",
    "content": "import { toFile } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { AppGeneratorContext } from '../index.js'\n\nconst validatorTemplate = /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/validators.html\nimport { Ajv, addFormats } from '@feathersjs/schema'\nimport type { FormatsPluginOptions } from '@feathersjs/schema'\n\nconst formats: FormatsPluginOptions = [\n  'date-time', \n  'time', \n  'date', \n  'email',  \n  'hostname', \n  'ipv4', \n  'ipv6', \n  'uri', \n  'uri-reference', \n  'uuid',\n  'uri-template', \n  'json-pointer', \n  'relative-json-pointer', \n  'regex'\n]\n\nexport const dataValidator: Ajv = addFormats(new Ajv({}), formats)\n\nexport const queryValidator: Ajv = addFormats(new Ajv({\n  coerceTypes: true\n}), formats)\n`\n\nexport const generate = (ctx: AppGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    renderSource(\n      validatorTemplate,\n      toFile<AppGeneratorContext>(({ lib }) => lib, 'validators')\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/authentication/index.ts",
    "content": "import chalk from 'chalk'\nimport { dirname } from 'path'\nimport { runGenerators, prompt } from '@featherscloud/pinion'\nimport { fileURLToPath } from 'url'\nimport {\n  addVersions,\n  checkPreconditions,\n  FeathersBaseContext,\n  initializeBaseContext,\n  install\n} from '../commons.js'\nimport { generate as serviceGenerator, ServiceGeneratorContext } from '../service/index.js'\n\n// Set __dirname in es module\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nexport interface AuthenticationGeneratorContext extends ServiceGeneratorContext {\n  service: string\n  entity: string\n  authStrategies: string[]\n  dependencies: string[]\n}\n\nexport type AuthenticationGeneratorArguments = FeathersBaseContext &\n  Partial<Pick<AuthenticationGeneratorContext, 'service' | 'authStrategies' | 'path' | 'schema' | 'type'>>\n\nexport const generate = (ctx: AuthenticationGeneratorArguments) =>\n  Promise.resolve(ctx)\n    .then(initializeBaseContext())\n    .then(checkPreconditions())\n    .then(\n      prompt((ctx: AuthenticationGeneratorArguments) => [\n        {\n          type: 'checkbox',\n          name: 'authStrategies',\n          when: !ctx.authStrategies,\n          message: 'Which authentication methods do you want to use?',\n          suffix: chalk.grey(' Other methods and providers can be added at any time.'),\n          choices: [\n            {\n              name: 'Email + Password',\n              value: 'local',\n              checked: true\n            },\n            {\n              name: 'Google',\n              value: 'google'\n            },\n            {\n              name: 'Facebook',\n              value: 'facebook'\n            },\n            {\n              name: 'Twitter',\n              value: 'twitter'\n            },\n            {\n              name: 'GitHub',\n              value: 'github'\n            },\n            {\n              name: 'Auth0',\n              value: 'auth0'\n            }\n          ]\n        },\n        {\n          name: 'service',\n          type: 'input',\n          when: !ctx.service,\n          message: 'What is your authentication service name?',\n          default: 'user'\n        },\n        {\n          name: 'path',\n          type: 'input',\n          when: !ctx.path,\n          message: 'What path should the service be registered on?',\n          default: 'users'\n        }\n      ])\n    )\n    .then(async (ctx) => {\n      const serviceContext = await serviceGenerator({\n        ...ctx,\n        name: ctx.service,\n        isEntityService: true\n      })\n\n      return {\n        ...ctx,\n        entity: ctx.service,\n        ...serviceContext\n      }\n    })\n    .then(runGenerators(__dirname, 'templates'))\n    .then((ctx) => ctx as AuthenticationGeneratorContext)\n    .then((ctx) => {\n      const dependencies: string[] = []\n\n      dependencies.push('@feathersjs/authentication-oauth')\n\n      if (ctx.authStrategies.includes('local')) {\n        dependencies.push('@feathersjs/authentication-local')\n      }\n\n      if (ctx.dependencies) {\n        return {\n          ...ctx,\n          dependencies: [...ctx.dependencies, ...dependencies]\n        }\n      }\n\n      return install<AuthenticationGeneratorContext>(\n        addVersions(dependencies, ctx.dependencyVersions),\n        false,\n        ctx.feathers.packager\n      )(ctx)\n    })\n"
  },
  {
    "path": "packages/generators/src/authentication/templates/authentication.tpl.ts",
    "content": "import { before, toFile } from '@featherscloud/pinion'\nimport { injectSource, renderSource } from '../../commons.js'\nimport { AuthenticationGeneratorContext } from '../index.js'\nimport { localTemplate, oauthTemplate } from '../../commons.js'\n\nconst template = ({\n  authStrategies\n}: AuthenticationGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/authentication.html\nimport { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'\n${localTemplate(authStrategies, `import { LocalStrategy } from '@feathersjs/authentication-local'`)}\n${oauthTemplate(authStrategies, `import { oauth, OAuthStrategy } from '@feathersjs/authentication-oauth'`)}\n\nimport type { Application } from './declarations'\n\ndeclare module './declarations' {\n  interface ServiceTypes {\n    'authentication': AuthenticationService\n  }\n}\n\nexport const authentication = (app: Application) => {\n  const authentication = new AuthenticationService(app)\n\n  authentication.register('jwt', new JWTStrategy())\n  ${authStrategies\n    .map(\n      (strategy) =>\n        `  authentication.register('${strategy}', ${\n          strategy === 'local' ? `new LocalStrategy()` : `new OAuthStrategy()`\n        })`\n    )\n    .join('\\n')}\n\n  app.use('authentication', authentication)\n  ${oauthTemplate(authStrategies, `app.configure(oauth())`)}\n}\n`\n\nconst importTemplate = \"import { authentication } from './authentication'\"\nconst configureTemplate = 'app.configure(authentication)'\nconst toAppFile = toFile<AuthenticationGeneratorContext>(({ lib }) => [lib, 'app'])\n\nexport const generate = (ctx: AuthenticationGeneratorContext) =>\n  Promise.resolve(ctx)\n    .then(\n      renderSource(\n        template,\n        toFile<AuthenticationGeneratorContext>(({ lib }) => lib, 'authentication')\n      )\n    )\n    .then(injectSource(importTemplate, before('import { services } from'), toAppFile))\n    .then(injectSource(configureTemplate, before('app.configure(services)'), toAppFile))\n"
  },
  {
    "path": "packages/generators/src/authentication/templates/client.test.tpl.ts",
    "content": "import { toFile, when } from '@featherscloud/pinion'\nimport { fileExists, renderSource } from '../../commons.js'\nimport { AuthenticationGeneratorContext } from '../index.js'\nimport { localTemplate } from '../../commons.js'\n\nconst template = ({\n  authStrategies,\n  upperName,\n  type,\n  lib\n}: AuthenticationGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/client.test.html\nimport assert from 'assert'\nimport axios from 'axios'\n\nimport rest from '@feathersjs/rest-client'\n${localTemplate(authStrategies, `import authenticationClient from '@feathersjs/authentication-client'`)}\nimport { app } from '../${lib}/app'\nimport { createClient } from '../${lib}/client' \n${localTemplate(authStrategies, `import type { ${upperName}Data } from '../${lib}/client'`)}\n\nconst port = app.get('port')\nconst appUrl = \\`http://\\${app.get('host')}:\\${port}\\`\n\ndescribe('application client tests', () => {\n  const client = createClient(rest(appUrl).axios(axios))\n\n  before(async () => {\n    await app.listen(port)\n  })\n\n  after(async () => {\n    await app.teardown()\n  })\n\n  it('initialized the client', () => {\n    assert.ok(client)\n  })\n\n  ${localTemplate(\n    authStrategies,\n    `\n  it('creates and authenticates a user with email and password', async () => {\n    const userData: ${upperName}Data = {\n      email: 'someone@example.com',\n      password: 'supersecret'\n    }\n\n    await client.service('users').create(userData)\n    \n    const { user, accessToken } = await client.authenticate({\n      strategy: 'local',\n      ...userData\n    })\n    \n    assert.ok(accessToken, 'Created access token for user')\n    assert.ok(user, 'Includes user in authentication data')\n    assert.strictEqual(user.password, undefined, 'Password is hidden to clients')\n\n    await client.logout()\n\n    // Remove the test user on the server\n    await app.service('users').remove(user.${type === 'mongodb' ? '_id' : 'id'})\n  })`\n  )}\n})\n`\n\nexport const generate = (ctx: AuthenticationGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    when<AuthenticationGeneratorContext>(\n      ({ lib, language }) => fileExists(lib, `client.${language}`),\n      renderSource(\n        template,\n        toFile<AuthenticationGeneratorContext>(({ test }) => test, 'client.test'),\n        { force: true }\n      )\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/authentication/templates/config.tpl.ts",
    "content": "import crypto from 'crypto'\nimport { toFile, mergeJSON } from '@featherscloud/pinion'\nimport { AuthenticationGeneratorContext } from '../index.js'\n\nexport const generate = (ctx: AuthenticationGeneratorContext) =>\n  Promise.resolve(ctx)\n    .then(\n      mergeJSON<AuthenticationGeneratorContext>(\n        ({ authStrategies }) => {\n          const authentication: any = {\n            entity: ctx.entity,\n            service: ctx.path,\n            secret: crypto.randomBytes(24).toString('base64'),\n            authStrategies: ['jwt'],\n            jwtOptions: {\n              header: {\n                typ: 'access'\n              },\n              audience: 'https://yourdomain.com',\n              algorithm: 'HS256',\n              expiresIn: '1d'\n            }\n          }\n\n          if (authStrategies.includes('local')) {\n            authentication.authStrategies.push('local')\n            authentication.local = {\n              usernameField: 'email',\n              passwordField: 'password'\n            }\n          }\n\n          const oauthStrategies = authStrategies.filter((name) => name !== 'local')\n\n          if (oauthStrategies.length) {\n            authentication.oauth = oauthStrategies.reduce((oauth, name) => {\n              oauth[name] = {\n                key: '<Client ID>',\n                secret: '<Client secret>'\n              }\n\n              return oauth\n            }, {} as any)\n          }\n\n          return { authentication }\n        },\n        toFile('config', 'default.json')\n      )\n    )\n    .then(\n      mergeJSON<AuthenticationGeneratorContext>(\n        {\n          authentication: {\n            secret: 'FEATHERS_SECRET'\n          }\n        },\n        toFile('config', 'custom-environment-variables.json')\n      )\n    )\n"
  },
  {
    "path": "packages/generators/src/authentication/templates/declarations.tpl.ts",
    "content": "import { inject, before, toFile, when, append } from '@featherscloud/pinion'\nimport { AuthenticationGeneratorContext } from '../index.js'\n\nconst importTemplate = ({\n  upperName,\n  folder,\n  fileName\n}: AuthenticationGeneratorContext) => /* ts */ `import { ${upperName} } from './services/${folder.join(\n  '/'\n)}/${fileName}'\n`\n\nconst paramsTemplate = ({\n  entity,\n  upperName\n}: AuthenticationGeneratorContext) => /* ts */ `// Add the ${entity} as an optional property to all params\ndeclare module '@feathersjs/feathers' {\n  interface Params {\n    ${entity}?: ${upperName}\n  }\n}\n`\n\nconst toDeclarationFile = toFile<AuthenticationGeneratorContext>(({ lib }) => lib, 'declarations.ts')\n\nexport const generate = (ctx: AuthenticationGeneratorContext) =>\n  Promise.resolve(ctx)\n    .then(\n      when(\n        (ctx) => ctx.language === 'ts',\n        inject(\n          importTemplate,\n          before(/export \\{ NextFunction \\}|export type \\{ NextFunction \\}/),\n          toDeclarationFile\n        )\n      )\n    )\n    .then(when((ctx) => ctx.language === 'ts', inject(paramsTemplate, append(), toDeclarationFile)))\n"
  },
  {
    "path": "packages/generators/src/commons.ts",
    "content": "import fs from 'fs'\nimport { join, dirname } from 'path'\nimport { PackageJson } from 'type-fest'\nimport { readFile, writeFile } from 'fs/promises'\nimport {\n  Callable,\n  PinionContext,\n  loadJSON,\n  fromFile,\n  getCallable,\n  renderTemplate,\n  inject,\n  Location,\n  exec\n} from '@featherscloud/pinion'\nimport ts from 'typescript'\nimport prettier, { Options as PrettierOptions } from 'prettier'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\n\n// Set __dirname in es module\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nexport const { version } = JSON.parse(fs.readFileSync(join(__dirname, '..', 'package.json')).toString())\n\nexport type DependencyVersions = { [key: string]: string }\n\nexport const DATABASE_TYPES = ['mongodb', 'mysql', 'postgresql', 'sqlite', 'mssql', 'other'] as const\n\n/**\n * The database types supported by this generator\n */\nexport type DatabaseType = (typeof DATABASE_TYPES)[number]\n\n/**\n * Returns the name of the Feathers database adapter for a supported database type\n *\n * @param database The type of the database\n * @returns The name of the adapter\n */\nexport const getDatabaseAdapter = (database: DatabaseType) => (database === 'mongodb' ? 'mongodb' : 'knex')\n\nexport type FeathersAppInfo = {\n  /**\n   * The application language\n   */\n  language: 'ts' | 'js'\n  /**\n   * The main database\n   */\n  database: DatabaseType\n  /**\n   * The package manager used\n   */\n  packager: 'yarn' | 'npm' | 'pnpm'\n  /**\n   * A list of all chosen transports\n   */\n  transports: ('rest' | 'websockets')[]\n  /**\n   * The HTTP framework used\n   */\n  framework: 'koa' | 'express'\n  /**\n   * The main schema definition format\n   */\n  schema: 'typebox' | 'json' | false\n}\n\nexport interface AppPackageJson extends PackageJson {\n  feathers?: FeathersAppInfo\n}\n\nexport interface FeathersBaseContext extends PinionContext {\n  /**\n   * Information about the Feathers application (like chosen language, database etc.)\n   * usually taken from `package.json`\n   */\n  feathers: FeathersAppInfo\n  /**\n   * The package.json file\n   */\n  pkg: AppPackageJson\n  /**\n   * The folder where source files are put\n   */\n  lib: string\n  /**\n   * The folder where test files are put\n   */\n  test: string\n  /**\n   * The language the app is generated in\n   */\n  language: 'js' | 'ts'\n  /**\n   * A list dependencies that should be installed with a certain version.\n   * Used for installing development dependencies during testing.\n   */\n  dependencyVersions?: DependencyVersions\n}\n\n/**\n * Returns dependencies with the versions from the context attached (if available)\n *\n * @param dependencies The dependencies to install\n * @param versions The dependency version list\n * @returns A list of dependencies with their versions\n */\nexport const addVersions = (\n  dependencies: string[],\n  versions: DependencyVersions,\n  defaultVersion = 'latest'\n): string[] => dependencies.map((dep) => `${dep}@${versions[dep] || defaultVersion}`)\n\n/**\n * Loads the application package.json and populates information like the library and test directory\n * and Feathers app specific information.\n *\n * @returns The updated context\n */\nexport const initializeBaseContext =\n  () =>\n  <C extends FeathersBaseContext>(ctx: C) =>\n    Promise.resolve(ctx)\n      .then(loadJSON(fromFile('package.json'), (pkg) => ({ pkg }), {}))\n      .then(\n        loadJSON(path.join(__dirname, '..', 'package.json'), (pkg: PackageJson) => ({\n          dependencyVersions: {\n            ...pkg.devDependencies,\n            ...ctx.dependencyVersions,\n            '@feathersjs/cli': version\n          }\n        }))\n      )\n      .then((ctx) => ({\n        ...ctx,\n        lib: ctx.pkg?.directories?.lib || 'src',\n        test: ctx.pkg?.directories?.test || 'test',\n        language: ctx.language || ctx.pkg?.feathers?.language,\n        feathers: ctx.pkg?.feathers\n      }))\n\n/**\n * A special error that can be thrown by generators. It contains additional\n * information about the error that can be used to display a more helpful\n * error message to the user.\n */\nexport class FeathersGeneratorError extends Error {\n  /**\n   * Additional information about the error. This can include things like\n   * the reason for the error and suggested actions to take.\n   */\n  context?: Record<string, unknown>\n\n  /**\n   * Creates a new FeathersGeneratorError\n   * @param message The error message\n   * @param context Additional information about the error\n   */\n  constructor(message: string, context?: Record<string, unknown>) {\n    super(message)\n    this.name = 'FeathersGeneratorError'\n    this.context = context\n  }\n}\n\n/**\n * Checks if the current context contains a valid generated application. This is necesary for most\n * generators (besides the app generator).\n *\n * @param ctx The context to check against\n * @returns Throws an error or returns the original context\n */\nexport const checkPreconditions =\n  () =>\n  async <T extends FeathersBaseContext>(ctx: T) => {\n    if (!ctx.feathers) {\n      throw new FeathersGeneratorError('Invalid Feathers application context', {\n        reason: 'Missing Feathers configuration',\n        suggestedAction: 'Verify package.json contains Feathers metadata'\n      })\n    }\n    return ctx\n  }\n\nconst importRegex = /from '(\\..*)'/g\nconst escapeNewLines = (code: string) => code.replace(/\\n\\n/g, '\\n/* :newline: */')\nconst restoreNewLines = (code: string) => code.replace(/\\/\\* :newline: \\*\\//g, '\\n')\nconst fixLocalImports = (code: string) => code.replace(importRegex, \"from '$1.js'\")\n\n/**\n * Returns the transpiled and prettified JavaScript for a TypeScript source code\n *\n * @param typescript The TypeScript source code\n * @param options TypeScript transpilation options\n * @returns The formatted JavaScript source code\n */\nexport const getJavaScript = (typescript: string, options: ts.TranspileOptions = {}) => {\n  const source = escapeNewLines(typescript)\n  const transpiled = ts.transpileModule(source, {\n    ...options,\n    compilerOptions: {\n      module: ts.ModuleKind.ESNext,\n      target: ts.ScriptTarget.ES2020,\n      preserveValueImports: true,\n      ...options.compilerOptions\n    }\n  })\n  const { outputText } = transpiled\n\n  if (outputText.startsWith('export {}') && typescript.startsWith('import')) {\n    return fixLocalImports(typescript)\n  }\n\n  return fixLocalImports(restoreNewLines(transpiled.outputText))\n}\n\nconst getFileName = async <C extends PinionContext & { language: 'js' | 'ts' }>(\n  target: Callable<string, C>,\n  ctx: C\n) => `${await getCallable(target, ctx)}.${ctx.language}`\n\n/**\n * The default configuration for prettifying files\n */\nexport const PRETTIERRC: PrettierOptions = {\n  tabWidth: 2,\n  useTabs: false,\n  printWidth: 110,\n  semi: false,\n  trailingComma: 'none',\n  singleQuote: true,\n  arrowParens: 'avoid',\n  bracketSpacing: true,\n  endOfLine: 'auto',\n  jsxSingleQuote: false,\n  quoteProps: 'as-needed'\n}\n\n/*\n * Format a source file using Prettier. Will use the local configuration, the settings set in\n * `options` or a default configuration\n *\n * @param target The file to prettify\n * @param options The Prettier options\n * @returns The updated context\n */\nexport const prettify =\n  <C extends PinionContext & { language: 'js' | 'ts' }>(\n    target: Callable<string, C>,\n    options: PrettierOptions = PRETTIERRC\n  ) =>\n  async (ctx: C) => {\n    const fileName = await getFileName(target, ctx)\n    const config = (await prettier.resolveConfig(ctx.cwd)) || options\n    const content = (await readFile(fileName)).toString()\n\n    try {\n      await writeFile(\n        fileName,\n        await prettier.format(content, {\n          parser: ctx.language === 'ts' ? 'typescript' : 'babel',\n          ...config\n        })\n      )\n    } catch (error: any) {\n      throw new Error(`Error prettifying ${fileName}: ${error.message}`)\n    }\n\n    return ctx\n  }\n\n/**\n * Render a source file template for the language set in the context.\n *\n * @param templates The JavaScript and TypeScript template to render\n * @param target The target filename without extension (will be added based on language)\n * @returns The updated context\n */\nexport const renderSource =\n  <C extends PinionContext & { language: 'js' | 'ts' }>(\n    template: Callable<string, C>,\n    target: Callable<string, C>,\n    options?: { force: boolean }\n  ) =>\n  async (ctx: C) => {\n    const { language } = ctx\n    const fileName = await getFileName(target, ctx)\n    const content = language === 'js' ? getJavaScript(await getCallable<string, C>(template, ctx)) : template\n    const renderer = renderTemplate(content, fileName, options)\n\n    return renderer(ctx).then(prettify(target))\n  }\n\nexport const install =\n  <C extends PinionContext & { language: 'js' | 'ts' }>(\n    dependencies: Callable<string[], C>,\n    dev: Callable<boolean, C>,\n    packager: Callable<string, C>\n  ) =>\n  async (ctx: C) => {\n    const dependencyList = await getCallable(dependencies, ctx)\n    const packageManager = await getCallable(packager, ctx)\n    const flags = dev ? [packageManager === 'yarn' ? '--dev' : '--save-dev'] : []\n\n    return exec(packager, [packageManager === 'yarn' ? 'add' : 'install', ...dependencyList, ...flags])(ctx)\n  }\n\n/**\n * Inject a source template as the language set in the context.\n *\n * @param template The source template to render\n * @param location The location to inject the code to. Must use the target language.\n * @param target The target file name\n * @param transpile Set to `false` if the code should not be transpiled to JavaScript\n * @returns\n */\nexport const injectSource =\n  <C extends PinionContext & { language: 'js' | 'ts' }>(\n    template: Callable<string, C>,\n    location: Location<C>,\n    target: Callable<string, C>,\n    transpile = true\n  ) =>\n  async (ctx: C) => {\n    const { language } = ctx\n    const source =\n      language === 'js' && transpile ? getJavaScript(await getCallable<string, C>(template, ctx)) : template\n    const fileName = await getFileName(target, ctx)\n    const injector = inject(source, location, fileName)\n\n    return injector(ctx).then(prettify(target))\n  }\n\n/**\n * Synchronously checks if a file exits\n * @param context The base context\n * @param filenames The filenames to check\n * @returns Wether the file exists or not\n */\nexport const fileExists = (...filenames: string[]) => fs.existsSync(join(...filenames))\n\n/**\n * The helper used by Knex to create migration names\n * @returns The current date and time in the format `YYYYMMDDHHMMSS`\n */\nexport const yyyymmddhhmmss = (offset = 0) => {\n  const now = new Date(Date.now() + offset)\n\n  return (\n    now.getUTCFullYear().toString() +\n    (now.getUTCMonth() + 1).toString().padStart(2, '0') +\n    now.getUTCDate().toString().padStart(2, '0') +\n    now.getUTCHours().toString().padStart(2, '0') +\n    now.getUTCMinutes().toString().padStart(2, '0') +\n    now.getUTCSeconds().toString().padStart(2, '0')\n  )\n}\n\n/**\n * Render a template if `local` authentication strategy has been selected\n * @param authStrategies The list of selected authentication strategies\n * @param content The content to render if `local` is selected\n * @param alt The content to render if `local` is not selected\n * @returns\n */\nexport const localTemplate = (authStrategies: string[], content: string, alt = '') =>\n  authStrategies.includes('local') ? content : alt\n\n/**\n * Render a template if an `oauth` authentication strategy has been selected\n * @param authStrategies\n * @param content\n * @returns\n */\nexport const oauthTemplate = (authStrategies: string[], content: string) =>\n  authStrategies.filter((s) => s !== 'local').length > 0 ? content : ''\n"
  },
  {
    "path": "packages/generators/src/connection/index.ts",
    "content": "import { dirname } from 'path'\nimport { runGenerator, prompt, mergeJSON, toFile, when } from '@featherscloud/pinion'\nimport { fileURLToPath } from 'url'\nimport chalk from 'chalk'\nimport {\n  install,\n  FeathersBaseContext,\n  DatabaseType,\n  getDatabaseAdapter,\n  addVersions,\n  checkPreconditions,\n  initializeBaseContext\n} from '../commons.js'\n\n// Set __dirname in es module\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nexport interface ConnectionGeneratorContext extends FeathersBaseContext {\n  name?: string\n  database: DatabaseType\n  connectionString: string\n  dependencies: string[]\n}\n\nexport type ConnectionGeneratorArguments = FeathersBaseContext &\n  Partial<Pick<ConnectionGeneratorContext, 'database' | 'connectionString' | 'name'>>\n\nexport const defaultConnectionString = (type: DatabaseType, name: string) => {\n  const connectionStrings = {\n    mongodb: `mongodb://127.0.0.1:27017/${name}`,\n    mysql: `mysql://root:@localhost:3306/${name}`,\n    postgresql: `postgres://postgres:@localhost:5432/${name}`,\n    sqlite: `${name}.sqlite`,\n    mssql: `mssql://root:password@localhost:1433/${name}`,\n    other: ''\n  }\n\n  return connectionStrings[type]\n}\n\nexport const prompts = ({ database, connectionString, pkg, name }: ConnectionGeneratorArguments) => [\n  {\n    name: 'database',\n    type: 'list',\n    when: !database,\n    message: 'Which database are you connecting to?',\n    suffix: chalk.grey(' Databases can be added at any time'),\n    choices: [\n      { value: 'sqlite', name: 'SQLite' },\n      { value: 'mongodb', name: 'MongoDB' },\n      { value: 'postgresql', name: 'PostgreSQL' },\n      { value: 'mysql', name: 'MySQL/MariaDB' },\n      { value: 'mssql', name: 'Microsoft SQL' },\n      {\n        value: 'other',\n        name: `Another database ${chalk.grey('(not configured automatically, use with custom services)')}`\n      }\n    ]\n  },\n  {\n    name: 'connectionString',\n    type: 'input',\n    when: (answers: ConnectionGeneratorContext) =>\n      !connectionString && database !== 'other' && answers.database !== 'other',\n    message: 'Enter your database connection string',\n    default: (answers: ConnectionGeneratorContext) =>\n      defaultConnectionString(answers.database, answers.name || name || pkg.name)\n  }\n]\n\nexport const DATABASE_CLIENTS = {\n  mongodb: 'mongodb',\n  sqlite: 'sqlite3',\n  postgresql: 'pg',\n  mysql: 'mysql',\n  mssql: 'mssql'\n}\n\nexport const getDatabaseClient = (database: DatabaseType) =>\n  database === 'other' ? null : DATABASE_CLIENTS[database]\n\nexport const generate = (ctx: ConnectionGeneratorArguments) =>\n  Promise.resolve(ctx)\n    .then(initializeBaseContext())\n    .then(checkPreconditions())\n    .then(prompt(prompts))\n    .then((ctx) => ctx as ConnectionGeneratorContext)\n    .then(\n      when<ConnectionGeneratorContext>(\n        (ctx) => ctx.database !== 'other',\n        runGenerator<ConnectionGeneratorContext>(\n          __dirname,\n          'templates',\n          ({ database }) => `${getDatabaseAdapter(database)}.tpl.js`\n        ),\n        mergeJSON<ConnectionGeneratorContext>(\n          ({ connectionString, database }) =>\n            getDatabaseAdapter(database) === 'knex'\n              ? {\n                  [database]: {\n                    client: getDatabaseClient(database),\n                    connection: connectionString,\n                    ...(database === 'sqlite' ? { useNullAsDefault: true } : {})\n                  }\n                }\n              : {\n                  [database]: connectionString\n                },\n          toFile('config', 'default.json')\n        ),\n        async (ctx: ConnectionGeneratorContext) => {\n          const dependencies: string[] = []\n          const adapter = getDatabaseAdapter(ctx.database)\n          const dbClient = getDatabaseClient(ctx.database)\n\n          dependencies.push(`@feathersjs/${adapter}`)\n\n          if (adapter === 'knex') {\n            dependencies.push('knex')\n          }\n\n          dependencies.push(dbClient)\n\n          if (ctx.dependencies) {\n            return {\n              ...ctx,\n              dependencies: [...ctx.dependencies, ...dependencies]\n            }\n          }\n\n          return install<ConnectionGeneratorContext>(\n            addVersions(dependencies, ctx.dependencyVersions),\n            false,\n            ctx.feathers.packager\n          )(ctx)\n        }\n      )\n    )\n"
  },
  {
    "path": "packages/generators/src/connection/templates/knex.tpl.ts",
    "content": "import { toFile, before, mergeJSON } from '@featherscloud/pinion'\nimport { ConnectionGeneratorContext } from '../index.js'\nimport { injectSource, renderSource } from '../../commons.js'\nimport { mkdir } from 'fs/promises'\nimport path from 'path'\n\nconst template = ({\n  database\n}: ConnectionGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/databases.html\nimport knex from 'knex'\nimport type { Knex } from 'knex'\nimport type { Application } from './declarations'\n\ndeclare module './declarations' {\n  interface Configuration {\n    ${database}Client: Knex\n  }\n}\n\nexport const ${database} = (app: Application) => {\n  const config = app.get('${database}')\n  const db = knex(config!)\n\n  app.set('${database}Client', db)\n}\n`\n\nconst knexfile = ({\n  lib,\n  language,\n  database\n}: ConnectionGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/databases.html\nimport { app } from './${lib}/app'\n\n// Load our database connection info from the app configuration\nconst config = app.get('${database}')\n\n${language === 'js' ? 'export default config' : 'module.exports = config'}\n`\n\nconst importTemplate = ({ database }: ConnectionGeneratorContext) =>\n  `import { ${database} } from './${database}'`\nconst configureTemplate = ({ database }: ConnectionGeneratorContext) => `app.configure(${database})`\n\nconst toAppFile = toFile<ConnectionGeneratorContext>(({ lib }) => [lib, 'app'])\n\nexport const generate = (ctx: ConnectionGeneratorContext) =>\n  Promise.resolve(ctx)\n    .then(\n      renderSource(\n        template,\n        toFile<ConnectionGeneratorContext>(({ lib, database }) => [lib, database])\n      )\n    )\n    .then(renderSource(knexfile, toFile('knexfile')))\n    .then(\n      mergeJSON<ConnectionGeneratorContext>(\n        (ctx) => ({\n          scripts: {\n            migrate: 'knex migrate:latest',\n            'migrate:make': 'knex migrate:make' + (ctx.language === 'js' ? ' -x mjs' : ''),\n            test: 'cross-env NODE_ENV=test npm run migrate && npm run mocha'\n          }\n        }),\n        toFile('package.json')\n      )\n    )\n    .then(injectSource(importTemplate, before('import { services } from'), toAppFile))\n    .then(injectSource(configureTemplate, before('app.configure(services)'), toAppFile))\n    .then(async (ctx) => {\n      await mkdir(path.join(ctx.cwd, 'migrations'))\n      return ctx\n    })\n"
  },
  {
    "path": "packages/generators/src/connection/templates/mongodb.tpl.ts",
    "content": "import { toFile, before, prepend, append } from '@featherscloud/pinion'\nimport { ConnectionGeneratorContext } from '../index.js'\nimport { injectSource, renderSource } from '../../commons.js'\n\nconst template = ({\n  database\n}: ConnectionGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/databases.html\nimport { MongoClient } from 'mongodb'\nimport type { Db } from 'mongodb'\nimport type { Application } from './declarations'\n\ndeclare module './declarations' {\n  interface Configuration {\n    ${database}Client: Promise<Db>\n  }\n}\n\nexport const ${database} = (app: Application) => {\n  const connection = app.get('${database}') as string\n  const database = new URL(connection).pathname.substring(1)\n  const mongoClient = MongoClient.connect(connection)\n    .then(client => client.db(database))\n\n  app.set('${database}Client', mongoClient)\n}\n`\n\nconst keywordImport = `import { keywordObjectId } from '@feathersjs/mongodb'`\n\nconst keywordTemplate = `dataValidator.addKeyword(keywordObjectId)\nqueryValidator.addKeyword(keywordObjectId)`\n\nconst importTemplate = ({ database }: ConnectionGeneratorContext) =>\n  `import { ${database} } from './${database}'`\nconst configureTemplate = ({ database }: ConnectionGeneratorContext) => `app.configure(${database})`\nconst toAppFile = toFile<ConnectionGeneratorContext>(({ lib }) => [lib, 'app'])\nconst toValidatorFile = toFile<ConnectionGeneratorContext>(({ lib }) => [lib, 'validators'])\n\nexport const generate = (ctx: ConnectionGeneratorContext) =>\n  Promise.resolve(ctx)\n    .then(\n      renderSource(\n        template,\n        toFile<ConnectionGeneratorContext>(({ lib, database }) => [lib, database])\n      )\n    )\n    .then(injectSource(importTemplate, before('import { services } from'), toAppFile))\n    .then(injectSource(configureTemplate, before('app.configure(services)'), toAppFile))\n    .then(injectSource(keywordImport, prepend(), toValidatorFile))\n    .then(injectSource(keywordTemplate, append(), toValidatorFile))\n"
  },
  {
    "path": "packages/generators/src/hook/index.ts",
    "content": "import { dirname } from 'path'\nimport { fileURLToPath } from 'url'\nimport { prompt, runGenerators } from '@featherscloud/pinion'\nimport _ from 'lodash'\nimport { checkPreconditions, FeathersBaseContext, initializeBaseContext } from '../commons.js'\n\n// Set __dirname in es module\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nexport interface HookGeneratorContext extends FeathersBaseContext {\n  name: string\n  camelName: string\n  kebabName: string\n  type: 'regular' | 'around'\n}\n\nexport const generate = (ctx: HookGeneratorContext) =>\n  Promise.resolve(ctx)\n    .then(initializeBaseContext())\n    .then(checkPreconditions())\n    .then(\n      prompt<HookGeneratorContext>(({ type, name }) => [\n        {\n          type: 'input',\n          name: 'name',\n          message: 'What is the name of the hook?',\n          when: !name\n        },\n        {\n          name: 'type',\n          type: 'list',\n          when: !type,\n          message: 'What kind of hook is it?',\n          choices: [\n            { value: 'around', name: 'Around' },\n            { value: 'regular', name: 'Before, After or Error' }\n          ]\n        }\n      ])\n    )\n    .then((ctx) => {\n      const { name } = ctx\n      const kebabName = _.kebabCase(name)\n      const camelName = _.camelCase(name)\n\n      return {\n        ...ctx,\n        kebabName,\n        camelName\n      }\n    })\n    .then(runGenerators(__dirname, 'templates'))\n"
  },
  {
    "path": "packages/generators/src/hook/templates/hook.tpl.ts",
    "content": "import { toFile } from '@featherscloud/pinion'\nimport { HookGeneratorContext } from '../index.js'\nimport { renderSource } from '../../commons.js'\n\nconst aroundTemplate = ({\n  camelName,\n  name\n}: HookGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/hook.html\nimport type { HookContext, NextFunction } from '../declarations'\n\nexport const ${camelName} = async (context: HookContext, next: NextFunction) => {\n  console.log(\\`Running hook ${name} on \\${context.path}\\.\\${context.method}\\`)\n  await next()\n}\n`\n\nconst regularTemplate = ({\n  camelName,\n  name\n}: HookGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/hook.html\nimport type { HookContext } from '../declarations'\n\nexport const ${camelName} = async (context: HookContext) => {\n  console.log(\\`Running hook ${name} on \\${context.path}\\.\\${context.method}\\`)\n}`\n\nexport const generate = (ctx: HookGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    renderSource(\n      (ctx) => (ctx.type === 'around' ? aroundTemplate(ctx) : regularTemplate(ctx)),\n      toFile<HookGeneratorContext>(({ lib, kebabName }) => [lib, 'hooks', kebabName])\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/index.ts",
    "content": "export * from '@featherscloud/pinion'\n\nexport * from './commons.js'\nexport * as app from './app/index.js'\nexport * as authentication from './authentication/index.js'\nexport * as connection from './connection/index.js'\nexport * as hook from './hook/index.js'\nexport * as service from './service/index.js'\n"
  },
  {
    "path": "packages/generators/src/service/index.ts",
    "content": "import { dirname } from 'path'\nimport _ from 'lodash'\nimport { runGenerator, runGenerators, prompt } from '@featherscloud/pinion'\nimport { fileURLToPath } from 'url'\nimport chalk from 'chalk'\n\nimport {\n  checkPreconditions,\n  DATABASE_TYPES,\n  FeathersBaseContext,\n  fileExists,\n  getDatabaseAdapter,\n  initializeBaseContext\n} from '../commons.js'\n\n// Set __dirname in es module\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nexport interface ServiceGeneratorContext extends FeathersBaseContext {\n  /**\n   * The chosen service name\n   */\n  name: string\n  /**\n   * The path the service is registered on\n   */\n  path: string\n  /**\n   * The list of subfolders this service is in\n   */\n  folder: string[]\n  /**\n   * The `camelCase` service name starting with a lowercase letter\n   */\n  camelName: string\n  /**\n   * The `CamelCase` service name starting with an uppercase letter\n   */\n  upperName: string\n  /**\n   * The service class name combined as `CamelCaseService`\n   */\n  className: string\n  /**\n   * A kebab-cased (filename friendly) version of the service name\n   */\n  kebabName: string\n  /**\n   * The actual filename (the last element of the path)\n   */\n  fileName: string\n  /**\n   * The kebab-cased name of the path. Will be used for e.g. database names\n   */\n  kebabPath: string\n  /**\n   * Indicates how many file paths we should go up to import other things (e.g. `../../`)\n   */\n  relative: string\n  /**\n   * The chosen service type\n   */\n  type: 'knex' | 'mongodb' | 'custom'\n  /**\n   * Which schema definition format to use\n   */\n  schema: 'typebox' | 'json' | false\n  /**\n   * Wether this service uses authentication\n   */\n  authentication: boolean\n  /**\n   * Set to true if this service is for an authentication entity\n   */\n  isEntityService?: boolean\n  /**\n   * The authentication strategies (if it is an entity service)\n   */\n  authStrategies: string[]\n}\n\n/**\n * Parameters the generator is called with\n */\nexport type ServiceGeneratorArguments = FeathersBaseContext &\n  Partial<\n    Pick<ServiceGeneratorContext, 'name' | 'path' | 'type' | 'authentication' | 'isEntityService' | 'schema'>\n  >\n\nexport const generate = (ctx: ServiceGeneratorArguments) =>\n  Promise.resolve(ctx)\n    .then(initializeBaseContext())\n    .then(checkPreconditions())\n    .then(\n      prompt(({ name, path, type, schema, authentication, isEntityService, feathers, lib, language }) => {\n        const sqlDisabled = DATABASE_TYPES.every(\n          (name) => name === 'mongodb' || name === 'other' || !fileExists(lib, `${name}.${language}`)\n        )\n        const mongodbDisabled = !fileExists(lib, `mongodb.${language}`)\n\n        return [\n          {\n            name: 'name',\n            type: 'input',\n            when: !name,\n            message: 'What is the name of your service?',\n            validate: (input: any) => {\n              if (!input || input === 'authentication') {\n                return 'Invalid service name'\n              }\n\n              return true\n            }\n          },\n          {\n            name: 'path',\n            type: 'input',\n            when: !path,\n            message: 'Which path should the service be registered on?',\n            default: (answers: ServiceGeneratorArguments) => `${_.kebabCase(answers.name)}`,\n            validate: (input: any) => {\n              if (!input || input === 'authentication') {\n                return 'Invalid service path'\n              }\n\n              return true\n            }\n          },\n          {\n            name: 'authentication',\n            type: 'confirm',\n            when: authentication === undefined && !isEntityService,\n            message: 'Does this service require authentication?'\n          },\n          {\n            name: 'type',\n            type: 'list',\n            when: !type,\n            message: 'What database is the service using?',\n            default: getDatabaseAdapter(feathers?.database),\n            choices: [\n              {\n                value: 'knex',\n                name: `SQL${sqlDisabled ? chalk.gray(' (connection not available)') : ''}`,\n                disabled: sqlDisabled\n              },\n              {\n                value: 'mongodb',\n                name: `MongoDB${mongodbDisabled ? chalk.gray(' (connection not available)') : ''}`,\n                disabled: mongodbDisabled\n              },\n              {\n                value: 'custom',\n                name: 'A custom service'\n              }\n            ]\n          },\n          {\n            name: 'schema',\n            type: 'list',\n            when: schema === undefined,\n            message: 'Which schema definition format do you want to use?',\n            suffix: chalk.grey(' Schemas allow to type, validate, secure and populate data'),\n            default: feathers?.schema,\n            choices: (answers: ServiceGeneratorContext) => [\n              {\n                value: 'typebox',\n                name: `TypeBox ${chalk.gray(' (recommended)')}`\n              },\n              {\n                value: 'json',\n                name: 'JSON schema'\n              },\n              {\n                value: false,\n                name: `No schema${\n                  answers.type !== 'custom' ? chalk.gray(' (not recommended with a database)') : ''\n                }`\n              }\n            ]\n          }\n        ]\n      })\n    )\n    .then(async (ctx): Promise<ServiceGeneratorContext> => {\n      const { name, path, type, authStrategies = [] } = ctx as any as ServiceGeneratorContext\n      const kebabName = _.kebabCase(name)\n      const camelName = _.camelCase(name)\n      const upperName = _.upperFirst(camelName)\n      const className = `${upperName}Service`\n\n      const folder = path.split('/').filter((el) => el !== '')\n      const relative = ['', ...folder].map(() => '..').join('/')\n      const fileName = _.last(folder)\n      const kebabPath = _.kebabCase(path)\n\n      return {\n        name,\n        type,\n        path,\n        folder,\n        fileName,\n        upperName,\n        className,\n        kebabName,\n        camelName,\n        kebabPath,\n        relative,\n        authStrategies,\n        ...ctx\n      } as ServiceGeneratorContext\n    })\n    .then(runGenerators<ServiceGeneratorContext>(__dirname, 'templates'))\n    .then(runGenerator<ServiceGeneratorContext>(__dirname, 'type', ({ type }) => `${type}.tpl.js`))\n"
  },
  {
    "path": "packages/generators/src/service/templates/client.tpl.ts",
    "content": "import { toFile, after, before, when } from '@featherscloud/pinion'\nimport { fileExists, injectSource } from '../../commons.js'\nimport { ServiceGeneratorContext } from '../index.js'\n\nconst importTemplate = ({ upperName, folder, fileName, camelName }: ServiceGeneratorContext) => /* ts */ `\nimport { ${camelName}Client } from './services/${folder.join('/')}/${fileName}.shared'\nexport type {\n  ${upperName},\n  ${upperName}Data,\n  ${upperName}Query,\n  ${upperName}Patch\n} from './services/${folder.join('/')}/${fileName}.shared'\n`\n\nconst registrationTemplate = ({ camelName }: ServiceGeneratorContext) =>\n  `  client.configure(${camelName}Client)`\n\nconst toClientFile = toFile<ServiceGeneratorContext>(({ lib }) => [lib, 'client'])\n\nexport const generate = async (ctx: ServiceGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    when<ServiceGeneratorContext>(\n      ({ lib, language }) => fileExists(lib, `client.${language}`),\n      injectSource(registrationTemplate, before('return client'), toClientFile),\n      injectSource(\n        importTemplate,\n        after<ServiceGeneratorContext>(({ language }) =>\n          language === 'ts' ? 'import type { AuthenticationClientOptions }' : 'import authenticationClient'\n        ),\n        toClientFile\n      )\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/service/templates/schema.json.tpl.ts",
    "content": "import { toFile, when } from '@featherscloud/pinion'\nimport { fileExists, localTemplate, renderSource } from '../../commons.js'\nimport { ServiceGeneratorContext } from '../index.js'\n\nconst authFieldsTemplate = (authStrategies: string[]) =>\n  authStrategies\n    .map((name) =>\n      name === 'local'\n        ? `    email: { type: 'string' },\n    password: { type: 'string' }`\n        : `    ${name}Id: { type: 'string' }`\n    )\n    .join(',\\n')\n\nconst template = ({\n  camelName,\n  upperName,\n  fileName,\n  relative,\n  authStrategies,\n  isEntityService,\n  type,\n  cwd,\n  lib\n}: ServiceGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/service.schemas.html\nimport { resolve, getValidator, querySyntax } from '@feathersjs/schema'${\n  type === 'mongodb'\n    ? `\nimport { ObjectIdSchema } from '@feathersjs/schema'`\n    : ''\n}\nimport type { FromSchema } from '@feathersjs/schema'\n${localTemplate(authStrategies, `import { passwordHash } from '@feathersjs/authentication-local'`)}\n\nimport type { HookContext } from '${relative}/declarations'\nimport { dataValidator, queryValidator } from '${relative}/${\n  fileExists(cwd, lib, 'schemas') ? 'schemas/' : '' // This is for legacy backwards compatibility\n}validators'\nimport type { ${upperName}Service } from './${fileName}.class'\n\n// Main data model schema\nexport const ${camelName}Schema = {\n  $id: '${upperName}',\n  type: 'object',\n  additionalProperties: false,\n  required: [ '${type === 'mongodb' ? '_id' : 'id'}', ${localTemplate(authStrategies, `'email'`, `'text'`)} ],\n  properties: {\n    ${type === 'mongodb' ? `_id: ObjectIdSchema(),` : `id: { type: 'number' },`}\n    ${\n      isEntityService\n        ? authFieldsTemplate(authStrategies)\n        : `\n    text: { type: 'string' }`\n    }\n  }\n} as const\nexport type ${upperName} = FromSchema<typeof ${camelName}Schema>\nexport const ${camelName}Validator = getValidator(${camelName}Schema, dataValidator)\nexport const ${camelName}Resolver = resolve<${upperName}, HookContext<${upperName}Service>>({})\n\nexport const ${camelName}ExternalResolver = resolve<${upperName}, HookContext<${upperName}Service>>({\n  ${localTemplate(\n    authStrategies,\n    `// The password should never be visible externally\n  password: async () => undefined`\n  )}\n})\n\n// Schema for creating new data\nexport const ${camelName}DataSchema = {\n  $id: '${upperName}Data',\n  type: 'object',\n  additionalProperties: false,\n  required: [ ${localTemplate(authStrategies, `'email'`, `'text'`)} ],\n  properties: {\n    ...${camelName}Schema.properties\n  }\n} as const\nexport type ${upperName}Data = FromSchema<typeof ${camelName}DataSchema>\nexport const ${camelName}DataValidator = getValidator(${camelName}DataSchema, dataValidator)\nexport const ${camelName}DataResolver = resolve<${upperName}Data, HookContext<${upperName}Service>>({\n  ${localTemplate(authStrategies, `password: passwordHash({ strategy: 'local' })`)}\n})\n\n// Schema for updating existing data\nexport const ${camelName}PatchSchema = {\n  $id: '${upperName}Patch',\n  type: 'object',\n  additionalProperties: false,\n  required: [],\n  properties: {\n    ...${camelName}Schema.properties\n  }\n} as const\nexport type ${upperName}Patch = FromSchema<typeof ${camelName}PatchSchema>\nexport const ${camelName}PatchValidator = getValidator(${camelName}PatchSchema, dataValidator)\nexport const ${camelName}PatchResolver = resolve<${upperName}Patch, HookContext<${upperName}Service>>({\n  ${localTemplate(authStrategies, `password: passwordHash({ strategy: 'local' })`)}\n})\n\n// Schema for allowed query properties\nexport const ${camelName}QuerySchema = {\n  $id: '${upperName}Query',\n  type: 'object',\n  additionalProperties: false,\n  properties: {\n    ...querySyntax(${camelName}Schema.properties)\n  }\n} as const\nexport type ${upperName}Query = FromSchema<typeof ${camelName}QuerySchema>\nexport const ${camelName}QueryValidator = getValidator(${camelName}QuerySchema, queryValidator)\nexport const ${camelName}QueryResolver = resolve<${upperName}Query, HookContext<${upperName}Service>>({\n  ${\n    isEntityService\n      ? `\n  // If there is a user (e.g. with authentication), they are only allowed to see their own data\n  ${type === 'mongodb' ? '_id' : 'id'}: async (value, user, context) => {\n    if (context.params.user) {\n      return context.params.user.${type === 'mongodb' ? '_id' : 'id'}\n    }\n\n    return value\n  }`\n      : ''\n  }\n})\n`\n\nexport const generate = (ctx: ServiceGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    when<ServiceGeneratorContext>(\n      ({ schema }) => schema === 'json',\n      renderSource(\n        template,\n        toFile(({ lib, folder, fileName }: ServiceGeneratorContext) => [\n          lib,\n          'services',\n          ...folder,\n          `${fileName}.schema`\n        ])\n      )\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/service/templates/schema.typebox.tpl.ts",
    "content": "import { toFile, when } from '@featherscloud/pinion'\nimport { fileExists, localTemplate, renderSource } from '../../commons.js'\nimport { ServiceGeneratorContext } from '../index.js'\n\nconst authFieldsTemplate = (authStrategies: string[]) =>\n  authStrategies\n    .map((name) =>\n      name === 'local'\n        ? `  email: Type.String(),\n  password: Type.Optional(Type.String())`\n        : `  ${name}Id: Type.Optional(Type.String())`\n    )\n    .join(',\\n')\n\nconst template = ({\n  camelName,\n  upperName,\n  fileName,\n  relative,\n  authStrategies,\n  isEntityService,\n  type,\n  cwd,\n  lib\n}: ServiceGeneratorContext) => /* ts */ `// // For more information about this file see https://dove.feathersjs.com/guides/cli/service.schemas.html\nimport { resolve } from '@feathersjs/schema'\nimport { Type, getValidator, querySyntax } from '@feathersjs/typebox'${\n  type === 'mongodb'\n    ? `\nimport { ObjectIdSchema } from '@feathersjs/typebox'`\n    : ''\n}\nimport type { Static } from '@feathersjs/typebox'\n${localTemplate(authStrategies, `import { passwordHash } from '@feathersjs/authentication-local'`)}\n\nimport type { HookContext } from '${relative}/declarations'\nimport { dataValidator, queryValidator } from '${relative}/${\n  fileExists(cwd, lib, 'schemas') ? 'schemas/' : '' // This is for legacy backwards compatibility\n}validators'\nimport type { ${upperName}Service } from './${fileName}.class'\n\n// Main data model schema\nexport const ${camelName}Schema = Type.Object({\n    ${type === 'mongodb' ? '_id: ObjectIdSchema()' : 'id: Type.Number()'},\n    ${isEntityService ? authFieldsTemplate(authStrategies) : `text: Type.String()`}\n  }, { $id: '${upperName}', additionalProperties: false })\nexport type ${upperName} = Static<typeof ${camelName}Schema>\nexport const ${camelName}Validator = getValidator(${camelName}Schema, dataValidator)\nexport const ${camelName}Resolver = resolve<${upperName}Query, HookContext<${upperName}Service>>({})\n\nexport const ${camelName}ExternalResolver = resolve<${upperName}, HookContext<${upperName}Service>>({\n  ${localTemplate(\n    authStrategies,\n    `// The password should never be visible externally\n  password: async () => undefined`\n  )}  \n})\n\n// Schema for creating new entries\nexport const ${camelName}DataSchema = Type.Pick(${camelName}Schema, [\n  ${\n    isEntityService\n      ? authStrategies.map((name) => (name === 'local' ? `'email', 'password'` : `'${name}Id'`)).join(', ')\n      : `'text'`\n  }\n], {\n  $id: '${upperName}Data'\n})\nexport type ${upperName}Data = Static<typeof ${camelName}DataSchema>\nexport const ${camelName}DataValidator = getValidator(${camelName}DataSchema, dataValidator)\nexport const ${camelName}DataResolver = resolve<${upperName}Data, HookContext<${upperName}Service>>({\n  ${localTemplate(authStrategies, `password: passwordHash({ strategy: 'local' })`)}\n})\n\n// Schema for updating existing entries\nexport const ${camelName}PatchSchema = Type.Partial(${camelName}Schema, {\n  $id: '${upperName}Patch'\n})\nexport type ${upperName}Patch = Static<typeof ${camelName}PatchSchema>\nexport const ${camelName}PatchValidator = getValidator(${camelName}PatchSchema, dataValidator)\nexport const ${camelName}PatchResolver = resolve<${upperName}Patch, HookContext<${upperName}Service>>({\n  ${localTemplate(authStrategies, `password: passwordHash({ strategy: 'local' })`)}\n})\n\n// Schema for allowed query properties\nexport const ${camelName}QueryProperties = Type.Pick(${camelName}Schema, [\n  '${type === 'mongodb' ? '_id' : 'id'}', ${\n    isEntityService\n      ? authStrategies.map((name) => (name === 'local' ? `'email'` : `'${name}Id'`)).join(', ')\n      : `'text'`\n  }\n])\nexport const ${camelName}QuerySchema = Type.Intersect([\n  querySyntax(${camelName}QueryProperties),\n  // Add additional query properties here\n  Type.Object({}, { additionalProperties: false })\n], { additionalProperties: false })\nexport type ${upperName}Query = Static<typeof ${camelName}QuerySchema>\nexport const ${camelName}QueryValidator = getValidator(${camelName}QuerySchema, queryValidator)\nexport const ${camelName}QueryResolver = resolve<${upperName}Query, HookContext<${upperName}Service>>({\n  ${\n    isEntityService\n      ? `\n  // If there is a user (e.g. with authentication), they are only allowed to see their own data\n  ${type === 'mongodb' ? '_id' : 'id'}: async (value, user, context) => {\n    if (context.params.user) {\n      return context.params.user.${type === 'mongodb' ? '_id' : 'id'}\n    }\n\n    return value\n  }`\n      : ''\n  }\n})\n`\n\nexport const generate = (ctx: ServiceGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    when<ServiceGeneratorContext>(\n      ({ schema }) => schema === 'typebox',\n      renderSource(\n        template,\n        toFile(({ lib, folder, fileName }: ServiceGeneratorContext) => [\n          lib,\n          'services',\n          ...folder,\n          `${fileName}.schema`\n        ])\n      )\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/service/templates/service.tpl.ts",
    "content": "import { toFile, after, prepend } from '@featherscloud/pinion'\nimport { fileExists, injectSource, renderSource } from '../../commons.js'\nimport { ServiceGeneratorContext } from '../index.js'\n\nexport const template = ({\n  camelName,\n  authentication,\n  isEntityService,\n  path,\n  lib,\n  language,\n  className,\n  relative,\n  schema,\n  fileName\n}: ServiceGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/service.html\n${authentication || isEntityService ? `import { authenticate } from '@feathersjs/authentication'` : ''}\n${\n  schema\n    ? `\nimport { hooks as schemaHooks } from '@feathersjs/schema'\n    \nimport {\n  ${camelName}DataValidator,\n  ${camelName}PatchValidator,\n  ${camelName}QueryValidator,\n  ${camelName}Resolver,\n  ${camelName}ExternalResolver,\n  ${camelName}DataResolver,\n  ${camelName}PatchResolver,\n  ${camelName}QueryResolver\n} from './${fileName}.schema'\n`\n    : ''\n}\n\nimport type { Application } from '${relative}/declarations'\nimport { ${className}, getOptions } from './${fileName}.class'\n${\n  fileExists(lib, `client.${language}`)\n    ? `import { ${camelName}Path, ${camelName}Methods } from './${fileName}.shared'`\n    : `\nexport const ${camelName}Path = '${path}'\nexport const ${camelName}Methods: Array<keyof ${className}> = ['find', 'get', 'create', 'patch', 'remove']`\n}\n\nexport * from './${fileName}.class'\n${schema ? `export * from './${fileName}.schema'` : ''}\n\n// A configure function that registers the service and its hooks via \\`app.configure\\`\nexport const ${camelName} = (app: Application) => {\n  // Register our service on the Feathers application\n  app.use(${camelName}Path, new ${className}(getOptions(app)), {\n    // A list of all methods this service exposes externally\n    methods: ${camelName}Methods,\n    // You can add additional custom events to be sent to clients here\n    events: []\n  })\n  // Initialize hooks\n  app.service(${camelName}Path).hooks({\n    around: {\n      all: [${\n        authentication\n          ? `\n        authenticate('jwt'),`\n          : ''\n      } ${\n        schema\n          ? `\n        schemaHooks.resolveExternal(${camelName}ExternalResolver),\n        schemaHooks.resolveResult(${camelName}Resolver),`\n          : ''\n      }\n      ],${\n        isEntityService\n          ? `\n      find: [authenticate('jwt')],\n      get: [authenticate('jwt')],\n      create: [],\n      update: [authenticate('jwt')],\n      patch: [authenticate('jwt')],\n      remove: [authenticate('jwt')]`\n          : ''\n      }\n    },\n    before: {\n      all: [${\n        schema\n          ? `\n        schemaHooks.validateQuery(${camelName}QueryValidator),\n        schemaHooks.resolveQuery(${camelName}QueryResolver)\n      `\n          : ''\n      }],\n      find: [],\n      get: [],\n      create: [${\n        schema\n          ? `\n        schemaHooks.validateData(${camelName}DataValidator),\n        schemaHooks.resolveData(${camelName}DataResolver)\n      `\n          : ''\n      }],\n      patch: [${\n        schema\n          ? `\n        schemaHooks.validateData(${camelName}PatchValidator),\n        schemaHooks.resolveData(${camelName}PatchResolver)\n      `\n          : ''\n      }],\n      remove: []\n    },\n    after: {\n      all: []\n    },\n    error: {\n      all: []\n    }\n  })\n}\n\n// Add this service to the service type index\ndeclare module '${relative}/declarations' {\n  interface ServiceTypes {\n    [${camelName}Path]: ${className}\n  }\n}\n`\n\nconst toServiceIndex = toFile(({ lib }: ServiceGeneratorContext) => [lib, 'services', `index`])\n\nexport const generate = (ctx: ServiceGeneratorContext) =>\n  Promise.resolve(ctx)\n    .then(\n      renderSource(\n        template,\n        toFile(({ lib, fileName, folder }: ServiceGeneratorContext) => [\n          lib,\n          'services',\n          ...folder,\n          `${fileName}`\n        ])\n      )\n    )\n    .then(\n      injectSource<ServiceGeneratorContext>(\n        ({ camelName, folder, fileName }) =>\n          `import { ${camelName} } from './${folder.join('/')}/${fileName}'`,\n        prepend(),\n        toServiceIndex\n      )\n    )\n    .then(\n      injectSource<ServiceGeneratorContext>(\n        ({ camelName }) => `  app.configure(${camelName})`,\n        after('export const services'),\n        toServiceIndex\n      )\n    )\n"
  },
  {
    "path": "packages/generators/src/service/templates/shared.tpl.ts",
    "content": "import { toFile, when } from '@featherscloud/pinion'\nimport { fileExists, renderSource } from '../../commons.js'\nimport { ServiceGeneratorContext } from '../index.js'\n\nconst sharedTemplate = ({\n  camelName,\n  upperName,\n  className,\n  fileName,\n  relative,\n  path\n}: ServiceGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/service.shared.html\nimport type { Params } from '@feathersjs/feathers'\nimport type { ClientApplication } from '${relative}/client'\nimport type {\n  ${upperName},\n  ${upperName}Data,\n  ${upperName}Patch,\n  ${upperName}Query,\n  ${className}\n} from './${fileName}.class'\n\nexport type { ${upperName}, ${upperName}Data, ${upperName}Patch, ${upperName}Query }\n\nexport type ${upperName}ClientService = Pick<\n  ${className}<Params<${upperName}Query>>,\n  typeof ${camelName}Methods[number]\n>\n\nexport const ${camelName}Path = '${path}'\n\nexport const ${camelName}Methods: Array<keyof ${className}> = ['find', 'get', 'create', 'patch', 'remove']\n\nexport const ${camelName}Client = (client: ClientApplication) => {\n  const connection = client.get('connection')\n\n  client.use(${camelName}Path, connection.service(${camelName}Path), {\n    methods: ${camelName}Methods\n  })\n}\n\n// Add this service to the client service type index\ndeclare module '${relative}/client' {\n  interface ServiceTypes {\n    [${camelName}Path]: ${upperName}ClientService\n  }\n}\n`\n\nexport const generate = async (ctx: ServiceGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    when<ServiceGeneratorContext>(\n      ({ lib, language }) => fileExists(lib, `client.${language}`),\n      renderSource(\n        sharedTemplate,\n        toFile(({ lib, folder, fileName }: ServiceGeneratorContext) => [\n          lib,\n          'services',\n          ...folder,\n          `${fileName}.shared`\n        ])\n      )\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/service/templates/test.tpl.ts",
    "content": "import { toFile } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { ServiceGeneratorContext } from '../index.js'\n\nconst template = ({\n  relative,\n  lib,\n  path\n}: ServiceGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/service.test.html\nimport assert from 'assert'\nimport { app } from '../${relative}/${lib}/app'\n\ndescribe('${path} service', () => {\n  it('registered the service', () => {\n    const service = app.service('${path}')\n\n    assert.ok(service, 'Registered the service')\n  })\n})\n`\n\nexport const generate = (ctx: ServiceGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    renderSource(\n      template,\n      toFile<ServiceGeneratorContext>(({ test, folder, fileName }) => [\n        test,\n        'services',\n        ...folder,\n        `${fileName}.test`\n      ])\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/service/type/custom.tpl.ts",
    "content": "import { toFile } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { ServiceGeneratorContext } from '../index.js'\n\nexport const template = ({\n  className,\n  upperName,\n  schema,\n  fileName,\n  relative\n}: ServiceGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/service.class.html#custom-services\nimport type { Id, NullableId, Params, ServiceInterface } from '@feathersjs/feathers'\n\nimport type { Application } from '${relative}/declarations'\n${\n  schema\n    ? `import type {\n  ${upperName},\n  ${upperName}Data,\n  ${upperName}Patch,\n  ${upperName}Query\n} from './${fileName}.schema'\n`\n    : `\ntype ${upperName} = any\ntype ${upperName}Data = any\ntype ${upperName}Patch = any\ntype ${upperName}Query = any\n`\n}\n\nexport type { ${upperName}, ${upperName}Data, ${upperName}Patch, ${upperName}Query }\n\nexport interface ${className}Options {\n  app: Application\n}\n\nexport interface ${upperName}Params extends Params<${upperName}Query> {\n\n}\n\n// This is a skeleton for a custom service class. Remove or add the methods you need here\nexport class ${className}<ServiceParams extends ${upperName}Params = ${upperName}Params>\n    implements ServiceInterface<${upperName}, ${upperName}Data, ServiceParams, ${upperName}Patch> {\n  constructor (public options: ${className}Options) {\n  }\n\n  async find (_params?: ServiceParams): Promise<${upperName}[]> {\n    return []\n  }\n\n  async get (id: Id, _params?: ServiceParams): Promise<${upperName}> {\n    return {\n      id: 0,\n      text: \\`A new message with ID: \\${id}!\\`\n    }\n  }\n\n  async create (data: ${upperName}Data, params?: ServiceParams): Promise<${upperName}>\n  async create (data: ${upperName}Data[], params?: ServiceParams): Promise<${upperName}[]>\n  async create (data: ${upperName}Data|${upperName}Data[], params?: ServiceParams): Promise<${upperName}|${upperName}[]> {\n    if (Array.isArray(data)) {\n      return Promise.all(data.map(current => this.create(current, params)));\n    }\n\n    return {\n      id: 0,\n      ...data\n    }\n  }\n\n  // This method has to be added to the 'methods' option to make it available to clients\n  async update (id: NullableId, data: ${upperName}Data, _params?: ServiceParams): Promise<${upperName}> {\n    return {\n      id: 0,\n      ...data\n    }\n  }\n\n  async patch (id: NullableId, data: ${upperName}Patch, _params?: ServiceParams): Promise<${upperName}> {\n    return {\n      id: 0,\n      text: \\`Fallback for \\${id}\\`,\n      ...data\n    }\n  }\n\n  async remove (id: NullableId, _params?: ServiceParams): Promise<${upperName}> {\n    return {\n      id: 0,\n      text: 'removed'\n    }\n  }\n}\n\nexport const getOptions = (app: Application) => {\n  return { app }\n}\n`\n\nexport const generate = (ctx: ServiceGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    renderSource(\n      template,\n      toFile<ServiceGeneratorContext>(({ lib, folder, fileName }) => [\n        lib,\n        'services',\n        ...folder,\n        `${fileName}.class`\n      ])\n    )\n  )\n"
  },
  {
    "path": "packages/generators/src/service/type/knex.tpl.ts",
    "content": "import { toFile } from '@featherscloud/pinion'\nimport { renderSource, yyyymmddhhmmss } from '../../commons.js'\nimport { ServiceGeneratorContext } from '../index.js'\n\nconst migrationTemplate = ({\n  kebabPath,\n  authStrategies,\n  isEntityService\n}: ServiceGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/knexfile.html\nimport type { Knex } from 'knex'\n\nexport async function up(knex: Knex): Promise<void> {\n  await knex.schema.createTable('${kebabPath}', table => {\n    table.increments('id')\n    ${\n      isEntityService\n        ? authStrategies\n            .map((name) =>\n              name === 'local'\n                ? `    \n    table.string('email').unique()\n    table.string('password')`\n                : `    \n    table.string('${name}Id')`\n            )\n            .join('\\n')\n        : `\n    table.string('text')`\n    }\n  })\n}\n\nexport async function down(knex: Knex): Promise<void> {\n  await knex.schema.dropTable('${kebabPath}')\n}\n`\n\nexport const template = ({\n  className,\n  upperName,\n  feathers,\n  schema,\n  fileName,\n  relative\n}: ServiceGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/service.class.html#database-services\nimport type { Params } from '@feathersjs/feathers'\nimport { KnexService } from '@feathersjs/knex'\nimport type { KnexAdapterParams, KnexAdapterOptions } from '@feathersjs/knex'\n\nimport type { Application } from '${relative}/declarations'\n${\n  schema\n    ? `import type {\n  ${upperName},\n  ${upperName}Data,\n  ${upperName}Patch,\n  ${upperName}Query\n} from './${fileName}.schema'\n`\n    : `\ntype ${upperName} = any\ntype ${upperName}Data = any\ntype ${upperName}Patch = any\ntype ${upperName}Query = any\n`\n}\n\nexport type { ${upperName}, ${upperName}Data, ${upperName}Patch, ${upperName}Query }\n\nexport interface ${upperName}Params extends KnexAdapterParams<${upperName}Query> {\n}\n\n// By default calls the standard Knex adapter service methods but can be customized with your own functionality.\nexport class ${className}<ServiceParams extends Params = ${upperName}Params>\n  extends KnexService<${upperName}, ${upperName}Data, ${upperName}Params, ${upperName}Patch> {\n}\n\nexport const getOptions = (app: Application): KnexAdapterOptions => {\n  return {\n    paginate: app.get('paginate'),\n    Model: app.get('${feathers.database}Client'),\n    name: '${fileName}'\n  }\n}\n`\n\nexport const generate = (ctx: ServiceGeneratorContext) =>\n  Promise.resolve(ctx)\n    .then(\n      renderSource(\n        template,\n        toFile<ServiceGeneratorContext>(({ lib, folder, fileName }) => [\n          lib,\n          'services',\n          ...folder,\n          `${fileName}.class`\n        ])\n      )\n    )\n    .then(\n      renderSource(\n        migrationTemplate,\n        toFile<ServiceGeneratorContext>('migrations', ({ kebabName }) => `${yyyymmddhhmmss()}_${kebabName}`)\n      )\n    )\n"
  },
  {
    "path": "packages/generators/src/service/type/mongodb.tpl.ts",
    "content": "import { toFile } from '@featherscloud/pinion'\nimport { renderSource } from '../../commons.js'\nimport { ServiceGeneratorContext } from '../index.js'\n\nexport const template = ({\n  className,\n  upperName,\n  schema,\n  fileName,\n  kebabPath,\n  relative\n}: ServiceGeneratorContext) => /* ts */ `// For more information about this file see https://dove.feathersjs.com/guides/cli/service.class.html#database-services\nimport type { Params } from '@feathersjs/feathers'\nimport { MongoDBService } from \\'@feathersjs/mongodb\\'\nimport type { MongoDBAdapterParams, MongoDBAdapterOptions } from \\'@feathersjs/mongodb\\'\n\nimport type { Application } from '${relative}/declarations'\n${\n  schema\n    ? `import type {\n  ${upperName},\n  ${upperName}Data,\n  ${upperName}Patch,\n  ${upperName}Query\n} from './${fileName}.schema'\n`\n    : `\ntype ${upperName} = any\ntype ${upperName}Data = any\ntype ${upperName}Patch = any\ntype ${upperName}Query = any\n`\n}\n\nexport type { ${upperName}, ${upperName}Data, ${upperName}Patch, ${upperName}Query }\n\nexport interface ${upperName}Params extends MongoDBAdapterParams<${upperName}Query> {\n}\n\n// By default calls the standard MongoDB adapter service methods but can be customized with your own functionality.\nexport class ${className}<ServiceParams extends Params = ${upperName}Params>\n  extends MongoDBService<${upperName}, ${upperName}Data, ${upperName}Params, ${upperName}Patch> {\n}\n\nexport const getOptions = (app: Application): MongoDBAdapterOptions => {\n  return {\n    paginate: app.get('paginate'),\n    Model: app.get('mongodbClient').then(db => db.collection('${kebabPath}'))\n  }\n}\n`\n\nexport const generate = (ctx: ServiceGeneratorContext) =>\n  Promise.resolve(ctx).then(\n    renderSource(\n      template,\n      toFile<ServiceGeneratorContext>(({ lib, folder, fileName }) => [\n        lib,\n        'services',\n        ...folder,\n        `${fileName}.class`\n      ])\n    )\n  )\n"
  },
  {
    "path": "packages/generators/test/build/.gitkeep",
    "content": ""
  },
  {
    "path": "packages/generators/test/commons.test.ts",
    "content": "import { strictEqual } from 'assert'\nimport { getJavaScript } from '../lib/commons'\n\ndescribe('common tests', () => {\n  it('getJavaScript returns transpiled JavaScript', () => {\n    const transpiled = getJavaScript(\n      `import bla from 'bla'\nimport something from './file'\n\ntype X = { name: string }\n\nfunction test (arg: X) {\n  bla(something)\n}\n\n// This is a comment\nconst otherThing: string = \"Hello\"\n`\n    )\n\n    strictEqual(\n      transpiled,\n      `import bla from 'bla';\nimport something from './file.js';\n\n function test(arg) {\n    bla(something);\n}\n\n // This is a comment\nconst otherThing = \"Hello\";\n`\n    )\n\n    strictEqual(\n      getJavaScript(`import { authentication } from './authentication'`),\n      `import { authentication } from './authentication.js'`\n    )\n  })\n})\n"
  },
  {
    "path": "packages/generators/test/generators.test.ts",
    "content": "/* eslint-disable @typescript-eslint/prefer-for-of */\nimport os from 'os'\nimport path from 'path'\nimport { mkdtemp } from 'fs/promises'\nimport assert from 'assert'\nimport { getContext } from '@featherscloud/pinion'\n\nimport { AppGeneratorContext } from '../src/app'\nimport { FeathersBaseContext } from '../src/commons'\nimport { ConnectionGeneratorArguments } from '../src/connection'\nimport { ServiceGeneratorArguments } from '../src/service'\nimport { combinate, dependencyVersions } from './utils'\n\nimport { generate as generateApp } from '../lib/app'\nimport { generate as generateConnection } from '../lib/connection'\nimport { generate as generateAuthentication } from '../lib/authentication'\nimport { generate as generateService } from '../lib/service'\nimport { listAllFiles } from '@featherscloud/pinion/lib/utils'\nimport { AuthenticationGeneratorArguments } from '../lib/authentication'\n\nconst matrix = {\n  language: ['js', 'ts'] as const,\n  framework: ['koa', 'express'] as const,\n  schema: ['typebox', 'json'] as const\n}\n\nconst defaultCombination = {\n  language: process.env.FEATHERS_LANGUAGE || 'ts',\n  framework: process.env.FEATHERS_FRAMEWORK || 'koa',\n  schema: process.env.FEATHERS_SCHEMA || 'typebox'\n}\n\nconst combinations =\n  process.version > 'v16.0.0' ? (process.env.CI ? combinate(matrix as any) : [defaultCombination]) : []\n\ndescribe('@feathersjs/generators', () => {\n  for (const { language, framework, schema } of combinations) {\n    describe(`${language} ${framework} app`, () => {\n      const name = `feathers_${language}_${framework}_${schema}`\n\n      let context: FeathersBaseContext\n      let cwd: string\n\n      before(async () => {\n        cwd = await mkdtemp(path.join(os.tmpdir(), name + '-'))\n        console.log(`\\nGenerating test application to\\n${cwd}\\n\\n`)\n\n        try {\n          context = await generateApp(\n            getContext<AppGeneratorContext>(\n              {\n                name,\n                framework,\n                language,\n                dependencyVersions,\n                client: true,\n                lib: 'src',\n                description: 'A Feathers test app',\n                packager: 'npm',\n                database: 'sqlite',\n                connectionString: `${name}.sqlite`,\n                transports: ['rest', 'websockets'],\n                schema\n              },\n              { cwd }\n            )\n          )\n        } catch (error: any) {\n          console.error(error.stack)\n          console.error((await listAllFiles(cwd)).join('\\n'))\n          throw error\n        }\n      })\n\n      it('generated app with SQLite and passes tests', async () => {\n        const testResult = await context.pinion.exec('npm', ['test'], { cwd })\n\n        assert.ok(context)\n        assert.strictEqual(testResult, 0)\n      })\n\n      it('generates authentication with SQLite and passes tests', async () => {\n        const authContext = await generateAuthentication(\n          getContext<AuthenticationGeneratorArguments>(\n            {\n              dependencyVersions,\n              authStrategies: ['local', 'github'],\n              service: 'user',\n              path: 'users',\n              type: 'knex',\n              schema\n            },\n            { cwd }\n          )\n        )\n        const testResult = await context.pinion.exec('npm', ['test'], { cwd })\n\n        assert.ok(authContext)\n        assert.strictEqual(testResult, 0)\n      })\n\n      it('generates a MongoDB connection and service and passes tests', async () => {\n        const connectionContext = await generateConnection(\n          getContext<ConnectionGeneratorArguments>(\n            {\n              dependencyVersions,\n              database: 'mongodb' as const,\n              connectionString: `mongodb://127.0.0.1:27017/${name}`\n            },\n            { cwd }\n          )\n        )\n        const mongoService1Context = await generateService(\n          getContext<ServiceGeneratorArguments>(\n            {\n              dependencyVersions,\n              name: 'testing',\n              path: 'path/to/test',\n              authentication: true,\n              type: 'mongodb',\n              schema: false\n            },\n            { cwd }\n          )\n        )\n        const messageServiceContext = await generateService(\n          getContext<ServiceGeneratorArguments>(\n            {\n              dependencyVersions,\n              name: 'message',\n              path: 'messages',\n              authentication: true,\n              type: 'mongodb',\n              schema\n            },\n            { cwd }\n          )\n        )\n        const testResult = await context.pinion.exec('npm', ['test'], { cwd })\n\n        assert.ok(connectionContext)\n        assert.ok(mongoService1Context)\n        assert.ok(messageServiceContext)\n        assert.strictEqual(testResult, 0)\n      })\n\n      it('generates a custom service and passes tests', async () => {\n        const customServiceContext = await generateService(\n          getContext<ServiceGeneratorArguments>(\n            {\n              dependencyVersions,\n              name: 'Custom',\n              path: 'customized',\n              authentication: false,\n              type: 'custom',\n              schema\n            },\n            { cwd }\n          )\n        )\n        const testResult = await context.pinion.exec('npm', ['test'], { cwd })\n\n        assert.ok(customServiceContext)\n        assert.strictEqual(testResult, 0)\n      })\n\n      it('compiles successfully', async () => {\n        if (language === 'ts' && framework === 'koa') {\n          const testResult = await context.pinion.exec('npm', ['run', 'compile'], { cwd })\n\n          assert.strictEqual(testResult, 0)\n        }\n      })\n    })\n  }\n})\n"
  },
  {
    "path": "packages/generators/test/utils.ts",
    "content": "import path from 'path'\nimport pkg from '../package.json'\nimport { DependencyVersions } from '../src/commons'\nimport { readFileSync } from 'fs'\n\n// Set __dirname in es module\nconst __dirname = path.dirname(new URL(import.meta.url).pathname)\n\nexport function combinate<O extends Record<string | number, any[]>>(obj: O) {\n  let combos: { [k in keyof O]: O[k][number] }[] = []\n  for (const key of Object.keys(obj)) {\n    const values = obj[key]\n    const all: any[] = []\n    for (let i = 0; i < values.length; i++) {\n      for (let j = 0; j < (combos.length || 1); j++) {\n        const newCombo = { ...combos[j], [key]: values[i] }\n        all.push(newCombo)\n      }\n    }\n    combos = all\n  }\n  return combos\n}\n\nexport const dependencyVersions = Object.keys(pkg.devDependencies as any)\n  .filter((dep) => dep.startsWith('@feathersjs/'))\n  .reduce((acc, dep) => {\n    const [, name] = dep.split('/')\n    const { version } = JSON.parse(\n      readFileSync(path.join(__dirname, '..', '..', name, 'package.json'), 'utf8').toString()\n    )\n\n    acc[dep] = path.join(__dirname, 'build', `feathersjs-${name}-${version}.tgz`)\n\n    return acc\n  }, {} as DependencyVersions)\n"
  },
  {
    "path": "packages/generators/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Node\"\n  }\n}\n"
  },
  {
    "path": "packages/knex/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- **knex:** Add support for extended operators in query builder ([#3578](https://github.com/feathersjs/feathers/issues/3578)) ([c355ae3](https://github.com/feathersjs/feathers/commit/c355ae3184f07b15b4a313aa64fb9e7fdd0524d5))\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n- **knex:** Add tableOptions parameter for inheritance on knex adapter options to pass on knex builder ([#3539](https://github.com/feathersjs/feathers/issues/3539)) ([ba5621b](https://github.com/feathersjs/feathers/commit/ba5621bfe5e7ab01189b6b7bccb00891bc2b14c7))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n### Bug Fixes\n\n- **knex:** use driver name to identify client ([#3527](https://github.com/feathersjs/feathers/issues/3527)) ([bb075ec](https://github.com/feathersjs/feathers/commit/bb075ec8beb3ac9b0a1a8aebc3c3756d970cc6a4))\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n### Bug Fixes\n\n- **knex:** Update commited to boolean type ([#3458](https://github.com/feathersjs/feathers/issues/3458)) ([5fa4dbc](https://github.com/feathersjs/feathers/commit/5fa4dbc06d0126ac18f5643562d0b74f03502caa))\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n### Bug Fixes\n\n- **knex:** Fix Knex adapter date comparison queries ([#3429](https://github.com/feathersjs/feathers/issues/3429)) ([23bafe1](https://github.com/feathersjs/feathers/commit/23bafe1204f79ce2ab0eaaa5544fab1a3ffb5f41))\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n### Bug Fixes\n\n- **generators:** Move generators and CLI to featherscloud/pinion ([#3386](https://github.com/feathersjs/feathers/issues/3386)) ([eb87c99](https://github.com/feathersjs/feathers/commit/eb87c9922db56c5610e5b808f3ffe033c830e2b2))\n- **knex:** Add sqlite to returning clients ([#3389](https://github.com/feathersjs/feathers/issues/3389)) ([59fb40b](https://github.com/feathersjs/feathers/commit/59fb40b9eb34950ef2dd35b7de4762f224a171f1))\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n### Bug Fixes\n\n- **knex:** Add Error Handler to knex \\_update function ([#3371](https://github.com/feathersjs/feathers/issues/3371)) ([210f103](https://github.com/feathersjs/feathers/commit/210f1037bf69c641d4fd335cd4f084cbbac0a922))\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n### Bug Fixes\n\n- allow \\_patch to modify the entire base schema ([#3300](https://github.com/feathersjs/feathers/issues/3300)) ([0f41622](https://github.com/feathersjs/feathers/commit/0f41622307589b3a0b62ac411a73e6a601bda171))\n- **knex:** Add includeTriggerModifications for MSSQL support ([#3355](https://github.com/feathersjs/feathers/issues/3355)) ([cbe44b0](https://github.com/feathersjs/feathers/commit/cbe44b0e91506ab06c86355af67f83d5197bd896))\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n- **knex:** Ensure that columns are selected unambigiously and avoid duplicate id selection ([#3144](https://github.com/feathersjs/feathers/issues/3144)) ([3eb7428](https://github.com/feathersjs/feathers/commit/3eb7428f888f0e8a0fbc09f5261bff3e68a0ed63))\n- **knex:** Get by id and transactions should work with params.knex ([#3146](https://github.com/feathersjs/feathers/issues/3146)) ([b172b5e](https://github.com/feathersjs/feathers/commit/b172b5ea9b461642874eb7d2ba01dc4cfc275155))\n- **knex:** Only apply default order for MSSQL ([#3145](https://github.com/feathersjs/feathers/issues/3145)) ([28c2627](https://github.com/feathersjs/feathers/commit/28c26279befea6cf43cedd3af628234b170b8c91))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n### Bug Fixes\n\n- **core:** Use Symbol.for to instantiate shared symbols ([#3087](https://github.com/feathersjs/feathers/issues/3087)) ([7f3fc21](https://github.com/feathersjs/feathers/commit/7f3fc2167576f228f8183568eb52b077160e8d65))\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n### Bug Fixes\n\n- **knex:** The method getModel in the knex adapter ([#3043](https://github.com/feathersjs/feathers/issues/3043)) ([77e14dd](https://github.com/feathersjs/feathers/commit/77e14dd3f4a29adff8beb805d0e6186ead59e4fe))\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- **databases:** Ensure that query sanitization is not necessary when using query schemas ([#3022](https://github.com/feathersjs/feathers/issues/3022)) ([dbf514e](https://github.com/feathersjs/feathers/commit/dbf514e85d1508b95c007462a39b3cadd4ff391d))\n- **databases:** Improve documentation for adapters and allow dynamic Knex adapter options ([#3019](https://github.com/feathersjs/feathers/issues/3019)) ([66c4b5e](https://github.com/feathersjs/feathers/commit/66c4b5e72000dd03acb57fca1cad4737c85c9c9e))\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n### Features\n\n- **database:** Add and to the query syntax ([#3021](https://github.com/feathersjs/feathers/issues/3021)) ([00cb0d9](https://github.com/feathersjs/feathers/commit/00cb0d9c302ae951ae007d3d6ceba33e254edd9c))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Bug Fixes\n\n- **databases:** Make sure adapter method signatures are exported properly ([#2943](https://github.com/feathersjs/feathers/issues/2943)) ([458d668](https://github.com/feathersjs/feathers/commit/458d66859e256c5854e7590f0b4a11b233fe0374))\n- **knex:** Ensure custom ids are returned on create ([#2934](https://github.com/feathersjs/feathers/issues/2934)) ([c4fa3cf](https://github.com/feathersjs/feathers/commit/c4fa3cf812d59e6e8e3831ab098bb8768c92e8f4))\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Features\n\n- **adapter:** Add patch data type to adapters and refactor AdapterBase usage ([#2906](https://github.com/feathersjs/feathers/issues/2906)) ([9ddc2e6](https://github.com/feathersjs/feathers/commit/9ddc2e6b028f026f939d6af68125847e5c6734b4))\n- **cli:** Use separate patch schema and types ([#2916](https://github.com/feathersjs/feathers/issues/2916)) ([7088af6](https://github.com/feathersjs/feathers/commit/7088af64a539dc7f1a016d832b77b98aaaf92603))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n### Features\n\n- **cli:** Generate full client test suite and improve typed client ([#2788](https://github.com/feathersjs/feathers/issues/2788)) ([57119b6](https://github.com/feathersjs/feathers/commit/57119b6bb2797f7297cf054268a248c093ecd538))\n- **cli:** Improve generated schema definitions ([#2783](https://github.com/feathersjs/feathers/issues/2783)) ([474a9fd](https://github.com/feathersjs/feathers/commit/474a9fda2107e9bcf357746320a8e00cda8182b6))\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n- **knex:** Fix PostgreSQL integration issues and run CI tests against pg ([#2698](https://github.com/feathersjs/feathers/issues/2698)) ([1f71d78](https://github.com/feathersjs/feathers/commit/1f71d7884656c1494004931f4979ad59d23e4ee6))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/knex\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n### Bug Fixes\n\n- **cli:** Generator fixes to work with the new guide ([#2674](https://github.com/feathersjs/feathers/issues/2674)) ([b773fa5](https://github.com/feathersjs/feathers/commit/b773fa5dbd7ff450cfb2f7b93e64882592262712))\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Features\n\n- **knex:** Add KnexJS SQL database adapter to core ([#2671](https://github.com/feathersjs/feathers/issues/2671)) ([9380fff](https://github.com/feathersjs/feathers/commit/9380fff58596e8bb90b8bb098d2795b7eadfec20))\n"
  },
  {
    "path": "packages/knex/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/knex/README.md",
    "content": "# @feathersjs/knex\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/mongodb.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/mongodb)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Feathers SQL service adapter using KnexJS\n\n## Installation\n\n```\nnpm install @feathersjs/knex --save\n```\n\n## Documentation\n\nRefer to the [Feathers Knex adapter documentation](https://feathersjs.com/api/databases/knex.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/knex/package.json",
    "content": "{\n  \"name\": \"@feathersjs/knex\",\n  \"description\": \"Feathers SQL service adapter using KnexJS\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 14\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/adapter-commons\": \"^5.0.42\",\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\"\n  },\n  \"peerDependencies\": {\n    \"knex\": \">=3.1.0\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/adapter-tests\": \"^5.0.42\",\n    \"@feathersjs/schema\": \"^5.0.42\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"knex\": \"^3.1.0\",\n    \"mocha\": \"^11.7.5\",\n    \"pg\": \"^8.19.0\",\n    \"shx\": \"^0.4.0\",\n    \"sqlite3\": \"^5.1.7\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/knex/src/adapter.ts",
    "content": "import { Id, NullableId, Paginated, Query } from '@feathersjs/feathers'\nimport { _ } from '@feathersjs/commons'\nimport { AdapterBase, PaginationOptions, AdapterQuery, getLimit } from '@feathersjs/adapter-commons'\nimport { BadRequest, MethodNotAllowed, NotFound } from '@feathersjs/errors'\nimport { Knex } from 'knex'\n\nimport { errorHandler } from './error-handler'\nimport { KnexAdapterOptions, KnexAdapterParams } from './declarations'\nconst METHODS = {\n  $ne: 'whereNot',\n  $in: 'whereIn',\n  $nin: 'whereNotIn',\n  $or: 'orWhere',\n  $and: 'andWhere'\n}\n\nconst OPERATORS = {\n  $lt: '<',\n  $lte: '<=',\n  $gt: '>',\n  $gte: '>=',\n  $like: 'like',\n  $notlike: 'not like',\n  $ilike: 'ilike'\n}\n\nconst RETURNING_CLIENTS = ['postgresql', 'pg', 'oracledb', 'mssql', 'sqlite3']\n\nexport class KnexAdapter<\n  Result,\n  Data = Partial<Result>,\n  ServiceParams extends KnexAdapterParams<any> = KnexAdapterParams,\n  PatchData = Partial<Data>\n> extends AdapterBase<Result, Data, PatchData, ServiceParams, KnexAdapterOptions> {\n  schema?: string\n\n  constructor(options: KnexAdapterOptions) {\n    if (!options || !options.Model) {\n      throw new Error('You must provide a Model (the initialized knex object)')\n    }\n\n    if (typeof options.name !== 'string') {\n      throw new Error('No table name specified.')\n    }\n\n    super({\n      id: 'id',\n      ...options,\n      filters: {\n        ...options.filters,\n        $and: (value: any) => value\n      },\n      operators: [\n        ...(options.operators || []),\n        ...Object.keys(options.extendedOperators || {}),\n        '$like',\n        '$notlike',\n        '$ilike'\n      ]\n    })\n  }\n\n  get fullName() {\n    const { name, schema } = this.getOptions({} as ServiceParams)\n    return schema ? `${schema}.${name}` : name\n  }\n\n  get Model() {\n    return this.getModel()\n  }\n\n  getModel(params: ServiceParams = {} as ServiceParams) {\n    const { Model } = this.getOptions(params)\n    return Model\n  }\n\n  db(params?: ServiceParams) {\n    const { Model, name, schema, tableOptions } = this.getOptions(params)\n\n    if (params && params.transaction && params.transaction.trx) {\n      const { trx } = params.transaction\n      // debug('ran %s with transaction %s', fullName, id)\n      return schema ? (trx.withSchema(schema).table(name) as Knex.QueryBuilder) : trx(name)\n    }\n\n    return schema ? (Model.withSchema(schema).table(name) as Knex.QueryBuilder) : Model(name, tableOptions)\n  }\n\n  knexify(knexQuery: Knex.QueryBuilder, query: Query = {}, parentKey?: string): Knex.QueryBuilder {\n    const knexify = this.knexify.bind(this)\n    const { extendedOperators = {} } = this.getOptions({} as ServiceParams)\n    const operatorsMap = {\n      ...OPERATORS,\n      ...extendedOperators\n    }\n\n    return Object.keys(query || {}).reduce((currentQuery, key) => {\n      const value = query[key]\n\n      if (_.isObject(value) && !(value instanceof Date)) {\n        return knexify(currentQuery, value, key)\n      }\n\n      const column = parentKey || key\n      const method = METHODS[key as keyof typeof METHODS]\n\n      if (method) {\n        if (key === '$or' || key === '$and') {\n          // This will create a nested query\n          currentQuery.where(function (this: any) {\n            for (const condition of value) {\n              this[method](function (this: Knex.QueryBuilder) {\n                knexify(this, condition)\n              })\n            }\n          })\n\n          return currentQuery\n        }\n\n        return (currentQuery as any)[method](column, value)\n      }\n\n      const operator = operatorsMap[key as keyof typeof operatorsMap] || '='\n\n      return operator === '='\n        ? currentQuery.where(column, value)\n        : currentQuery.where(column, operator, value)\n    }, knexQuery)\n  }\n\n  createQuery(params: ServiceParams = {} as ServiceParams) {\n    const { name, id } = this.getOptions(params)\n    const { filters, query } = this.filterQuery(params)\n    const builder = this.db(params)\n\n    // $select uses a specific find syntax, so it has to come first.\n    if (filters.$select) {\n      const select = filters.$select.map((column) => (column.includes('.') ? column : `${name}.${column}`))\n      // always select the id field, but make sure we only select it once\n      builder.select(...new Set([...select, `${name}.${id}`]))\n    } else {\n      builder.select(`${name}.*`)\n    }\n\n    // build up the knex query out of the query params, include $and and $or filters\n    this.knexify(builder, {\n      ...query,\n      ..._.pick(filters, '$and', '$or')\n    })\n\n    // Handle $sort\n    if (filters.$sort) {\n      return Object.keys(filters.$sort).reduce(\n        (currentQuery, key) => currentQuery.orderBy(key, filters.$sort[key] === 1 ? 'asc' : 'desc'),\n        builder\n      )\n    }\n\n    return builder\n  }\n\n  filterQuery(params: ServiceParams) {\n    const options = this.getOptions(params)\n    const { $select, $sort, $limit: _limit, $skip = 0, ...query } = (params.query || {}) as AdapterQuery\n    const $limit = getLimit(_limit, options.paginate)\n\n    return {\n      paginate: options.paginate,\n      filters: { $select, $sort, $limit, $skip },\n      query\n    }\n  }\n\n  async _find(params?: ServiceParams & { paginate?: PaginationOptions }): Promise<Paginated<Result>>\n  async _find(params?: ServiceParams & { paginate: false }): Promise<Result[]>\n  async _find(params?: ServiceParams): Promise<Paginated<Result> | Result[]>\n  async _find(params: ServiceParams = {} as ServiceParams): Promise<Paginated<Result> | Result[]> {\n    const { filters, paginate } = this.filterQuery(params)\n    const { name, id } = this.getOptions(params)\n    const builder = params.knex ? params.knex.clone() : this.createQuery(params)\n    const countBuilder = builder.clone().clearSelect().clearOrder().count(`${name}.${id} as total`)\n\n    // Handle $limit\n    if (filters.$limit) {\n      builder.limit(filters.$limit)\n    }\n\n    // Handle $skip\n    if (filters.$skip) {\n      builder.offset(filters.$skip)\n    }\n\n    // provide default sorting if its not set\n    if (!filters.$sort && builder.client.driverName === 'mssql') {\n      builder.orderBy(`${name}.${id}`, 'asc')\n    }\n\n    const data = filters.$limit === 0 ? [] : await builder.catch(errorHandler)\n\n    if (paginate && paginate.default) {\n      const total = await countBuilder.then((count) => parseInt(count[0] ? count[0].total : 0))\n\n      return {\n        total,\n        limit: filters.$limit,\n        skip: filters.$skip || 0,\n        data\n      }\n    }\n\n    return data\n  }\n\n  async _findOrGet(id: NullableId, params?: ServiceParams) {\n    if (id !== null) {\n      const { name, id: idField } = this.getOptions(params)\n      const builder = params.knex ? params.knex.clone() : this.createQuery(params)\n      const idQuery = builder.andWhere(`${name}.${idField}`, '=', id).catch(errorHandler)\n\n      return idQuery as Promise<Result[]>\n    }\n\n    return this._find({\n      ...params,\n      paginate: false\n    })\n  }\n\n  async _get(id: Id, params: ServiceParams = {} as ServiceParams): Promise<Result> {\n    const data = await this._findOrGet(id, params)\n\n    if (data.length !== 1) {\n      throw new NotFound(`No record found for id '${id}'`)\n    }\n\n    return data[0]\n  }\n\n  async _create(data: Data, params?: ServiceParams): Promise<Result>\n  async _create(data: Data[], params?: ServiceParams): Promise<Result[]>\n  async _create(data: Data | Data[], _params?: ServiceParams): Promise<Result | Result[]>\n  async _create(\n    _data: Data | Data[],\n    params: ServiceParams = {} as ServiceParams\n  ): Promise<Result | Result[]> {\n    const data = _data as any\n\n    if (Array.isArray(data)) {\n      return Promise.all(data.map((current) => this._create(current, params)))\n    }\n\n    const { client } = this.db(params)\n    const returning = RETURNING_CLIENTS.includes(client.driverName) ? [this.id] : []\n    const rows: any = await this.db(params)\n      .insert(data, returning, { includeTriggerModifications: true })\n      .catch(errorHandler)\n    const id = data[this.id] || rows[0][this.id] || rows[0]\n\n    if (!id) {\n      return rows as Result[]\n    }\n\n    return this._get(id, {\n      ...params,\n      query: _.pick(params?.query || {}, '$select')\n    })\n  }\n\n  async _patch(id: null, data: PatchData | Partial<Result>, params?: ServiceParams): Promise<Result[]>\n  async _patch(id: Id, data: PatchData | Partial<Result>, params?: ServiceParams): Promise<Result>\n  async _patch(\n    id: NullableId,\n    data: PatchData | Partial<Result>,\n    _params?: ServiceParams\n  ): Promise<Result | Result[]>\n  async _patch(\n    id: NullableId,\n    raw: PatchData | Partial<Result>,\n    params: ServiceParams = {} as ServiceParams\n  ): Promise<Result | Result[]> {\n    if (id === null && !this.allowsMulti('patch', params)) {\n      throw new MethodNotAllowed('Can not patch multiple entries')\n    }\n\n    const { name, id: idField } = this.getOptions(params)\n    const data = _.omit(raw, this.id)\n    const results = await this._findOrGet(id, {\n      ...params,\n      query: {\n        ...params?.query,\n        $select: [`${name}.${idField}`]\n      }\n    })\n    const idList = results.map((current: any) => current[idField])\n    const updateParams = {\n      ...params,\n      query: {\n        [`${name}.${idField}`]: { $in: idList },\n        ...(params?.query?.$select ? { $select: params?.query?.$select } : {})\n      }\n    }\n    const builder = this.createQuery(updateParams)\n\n    await builder.update(data, [], { includeTriggerModifications: true })\n\n    const items = await this._findOrGet(null, updateParams)\n\n    if (id !== null) {\n      if (items.length === 1) {\n        return items[0]\n      } else {\n        throw new NotFound(`No record found for id '${id}'`)\n      }\n    }\n\n    return items\n  }\n\n  async _update(id: Id, _data: Data, params: ServiceParams = {} as ServiceParams): Promise<Result> {\n    if (id === null || Array.isArray(_data)) {\n      throw new BadRequest(\"You can not replace multiple instances. Did you mean 'patch'?\")\n    }\n\n    const data = _.omit(_data, this.id)\n    const oldData = await this._get(id, params)\n    const newObject = Object.keys(oldData).reduce((result: any, key) => {\n      if (key !== this.id) {\n        // We don't want the id field to be changed\n        result[key] = data[key] === undefined ? null : data[key]\n      }\n\n      return result\n    }, {})\n\n    await this.db(params)\n      .update(newObject, '*', { includeTriggerModifications: true })\n      .where(this.id, id)\n      .catch(errorHandler)\n\n    return this._get(id, params)\n  }\n\n  async _remove(id: null, params?: ServiceParams): Promise<Result[]>\n  async _remove(id: Id, params?: ServiceParams): Promise<Result>\n  async _remove(id: NullableId, _params?: ServiceParams): Promise<Result | Result[]>\n  async _remove(id: NullableId, params: ServiceParams = {} as ServiceParams): Promise<Result | Result[]> {\n    if (id === null && !this.allowsMulti('remove', params)) {\n      throw new MethodNotAllowed('Can not remove multiple entries')\n    }\n\n    const items = await this._findOrGet(id, params)\n    const { query } = this.filterQuery(params)\n    const q = this.db(params)\n    const idList = items.map((current: any) => current[this.id])\n\n    query[this.id] = { $in: idList }\n\n    // build up the knex query out of the query params\n    this.knexify(q, query)\n\n    await q.delete([], { includeTriggerModifications: true }).catch(errorHandler)\n\n    if (id !== null) {\n      if (items.length === 1) {\n        return items[0]\n      }\n\n      throw new NotFound(`No record found for id '${id}'`)\n    }\n\n    return items\n  }\n}\n"
  },
  {
    "path": "packages/knex/src/declarations.ts",
    "content": "import { Knex } from 'knex'\nimport { AdapterServiceOptions, AdapterParams, AdapterQuery } from '@feathersjs/adapter-commons'\n\nexport interface KnexAdapterOptions extends AdapterServiceOptions {\n  Model: Knex\n  name: string\n  schema?: string\n  tableOptions?: {\n    only?: boolean\n  }\n  extendedOperators?: {\n    [key: string]: string\n  }\n}\n\nexport interface KnexAdapterTransaction {\n  starting: boolean\n  parent?: KnexAdapterTransaction\n  committed?: Promise<boolean>\n  resolve?: any\n  trx?: Knex.Transaction\n  id?: number\n  promise?: Promise<any>\n}\n\nexport interface KnexAdapterParams<Q = AdapterQuery> extends AdapterParams<Q, Partial<KnexAdapterOptions>> {\n  knex?: Knex.QueryBuilder\n  transaction?: KnexAdapterTransaction\n}\n"
  },
  {
    "path": "packages/knex/src/error-handler.ts",
    "content": "import { errors } from '@feathersjs/errors'\n\nexport const ERROR = Symbol.for('@feathersjs/knex/error')\n\nexport function errorHandler(error: any) {\n  const { message } = error\n  let feathersError = error\n\n  if (error.sqlState && error.sqlState.length) {\n    // remove SQLSTATE marker (#) and pad/truncate SQLSTATE to 5 chars\n    const sqlState = ('00000' + error.sqlState.replace('#', '')).slice(-5)\n\n    switch (sqlState.slice(0, 2)) {\n      case '02':\n        feathersError = new errors.NotFound(message)\n        break\n      case '28':\n        feathersError = new errors.Forbidden(message)\n        break\n      case '08':\n      case '0A':\n      case '0K':\n        feathersError = new errors.Unavailable(message)\n        break\n      case '20':\n      case '21':\n      case '22':\n      case '23':\n      case '24':\n      case '25':\n      case '40':\n      case '42':\n      case '70':\n        feathersError = new errors.BadRequest(message)\n        break\n      default:\n        feathersError = new errors.GeneralError(message)\n    }\n  } else if (error.code === 'SQLITE_ERROR') {\n    // NOTE (EK): Error codes taken from\n    // https://www.sqlite.org/c3ref/c_abort.html\n    switch (error.errno) {\n      case 1:\n      case 8:\n      case 18:\n      case 19:\n      case 20:\n        feathersError = new errors.BadRequest(message)\n        break\n      case 2:\n        feathersError = new errors.Unavailable(message)\n        break\n      case 3:\n      case 23:\n        feathersError = new errors.Forbidden(message)\n        break\n      case 12:\n        feathersError = new errors.NotFound(message)\n        break\n      default:\n        feathersError = new errors.GeneralError(message)\n        break\n    }\n  } else if (typeof error.code === 'string' && error.severity && error.routine) {\n    // NOTE: Error codes taken from\n    // https://www.postgresql.org/docs/9.6/static/errcodes-appendix.html\n    // Omit query information\n    const messages = (error.message || '').split('-')\n\n    error.message = messages[messages.length - 1]\n\n    switch (error.code.slice(0, 2)) {\n      case '22':\n        feathersError = new errors.NotFound(message)\n        break\n      case '23':\n        feathersError = new errors.BadRequest(message)\n        break\n      case '28':\n        feathersError = new errors.Forbidden(message)\n        break\n      case '3D':\n      case '3F':\n      case '42':\n        feathersError = new errors.Unprocessable(message)\n        break\n      default:\n        feathersError = new errors.GeneralError(message)\n        break\n    }\n  } else if (!(error instanceof errors.FeathersError)) {\n    feathersError = new errors.GeneralError(message)\n  }\n\n  feathersError[ERROR] = error\n\n  throw feathersError\n}\n"
  },
  {
    "path": "packages/knex/src/hooks.ts",
    "content": "import { createDebug } from '@feathersjs/commons'\nimport { HookContext } from '@feathersjs/feathers'\nimport { Knex } from 'knex'\nimport { KnexAdapterTransaction } from './declarations'\n\nconst debug = createDebug('feathers-knex-transaction')\n\nconst ROLLBACK = { rollback: true }\n\nexport const getKnex = (context: HookContext): Knex => {\n  const knex = context.params?.knex\n    ? context.params.knex\n    : typeof context.service.getModel === 'function' && context.service.getModel(context.params)\n\n  return knex && typeof knex.transaction === 'function' ? knex : undefined\n}\n\nexport const start =\n  () =>\n  async (context: HookContext): Promise<void> => {\n    const { transaction } = context.params\n    const parent = transaction\n    const knex: Knex = transaction ? transaction.trx : getKnex(context)\n\n    if (!knex) {\n      return\n    }\n\n    return new Promise<void>((resolve, reject) => {\n      const transaction: KnexAdapterTransaction = {\n        starting: true\n      }\n\n      if (parent) {\n        transaction.parent = parent\n        transaction.committed = parent.committed\n      } else {\n        transaction.committed = new Promise((resolve) => {\n          transaction.resolve = resolve\n        })\n      }\n\n      transaction.starting = true\n      transaction.promise = knex\n        .transaction((trx) => {\n          transaction.trx = trx\n          transaction.id = Date.now()\n\n          context.params = { ...context.params, transaction }\n          debug('started a new transaction %s', transaction.id)\n\n          resolve()\n        })\n        .catch((error) => {\n          if (transaction.starting) {\n            reject(error)\n          } else if (error !== ROLLBACK) {\n            throw error\n          }\n        })\n    })\n  }\n\nexport const end = () => (context: HookContext) => {\n  const { transaction } = context.params\n\n  if (!transaction) {\n    return\n  }\n\n  const { trx, id, promise, parent } = transaction\n\n  context.params = { ...context.params, transaction: parent }\n  transaction.starting = false\n\n  return trx\n    .commit()\n    .then(() => promise)\n    .then(() => transaction.resolve && transaction.resolve(true))\n    .then(() => debug('ended transaction %s', id))\n    .then(() => context)\n}\n\nexport const rollback = () => (context: HookContext) => {\n  const { transaction } = context.params\n\n  if (!transaction) {\n    return\n  }\n\n  const { trx, id, promise, parent } = transaction\n\n  context.params = { ...context.params, transaction: parent }\n  transaction.starting = false\n\n  return trx\n    .rollback(ROLLBACK)\n    .then(() => promise)\n    .then(() => transaction.resolve && transaction.resolve(false))\n    .then(() => debug('rolled back transaction %s', id))\n    .then(() => context)\n}\n"
  },
  {
    "path": "packages/knex/src/index.ts",
    "content": "import { PaginationOptions } from '@feathersjs/adapter-commons'\nimport { MethodNotAllowed } from '@feathersjs/errors/lib'\nimport { Paginated, ServiceMethods, Id, NullableId, Params } from '@feathersjs/feathers'\nimport { KnexAdapter } from './adapter'\nimport { KnexAdapterParams } from './declarations'\n\nexport * from './declarations'\nexport * from './adapter'\nexport * from './error-handler'\nexport * as transaction from './hooks'\n\nexport class KnexService<\n  Result = any,\n  Data = Partial<Result>,\n  ServiceParams extends Params<any> = KnexAdapterParams,\n  PatchData = Partial<Data>\n>\n  extends KnexAdapter<Result, Data, ServiceParams, PatchData>\n  implements ServiceMethods<Result | Paginated<Result>, Data, ServiceParams, PatchData>\n{\n  async find(params?: ServiceParams & { paginate?: PaginationOptions }): Promise<Paginated<Result>>\n  async find(params?: ServiceParams & { paginate: false }): Promise<Result[]>\n  async find(params?: ServiceParams): Promise<Paginated<Result> | Result[]>\n  async find(params?: ServiceParams): Promise<Paginated<Result> | Result[]> {\n    return this._find({\n      ...params,\n      query: await this.sanitizeQuery(params)\n    })\n  }\n\n  async get(id: Id, params?: ServiceParams): Promise<Result> {\n    return this._get(id, {\n      ...params,\n      query: await this.sanitizeQuery(params)\n    })\n  }\n\n  async create(data: Data, params?: ServiceParams): Promise<Result>\n  async create(data: Data[], params?: ServiceParams): Promise<Result[]>\n  async create(data: Data | Data[], params?: ServiceParams): Promise<Result | Result[]>\n  async create(data: Data | Data[], params?: ServiceParams): Promise<Result | Result[]> {\n    if (Array.isArray(data) && !this.allowsMulti('create', params)) {\n      throw new MethodNotAllowed('Can not create multiple entries')\n    }\n\n    return this._create(data, params)\n  }\n\n  async update(id: Id, data: Data, params?: ServiceParams): Promise<Result> {\n    return this._update(id, data, {\n      ...params,\n      query: await this.sanitizeQuery(params)\n    })\n  }\n\n  async patch(id: Id, data: PatchData, params?: ServiceParams): Promise<Result>\n  async patch(id: null, data: PatchData, params?: ServiceParams): Promise<Result[]>\n  async patch(id: NullableId, data: PatchData, params?: ServiceParams): Promise<Result | Result[]>\n  async patch(id: NullableId, data: PatchData, params?: ServiceParams): Promise<Result | Result[]> {\n    const { $limit, ...query } = await this.sanitizeQuery(params)\n\n    return this._patch(id, data, {\n      ...params,\n      query\n    })\n  }\n\n  async remove(id: Id, params?: ServiceParams): Promise<Result>\n  async remove(id: null, params?: ServiceParams): Promise<Result[]>\n  async remove(id: NullableId, params?: ServiceParams): Promise<Result | Result[]>\n  async remove(id: NullableId, params?: ServiceParams): Promise<Result | Result[]> {\n    const { $limit, ...query } = await this.sanitizeQuery(params)\n\n    return this._remove(id, {\n      ...params,\n      query\n    })\n  }\n}\n"
  },
  {
    "path": "packages/knex/test/connection.ts",
    "content": "export default (DB: string) => {\n  if (DB === 'mysql') {\n    return {\n      client: 'mysql',\n      connection: {\n        host: '127.0.0.1',\n        user: 'root',\n        password: '',\n        database: 'feathers_knex'\n      }\n    }\n  }\n\n  if (DB === 'postgres') {\n    return {\n      client: 'postgresql',\n      connection: {\n        host: 'localhost',\n        database: 'feathers',\n        user: 'postgres',\n        password: 'postgres'\n      }\n    }\n  }\n\n  return {\n    client: 'sqlite3',\n    connection: {\n      filename: './db.sqlite'\n    }\n  }\n}\n"
  },
  {
    "path": "packages/knex/test/error-handler.test.ts",
    "content": "import assert from 'assert'\nimport { errorHandler } from '../src'\n\ndescribe('Knex Error handler', () => {\n  it('sqlState', () => {\n    assert.throws(\n      () =>\n        errorHandler({\n          sqlState: '#23503'\n        }),\n      {\n        name: 'BadRequest'\n      }\n    )\n  })\n\n  it('sqliteError', () => {\n    assert.throws(\n      () =>\n        errorHandler({\n          code: 'SQLITE_ERROR',\n          errno: 1\n        }),\n      {\n        name: 'BadRequest'\n      }\n    )\n    assert.throws(() => errorHandler({ code: 'SQLITE_ERROR', errno: 2 }), { name: 'Unavailable' })\n    assert.throws(() => errorHandler({ code: 'SQLITE_ERROR', errno: 3 }), { name: 'Forbidden' })\n    assert.throws(() => errorHandler({ code: 'SQLITE_ERROR', errno: 12 }), { name: 'NotFound' })\n    assert.throws(() => errorHandler({ code: 'SQLITE_ERROR', errno: 13 }), { name: 'GeneralError' })\n  })\n\n  it('postgresqlError', () => {\n    assert.throws(\n      () =>\n        errorHandler({\n          code: '22P02',\n          message: 'Key (id)=(1) is not present in table \"users\".',\n          severity: 'ERROR',\n          routine: 'ExecConstraints'\n        }),\n      {\n        name: 'NotFound'\n      }\n    )\n    assert.throws(\n      () =>\n        errorHandler({ code: '2874', message: 'Something', severity: 'ERROR', routine: 'ExecConstraints' }),\n      {\n        name: 'Forbidden'\n      }\n    )\n    assert.throws(\n      () =>\n        errorHandler({ code: '3D74', message: 'Something', severity: 'ERROR', routine: 'ExecConstraints' }),\n      {\n        name: 'Unprocessable'\n      }\n    )\n    assert.throws(() => errorHandler({ code: 'XYZ', severity: 'ERROR', routine: 'ExecConstraints' }), {\n      name: 'GeneralError'\n    })\n  })\n})\n"
  },
  {
    "path": "packages/knex/test/index.test.ts",
    "content": "import knex, { Knex } from 'knex'\nimport assert from 'assert'\nimport { feathers, HookContext, Service } from '@feathersjs/feathers'\nimport adapterTests from '@feathersjs/adapter-tests'\nimport { errors } from '@feathersjs/errors'\nimport { Ajv, getValidator, querySyntax, hooks } from '@feathersjs/schema'\n\nimport connection from './connection'\nimport { ERROR, KnexAdapterParams, KnexService, transaction } from '../src/index'\nimport { AdapterQuery } from '@feathersjs/adapter-commons/lib'\n\nconst testSuite = adapterTests([\n  '.options',\n  '.events',\n  '._get',\n  '._find',\n  '._create',\n  '._update',\n  '._patch',\n  '._remove',\n  '.get',\n  '.get + $select',\n  '.get + id + query',\n  '.get + NotFound',\n  '.get + id + query id',\n  '.find',\n  '.remove',\n  '.remove + $select',\n  '.remove + id + query',\n  '.remove + multi',\n  '.remove + multi no pagination',\n  '.remove + id + query id',\n  '.update',\n  '.update + $select',\n  '.update + id + query',\n  '.update + NotFound',\n  '.update + query + NotFound',\n  '.update + id + query id',\n  '.patch',\n  '.patch + $select',\n  '.patch + id + query',\n  '.patch multiple',\n  '.patch multiple no pagination',\n  '.patch multi query same',\n  '.patch multi query changed',\n  '.patch + NotFound',\n  '.patch + query + NotFound',\n  '.patch + id + query id',\n  '.create',\n  '.create ignores query',\n  '.create + $select',\n  '.create multi',\n  'internal .find',\n  'internal .get',\n  'internal .create',\n  'internal .update',\n  'internal .patch',\n  'internal .remove',\n  '.find + equal',\n  '.find + equal multiple',\n  '.find + $sort',\n  '.find + $sort + string',\n  '.find + $limit',\n  '.find + $limit 0',\n  '.find + $skip',\n  '.find + $select',\n  '.find + $or',\n  '.find + $and',\n  '.find + $in',\n  '.find + $nin',\n  '.find + $lt',\n  '.find + $lte',\n  '.find + $gt',\n  '.find + $gte',\n  '.find + $ne',\n  '.find + $gt + $lt + $sort',\n  '.find + $or nested + $sort',\n  '.find + $and + $or',\n  'params.adapter + paginate',\n  'params.adapter + multi',\n  '.find + paginate',\n  '.find + paginate + query',\n  '.find + paginate + $limit + $skip',\n  '.find + paginate + $limit 0',\n  '.find + paginate + params'\n])\n\nconst TYPE = process.env.TEST_DB || 'sqlite'\nconst db = knex(connection(TYPE) as any)\n\n// Create a public database to mimic a \"schema\"\nconst schemaName = 'public'\n\nconst clean = async () => {\n  await db.schema.dropTableIfExists('todos')\n  await db.schema.dropTableIfExists(people.fullName)\n  await db.schema.createTable(people.fullName, (table) => {\n    table.increments('id')\n    table.string('name').notNullable()\n    table.integer('age')\n    table.integer('time')\n    table.boolean('created')\n    return table\n  })\n  await db.schema.createTable('todos', (table) => {\n    table.increments('id')\n    table.string('text')\n    table.integer('personId')\n    return table\n  })\n  await db.schema.dropTableIfExists(peopleId.fullName)\n  await db.schema.createTable(peopleId.fullName, (table) => {\n    table.increments('customid')\n    table.string('name')\n    table.integer('age')\n    table.integer('time')\n    table.boolean('created')\n    return table\n  })\n  await db.schema.dropTableIfExists(peopleExtendedOps.fullName)\n  await db.schema.createTable(peopleExtendedOps.fullName, (table) => {\n    table.increments('id')\n    table.string('name')\n    table.integer('age')\n    table.integer('time')\n    table.boolean('created')\n    return table\n  })\n  await db.schema.dropTableIfExists(users.fullName)\n  await db.schema.createTable(users.fullName, (table) => {\n    table.increments('id')\n    table.string('name')\n    table.integer('age')\n    table.integer('time')\n    table.boolean('created')\n    return table\n  })\n}\n\nconst personSchema = {\n  $id: 'Person',\n  type: 'object',\n  additionalProperties: false,\n  required: ['_id', 'name', 'age'],\n  properties: {\n    id: { type: 'number' },\n    name: { type: 'string' },\n    age: { type: ['number', 'null'] },\n    time: { type: 'string' },\n    create: { type: 'boolean' }\n  }\n} as const\nconst personQuery = {\n  $id: 'PersonQuery',\n  type: 'object',\n  additionalProperties: false,\n  properties: {\n    ...querySyntax(personSchema.properties, {\n      name: {\n        $like: { type: 'string' },\n        $ilike: { type: 'string' },\n        $notlike: { type: 'string' }\n      }\n    })\n  }\n} as const\nconst validator = new Ajv({\n  coerceTypes: true\n})\nconst personQueryValidator = getValidator(personQuery, validator)\n\ntype Person = {\n  id: number\n  name: string\n  age: number | null\n  time: string\n  create: boolean\n}\n\ntype Todo = {\n  id: number\n  text: string\n  personId: number\n  personName: string\n}\n\ntype ServiceTypes = {\n  people: KnexService<Person>\n  'people-customid': KnexService<Person>\n  users: KnexService<Person>\n  todos: KnexService<Todo>\n  'people-extended-ops': KnexService<Person>\n}\n\nclass TodoService extends KnexService<Todo> {\n  createQuery(params: KnexAdapterParams<AdapterQuery>) {\n    const query = super.createQuery(params)\n\n    query.join('people as person', 'todos.personId', 'person.id').select('person.name as personName')\n\n    return query\n  }\n}\n\nconst people = new KnexService({\n  Model: db,\n  name: 'people',\n  events: ['testing']\n})\n\nconst peopleId = new KnexService({\n  Model: db,\n  id: 'customid',\n  name: 'people-customid',\n  events: ['testing']\n})\n\nconst users = new KnexService({\n  Model: db,\n  name: 'users',\n  events: ['testing']\n})\n\nconst todos = new TodoService({\n  Model: db,\n  name: 'todos'\n})\n\nconst peopleExtendedOps = new KnexService({\n  Model: db,\n  name: 'people-extended-ops',\n  events: ['testing'],\n  extendedOperators: {\n    $neq: '<>', // Not equal (alternative syntax)\n    $startsWith: 'like' // Same as $like but with a different name\n  }\n})\n\ndescribe('Feathers Knex Service', () => {\n  const app = feathers<ServiceTypes>()\n    .hooks({\n      before: [transaction.start()],\n      after: [transaction.end()],\n      error: [transaction.rollback()]\n    })\n    .use('people', people)\n    .use('people-customid', peopleId)\n    .use('users', users)\n    .use('todos', todos)\n    .use('people-extended-ops', peopleExtendedOps)\n  const peopleService = app.service('people')\n\n  peopleService.hooks({\n    before: {\n      find: [hooks.validateQuery(personQueryValidator)]\n    }\n  })\n  before(() => {\n    if (TYPE === 'sqlite') {\n      // Attach the public database to mimic a \"schema\"\n      db.schema.raw(`attach database '${schemaName}.sqlite' as ${schemaName}`)\n    }\n  })\n  before(clean)\n  after(clean)\n\n  describe('$like method', () => {\n    let charlie: Person\n\n    beforeEach(async () => {\n      charlie = await peopleService.create({\n        name: 'Charlie Brown',\n        age: 10\n      })\n    })\n\n    afterEach(() => peopleService.remove(charlie.id))\n\n    it('$like in query', async () => {\n      const data = await peopleService.find({\n        paginate: false,\n        query: { name: { $like: '%lie%' } }\n      })\n\n      assert.strictEqual(data[0].name, 'Charlie Brown')\n    })\n  })\n\n  describe('$notlike method', () => {\n    let hasMatch: Person\n    let hasNoMatch: Person\n\n    beforeEach(async () => {\n      hasMatch = await peopleService.create({\n        name: 'XYZabcZYX'\n      })\n      hasNoMatch = await peopleService.create({\n        name: 'XYZZYX'\n      })\n    })\n\n    afterEach(() => {\n      peopleService.remove(hasMatch.id)\n      peopleService.remove(hasNoMatch.id)\n    })\n\n    it('$notlike in query', async () => {\n      const data = await peopleService.find({\n        paginate: false,\n        query: { name: { $notlike: '%abc%' } }\n      })\n\n      assert.strictEqual(data.length, 1)\n      assert.strictEqual(data[0].name, 'XYZZYX')\n    })\n  })\n\n  describe('adapter specifics', () => {\n    let daves: Person[]\n\n    beforeEach(async () => {\n      daves = await Promise.all([\n        peopleService.create({\n          name: 'Ageless',\n          age: null\n        }),\n        peopleService.create({\n          name: 'Dave',\n          age: 32\n        }),\n        peopleService.create({\n          name: 'Dada',\n          age: 1\n        })\n      ])\n    })\n\n    afterEach(async () => {\n      try {\n        await peopleService.remove(daves[0].id)\n        await peopleService.remove(daves[1].id)\n        await peopleService.remove(daves[2].id)\n      } catch (error: unknown) {}\n    })\n\n    it('$or works properly (#120)', async () => {\n      const data = await peopleService.find({\n        paginate: false,\n        query: {\n          name: 'Dave',\n          $or: [\n            {\n              age: 1\n            },\n            {\n              age: 32\n            }\n          ]\n        }\n      })\n\n      assert.strictEqual(data.length, 1)\n      assert.strictEqual(data[0].name, 'Dave')\n      assert.strictEqual(data[0].age, 32)\n    })\n\n    it('$and works properly', async () => {\n      const data = await peopleService.find({\n        paginate: false,\n        query: {\n          $and: [\n            {\n              $or: [{ name: 'Dave' }, { name: 'Dada' }]\n            },\n            {\n              age: { $lt: 23 }\n            }\n          ]\n        }\n      })\n\n      assert.strictEqual(data.length, 1)\n      assert.strictEqual(data[0].name, 'Dada')\n      assert.strictEqual(data[0].age, 1)\n    })\n\n    it('where conditions support NULL values properly', async () => {\n      const data = await peopleService.find({\n        paginate: false,\n        query: {\n          age: null\n        }\n      })\n\n      assert.strictEqual(data.length, 1)\n      assert.strictEqual(data[0].name, 'Ageless')\n      assert.strictEqual(data[0].age, null)\n    })\n\n    it('where conditions support NOT NULL case properly', async () => {\n      const data = await peopleService.find({\n        paginate: false,\n        query: {\n          age: { $ne: null }\n        }\n      })\n\n      assert.strictEqual(data.length, 2)\n      assert.notStrictEqual(data[0].name, 'Ageless')\n      assert.notStrictEqual(data[0].age, null)\n      assert.notStrictEqual(data[1].name, 'Ageless')\n      assert.notStrictEqual(data[1].age, null)\n    })\n\n    it('where conditions support NULL values within AND conditions', async () => {\n      const data = await peopleService.find({\n        paginate: false,\n        query: {\n          age: null,\n          name: 'Ageless'\n        }\n      })\n\n      assert.strictEqual(data.length, 1)\n      assert.strictEqual(data[0].name, 'Ageless')\n      assert.strictEqual(data[0].age, null)\n    })\n\n    it('where conditions support NULL values within OR conditions', async () => {\n      const data = await peopleService.find({\n        paginate: false,\n        query: {\n          $or: [\n            {\n              age: null\n            },\n            {\n              name: 'Dada'\n            }\n          ]\n        }\n      })\n\n      assert.strictEqual(data.length, 2)\n      assert.notStrictEqual(data[0].name, 'Dave')\n      assert.notStrictEqual(data[0].age, 32)\n      assert.notStrictEqual(data[1].name, 'Dave')\n      assert.notStrictEqual(data[1].age, 32)\n    })\n\n    it('attaches the SQL error', async () => {\n      await assert.rejects(\n        () => peopleService.create({}),\n        (error: any) => {\n          assert.ok(error[ERROR])\n          return true\n        }\n      )\n    })\n\n    it('get by id works with `createQuery` as params.knex', async () => {\n      const knex = peopleService.createQuery()\n      const dave = await peopleService.get(daves[0].id, { knex })\n\n      assert.deepStrictEqual(dave, daves[0])\n    })\n  })\n\n  describe('hooks', () => {\n    type ModelStub = { getModel: () => Knex }\n\n    afterEach(async () => {\n      await db('people').truncate()\n    })\n\n    it('does reject on problem with commit', async () => {\n      const app = feathers()\n\n      app.hooks({\n        before: transaction.start(),\n        after: [\n          (context: HookContext) => {\n            const client = context.params.transaction.trx.client\n            const query = client.query\n\n            client.query = (conn: any, sql: any) => {\n              let result = query.call(client, conn, sql)\n\n              if (sql === 'COMMIT;') {\n                result = result.then(() => {\n                  throw new TypeError('Deliberate')\n                })\n              }\n\n              return result\n            }\n          },\n          transaction.end()\n        ],\n        error: transaction.rollback()\n      })\n\n      app.use('/people', people)\n\n      await assert.rejects(() => app.service('/people').create({ name: 'Foo' }), {\n        message: 'Deliberate'\n      })\n    })\n\n    it('does commit, rollback, nesting', async () => {\n      const app = feathers<{\n        people: typeof people\n        test: Pick<Service, 'create'> & ModelStub\n      }>()\n\n      app.hooks({\n        before: transaction.start(),\n        after: transaction.end(),\n        error: transaction.rollback()\n      })\n\n      app.use('people', people)\n\n      app.use('test', {\n        getModel: () => db,\n        create: async (data: any, params) => {\n          const created = await app.service('people').create({ name: 'Foo' }, { ...params })\n\n          if (data.throw) {\n            throw new TypeError('Deliberate')\n          }\n\n          return created\n        }\n      })\n\n      await assert.rejects(() => app.service('test').create({ throw: true }), {\n        message: 'Deliberate'\n      })\n\n      assert.strictEqual((await app.service('people').find({ paginate: false })).length, 0)\n\n      await app.service('test').create({})\n\n      assert.strictEqual((await app.service('people').find({ paginate: false })).length, 1)\n    })\n\n    it('does use savepoints for nested calls', async () => {\n      const app = feathers<{\n        people: typeof people\n        success: Pick<Service, 'create'> & ModelStub\n        fail: Pick<Service, 'create'> & ModelStub\n        test: Pick<Service, 'create'> & ModelStub\n      }>()\n\n      app.hooks({\n        before: transaction.start(),\n        after: transaction.end(),\n        error: transaction.rollback()\n      })\n\n      app.use('people', people)\n\n      app.use('success', {\n        getModel: () => db,\n        create: async (_data, params) => {\n          return app.service('people').create({ name: 'Success' }, { ...params })\n        }\n      })\n\n      app.use('fail', {\n        getModel: () => db,\n        create: async (_data, params) => {\n          await app.service('people').create({ name: 'Fail' }, { ...params })\n          throw new TypeError('Deliberate')\n        }\n      })\n\n      app.use('test', {\n        getModel: () => db,\n        create: async (_data, params) => {\n          await app.service('success').create({}, { ...params })\n          await app\n            .service('fail')\n            .create({}, { ...params })\n            // eslint-disable-next-line @typescript-eslint/no-empty-function\n            .catch(() => {})\n          return []\n        }\n      })\n\n      await app.service('test').create({})\n\n      const created = await app.service('people').find({ paginate: false })\n\n      assert.strictEqual(created.length, 1)\n      assert.ok(created[0].name)\n    })\n\n    it('allows waiting for transaction to complete', async () => {\n      const app = feathers<{\n        people: typeof people\n        test: Pick<Service, 'create'> & ModelStub\n      }>()\n\n      let seq: string[] = []\n\n      app.hooks({\n        before: [\n          transaction.start(),\n          (context: HookContext) => {\n            seq.push(`${context.path}: waiting for trx to be committed`)\n            context.params.transaction.committed.then((success: any) => {\n              seq.push(`${context.path}: committed ${success}`)\n            })\n          },\n          async (context: HookContext) => {\n            seq.push(`${context.path}: another hook`)\n          }\n        ],\n        after: [\n          transaction.end(),\n          (context: HookContext) => {\n            seq.push(`${context.path}: trx ended`)\n          }\n        ],\n        error: [\n          transaction.rollback(),\n          (context: HookContext) => {\n            seq.push(`${context.path}: trx rolled back`)\n          }\n        ]\n      })\n\n      app.use('people', people)\n\n      app.use('test', {\n        getModel: () => db,\n        create: async (data: any, params) => {\n          const peeps = await app.service('people').create({ name: 'Foo' }, { ...params })\n\n          if (data.throw) {\n            throw new TypeError('Deliberate')\n          }\n          return peeps\n        }\n      })\n\n      assert.deepStrictEqual(seq, [])\n\n      await assert.rejects(() => app.service('test').create({ throw: true }), {\n        message: 'Deliberate'\n      })\n\n      assert.deepStrictEqual(seq, [\n        'test: waiting for trx to be committed',\n        'test: another hook',\n        'people: waiting for trx to be committed',\n        'people: another hook',\n        'people: trx ended',\n        'test: committed false',\n        'people: committed false',\n        'test: trx rolled back'\n      ])\n\n      seq = []\n\n      assert.strictEqual((await app.service('people').find({ paginate: false })).length, 0)\n\n      assert.deepStrictEqual(seq, [\n        'people: waiting for trx to be committed',\n        'people: another hook',\n        'people: committed true',\n        'people: trx ended'\n      ])\n\n      seq = []\n\n      await app.service('test').create({})\n\n      assert.deepStrictEqual(seq, [\n        'test: waiting for trx to be committed',\n        'test: another hook',\n        'people: waiting for trx to be committed',\n        'people: another hook',\n        'people: trx ended',\n        'test: committed true',\n        'people: committed true',\n        'test: trx ended'\n      ])\n\n      seq = []\n\n      assert.strictEqual((await app.service('people').find({ paginate: false })).length, 1)\n\n      assert.deepStrictEqual(seq, [\n        'people: waiting for trx to be committed',\n        'people: another hook',\n        'people: committed true',\n        'people: trx ended'\n      ])\n    })\n  })\n\n  describe('associations', () => {\n    const todoService = app.service('todos')\n\n    it('create, query and get with associations, can unambigiously $select', async () => {\n      const dave = await peopleService.create({\n        name: 'Dave',\n        age: 133\n      })\n      const todo = await todoService.create({\n        text: 'Do dishes',\n        personId: dave.id\n      })\n\n      const [found] = await todoService.find({\n        paginate: false,\n        query: {\n          'person.age': { $gt: 100 }\n        }\n      })\n      const got = await todoService.get(todo.id)\n\n      assert.deepStrictEqual(\n        await todoService.get(todo.id, {\n          query: { $select: ['id', 'text'] }\n        }),\n        {\n          id: todo.id,\n          text: todo.text,\n          personName: 'Dave'\n        }\n      )\n      assert.strictEqual(got.personName, dave.name)\n      assert.deepStrictEqual(got, todo)\n      assert.deepStrictEqual(found, todo)\n\n      peopleService.remove(dave.id)\n      todoService.remove(todo.id)\n    })\n  })\n\n  describe('extendedOperators', () => {\n    const extendedService = app.service('people-extended-ops')\n    let testData: Person[]\n\n    beforeEach(async () => {\n      testData = await Promise.all([\n        extendedService.create({\n          name: 'StartWithA',\n          age: 25\n        }),\n        extendedService.create({\n          name: 'MiddleAMiddle',\n          age: 30\n        }),\n        extendedService.create({\n          name: 'EndWithA',\n          age: 35\n        })\n      ])\n    })\n\n    afterEach(async () => {\n      try {\n        for (const item of testData) {\n          await extendedService.remove(item.id)\n        }\n      } catch (error: unknown) {}\n    })\n\n    it('supports custom operators through extendedOperators option', async () => {\n      // Test the $startsWith custom operator\n      const startsWithResults = await extendedService.find({\n        paginate: false,\n        query: {\n          name: {\n            $startsWith: 'Start%' // LIKE operator with % wildcard\n          }\n        }\n      })\n\n      assert.strictEqual(startsWithResults.length, 1)\n      assert.strictEqual(startsWithResults[0].name, 'StartWithA')\n\n      // Test that regular operators still work alongside extended ones\n      const combinedResults = await extendedService.find({\n        paginate: false,\n        query: {\n          $and: [{ name: { $neq: 'EndWithA' } }, { age: { $gt: 26 } }]\n        }\n      })\n\n      assert.strictEqual(combinedResults.length, 1)\n      assert.strictEqual(combinedResults[0].name, 'MiddleAMiddle')\n    })\n  })\n\n  testSuite(app, errors, 'users')\n  testSuite(app, errors, 'people')\n  testSuite(app, errors, 'people-customid', 'customid')\n  testSuite(app, errors, 'people-extended-ops')\n})\n"
  },
  {
    "path": "packages/knex/test/overrides.test.ts",
    "content": "import knex from 'knex'\nimport assert from 'assert'\nimport { feathers, Paginated } from '@feathersjs/feathers'\nimport { KnexAdapterParams, KnexService, transaction } from '../src'\nimport { PaginationOptions } from '@feathersjs/adapter-commons'\n\n// const { transaction } = service.hooks\n\nconst db = knex({\n  client: 'sqlite3',\n  connection: {\n    filename: './db.sqlite'\n  }\n})\n\nconst schemaName = 'overrides'\n\nknex({\n  client: 'sqlite3',\n  connection: {\n    filename: `./${schemaName}.sqlite`\n  }\n})\n\ntype Animal = {\n  id: number\n  ancestor_id: number\n  ancestor_name: string\n  name: string\n}\n\n/**\n * Override the _find() method to manipulate the knex query, and\n * introduce ambiguity by the table to itself.\n */\nclass AnimalService<T = Animal, P extends KnexAdapterParams = KnexAdapterParams> extends KnexService<T> {\n  async _find(params?: P & { paginate?: PaginationOptions }): Promise<Paginated<T>>\n  async _find(params?: P & { paginate: false }): Promise<T[]>\n  async _find(params?: P): Promise<Paginated<T> | T[]>\n  async _find(params: P = {} as P): Promise<Paginated<T> | T[]> {\n    const knexQuery = this.createQuery(params)\n    knexQuery\n      .select('ancestors.name as ancestor_name')\n      .leftJoin('animals as ancestors', 'ancestors.id', '=', 'animals.ancestor_id')\n    params.knex = knexQuery\n    return super._find(params)\n  }\n}\n\nconst animals = new AnimalService({\n  Model: db,\n  name: 'animals',\n  events: ['testing']\n})\n\nfunction clean() {\n  return db.schema.dropTableIfExists(animals.fullName).then(() => {\n    return db.schema.createTable(animals.fullName, (table) => {\n      table.increments('id')\n      table.integer('ancestor_id')\n      table.string('name').notNullable()\n      return table\n    })\n  })\n}\n\ndescribe('Feathers Knex Overridden Method With Self-Join', () => {\n  let ancestor: Animal\n  let animal: Animal\n\n  const app = feathers<{ animals: AnimalService }>()\n    .hooks({\n      before: [transaction.start()],\n      after: [transaction.end()],\n      error: [transaction.rollback()]\n    })\n    .use('animals', animals)\n  const animalService = app.service('animals')\n\n  before(() => {\n    return db.schema.raw(`attach database '${schemaName}.sqlite' as ${schemaName}`)\n  })\n  before(clean)\n  after(clean)\n\n  beforeEach(async () => {\n    ancestor = await animalService.create({\n      name: 'Ape'\n    })\n    animal = await animalService.create({\n      ancestor_id: ancestor.id,\n      name: 'Human'\n    })\n  })\n\n  it('finds properly', async () => {\n    const foundAnimals = await animalService.find({\n      paginate: false,\n      query: {\n        $limit: 1,\n        ancestor_name: 'Ape'\n      }\n    })\n    assert.strictEqual(foundAnimals[0].id, animal.id)\n    assert.strictEqual(foundAnimals[0].name, 'Human')\n    assert.strictEqual(foundAnimals[0].ancestor_name, 'Ape')\n  })\n\n  /**\n   * Previously, any query modified to include joins with ambiguous primary keys\n   * would yield an ambiguous column errors:\n   *   BadRequest: select `animals`.*\n   *   from `animals`\n   *      left join `animals` as `ancestors` on `ancestors`.`id` = `animals`.`ancestor_id`\n   *   where `id` in (2) - SQLITE_ERROR: ambiguous column name: id\n   *\n   * The fix involves explicitly specifying the table to query in the _patch() method\n   */\n  it('patches without ambiguous query', async () => {\n    const newName = 'Homo Sapiens'\n    const patchedAnimal = await animalService.patch(animal.id, { name: newName })\n\n    assert.strictEqual(patchedAnimal.name, newName)\n  })\n\n  it('get the service model (getModel)', async () => {\n    const model = animalService.Model\n    const options = animalService.options\n\n    assert.strictEqual(model, options.Model)\n  })\n})\n"
  },
  {
    "path": "packages/knex/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/koa/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n### Bug Fixes\n\n- **koa:** Ensure .teardown works without a server ([#3234](https://github.com/feathersjs/feathers/issues/3234)) ([818572d](https://github.com/feathersjs/feathers/commit/818572df98456bc3e1a300e879329aa8f849be64))\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n### Bug Fixes\n\n- **koa:** Replace koa-bodyparser with koa-body ([#3093](https://github.com/feathersjs/feathers/issues/3093)) ([2456bf8](https://github.com/feathersjs/feathers/commit/2456bf882c99ae2cddd1a39bffba7e61217fc055))\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n### Bug Fixes\n\n- **koa:** Make Koa app inspectable ([#3069](https://github.com/feathersjs/feathers/issues/3069)) ([4fbbfff](https://github.com/feathersjs/feathers/commit/4fbbfff2a3c625f8e6929e5a09e2cf7b739ffe11))\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n### Bug Fixes\n\n- **koa:** Fix missing dependency on feathers ([#3061](https://github.com/feathersjs/feathers/issues/3061)) ([80dc95f](https://github.com/feathersjs/feathers/commit/80dc95ff85c9074b8f70e3ff71562f18863ef2be))\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n### Bug Fixes\n\n- **transports:** Add remaining middleware for generated apps to Koa and Express ([#2796](https://github.com/feathersjs/feathers/issues/2796)) ([0d5781a](https://github.com/feathersjs/feathers/commit/0d5781a5c72a0cbb2ec8211bfa099f0aefe115a2))\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n### Bug Fixes\n\n- **koa:** Only set error code for Feathers errors ([#2793](https://github.com/feathersjs/feathers/issues/2793)) ([d3ee41e](https://github.com/feathersjs/feathers/commit/d3ee41e27b0ea5d29b344d6584ab03e48d16e2b4))\n\n### Features\n\n- **cli:** Generate full client test suite and improve typed client ([#2788](https://github.com/feathersjs/feathers/issues/2788)) ([57119b6](https://github.com/feathersjs/feathers/commit/57119b6bb2797f7297cf054268a248c093ecd538))\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Bug Fixes\n\n- **core:** Ensure setup and teardown can be overriden and maintain hook functionality ([#2779](https://github.com/feathersjs/feathers/issues/2779)) ([ab580cb](https://github.com/feathersjs/feathers/commit/ab580cbcaa68d19144d86798c13bf564f9d424a6))\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n### Features\n\n- Add CORS support to oAuth, Express, Koa and generated application ([#2744](https://github.com/feathersjs/feathers/issues/2744)) ([fd218f2](https://github.com/feathersjs/feathers/commit/fd218f289f8ca4c101e9938e8683e2efef6e8131))\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Features\n\n- **cli:** Add support for JavaScript to the new CLI ([#2668](https://github.com/feathersjs/feathers/issues/2668)) ([ebac587](https://github.com/feathersjs/feathers/commit/ebac587f7d00dc7607c3f546352d79f79b89a5d4))\n- **cli:** Initial Feathers v5 CLI and Pinion generator ([#2578](https://github.com/feathersjs/feathers/issues/2578)) ([7f59ae7](https://github.com/feathersjs/feathers/commit/7f59ae7f1471895ba8a82aa4702f1a23f71b7682))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n### Features\n\n- **core:** Add app.teardown functionality ([#2570](https://github.com/feathersjs/feathers/issues/2570)) ([fcdf524](https://github.com/feathersjs/feathers/commit/fcdf524ae1995bb59265d39f12e98b7794bed023))\n- **core:** Finalize app.teardown() functionality ([#2584](https://github.com/feathersjs/feathers/issues/2584)) ([1a166f3](https://github.com/feathersjs/feathers/commit/1a166f3ded811ecacf0ae8cb67880bc9fa2eeafa))\n- **transport-commons:** add `context.http.response` ([#2524](https://github.com/feathersjs/feathers/issues/2524)) ([5bc9d44](https://github.com/feathersjs/feathers/commit/5bc9d447043c2e2b742c73ed28ecf3b3264dd9e5))\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n### Features\n\n- **express, koa:** make transports similar ([#2486](https://github.com/feathersjs/feathers/issues/2486)) ([26aa937](https://github.com/feathersjs/feathers/commit/26aa937c114fb8596dfefc599b1f53cead69c159))\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n### Features\n\n- **core:** add `context.http` and move `statusCode` there ([#2496](https://github.com/feathersjs/feathers/issues/2496)) ([b701bf7](https://github.com/feathersjs/feathers/commit/b701bf77fb83048aa1dffa492b3d77dd53f7b72b))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/koa\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n### Bug Fixes\n\n- **koa:** Throw a NotFound Feathers error on missing paths ([#2415](https://github.com/feathersjs/feathers/issues/2415)) ([e013f98](https://github.com/feathersjs/feathers/commit/e013f98315d550ced6eacffd615c61bb0912b4ba))\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- **koa:** Use extended query parser for compatibility ([#2397](https://github.com/feathersjs/feathers/issues/2397)) ([b2944ba](https://github.com/feathersjs/feathers/commit/b2944bac3ec6d5ecc80dc518cd4e58093692db74))\n\n### Features\n\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n### Features\n\n- **koa:** KoaJS transport adapter ([#2315](https://github.com/feathersjs/feathers/issues/2315)) ([2554b57](https://github.com/feathersjs/feathers/commit/2554b57cf05731df58feeba9c12faab18e442107))\n"
  },
  {
    "path": "packages/koa/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2018 Feathers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/koa/README.md",
    "content": "# @feathersjs/koa\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/koa.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/koa)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Feathers KoaJS framework bindings and REST provider\n\n## Installation\n\n```\nnpm install @feathersjs/koa --save\n```\n\n## Documentation\n\nRefer to the [Feathers Koa API documentation](https://feathersjs.com/api/koa.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/koa/package.json",
    "content": "{\n  \"name\": \"@feathersjs/koa\",\n  \"description\": \"Feathers KoaJS framework bindings and REST provider\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"koajs\"\n  ],\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/koa\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 14\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/authentication\": \"^5.0.42\",\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@feathersjs/transport-commons\": \"^5.0.42\",\n    \"@koa/cors\": \"^5.0.0\",\n    \"@types/koa\": \"^3.0.1\",\n    \"@types/koa-qs\": \"^2.0.5\",\n    \"@types/koa-static\": \"^4.0.4\",\n    \"@types/koa__cors\": \"^5.0.1\",\n    \"koa\": \"^3.1.2\",\n    \"koa-body\": \"^7.0.1\",\n    \"koa-compose\": \"^4.1.0\",\n    \"koa-qs\": \"^3.0.0\",\n    \"koa-static\": \"^5.0.0\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/authentication-local\": \"^5.0.42\",\n    \"@feathersjs/memory\": \"^5.0.42\",\n    \"@feathersjs/tests\": \"^5.0.42\",\n    \"@types/koa-compose\": \"^3.2.9\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"axios\": \"^1.13.6\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/koa/src/authentication.ts",
    "content": "import { Application, HookContext } from '@feathersjs/feathers'\nimport { createDebug } from '@feathersjs/commons'\nimport { authenticate as AuthenticateHook } from '@feathersjs/authentication'\n\nimport { Middleware } from './declarations'\n\nconst debug = createDebug('@feathersjs/koa/authentication')\n\nexport type AuthenticationSettings = {\n  service?: string\n  strategies?: string[]\n}\n\nexport function parseAuthentication(settings: AuthenticationSettings = {}): Middleware {\n  return async (ctx, next) => {\n    const app = ctx.app\n    const service = app.defaultAuthentication?.(settings.service)\n\n    if (!service) {\n      return next()\n    }\n\n    const config = service.configuration\n    const authStrategies = settings.strategies || config.parseStrategies || config.authStrategies || []\n\n    if (authStrategies.length === 0) {\n      debug('No `authStrategies` or `parseStrategies` found in authentication configuration')\n      return next()\n    }\n\n    const authentication = await service.parse(ctx.req, ctx.res, ...authStrategies)\n\n    if (authentication) {\n      debug('Parsed authentication from HTTP header', authentication)\n      ctx.feathers = { ...ctx.feathers, authentication }\n    }\n\n    return next()\n  }\n}\n\nexport function authenticate(settings: string | AuthenticationSettings, ...strategies: string[]): Middleware {\n  const hook = AuthenticateHook(settings, ...strategies)\n\n  return async (ctx, next) => {\n    const app = ctx.app as Application\n    const params = ctx.feathers\n    const context = { app, params } as HookContext\n\n    await hook(context)\n\n    ctx.feathers = context.params\n\n    return next()\n  }\n}\n"
  },
  {
    "path": "packages/koa/src/declarations.ts",
    "content": "import Koa, { Next } from 'koa'\nimport { Server } from 'http'\nimport { Application as FeathersApplication, HookContext, Params, RouteLookup } from '@feathersjs/feathers'\nimport '@feathersjs/authentication'\n\nexport type ApplicationAddons = {\n  server: Server\n  listen(port?: number, ...args: any[]): Promise<Server>\n}\n\nexport type Application<T = any, C = any> = Omit<Koa, 'listen'> &\n  FeathersApplication<T, C> &\n  ApplicationAddons\n\nexport type FeathersKoaContext<A = Application> = Koa.Context & {\n  app: A\n}\n\nexport type Middleware<A = Application> = (context: FeathersKoaContext<A>, next: Next) => any\n\ndeclare module '@feathersjs/feathers/lib/declarations' {\n  interface ServiceOptions {\n    koa?: {\n      before?: Middleware[]\n      after?: Middleware[]\n      composed?: Middleware\n    }\n  }\n}\n\ndeclare module 'koa' {\n  interface ExtendableContext {\n    feathers?: Partial<Params>\n    lookup?: RouteLookup\n    hook?: HookContext\n  }\n}\n"
  },
  {
    "path": "packages/koa/src/handlers.ts",
    "content": "import { FeathersError, NotFound } from '@feathersjs/errors'\nimport { FeathersKoaContext } from './declarations'\n\nexport const errorHandler = () => async (ctx: FeathersKoaContext, next: () => Promise<any>) => {\n  try {\n    await next()\n\n    if (ctx.body === undefined) {\n      throw new NotFound(`Path ${ctx.path} not found`)\n    }\n  } catch (error: any) {\n    ctx.response.status = error instanceof FeathersError ? error.code : 500\n    ctx.body =\n      typeof error.toJSON === 'function'\n        ? error.toJSON()\n        : {\n            message: error.message\n          }\n  }\n}\n"
  },
  {
    "path": "packages/koa/src/index.ts",
    "content": "import Koa from 'koa'\nimport koaQs from 'koa-qs'\nimport { Application as FeathersApplication } from '@feathersjs/feathers'\nimport { routing } from '@feathersjs/transport-commons'\nimport { createDebug } from '@feathersjs/commons'\nimport { koaBody as bodyParser } from 'koa-body'\nimport cors from '@koa/cors'\nimport serveStatic from 'koa-static'\n\nimport { Application } from './declarations'\n\nexport { Koa, bodyParser, cors, serveStatic }\nexport * from './authentication'\nexport * from './declarations'\nexport * from './handlers'\nexport * from './rest'\n\nconst debug = createDebug('@feathersjs/koa')\n\nexport function koa<S = any, C = any>(\n  feathersApp?: FeathersApplication<S, C>,\n  koaApp: Koa = new Koa()\n): Application<S, C> {\n  if (!feathersApp) {\n    return koaApp as any\n  }\n\n  if (typeof feathersApp.setup !== 'function') {\n    throw new Error('@feathersjs/koa requires a valid Feathers application instance')\n  }\n\n  const app = feathersApp as any as Application<S, C>\n  const { listen: koaListen, use: koaUse } = koaApp\n  const { use: feathersUse, teardown: feathersTeardown } = feathersApp\n\n  Object.assign(app, {\n    use(location: string | Koa.Middleware, ...args: any[]) {\n      if (typeof location === 'string') {\n        return (feathersUse as any).call(this, location, ...args)\n      }\n\n      return koaUse.call(this, location)\n    },\n\n    async listen(port?: number, ...args: any[]) {\n      const server = koaListen.call(this, port, ...args)\n\n      this.server = server\n      await this.setup(server)\n      debug('Feathers application listening')\n\n      return server\n    },\n\n    async teardown(server?: any) {\n      return feathersTeardown.call(this, server).then(\n        () =>\n          new Promise((resolve, reject) => {\n            if (this.server) {\n              this.server.close((e) => (e ? reject(e) : resolve(this)))\n            } else {\n              resolve(this)\n            }\n          })\n      )\n    }\n  } as Application)\n\n  const appDescriptors = {\n    ...Object.getOwnPropertyDescriptors(Object.getPrototypeOf(app)),\n    ...Object.getOwnPropertyDescriptors(app)\n  }\n  const newDescriptors = {\n    ...Object.getOwnPropertyDescriptors(Object.getPrototypeOf(koaApp)),\n    ...Object.getOwnPropertyDescriptors(koaApp)\n  }\n\n  // Copy all non-existing properties (including non-enumerables)\n  // that don't already exist on the Express app\n  Object.keys(newDescriptors).forEach((prop) => {\n    const appProp = appDescriptors[prop]\n    const newProp = newDescriptors[prop]\n\n    if (appProp === undefined && newProp !== undefined) {\n      Object.defineProperty(app, prop, newProp)\n    }\n  })\n\n  koaQs(app as any)\n\n  Object.getOwnPropertySymbols(koaApp).forEach((symbol) => {\n    const target = app as any\n    const source = koaApp as any\n\n    target[symbol] = source[symbol]\n  })\n\n  // This reinitializes hooks\n  app.setup = feathersApp.setup as any\n  app.teardown = feathersApp.teardown as any\n\n  app.configure(routing() as any)\n  app.use((ctx, next) => {\n    ctx.feathers = { ...ctx.feathers, provider: 'rest' }\n    return next()\n  })\n\n  return app\n}\n"
  },
  {
    "path": "packages/koa/src/rest.ts",
    "content": "import compose from 'koa-compose'\nimport { http } from '@feathersjs/transport-commons'\nimport { createDebug } from '@feathersjs/commons'\nimport { getServiceOptions, defaultServiceMethods, createContext } from '@feathersjs/feathers'\nimport { MethodNotAllowed } from '@feathersjs/errors'\n\nimport { Application, Middleware } from './declarations'\nimport { AuthenticationSettings, parseAuthentication } from './authentication'\n\nconst debug = createDebug('@feathersjs/koa/rest')\n\nconst serviceMiddleware = (): Middleware => {\n  return async (ctx, next) => {\n    const { query, headers, path, body: data, method: httpMethod } = ctx.request as any\n    const methodOverride = ctx.request.headers[http.METHOD_HEADER] as string | undefined\n\n    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n    const { service, params: { __id: id = null, ...route } = {} } = ctx.lookup!\n    const method = http.getServiceMethod(httpMethod, id, methodOverride)\n    const { methods } = getServiceOptions(service)\n\n    debug(`Found service for path ${path}, attempting to run '${method}' service method`)\n\n    if (!methods.includes(method) || defaultServiceMethods.includes(methodOverride)) {\n      const error = new MethodNotAllowed(`Method \\`${method}\\` is not supported by this endpoint.`)\n      ctx.response.status = error.code\n      throw error\n    }\n\n    const createArguments = http.argumentsFor[method as 'get'] || http.argumentsFor.default\n    const params = { query, headers, route, ...ctx.feathers }\n    const args = createArguments({ id, data, params })\n    const contextBase = createContext(service, method, { http: {} })\n    ctx.hook = contextBase\n\n    const context = await (service as any)[method](...args, contextBase)\n    ctx.hook = context\n\n    const response = http.getResponse(context)\n    ctx.status = response.status\n    ctx.set(response.headers)\n    ctx.body = response.body\n\n    return next()\n  }\n}\n\nconst servicesMiddleware = (): Middleware => {\n  return async (ctx, next) => {\n    const app = ctx.app\n    const lookup = app.lookup(ctx.request.path)\n\n    if (!lookup) {\n      return next()\n    }\n\n    ctx.lookup = lookup\n\n    const options = getServiceOptions(lookup.service)\n    const middleware = options.koa.composed\n\n    return middleware(ctx, next)\n  }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nexport const formatter: Middleware = (_ctx, _next) => {}\n\nexport type RestOptions = {\n  formatter?: Middleware\n  authentication?: AuthenticationSettings\n}\n\nexport const rest = (options?: RestOptions | Middleware) => {\n  options = typeof options === 'function' ? { formatter: options } : options || {}\n\n  const formatterMiddleware = options.formatter || formatter\n  const authenticationOptions = options.authentication\n\n  return (app: Application) => {\n    app.use(parseAuthentication(authenticationOptions))\n    app.use(servicesMiddleware())\n\n    app.mixins.push((_service, _path, options) => {\n      const { koa: { before = [], after = [] } = {} } = options\n\n      const middlewares = [].concat(before, serviceMiddleware(), after, formatterMiddleware)\n      const middleware = compose(middlewares)\n\n      options.koa ||= {}\n      options.koa.composed = middleware\n    })\n  }\n}\n"
  },
  {
    "path": "packages/koa/test/app.fixture.ts",
    "content": "import { memory } from '@feathersjs/memory'\nimport { feathers, Params, HookContext } from '@feathersjs/feathers'\nimport { authenticate, AuthenticationService, JWTStrategy } from '@feathersjs/authentication'\nimport { LocalStrategy, hooks } from '@feathersjs/authentication-local'\n\nimport { koa, rest, bodyParser, errorHandler, cors } from '../src'\n\nconst { protect, hashPassword } = hooks\nconst app = koa(feathers())\nconst authService = new AuthenticationService(app)\n\napp.use(errorHandler())\napp.use(cors())\napp.use(bodyParser())\napp.configure(rest())\napp.set('authentication', {\n  entity: 'user',\n  service: 'users',\n  secret: 'supersecret',\n  authStrategies: ['local', 'jwt'],\n  parseStrategies: ['jwt'],\n  local: {\n    usernameField: 'email',\n    passwordField: 'password'\n  }\n})\n\nauthService.register('jwt', new JWTStrategy())\nauthService.register('local', new LocalStrategy())\n\napp.use('/authentication', authService)\napp.use(\n  '/users',\n  memory({\n    paginate: {\n      default: 10,\n      max: 20\n    }\n  })\n)\n\napp.service('users').hooks({\n  before: {\n    create: [hashPassword('password')]\n  },\n  after: {\n    all: [protect('password')],\n    get: [\n      (context: HookContext) => {\n        if (context.params.provider) {\n          context.result.fromGet = true\n        }\n\n        return context\n      }\n    ]\n  }\n})\n\napp.use('/dummy', {\n  async get(id: string, params: Params) {\n    return { id, params }\n  }\n})\n\napp.service('dummy').hooks({\n  before: [authenticate('jwt')]\n})\n\nexport default app\n"
  },
  {
    "path": "packages/koa/test/authentication.test.ts",
    "content": "import { strict as assert } from 'assert'\nimport _axios from 'axios'\nimport { AuthenticationResult } from '@feathersjs/authentication'\n\nimport app from './app.fixture'\n\nconst axios = _axios.create({\n  baseURL: 'http://localhost:9776/'\n})\n\ndescribe('@feathersjs/koa/authentication', () => {\n  const email = 'koatest@authentication.com'\n  const password = 'superkoa'\n\n  let authResult: AuthenticationResult\n  let user: any\n\n  before(async () => {\n    await app.listen(9776)\n    user = await app.service('users').create({ email, password })\n    authResult = (\n      await axios.post<any>('/authentication', {\n        strategy: 'local',\n        password,\n        email\n      })\n    ).data\n  })\n\n  after(() => app.teardown())\n\n  describe('service authentication', () => {\n    it('successful local authentication', () => {\n      assert.ok(authResult.accessToken)\n      assert.strictEqual(authResult.user.email, email)\n      assert.strictEqual(authResult.user.password, undefined)\n    })\n\n    it('local authentication with wrong password fails', async () => {\n      try {\n        await axios.post<any>('/authentication', {\n          strategy: 'local',\n          password: 'wrong',\n          email\n        })\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        const { data } = error.response\n        assert.strictEqual(data.name, 'NotAuthenticated')\n        assert.strictEqual(data.message, 'Invalid login')\n      }\n    })\n\n    it('authenticating with JWT works but returns same accessToken', async () => {\n      const { accessToken } = authResult\n\n      const { data } = await axios.post<any>('/authentication', {\n        strategy: 'jwt',\n        accessToken\n      })\n\n      assert.strictEqual(data.accessToken, accessToken)\n      assert.strictEqual(data.authentication.strategy, 'jwt')\n      assert.strictEqual(data.authentication.payload.sub, user.id.toString())\n      assert.strictEqual(data.user.email, email)\n    })\n\n    it('can make a protected request with Authorization header', async () => {\n      const { accessToken } = authResult\n\n      const { data } = await axios.get<any>('/dummy/dave?user[name]=thing&user[message]=hi', {\n        headers: {\n          Authorization: accessToken\n        }\n      })\n\n      assert.strictEqual(data.id, 'dave')\n      assert.deepStrictEqual(data.params.query, {\n        user: {\n          name: 'thing',\n          message: 'hi'\n        }\n      })\n      assert.deepStrictEqual(data.params.user, user)\n      assert.strictEqual(data.params.authentication.accessToken, accessToken)\n    })\n\n    it('errors when there are no authStrategies and parseStrategies', async () => {\n      const { accessToken } = authResult\n\n      app.get('authentication').authStrategies = []\n      delete app.get('authentication').parseStrategies\n\n      try {\n        await axios.get<any>('/dummy/dave', {\n          headers: {\n            Authorization: accessToken\n          }\n        })\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.response.data.name, 'NotAuthenticated')\n        app.get('authentication').authStrategies = ['jwt', 'local']\n      }\n    })\n\n    it('can make a protected request with Authorization header and bearer scheme', () => {\n      const { accessToken } = authResult\n\n      return axios\n        .get<any>('/dummy/dave', {\n          headers: {\n            Authorization: ` Bearer: ${accessToken}`\n          }\n        })\n        .then((res) => {\n          const {\n            data,\n            data: { params }\n          } = res\n\n          assert.strictEqual(data.id, 'dave')\n          assert.deepStrictEqual(params.user, user)\n          assert.strictEqual(params.authentication.accessToken, accessToken)\n        })\n    })\n  })\n})\n"
  },
  {
    "path": "packages/koa/test/index.test.ts",
    "content": "import { strict as assert } from 'assert'\nimport Koa from 'koa'\nimport axios from 'axios'\nimport { ApplicationHookMap, feathers, Id } from '@feathersjs/feathers'\nimport { Service, restTests } from '@feathersjs/tests'\nimport { koa, rest, Application, bodyParser, errorHandler } from '../src'\n\ndescribe('@feathersjs/koa', () => {\n  let app: Application\n\n  before(async () => {\n    app = koa(feathers())\n    app.use(errorHandler())\n    app.use(bodyParser())\n    app.use(async (ctx, next) => {\n      if (ctx.request.path === '/middleware') {\n        ctx.body = {\n          feathers: ctx.feathers,\n          message: 'Hello from middleware'\n        }\n      } else {\n        await next()\n      }\n    })\n    app.configure(rest())\n    app.use('/', new Service())\n    app.use('todo', new Service(), {\n      koa: {\n        after: [\n          async (ctx, next) => {\n            const body = ctx.body as any\n\n            if (body.id === 'custom-middleware') {\n              body.description = 'Description from custom middleware'\n            }\n\n            await next()\n          }\n        ]\n      },\n      methods: ['get', 'find', 'create', 'update', 'patch', 'remove', 'customMethod']\n    })\n\n    app.hooks({\n      setup: [\n        async (context, next) => {\n          assert.ok(context.app)\n          await next()\n        }\n      ],\n      teardown: [\n        async (context, next) => {\n          assert.ok(context.app)\n          await next()\n        }\n      ]\n    } as ApplicationHookMap<Application>)\n\n    await app.listen(8465)\n  })\n\n  after(() => app.teardown())\n\n  it('throws an error when initialized with invalid application', () => {\n    try {\n      koa({} as Application)\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.equal(error.message, '@feathersjs/koa requires a valid Feathers application instance')\n    }\n  })\n\n  it('returns Koa instance when no Feathers app is passed', () => {\n    assert.ok(koa() instanceof Koa)\n  })\n\n  it('Koa wrapped and context.app are the same', async () => {\n    const app = koa(feathers())\n\n    app.use('/test', {\n      async get(id: Id) {\n        return { id }\n      }\n    })\n\n    app.service('test').hooks({\n      before: {\n        get: [\n          (context) => {\n            assert.ok(context.app === app)\n          }\n        ]\n      }\n    })\n\n    assert.deepStrictEqual(await app.service('test').get('testing'), {\n      id: 'testing'\n    })\n  })\n\n  it('starts as a Koa and Feathers application', async () => {\n    const { data } = await axios.get<any>('http://localhost:8465/middleware')\n    const todo = await app.service('todo').get('dishes', {\n      query: {}\n    })\n\n    assert.deepEqual(data, {\n      message: 'Hello from middleware',\n      feathers: {\n        provider: 'rest'\n      }\n    })\n    assert.deepEqual(todo, {\n      id: 'dishes',\n      description: 'You have to do dishes!'\n    })\n  })\n\n  it('supports custom service middleware', async () => {\n    const { data } = await axios.get<any>('http://localhost:8465/todo/custom-middleware')\n\n    assert.deepStrictEqual(data, {\n      id: 'custom-middleware',\n      description: 'Description from custom middleware'\n    })\n  })\n\n  it('works with custom methods that are allowed', async () => {\n    const { data } = await axios.post<any>(\n      'http://localhost:8465/todo',\n      {\n        message: 'Custom hello'\n      },\n      {\n        headers: {\n          'X-Service-Method': 'customMethod'\n        }\n      }\n    )\n\n    assert.deepStrictEqual(data, {\n      data: { message: 'Custom hello' },\n      method: 'customMethod',\n      provider: 'rest'\n    })\n\n    await assert.rejects(\n      () =>\n        axios.post<any>(\n          'http://localhost:8465/todo',\n          {},\n          {\n            headers: {\n              'X-Service-Method': 'internalMethod'\n            }\n          }\n        ),\n      (error: any) => {\n        const { data } = error.response\n\n        assert.strictEqual(data.code, 405)\n        assert.strictEqual(data.message, 'Method `internalMethod` is not supported by this endpoint.')\n\n        return true\n      }\n    )\n  })\n\n  it('throws a 404 NotFound JSON error', async () => {\n    await assert.rejects(\n      () =>\n        axios.post<any>(\n          'http://localhost:8465/no/where',\n          {},\n          {\n            headers: {\n              'X-Service-Method': 'internalMethod',\n              Accept: 'application/json'\n            }\n          }\n        ),\n      (error: any) => {\n        const { data } = error.response\n\n        assert.deepStrictEqual(data, {\n          name: 'NotFound',\n          message: 'Path /no/where not found',\n          code: 404,\n          className: 'not-found'\n        })\n\n        return true\n      }\n    )\n  })\n\n  it('.teardown closes http server', async () => {\n    const app = koa(feathers())\n    let called = false\n\n    const server = await app.listen(8787)\n\n    server.on('close', () => {\n      called = true\n    })\n\n    await app.teardown()\n    assert.ok(called)\n  })\n\n  it('.teardown works without server (#3224)', async () => {\n    const app = koa(feathers())\n\n    await app.teardown()\n  })\n\n  restTests('Services', 'todo', 8465)\n  restTests('Root service', '/', 8465)\n})\n"
  },
  {
    "path": "packages/koa/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/memory/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- @feathersjs/memory update with query ([#3617](https://github.com/feathersjs/feathers/issues/3617)) ([4c6caa2](https://github.com/feathersjs/feathers/commit/4c6caa27e9af1312718d0c233a0c35f7739ac553))\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n### Bug Fixes\n\n- allow \\_patch to modify the entire base schema ([#3300](https://github.com/feathersjs/feathers/issues/3300)) ([0f41622](https://github.com/feathersjs/feathers/commit/0f41622307589b3a0b62ac411a73e6a601bda171))\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n- **memory:** Ensure correct pagination totals ([#3307](https://github.com/feathersjs/feathers/issues/3307)) ([c59e1b8](https://github.com/feathersjs/feathers/commit/c59e1b80cb43571077b035ab2bf0b44f9daa5ab8))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n- **memory:** Fix memory adapter readme ([#3153](https://github.com/feathersjs/feathers/issues/3153)) ([a9d826a](https://github.com/feathersjs/feathers/commit/a9d826a7dbe7df4501fbf82a47d2c3a77ca9e0c0))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n### Bug Fixes\n\n- **memory/mongodb:** $select as only property & force 'id' in '$select' ([#3081](https://github.com/feathersjs/feathers/issues/3081)) ([fbe3cf5](https://github.com/feathersjs/feathers/commit/fbe3cf5199e102b5aeda2ae33828d5034df3d105))\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Features\n\n- **adapter:** Add patch data type to adapters and refactor AdapterBase usage ([#2906](https://github.com/feathersjs/feathers/issues/2906)) ([9ddc2e6](https://github.com/feathersjs/feathers/commit/9ddc2e6b028f026f939d6af68125847e5c6734b4))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n### Bug Fixes\n\n- **memory:** Use for loop in \\_find() for better performance ([#2844](https://github.com/feathersjs/feathers/issues/2844)) ([d6ee5f1](https://github.com/feathersjs/feathers/commit/d6ee5f1c869f0c65cb470130f35956a52356e5c3))\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n### Features\n\n- **cli:** Generate full client test suite and improve typed client ([#2788](https://github.com/feathersjs/feathers/issues/2788)) ([57119b6](https://github.com/feathersjs/feathers/commit/57119b6bb2797f7297cf054268a248c093ecd538))\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Features\n\n- **cli:** Initial Feathers v5 CLI and Pinion generator ([#2578](https://github.com/feathersjs/feathers/issues/2578)) ([7f59ae7](https://github.com/feathersjs/feathers/commit/7f59ae7f1471895ba8a82aa4702f1a23f71b7682))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Bug Fixes\n\n- **adapter-commons:** Clarify adapter query filtering ([#2607](https://github.com/feathersjs/feathers/issues/2607)) ([2dac771](https://github.com/feathersjs/feathers/commit/2dac771b0a3298d6dd25994d05186701b0617718))\n\n### Features\n\n- **mongodb:** Add feathers-mongodb adapter as @feathersjs/mongodb ([#2610](https://github.com/feathersjs/feathers/issues/2610)) ([6d43734](https://github.com/feathersjs/feathers/commit/6d43734a53db02c435cafc52a22dca414e5d0940))\n- **typescript:** Improve adapter typings ([#2605](https://github.com/feathersjs/feathers/issues/2605)) ([3b2ca0a](https://github.com/feathersjs/feathers/commit/3b2ca0a6a8e03e8390272c4d7e930b4bffdaacf5))\n- **typescript:** Improve params and query typeability ([#2600](https://github.com/feathersjs/feathers/issues/2600)) ([df28b76](https://github.com/feathersjs/feathers/commit/df28b7619161f1df5e700326f52cca1a92dc5d28))\n\n### BREAKING CHANGES\n\n- **adapter-commons:** Changes the common adapter base class to use `sanitizeQuery` and `sanitizeData`\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n### Bug Fixes\n\n- **adapter-tests:** Add tests for pagination in multi updates ([#2472](https://github.com/feathersjs/feathers/issues/2472)) ([98a811a](https://github.com/feathersjs/feathers/commit/98a811ac605575ff812a08d0504729a5efe7a69c))\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n### Features\n\n- **schema:** Initial version of schema definitions and resolvers ([#2441](https://github.com/feathersjs/feathers/issues/2441)) ([c57a5cd](https://github.com/feathersjs/feathers/commit/c57a5cd56699a121647be4506d8f967e6d72ecae))\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- Update database adapter common repository urls ([#2380](https://github.com/feathersjs/feathers/issues/2380)) ([3f4db68](https://github.com/feathersjs/feathers/commit/3f4db68d6700c7d9023ecd17d0d39893f75a19fd))\n\n### Features\n\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n- **typescript:** Allow to pass generic service options to adapter services ([#2392](https://github.com/feathersjs/feathers/issues/2392)) ([f9431f2](https://github.com/feathersjs/feathers/commit/f9431f242354f804cafb835519f98dd405ac4f0b))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n### Features\n\n- **koa:** KoaJS transport adapter ([#2315](https://github.com/feathersjs/feathers/issues/2315)) ([2554b57](https://github.com/feathersjs/feathers/commit/2554b57cf05731df58feeba9c12faab18e442107))\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n**Note:** Version bump only for package @feathersjs/memory\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n### Features\n\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n### Features\n\n- **memory:** Move feathers-memory into @feathersjs/memory ([#2153](https://github.com/feathersjs/feathers/issues/2153)) ([dd61fe3](https://github.com/feathersjs/feathers/commit/dd61fe371fb0502f78b8ccbe1f45a030e31ecff6))\n\n# Change Log\n\n## [v4.1.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v4.1.0) (2019-10-07)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v4.0.1...v4.1.0)\n\n**Merged pull requests:**\n\n- Update all dependencies [\\#104](https://github.com/feathersjs-ecosystem/feathers-memory/pull/104) ([daffl](https://github.com/daffl))\n\n## [v4.0.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v4.0.1) (2019-09-29)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v4.0.0...v4.0.1)\n\n**Closed issues:**\n\n- An in-range update of @types/node is breaking the build 🚨 [\\#101](https://github.com/feathersjs-ecosystem/feathers-memory/issues/101)\n- An in-range update of webpack is breaking the build 🚨 [\\#98](https://github.com/feathersjs-ecosystem/feathers-memory/issues/98)\n\n**Merged pull requests:**\n\n- Pass entity type to AdapterService\\<T\\> [\\#103](https://github.com/feathersjs-ecosystem/feathers-memory/pull/103) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#102](https://github.com/feathersjs-ecosystem/feathers-memory/pull/102) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update dtslint to the latest version 🚀 [\\#100](https://github.com/feathersjs-ecosystem/feathers-memory/pull/100) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Greenkeeper/webpack 4.36.1 [\\#99](https://github.com/feathersjs-ecosystem/feathers-memory/pull/99) ([daffl](https://github.com/daffl))\n\n## [v4.0.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v4.0.0) (2019-07-05)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v3.0.2...v4.0.0)\n\n**Merged pull requests:**\n\n- Add TypeScript definitions and upgrade to Feathers 4 [\\#97](https://github.com/feathersjs-ecosystem/feathers-memory/pull/97) ([daffl](https://github.com/daffl))\n- Update mocha to the latest version 🚀 [\\#94](https://github.com/feathersjs-ecosystem/feathers-memory/pull/94) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.0.2](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v3.0.2) (2019-01-24)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v3.0.1...v3.0.2)\n\n**Closed issues:**\n\n- Multiple patch records [\\#92](https://github.com/feathersjs-ecosystem/feathers-memory/issues/92)\n\n**Merged pull requests:**\n\n- Allow patch to update prop that is within the query [\\#93](https://github.com/feathersjs-ecosystem/feathers-memory/pull/93) ([Mattchewone](https://github.com/Mattchewone))\n- Add new tests [\\#91](https://github.com/feathersjs-ecosystem/feathers-memory/pull/91) ([daffl](https://github.com/daffl))\n- Update @feathersjs/adapter-commons to the latest version 🚀 [\\#90](https://github.com/feathersjs-ecosystem/feathers-memory/pull/90) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.0.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v3.0.1) (2018-12-29)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v3.0.0...v3.0.1)\n\n**Merged pull requests:**\n\n- Add default params to hook-less methods [\\#89](https://github.com/feathersjs-ecosystem/feathers-memory/pull/89) ([daffl](https://github.com/daffl))\n\n## [v3.0.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v3.0.0) (2018-12-17)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v2.2.0...v3.0.0)\n\n**Closed issues:**\n\n- An in-range update of webpack is breaking the build 🚨 [\\#84](https://github.com/feathersjs-ecosystem/feathers-memory/issues/84)\n- An in-range update of @feathersjs/errors is breaking the build 🚨 [\\#83](https://github.com/feathersjs-ecosystem/feathers-memory/issues/83)\n\n**Merged pull requests:**\n\n- Update to @feathersjs/adapter-commons and drop Node 6 [\\#88](https://github.com/feathersjs-ecosystem/feathers-memory/pull/88) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#87](https://github.com/feathersjs-ecosystem/feathers-memory/pull/87) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update all dependencies and Webpack build [\\#85](https://github.com/feathersjs-ecosystem/feathers-memory/pull/85) ([daffl](https://github.com/daffl))\n- Update babel-loader to the latest version 🚀 [\\#81](https://github.com/feathersjs-ecosystem/feathers-memory/pull/81) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.2.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v2.2.0) (2018-08-26)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v2.1.3...v2.2.0)\n\n**Closed issues:**\n\n- Previously functional batch service no longer works when creating in-memory service [\\#77](https://github.com/feathersjs-ecosystem/feathers-memory/issues/77)\n\n**Merged pull requests:**\n\n- Remove cloneDeep dependency [\\#80](https://github.com/feathersjs-ecosystem/feathers-memory/pull/80) ([daffl](https://github.com/daffl))\n- Fix cloning of instances [\\#79](https://github.com/feathersjs-ecosystem/feathers-memory/pull/79) ([homerjam](https://github.com/homerjam))\n- Update sift to the latest version 🚀 [\\#76](https://github.com/feathersjs-ecosystem/feathers-memory/pull/76) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.1.3](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v2.1.3) (2018-06-11)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v2.1.2...v2.1.3)\n\n**Closed issues:**\n\n- Use with create-react-app [\\#74](https://github.com/feathersjs-ecosystem/feathers-memory/issues/74)\n\n**Merged pull requests:**\n\n- Transpile all Feathers modules for distributable [\\#75](https://github.com/feathersjs-ecosystem/feathers-memory/pull/75) ([saiichihashimoto](https://github.com/saiichihashimoto))\n- Update shx to the latest version 🚀 [\\#73](https://github.com/feathersjs-ecosystem/feathers-memory/pull/73) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.1.2](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v2.1.2) (2018-06-03)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v2.1.1...v2.1.2)\n\n**Merged pull requests:**\n\n- Update uberproto to the latest version 🚀 [\\#72](https://github.com/feathersjs-ecosystem/feathers-memory/pull/72) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update clone-deep to the latest version 🚀 [\\#70](https://github.com/feathersjs-ecosystem/feathers-memory/pull/70) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.1.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v2.1.1) (2018-03-07)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v2.1.0...v2.1.1)\n\n**Closed issues:**\n\n- Why are all the data deleted after the server is rebooted? [\\#68](https://github.com/feathersjs-ecosystem/feathers-memory/issues/68)\n\n**Merged pull requests:**\n\n- Update webpack to the latest version 🚀 [\\#69](https://github.com/feathersjs-ecosystem/feathers-memory/pull/69) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update clone-deep to the latest version 🚀 [\\#67](https://github.com/feathersjs-ecosystem/feathers-memory/pull/67) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update mocha to the latest version 🚀 [\\#66](https://github.com/feathersjs-ecosystem/feathers-memory/pull/66) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update semistandard to the latest version 🚀 [\\#65](https://github.com/feathersjs-ecosystem/feathers-memory/pull/65) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.1.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v2.1.0) (2017-12-03)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v2.0.0...v2.1.0)\n\n**Merged pull requests:**\n\n- Use namespaced module name for exporting [\\#64](https://github.com/feathersjs-ecosystem/feathers-memory/pull/64) ([daffl](https://github.com/daffl))\n\n## [v2.0.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v2.0.0) (2017-12-03)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v1.3.1...v2.0.0)\n\n**Merged pull requests:**\n\n- Client build [\\#63](https://github.com/feathersjs-ecosystem/feathers-memory/pull/63) ([daffl](https://github.com/daffl))\n- Upgrade to Feathers Buzzard \\(v3\\) [\\#62](https://github.com/feathersjs-ecosystem/feathers-memory/pull/62) ([daffl](https://github.com/daffl))\n- Update to new plugin infrastructure [\\#61](https://github.com/feathersjs-ecosystem/feathers-memory/pull/61) ([daffl](https://github.com/daffl))\n- Update clone-deep to the latest version 🚀 [\\#60](https://github.com/feathersjs-ecosystem/feathers-memory/pull/60) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.3.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v1.3.1) (2017-10-20)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v1.3.0...v1.3.1)\n\n**Closed issues:**\n\n- Custom $select returning `id` [\\#58](https://github.com/feathersjs-ecosystem/feathers-memory/issues/58)\n- Best practice for $search [\\#51](https://github.com/feathersjs-ecosystem/feathers-memory/issues/51)\n\n**Merged pull requests:**\n\n- Do not select the id by default [\\#59](https://github.com/feathersjs-ecosystem/feathers-memory/pull/59) ([daffl](https://github.com/daffl))\n\n## [v1.3.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v1.3.0) (2017-10-19)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v1.2.1...v1.3.0)\n\n**Merged pull requests:**\n\n- Modified matcher to use new sift package [\\#57](https://github.com/feathersjs-ecosystem/feathers-memory/pull/57) ([Mattchewone](https://github.com/Mattchewone))\n- Update mocha to the latest version 🚀 [\\#56](https://github.com/feathersjs-ecosystem/feathers-memory/pull/56) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.2.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v1.2.1) (2017-09-13)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v1.2.0...v1.2.1)\n\n## [v1.2.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v1.2.0) (2017-09-13)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v1.1.0...v1.2.0)\n\n**Closed issues:**\n\n- \\[RFE\\] An option to set the type of the id field to String [\\#54](https://github.com/feathersjs-ecosystem/feathers-memory/issues/54)\n\n**Merged pull requests:**\n\n- Deep clone objects before returning [\\#55](https://github.com/feathersjs-ecosystem/feathers-memory/pull/55) ([daffl](https://github.com/daffl))\n- Update feathers-socketio to the latest version 🚀 [\\#52](https://github.com/feathersjs-ecosystem/feathers-memory/pull/52) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update feathers-service-tests to the latest version 🚀 [\\#50](https://github.com/feathersjs-ecosystem/feathers-memory/pull/50) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update semistandard to the latest version 🚀 [\\#49](https://github.com/feathersjs-ecosystem/feathers-memory/pull/49) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update dependencies to enable Greenkeeper 🌴 [\\#48](https://github.com/feathersjs-ecosystem/feathers-memory/pull/48) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.1.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v1.1.0) (2017-01-31)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v1.0.1...v1.1.0)\n\n**Merged pull requests:**\n\n- Allow to pass a custom matcher and sorter in the options [\\#47](https://github.com/feathersjs-ecosystem/feathers-memory/pull/47) ([daffl](https://github.com/daffl))\n- Change `var` to `const`, fix a mistake with `feathers-memory` requiring [\\#46](https://github.com/feathersjs-ecosystem/feathers-memory/pull/46) ([osenvosem](https://github.com/osenvosem))\n\n## [v1.0.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v1.0.1) (2016-11-15)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v1.0.0...v1.0.1)\n\n**Merged pull requests:**\n\n- feathers-service-tests@0.9.1 breaks build 🚨 [\\#45](https://github.com/feathersjs-ecosystem/feathers-memory/pull/45) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.0.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v1.0.0) (2016-11-11)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.8.1...v1.0.0)\n\n**Closed issues:**\n\n- Support $select for gets [\\#35](https://github.com/feathersjs-ecosystem/feathers-memory/issues/35)\n\n**Merged pull requests:**\n\n- Update feathers-service-tests to version 0.9.0 🚀 [\\#44](https://github.com/feathersjs-ecosystem/feathers-memory/pull/44) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-commons to version 0.8.0 🚀 [\\#43](https://github.com/feathersjs-ecosystem/feathers-memory/pull/43) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v0.8.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.8.1) (2016-11-02)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.8.0...v0.8.1)\n\n**Merged pull requests:**\n\n- fix $select with more than one field [\\#42](https://github.com/feathersjs-ecosystem/feathers-memory/pull/42) ([t2t2](https://github.com/t2t2))\n- babel-preset-es2015@6.18.0 breaks build 🚨 [\\#41](https://github.com/feathersjs-ecosystem/feathers-memory/pull/41) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Two tweaks for clean build and tests on Windows [\\#38](https://github.com/feathersjs-ecosystem/feathers-memory/pull/38) ([ghost](https://github.com/ghost))\n- jshint —\\> semistandard [\\#37](https://github.com/feathersjs-ecosystem/feathers-memory/pull/37) ([marshallswain](https://github.com/marshallswain))\n- adding code coverage reporting [\\#36](https://github.com/feathersjs-ecosystem/feathers-memory/pull/36) ([ekryski](https://github.com/ekryski))\n- Update feathers-service-tests to version 0.8.0 🚀 [\\#32](https://github.com/feathersjs-ecosystem/feathers-memory/pull/32) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v0.8.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.8.0) (2016-09-08)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.7.5...v0.8.0)\n\n**Closed issues:**\n\n- Remove object from memory once sent? [\\#30](https://github.com/feathersjs-ecosystem/feathers-memory/issues/30)\n\n**Merged pull requests:**\n\n- Update service tests, id and events option [\\#31](https://github.com/feathersjs-ecosystem/feathers-memory/pull/31) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update mocha to version 3.0.0 🚀 [\\#29](https://github.com/feathersjs-ecosystem/feathers-memory/pull/29) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v0.7.5](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.7.5) (2016-07-25)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.7.4...v0.7.5)\n\n## [v0.7.4](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.7.4) (2016-07-21)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.7.3...v0.7.4)\n\n**Merged pull requests:**\n\n- Update feathers-query-filters to version 2.0.0 🚀 [\\#28](https://github.com/feathersjs-ecosystem/feathers-memory/pull/28) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v0.7.3](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.7.3) (2016-06-16)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.7.2...v0.7.3)\n\n**Merged pull requests:**\n\n- Update feathers-service-tests to version 0.6.0 🚀 [\\#27](https://github.com/feathersjs-ecosystem/feathers-memory/pull/27) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v0.7.2](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.7.2) (2016-06-14)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.7.1...v0.7.2)\n\n**Closed issues:**\n\n- Support $search [\\#14](https://github.com/feathersjs-ecosystem/feathers-memory/issues/14)\n\n**Merged pull requests:**\n\n- Use the original id if it can be coerced [\\#26](https://github.com/feathersjs-ecosystem/feathers-memory/pull/26) ([daffl](https://github.com/daffl))\n- mocha@2.5.0 breaks build 🚨 [\\#25](https://github.com/feathersjs-ecosystem/feathers-memory/pull/25) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update babel-plugin-add-module-exports to version 0.2.0 🚀 [\\#24](https://github.com/feathersjs-ecosystem/feathers-memory/pull/24) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v0.7.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.7.1) (2016-04-05)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.7.0...v0.7.1)\n\n## [v0.7.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.7.0) (2016-04-04)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.6.3...v0.7.0)\n\n**Merged pull requests:**\n\n- Move to feathers-commons utilities [\\#20](https://github.com/feathersjs-ecosystem/feathers-memory/pull/20) ([daffl](https://github.com/daffl))\n\n## [v0.6.3](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.6.3) (2016-02-25)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.6.2...v0.6.3)\n\n**Closed issues:**\n\n- Upgrade to lodash 4 [\\#17](https://github.com/feathersjs-ecosystem/feathers-memory/issues/17)\n\n**Merged pull requests:**\n\n- Use individual Lodash methods [\\#19](https://github.com/feathersjs-ecosystem/feathers-memory/pull/19) ([daffl](https://github.com/daffl))\n\n## [v0.6.2](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.6.2) (2016-02-24)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.6.1...v0.6.2)\n\n**Merged pull requests:**\n\n- bumping feathers-errors version [\\#16](https://github.com/feathersjs-ecosystem/feathers-memory/pull/16) ([ekryski](https://github.com/ekryski))\n\n## [v0.6.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.6.1) (2016-02-22)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.6.0...v0.6.1)\n\n**Merged pull requests:**\n\n- Exmaple update [\\#15](https://github.com/feathersjs-ecosystem/feathers-memory/pull/15) ([ekryski](https://github.com/ekryski))\n\n## [v0.6.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.6.0) (2016-01-30)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.5.3...v0.6.0)\n\n**Merged pull requests:**\n\n- Use internal methods instead of service methods directly [\\#13](https://github.com/feathersjs-ecosystem/feathers-memory/pull/13) ([daffl](https://github.com/daffl))\n\n## [v0.5.3](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.5.3) (2016-01-23)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.5.2...v0.5.3)\n\n## [v0.5.2](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.5.2) (2016-01-23)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.5.1...v0.5.2)\n\n**Merged pull requests:**\n\n- Adding nsp check [\\#12](https://github.com/feathersjs-ecosystem/feathers-memory/pull/12) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.5.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.5.1) (2015-12-19)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.5.0...v0.5.1)\n\n## [v0.5.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.5.0) (2015-12-03)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.4.1...v0.5.0)\n\n## [v0.4.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.4.1) (2015-12-03)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/v0.4.0...v0.4.1)\n\n**Merged pull requests:**\n\n- Use ES6 classes, Promises and support pagination [\\#11](https://github.com/feathersjs-ecosystem/feathers-memory/pull/11) ([daffl](https://github.com/daffl))\n\n## [v0.4.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/v0.4.0) (2015-11-07)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/0.3.4...v0.4.0)\n\n**Closed issues:**\n\n- How properly append values to an existing memory element [\\#9](https://github.com/feathersjs-ecosystem/feathers-memory/issues/9)\n- how to initialize memory on app startup [\\#8](https://github.com/feathersjs-ecosystem/feathers-memory/issues/8)\n- Add query-filter support [\\#7](https://github.com/feathersjs-ecosystem/feathers-memory/issues/7)\n- Remove sorting and other processing from core service [\\#4](https://github.com/feathersjs-ecosystem/feathers-memory/issues/4)\n\n**Merged pull requests:**\n\n- Migrate to ES6 plugin infrastructure and shared feathers-service-tests [\\#10](https://github.com/feathersjs-ecosystem/feathers-memory/pull/10) ([daffl](https://github.com/daffl))\n- Added support for simple query in find [\\#6](https://github.com/feathersjs-ecosystem/feathers-memory/pull/6) ([ruimgoncalves](https://github.com/ruimgoncalves))\n\n## [0.3.4](https://github.com/feathersjs-ecosystem/feathers-memory/tree/0.3.4) (2014-09-25)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/0.3.3...0.3.4)\n\n**Closed issues:**\n\n- Query and persisting Data [\\#5](https://github.com/feathersjs-ecosystem/feathers-memory/issues/5)\n\n## [0.3.3](https://github.com/feathersjs-ecosystem/feathers-memory/tree/0.3.3) (2014-06-13)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/0.3.2...0.3.3)\n\n## [0.3.2](https://github.com/feathersjs-ecosystem/feathers-memory/tree/0.3.2) (2014-06-13)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/0.3.1...0.3.2)\n\n## [0.3.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/0.3.1) (2014-06-13)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/0.3.0...0.3.1)\n\n**Closed issues:**\n\n- Fix peer dependency [\\#3](https://github.com/feathersjs-ecosystem/feathers-memory/issues/3)\n- Should support `patch` service method [\\#2](https://github.com/feathersjs-ecosystem/feathers-memory/issues/2)\n- Need to return proper errors [\\#1](https://github.com/feathersjs-ecosystem/feathers-memory/issues/1)\n\n## [0.3.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/0.3.0) (2014-06-05)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/0.2.1...0.3.0)\n\n## [0.2.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/0.2.1) (2014-06-04)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/0.2.0...0.2.1)\n\n## [0.2.0](https://github.com/feathersjs-ecosystem/feathers-memory/tree/0.2.0) (2014-04-22)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/0.1.2...0.2.0)\n\n## [0.1.2](https://github.com/feathersjs-ecosystem/feathers-memory/tree/0.1.2) (2014-04-11)\n\n[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-memory/compare/0.1.1...0.1.2)\n\n## [0.1.1](https://github.com/feathersjs-ecosystem/feathers-memory/tree/0.1.1) (2014-04-11)\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/memory/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/memory/README.md",
    "content": "# @feathersjs/memory\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/memory.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/memory)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> A Feathers service adapter for in-memory data storage that works on all platforms.\n\n## Installation\n\n```bash\n$ npm install --save @feathersjs/memory\n```\n\n## Documentation\n\nSee [FeathersJS Memory Adapter API documentation](https://feathersjs.com/api/databases/memory.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/memory/package.json",
    "content": "{\n  \"name\": \"@feathersjs/memory\",\n  \"description\": \"An in memory service store\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://github.com/feathersjs/feathers\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/memory\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"_templates/**\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**/*.test.ts\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/adapter-commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"sift\": \"^17.1.3\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/adapter-tests\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/memory/src/index.ts",
    "content": "import { BadRequest, MethodNotAllowed, NotFound } from '@feathersjs/errors'\nimport {\n  sorter,\n  select,\n  AdapterBase,\n  AdapterServiceOptions,\n  PaginationOptions,\n  AdapterParams\n} from '@feathersjs/adapter-commons'\nimport sift from 'sift'\nimport { NullableId, Id, Params, Paginated } from '@feathersjs/feathers'\n\nexport interface MemoryServiceStore<T> {\n  [key: string]: T\n}\n\nexport interface MemoryServiceOptions<T = any> extends AdapterServiceOptions {\n  store?: MemoryServiceStore<T>\n  startId?: number\n  matcher?: (query: any) => any\n  sorter?: (sort: any) => any\n}\n\nconst _select = (data: any, params: any, ...args: string[]) => {\n  const base = select(params, ...args)\n\n  return base(JSON.parse(JSON.stringify(data)))\n}\n\nexport class MemoryAdapter<\n  Result = any,\n  Data = Partial<Result>,\n  ServiceParams extends Params = Params,\n  PatchData = Partial<Data>\n> extends AdapterBase<Result, Data, PatchData, ServiceParams, MemoryServiceOptions<Result>> {\n  store: MemoryServiceStore<Result>\n  _uId: number\n\n  constructor(options: MemoryServiceOptions<Result> = {}) {\n    super({\n      id: 'id',\n      matcher: sift,\n      sorter,\n      store: {},\n      startId: 0,\n      ...options\n    })\n    this._uId = this.options.startId\n    this.store = { ...this.options.store }\n  }\n\n  async getEntries(_params?: ServiceParams) {\n    const params = _params || ({} as ServiceParams)\n\n    return this._find({\n      ...params,\n      paginate: false\n    })\n  }\n\n  getQuery(params: ServiceParams) {\n    const { $skip, $sort, $limit, $select, ...query } = params.query || {}\n\n    return {\n      query,\n      filters: { $skip, $sort, $limit, $select }\n    }\n  }\n\n  async _find(_params?: ServiceParams & { paginate?: PaginationOptions }): Promise<Paginated<Result>>\n  async _find(_params?: ServiceParams & { paginate: false }): Promise<Result[]>\n  async _find(_params?: ServiceParams): Promise<Paginated<Result> | Result[]>\n  async _find(params: ServiceParams = {} as ServiceParams): Promise<Paginated<Result> | Result[]> {\n    const { paginate } = this.getOptions(params)\n    const { query, filters } = this.getQuery(params)\n\n    let values = Object.values(this.store)\n    const hasSkip = filters.$skip !== undefined\n    const hasSort = filters.$sort !== undefined\n    const hasLimit = filters.$limit !== undefined\n    const hasQuery = Object.keys(query).length > 0\n\n    if (hasSort) {\n      values.sort(this.options.sorter(filters.$sort))\n    }\n\n    if (paginate) {\n      if (hasQuery) {\n        values = values.filter(this.options.matcher(query))\n      }\n\n      const total = values.length\n\n      if (hasSkip) {\n        values = values.slice(filters.$skip)\n      }\n\n      if (hasLimit) {\n        values = values.slice(0, filters.$limit)\n      }\n\n      const result: Paginated<Result> = {\n        total,\n        limit: filters.$limit,\n        skip: filters.$skip || 0,\n        data: values.map((value) => _select(value, params, this.id))\n      }\n\n      return result\n    }\n\n    /*  Without pagination, we don't have to match every result and gain considerable performance improvements with a breaking for loop. */\n    if (hasQuery || hasLimit || hasSkip) {\n      let skipped = 0\n      const matcher = this.options.matcher(query)\n      const matched = []\n\n      if (hasLimit && filters.$limit === 0) {\n        return []\n      }\n\n      for (let index = 0, length = values.length; index < length; index++) {\n        const value = values[index]\n\n        if (hasQuery && !matcher(value, index, values)) {\n          continue\n        }\n\n        if (hasSkip && filters.$skip > skipped) {\n          skipped++\n          continue\n        }\n\n        matched.push(_select(value, params, this.id))\n\n        if (hasLimit && filters.$limit === matched.length) {\n          break\n        }\n      }\n\n      return matched\n    }\n\n    return values.map((value) => _select(value, params, this.id))\n  }\n\n  async _get(id: Id, params: ServiceParams = {} as ServiceParams): Promise<Result> {\n    const { query } = this.getQuery(params)\n\n    if (id in this.store) {\n      const value = this.store[id]\n\n      if (this.options.matcher(query)(value)) {\n        return _select(value, params, this.id)\n      }\n    }\n\n    throw new NotFound(`No record found for id '${id}'`)\n  }\n\n  async _create(data: Partial<Data>, params?: ServiceParams): Promise<Result>\n  async _create(data: Partial<Data>[], params?: ServiceParams): Promise<Result[]>\n  async _create(data: Partial<Data> | Partial<Data>[], _params?: ServiceParams): Promise<Result | Result[]>\n  async _create(\n    data: Partial<Data> | Partial<Data>[],\n    params: ServiceParams = {} as ServiceParams\n  ): Promise<Result | Result[]> {\n    if (Array.isArray(data)) {\n      return Promise.all(data.map((current) => this._create(current, params)))\n    }\n\n    const id = (data as any)[this.id] || this._uId++\n    const current = { ...data, [this.id]: id }\n    const result = (this.store[id] = current as any)\n\n    return _select(result, params, this.id) as Result\n  }\n\n  async _update(id: Id, data: Data, params: ServiceParams = {} as ServiceParams): Promise<Result> {\n    if (id === null || Array.isArray(data)) {\n      throw new BadRequest(\"You can not replace multiple instances. Did you mean 'patch'?\")\n    }\n\n    const oldEntry = await this._get(id, params)\n\n    this.store[id] = { ...data, [this.id]: (oldEntry as any)[this.id] } as Result\n\n    return this._get(id, params)\n  }\n\n  async _patch(id: null, data: PatchData | Partial<Result>, params?: ServiceParams): Promise<Result[]>\n  async _patch(id: Id, data: PatchData | Partial<Result>, params?: ServiceParams): Promise<Result>\n  async _patch(\n    id: NullableId,\n    data: PatchData | Partial<Result>,\n    _params?: ServiceParams\n  ): Promise<Result | Result[]>\n  async _patch(\n    id: NullableId,\n    data: PatchData | Partial<Result>,\n    params: ServiceParams = {} as ServiceParams\n  ): Promise<Result | Result[]> {\n    if (id === null && !this.allowsMulti('patch', params)) {\n      throw new MethodNotAllowed('Can not patch multiple entries')\n    }\n\n    const { query } = this.getQuery(params)\n    const patchEntry = (entry: Result) => {\n      const currentId = (entry as any)[this.id]\n\n      this.store[currentId] = {\n        ...this.store[currentId],\n        ...data,\n        [this.id]: (entry as any)[this.id]\n      }\n\n      return _select(this.store[currentId], params, this.id)\n    }\n\n    if (id === null) {\n      const entries = await this.getEntries({\n        ...params,\n        query\n      })\n\n      return entries.map(patchEntry)\n    }\n\n    return patchEntry(await this._get(id, params)) // Will throw an error if not found\n  }\n\n  async _remove(id: null, params?: ServiceParams): Promise<Result[]>\n  async _remove(id: Id, params?: ServiceParams): Promise<Result>\n  async _remove(id: NullableId, _params?: ServiceParams): Promise<Result | Result[]>\n  async _remove(id: NullableId, params: ServiceParams = {} as ServiceParams): Promise<Result | Result[]> {\n    if (id === null && !this.allowsMulti('remove', params)) {\n      throw new MethodNotAllowed('Can not remove multiple entries')\n    }\n\n    const { query } = this.getQuery(params)\n\n    if (id === null) {\n      const entries = await this.getEntries({\n        ...params,\n        query\n      })\n\n      return Promise.all(entries.map((current: any) => this._remove(current[this.id] as Id, params)))\n    }\n\n    const entry = await this._get(id, params)\n\n    delete this.store[id]\n\n    return entry\n  }\n}\n\nexport class MemoryService<\n  Result = any,\n  Data = Partial<Result>,\n  ServiceParams extends AdapterParams = AdapterParams,\n  PatchData = Partial<Data>\n> extends MemoryAdapter<Result, Data, ServiceParams, PatchData> {\n  async find(params?: ServiceParams & { paginate?: PaginationOptions }): Promise<Paginated<Result>>\n  async find(params?: ServiceParams & { paginate: false }): Promise<Result[]>\n  async find(params?: ServiceParams): Promise<Paginated<Result> | Result[]>\n  async find(params?: ServiceParams): Promise<Paginated<Result> | Result[]> {\n    return this._find({\n      ...params,\n      query: await this.sanitizeQuery(params)\n    })\n  }\n\n  async get(id: Id, params?: ServiceParams): Promise<Result> {\n    return this._get(id, {\n      ...params,\n      query: await this.sanitizeQuery(params)\n    })\n  }\n\n  async create(data: Data, params?: ServiceParams): Promise<Result>\n  async create(data: Data[], params?: ServiceParams): Promise<Result[]>\n  async create(data: Data | Data[], params?: ServiceParams): Promise<Result | Result[]> {\n    if (Array.isArray(data) && !this.allowsMulti('create', params)) {\n      throw new MethodNotAllowed('Can not create multiple entries')\n    }\n\n    return this._create(data, params)\n  }\n\n  async update(id: Id, data: Data, params?: ServiceParams): Promise<Result> {\n    return this._update(id, data, {\n      ...params,\n      query: await this.sanitizeQuery(params)\n    })\n  }\n\n  async patch(id: Id, data: PatchData, params?: ServiceParams): Promise<Result>\n  async patch(id: null, data: PatchData, params?: ServiceParams): Promise<Result[]>\n  async patch(id: NullableId, data: PatchData, params?: ServiceParams): Promise<Result | Result[]> {\n    const { $limit, ...query } = await this.sanitizeQuery(params)\n\n    return this._patch(id, data, {\n      ...params,\n      query\n    })\n  }\n\n  async remove(id: Id, params?: ServiceParams): Promise<Result>\n  async remove(id: null, params?: ServiceParams): Promise<Result[]>\n  async remove(id: NullableId, params?: ServiceParams): Promise<Result | Result[]> {\n    const { $limit, ...query } = await this.sanitizeQuery(params)\n\n    return this._remove(id, {\n      ...params,\n      query\n    })\n  }\n}\n\nexport function memory<T = any, D = Partial<T>, P extends Params = Params>(\n  options: Partial<MemoryServiceOptions<T>> = {}\n) {\n  return new MemoryService<T, D, P>(options)\n}\n"
  },
  {
    "path": "packages/memory/test/index.test.ts",
    "content": "import assert from 'assert'\nimport adapterTests from '@feathersjs/adapter-tests'\nimport errors from '@feathersjs/errors'\nimport { feathers } from '@feathersjs/feathers'\n\nimport { MemoryService } from '../src'\n\nconst testSuite = adapterTests([\n  '.options',\n  '.events',\n  '._get',\n  '._find',\n  '._create',\n  '._update',\n  '._patch',\n  '._remove',\n  '.get',\n  '.get + $select',\n  '.get + id + query',\n  '.get + NotFound',\n  '.get + id + query id',\n  '.find',\n  '.find + paginate + query',\n  '.remove',\n  '.remove + $select',\n  '.remove + id + query',\n  '.remove + multi',\n  '.remove + multi no pagination',\n  '.remove + id + query id',\n  '.update',\n  '.update + $select',\n  '.update + id + query',\n  '.update + NotFound',\n  '.update + id + query id',\n  '.update + query + NotFound',\n  '.patch',\n  '.patch + $select',\n  '.patch + id + query',\n  '.patch multiple',\n  '.patch multiple no pagination',\n  '.patch multi query same',\n  '.patch multi query changed',\n  '.patch + query + NotFound',\n  '.patch + NotFound',\n  '.patch + id + query id',\n  '.create',\n  '.create + $select',\n  '.create multi',\n  'internal .find',\n  'internal .get',\n  'internal .create',\n  'internal .update',\n  'internal .patch',\n  'internal .remove',\n  '.find + equal',\n  '.find + equal multiple',\n  '.find + $sort',\n  '.find + $sort + string',\n  '.find + $limit',\n  '.find + $limit 0',\n  '.find + $skip',\n  '.find + $select',\n  '.find + $or',\n  '.find + $in',\n  '.find + $nin',\n  '.find + $lt',\n  '.find + $lte',\n  '.find + $gt',\n  '.find + $gte',\n  '.find + $ne',\n  '.find + $gt + $lt + $sort',\n  '.find + $or nested + $sort',\n  '.find + paginate',\n  '.find + paginate + $limit + $skip',\n  '.find + paginate + $limit 0',\n  '.find + paginate + params',\n  'params.adapter + paginate',\n  'params.adapter + multi'\n])\n\ndescribe('Feathers Memory Service', () => {\n  type Person = {\n    id: number\n    name: string\n    age: number\n  }\n\n  type Animal = {\n    type: string\n    age: number\n  }\n\n  const events = ['testing']\n  const app = feathers<{\n    people: MemoryService<Person>\n    'people-paginate': MemoryService<Person>\n    'people-customid': MemoryService<Person>\n    animals: MemoryService<Animal>\n    matcher: MemoryService\n  }>()\n\n  app.use(\n    'people',\n    new MemoryService<Person>({\n      events\n    })\n  )\n\n  app.use(\n    'people-paginate',\n    new MemoryService<Person>({\n      events,\n      multi: true,\n      paginate: {\n        default: 10,\n        max: 100\n      }\n    })\n  )\n\n  app.use(\n    'people-customid',\n    new MemoryService<Person>({\n      id: 'customid',\n      events\n    })\n  )\n\n  it('update with string id works', async () => {\n    const people = app.service('people')\n    const person = await people.create({\n      name: 'Tester',\n      age: 33\n    })\n\n    const updatedPerson: any = await people.update(person.id.toString(), person)\n\n    assert.strictEqual(typeof updatedPerson.id, 'number')\n\n    await people.remove(person.id.toString())\n  })\n\n  it('patch record with prop also in query', async () => {\n    app.use('animals', new MemoryService<Animal>({ multi: true }))\n    const animals = app.service('animals')\n    await animals.create([\n      {\n        type: 'cat',\n        age: 30\n      },\n      {\n        type: 'dog',\n        age: 10\n      }\n    ])\n\n    const [updated] = await animals.patch(null, { age: 40 }, { query: { age: 30 } })\n\n    assert.strictEqual(updated.age, 40)\n\n    await animals.remove(null, {})\n  })\n\n  it('allows to pass custom find and sort matcher', async () => {\n    let sorterCalled = false\n    let matcherCalled = false\n\n    app.use(\n      'matcher',\n      new MemoryService({\n        matcher() {\n          matcherCalled = true\n          return function () {\n            return true\n          }\n        },\n\n        sorter() {\n          sorterCalled = true\n          return function () {\n            return 0\n          }\n        }\n      })\n    )\n\n    await app.service('matcher').find({\n      query: { something: 1, $sort: { something: 1 } }\n    })\n\n    assert.ok(sorterCalled, 'sorter called')\n    assert.ok(matcherCalled, 'matcher called')\n  })\n\n  it('does not modify the original data', async () => {\n    const people = app.service('people')\n\n    const person = await people.create({\n      name: 'Delete tester',\n      age: 33\n    })\n\n    delete person.age\n\n    const otherPerson = await people.get(person.id)\n\n    assert.strictEqual(otherPerson.age, 33)\n\n    await people.remove(person.id)\n  })\n\n  it('update with null throws error', async () => {\n    try {\n      await app.service('people').update(null, {})\n      throw new Error('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.message, \"You can not replace multiple instances. Did you mean 'patch'?\")\n    }\n  })\n\n  it('use $select as only query property', async () => {\n    const people = app.service('people')\n    const person = await people.create({\n      name: 'Tester',\n      age: 42\n    })\n\n    const results = await people.find({\n      paginate: false,\n      query: {\n        $select: ['name']\n      }\n    })\n\n    assert.deepStrictEqual(results[0], { id: person.id, name: 'Tester' })\n\n    await people.remove(person.id)\n  })\n\n  it('using $limit still returns correct total', async () => {\n    const service = app.service('people-paginate')\n\n    for (let i = 0; i < 10; i++) {\n      await service.create({\n        name: `Tester ${i}`,\n        age: 19\n      })\n\n      await service.create({\n        name: `Tester ${i}`,\n        age: 20\n      })\n    }\n\n    try {\n      const results = await service.find({\n        query: {\n          $skip: 3,\n          $limit: 5,\n          age: 19\n        }\n      })\n\n      assert.strictEqual(results.total, 10)\n      assert.strictEqual(results.skip, 3)\n      assert.strictEqual(results.limit, 5)\n    } finally {\n      await service.remove(null, {\n        query: {\n          age: {\n            $in: [19, 20]\n          }\n        }\n      })\n    }\n  })\n\n  testSuite(app, errors, 'people')\n  testSuite(app, errors, 'people-customid', 'customid')\n})\n"
  },
  {
    "path": "packages/memory/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/mongodb/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- **mongodb:** Ensure arbitrary objects can't be passed as MongoDB ids ([#3664](https://github.com/feathersjs/feathers/issues/3664)) ([163e664](https://github.com/feathersjs/feathers/commit/163e664f231a57041034c852b80525fc5c8cf68d))\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n- **mongodb:** Fix mongo count ([#3541](https://github.com/feathersjs/feathers/issues/3541)) ([3e95c7d](https://github.com/feathersjs/feathers/commit/3e95c7df6ae7de6a3a406dfb61dd044ea905456f))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n### Bug Fixes\n\n- **mongodb:** Added Update Method Prototype to MongoDBService Class ([#3494](https://github.com/feathersjs/feathers/issues/3494)) ([428f23a](https://github.com/feathersjs/feathers/commit/428f23a8c622cd8bc4d06253206aadd514267846))\n- **mongodb:** MongoDB Aggregation improvements ([#3366](https://github.com/feathersjs/feathers/issues/3366)) ([f2829b1](https://github.com/feathersjs/feathers/commit/f2829b1f8e33d13caae3557d37225d990467fb39))\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n### Bug Fixes\n\n- allow \\_patch to modify the entire base schema ([#3300](https://github.com/feathersjs/feathers/issues/3300)) ([0f41622](https://github.com/feathersjs/feathers/commit/0f41622307589b3a0b62ac411a73e6a601bda171))\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n### Bug Fixes\n\n- **mongodb:** Speed up multi create ([#3171](https://github.com/feathersjs/feathers/issues/3171)) ([e34f728](https://github.com/feathersjs/feathers/commit/e34f728139a1008503aa440f1b7cf6395719417b))\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n- **mongodb:** Add MongoDB as peerDependency ([#3148](https://github.com/feathersjs/feathers/issues/3148)) ([0137b40](https://github.com/feathersjs/feathers/commit/0137b40fb694fa95e3b7b7ad41504831b894d977))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n### Bug Fixes\n\n- **memory/mongodb:** $select as only property & force 'id' in '$select' ([#3081](https://github.com/feathersjs/feathers/issues/3081)) ([fbe3cf5](https://github.com/feathersjs/feathers/commit/fbe3cf5199e102b5aeda2ae33828d5034df3d105))\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n### Features\n\n- **mongodb:** Add Object ID keyword converter and update MongoDB CLI & docs ([#3041](https://github.com/feathersjs/feathers/issues/3041)) ([ca0994e](https://github.com/feathersjs/feathers/commit/ca0994eaecb5a31f310bc980d106834e11f24f41))\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- **databases:** Ensure that query sanitization is not necessary when using query schemas ([#3022](https://github.com/feathersjs/feathers/issues/3022)) ([dbf514e](https://github.com/feathersjs/feathers/commit/dbf514e85d1508b95c007462a39b3cadd4ff391d))\n- **databases:** Improve documentation for adapters and allow dynamic Knex adapter options ([#3019](https://github.com/feathersjs/feathers/issues/3019)) ([66c4b5e](https://github.com/feathersjs/feathers/commit/66c4b5e72000dd03acb57fca1cad4737c85c9c9e))\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n### Features\n\n- **database:** Add and to the query syntax ([#3021](https://github.com/feathersjs/feathers/issues/3021)) ([00cb0d9](https://github.com/feathersjs/feathers/commit/00cb0d9c302ae951ae007d3d6ceba33e254edd9c))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Bug Fixes\n\n- **databases:** Make sure adapter method signatures are exported properly ([#2943](https://github.com/feathersjs/feathers/issues/2943)) ([458d668](https://github.com/feathersjs/feathers/commit/458d66859e256c5854e7590f0b4a11b233fe0374))\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **schema:** Check for undefined value in resolveQueryObjectId resolver ([#2914](https://github.com/feathersjs/feathers/issues/2914)) ([d9449fa](https://github.com/feathersjs/feathers/commit/d9449fa835f58fc9cec5f7254c50219494129140))\n\n### Features\n\n- **adapter:** Add patch data type to adapters and refactor AdapterBase usage ([#2906](https://github.com/feathersjs/feathers/issues/2906)) ([9ddc2e6](https://github.com/feathersjs/feathers/commit/9ddc2e6b028f026f939d6af68125847e5c6734b4))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n### Features\n\n- **mongodb:** Add ObjectId resolvers and MongoDB option in the guide ([#2847](https://github.com/feathersjs/feathers/issues/2847)) ([c5c1fba](https://github.com/feathersjs/feathers/commit/c5c1fba5718a63412075cd3838b86b889eb0bd48))\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n### Features\n\n- **cli:** Generate full client test suite and improve typed client ([#2788](https://github.com/feathersjs/feathers/issues/2788)) ([57119b6](https://github.com/feathersjs/feathers/commit/57119b6bb2797f7297cf054268a248c093ecd538))\n- **cli:** Improve generated schema definitions ([#2783](https://github.com/feathersjs/feathers/issues/2783)) ([474a9fd](https://github.com/feathersjs/feathers/commit/474a9fda2107e9bcf357746320a8e00cda8182b6))\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n- **mongodb:** Ensure transactions are used properly in create ([#2699](https://github.com/feathersjs/feathers/issues/2699)) ([fe22615](https://github.com/feathersjs/feathers/commit/fe22615b7fa17d3c20ac26d6f82097917c9b63f6))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Features\n\n- **authentication-local:** Add passwordHash property resolver ([#2660](https://github.com/feathersjs/feathers/issues/2660)) ([b41279b](https://github.com/feathersjs/feathers/commit/b41279b55eea3771a6fa4983a37be2413287bbc6))\n- **knex:** Add KnexJS SQL database adapter to core ([#2671](https://github.com/feathersjs/feathers/issues/2671)) ([9380fff](https://github.com/feathersjs/feathers/commit/9380fff58596e8bb90b8bb098d2795b7eadfec20))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/mongodb\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n### Bug Fixes\n\n- **typescript:** Make additional types generic to work with extended types ([#2625](https://github.com/feathersjs/feathers/issues/2625)) ([269fdec](https://github.com/feathersjs/feathers/commit/269fdecc5961092dc8608b3cbe16f433c80bfa96))\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Features\n\n- **mongodb:** Add feathers-mongodb adapter as @feathersjs/mongodb ([#2610](https://github.com/feathersjs/feathers/issues/2610)) ([6d43734](https://github.com/feathersjs/feathers/commit/6d43734a53db02c435cafc52a22dca414e5d0940))\n"
  },
  {
    "path": "packages/mongodb/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/mongodb/README.md",
    "content": "# @feathersjs/mongodb\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/mongodb.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/mongodb)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Feathers MongoDB service adapter\n\n## Installation\n\n```\nnpm install @feathersjs/mongodb --save\n```\n\n## Documentation\n\nRefer to the [Feathers MongoDB adapter documentation](https://feathersjs.com/api/databases/mongodb.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/mongodb/package.json",
    "content": "{\n  \"name\": \"@feathersjs/mongodb\",\n  \"description\": \"Feathers MongoDB service adapter\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 14\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/adapter-commons\": \"^5.0.42\",\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\"\n  },\n  \"peerDependencies\": {\n    \"mongodb\": \"^6.19.0\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/adapter-tests\": \"^5.0.42\",\n    \"@feathersjs/schema\": \"^5.0.42\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"mongodb-memory-server\": \"^11.0.1\",\n    \"shx\": \"^0.4.0\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/mongodb/src/adapter.ts",
    "content": "import {\n  ObjectId,\n  Collection,\n  FindOptions,\n  BulkWriteOptions,\n  InsertOneOptions,\n  DeleteOptions,\n  CountDocumentsOptions,\n  ReplaceOptions,\n  FindOneAndReplaceOptions,\n  FindOneAndUpdateOptions,\n  Document,\n  FindOneAndDeleteOptions\n} from 'mongodb'\nimport { BadRequest, MethodNotAllowed, NotFound } from '@feathersjs/errors'\nimport { _ } from '@feathersjs/commons'\nimport {\n  AdapterBase,\n  AdapterParams,\n  AdapterServiceOptions,\n  PaginationOptions,\n  AdapterQuery,\n  getLimit\n} from '@feathersjs/adapter-commons'\nimport { Id, Paginated } from '@feathersjs/feathers'\nimport { errorHandler } from './error-handler'\n\nexport interface MongoDBAdapterOptions extends AdapterServiceOptions {\n  Model: Collection | Promise<Collection>\n  disableObjectify?: boolean\n  useEstimatedDocumentCount?: boolean\n  /**\n   * A list of MongoDB update operators to block in `patch` data.\n   * Defaults to `['$rename']`. Any `$`-prefixed key in this list will be\n   * silently dropped from the update.\n   */\n  disabledOperators?: string[]\n}\n\nexport interface MongoDBAdapterParams<Q = AdapterQuery> extends AdapterParams<\n  Q,\n  Partial<MongoDBAdapterOptions>\n> {\n  pipeline?: Document[]\n  mongodb?:\n    | BulkWriteOptions\n    | FindOptions\n    | InsertOneOptions\n    | DeleteOptions\n    | CountDocumentsOptions\n    | ReplaceOptions\n    | FindOneAndReplaceOptions\n    | FindOneAndDeleteOptions\n}\n\nexport type AdapterId = Id | ObjectId\n\nexport type NullableAdapterId = AdapterId | null\n\n// Create the service.\nexport class MongoDbAdapter<\n  Result,\n  Data = Partial<Result>,\n  ServiceParams extends MongoDBAdapterParams<any> = MongoDBAdapterParams,\n  PatchData = Partial<Data>\n> extends AdapterBase<Result, Data, PatchData, ServiceParams, MongoDBAdapterOptions, AdapterId> {\n  constructor(options: MongoDBAdapterOptions) {\n    if (!options) {\n      throw new Error('MongoDB options have to be provided')\n    }\n\n    super({\n      id: '_id',\n      ...options\n    })\n  }\n\n  getObjectId(id: AdapterId) {\n    if (this.options.disableObjectify) {\n      return id\n    }\n\n    if (this.id === '_id' && ObjectId.isValid(id as string)) {\n      id = new ObjectId(id.toString())\n    }\n\n    return id\n  }\n\n  filterQuery(id: NullableAdapterId, params: ServiceParams) {\n    const options = this.getOptions(params)\n    const { $select, $sort, $limit: _limit, $skip = 0, ...query } = (params.query || {}) as AdapterQuery\n    const $limit = getLimit(_limit, options.paginate)\n    if (id !== null) {\n      if (typeof id !== 'string' && typeof id !== 'number' && !(id instanceof ObjectId)) {\n        throw new BadRequest(`Invalid id '${JSON.stringify(id)}'`)\n      }\n      query.$and = (query.$and || []).concat({\n        [this.id]: this.getObjectId(id)\n      })\n    }\n\n    if (query[this.id]) {\n      query[this.id] = this.getObjectId(query[this.id])\n    }\n\n    return {\n      filters: { $select, $sort, $limit, $skip },\n      query\n    }\n  }\n\n  getModel(params: ServiceParams = {} as ServiceParams) {\n    const { Model } = this.getOptions(params)\n    return Promise.resolve(Model)\n  }\n\n  async findRaw(params: ServiceParams) {\n    const { filters, query } = this.filterQuery(null, params)\n    const model = await this.getModel(params)\n    const q = model.find(query, params.mongodb)\n\n    if (filters.$sort !== undefined) {\n      q.sort(filters.$sort)\n    }\n\n    if (filters.$select !== undefined) {\n      q.project(this.getProjection(filters.$select))\n    }\n\n    if (filters.$skip !== undefined) {\n      q.skip(filters.$skip)\n    }\n\n    if (filters.$limit !== undefined) {\n      q.limit(filters.$limit)\n    }\n\n    return q\n  }\n\n  /* TODO: Remove $out and $merge stages, else it returns an empty cursor. I think its safe to assume this is primarily for querying. */\n  async aggregateRaw(params: ServiceParams) {\n    const model = await this.getModel(params)\n    const pipeline = params.pipeline || []\n    const index = pipeline.findIndex((stage: Document) => stage.$feathers)\n    const before = index >= 0 ? pipeline.slice(0, index) : []\n    const feathersPipeline = this.makeFeathersPipeline(params)\n    const after = index >= 0 ? pipeline.slice(index + 1) : pipeline\n\n    return model.aggregate([...before, ...feathersPipeline, ...after], params.mongodb)\n  }\n\n  makeFeathersPipeline(params: ServiceParams) {\n    const { filters, query } = this.filterQuery(null, params)\n    const pipeline: Document[] = [{ $match: query }]\n\n    if (filters.$sort !== undefined) {\n      pipeline.push({ $sort: filters.$sort })\n    }\n\n    if (filters.$skip !== undefined) {\n      pipeline.push({ $skip: filters.$skip })\n    }\n\n    if (filters.$limit !== undefined) {\n      pipeline.push({ $limit: filters.$limit })\n    }\n\n    if (filters.$select !== undefined) {\n      pipeline.push({ $project: this.getProjection(filters.$select) })\n    }\n\n    return pipeline\n  }\n\n  getProjection(select?: string[] | { [key: string]: number }) {\n    if (!select) {\n      return undefined\n    }\n\n    if (Array.isArray(select)) {\n      if (!select.includes(this.id)) {\n        select = [this.id, ...select]\n      }\n      return select.reduce<{ [key: string]: number }>(\n        (value, name) => ({\n          ...value,\n          [name]: 1\n        }),\n        {}\n      )\n    }\n\n    if (!select[this.id]) {\n      return {\n        ...select,\n        [this.id]: 1\n      }\n    }\n\n    return select\n  }\n\n  normalizeId<D>(id: NullableAdapterId, data: D): D {\n    if (this.id === '_id') {\n      // Default Mongo IDs cannot be updated. The Mongo library handles\n      // this automatically.\n      return _.omit(data, this.id)\n    } else if (id !== null) {\n      // If not using the default Mongo _id field set the ID to its\n      // previous value. This prevents orphaned documents.\n      return {\n        ...data,\n        [this.id]: id\n      }\n    }\n    return data\n  }\n\n  async countDocuments(params: ServiceParams) {\n    const { useEstimatedDocumentCount } = this.getOptions(params)\n    const { query } = this.filterQuery(null, params)\n\n    if (params.pipeline) {\n      const aggregateParams = {\n        ...params,\n        paginate: false,\n        pipeline: [...params.pipeline, { $count: 'total' }],\n        query: {\n          ...params.query,\n          $select: [this.id],\n          $sort: undefined,\n          $skip: undefined,\n          $limit: undefined\n        }\n      }\n      const [result] = await this.aggregateRaw(aggregateParams).then((result) => result.toArray())\n      if (!result) {\n        return 0\n      }\n      return result.total\n    }\n\n    const model = await this.getModel(params)\n\n    if (useEstimatedDocumentCount && typeof model.estimatedDocumentCount === 'function') {\n      return model.estimatedDocumentCount()\n    }\n\n    return model.countDocuments(query, params.mongodb)\n  }\n\n  async _get(id: AdapterId, params: ServiceParams = {} as ServiceParams): Promise<Result> {\n    const {\n      query,\n      filters: { $select }\n    } = this.filterQuery(id, params)\n\n    if (params.pipeline) {\n      const aggregateParams = {\n        ...params,\n        query: {\n          ...params.query,\n          $limit: 1,\n          $and: (params.query.$and || []).concat({\n            [this.id]: this.getObjectId(id)\n          })\n        }\n      }\n\n      return this.aggregateRaw(aggregateParams)\n        .then((result) => result.toArray())\n        .then(([result]) => {\n          if (!result) {\n            throw new NotFound(`No record found for id '${id}'`)\n          }\n\n          return result\n        })\n        .catch(errorHandler)\n    }\n\n    const findOptions: FindOptions = {\n      projection: this.getProjection($select),\n      ...params.mongodb\n    }\n\n    return this.getModel(params)\n      .then((model) => model.findOne(query, findOptions))\n      .then((result) => {\n        if (!result) {\n          throw new NotFound(`No record found for id '${id}'`)\n        }\n\n        return result\n      })\n      .catch(errorHandler)\n  }\n\n  async _find(params?: ServiceParams & { paginate?: PaginationOptions }): Promise<Paginated<Result>>\n  async _find(params?: ServiceParams & { paginate: false }): Promise<Result[]>\n  async _find(params?: ServiceParams): Promise<Paginated<Result> | Result[]>\n  async _find(params: ServiceParams = {} as ServiceParams): Promise<Paginated<Result> | Result[]> {\n    const { paginate } = this.getOptions(params)\n    const { filters } = this.filterQuery(null, params)\n    const paginationDisabled = params.paginate === false || !paginate || !paginate.default\n\n    const getData = () => {\n      const result = params.pipeline ? this.aggregateRaw(params) : this.findRaw(params)\n      return result.then((result) => result.toArray())\n    }\n\n    if (paginationDisabled) {\n      if (filters.$limit === 0) {\n        return [] as Result[]\n      }\n      const data = await getData()\n      return data as Result[]\n    }\n\n    if (filters.$limit === 0) {\n      return {\n        total: await this.countDocuments(params),\n        data: [] as Result[],\n        limit: filters.$limit,\n        skip: filters.$skip || 0\n      }\n    }\n\n    const [data, total] = await Promise.all([getData(), this.countDocuments(params)])\n\n    return {\n      total,\n      data: data as Result[],\n      limit: filters.$limit,\n      skip: filters.$skip || 0\n    }\n  }\n\n  async _create(data: Data, params?: ServiceParams): Promise<Result>\n  async _create(data: Data[], params?: ServiceParams): Promise<Result[]>\n  async _create(data: Data | Data[], _params?: ServiceParams): Promise<Result | Result[]>\n  async _create(\n    data: Data | Data[],\n    params: ServiceParams = {} as ServiceParams\n  ): Promise<Result | Result[]> {\n    if (Array.isArray(data) && !this.allowsMulti('create', params)) {\n      throw new MethodNotAllowed('Can not create multiple entries')\n    }\n\n    const model = await this.getModel(params)\n    const setId = (item: any) => {\n      const entry = Object.assign({}, item)\n\n      if (this.id !== '_id' && typeof entry[this.id] === 'undefined') {\n        return {\n          [this.id]: new ObjectId().toHexString(),\n          ...entry\n        }\n      }\n\n      return entry\n    }\n\n    if (Array.isArray(data)) {\n      const created = await model.insertMany(data.map(setId), params.mongodb).catch(errorHandler)\n      return this._find({\n        ...params,\n        paginate: false,\n        query: {\n          _id: { $in: Object.values(created.insertedIds) },\n          $select: params.query?.$select\n        }\n      })\n    }\n\n    const created = await model.insertOne(setId(data), params.mongodb).catch(errorHandler)\n    const result = await this._find({\n      ...params,\n      paginate: false,\n      query: {\n        _id: created.insertedId,\n        $select: params.query?.$select,\n        $limit: 1\n      }\n    })\n    return result[0]\n  }\n\n  async _patch(id: null, data: PatchData | Partial<Result>, params?: ServiceParams): Promise<Result[]>\n  async _patch(id: AdapterId, data: PatchData | Partial<Result>, params?: ServiceParams): Promise<Result>\n  async _patch(\n    id: NullableAdapterId,\n    data: PatchData | Partial<Result>,\n    _params?: ServiceParams\n  ): Promise<Result | Result[]>\n  async _patch(\n    id: NullableAdapterId,\n    _data: PatchData | Partial<Result>,\n    params: ServiceParams = {} as ServiceParams\n  ): Promise<Result | Result[]> {\n    if (id === null && !this.allowsMulti('patch', params)) {\n      throw new MethodNotAllowed('Can not patch multiple entries')\n    }\n\n    const data = this.normalizeId(id, _data)\n    const model = await this.getModel(params)\n    const {\n      query,\n      filters: { $sort, $select }\n    } = this.filterQuery(id, params)\n    const disabledOperators = this.getOptions(params).disabledOperators || ['$rename']\n\n    const replacement = Object.keys(data).reduce(\n      (current, key) => {\n        const value = (data as any)[key]\n\n        if (key.charAt(0) !== '$') {\n          current.$set[key] = value\n        } else if (key === '$set') {\n          current.$set = {\n            ...current.$set,\n            ...value\n          }\n        } else if (!disabledOperators.includes(key)) {\n          current[key] = value\n        }\n\n        return current\n      },\n      { $set: {} } as any\n    )\n\n    if (id === null) {\n      const findParams = {\n        ...params,\n        paginate: false,\n        query: {\n          ...params.query,\n          $select: [this.id]\n        }\n      }\n\n      return this._find(findParams)\n        .then(async (result) => {\n          const idList = (result as Result[]).map((item: any) => item[this.id])\n          await model.updateMany({ [this.id]: { $in: idList } }, replacement, params.mongodb)\n          return this._find({\n            ...params,\n            paginate: false,\n            query: {\n              [this.id]: { $in: idList },\n              $sort,\n              $select\n            }\n          })\n        })\n        .catch(errorHandler)\n    }\n\n    if (params.pipeline) {\n      const getParams = {\n        ...params,\n        query: {\n          ...params.query,\n          $select: [this.id]\n        }\n      }\n\n      return this._get(id, getParams)\n        .then(async () => {\n          await model.updateOne({ [this.id]: id }, replacement, params.mongodb)\n          return this._get(id, {\n            ...params,\n            query: { $select }\n          })\n        })\n        .catch(errorHandler)\n    }\n\n    const updateOptions: FindOneAndUpdateOptions = {\n      projection: this.getProjection($select),\n      ...(params.mongodb as FindOneAndUpdateOptions),\n      returnDocument: 'after'\n    }\n\n    return model\n      .findOneAndUpdate(query, replacement, updateOptions)\n      .then((result) => {\n        if (!result) {\n          throw new NotFound(`No record found for id '${id}'`)\n        }\n        return result as Result\n      })\n      .catch(errorHandler)\n  }\n\n  async _update(id: AdapterId, data: Data, params: ServiceParams = {} as ServiceParams): Promise<Result> {\n    if (id === null || Array.isArray(data)) {\n      throw new BadRequest(\"You can not replace multiple instances. Did you mean 'patch'?\")\n    }\n\n    const {\n      query,\n      filters: { $select }\n    } = this.filterQuery(id, params)\n    const model = await this.getModel(params)\n    const replacement = this.normalizeId(id, data)\n\n    if (params.pipeline) {\n      const getParams = {\n        ...params,\n        query: {\n          ...params.query,\n          $select: [this.id]\n        }\n      }\n\n      return this._get(id, getParams)\n        .then(async () => {\n          await model.replaceOne({ [this.id]: id }, replacement, params.mongodb)\n          return this._get(id, {\n            ...params,\n            query: { $select }\n          })\n        })\n        .catch(errorHandler)\n    }\n\n    const replaceOptions: FindOneAndReplaceOptions = {\n      projection: this.getProjection($select),\n      ...(params.mongodb as FindOneAndReplaceOptions),\n      returnDocument: 'after'\n    }\n\n    return model\n      .findOneAndReplace(query, replacement, replaceOptions)\n      .then((result) => {\n        if (!result) {\n          throw new NotFound(`No record found for id '${id}'`)\n        }\n        return result as Result\n      })\n      .catch(errorHandler)\n  }\n\n  async _remove(id: null, params?: ServiceParams): Promise<Result[]>\n  async _remove(id: AdapterId, params?: ServiceParams): Promise<Result>\n  async _remove(id: NullableAdapterId, _params?: ServiceParams): Promise<Result | Result[]>\n  async _remove(\n    id: NullableAdapterId | ObjectId,\n    params: ServiceParams = {} as ServiceParams\n  ): Promise<Result | Result[]> {\n    if (id === null && !this.allowsMulti('remove', params)) {\n      throw new MethodNotAllowed('Can not remove multiple entries')\n    }\n\n    const model = await this.getModel(params)\n    const { query } = this.filterQuery(id, params)\n    const findParams = {\n      ...params,\n      paginate: false\n    }\n\n    if (id === null) {\n      return this._find(findParams)\n        .then(async (result) => {\n          const idList = (result as Result[]).map((item: any) => item[this.id])\n          await model.deleteMany({ [this.id]: { $in: idList } }, params.mongodb)\n          return result\n        })\n        .catch(errorHandler)\n    }\n\n    if (params.pipeline) {\n      return this._get(id, params)\n        .then(async (result) => {\n          await model.deleteOne({ [this.id]: id }, params.mongodb)\n          return result\n        })\n        .catch(errorHandler)\n    }\n\n    const deleteOptions: FindOneAndDeleteOptions = {\n      ...(params.mongodb as FindOneAndDeleteOptions),\n      projection: this.getProjection(params.query?.$select)\n    }\n\n    return model\n      .findOneAndDelete(query, deleteOptions)\n      .then((result) => {\n        if (!result) {\n          throw new NotFound(`No record found for id '${id}'`)\n        }\n        return result as Result\n      })\n      .catch(errorHandler)\n  }\n}\n"
  },
  {
    "path": "packages/mongodb/src/converters.ts",
    "content": "import { ObjectId } from 'mongodb'\n\nexport type ObjectIdParam = string | number | ObjectId\n\nexport type IdQueryObject<T> = {\n  $in?: T[]\n  $nin?: T[]\n  $ne?: T\n}\n\nconst toObjectId = (value: ObjectIdParam) => new ObjectId(value as string)\n\nexport async function resolveObjectId(value: ObjectIdParam) {\n  return toObjectId(value)\n}\n\nexport async function resolveQueryObjectId(\n  value: IdQueryObject<ObjectIdParam>\n): Promise<IdQueryObject<ObjectId>>\nexport async function resolveQueryObjectId(value: ObjectIdParam): Promise<ObjectId>\nexport async function resolveQueryObjectId(value: ObjectIdParam | IdQueryObject<ObjectIdParam>) {\n  if (!value) {\n    return undefined\n  }\n\n  if (typeof value === 'string' || typeof value === 'number' || value instanceof ObjectId) {\n    return toObjectId(value)\n  }\n\n  const convertedObject: IdQueryObject<ObjectId> = {}\n\n  if (Array.isArray(value.$in)) {\n    convertedObject.$in = value.$in.map(toObjectId)\n  }\n\n  if (Array.isArray(value.$nin)) {\n    convertedObject.$nin = value.$nin.map(toObjectId)\n  }\n\n  if (value.$ne !== undefined) {\n    convertedObject.$ne = toObjectId(value.$ne)\n  }\n\n  return convertedObject\n}\n\nexport const keywordObjectId = {\n  keyword: 'objectid',\n  type: 'string',\n  modifying: true,\n  compile(schemaVal: boolean) {\n    if (!schemaVal) return () => true\n\n    return function (value: string, obj: any) {\n      const { parentData, parentDataProperty } = obj\n      try {\n        parentData[parentDataProperty] = new ObjectId(value)\n        return true\n      } catch (error) {\n        throw new Error(`invalid objectid for property \"${parentDataProperty}\"`)\n      }\n    }\n  }\n} as const\n"
  },
  {
    "path": "packages/mongodb/src/error-handler.ts",
    "content": "import { GeneralError } from '@feathersjs/errors'\nimport { MongoError } from 'mongodb'\n\nexport function errorHandler(error: MongoError): any {\n  // See https://github.com/mongodb/mongo/blob/master/docs/errors.md\n  if (error && error.name && error.name.startsWith('Mongo')) {\n    throw new GeneralError(error, {\n      name: error.name,\n      code: error.code\n    })\n  }\n\n  throw error\n}\n"
  },
  {
    "path": "packages/mongodb/src/index.ts",
    "content": "import { PaginationOptions } from '@feathersjs/adapter-commons'\nimport { MethodNotAllowed } from '@feathersjs/errors/lib'\nimport { Paginated, Params } from '@feathersjs/feathers'\nimport { AdapterId, MongoDbAdapter, MongoDBAdapterParams, NullableAdapterId } from './adapter'\n\nexport * from './adapter'\nexport * from './error-handler'\nexport * from './converters'\n\nexport class MongoDBService<\n  Result = any,\n  Data = Partial<Result>,\n  ServiceParams extends Params<any> = MongoDBAdapterParams,\n  PatchData = Partial<Data>\n> extends MongoDbAdapter<Result, Data, ServiceParams, PatchData> {\n  async find(params?: ServiceParams & { paginate?: PaginationOptions }): Promise<Paginated<Result>>\n  async find(params?: ServiceParams & { paginate: false }): Promise<Result[]>\n  async find(params?: ServiceParams): Promise<Paginated<Result> | Result[]>\n  async find(params?: ServiceParams): Promise<Paginated<Result> | Result[]> {\n    return this._find({\n      ...params,\n      query: await this.sanitizeQuery(params)\n    })\n  }\n\n  async get(id: AdapterId, params?: ServiceParams): Promise<Result> {\n    return this._get(id, {\n      ...params,\n      query: await this.sanitizeQuery(params)\n    })\n  }\n\n  async create(data: Data, params?: ServiceParams): Promise<Result>\n  async create(data: Data[], params?: ServiceParams): Promise<Result[]>\n  async create(data: Data | Data[], params?: ServiceParams): Promise<Result | Result[]>\n  async create(data: Data | Data[], params?: ServiceParams): Promise<Result | Result[]> {\n    if (Array.isArray(data) && !this.allowsMulti('create', params)) {\n      throw new MethodNotAllowed('Can not create multiple entries')\n    }\n\n    return this._create(data, params)\n  }\n\n  async update(id: NullableAdapterId, data: Data, params?: ServiceParams): Promise<Result>\n  async update(id: AdapterId, data: Data, params?: ServiceParams): Promise<Result> {\n    return this._update(id, data, {\n      ...params,\n      query: await this.sanitizeQuery(params)\n    })\n  }\n\n  async patch(id: null, data: PatchData, params?: ServiceParams): Promise<Result[]>\n  async patch(id: AdapterId, data: PatchData, params?: ServiceParams): Promise<Result>\n  async patch(id: NullableAdapterId, data: PatchData, params?: ServiceParams): Promise<Result | Result[]>\n  async patch(id: NullableAdapterId, data: PatchData, params?: ServiceParams): Promise<Result | Result[]> {\n    const { $limit, ...query } = await this.sanitizeQuery(params)\n\n    return this._patch(id, data, {\n      ...params,\n      query\n    })\n  }\n\n  async remove(id: AdapterId, params?: ServiceParams): Promise<Result>\n  async remove(id: null, params?: ServiceParams): Promise<Result[]>\n  async remove(id: NullableAdapterId, params?: ServiceParams): Promise<Result | Result[]>\n  async remove(id: NullableAdapterId, params?: ServiceParams): Promise<Result | Result[]> {\n    const { $limit, ...query } = await this.sanitizeQuery(params)\n\n    return this._remove(id, {\n      ...params,\n      query\n    })\n  }\n}\n"
  },
  {
    "path": "packages/mongodb/test/converters.test.ts",
    "content": "import { Ajv } from '@feathersjs/schema'\nimport assert from 'assert'\nimport { ObjectId } from 'mongodb'\nimport { keywordObjectId, resolveObjectId, resolveQueryObjectId } from '../src'\n\ndescribe('ObjectId resolvers', () => {\n  it('resolveObjectId', async () => {\n    const oid = await resolveObjectId('5f9e3c1b9b9b9b9b9b9b9b9b')\n\n    assert.ok(oid instanceof ObjectId)\n  })\n\n  it('resolveQueryObjectId', async () => {\n    const oid = await resolveQueryObjectId('5f9e3c1b9b9b9b9b9b9b9b9b')\n\n    assert.ok(oid instanceof ObjectId)\n  })\n\n  it('resolveQueryObjectId with object', async () => {\n    const oids = await resolveQueryObjectId({\n      $in: ['5f9e3c1b9b9b9b9b9b9b9b9b'],\n      $ne: '5f9e3c1b9b9b9b9b9b9b9b9a'\n    })\n\n    assert.ok(oids.$in && oids.$in[0] instanceof ObjectId)\n    assert.ok(oids.$ne instanceof ObjectId)\n  })\n\n  it('resolveQueryObjectId with falsey value', async () => {\n    await resolveQueryObjectId(undefined)\n    await resolveQueryObjectId(null)\n    await resolveQueryObjectId(0)\n\n    assert.ok('Falsey value does not throw exception')\n  })\n})\n\nconst validator = new Ajv({ coerceTypes: true })\nvalidator.addKeyword(keywordObjectId)\n\ndescribe('objectid keyword', () => {\n  it('converts objectid strings when keyword is used', async () => {\n    const schema = {\n      type: 'object',\n      properties: {\n        _id: { type: 'string', objectid: true },\n        otherId: { type: 'string', objectid: true }\n      },\n      additionalProperties: false\n    }\n    const validate = validator.compile(schema)\n\n    const data = {\n      _id: '622585621f3996763f1e4444',\n      otherId: '622585621f3996763f1e5555'\n    }\n    assert.equal(typeof data._id, 'string')\n    assert.equal(typeof data.otherId, 'string')\n\n    // runs converters\n    validate(data)\n\n    assert.ok((data._id as any) instanceof ObjectId)\n    assert.equal(typeof data.otherId, 'object')\n  })\n\n  it('does not convert objectid strings without keyword', async () => {\n    const schema = {\n      type: 'object',\n      properties: {\n        _id: { type: 'string' },\n        otherId: { type: 'string' }\n      },\n      additionalProperties: false\n    }\n    const validate = validator.compile(schema)\n\n    const data = {\n      _id: '622585621f3996763f1e4444',\n      otherId: '622585621f3996763f1e5555'\n    }\n    assert.equal(typeof data._id, 'string')\n    assert.equal(typeof data.otherId, 'string')\n\n    // runs converters\n    validate(data)\n\n    assert.equal(typeof data._id, 'string')\n    assert.equal(typeof data.otherId, 'string')\n  })\n\n  it('fails on invalid objectids', async () => {\n    const schema = {\n      type: 'object',\n      properties: {\n        _id: { type: 'string', objectid: true }\n      },\n      additionalProperties: false\n    }\n    const validate = validator.compile(schema)\n\n    const data = {\n      _id: '622585621f3996763f1e444'\n    }\n    assert.equal(typeof data._id, 'string')\n\n    assert.throws(() => validate(data), /invalid objectid for property \"_id\"/)\n  })\n})\n"
  },
  {
    "path": "packages/mongodb/test/index.test.ts",
    "content": "import { Db, MongoClient, ObjectId } from 'mongodb'\nimport adapterTests from '@feathersjs/adapter-tests'\nimport assert from 'assert'\nimport { MongoMemoryServer } from 'mongodb-memory-server'\nimport { Ajv, FromSchema, getValidator, hooks, querySyntax } from '@feathersjs/schema'\nimport { feathers } from '@feathersjs/feathers'\nimport errors from '@feathersjs/errors'\nimport { MongoDBService, AdapterId } from '../src'\n\nconst testSuite = adapterTests([\n  '.options',\n  '.events',\n  '._get',\n  '._find',\n  '._create',\n  '._update',\n  '._patch',\n  '._remove',\n  '.get',\n  '.get + $select',\n  '.get + id + query',\n  '.get + NotFound',\n  '.get + id + query id',\n  '.find',\n  '.find + paginate + query',\n  '.remove',\n  '.remove + $select',\n  '.remove + id + query',\n  '.remove + multi',\n  '.remove + multi no pagination',\n  '.remove + id + query id',\n  '.remove + NotFound',\n  '.update',\n  '.update + $select',\n  '.update + id + query',\n  '.update + NotFound',\n  '.update + id + query id',\n  '.update + query + NotFound',\n  '.patch',\n  '.patch + $select',\n  '.patch + id + query',\n  '.patch multiple',\n  '.patch multiple no pagination',\n  '.patch multi query same',\n  '.patch multi query changed',\n  '.patch + query + NotFound',\n  '.patch + NotFound',\n  '.patch + id + query id',\n  '.create',\n  '.create ignores query',\n  '.create + $select',\n  '.create multi',\n  'internal .find',\n  'internal .get',\n  'internal .create',\n  'internal .update',\n  'internal .patch',\n  'internal .remove',\n  '.find + equal',\n  '.find + equal multiple',\n  '.find + $sort',\n  '.find + $sort + string',\n  '.find + $limit',\n  '.find + $limit 0',\n  '.find + $skip',\n  '.find + $select',\n  '.find + $or',\n  '.find + $and',\n  '.find + $in',\n  '.find + $nin',\n  '.find + $lt',\n  '.find + $lte',\n  '.find + $gt',\n  '.find + $gte',\n  '.find + $ne',\n  '.find + $gt + $lt + $sort',\n  '.find + $or nested + $sort',\n  '.find + $and + $or',\n  '.find + paginate',\n  '.find + paginate + $limit + $skip',\n  '.find + paginate + $limit 0',\n  '.find + paginate + params',\n  'params.adapter + paginate',\n  'params.adapter + multi'\n])\n\ndescribe('Feathers MongoDB Service', () => {\n  const personSchema = {\n    $id: 'Person',\n    type: 'object',\n    additionalProperties: false,\n    required: ['_id', 'name', 'age'],\n    properties: {\n      _id: { oneOf: [{ type: 'string' }, { type: 'object' }] },\n      name: { type: 'string' },\n      age: { type: 'number' },\n      friends: { type: 'array', items: { type: 'string' } },\n      team: { type: 'string' },\n      $push: {\n        type: 'object',\n        properties: {\n          friends: { type: 'string' }\n        }\n      }\n    }\n  } as const\n  const personQuery = {\n    $id: 'PersonQuery',\n    type: 'object',\n    additionalProperties: false,\n    properties: {\n      ...querySyntax(personSchema.properties, {\n        name: {\n          $regex: { type: 'string' }\n        }\n      })\n    }\n  } as const\n  const validator = new Ajv({\n    coerceTypes: true\n  })\n  const personQueryValidator = getValidator(personQuery, validator)\n\n  type Person = Omit<FromSchema<typeof personSchema>, '_id'> & { _id: AdapterId }\n  type Todo = {\n    _id: string\n    name: string\n    userId: string\n    person?: Person\n  }\n\n  type ServiceTypes = {\n    people: MongoDBService<Person>\n    'people-customid': MongoDBService<Person>\n    todos: MongoDBService<Todo>\n  }\n\n  const app = feathers<ServiceTypes>()\n\n  let db: Db\n  let mongoClient: MongoClient\n  let mongod: MongoMemoryServer\n\n  before(async () => {\n    mongod = await MongoMemoryServer.create()\n\n    const client = await MongoClient.connect(mongod.getUri())\n\n    mongoClient = client\n    db = client.db('feathers-test')\n\n    app.use(\n      'people',\n      new MongoDBService({\n        Model: db.collection('people'),\n        events: ['testing']\n      })\n    )\n    app.use(\n      'people-customid',\n      new MongoDBService({\n        Model: db.collection('people-customid'),\n        id: 'customid',\n        events: ['testing']\n      })\n    )\n\n    app.service('people').hooks({\n      before: {\n        find: [hooks.validateQuery(personQueryValidator)]\n      }\n    })\n\n    db.collection('people-customid').deleteMany({})\n    db.collection('people').deleteMany({})\n    db.collection('todos').deleteMany({})\n\n    db.collection('people').createIndex({ name: 1 }, { partialFilterExpression: { team: 'blue' } })\n  })\n\n  after(async () => {\n    await db.dropDatabase()\n    await mongoClient.close()\n    await mongod.stop()\n  })\n\n  describe('Service utility functions', () => {\n    describe('getObjectId', () => {\n      it('returns an ObjectID instance for a valid ID', () => {\n        const id = new ObjectId()\n        const objectify = app.service('people').getObjectId(id.toString())\n\n        assert.ok(objectify instanceof ObjectId)\n        assert.strictEqual(objectify.toString(), id.toString())\n      })\n\n      it('returns an ObjectID instance for a valid ID', () => {\n        const id = 'non-valid object id'\n        const objectify = app.service('people').getObjectId(id.toString())\n\n        assert.ok(!(objectify instanceof ObjectId))\n        assert.strictEqual(objectify, id)\n      })\n    })\n  })\n\n  // For some bizarre reason this test is flaky\n  describe.skip('works with ObjectIds', () => {\n    it('can call methods with ObjectId instance', async () => {\n      const person = await app.service('people').create({\n        name: 'David'\n      })\n\n      const withId = await app.service('people').get(person._id.toString())\n\n      assert.strictEqual(withId.name, 'David')\n\n      await app.service('people').remove(new ObjectId(person._id.toString()))\n    })\n  })\n\n  describe('Special collation param', () => {\n    let peopleService: MongoDBService<Person>\n    let people: Person[]\n\n    function indexOfName(results: Person[], name: string) {\n      let index = 0\n\n      for (const person of results) {\n        if (person.name === name) {\n          return index\n        }\n        index++\n      }\n\n      return -1\n    }\n\n    beforeEach(async () => {\n      peopleService = app.service('people')\n      peopleService.options.multi = true\n      peopleService.options.disableObjectify = true\n      people = await peopleService.create([{ name: 'AAA' }, { name: 'aaa' }, { name: 'ccc' }])\n    })\n\n    afterEach(async () => {\n      peopleService.options.multi = false\n\n      try {\n        await Promise.all([\n          peopleService.remove(people[0]._id),\n          peopleService.remove(people[1]._id),\n          peopleService.remove(people[2]._id)\n        ])\n      } catch (error: unknown) {}\n    })\n\n    it('queries for ObjectId in find', async () => {\n      const person = await peopleService.create({ name: 'Coerce' })\n      const results = await peopleService.find({\n        paginate: false,\n        query: {\n          _id: new ObjectId(person._id)\n        }\n      })\n\n      assert.strictEqual(results.length, 1)\n\n      await peopleService.remove(person._id)\n    })\n\n    it('works with normal string _id', async () => {\n      const person = await peopleService.create({\n        _id: 'lessonKTDA08',\n        name: 'Coerce'\n      })\n      const result = await peopleService.get(person._id)\n\n      assert.strictEqual(result.name, 'Coerce')\n\n      await peopleService.remove(person._id)\n    })\n\n    it('sorts with default behavior without collation param', async () => {\n      const results = await peopleService.find({\n        paginate: false,\n        query: { $sort: { name: -1 } }\n      })\n\n      assert.ok(indexOfName(results, 'aaa') < indexOfName(results, 'AAA'))\n    })\n\n    it('sorts using collation param if present', async () => {\n      const results = await peopleService.find({\n        paginate: false,\n        query: { $sort: { name: -1 } },\n        mongodb: { collation: { locale: 'en', strength: 1 } }\n      })\n\n      assert.ok(indexOfName(results, 'aaa') > indexOfName(results, 'AAA'))\n    })\n\n    it('removes with default behavior without collation param', async () => {\n      await peopleService.remove(null, { query: { name: { $gt: 'AAA' } } })\n\n      const results = await peopleService.find({ paginate: false })\n\n      assert.strictEqual(results.length, 1)\n      assert.strictEqual(results[0].name, 'AAA')\n    })\n\n    it('removes using collation param if present', async () => {\n      const removed = await peopleService.remove(null, {\n        query: { name: 'AAA' },\n        mongodb: { collation: { locale: 'en', strength: 1 } }\n      })\n      const results = await peopleService.find({ paginate: false })\n\n      assert.strictEqual(removed.length, 2)\n      assert.strictEqual(results[0].name, 'ccc')\n      assert.strictEqual(results.length, 1)\n    })\n\n    it('handles errors', async () => {\n      await assert.rejects(\n        () =>\n          peopleService.create(\n            {\n              name: 'Dave'\n            },\n            {\n              mongodb: { collation: { locale: 'fdsfdsfds', strength: 1 } }\n            }\n          ),\n        {\n          name: 'GeneralError'\n        }\n      )\n    })\n\n    it('updates with default behavior without collation param', async () => {\n      const query = { name: { $gt: 'AAA' } }\n\n      const result = await peopleService.patch(null, { age: 99 }, { query })\n\n      assert.strictEqual(result.length, 2)\n      result.forEach((person) => {\n        assert.strictEqual(person.age, 99)\n      })\n    })\n\n    it('updates using collation param if present', async () => {\n      const result = await peopleService.patch(\n        null,\n        { age: 110 },\n        {\n          query: { name: { $gt: 'AAA' } },\n          mongodb: { collation: { locale: 'en', strength: 1 } }\n        }\n      )\n\n      assert.strictEqual(result.length, 1)\n      assert.strictEqual(result[0].name, 'ccc')\n    })\n\n    it('pushes to an array using patch', async () => {\n      const result = await peopleService.patch(\n        null,\n        { $push: { friends: 'Adam' } },\n        {\n          query: { name: { $gt: 'AAA' } }\n        }\n      )\n\n      assert.strictEqual(result[0].friends?.length, 1)\n\n      const patched = await peopleService.patch(\n        null,\n        {\n          $push: { friends: 'Bell' }\n        },\n        { query: { name: { $gt: 'AAA' } } }\n      )\n\n      assert.strictEqual(patched[0].friends?.length, 2)\n    })\n\n    it('can use $limit in patch', async () => {\n      const data = { name: 'ddd' }\n      const query = { $limit: 1 }\n\n      const result = await peopleService._patch(null, data, {\n        query\n      })\n\n      assert.strictEqual(result.length, 1)\n      assert.strictEqual(result[0].name, 'ddd')\n\n      const pipelineResult = await peopleService._patch(null, data, {\n        pipeline: [],\n        query\n      })\n\n      assert.strictEqual(pipelineResult.length, 1)\n      assert.strictEqual(pipelineResult[0].name, 'ddd')\n    })\n\n    it('can use $limit in remove', async () => {\n      const query = { $limit: 1 }\n\n      const result = await peopleService._remove(null, {\n        query\n      })\n\n      assert.strictEqual(result.length, 1)\n\n      const pipelineResult = await peopleService._remove(null, {\n        pipeline: [],\n        query\n      })\n\n      assert.strictEqual(pipelineResult.length, 1)\n    })\n\n    it('can use $sort in patch', async () => {\n      const updated = await peopleService._patch(\n        null,\n        { name: 'ddd' },\n        {\n          query: { $limit: 1, $sort: { name: -1 } }\n        }\n      )\n\n      const result = await peopleService.find({\n        paginate: false,\n        query: { $limit: 1, $sort: { name: -1 } }\n      })\n\n      assert.strictEqual(updated.length, 1)\n      assert.strictEqual(result[0].name, 'ddd')\n\n      const pipelineUpdated = await peopleService._patch(\n        null,\n        { name: 'eee' },\n        {\n          pipeline: [],\n          query: { $limit: 1, $sort: { name: -1 } }\n        }\n      )\n\n      const pipelineResult = await peopleService.find({\n        paginate: false,\n        pipeline: [],\n        query: { $limit: 1, $sort: { name: -1 } }\n      })\n\n      assert.strictEqual(pipelineUpdated.length, 1)\n      assert.strictEqual(pipelineResult[0].name, 'eee')\n    })\n\n    it('can use $sort in remove', async () => {\n      const removed = await peopleService._remove(null, {\n        query: { $limit: 1, $sort: { name: -1 } }\n      })\n\n      assert.strictEqual(removed.length, 1)\n      assert.strictEqual(removed[0].name, 'ccc')\n\n      const pipelineRemoved = await peopleService._remove(null, {\n        pipeline: [],\n        query: { $limit: 1, $sort: { name: -1 } }\n      })\n\n      assert.strictEqual(pipelineRemoved.length, 1)\n      assert.strictEqual(pipelineRemoved[0].name, 'aaa')\n    })\n\n    it('overrides default index selection using hint param if present', async () => {\n      const indexed = await peopleService.create({\n        name: 'Indexed',\n        team: 'blue'\n      })\n\n      const result = await peopleService.find({\n        paginate: false,\n        query: {},\n        mongodb: { hint: { name: 1 } }\n      })\n\n      assert.strictEqual(result[0].name, 'Indexed')\n      assert.strictEqual(result.length, 1)\n\n      await peopleService.remove(indexed._id)\n    })\n  })\n\n  describe('Aggregation', () => {\n    let bob: any\n    let alice: any\n    let doug: any\n\n    before(async () => {\n      app.use(\n        'todos',\n        new MongoDBService({\n          Model: db.collection('todos'),\n          events: ['testing']\n        })\n      )\n      bob = await app.service('people').create({ name: 'Bob', age: 25 })\n      alice = await app.service('people').create({ name: 'Alice', age: 19 })\n      doug = await app.service('people').create({ name: 'Doug', age: 32 })\n\n      // Create a task for each person\n      await app.service('todos').create({ name: 'Bob do dishes', userId: bob._id })\n      await app.service('todos').create({ name: 'Bob do laundry', userId: bob._id })\n      await app.service('todos').create({ name: 'Alice do dishes', userId: alice._id })\n      await app.service('todos').create({ name: 'Doug do dishes', userId: doug._id })\n    })\n\n    after(async () => {\n      db.collection('people').deleteMany({})\n      db.collection('todos').deleteMany({})\n    })\n\n    it('assumes the feathers stage runs before all if it is not explicitly provided in pipeline', async () => {\n      const result = await app.service('todos').find({\n        query: { name: /dishes/, $sort: { name: 1 } },\n        pipeline: [\n          {\n            $lookup: {\n              from: 'people',\n              localField: 'userId',\n              foreignField: '_id',\n              as: 'person'\n            }\n          },\n          { $unwind: { path: '$person' } }\n        ],\n        paginate: false\n      })\n      assert.deepEqual(result[0].person, alice)\n      assert.deepEqual(result[1].person, bob)\n      assert.deepEqual(result[2].person, doug)\n    })\n\n    it('can prepend stages by explicitly placing the feathers stage', async () => {\n      const result = await app.service('todos').find({\n        query: { $sort: { name: 1 } },\n        pipeline: [\n          { $match: { name: 'Bob do dishes' } },\n          { $feathers: {} },\n          {\n            $lookup: {\n              from: 'people',\n              localField: 'userId',\n              foreignField: '_id',\n              as: 'person'\n            }\n          },\n          { $unwind: { path: '$person' } }\n        ],\n        paginate: false\n      })\n      assert.deepEqual(result[0].person, bob)\n      assert.equal(result.length, 1)\n    })\n\n    it('can count documents with aggregation', async () => {\n      const service = app.service('people')\n      const paginateBefore = service.options.paginate\n\n      const test = async (paginate: any) => {\n        service.options.paginate = paginate\n        const query = { age: { $gte: 25 } }\n        const findResult = await app.service('people').find({ query })\n        const aggregationResult = await app.service('people').find({ query, pipeline: [] })\n        assert.deepStrictEqual(findResult.total, aggregationResult.total)\n      }\n\n      await test({ default: 10, max: 50 })\n      // There are 2 people with age >= 25.\n      // Test that aggregation works when results are less than default\n      await test({ default: 1, max: 50 })\n\n      service.options.paginate = paginateBefore\n    })\n\n    it('can use aggregation in _get', async () => {\n      const dave = await app.service('people').create({ name: 'Dave', age: 25 })\n      const result = await app.service('people').get(dave._id, {\n        pipeline: [{ $addFields: { aggregation: true } }]\n      })\n\n      assert.deepStrictEqual(result, { ...dave, aggregation: true })\n\n      app.service('people').remove(dave._id)\n    })\n\n    it('can use aggregation in _create', async () => {\n      const dave = (await app.service('people').create(\n        { name: 'Dave' },\n        {\n          pipeline: [{ $addFields: { aggregation: true } }]\n        }\n      )) as any\n\n      assert.deepStrictEqual(dave.aggregation, true)\n\n      app.service('people').remove(dave._id)\n    })\n\n    it('can use aggregation in multi _create', async () => {\n      app.service('people').options.multi = true\n      const dave = (await app.service('people').create([{ name: 'Dave' }], {\n        pipeline: [{ $addFields: { aggregation: true } }]\n      })) as any\n\n      assert.deepStrictEqual(dave[0].aggregation, true)\n\n      app.service('people').options.multi = false\n      app.service('people').remove(dave[0]._id)\n    })\n\n    it('can use aggregation in _update', async () => {\n      const dave = await app.service('people').create({ name: 'Dave' })\n      const result = await app.service('people').update(\n        dave._id,\n        {\n          name: 'Marshal'\n        },\n        {\n          pipeline: [{ $addFields: { aggregation: true } }]\n        }\n      )\n\n      assert.deepStrictEqual(result, { ...dave, name: 'Marshal', aggregation: true })\n\n      app.service('people').remove(dave._id)\n    })\n\n    it('can use aggregation in _patch', async () => {\n      const dave = await app.service('people').create({ name: 'Dave' })\n      const result = await app.service('people').patch(\n        dave._id,\n        {\n          name: 'Marshal'\n        },\n        {\n          pipeline: [{ $addFields: { aggregation: true } }]\n        }\n      )\n\n      assert.deepStrictEqual(result, { ...dave, name: 'Marshal', aggregation: true })\n\n      app.service('people').remove(dave._id)\n    })\n\n    it('can use aggregation in multi _patch', async () => {\n      app.service('people').options.multi = true\n      const dave = await app.service('people').create({ name: 'Dave' })\n      const result = await app.service('people').patch(\n        null,\n        {\n          name: 'Marshal'\n        },\n        {\n          query: { _id: dave._id },\n          pipeline: [{ $addFields: { aggregation: true } }]\n        }\n      )\n\n      assert.deepStrictEqual(result[0], { ...dave, name: 'Marshal', aggregation: true })\n\n      app.service('people').options.multi = false\n      app.service('people').remove(dave._id)\n    })\n\n    it('can use aggregation and query in _update', async () => {\n      const dave = await app.service('people').create({ name: 'Dave' })\n      const result = await app.service('people').update(\n        dave._id,\n        {\n          name: 'Marshal'\n        },\n        {\n          query: { name: 'Dave' },\n          pipeline: [{ $addFields: { aggregation: true } }]\n        }\n      )\n\n      assert.deepStrictEqual(result, { ...dave, name: 'Marshal', aggregation: true })\n\n      app.service('people').remove(dave._id)\n    })\n\n    it('can use aggregation and query in _patch', async () => {\n      const dave = await app.service('people').create({ name: 'Dave' })\n      const result = await app.service('people').patch(\n        dave._id,\n        {\n          name: 'Marshal'\n        },\n        {\n          query: { name: 'Dave' },\n          pipeline: [{ $addFields: { aggregation: true } }]\n        }\n      )\n\n      assert.deepStrictEqual(result, { ...dave, name: 'Marshal', aggregation: true })\n\n      app.service('people').remove(dave._id)\n    })\n\n    it('can use aggregation in _remove', async () => {\n      const dave = await app.service('people').create({ name: 'Dave' })\n      const result = await app.service('people').remove(dave._id, {\n        pipeline: [{ $addFields: { aggregation: true } }]\n      })\n\n      assert.deepStrictEqual(result, { ...dave, aggregation: true })\n\n      try {\n        await await app.service('people').get(dave._id)\n        throw new Error('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.name, 'NotFound', 'Got a NotFound Feathers error')\n      }\n    })\n\n    it('can use aggregation in multi _remove', async () => {\n      app.service('people').options.multi = true\n      const dave = await app.service('people').create({ name: 'Dave' })\n      const result = await app.service('people').remove(null, {\n        query: { _id: dave._id },\n        pipeline: [{ $addFields: { aggregation: true } }]\n      })\n\n      assert.deepStrictEqual(result[0], { ...dave, aggregation: true })\n\n      app.service('people').options.multi = false\n      // app.service('people').remove(dave._id)\n    })\n  })\n\n  describe('query validation', () => {\n    it('validated queries are not sanitized', async () => {\n      const dave = await app.service('people').create({ name: 'Dave' })\n      const result = await app.service('people').find({\n        query: {\n          name: {\n            $regex: 'Da.*'\n          }\n        }\n      })\n      assert.deepStrictEqual(result, [dave])\n\n      app.service('people').remove(dave._id)\n    })\n  })\n\n  // TODO: Should this test be part of the adapterTests?\n  describe('Updates mutated query', () => {\n    it('Can re-query mutated data', async () => {\n      const dave = await app.service('people').create({ name: 'Dave' })\n      const dave2 = await app.service('people').create({ name: 'Dave' })\n      app.service('people').options.multi = true\n\n      const updated = await app\n        .service('people')\n        .update(dave._id, { name: 'Marshal' }, { query: { name: 'Dave' } })\n\n      assert.deepStrictEqual(updated, {\n        ...dave,\n        name: 'Marshal'\n      })\n\n      const patched = await app\n        .service('people')\n        .patch(dave._id, { name: 'Dave' }, { query: { name: 'Marshal' } })\n\n      assert.deepStrictEqual(patched, {\n        ...dave,\n        name: 'Dave'\n      })\n\n      const updatedPipeline = await app\n        .service('people')\n        .update(dave._id, { name: 'Marshal' }, { query: { name: 'Dave' }, pipeline: [] })\n\n      assert.deepStrictEqual(updatedPipeline, {\n        ...dave,\n        name: 'Marshal'\n      })\n\n      const patchedPipeline = await app\n        .service('people')\n        .patch(dave._id, { name: 'Dave' }, { query: { name: 'Marshal' }, pipeline: [] })\n\n      assert.deepStrictEqual(patchedPipeline, {\n        ...dave,\n        name: 'Dave'\n      })\n\n      const multiPatch = await app\n        .service('people')\n        .patch(null, { name: 'Marshal' }, { query: { name: 'Dave' } })\n\n      assert.deepStrictEqual(multiPatch, [\n        {\n          ...dave,\n          name: 'Marshal'\n        },\n        {\n          ...dave2,\n          name: 'Marshal'\n        }\n      ])\n\n      const multiPatchPipeline = await app\n        .service('people')\n        .patch(null, { name: 'Dave' }, { query: { name: 'Marshal' }, pipeline: [] })\n\n      assert.deepStrictEqual(multiPatchPipeline, [\n        {\n          ...dave,\n          name: 'Dave'\n        },\n        {\n          ...dave2,\n          name: 'Dave'\n        }\n      ])\n\n      app.service('people').options.multi = false\n\n      app.service('people').remove(dave._id)\n      app.service('people').remove(dave2._id)\n    })\n  })\n\n  describe('disabledOperators in _patch', () => {\n    it('drops $rename by default', async () => {\n      const person = await app.service('people').create({ name: 'Secure', age: 30 })\n\n      const result = await app.service('people').patch(person._id, {\n        name: 'Updated',\n        $rename: { age: 'exposed' }\n      } as any)\n\n      assert.strictEqual(result.name, 'Updated')\n      assert.strictEqual(result.age, 30)\n\n      await app.service('people').remove(person._id)\n    })\n\n    it('allows $push and other operators not in the denylist', async () => {\n      const person = await app.service('people').create({ name: 'PushTest', age: 20 })\n\n      const result = await app.service('people').patch(person._id, {\n        $push: { friends: 'Alice' }\n      } as any)\n\n      assert.strictEqual(result.friends?.length, 1)\n      assert.strictEqual(result.friends[0], 'Alice')\n\n      await app.service('people').remove(person._id)\n    })\n\n    it('drops operators added to disabledOperators', async () => {\n      const person = await app.service('people').create({ name: 'IncTest', age: 25 })\n\n      const result = await app.service('people').patch(\n        person._id,\n        {\n          $inc: { age: 100 }\n        } as any,\n        {\n          adapter: { disabledOperators: ['$rename', '$inc'] }\n        }\n      )\n\n      assert.strictEqual(result.age, 25)\n\n      await app.service('people').remove(person._id)\n    })\n  })\n\n  describe('NoSQL injection via object id', () => {\n    let target: Person\n\n    beforeEach(async () => {\n      target = await app.service('people').create({ name: 'Target' })\n    })\n\n    afterEach(async () => {\n      try {\n        await app.service('people').remove(target._id)\n      } catch (e: unknown) {}\n    })\n\n    it('rejects object as id in get', async () => {\n      await assert.rejects(() => app.service('people').get({ $ne: null } as any), {\n        name: 'BadRequest'\n      })\n    })\n\n    it('rejects object as id in remove', async () => {\n      await assert.rejects(() => app.service('people').remove({ $ne: null } as any), {\n        name: 'BadRequest'\n      })\n    })\n\n    it('rejects object as id in update', async () => {\n      await assert.rejects(() => app.service('people').update({ $ne: null } as any, { name: 'Hacked' }), {\n        name: 'BadRequest'\n      })\n    })\n\n    it('rejects object as id in patch', async () => {\n      await assert.rejects(() => app.service('people').patch({ $ne: null } as any, { name: 'Hacked' }), {\n        name: 'BadRequest'\n      })\n    })\n\n    it('rejects regex operator as id', async () => {\n      await assert.rejects(() => app.service('people').get({ $regex: '^' } as any), {\n        name: 'BadRequest'\n      })\n    })\n  })\n\n  testSuite(app, errors, 'people', '_id')\n  testSuite(app, errors, 'people-customid', 'customid')\n})\n"
  },
  {
    "path": "packages/mongodb/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/rest-client/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n### Bug Fixes\n\n- **client:** Ensure all client methods require valid ids ([#3661](https://github.com/feathersjs/feathers/issues/3661)) ([bc754d3](https://github.com/feathersjs/feathers/commit/bc754d3666b059b9d93799602dac427cb419ddc6))\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **client:** Replace placeholders in URL with route params ([#3270](https://github.com/feathersjs/feathers/issues/3270)) ([a0624eb](https://github.com/feathersjs/feathers/commit/a0624eb5a7919aa1b179a71beb1c1b9cab574525))\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n### Bug Fixes\n\n- **client:** Add underscored methods to clients ([#3176](https://github.com/feathersjs/feathers/issues/3176)) ([f3c01f7](https://github.com/feathersjs/feathers/commit/f3c01f7b8266bfc642c55b77ba8e5bb333542630))\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Features\n\n- **cli:** Add typed client to a generated app ([#2669](https://github.com/feathersjs/feathers/issues/2669)) ([5b801b5](https://github.com/feathersjs/feathers/commit/5b801b5017ddc3eaa95622b539f51d605916bc86))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n### Bug Fixes\n\n- **express:** Ensure Express options can be set before configuring REST transport ([#2655](https://github.com/feathersjs/feathers/issues/2655)) ([c9b8f74](https://github.com/feathersjs/feathers/commit/c9b8f74a0196acb99be44ac5e0fff3f1128288cd))\n\n### Features\n\n- **client:** Improve client side custom method support ([#2654](https://github.com/feathersjs/feathers/issues/2654)) ([c138acf](https://github.com/feathersjs/feathers/commit/c138acf50affbe6b66177d084d3c7a3e9220f09f))\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Features\n\n- **typescript:** Improve adapter typings ([#2605](https://github.com/feathersjs/feathers/issues/2605)) ([3b2ca0a](https://github.com/feathersjs/feathers/commit/3b2ca0a6a8e03e8390272c4d7e930b4bffdaacf5))\n- **typescript:** Improve params and query typeability ([#2600](https://github.com/feathersjs/feathers/issues/2600)) ([df28b76](https://github.com/feathersjs/feathers/commit/df28b7619161f1df5e700326f52cca1a92dc5d28))\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n### Features\n\n- **express, koa:** make transports similar ([#2486](https://github.com/feathersjs/feathers/issues/2486)) ([26aa937](https://github.com/feathersjs/feathers/commit/26aa937c114fb8596dfefc599b1f53cead69c159))\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Features\n\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n### Bug Fixes\n\n- **dependencies:** Fix transport-commons dependency and update other dependencies ([#2284](https://github.com/feathersjs/feathers/issues/2284)) ([05b03b2](https://github.com/feathersjs/feathers/commit/05b03b27b40604d956047e3021d8053c3a137616))\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n### Features\n\n- **core:** Public custom service methods ([#2270](https://github.com/feathersjs/feathers/issues/2270)) ([e65abfb](https://github.com/feathersjs/feathers/commit/e65abfb5388df6c19a11c565cf1076a29f32668d))\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n### Bug Fixes\n\n- **rest-client:** Handle non-JSON errors with fetch adapter ([#2086](https://github.com/feathersjs/feathers/issues/2086)) ([e24217a](https://github.com/feathersjs/feathers/commit/e24217ad1e784ad71cd9d64fe1727dd02f039991))\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.5.6](https://github.com/feathersjs/feathers/compare/v4.5.5...v4.5.6) (2020-07-12)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.5.4](https://github.com/feathersjs/feathers/compare/v4.5.3...v4.5.4) (2020-04-29)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n### Features\n\n- **rest-client:** Allow for customising rest clients ([#1780](https://github.com/feathersjs/feathers/issues/1780)) ([c5cfec7](https://github.com/feathersjs/feathers/commit/c5cfec7a4aafcaffaab0cdacb9b5d297ff20320f))\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n### Bug Fixes\n\n- **core:** Improve hook missing parameter message by adding the service name ([#1703](https://github.com/feathersjs/feathers/issues/1703)) ([2331c2a](https://github.com/feathersjs/feathers/commit/2331c2a3dd70d432db7d62a76ed805d359cbbba5))\n- **rest-client:** Allow to customize getting the query ([#1594](https://github.com/feathersjs/feathers/issues/1594)) ([5f21272](https://github.com/feathersjs/feathers/commit/5f212729849414c4da6f0d51edd1986feca992ee))\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.3.5](https://github.com/feathersjs/feathers/compare/v4.3.4...v4.3.5) (2019-10-07)\n\n### Bug Fixes\n\n- Change this reference in client libraries to explicitly passed app ([#1597](https://github.com/feathersjs/feathers/issues/1597)) ([4e4d10a](https://github.com/feathersjs/feathers/commit/4e4d10a))\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n### Bug Fixes\n\n- Use `export =` in TypeScript definitions ([#1285](https://github.com/feathersjs/feathers/issues/1285)) ([12d0f4b](https://github.com/feathersjs/feathers/commit/12d0f4b))\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n\n### Features\n\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Authentication v3 core server implementation ([#1205](https://github.com/feathersjs/feathers/issues/1205)) ([1bd7591](https://github.com/feathersjs/feathers/commit/1bd7591))\n\n## [1.4.7](https://github.com/feathersjs/feathers/compare/@feathersjs/rest-client@1.4.6...@feathersjs/rest-client@1.4.7) (2019-01-02)\n\n### Bug Fixes\n\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n\n<a name=\"1.4.6\"></a>\n\n## [1.4.6](https://github.com/feathersjs/feathers/compare/@feathersjs/rest-client@1.4.5...@feathersjs/rest-client@1.4.6) (2018-12-16)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n\n<a name=\"1.4.5\"></a>\n\n## [1.4.5](https://github.com/feathersjs/feathers/compare/@feathersjs/rest-client@1.4.4...@feathersjs/rest-client@1.4.5) (2018-09-21)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n<a name=\"1.4.4\"></a>\n\n## [1.4.4](https://github.com/feathersjs/feathers/compare/@feathersjs/rest-client@1.4.3...@feathersjs/rest-client@1.4.4) (2018-09-17)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n<a name=\"1.4.3\"></a>\n\n## [1.4.3](https://github.com/feathersjs/feathers/compare/@feathersjs/rest-client@1.4.2...@feathersjs/rest-client@1.4.3) (2018-09-02)\n\n**Note:** Version bump only for package @feathersjs/rest-client\n\n<a name=\"1.4.2\"></a>\n\n## 1.4.2\n\n- Migrate to Monorepo ([feathers#462](https://github.com/feathersjs/feathers/issues/462))\n\n## [v1.4.1](https://github.com/feathersjs/rest-client/tree/v1.4.1) (2018-06-27)\n\n[Full Changelog](https://github.com/feathersjs/rest-client/compare/v1.4.0...v1.4.1)\n\n**Merged pull requests:**\n\n- URL encode ID. [\\#33](https://github.com/feathersjs/rest-client/pull/33) ([SteffenLanger](https://github.com/SteffenLanger))\n- Update shx to the latest version 🚀 [\\#31](https://github.com/feathersjs/rest-client/pull/31) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.4.0](https://github.com/feathersjs/rest-client/tree/v1.4.0) (2018-05-17)\n\n[Full Changelog](https://github.com/feathersjs/rest-client/compare/v1.3.4...v1.4.0)\n\n**Closed issues:**\n\n- Need a way to abort requests [\\#29](https://github.com/feathersjs/rest-client/issues/29)\n- Pass request options to transport \\(request\\) [\\#26](https://github.com/feathersjs/rest-client/issues/26)\n\n**Merged pull requests:**\n\n- Add support for passing library options in params.connection [\\#30](https://github.com/feathersjs/rest-client/pull/30) ([daffl](https://github.com/daffl))\n- Update dependencies to enable Greenkeeper 🌴 [\\#28](https://github.com/feathersjs/rest-client/pull/28) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.3.4](https://github.com/feathersjs/rest-client/tree/v1.3.4) (2018-03-17)\n\n[Full Changelog](https://github.com/feathersjs/rest-client/compare/v1.3.3...v1.3.4)\n\n**Closed issues:**\n\n- Window.fetch on macOS [\\#24](https://github.com/feathersjs/rest-client/issues/24)\n- Error on server side rendering [\\#23](https://github.com/feathersjs/rest-client/issues/23)\n\n**Merged pull requests:**\n\n- Properly serialize ECONNREFUSED errors [\\#27](https://github.com/feathersjs/rest-client/pull/27) ([daffl](https://github.com/daffl))\n- Update axios to the latest version 🚀 [\\#25](https://github.com/feathersjs/rest-client/pull/25) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update node-fetch to the latest version 🚀 [\\#22](https://github.com/feathersjs/rest-client/pull/22) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update mocha to the latest version 🚀 [\\#21](https://github.com/feathersjs/rest-client/pull/21) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.3.3](https://github.com/feathersjs/rest-client/tree/v1.3.3) (2018-01-03)\n\n[Full Changelog](https://github.com/feathersjs/rest-client/compare/v1.3.2...v1.3.3)\n\n**Closed issues:**\n\n- Conditions, like { name: null } , to query resources can't be used. [\\#18](https://github.com/feathersjs/rest-client/issues/18)\n- Failed to minify the code from /lib/base.js [\\#14](https://github.com/feathersjs/rest-client/issues/14)\n\n**Merged pull requests:**\n\n- Update documentation to correspond with latest release [\\#20](https://github.com/feathersjs/rest-client/pull/20) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#19](https://github.com/feathersjs/rest-client/pull/19) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update feathers-memory to the latest version 🚀 [\\#17](https://github.com/feathersjs/rest-client/pull/17) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.3.2](https://github.com/feathersjs/rest-client/tree/v1.3.2) (2017-11-16)\n\n[Full Changelog](https://github.com/feathersjs/rest-client/compare/v1.3.1...v1.3.2)\n\n**Merged pull requests:**\n\n- Add default export for better ES module \\(TypeScript\\) compatibility [\\#16](https://github.com/feathersjs/rest-client/pull/16) ([daffl](https://github.com/daffl))\n- Update package.json [\\#15](https://github.com/feathersjs/rest-client/pull/15) ([frank-dspeed](https://github.com/frank-dspeed))\n- Update @angular/platform-browser to the latest version 🚀 [\\#13](https://github.com/feathersjs/rest-client/pull/13) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update @angular/http to the latest version 🚀 [\\#12](https://github.com/feathersjs/rest-client/pull/12) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update @angular/core to the latest version 🚀 [\\#11](https://github.com/feathersjs/rest-client/pull/11) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update @angular/common to the latest version 🚀 [\\#10](https://github.com/feathersjs/rest-client/pull/10) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.3.1](https://github.com/feathersjs/rest-client/tree/v1.3.1) (2017-11-01)\n\n[Full Changelog](https://github.com/feathersjs/rest-client/compare/v1.3.0...v1.3.1)\n\n**Merged pull requests:**\n\n- Update dependencies [\\#9](https://github.com/feathersjs/rest-client/pull/9) ([daffl](https://github.com/daffl))\n- Update babelify to the latest version 🚀 [\\#8](https://github.com/feathersjs/rest-client/pull/8) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.3.0](https://github.com/feathersjs/rest-client/tree/v1.3.0) (2017-10-23)\n\n[Full Changelog](https://github.com/feathersjs/rest-client/compare/v1.2.0...v1.3.0)\n\n**Merged pull requests:**\n\n- Update all dependencies to use npm scope [\\#7](https://github.com/feathersjs/rest-client/pull/7) ([daffl](https://github.com/daffl))\n- Update axios to the latest version 🚀 [\\#6](https://github.com/feathersjs/rest-client/pull/6) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.2.0](https://github.com/feathersjs/rest-client/tree/v1.2.0) (2017-10-19)\n\n[Full Changelog](https://github.com/feathersjs/rest-client/compare/v1.1.1-0...v1.2.0)\n\n## [v1.1.1-0](https://github.com/feathersjs/rest-client/tree/v1.1.1-0) (2017-10-19)\n\n[Full Changelog](https://github.com/feathersjs/rest-client/compare/v1.1.0...v1.1.1-0)\n\n**Merged pull requests:**\n\n- Rename repository to publish in npm namespace [\\#5](https://github.com/feathersjs/rest-client/pull/5) ([daffl](https://github.com/daffl))\n- Upgrade to use Feathers v3 [\\#4](https://github.com/feathersjs/rest-client/pull/4) ([daffl](https://github.com/daffl))\n- Update mocha to the latest version 🚀 [\\#3](https://github.com/feathersjs/rest-client/pull/3) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.1.0](https://github.com/feathersjs/rest-client/tree/v1.1.0) (2017-07-20)\n\n[Full Changelog](https://github.com/feathersjs/rest-client/compare/v1.0.0...v1.1.0)\n\n**Merged pull requests:**\n\n- add support for @angular/common/http \\(HttpClient\\) [\\#2](https://github.com/feathersjs/rest-client/pull/2) ([j2L4e](https://github.com/j2L4e))\n\n## [v1.0.0](https://github.com/feathersjs/rest-client/tree/v1.0.0) (2017-07-16)\n\n**Merged pull requests:**\n\n- Update dependencies to enable Greenkeeper 🌴 [\\#1](https://github.com/feathersjs/rest-client/pull/1) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/rest-client/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/rest-client/README.md",
    "content": "# @feathersjs/rest-client\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/rest-client.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/rest-client)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> REST client services for different HTTP libraries\n\n## Installation\n\n```\nnpm install @feathersjs/rest-client --save\n```\n\n## Documentation\n\nRefer to the [Feathers REST client API documentation](https://feathersjs.com/api/client/rest.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/rest-client/package.json",
    "content": "{\n  \"name\": \"@feathersjs/rest-client\",\n  \"description\": \"REST client services for different Ajax libraries\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/rest-client\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@types/superagent\": \"^8.1.9\",\n    \"qs\": \"^6.15.0\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/express\": \"^5.0.42\",\n    \"@feathersjs/memory\": \"^5.0.42\",\n    \"@feathersjs/tests\": \"^5.0.42\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"@types/node-fetch\": \"^2.6.13\",\n    \"@types/qs\": \"^6.14.0\",\n    \"axios\": \"^1.13.6\",\n    \"mocha\": \"^11.7.5\",\n    \"node-fetch\": \"^2.6.1\",\n    \"rxjs\": \"^7.8.2\",\n    \"shx\": \"^0.4.0\",\n    \"superagent\": \"^10.3.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/rest-client/src/axios.ts",
    "content": "import { Params } from '@feathersjs/feathers'\nimport { Base, RestClientParams } from './base'\n\nexport class AxiosClient<T = any, D = Partial<T>, P extends Params = RestClientParams> extends Base<T, D, P> {\n  request(options: any, params: RestClientParams) {\n    const config = Object.assign(\n      {\n        url: options.url,\n        method: options.method,\n        data: options.body,\n        headers: Object.assign(\n          {\n            Accept: 'application/json'\n          },\n          this.options.headers,\n          options.headers\n        )\n      },\n      params.connection\n    )\n\n    return this.connection\n      .request(config)\n      .then((res: any) => res.data)\n      .catch((error: any) => {\n        const response = error.response || error\n\n        throw response instanceof Error ? response : response.data || response\n      })\n  }\n}\n"
  },
  {
    "path": "packages/rest-client/src/base.ts",
    "content": "import qs from 'qs'\nimport { Params, Id, Query, NullableId, ServiceInterface } from '@feathersjs/feathers'\nimport { BadRequest, Unavailable, convert } from '@feathersjs/errors'\nimport { _, stripSlashes } from '@feathersjs/commons'\n\nfunction toError(error: Error & { code: string }) {\n  if (error.code === 'ECONNREFUSED') {\n    throw new Unavailable(error.message, _.pick(error, 'address', 'port', 'config'))\n  }\n\n  throw convert(error)\n}\n\nexport interface RestClientParams extends Params {\n  connection?: any\n}\n\ninterface RestClientSettings {\n  name: string\n  base: string\n  connection: any\n  options: any\n}\n\nexport abstract class Base<\n  T = any,\n  D = Partial<T>,\n  P extends Params = RestClientParams\n> implements ServiceInterface<T, D, P> {\n  name: string\n  base: string\n  connection: any\n  options: any\n\n  constructor(settings: RestClientSettings) {\n    this.name = stripSlashes(settings.name)\n    this.options = settings.options\n    this.connection = settings.connection\n    this.base = `${settings.base}/${this.name}`\n  }\n\n  makeUrl(query: Query, id?: string | number | null, route?: { [key: string]: string }) {\n    let url = this.base\n\n    if (route) {\n      Object.keys(route).forEach((key) => {\n        url = url.replace(`:${key}`, route[key])\n      })\n    }\n\n    query = query || {}\n\n    if (typeof id !== 'undefined' && id !== null) {\n      url += `/${encodeURIComponent(id)}`\n    }\n\n    return url + this.getQuery(query)\n  }\n\n  getQuery(query: Query) {\n    if (Object.keys(query).length !== 0) {\n      const queryString = qs.stringify(query)\n\n      return `?${queryString}`\n    }\n\n    return ''\n  }\n\n  abstract request(options: any, params: P): any\n\n  methods(this: any, ...names: string[]) {\n    names.forEach((method) => {\n      const _method = `_${method}`\n      this[_method] = function (data: any, params: Params = {}) {\n        return this.request(\n          {\n            body: data,\n            url: this.makeUrl(params.query, null, params.route),\n            method: 'POST',\n            headers: Object.assign(\n              {\n                'Content-Type': 'application/json',\n                'X-Service-Method': method\n              },\n              params.headers\n            )\n          },\n          params\n        ).catch(toError)\n      }\n      this[method] = function (data: any, params: Params = {}) {\n        return this[_method](data, params)\n      }\n    })\n\n    return this\n  }\n\n  _find(params?: P) {\n    return this.request(\n      {\n        url: this.makeUrl(params.query, null, params.route),\n        method: 'GET',\n        headers: Object.assign({}, params.headers)\n      },\n      params\n    ).catch(toError)\n  }\n\n  find(params?: P) {\n    return this._find(params)\n  }\n\n  _get(id: Id, params?: P) {\n    if (id === undefined || id === '') {\n      return Promise.reject(new BadRequest('id for .get is required'))\n    }\n\n    return this.request(\n      {\n        url: this.makeUrl(params.query, id, params.route),\n        method: 'GET',\n        headers: Object.assign({}, params.headers)\n      },\n      params\n    ).catch(toError)\n  }\n\n  get(id: Id, params?: P) {\n    return this._get(id, params)\n  }\n\n  _create(data: D, params?: P) {\n    return this.request(\n      {\n        url: this.makeUrl(params.query, null, params.route),\n        body: data,\n        method: 'POST',\n        headers: Object.assign({ 'Content-Type': 'application/json' }, params.headers)\n      },\n      params\n    ).catch(toError)\n  }\n\n  create(data: D, params?: P) {\n    return this._create(data, params)\n  }\n\n  _update(id: NullableId, data: D, params?: P) {\n    if (id === undefined || id === '') {\n      return Promise.reject(new BadRequest('id for .update is required'))\n    }\n\n    return this.request(\n      {\n        url: this.makeUrl(params.query, id, params.route),\n        body: data,\n        method: 'PUT',\n        headers: Object.assign({ 'Content-Type': 'application/json' }, params.headers)\n      },\n      params\n    ).catch(toError)\n  }\n\n  update(id: NullableId, data: D, params?: P) {\n    return this._update(id, data, params)\n  }\n\n  _patch(id: NullableId, data: D, params?: P) {\n    if (id === undefined || id === '') {\n      return Promise.reject(new BadRequest('id for .patch is required'))\n    }\n\n    return this.request(\n      {\n        url: this.makeUrl(params.query, id, params.route),\n        body: data,\n        method: 'PATCH',\n        headers: Object.assign({ 'Content-Type': 'application/json' }, params.headers)\n      },\n      params\n    ).catch(toError)\n  }\n\n  patch(id: NullableId, data: D, params?: P) {\n    return this._patch(id, data, params)\n  }\n\n  _remove(id: NullableId, params?: P) {\n    if (id === undefined || id === '') {\n      return Promise.reject(new BadRequest('id for .remove is required'))\n    }\n\n    return this.request(\n      {\n        url: this.makeUrl(params.query, id, params.route),\n        method: 'DELETE',\n        headers: Object.assign({}, params.headers)\n      },\n      params\n    ).catch(toError)\n  }\n\n  remove(id: NullableId, params?: P) {\n    return this._remove(id, params)\n  }\n}\n"
  },
  {
    "path": "packages/rest-client/src/fetch.ts",
    "content": "import { errors } from '@feathersjs/errors'\nimport { Params } from '@feathersjs/feathers'\nimport { Base, RestClientParams } from './base'\n\nexport class FetchClient<T = any, D = Partial<T>, P extends Params = RestClientParams> extends Base<T, D, P> {\n  request(options: any, params: RestClientParams) {\n    const fetchOptions = Object.assign({}, options, params.connection)\n\n    fetchOptions.headers = Object.assign(\n      {\n        Accept: 'application/json'\n      },\n      this.options.headers,\n      fetchOptions.headers\n    )\n\n    if (options.body) {\n      fetchOptions.body = JSON.stringify(options.body)\n    }\n\n    return this.connection(options.url, fetchOptions)\n      .then(this.checkStatus)\n      .then((response: any) => {\n        if (response.status === 204) {\n          return null\n        }\n\n        return response.json()\n      })\n  }\n\n  checkStatus(response: any) {\n    if (response.ok) {\n      return response\n    }\n\n    return response\n      .json()\n      .catch(() => {\n        const ErrorClass = (errors as any)[response.status] || Error\n\n        return new ErrorClass('JSON parsing error')\n      })\n      .then((error: any) => {\n        error.response = response\n        throw error\n      })\n  }\n}\n"
  },
  {
    "path": "packages/rest-client/src/index.ts",
    "content": "import { Application, TransportConnection, defaultServiceMethods } from '@feathersjs/feathers'\n\nimport { Base } from './base'\nimport { AxiosClient } from './axios'\nimport { FetchClient } from './fetch'\nimport { SuperagentClient } from './superagent'\n\nexport { AxiosClient, FetchClient, SuperagentClient }\n\nconst transports = {\n  superagent: SuperagentClient,\n  fetch: FetchClient,\n  axios: AxiosClient\n}\n\nexport type Handler<ServiceTypes> = (\n  connection: any,\n  options?: any,\n  Service?: any\n) => TransportConnection<ServiceTypes>\n\nexport interface Transport<ServiceTypes> {\n  superagent: Handler<ServiceTypes>\n  fetch: Handler<ServiceTypes>\n  axios: Handler<ServiceTypes>\n}\n\nexport type RestService<T = any, D = Partial<any>> = Base<T, D>\n\nexport default function restClient<ServiceTypes = any>(base = '') {\n  const result: any = { Base }\n\n  Object.keys(transports).forEach((key) => {\n    result[key] = function (connection: any, options: any = {}, Service: Base = (transports as any)[key]) {\n      if (!connection) {\n        throw new Error(`${key} has to be provided to feathers-rest`)\n      }\n\n      if (typeof options === 'function') {\n        Service = options\n        options = {}\n      }\n\n      const defaultService = function (name: string) {\n        return new (Service as any)({ base, name, connection, options })\n      }\n\n      const initialize = (app: Application & { rest: any }) => {\n        if (app.rest !== undefined) {\n          throw new Error('Only one default client provider can be configured')\n        }\n\n        app.rest = connection\n        app.defaultService = defaultService\n        app.mixins.unshift((service, _location, options) => {\n          if (options && options.methods && service instanceof Base) {\n            const customMethods = options.methods.filter((name) => !defaultServiceMethods.includes(name))\n\n            service.methods(...customMethods)\n          }\n        })\n      }\n\n      initialize.Service = Service\n      initialize.service = defaultService\n\n      return initialize\n    }\n  })\n\n  return result as Transport<ServiceTypes>\n}\n\nif (typeof module !== 'undefined') {\n  module.exports = Object.assign(restClient, module.exports)\n}\n"
  },
  {
    "path": "packages/rest-client/src/superagent.ts",
    "content": "import { Params } from '@feathersjs/feathers'\nimport { Base, RestClientParams } from './base'\n\nexport class SuperagentClient<T = any, D = Partial<T>, P extends Params = RestClientParams> extends Base<\n  T,\n  D,\n  P\n> {\n  request(options: any, params: RestClientParams) {\n    const superagent = this.connection(options.method, options.url)\n      .set(this.options.headers || {})\n      .set('Accept', 'application/json')\n      .set(params.connection || {})\n      .set(options.headers || {})\n      .type(options.type || 'json')\n\n    return new Promise((resolve, reject) => {\n      superagent.set(options.headers)\n\n      if (options.body) {\n        superagent.send(options.body)\n      }\n\n      superagent.end(function (error: any, res: any) {\n        if (error) {\n          try {\n            const response = error.response\n            error = JSON.parse(error.response.text)\n            error.response = response\n          } catch (e: any) {}\n\n          return reject(error)\n        }\n\n        resolve(res && res.body)\n      })\n    })\n  }\n}\n"
  },
  {
    "path": "packages/rest-client/test/axios.test.ts",
    "content": "import { strict as assert } from 'assert'\n\nimport axios from 'axios'\nimport { Server } from 'http'\nimport { feathers } from '@feathersjs/feathers'\nimport { clientTests } from '@feathersjs/tests'\nimport { NotAcceptable } from '@feathersjs/errors'\n\nimport createServer from './server'\nimport rest from '../src'\nimport { ServiceTypes } from './declarations'\n\ndescribe('Axios REST connector', function () {\n  const url = 'http://localhost:8889'\n  const connection = rest<ServiceTypes>(url).axios(axios)\n  const app = feathers<ServiceTypes>()\n    .configure(connection)\n    .use('todos', connection.service('todos'), {\n      methods: ['get', 'find', 'create', 'patch', 'customMethod']\n    })\n  const service = app.service('todos')\n  let server: Server\n\n  before(async () => {\n    server = await createServer().listen(8889)\n  })\n\n  after((done) => server.close(done))\n\n  it('supports custom headers', async () => {\n    const headers = {\n      Authorization: 'let-me-in'\n    }\n\n    const todo = await service.get(0, { headers })\n\n    assert.deepStrictEqual(todo, {\n      id: 0,\n      authorization: 'let-me-in',\n      text: 'some todo',\n      complete: false,\n      query: {}\n    })\n  })\n\n  it('uses params.connection for additional options', async () => {\n    const connection = {\n      headers: {\n        Authorization: 'let-me-in'\n      }\n    }\n\n    const todo = await service.get(0, { connection })\n\n    assert.deepStrictEqual(todo, {\n      id: 0,\n      authorization: 'let-me-in',\n      text: 'some todo',\n      complete: false,\n      query: {}\n    })\n  })\n\n  it('can initialize a client instance', async () => {\n    const init = rest(url).axios(axios)\n    const todoService = init.service('todos')\n\n    assert.ok(todoService instanceof init.Service, 'Returned service is a client')\n\n    const todos = await todoService.find({})\n\n    assert.deepStrictEqual(todos, [\n      {\n        text: 'some todo',\n        complete: false,\n        id: 0\n      }\n    ])\n  })\n\n  it('supports nested arrays in queries', async () => {\n    const query = { test: { $in: ['0', '1', '2'] } }\n\n    const data = await service.get(0, { query })\n\n    assert.deepStrictEqual(data.query, query)\n  })\n\n  it('remove many', async () => {\n    const todo: any = await service.remove(null)\n\n    assert.strictEqual(todo.id, null)\n    assert.strictEqual(todo.text, 'deleted many')\n  })\n\n  it('converts feathers errors (#50)', async () => {\n    try {\n      await service.get(0, { query: { feathersError: true } })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.ok(error instanceof NotAcceptable)\n      assert.strictEqual(error.message, 'This is a Feathers error')\n      assert.strictEqual(error.code, 406)\n    }\n  })\n\n  it('ECONNREFUSED errors are serializable', async () => {\n    const url = 'http://localhost:60000'\n    const setup = rest(url).axios(axios)\n    const app = feathers().configure(setup)\n\n    try {\n      await app.service('something').find()\n      assert.fail('Should never get here')\n    } catch (e: any) {\n      const err = JSON.parse(JSON.stringify(e))\n\n      assert.strictEqual(err.name, 'Unavailable')\n      assert.ok(e.data.config)\n    }\n  })\n\n  it('works with custom method .customMethod', async () => {\n    const result = await service.customMethod({ message: 'hi' })\n\n    assert.deepEqual(result, {\n      data: { message: 'hi' },\n      provider: 'rest',\n      type: 'customMethod'\n    })\n  })\n\n  clientTests(service, 'todos')\n})\n"
  },
  {
    "path": "packages/rest-client/test/declarations.ts",
    "content": "import { CustomMethod } from '@feathersjs/feathers'\nimport { RestService } from '../src'\n\ntype Data = { message: string }\ntype Result = {\n  data: Data\n  provider: string\n  type: string\n}\n\nexport type ServiceTypes = {\n  todos: RestService & {\n    customMethod: CustomMethod<Data, Result>\n  }\n}\n"
  },
  {
    "path": "packages/rest-client/test/fetch.test.ts",
    "content": "import { strict as assert } from 'assert'\nimport fetch from 'node-fetch'\nimport { feathers } from '@feathersjs/feathers'\nimport { clientTests } from '@feathersjs/tests'\nimport { NotAcceptable } from '@feathersjs/errors'\nimport { Server } from 'http'\n\nimport rest from '../src'\nimport createServer from './server'\nimport { ServiceTypes } from './declarations'\n\ndescribe('fetch REST connector', function () {\n  const url = 'http://localhost:8889'\n  const connection = rest<ServiceTypes>(url).fetch(fetch)\n  const app = feathers<ServiceTypes>()\n    .configure(connection)\n    .use('todos', connection.service('todos'), {\n      methods: ['get', 'find', 'create', 'patch', 'customMethod']\n    })\n\n  const service = app.service('todos')\n  let server: Server\n\n  service.hooks({\n    after: {\n      customMethod: [\n        (context) => {\n          context.result.data.message += '!'\n        }\n      ]\n    }\n  })\n\n  before(async () => {\n    server = await createServer().listen(8889)\n  })\n\n  after((done) => server.close(done))\n\n  it('supports custom headers', async () => {\n    const headers = {\n      Authorization: 'let-me-in'\n    }\n\n    const todo = await service.get(0, { headers })\n\n    assert.deepStrictEqual(todo, {\n      id: 0,\n      text: 'some todo',\n      authorization: 'let-me-in',\n      complete: false,\n      query: {}\n    })\n  })\n\n  it('supports params.connection', async () => {\n    const connection = {\n      headers: {\n        Authorization: 'let-me-in'\n      }\n    }\n\n    const todo = await service.get(0, { connection })\n\n    assert.deepStrictEqual(todo, {\n      id: 0,\n      text: 'some todo',\n      authorization: 'let-me-in',\n      complete: false,\n      query: {}\n    })\n  })\n\n  it('handles errors properly', async () => {\n    try {\n      await service.get(-1, {})\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.code, 404)\n    }\n  })\n\n  it('supports nested arrays in queries', async () => {\n    const query = { test: { $in: ['0', '1', '2'] } }\n\n    const data = await service.get(0, { query })\n\n    assert.deepStrictEqual(data.query, query)\n  })\n\n  it('can initialize a client instance', async () => {\n    const init = rest(url).fetch(fetch)\n    const todoService = init.service('todos')\n\n    assert.ok(todoService instanceof init.Service, 'Returned service is a client')\n\n    const todos = await todoService.find({})\n\n    assert.deepStrictEqual(todos, [\n      {\n        text: 'some todo',\n        complete: false,\n        id: 0\n      }\n    ])\n  })\n\n  it('remove many', async () => {\n    const todo: any = await service.remove(null)\n\n    assert.strictEqual(todo.id, null)\n    assert.strictEqual(todo.text, 'deleted many')\n  })\n\n  it('converts feathers errors (#50)', async () => {\n    try {\n      await service.get(0, { query: { feathersError: true } })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.ok(error.response)\n      assert.ok(error instanceof NotAcceptable)\n      assert.strictEqual(error.message, 'This is a Feathers error')\n      assert.strictEqual(error.code, 406)\n      assert.deepStrictEqual(error.data, { data: true })\n    }\n  })\n\n  it('returns null for 204 responses', async () => {\n    const response = await service.remove(0, {\n      query: { noContent: true }\n    })\n\n    assert.strictEqual(response, null)\n  })\n\n  it('works with custom method .customMethod', async () => {\n    const result = await service.customMethod({ message: 'hi' })\n\n    assert.deepEqual(result, {\n      data: { message: 'hi!' },\n      provider: 'rest',\n      type: 'customMethod'\n    })\n  })\n\n  clientTests(service, 'todos')\n})\n"
  },
  {
    "path": "packages/rest-client/test/index.test.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport fetch from 'node-fetch'\nimport { strict as assert } from 'assert'\nimport { feathers } from '@feathersjs/feathers'\nimport { default as init, FetchClient } from '../src'\n\ndescribe('REST client tests', function () {\n  it('is built correctly', () => {\n    const transports = init()\n\n    assert.strictEqual(typeof init, 'function')\n    assert.strictEqual(typeof transports.superagent, 'function')\n    assert.strictEqual(typeof transports.fetch, 'function')\n    assert.strictEqual(typeof transports.axios, 'function')\n  })\n\n  it('throw errors when no connection is provided', () => {\n    const transports = init()\n\n    try {\n      // @ts-ignore\n      transports.fetch()\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'fetch has to be provided to feathers-rest')\n    }\n  })\n\n  it('app has the rest attribute', () => {\n    const app = feathers()\n\n    app.configure(init('http://localhost:8889').fetch(fetch))\n\n    assert.ok((app as any).rest)\n  })\n\n  it('throws an error when configured twice', () => {\n    const app = feathers()\n\n    app.configure(init('http://localhost:8889').fetch(fetch))\n\n    try {\n      app.configure(init('http://localhost:8889').fetch(fetch))\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'Only one default client provider can be configured')\n    }\n  })\n\n  it('errors when id property for get, patch, update or remove is undefined or empty string', async () => {\n    const app = feathers().configure(init('http://localhost:8889').fetch(fetch))\n\n    const service = app.service('todos')\n\n    await assert.rejects(() => service.get(undefined), {\n      message: 'id for .get is required'\n    })\n\n    await assert.rejects(() => service.get(''), {\n      message: 'id for .get is required'\n    })\n\n    await assert.rejects(() => service.remove(undefined), {\n      message: 'id for .remove is required'\n    })\n\n    await assert.rejects(() => service.remove(''), {\n      message: 'id for .remove is required'\n    })\n\n    await assert.rejects(() => service.update(undefined, {}), {\n      message: 'id for .update is required'\n    })\n\n    await assert.rejects(() => service.update('', {}), {\n      message: 'id for .update is required'\n    })\n\n    await assert.rejects(() => service.patch(undefined, {}), {\n      message: 'id for .patch is required'\n    })\n\n    await assert.rejects(() => service.patch('', {}), {\n      message: 'id for .patch is required'\n    })\n  })\n\n  it('uses a custom client', async () => {\n    const app = feathers()\n    class MyFetchClient extends FetchClient {\n      find() {\n        return Promise.resolve({\n          connection: this.connection,\n          base: this.base,\n          message: 'Custom fetch client'\n        })\n      }\n    }\n\n    app.configure(init('http://localhost:8889').fetch(fetch, {}, MyFetchClient))\n\n    const data = await app.service('messages').find()\n\n    assert.deepStrictEqual(data, {\n      connection: fetch,\n      base: 'http://localhost:8889/messages',\n      message: 'Custom fetch client'\n    })\n  })\n\n  it('uses a custom client as second arg', async () => {\n    const app = feathers()\n    class MyFetchClient extends FetchClient {\n      find() {\n        return Promise.resolve({\n          connection: this.connection,\n          base: this.base,\n          message: 'Custom fetch client'\n        })\n      }\n    }\n\n    app.configure(init('http://localhost:8889').fetch(fetch, MyFetchClient))\n\n    const data = await app.service('messages').find()\n\n    assert.deepStrictEqual(data, {\n      connection: fetch,\n      base: 'http://localhost:8889/messages',\n      message: 'Custom fetch client'\n    })\n  })\n\n  it('replace placeholder in route URLs', async () => {\n    const app = feathers()\n    let expectedValue: string | null = null\n    class MyFetchClient extends FetchClient {\n      request(options: any, _params: any) {\n        assert.equal(options.url, expectedValue)\n        return Promise.resolve()\n      }\n    }\n    app.configure(init('http://localhost:8889').fetch(fetch, {}, MyFetchClient))\n\n    expectedValue = 'http://localhost:8889/admin/todos'\n    await app.service(':slug/todos').find({\n      route: {\n        slug: 'admin'\n      }\n    })\n    await app.service(':slug/todos').create(\n      {},\n      {\n        route: {\n          slug: 'admin'\n        }\n      }\n    )\n    expectedValue = 'http://localhost:8889/admin/todos/0'\n    await app.service(':slug/todos').get(0, {\n      route: {\n        slug: 'admin'\n      }\n    })\n    expectedValue = 'http://localhost:8889/admin/todos/0'\n    await app.service(':slug/todos').patch(\n      0,\n      {},\n      {\n        route: {\n          slug: 'admin'\n        }\n      }\n    )\n    expectedValue = 'http://localhost:8889/admin/todos/0'\n    await app.service(':slug/todos').update(\n      0,\n      {},\n      {\n        route: {\n          slug: 'admin'\n        }\n      }\n    )\n    expectedValue = 'http://localhost:8889/admin/todos/0'\n    await app.service(':slug/todos').remove(0, {\n      route: {\n        slug: 'admin'\n      }\n    })\n  })\n})\n"
  },
  {
    "path": "packages/rest-client/test/server.ts",
    "content": "import { feathers, Id, NullableId, Params } from '@feathersjs/feathers'\nimport expressify, { rest, urlencoded, json } from '@feathersjs/express'\nimport { MemoryService } from '@feathersjs/memory'\nimport { FeathersError, NotAcceptable } from '@feathersjs/errors'\n\n// eslint-disable-next-line no-extend-native\nObject.defineProperty(Error.prototype, 'toJSON', {\n  value() {\n    const alt: any = {}\n\n    Object.getOwnPropertyNames(this).forEach((key: string) => {\n      alt[key] = this[key]\n    }, this)\n\n    return alt\n  },\n  configurable: true,\n  writable: true\n})\n\nconst errorHandler = function (error: FeathersError, _req: any, res: any, _next: any) {\n  // eslint-disable-line @typescript-eslint/no-unused-vars\n  const code = !isNaN(parseInt(error.code as any, 10)) ? parseInt(error.code as any, 10) : 500\n  res.status(code)\n\n  res.format({\n    'application/json'() {\n      res.json(Object.assign({}, error.toJSON()))\n    }\n  })\n}\n\ninterface TodoServiceParams extends Params {\n  authorization: any\n}\n\n// Create an in-memory CRUD service for our Todos\nclass TodoService extends MemoryService {\n  get(id: Id, params: TodoServiceParams) {\n    if (params.query.error) {\n      throw new Error('Something went wrong')\n    }\n\n    if (params.query.feathersError) {\n      throw new NotAcceptable('This is a Feathers error', { data: true })\n    }\n\n    return super.get(id).then((data) => {\n      console.log('!', params.query)\n      const result = Object.assign({ query: params.query }, data)\n\n      if (params.authorization) {\n        result.authorization = params.authorization\n      }\n\n      return result\n    })\n  }\n\n  remove(id: NullableId, params: Params) {\n    if (id === null) {\n      return Promise.resolve({\n        id,\n        text: 'deleted many'\n      })\n    }\n\n    if (params.query.noContent) {\n      return Promise.resolve()\n    }\n\n    return super.remove(id, params)\n  }\n\n  async customMethod(data: any, { provider }: Params) {\n    return {\n      data,\n      provider,\n      type: 'customMethod'\n    }\n  }\n}\n\nexport default (configurer?: any) => {\n  const app = expressify(feathers())\n    .use(function (req, res, next) {\n      res.header('Access-Control-Allow-Origin', '*')\n      res.header('Access-Control-Allow-Headers', 'Authorization')\n      req.feathers = {\n        ...req.feathers,\n        authorization: req.headers.authorization\n      }\n      next()\n    })\n    // Parse HTTP bodies\n    .use(json())\n    .use(urlencoded({ extended: true }))\n    .configure(\n      rest(function formatter(_req, res, next) {\n        if (!res.data) {\n          next()\n        }\n\n        res.format({\n          html() {\n            res.end('<h1>This is HTML content. You should not see it.</h1>')\n          },\n\n          json() {\n            res.json(res.data)\n          }\n        })\n      })\n    )\n    // Host our Todos service on the /todos path\n    .use('todos', new TodoService(), {\n      methods: ['find', 'get', 'create', 'patch', 'update', 'remove', 'customMethod']\n    })\n    .use(errorHandler)\n\n  if (typeof configurer === 'function') {\n    configurer.call(app)\n  }\n\n  app.service('todos').create({\n    text: 'some todo',\n    complete: false\n  })\n\n  return app\n}\n"
  },
  {
    "path": "packages/rest-client/test/superagent.test.ts",
    "content": "import { strict as assert } from 'assert'\n\nimport superagent from 'superagent'\nimport { Server } from 'http'\nimport { feathers } from '@feathersjs/feathers'\nimport { clientTests } from '@feathersjs/tests'\nimport { NotAcceptable } from '@feathersjs/errors'\n\nimport rest from '../src'\nimport createServer from './server'\nimport { ServiceTypes } from './declarations'\n\ndescribe('Superagent REST connector', function () {\n  let server: Server\n\n  const url = 'http://localhost:8889'\n  const setup = rest(url).superagent(superagent)\n  const app = feathers<ServiceTypes>().configure(setup)\n  const service = app.service('todos')\n\n  service.methods('customMethod')\n\n  before(async () => {\n    server = await createServer().listen(8889)\n  })\n\n  after((done) => server.close(done))\n\n  it('supports custom headers', async () => {\n    const headers = {\n      Authorization: 'let-me-in'\n    }\n\n    const todo = await service.get(0, { headers })\n\n    assert.deepStrictEqual(todo, {\n      id: 0,\n      authorization: 'let-me-in',\n      text: 'some todo',\n      complete: false,\n      query: {}\n    })\n  })\n\n  it('supports params.connection', async () => {\n    const connection = {\n      Authorization: 'let-me-in'\n    }\n\n    const todo = await service.get(0, { connection })\n\n    assert.deepStrictEqual(todo, {\n      id: 0,\n      authorization: 'let-me-in',\n      text: 'some todo',\n      complete: false,\n      query: {}\n    })\n  })\n\n  it('can initialize a client instance', async () => {\n    const init = rest(url).superagent(superagent)\n    const todoService = init.service('todos')\n\n    assert.ok(todoService instanceof init.Service, 'Returned service is a client')\n\n    const todos = await todoService.find({})\n\n    assert.deepStrictEqual(todos, [\n      {\n        text: 'some todo',\n        complete: false,\n        id: 0\n      }\n    ])\n  })\n\n  it('supports nested arrays in queries', async () => {\n    const query = { test: { $in: ['0', '1', '2'] } }\n\n    const data = await service.get(0, { query })\n\n    assert.deepStrictEqual(data.query, query)\n  })\n\n  it('remove many', async () => {\n    const todo: any = await service.remove(null)\n\n    assert.strictEqual(todo.id, null)\n    assert.strictEqual(todo.text, 'deleted many')\n  })\n\n  it('converts feathers errors (#50)', async () => {\n    try {\n      await service.get(0, { query: { feathersError: true } })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.ok(error.response)\n      assert.ok(error instanceof NotAcceptable)\n      assert.strictEqual(error.message, 'This is a Feathers error')\n      assert.strictEqual(error.code, 406)\n    }\n  })\n\n  it('works with custom method .customMethod', async () => {\n    const result = await service.customMethod({ message: 'hi' })\n\n    assert.deepEqual(result, {\n      data: { message: 'hi' },\n      provider: 'rest',\n      type: 'customMethod'\n    })\n  })\n\n  clientTests(service, 'todos')\n})\n"
  },
  {
    "path": "packages/rest-client/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/schema/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n### Bug Fixes\n\n- **schema:** Allow regular functions in resolvers ([#3487](https://github.com/feathersjs/feathers/issues/3487)) ([187868e](https://github.com/feathersjs/feathers/commit/187868edd9c0c9d885c482b85be7a90655c86ca2))\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n### Bug Fixes\n\n- **schema:** Fix setting dispatch on existing nested objects ([#3380](https://github.com/feathersjs/feathers/issues/3380)) ([04efd5a](https://github.com/feathersjs/feathers/commit/04efd5ab3339beafa0e1a9ef851483a387c6ec96))\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n### Bug Fixes\n\n- **schema:** Allow $in and $nin queries to work for arrays ([#3352](https://github.com/feathersjs/feathers/issues/3352)) ([677c214](https://github.com/feathersjs/feathers/commit/677c214a353a7f9a1f90649b9bbec4d0d6517a6f))\n- **schema:** Remove undefined $select when using resolveResult hook ([#3354](https://github.com/feathersjs/feathers/issues/3354)) ([c43e009](https://github.com/feathersjs/feathers/commit/c43e009188eb84f98e3f5f29ac4444e6967afc1f))\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n### Bug Fixes\n\n- **schema:** Add typescript as peerDependency ([#3287](https://github.com/feathersjs/feathers/issues/3287)) ([cb562ee](https://github.com/feathersjs/feathers/commit/cb562eeddfa88e34fe5727d4000fa037746b0249))\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n### Bug Fixes\n\n- **schema:** Exclude json-schema-to-ts@2.8.0 ([#3180](https://github.com/feathersjs/feathers/issues/3180)) ([aee8531](https://github.com/feathersjs/feathers/commit/aee8531b5f0578f11e43b19a469b96e6f4b170ce))\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n### Bug Fixes\n\n- **core:** Use Symbol.for to instantiate shared symbols ([#3087](https://github.com/feathersjs/feathers/issues/3087)) ([7f3fc21](https://github.com/feathersjs/feathers/commit/7f3fc2167576f228f8183568eb52b077160e8d65))\n- **memory/mongodb:** $select as only property & force 'id' in '$select' ([#3081](https://github.com/feathersjs/feathers/issues/3081)) ([fbe3cf5](https://github.com/feathersjs/feathers/commit/fbe3cf5199e102b5aeda2ae33828d5034df3d105))\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n### Bug Fixes\n\n- **schema:** validateQuery - move next function outside of try-catch ([#3053](https://github.com/feathersjs/feathers/issues/3053)) ([37fe5c4](https://github.com/feathersjs/feathers/commit/37fe5c4a4d813867f6d02098b7c77d08786248c7))\n\n### Features\n\n- **schema:** Add schema helper for handling Object ids ([#3058](https://github.com/feathersjs/feathers/issues/3058)) ([1393bed](https://github.com/feathersjs/feathers/commit/1393bed81a9ee814de6aab0e537af83e667591a2))\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n### Bug Fixes\n\n- **schema:** Do not change the hook context in resolvers ([#3048](https://github.com/feathersjs/feathers/issues/3048)) ([bfd8c04](https://github.com/feathersjs/feathers/commit/bfd8c04c15279063a0d4b70771715c656dda5f7c))\n- **schema:** Ensure that resolveResult and resolveExternal are run as around hooks ([#3032](https://github.com/feathersjs/feathers/issues/3032)) ([71942f4](https://github.com/feathersjs/feathers/commit/71942f418e3afe167aef4f98b1a97356dae7625c))\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- **configuration:** Add pool and connection object to SQL database default configuration ([#3023](https://github.com/feathersjs/feathers/issues/3023)) ([092c749](https://github.com/feathersjs/feathers/commit/092c749d43f7da4d019576d1210fe7d3719a44a2))\n- **databases:** Ensure that query sanitization is not necessary when using query schemas ([#3022](https://github.com/feathersjs/feathers/issues/3022)) ([dbf514e](https://github.com/feathersjs/feathers/commit/dbf514e85d1508b95c007462a39b3cadd4ff391d))\n- **schema:** Allow any type in resolver hooks ([#3006](https://github.com/feathersjs/feathers/issues/3006)) ([f01281f](https://github.com/feathersjs/feathers/commit/f01281f7d83262738459585fc3f53f56c0a0deb8))\n- **schema:** Ensure all types of nested data are securely dispatched ([#3005](https://github.com/feathersjs/feathers/issues/3005)) ([e4a9da5](https://github.com/feathersjs/feathers/commit/e4a9da5f3288e8e9f02087754473c7a9dfda6cb1))\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n- **schema:** Allow to add additional operators to the query syntax ([#2941](https://github.com/feathersjs/feathers/issues/2941)) ([f324940](https://github.com/feathersjs/feathers/commit/f324940d5795b41e8c6fc113defb0beb7ab03a0a))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **core:** `context.type` for around hooks ([#2890](https://github.com/feathersjs/feathers/issues/2890)) ([d606ac6](https://github.com/feathersjs/feathers/commit/d606ac660fd5335c95206784fea36530dd2e851a))\n- **core:** Improve service option usage and method option typings ([#2902](https://github.com/feathersjs/feathers/issues/2902)) ([164d75c](https://github.com/feathersjs/feathers/commit/164d75c0f11139a316baa91f1762de8f8eb7da2d))\n- **schema:** Allow query schemas with no properties, error on unsupported types ([#2904](https://github.com/feathersjs/feathers/issues/2904)) ([b66c734](https://github.com/feathersjs/feathers/commit/b66c734357478f51b2d38fa7f3eee08640cea26e))\n\n### Features\n\n- **adapter:** Add patch data type to adapters and refactor AdapterBase usage ([#2906](https://github.com/feathersjs/feathers/issues/2906)) ([9ddc2e6](https://github.com/feathersjs/feathers/commit/9ddc2e6b028f026f939d6af68125847e5c6734b4))\n- **cli:** Use separate patch schema and types ([#2916](https://github.com/feathersjs/feathers/issues/2916)) ([7088af6](https://github.com/feathersjs/feathers/commit/7088af64a539dc7f1a016d832b77b98aaaf92603))\n- **schema:** Split resolver options and property resolvers ([#2889](https://github.com/feathersjs/feathers/issues/2889)) ([4822c94](https://github.com/feathersjs/feathers/commit/4822c949812e5a1dceff3c62b2f9de4781b4d601))\n- **schema:** Virtual property resolvers ([#2900](https://github.com/feathersjs/feathers/issues/2900)) ([7d03b57](https://github.com/feathersjs/feathers/commit/7d03b57ae2f633bdd4a368e0d5955011fbd6c329))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n### Bug Fixes\n\n- **schema:** Improve resolver performance ([#2822](https://github.com/feathersjs/feathers/issues/2822)) ([5fa900f](https://github.com/feathersjs/feathers/commit/5fa900f90d55859332c90283dddddab26ae3759c))\n- **schema:** Use the same options for resolveData hook ([#2833](https://github.com/feathersjs/feathers/issues/2833)) ([ed3b050](https://github.com/feathersjs/feathers/commit/ed3b05051db6886729d4824825ca8f00c2459af7))\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n### Features\n\n- **cli:** Generate full client test suite and improve typed client ([#2788](https://github.com/feathersjs/feathers/issues/2788)) ([57119b6](https://github.com/feathersjs/feathers/commit/57119b6bb2797f7297cf054268a248c093ecd538))\n- **cli:** Improve generated schema definitions ([#2783](https://github.com/feathersjs/feathers/issues/2783)) ([474a9fd](https://github.com/feathersjs/feathers/commit/474a9fda2107e9bcf357746320a8e00cda8182b6))\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n- **schema:** Make schemas validation library independent and add TypeBox support ([#2772](https://github.com/feathersjs/feathers/issues/2772)) ([44172d9](https://github.com/feathersjs/feathers/commit/44172d99b566d11d9ceda04f1d0bf72b6d05ce76))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n### Bug Fixes\n\n- **schema:** Fix for Ajv global collision bug [#2681](https://github.com/feathersjs/feathers/issues/2681) ([#2702](https://github.com/feathersjs/feathers/issues/2702)) ([0b2def6](https://github.com/feathersjs/feathers/commit/0b2def6ca483fad6ca22fcc4ea9873bc027925d8))\n\n### Features\n\n- **authentication-oauth:** Koa and transport independent oAuth authentication ([#2737](https://github.com/feathersjs/feathers/issues/2737)) ([9231525](https://github.com/feathersjs/feathers/commit/9231525a24bb790ba9c5d940f2867a9c727691c9))\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n### Bug Fixes\n\n- Freeze the resolver context ([#2685](https://github.com/feathersjs/feathers/issues/2685)) ([247dccb](https://github.com/feathersjs/feathers/commit/247dccb2eb72551962030321cb1c0ecb11b0181e))\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Bug Fixes\n\n- **schema:** Fix dispatch resovler hook to convert actually resolved data ([#2663](https://github.com/feathersjs/feathers/issues/2663)) ([f7e87db](https://github.com/feathersjs/feathers/commit/f7e87dbb9a0bc8d89aee47318dddbaa4d6ba5b91))\n\n### Features\n\n- **cli:** Add typed client to a generated app ([#2669](https://github.com/feathersjs/feathers/issues/2669)) ([5b801b5](https://github.com/feathersjs/feathers/commit/5b801b5017ddc3eaa95622b539f51d605916bc86))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n### Bug Fixes\n\n- **schema:** Always resolve dispatch in resolveAll and add getDispatch method ([#2645](https://github.com/feathersjs/feathers/issues/2645)) ([145b366](https://github.com/feathersjs/feathers/commit/145b366435695438fbc8db9fdb161162ca9049ad))\n- **schema:** remove `default` from queryProperty schemas ([#2646](https://github.com/feathersjs/feathers/issues/2646)) ([940a2b6](https://github.com/feathersjs/feathers/commit/940a2b6868d2f77f81edb1661f6417ec2ea6e372))\n\n### Features\n\n- **core:** Rename async hooks to around hooks, allow usual registration format ([#2652](https://github.com/feathersjs/feathers/issues/2652)) ([2a485a0](https://github.com/feathersjs/feathers/commit/2a485a07929184261f27437fc0fdfe5a44694834))\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n### Bug Fixes\n\n- **schema:** Allows resolveData with different resolvers based on method ([#2644](https://github.com/feathersjs/feathers/issues/2644)) ([be71fa2](https://github.com/feathersjs/feathers/commit/be71fa2fe260e05b7dcc0d5f439e33f2e9ec2434))\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n### Bug Fixes\n\n- **schema:** Add Combine helper to allow merging schema types that use ([#2637](https://github.com/feathersjs/feathers/issues/2637)) ([06d03e9](https://github.com/feathersjs/feathers/commit/06d03e91abb1347576c2351c12322d01c58473e5))\n- **typescript:** Make additional types generic to work with extended types ([#2625](https://github.com/feathersjs/feathers/issues/2625)) ([269fdec](https://github.com/feathersjs/feathers/commit/269fdecc5961092dc8608b3cbe16f433c80bfa96))\n\n### Features\n\n- **schema:** Add resolveAll hook ([#2643](https://github.com/feathersjs/feathers/issues/2643)) ([85527d7](https://github.com/feathersjs/feathers/commit/85527d71cb78852880696e5d96abdcdf24593934))\n- **schema:** Add resolver for safe external data dispatching ([#2641](https://github.com/feathersjs/feathers/issues/2641)) ([72b980e](https://github.com/feathersjs/feathers/commit/72b980e05631136d30c8f1468dee45ec6a8d2503))\n- **schema:** Add schema resolver converter functionality ([#2640](https://github.com/feathersjs/feathers/issues/2640)) ([26d9e05](https://github.com/feathersjs/feathers/commit/26d9e05327d6e0144466cd57d6fcc11ac7ecb06a))\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n### Features\n\n- **schema:** Add querySyntax helper to create full query schemas ([#2621](https://github.com/feathersjs/feathers/issues/2621)) ([2bbb103](https://github.com/feathersjs/feathers/commit/2bbb103b2f3e30fb0fff935f92ad3276a1a67e41))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Features\n\n- **schema:** Allow hooks to run resolvers in sequence ([#2609](https://github.com/feathersjs/feathers/issues/2609)) ([d85c507](https://github.com/feathersjs/feathers/commit/d85c507c76d07e48fc8e7e28ff7de0ef435e0ef8))\n- **typescript:** Improve adapter typings ([#2605](https://github.com/feathersjs/feathers/issues/2605)) ([3b2ca0a](https://github.com/feathersjs/feathers/commit/3b2ca0a6a8e03e8390272c4d7e930b4bffdaacf5))\n- **typescript:** Improve params and query typeability ([#2600](https://github.com/feathersjs/feathers/issues/2600)) ([df28b76](https://github.com/feathersjs/feathers/commit/df28b7619161f1df5e700326f52cca1a92dc5d28))\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n### Bug Fixes\n\n- **schema:** result resolver correctly resolves paginated find result ([#2594](https://github.com/feathersjs/feathers/issues/2594)) ([6511e45](https://github.com/feathersjs/feathers/commit/6511e45bd0624f1a629530719709f4b27fecbe0b))\n\n### Features\n\n- **configuration:** Allow app configuration to be validated against a schema ([#2590](https://github.com/feathersjs/feathers/issues/2590)) ([a268f86](https://github.com/feathersjs/feathers/commit/a268f86da92a8ada14ed11ab456aac0a4bba5bb0))\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n### Bug Fixes\n\n- **hooks:** Allow all built-in hooks to be used the async and regular way ([#2559](https://github.com/feathersjs/feathers/issues/2559)) ([8f9f631](https://github.com/feathersjs/feathers/commit/8f9f631e0ce89de349207db72def84e7ab496a4a))\n- **queryProperty:** allow compound oneOf ([#2545](https://github.com/feathersjs/feathers/issues/2545)) ([3077d2d](https://github.com/feathersjs/feathers/commit/3077d2d896a38d579ce4d5b530e21ad332bcf221))\n- **schema:** Properly handle resolver errors ([#2540](https://github.com/feathersjs/feathers/issues/2540)) ([31fbdff](https://github.com/feathersjs/feathers/commit/31fbdff8bd848ac7e0eda56e307ac34b1bfcf17f))\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n### Bug Fixes\n\n- **schema:** Do not error for schemas without properties ([#2519](https://github.com/feathersjs/feathers/issues/2519)) ([96fdb47](https://github.com/feathersjs/feathers/commit/96fdb47d45fd88a8039aa9cc9ec8aebd98672b95))\n- **schema:** Fix resolver data type and use new validation feature in test fixture ([#2523](https://github.com/feathersjs/feathers/issues/2523)) ([1093f12](https://github.com/feathersjs/feathers/commit/1093f124b60524cbd9050fcf07ddaf1d558973da))\n\n### Features\n\n- **schema:** Allow to use custom AJV and test with ajv-formats ([#2513](https://github.com/feathersjs/feathers/issues/2513)) ([ecfa4df](https://github.com/feathersjs/feathers/commit/ecfa4df29f029f6ca8517cacf518c14b46ffeb4e))\n- **schema:** Improve schema typing, validation and extensibility ([#2521](https://github.com/feathersjs/feathers/issues/2521)) ([8c1b350](https://github.com/feathersjs/feathers/commit/8c1b35052792e82d13be03c06583534284fbae82))\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/schema\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n### Features\n\n- **schema:** Allow resolvers to validate a schema ([#2465](https://github.com/feathersjs/feathers/issues/2465)) ([7d9590b](https://github.com/feathersjs/feathers/commit/7d9590bbe12b94b8b5a7987684f5d4968e426481))\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n### Features\n\n- **schema:** Initial version of schema definitions and resolvers ([#2441](https://github.com/feathersjs/feathers/issues/2441)) ([c57a5cd](https://github.com/feathersjs/feathers/commit/c57a5cd56699a121647be4506d8f967e6d72ecae))\n"
  },
  {
    "path": "packages/schema/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/schema/README.md",
    "content": "# @feathersjs/schema\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/schema.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/schema)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> A common data schema definition format\n\n## Installation\n\n```\nnpm install @feathersjs/schema --save\n```\n\n## Documentation\n\nRefer to the [Feathers schema API documentation](https://feathersjs.com/api/schema/) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/schema/package.json",
    "content": "{\n  \"name\": \"@feathersjs/schema\",\n  \"description\": \"A common data schema definition format\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/schema\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"mocha\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\",\n    \"test\": \"npm run compile && npm run mocha\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/adapter-commons\": \"^5.0.42\",\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@feathersjs/hooks\": \"^0.9.0\",\n    \"@types/json-schema\": \"^7.0.15\",\n    \"ajv\": \"^8.18.0\",\n    \"ajv-formats\": \"^3.0.1\",\n    \"json-schema-to-ts\": \"^3.1.1\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/memory\": \"^5.0.42\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"ajv-formats\": \"^3.0.1\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"typescript\": \"^5.9.2\"\n  },\n  \"peerDependencies\": {\n    \"typescript\": \">=5.9\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/schema/src/default-schemas.ts",
    "content": "import { FromSchema } from 'json-schema-to-ts'\n\nexport const authenticationSettingsSchema = {\n  type: 'object',\n  required: ['secret', 'entity', 'authStrategies'],\n  properties: {\n    secret: {\n      type: 'string',\n      description: 'The JWT signing secret'\n    },\n    entity: {\n      oneOf: [\n        {\n          type: 'null'\n        },\n        {\n          type: 'string'\n        }\n      ],\n      description: 'The name of the authentication entity (e.g. user)'\n    },\n    entityId: {\n      type: 'string',\n      description: 'The name of the authentication entity id property'\n    },\n    service: {\n      type: 'string',\n      description: 'The path of the entity service'\n    },\n    authStrategies: {\n      type: 'array',\n      items: { type: 'string' },\n      description: 'A list of authentication strategy names that are allowed to create JWT access tokens'\n    },\n    parseStrategies: {\n      type: 'array',\n      items: { type: 'string' },\n      description:\n        'A list of authentication strategy names that should parse HTTP headers for authentication information (defaults to `authStrategies`)'\n    },\n    jwtOptions: {\n      type: 'object'\n    },\n    jwt: {\n      type: 'object',\n      properties: {\n        header: {\n          type: 'string',\n          default: 'Authorization',\n          description: 'The HTTP header containing the JWT'\n        },\n        schemes: {\n          type: 'array',\n          items: { type: 'string' },\n          description: 'An array of schemes to support'\n        }\n      }\n    },\n    local: {\n      type: 'object',\n      required: ['usernameField', 'passwordField'],\n      properties: {\n        usernameField: {\n          type: 'string',\n          description: 'Name of the username field (e.g. `email`)'\n        },\n        passwordField: {\n          type: 'string',\n          description: 'Name of the password field (e.g. `password`)'\n        },\n        hashSize: {\n          type: 'number',\n          description: 'The BCrypt salt length'\n        },\n        errorMessage: {\n          type: 'string',\n          default: 'Invalid login',\n          description: 'The error message to return on errors'\n        },\n        entityUsernameField: {\n          type: 'string',\n          description:\n            'Name of the username field on the entity if authentication request data and entity field names are different'\n        },\n        entityPasswordField: {\n          type: 'string',\n          description:\n            'Name of the password field on the entity if authentication request data and entity field names are different'\n        }\n      }\n    },\n    oauth: {\n      type: 'object',\n      properties: {\n        redirect: {\n          type: 'string'\n        },\n        origins: {\n          type: 'array',\n          items: { type: 'string' }\n        },\n        defaults: {\n          type: 'object',\n          properties: {\n            key: { type: 'string' },\n            secret: { type: 'string' }\n          }\n        }\n      }\n    }\n  }\n} as const\n\nexport type AuthenticationConfiguration = FromSchema<typeof authenticationSettingsSchema>\n\nexport const sqlSettingsSchema = {\n  type: 'object',\n  properties: {\n    client: { type: 'string' },\n    pool: {\n      type: 'object',\n      properties: {\n        min: { type: 'number' },\n        max: { type: 'number' }\n      }\n    },\n    connection: {\n      oneOf: [\n        { type: 'string' },\n        {\n          type: 'object',\n          properties: {\n            host: { type: 'string' },\n            port: { type: 'number' },\n            user: { type: 'string' },\n            password: { type: 'string' },\n            database: { type: 'string' }\n          }\n        }\n      ]\n    }\n  }\n} as const\n\n/**\n * Schema for properties that are available in a standard Feathers application.\n */\nexport const defaultAppSettings = {\n  authentication: authenticationSettingsSchema,\n  origins: {\n    type: 'array',\n    items: {\n      type: 'string'\n    }\n  },\n  paginate: {\n    type: 'object',\n    additionalProperties: false,\n    required: ['default', 'max'],\n    properties: {\n      default: { type: 'number' },\n      max: { type: 'number' }\n    }\n  },\n  mongodb: { type: 'string' },\n  mysql: sqlSettingsSchema,\n  postgresql: sqlSettingsSchema,\n  sqlite: sqlSettingsSchema,\n  mssql: sqlSettingsSchema\n} as const\n\nexport const defaultAppConfiguration = {\n  type: 'object',\n  additionalProperties: false,\n  properties: defaultAppSettings\n} as const\n\nexport type DefaultAppConfiguration = FromSchema<typeof defaultAppConfiguration>\n"
  },
  {
    "path": "packages/schema/src/hooks/index.ts",
    "content": "export * from './resolve'\nexport * from './validate'\n"
  },
  {
    "path": "packages/schema/src/hooks/resolve.ts",
    "content": "import { HookContext, NextFunction } from '@feathersjs/feathers'\nimport { compose } from '@feathersjs/hooks'\nimport { Resolver, ResolverStatus } from '../resolver'\n\nconst getResult = <H extends HookContext>(context: H) => {\n  const isPaginated = context.method === 'find' && context.result.data\n  const data = isPaginated ? context.result.data : context.result\n\n  return { isPaginated, data }\n}\n\nconst runResolvers = async <T, H extends HookContext>(\n  resolvers: Resolver<T, H>[],\n  data: any,\n  ctx: H,\n  status?: Partial<ResolverStatus<T, H>>\n) => {\n  let current: any = data\n\n  for (const resolver of resolvers) {\n    if (resolver && typeof resolver.resolve === 'function') {\n      current = await resolver.resolve(current, ctx, status)\n    }\n  }\n\n  return current as T\n}\n\nexport type ResolverSetting<H extends HookContext> = Resolver<any, H> | Resolver<any, H>[]\n\nexport const resolveQuery =\n  <H extends HookContext>(...resolvers: Resolver<any, H>[]) =>\n  async (context: H, next?: NextFunction) => {\n    const data = context?.params?.query || {}\n    const query = await runResolvers(resolvers, data, context)\n\n    context.params = {\n      ...context.params,\n      query\n    }\n\n    if (typeof next === 'function') {\n      return next()\n    }\n  }\n\nexport const resolveData =\n  <H extends HookContext>(...resolvers: Resolver<any, H>[]) =>\n  async (context: H, next?: NextFunction) => {\n    if (context.data !== undefined) {\n      const data = context.data\n\n      const status = {\n        originalContext: context\n      }\n\n      if (Array.isArray(data)) {\n        context.data = await Promise.all(\n          data.map((current) => runResolvers(resolvers, current, context, status))\n        )\n      } else {\n        context.data = await runResolvers(resolvers, data, context, status)\n      }\n    }\n\n    if (typeof next === 'function') {\n      return next()\n    }\n  }\n\nexport const resolveResult = <H extends HookContext>(...resolvers: Resolver<any, H>[]) => {\n  const virtualProperties = new Set(resolvers.reduce((acc, current) => acc.concat(current.virtualNames), []))\n\n  return async (context: H, next: NextFunction) => {\n    if (typeof next !== 'function') {\n      throw new Error('The resolveResult hook must be used as an around hook')\n    }\n\n    const { $resolve, $select, ...query } = context.params?.query || {}\n    const hasVirtualSelects = Array.isArray($select) && $select.some((name) => virtualProperties.has(name))\n\n    const resolve = {\n      originalContext: context,\n      ...context.params.resolve,\n      properties: $resolve || $select\n    }\n\n    context.params = {\n      ...context.params,\n      resolve,\n      query: {\n        ...query,\n        ...(!!$select && !hasVirtualSelects ? { $select } : {})\n      }\n    }\n\n    await next()\n\n    const status = context.params.resolve\n    const { isPaginated, data } = getResult(context)\n\n    const result = Array.isArray(data)\n      ? await Promise.all(data.map(async (current) => runResolvers(resolvers, current, context, status)))\n      : await runResolvers(resolvers, data, context, status)\n\n    if (isPaginated) {\n      context.result.data = result\n    } else {\n      context.result = result\n    }\n  }\n}\n\nexport const DISPATCH = Symbol.for('@feathersjs/schema/dispatch')\n\nexport const getDispatchValue = (value: any): any => {\n  if (typeof value === 'object' && value !== null) {\n    if (value[DISPATCH] !== undefined) {\n      return value[DISPATCH]\n    }\n\n    if (Array.isArray(value)) {\n      return value.map((item) => getDispatchValue(item))\n    }\n  }\n\n  return value\n}\n\nexport const getDispatch = (value: any): any =>\n  typeof value === 'object' && value !== null && value[DISPATCH] ? value[DISPATCH] : null\n\nexport const setDispatch = (current: any, dispatch: any) => {\n  Object.defineProperty(current, DISPATCH, {\n    value: dispatch,\n    enumerable: false,\n    configurable: false\n  })\n\n  return dispatch\n}\n\nexport const resolveExternal =\n  <H extends HookContext>(...resolvers: Resolver<any, H>[]) =>\n  async (context: H, next: NextFunction) => {\n    if (typeof next !== 'function') {\n      throw new Error('The resolveExternal hook must be used as an around hook')\n    }\n\n    await next()\n\n    const existingDispatch = getDispatch(context.result)\n\n    if (existingDispatch !== null) {\n      context.dispatch = existingDispatch\n    } else {\n      const status = context.params.resolve\n      const { isPaginated, data } = getResult(context)\n      const resolveAndGetDispatch = async (current: any) => {\n        const currentExistingDispatch = getDispatch(current)\n\n        if (currentExistingDispatch !== null) {\n          return currentExistingDispatch\n        }\n\n        const resolved = await runResolvers(resolvers, current, context, status)\n        const currentDispatch = Object.keys(resolved).reduce(\n          (res, key) => {\n            res[key] = getDispatchValue(resolved[key])\n\n            return res\n          },\n          {} as Record<string, any>\n        )\n\n        return setDispatch(current, currentDispatch)\n      }\n\n      const result = await (Array.isArray(data)\n        ? Promise.all(data.map(resolveAndGetDispatch))\n        : resolveAndGetDispatch(data))\n      const dispatch = isPaginated\n        ? {\n            ...context.result,\n            data: result\n          }\n        : result\n\n      context.dispatch = setDispatch(context.result, dispatch)\n    }\n  }\n\nexport const resolveDispatch = resolveExternal\n\ntype ResolveAllSettings<H extends HookContext> = {\n  data?: {\n    create: Resolver<any, H>\n    patch: Resolver<any, H>\n    update: Resolver<any, H>\n  }\n  query?: Resolver<any, H>\n  result?: Resolver<any, H>\n  dispatch?: Resolver<any, H>\n}\n\nconst dataMethods = ['create', 'update', 'patch'] as const\n\n/**\n * Resolve all resolvers at once.\n *\n * @param map The individual resolvers\n * @returns A combined resolver middleware\n * @deprecated Use individual data, query and external resolvers and hooks instead.\n * @see https://dove.feathersjs.com/guides/cli/service.schemas.html\n */\nexport const resolveAll = <H extends HookContext>(map: ResolveAllSettings<H>) => {\n  const middleware = []\n\n  middleware.push(resolveDispatch(map.dispatch))\n\n  if (map.result) {\n    middleware.push(resolveResult(map.result))\n  }\n\n  if (map.query) {\n    middleware.push(resolveQuery(map.query))\n  }\n\n  if (map.data) {\n    dataMethods.forEach((name) => {\n      if (map.data[name]) {\n        const resolver = resolveData(map.data[name])\n\n        middleware.push(async (context: H, next: NextFunction) =>\n          context.method === name ? resolver(context, next) : next()\n        )\n      }\n    })\n  }\n\n  return compose(middleware)\n}\n"
  },
  {
    "path": "packages/schema/src/hooks/validate.ts",
    "content": "import { HookContext, NextFunction } from '@feathersjs/feathers'\nimport { BadRequest } from '@feathersjs/errors'\nimport { VALIDATED } from '@feathersjs/adapter-commons'\nimport { Schema, Validator } from '../schema'\nimport { DataValidatorMap } from '../json-schema'\n\nexport const validateQuery = <H extends HookContext>(schema: Schema<any> | Validator) => {\n  const validator: Validator = typeof schema === 'function' ? schema : schema.validate.bind(schema)\n\n  return async (context: H, next?: NextFunction) => {\n    const data = context?.params?.query || {}\n\n    try {\n      const query = await validator(data)\n\n      Object.defineProperty(query, VALIDATED, { value: true })\n\n      context.params = {\n        ...context.params,\n        query\n      }\n    } catch (error: any) {\n      throw error.ajv ? new BadRequest(error.message, error.errors) : error\n    }\n\n    if (typeof next === 'function') {\n      return next()\n    }\n  }\n}\n\nexport const validateData = <H extends HookContext>(schema: Schema<any> | DataValidatorMap | Validator) => {\n  return async (context: H, next?: NextFunction) => {\n    const data = context.data\n    const validator =\n      typeof (schema as Schema<any>).validate === 'function'\n        ? (schema as Schema<any>).validate.bind(schema)\n        : typeof schema === 'function'\n          ? schema\n          : (schema as any)[context.method]\n\n    if (validator) {\n      try {\n        if (Array.isArray(data)) {\n          context.data = await Promise.all(data.map((current) => validator(current)))\n        } else {\n          context.data = await validator(data)\n        }\n\n        Object.defineProperty(context.data, VALIDATED, { value: true })\n      } catch (error: any) {\n        throw error.ajv ? new BadRequest(error.message, error.errors) : error\n      }\n    }\n\n    if (typeof next === 'function') {\n      return next()\n    }\n  }\n}\n"
  },
  {
    "path": "packages/schema/src/index.ts",
    "content": "import addFormats, { FormatName, FormatOptions, FormatsPluginOptions } from 'ajv-formats'\nimport { ResolverStatus } from './resolver'\n\nexport type { FromSchema } from 'json-schema-to-ts'\nexport { addFormats, FormatName, FormatOptions, FormatsPluginOptions }\n\nexport * from './schema'\nexport * from './resolver'\nexport * from './hooks'\nexport * from './json-schema'\nexport * from './default-schemas'\n\nexport * as hooks from './hooks'\nexport * as jsonSchema from './json-schema'\n\nexport type Infer<S extends { _type: any }> = S['_type']\n\nexport type Combine<S extends { _type: any }, U> = Pick<Infer<S>, Exclude<keyof Infer<S>, keyof U>> & U\n\ndeclare module '@feathersjs/feathers/lib/declarations' {\n  interface Params {\n    resolve?: ResolverStatus<any, HookContext>\n  }\n}\n"
  },
  {
    "path": "packages/schema/src/json-schema.ts",
    "content": "import { _ } from '@feathersjs/commons'\nimport { JSONSchema } from 'json-schema-to-ts'\nimport { JSONSchemaDefinition, Ajv, Validator } from './schema'\n\nexport type DataSchemaMap = {\n  create: JSONSchemaDefinition\n  update?: JSONSchemaDefinition\n  patch?: JSONSchemaDefinition\n}\n\nexport type DataValidatorMap = {\n  create: Validator\n  update: Validator\n  patch: Validator\n}\n\n/**\n * Returns a compiled validation function for a schema and AJV validator instance.\n *\n * @param schema The JSON schema definition\n * @param validator The AJV validation instance\n * @returns A compiled validation function\n */\nexport const getValidator = <T = any, R = T>(schema: JSONSchemaDefinition, validator: Ajv): Validator<T, R> =>\n  validator.compile({\n    $async: true,\n    ...(schema as any)\n  }) as any as Validator<T, R>\n\n/**\n * Returns compiled validation functions to validate data for the `create`, `update` and `patch`\n * service methods. If not passed explicitly, the `update` validator will be the same as the `create`\n * and `patch` will be the `create` validator with no required fields.\n *\n * @param def Either general JSON schema definition or a mapping of `create`, `update` and `patch`\n * to their respecitve JSON schema\n * @param validator The Ajv instance to use as the validator\n * @returns A map of validator functions\n */\nexport const getDataValidator = (\n  def: JSONSchemaDefinition | DataSchemaMap,\n  validator: Ajv\n): DataValidatorMap => {\n  const schema = ((def as any).create ? def : { create: def }) as DataSchemaMap\n\n  return {\n    create: getValidator(schema.create, validator),\n    update: getValidator(\n      schema.update || {\n        ...(schema.create as any),\n        $id: `${schema.create.$id}Update`\n      },\n      validator\n    ),\n    patch: getValidator(\n      schema.patch || {\n        ...(schema.create as any),\n        $id: `${schema.create.$id}Patch`,\n        required: []\n      },\n      validator\n    )\n  }\n}\n\nexport type PropertyQuery<D extends JSONSchema, X> = {\n  anyOf: [\n    D,\n    {\n      type: 'object'\n      additionalProperties: false\n      properties: {\n        $gt: D\n        $gte: D\n        $lt: D\n        $lte: D\n        $ne: D\n        $in: {\n          type: 'array'\n          items: D\n        }\n        $nin: {\n          type: 'array'\n          items: D\n        }\n      } & X\n    }\n  ]\n}\n\n/**\n * Create a Feathers query syntax compatible JSON schema definition for a property definition.\n *\n * @param def The property definition (e.g. `{ type: 'string' }`)\n * @param extensions Additional properties to add to the query property schema\n * @returns A JSON schema definition for the Feathers query syntax for this property.\n */\nexport const queryProperty = <T extends JSONSchema, X extends { [key: string]: JSONSchema }>(\n  def: T,\n  extensions: X = {} as X\n) => {\n  const definition = _.omit(def, 'default')\n  return {\n    anyOf: [\n      definition,\n      {\n        type: 'object',\n        additionalProperties: false,\n        properties: {\n          $gt: definition,\n          $gte: definition,\n          $lt: definition,\n          $lte: definition,\n          $ne: definition,\n          $in:\n            definition.type === 'array'\n              ? definition\n              : {\n                  type: 'array',\n                  items: definition\n                },\n          $nin:\n            definition.type === 'array'\n              ? definition\n              : {\n                  type: 'array',\n                  items: definition\n                },\n          ...extensions\n        }\n      }\n    ]\n  } as const\n}\n\n/**\n * Creates Feathers a query syntax compatible JSON schema for multiple properties.\n *\n * @param definitions A map of property definitions\n * @param extensions Additional properties to add to the query property schema\n * @returns The JSON schema definition for the Feathers query syntax for multiple properties\n */\nexport const queryProperties = <\n  T extends { [key: string]: JSONSchema },\n  X extends { [K in keyof T]?: { [key: string]: JSONSchema } }\n>(\n  definitions: T,\n  extensions: X = {} as X\n) =>\n  Object.keys(definitions).reduce(\n    (res, key) => {\n      const result = res as any\n      const definition = definitions[key]\n\n      result[key] = queryProperty(definition as JSONSchemaDefinition, extensions[key as keyof T])\n\n      return result\n    },\n    {} as { [K in keyof T]: PropertyQuery<T[K], X[K]> }\n  )\n\n/**\n * Creates a JSON schema for the complete Feathers query syntax including `$limit`, $skip`\n * and `$sort` and `$select` for the allowed properties.\n *\n * @param definition The property definitions to create the query syntax schema for\n * @param extensions Additional properties to add to the query property schema\n * @returns A JSON schema for the complete query syntax\n */\nexport const querySyntax = <\n  T extends { [key: string]: JSONSchema },\n  X extends { [K in keyof T]?: { [key: string]: JSONSchema } }\n>(\n  definition: T,\n  extensions: X = {} as X\n) => {\n  const keys = Object.keys(definition)\n  const props = queryProperties(definition, extensions)\n  const $or = {\n    type: 'array',\n    items: {\n      type: 'object',\n      additionalProperties: false,\n      properties: props\n    }\n  } as const\n  const $and = {\n    type: 'array',\n    items: {\n      type: 'object',\n      additionalProperties: false,\n      properties: {\n        ...props,\n        $or\n      }\n    }\n  } as const\n\n  return {\n    $limit: {\n      type: 'number',\n      minimum: 0\n    },\n    $skip: {\n      type: 'number',\n      minimum: 0\n    },\n    $sort: {\n      type: 'object',\n      properties: keys.reduce(\n        (res, key) => {\n          const result = res as any\n\n          result[key] = {\n            type: 'number',\n            enum: [1, -1]\n          }\n\n          return result\n        },\n        {} as { [K in keyof T]: { readonly type: 'number'; readonly enum: [1, -1] } }\n      )\n    },\n    $select: {\n      type: 'array',\n      maxItems: keys.length,\n      items: {\n        type: 'string',\n        ...(keys.length > 0 ? { enum: keys as any as (keyof T)[] } : {})\n      }\n    },\n    $or,\n    $and,\n    ...props\n  } as const\n}\n\nexport const ObjectIdSchema = () =>\n  ({\n    anyOf: [\n      { type: 'string', objectid: true },\n      { type: 'object', properties: {}, additionalProperties: true }\n    ]\n  }) as const\n"
  },
  {
    "path": "packages/schema/src/resolver.ts",
    "content": "import { BadRequest } from '@feathersjs/errors'\nimport { Schema } from './schema'\n\ntype PromiseOrLiteral<V> = Promise<V> | V\n\nexport type PropertyResolver<T, V, C> = ((\n  value: V | undefined,\n  obj: T,\n  context: C,\n  status: ResolverStatus<T, C>\n) => PromiseOrLiteral<V | undefined>) & { [IS_VIRTUAL]?: boolean }\n\nexport type VirtualResolver<T, V, C> = (\n  obj: T,\n  context: C,\n  status: ResolverStatus<T, C>\n) => PromiseOrLiteral<V | undefined>\n\nexport const IS_VIRTUAL = Symbol.for('@feathersjs/schema/virtual')\n\n/**\n * Create a resolver for a virtual property. A virtual property is a property that\n * is computed and never has an initial value.\n *\n * @param virtualResolver The virtual resolver function\n * @returns The property resolver function\n */\nexport const virtual = <T, V, C>(virtualResolver: VirtualResolver<T, V, C>) => {\n  const propertyResolver: PropertyResolver<T, V, C> = async (_value, obj, context, status) =>\n    virtualResolver(obj, context, status)\n\n  propertyResolver[IS_VIRTUAL] = true\n\n  return propertyResolver\n}\n\nexport type PropertyResolverMap<T, C> = {\n  [key in keyof T]?: PropertyResolver<T, T[key], C> | ReturnType<typeof virtual<T, T[key], C>>\n}\n\nexport type ResolverConverter<T, C> = (\n  obj: any,\n  context: C,\n  status: ResolverStatus<T, C>\n) => PromiseOrLiteral<T | undefined>\n\nexport interface ResolverOptions<T, C> {\n  schema?: Schema<T>\n  /**\n   * A converter function that is run before property resolvers\n   * to transform the initial data into a different format.\n   */\n  converter?: ResolverConverter<T, C>\n}\n\nexport interface ResolverConfig<T, C> extends ResolverOptions<T, C> {\n  /**\n   * @deprecated Use the `validateData` and `validateQuery` hooks explicitly instead\n   */\n  validate?: 'before' | 'after' | false\n  /**\n   * The properties to resolve\n   */\n  properties: PropertyResolverMap<T, C>\n}\n\nexport interface ResolverStatus<T, C> {\n  path: string[]\n  originalContext?: C\n  properties?: (keyof T)[]\n  stack: PropertyResolver<T, any, C>[]\n}\n\nexport class Resolver<T, C> {\n  readonly _type!: T\n  public propertyNames: (keyof T)[]\n  public virtualNames: (keyof T)[]\n\n  constructor(public readonly options: ResolverConfig<T, C>) {\n    this.propertyNames = Object.keys(options.properties) as any as (keyof T)[]\n    this.virtualNames = this.propertyNames.filter((name) => options.properties[name][IS_VIRTUAL])\n  }\n\n  /**\n   * Resolve a single property\n   *\n   * @param name The name of the property\n   * @param data The current data\n   * @param context The current resolver context\n   * @param status The current resolver status\n   * @returns The resolver property\n   */\n  async resolveProperty<D, K extends keyof T>(\n    name: K,\n    data: D,\n    context: C,\n    status: Partial<ResolverStatus<T, C>> = {}\n  ): Promise<T[K]> {\n    const resolver = this.options.properties[name]\n    const value = (data as any)[name]\n    const { path = [], stack = [] } = status || {}\n\n    // This prevents circular dependencies\n    if (stack.includes(resolver)) {\n      return undefined\n    }\n\n    const resolverStatus = {\n      ...status,\n      path: [...path, name as string],\n      stack: [...stack, resolver]\n    }\n\n    return resolver(value, data as any, context, resolverStatus)\n  }\n\n  async convert<D>(data: D, context: C, status?: Partial<ResolverStatus<T, C>>) {\n    if (this.options.converter) {\n      const { path = [], stack = [] } = status || {}\n\n      return this.options.converter(data, context, { ...status, path, stack })\n    }\n\n    return data\n  }\n\n  async resolve<D>(_data: D, context: C, status?: Partial<ResolverStatus<T, C>>): Promise<T> {\n    const { properties: resolvers, schema, validate } = this.options\n    const payload = await this.convert(_data, context, status)\n\n    if (!Array.isArray(status?.properties) && this.propertyNames.length === 0) {\n      return payload as T\n    }\n\n    const data = schema && validate === 'before' ? await schema.validate(payload) : payload\n    const propertyList = (\n      Array.isArray(status?.properties)\n        ? status?.properties\n        : // By default get all data and resolver keys but remove duplicates\n          [...new Set(Object.keys(data).concat(this.propertyNames as string[]))]\n    ) as (keyof T)[]\n\n    const result: any = {}\n    const errors: any = {}\n    let hasErrors = false\n\n    // Not the most elegant but better performance\n    await Promise.all(\n      propertyList.map(async (name) => {\n        const value = (data as any)[name]\n\n        if (resolvers[name]) {\n          try {\n            const resolved = await this.resolveProperty(name, data, context, status)\n\n            if (resolved !== undefined) {\n              result[name] = resolved\n            }\n          } catch (error: any) {\n            // TODO add error stacks\n            const convertedError =\n              typeof error.toJSON === 'function' ? error.toJSON() : { message: error.message || error }\n\n            errors[name] = convertedError\n            hasErrors = true\n          }\n        } else if (value !== undefined) {\n          result[name] = value\n        }\n      })\n    )\n\n    if (hasErrors) {\n      const propertyName = status?.properties ? ` ${status.properties.join('.')}` : ''\n\n      throw new BadRequest('Error resolving data' + (propertyName ? ` ${propertyName}` : ''), errors)\n    }\n\n    return schema && validate === 'after' ? await schema.validate(result) : result\n  }\n}\n\n/**\n * Create a new resolver with `<DataType, ContextType>`.\n *\n * @param options The configuration for the returned resolver\n * @returns A new resolver instance\n */\nexport function resolve<T, C>(\n  properties: PropertyResolverMap<T, C>,\n  options?: ResolverOptions<T, C>\n): Resolver<T, C>\nexport function resolve<T, C>(options: ResolverConfig<T, C>): Resolver<T, C>\nexport function resolve<T, C>(\n  properties: PropertyResolverMap<T, C> | ResolverConfig<T, C>,\n  options?: ResolverOptions<T, C>\n) {\n  const settings = (\n    (properties as ResolverConfig<T, C>).properties ? properties : { properties, ...options }\n  ) as ResolverConfig<T, C>\n\n  return new Resolver<T, C>(settings)\n}\n"
  },
  {
    "path": "packages/schema/src/schema.ts",
    "content": "import Ajv, { AsyncValidateFunction, ValidateFunction } from 'ajv'\nimport { FromSchema, JSONSchema } from 'json-schema-to-ts'\nimport { BadRequest } from '@feathersjs/errors'\n\nexport const DEFAULT_AJV = new Ajv({\n  coerceTypes: true,\n  addUsedSchema: false\n})\n\nexport { Ajv }\n\n/**\n * A validation function that takes data and returns the (possibly coerced)\n * data or throws a validation error.\n */\nexport type Validator<T = any, R = T> = (data: T) => Promise<R>\n\nexport type JSONSchemaDefinition = JSONSchema & {\n  $id: string\n  $async?: true\n  properties?: { [key: string]: JSONSchema }\n  required?: readonly string[]\n}\n\nexport interface Schema<T> {\n  validate<X = T>(...args: Parameters<ValidateFunction<X>>): Promise<X>\n}\n\nexport class SchemaWrapper<S extends JSONSchemaDefinition> implements Schema<FromSchema<S>> {\n  ajv: Ajv\n  validator: AsyncValidateFunction\n  readonly _type!: FromSchema<S>\n\n  constructor(\n    public definition: S,\n    ajv: Ajv = DEFAULT_AJV\n  ) {\n    this.ajv = ajv\n    this.validator = this.ajv.compile({\n      $async: true,\n      ...(this.definition as any)\n    }) as AsyncValidateFunction\n  }\n\n  get properties() {\n    return this.definition.properties as S['properties']\n  }\n\n  get required() {\n    return this.definition.required as S['required']\n  }\n\n  async validate<T = FromSchema<S>>(...args: Parameters<ValidateFunction<T>>) {\n    try {\n      const validated = (await this.validator(...args)) as T\n\n      return validated\n    } catch (error: any) {\n      throw new BadRequest(error.message, error.errors)\n    }\n  }\n\n  toJSON() {\n    return this.definition\n  }\n}\n\nexport function schema<S extends JSONSchemaDefinition>(definition: S, ajv: Ajv = DEFAULT_AJV) {\n  return new SchemaWrapper(definition, ajv)\n}\n"
  },
  {
    "path": "packages/schema/test/fixture.ts",
    "content": "import { feathers, HookContext, Application as FeathersApplication } from '@feathersjs/feathers'\nimport { memory, MemoryService } from '@feathersjs/memory'\nimport { GeneralError } from '@feathersjs/errors'\nimport { AdapterParams } from '@feathersjs/adapter-commons'\n\nimport {\n  resolve,\n  resolveResult,\n  resolveQuery,\n  resolveData,\n  validateData,\n  validateQuery,\n  querySyntax,\n  resolveDispatch,\n  resolveAll,\n  Ajv,\n  FromSchema,\n  getValidator,\n  getDataValidator,\n  virtual,\n  resolveExternal\n} from '../src'\n\nconst fixtureAjv = new Ajv({\n  coerceTypes: true,\n  addUsedSchema: false\n})\n\nexport const userDataSchema = {\n  $id: 'UserData',\n  type: 'object',\n  additionalProperties: false,\n  required: ['email'],\n  properties: {\n    email: { type: 'string' },\n    password: { type: 'string' }\n  }\n} as const\n\nexport const userDataValidator = getValidator(userDataSchema, fixtureAjv)\n\nexport const userDataValidatorMap = getDataValidator(userDataSchema, fixtureAjv)\n\nexport type UserData = FromSchema<typeof userDataSchema>\n\nexport const userDataResolver = resolve<UserData, HookContext<Application>>({\n  properties: {\n    password: async () => {\n      return 'hashed'\n    }\n  }\n})\n\nexport const userSchema = {\n  $id: 'User',\n  type: 'object',\n  additionalProperties: false,\n  required: ['id', ...userDataSchema.required],\n  properties: {\n    ...userDataSchema.properties,\n    id: { type: 'number' },\n    name: { type: 'string' }\n  }\n} as const\n\nexport type User = FromSchema<typeof userSchema>\n\nexport const userResolver = resolve<User, HookContext<Application>>({\n  name: async (_value, user) => user.email.split('@')[0]\n})\n\nexport const userExternalResolver = resolve<User, HookContext<Application>>({\n  properties: {\n    password: async (): Promise<undefined> => undefined,\n    email: async () => '[redacted]'\n  }\n})\n\nexport const secondUserResolver = resolve<User, HookContext<Application>>({\n  name: async (value, user) => `${value} (${user.email})`\n})\n\nexport const messageDataSchema = {\n  $id: 'MessageData',\n  type: 'object',\n  additionalProperties: false,\n  required: ['text', 'userId'],\n  properties: {\n    text: { type: 'string' },\n    userId: { type: 'number' }\n  }\n} as const\n\nexport type MessageData = FromSchema<typeof messageDataSchema>\n\nexport const messageSchema = {\n  $id: 'MessageResult',\n  type: 'object',\n  additionalProperties: false,\n  required: ['id', ...messageDataSchema.required],\n  properties: {\n    ...messageDataSchema.properties,\n    id: { type: 'number' },\n    user: { $ref: 'User' },\n    userList: { type: 'array', items: { $ref: 'User' } },\n    userPage: { type: 'object' }\n  }\n} as const\n\nexport type Message = FromSchema<\n  typeof messageSchema,\n  {\n    references: [typeof userSchema]\n  }\n>\n\nexport const messageResolver = resolve<Message, HookContext<Application>>({\n  user: virtual(async (message, context) => {\n    const { userId } = message\n\n    if (context.params.error === true) {\n      throw new GeneralError('This is an error')\n    }\n\n    const {\n      data: [user]\n    } = (await context.app.service('users').find({\n      ...context.params,\n      paginate: { default: 2 },\n      query: {\n        id: userId\n      }\n    })) as any\n\n    return user as Message['user']\n  }),\n  userList: virtual(async (_message, context) => {\n    const users = await context.app.service('users').find({\n      paginate: false\n    })\n\n    return users.map((user) => user) as any\n  }),\n  userPage: virtual(async (_message, context) => {\n    const users = await context.app.service('users').find({\n      adapter: {\n        paginate: {\n          default: 2\n        }\n      }\n    })\n\n    return users as any\n  })\n})\n\nexport const otherMessageResolver = resolve<{ text: string }, HookContext<Application>>({})\n\nexport const messageQuerySchema = {\n  $id: 'MessageQuery',\n  type: 'object',\n  additionalProperties: false,\n  required: [],\n  properties: {\n    ...querySyntax(messageDataSchema.properties),\n    $select: {\n      type: 'array',\n      items: { type: 'string' }\n    },\n    $resolve: {\n      type: 'array',\n      items: { type: 'string' }\n    }\n  }\n} as const\n\nexport type MessageQuery = FromSchema<typeof messageQuerySchema>\n\nexport const messageQueryValidator = getValidator(messageQuerySchema, fixtureAjv)\n\nexport const messageQueryResolver = resolve<MessageQuery, HookContext<Application>>({\n  userId: async (value, _query, context) => {\n    if (context.params?.user) {\n      return context.params.user.id\n    }\n\n    return value\n  }\n})\n\ninterface ServiceParams extends AdapterParams {\n  user?: User\n  error?: boolean\n}\n\nclass MessageService extends MemoryService<Message, MessageData, ServiceParams> {\n  async customMethod(data: any) {\n    return data\n  }\n}\n\nconst findResult = { message: 'Hello' }\nclass CustomService {\n  async find() {\n    return [findResult]\n  }\n}\n\nconst customMethodDataResolver = resolve<any, HookContext<Application>>({\n  properties: {\n    userId: async () => 0,\n    additionalData: async () => 'additional data'\n  }\n})\n\ntype ServiceTypes = {\n  users: MemoryService<User, UserData, ServiceParams>\n  messages: MessageService\n  paginatedMessages: MemoryService<Message, MessageData, ServiceParams>\n  custom: CustomService\n}\ntype Application = FeathersApplication<ServiceTypes>\n\nconst app = feathers<ServiceTypes>()\n\napp.use(\n  'users',\n  memory({\n    multi: ['create']\n  })\n)\napp.use('messages', new MessageService(), {\n  methods: ['find', 'get', 'create', 'update', 'patch', 'remove', 'customMethod']\n})\napp.use('custom', new CustomService())\n\napp.service('custom').hooks({\n  around: {\n    all: [resolveExternal(resolve<any, HookContext<Application>>({}))]\n  }\n})\n\napp.use('paginatedMessages', memory({ paginate: { default: 10 } }))\n\napp.service('messages').hooks({\n  around: {\n    all: [\n      resolveAll({\n        result: messageResolver,\n        query: messageQueryResolver\n      }),\n      validateQuery(messageQueryValidator)\n    ],\n    customMethod: [resolveData(customMethodDataResolver)],\n    find: [\n      async (context, next) => {\n        // A hook that makes sure that virtual properties are not passed to the adapter as `$select`\n        // An SQL adapter would throw an error if it received a query like this\n        if (context.params?.query?.$select && context.params?.query?.$select.includes('user')) {\n          throw new Error('Invalid $select')\n        }\n        await next()\n      }\n    ]\n  }\n})\n\napp\n  .service('paginatedMessages')\n  .hooks([\n    resolveDispatch(),\n    resolveResult(messageResolver, otherMessageResolver),\n    validateQuery(messageQueryValidator),\n    resolveQuery(messageQueryResolver)\n  ])\n\napp\n  .service('users')\n  .hooks([resolveDispatch(userExternalResolver), resolveResult(userResolver, secondUserResolver)])\n\napp.service('users').hooks({\n  create: [validateData(userDataValidator), validateData(userDataValidatorMap), resolveData(userDataResolver)]\n})\n\nexport { app }\n"
  },
  {
    "path": "packages/schema/test/hooks.test.ts",
    "content": "import { createContext } from '@feathersjs/feathers'\nimport assert from 'assert'\nimport { app, Message, User } from './fixture'\n\ndescribe('@feathersjs/schema/hooks', () => {\n  const text = 'Hi there'\n  let message: Message\n  let messageOnPaginatedService: Message\n  let user: User\n\n  const userProps = (user: User) => ({\n    user,\n    userList: [user],\n    userPage: {\n      limit: 2,\n      skip: 0,\n      total: 1,\n      data: [user]\n    }\n  })\n\n  before(async () => {\n    user = (\n      await app.service('users').create([\n        {\n          email: 'hello@feathersjs.com',\n          password: 'supersecret'\n        }\n      ])\n    )[0]\n    message = await app.service('messages').create({\n      text,\n      userId: user.id\n    })\n    messageOnPaginatedService = await app.service('paginatedMessages').create({\n      text,\n      userId: user.id\n    })\n  })\n\n  it('ran resolvers in sequence', async () => {\n    assert.strictEqual(user.name, 'hello (hello@feathersjs.com)')\n  })\n\n  it('validates data', async () => {\n    assert.rejects(() => app.service('users').create({ password: 'failing' } as any), {\n      name: 'BadRequest'\n    })\n  })\n\n  it('resolves results and handles resolver errors (#2534)', async () => {\n    const payload = {\n      userId: user.id,\n      text\n    }\n\n    assert.ok(user)\n    assert.strictEqual(user.password, 'hashed', 'Resolved data')\n    assert.deepStrictEqual(message, {\n      id: 0,\n      ...userProps(user),\n      ...payload\n    })\n\n    const messages = await app.service('messages').find({\n      provider: 'external'\n    })\n\n    assert.deepStrictEqual(messages, [\n      {\n        id: 0,\n        ...userProps(user),\n        ...payload\n      }\n    ])\n\n    await assert.rejects(\n      () =>\n        app.service('messages').find({\n          provider: 'external',\n          error: true\n        }),\n      {\n        name: 'BadRequest',\n        message: 'Error resolving data',\n        code: 400,\n        className: 'bad-request',\n        data: {\n          user: {\n            name: 'GeneralError',\n            message: 'This is an error',\n            code: 500,\n            className: 'general-error'\n          }\n        }\n      }\n    )\n  })\n\n  it('resolves get result with the object on result', async () => {\n    const payload = {\n      userId: user.id,\n      text\n    }\n\n    assert.ok(user)\n    assert.strictEqual(user.password, 'hashed', 'Resolved data')\n    assert.deepStrictEqual(message, {\n      id: 0,\n      ...userProps(user),\n      ...payload\n    })\n\n    const result = await app.service('messages').get(0, {\n      provider: 'external'\n    })\n\n    assert.deepStrictEqual(result, {\n      id: 0,\n      ...userProps(user),\n      ...payload\n    })\n  })\n\n  it('resolves with $select and virtual properties', async () => {\n    const messages = await app.service('messages').find({\n      paginate: false,\n      query: {\n        $select: ['user', 'text']\n      }\n    })\n    assert.deepStrictEqual(Object.keys(messages[0]), ['text', 'user'])\n  })\n\n  it('resolves find results with paginated result object', async () => {\n    const payload = {\n      userId: user.id,\n      text\n    }\n\n    assert.ok(user)\n    assert.strictEqual(user.password, 'hashed', 'Resolved data')\n    assert.deepStrictEqual(messageOnPaginatedService, {\n      id: 0,\n      ...userProps(user),\n      ...payload\n    })\n\n    const messages = await app.service('paginatedMessages').find({\n      provider: 'external',\n      query: {\n        $limit: 1,\n        $skip: 0\n      }\n    })\n\n    assert.deepStrictEqual(messages, {\n      limit: 1,\n      skip: 0,\n      total: 1,\n      data: [\n        {\n          id: 0,\n          ...userProps(user),\n          ...payload\n        }\n      ]\n    })\n  })\n\n  it('resolves safe dispatch data recursively and with arrays and pages', async () => {\n    const service = app.service('messages')\n    const context = await service.get(0, {}, createContext(service as any, 'get'))\n    const user = {\n      id: 0,\n      email: '[redacted]',\n      name: 'hello (hello@feathersjs.com)'\n    }\n\n    assert.strictEqual(context.result.user.password, 'hashed')\n\n    assert.deepStrictEqual(context.dispatch, {\n      text: 'Hi there',\n      userId: 0,\n      id: 0,\n      ...userProps(user)\n    })\n  })\n\n  it('resolves safe dispatch with static data', async () => {\n    const service = app.service('custom')\n\n    await service.find()\n    assert.deepStrictEqual(await service.find(), [{ message: 'Hello' }])\n  })\n\n  it('resolves data for custom methods', async () => {\n    const result = await app.service('messages').customMethod({ message: 'Hello' })\n    const user = {\n      email: 'hello@feathersjs.com',\n      password: 'hashed',\n      id: 0,\n      name: 'hello (hello@feathersjs.com)'\n    }\n\n    assert.deepStrictEqual(result, {\n      message: 'Hello',\n      userId: 0,\n      additionalData: 'additional data',\n      ...userProps(user)\n    })\n  })\n\n  it('validates and converts the query', async () => {\n    const otherUser = await app.service('users').create({\n      email: 'helloagain@feathersjs.com',\n      password: 'supersecret'\n    })\n\n    await app.service('messages').create({\n      text,\n      userId: otherUser.id\n    })\n\n    const messages = await app.service('messages').find({\n      paginate: false,\n      query: {\n        userId: `${user.id}`\n      }\n    })\n\n    assert.strictEqual(messages.length, 1)\n\n    const userMessages = await app.service('messages').find({\n      paginate: false,\n      user\n    })\n\n    assert.strictEqual(userMessages.length, 1)\n    assert.strictEqual(userMessages[0].userId, user.id)\n\n    const msg = await app.service('messages').get(userMessages[0].id, {\n      query: {\n        $resolve: ['user']\n      }\n    })\n\n    assert.deepStrictEqual(msg, {\n      user\n    })\n\n    assert.rejects(\n      () =>\n        app.service('messages').find({\n          query: {\n            thing: 'me'\n          }\n        }),\n      {\n        name: 'BadRequest',\n        message: 'validation failed',\n        code: 400,\n        className: 'bad-request',\n        data: [\n          {\n            instancePath: '',\n            schemaPath: '#/additionalProperties',\n            keyword: 'additionalProperties',\n            params: { additionalProperty: 'thing' },\n            message: 'must NOT have additional properties'\n          }\n        ]\n      }\n    )\n  })\n})\n"
  },
  {
    "path": "packages/schema/test/json-schema.test.ts",
    "content": "import Ajv from 'ajv'\nimport assert from 'assert'\nimport { ObjectId as MongoObjectId } from 'mongodb'\nimport { FromSchema } from '../src/'\nimport { querySyntax, ObjectIdSchema } from '../src/json-schema'\n\ndescribe('@feathersjs/schema/json-schema', () => {\n  it('querySyntax works with no properties', async () => {\n    const schema = {\n      type: 'object',\n      properties: querySyntax({})\n    }\n\n    new Ajv().compile(schema)\n  })\n\n  it('querySyntax with extensions', async () => {\n    const schema = {\n      name: {\n        type: 'string'\n      },\n      age: {\n        type: 'number'\n      }\n    } as const\n\n    const querySchema = {\n      type: 'object',\n      properties: querySyntax(schema, {\n        name: {\n          $ilike: {\n            type: 'string'\n          }\n        },\n        age: {\n          $value: {\n            type: 'null'\n          }\n        }\n      } as const)\n    } as const\n\n    type Query = FromSchema<typeof querySchema>\n\n    const q: Query = {\n      name: {\n        $ilike: 'hello'\n      },\n      age: {\n        $value: null,\n        $gte: 42\n      }\n    }\n\n    const validator = new Ajv({ strict: false }).compile(querySchema)\n\n    assert.ok(validator(q))\n  })\n\n  it('$in and $nin works with array definitions', async () => {\n    const schema = {\n      things: {\n        type: 'array',\n        items: { type: 'number' }\n      }\n    } as const\n\n    const querySchema = {\n      type: 'object',\n      properties: querySyntax(schema)\n    } as const\n\n    type Query = FromSchema<typeof querySchema>\n\n    const q: Query = {\n      things: {\n        $in: [10, 20],\n        $nin: [30]\n      }\n    }\n\n    const validator = new Ajv({ strict: false }).compile(querySchema)\n\n    assert.ok(validator(q))\n  })\n\n  // Test ObjectId validation\n  it('ObjectId', async () => {\n    const schema = {\n      type: 'object',\n      properties: {\n        _id: ObjectIdSchema()\n      }\n    }\n\n    const validator = new Ajv({\n      strict: false\n    }).compile(schema)\n    const validated = await validator({\n      _id: '507f191e810c19729de860ea'\n    })\n    assert.ok(validated)\n\n    const validated2 = await validator({\n      _id: new MongoObjectId()\n    })\n    assert.ok(validated2)\n  })\n})\n"
  },
  {
    "path": "packages/schema/test/resolver.test.ts",
    "content": "import assert from 'assert'\nimport { BadRequest } from '@feathersjs/errors'\n\nimport { FromSchema, schema, resolve, virtual } from '../src'\n\ndescribe('@feathersjs/schema/resolver', () => {\n  const userSchema = {\n    $id: 'simple-user',\n    type: 'object',\n    required: ['firstName', 'lastName'],\n    additionalProperties: false,\n    properties: {\n      firstName: { type: 'string' },\n      lastName: { type: 'string' },\n      password: { type: 'string' }\n    }\n  } as const\n  const context = {\n    isContext: true\n  }\n\n  type User = FromSchema<typeof userSchema> & {\n    name: string\n  }\n\n  it('simple resolver', async () => {\n    const userResolver = resolve<User, typeof context>({\n      password: async (): Promise<undefined> => undefined,\n\n      name: async (_value, user, ctx, status) => {\n        assert.deepStrictEqual(ctx, context)\n        assert.deepStrictEqual(status.path, ['name'])\n        assert.strictEqual(typeof status.stack[0], 'function')\n\n        return `${user.firstName} ${user.lastName}`\n      }\n    })\n\n    const u = await userResolver.resolve(\n      {\n        firstName: 'Dave',\n        lastName: 'L.'\n      },\n      context\n    )\n\n    assert.deepStrictEqual(u, {\n      firstName: 'Dave',\n      lastName: 'L.',\n      name: 'Dave L.'\n    })\n\n    const withProps = await userResolver.resolve(\n      {\n        firstName: 'David',\n        lastName: 'L'\n      },\n      context,\n      {\n        properties: ['name', 'lastName']\n      }\n    )\n\n    assert.deepStrictEqual(withProps, {\n      name: 'David L',\n      lastName: 'L'\n    })\n  })\n\n  it('simple resolver with virtual', async () => {\n    const userResolver = resolve<User, typeof context>({\n      password: async (): Promise<undefined> => undefined,\n\n      name: virtual(async (user, ctx, status) => {\n        assert.deepStrictEqual(ctx, context)\n        assert.deepStrictEqual(status.path, ['name'])\n        assert.strictEqual(typeof status.stack[0], 'function')\n\n        return `${user.firstName} ${user.lastName}`\n      })\n    })\n\n    const u = await userResolver.resolve(\n      {\n        firstName: 'Dave',\n        lastName: 'L.'\n      },\n      context\n    )\n\n    assert.deepStrictEqual(u, {\n      firstName: 'Dave',\n      lastName: 'L.',\n      name: 'Dave L.'\n    })\n  })\n\n  it('simple resolver with schema and validation', async () => {\n    const userFeathersSchema = schema(userSchema)\n    const userBeforeResolver = resolve<User, typeof context>({\n      schema: userFeathersSchema,\n      validate: 'before',\n      properties: {\n        name: async (_name, user) => `${user.firstName} ${user.lastName}`\n      }\n    })\n    const userAfterResolver = resolve<User, typeof context>({\n      schema: userFeathersSchema,\n      validate: 'after',\n      properties: {\n        firstName: async (): Promise<undefined> => undefined\n      }\n    })\n\n    await assert.rejects(() => userBeforeResolver.resolve({}, context), {\n      message: 'validation failed'\n    })\n    await assert.rejects(\n      () =>\n        userAfterResolver.resolve(\n          {\n            firstName: 'Test',\n            lastName: 'Me'\n          },\n          context\n        ),\n      {\n        message: 'validation failed'\n      }\n    )\n  })\n\n  it('simple resolver with converter', async () => {\n    const userConverterResolver = resolve<User, typeof context>({\n      converter: async (data) => ({\n        firstName: 'Default',\n        lastName: 'Name',\n        ...data\n      }),\n      properties: {\n        name: async (_name, user) => `${user.firstName} ${user.lastName}`\n      }\n    })\n\n    const u = await userConverterResolver.resolve({}, context)\n\n    assert.deepStrictEqual(u, {\n      firstName: 'Default',\n      lastName: 'Name',\n      name: 'Default Name'\n    })\n  })\n\n  it('resolving with errors', async () => {\n    const dummyResolver = resolve<{ name: string; age: number }, Record<string, unknown>>({\n      properties: {\n        name: async (value) => {\n          if (value === 'Dave') {\n            throw new Error(`No ${value}s allowed`)\n          }\n\n          return value\n        },\n        age: async (value) => {\n          if (value && value < 18) {\n            throw new BadRequest('Invalid age')\n          }\n\n          return value\n        }\n      }\n    })\n\n    assert.rejects(\n      () =>\n        dummyResolver.resolve(\n          {\n            name: 'Dave',\n            age: 16\n          },\n          {}\n        ),\n      {\n        name: 'BadRequest',\n        message: 'Error resolving data',\n        code: 400,\n        className: 'bad-request',\n        data: {\n          name: { message: 'No Daves allowed' },\n          age: {\n            name: 'BadRequest',\n            message: 'Invalid age',\n            code: 400,\n            className: 'bad-request'\n          }\n        }\n      }\n    )\n  })\n\n  it('empty resolver returns original data', async () => {\n    const resolver = resolve({\n      properties: {}\n    })\n    const data = { message: 'Hello' }\n    const resolved = await resolver.resolve(data, {})\n\n    assert.strictEqual(data, resolved)\n  })\n\n  it('empty resolver still allows to select properties', async () => {\n    const data = { message: 'Hello', name: 'David' }\n    const resolver = resolve<typeof data, any>({\n      properties: {}\n    })\n    const resolved = await resolver.resolve(data, {}, { properties: ['message'] })\n\n    assert.deepStrictEqual(resolved, { message: 'Hello' })\n  })\n})\n"
  },
  {
    "path": "packages/schema/test/schema.test.ts",
    "content": "import assert from 'assert'\n\nimport { schema, Infer, queryProperty } from '../src/'\nimport Ajv, { AnySchemaObject } from 'ajv'\nimport addFormats from 'ajv-formats'\n\nconst customAjv = new Ajv({\n  coerceTypes: true\n})\naddFormats(customAjv)\n\n// Utility for converting \"date\" and \"date-time\" string formats into Dates.\ncustomAjv.addKeyword({\n  keyword: 'convert',\n  type: 'string',\n  compile(schemaVal: boolean, parentSchema: AnySchemaObject) {\n    return ['date-time', 'date'].includes(parentSchema.format) && schemaVal\n      ? function (value: string, obj: any) {\n          const { parentData, parentDataProperty } = obj\n          // Update date-time string to Date object\n          parentData[parentDataProperty] = new Date(value)\n          return true\n        }\n      : () => true\n  }\n})\n\ndescribe('@feathersjs/schema/schema', () => {\n  it('type inference and validation', async () => {\n    const messageSchema = schema({\n      $id: 'message-test',\n      type: 'object',\n      required: ['text', 'read'],\n      additionalProperties: false,\n      properties: {\n        text: {\n          type: 'string'\n        },\n        read: {\n          type: 'boolean'\n        },\n        upvotes: {\n          type: 'number'\n        }\n      }\n    } as const)\n    type Message = Infer<typeof messageSchema>\n\n    const message = await messageSchema.validate<Message>({\n      text: 'hi',\n      read: 0,\n      upvotes: '10'\n    })\n\n    assert.deepStrictEqual(messageSchema.toJSON(), messageSchema.definition)\n    assert.deepStrictEqual(message, {\n      text: 'hi',\n      read: false,\n      upvotes: 10\n    })\n\n    await assert.rejects(() => messageSchema.validate({ text: 'failing' }), {\n      name: 'BadRequest',\n      data: [\n        {\n          instancePath: '',\n          keyword: 'required',\n          message: \"must have required property 'read'\",\n          params: {\n            missingProperty: 'read'\n          },\n          schemaPath: '#/required'\n        }\n      ]\n    })\n  })\n\n  it('uses custom AJV with format validation', async () => {\n    const formatsSchema = schema(\n      {\n        $id: 'formats-test',\n        type: 'object',\n        required: [],\n        additionalProperties: false,\n        properties: {\n          dobString: {\n            type: 'string',\n            format: 'date'\n          },\n          createdAt: {\n            type: 'string',\n            format: 'date-time'\n          }\n        }\n      } as const,\n      customAjv\n    )\n\n    await formatsSchema.validate({\n      createdAt: '2021-12-22T23:59:59.999Z'\n    })\n\n    try {\n      await formatsSchema.validate({\n        createdAt: '2021-12-22T23:59:59.bbb'\n      })\n    } catch (error: any) {\n      assert.equal(error.data[0].message, 'must match format \"date-time\"')\n    }\n  })\n\n  it('custom AJV can convert dates', async () => {\n    const definition = {\n      $id: 'converts-formats-test',\n      type: 'object',\n      required: [],\n      additionalProperties: false,\n      properties: {\n        dobString: queryProperty({\n          type: 'string',\n          format: 'date',\n          convert: true\n        }),\n        createdAt: {\n          type: 'string',\n          format: 'date-time',\n          convert: true\n        }\n      }\n    } as const\n\n    const formatsSchema = schema(definition, customAjv)\n\n    const validated: any = await formatsSchema.validate({\n      dobString: { $gt: '2025-04-25' },\n      createdAt: '2021-12-22T23:59:59.999Z'\n    })\n\n    assert.ok(validated.dobString.$gt instanceof Date)\n    assert.ok(validated.createdAt instanceof Date)\n  })\n\n  it('schema extension and type inference', async () => {\n    const messageSchema = schema({\n      $id: 'message-ext',\n      type: 'object',\n      required: ['text', 'read'],\n      additionalProperties: false,\n      properties: {\n        text: {\n          type: 'string'\n        },\n        read: {\n          type: 'boolean'\n        }\n      }\n    } as const)\n\n    const messageResultSchema = schema({\n      $id: 'message-ext-vote',\n      type: 'object',\n      required: ['upvotes', ...messageSchema.definition.required],\n      additionalProperties: false,\n      properties: {\n        ...messageSchema.definition.properties,\n        upvotes: {\n          type: 'number'\n        }\n      }\n    } as const)\n\n    type MessageResult = Infer<typeof messageResultSchema>\n\n    const m = await messageResultSchema.validate<MessageResult>({\n      text: 'Hi',\n      read: 'false',\n      upvotes: '23'\n    })\n\n    assert.deepStrictEqual(m, {\n      text: 'Hi',\n      read: false,\n      upvotes: 23\n    })\n  })\n\n  it('with references', async () => {\n    const userSchema = schema(\n      {\n        $id: 'ref-user',\n        type: 'object',\n        required: ['email'],\n        additionalProperties: false,\n        properties: {\n          email: { type: 'string' },\n          age: { type: 'number' }\n        }\n      } as const,\n      customAjv\n    )\n    const messageSchema = schema(\n      {\n        $id: 'ref-message',\n        type: 'object',\n        required: ['text', 'user'],\n        additionalProperties: false,\n        properties: {\n          text: {\n            type: 'string'\n          },\n          user: {\n            $ref: 'ref-user'\n          }\n        }\n      } as const,\n      customAjv\n    )\n\n    type User = Infer<typeof userSchema>\n    type Message = Infer<typeof messageSchema> & {\n      user: User\n    }\n\n    const res = await messageSchema.validate<Message>({\n      text: 'Hello',\n      user: {\n        email: 'hello@feathersjs.com',\n        age: '42'\n      }\n    })\n\n    assert.ok(userSchema)\n    assert.deepStrictEqual(res, {\n      text: 'Hello',\n      user: { email: 'hello@feathersjs.com', age: 42 }\n    })\n  })\n\n  it('works with oneOf properties (#2508)', async () => {\n    const oneOfSchema = schema({\n      $id: 'schemaA',\n      oneOf: [\n        {\n          type: 'object',\n          additionalProperties: false,\n          required: ['x'],\n          properties: {\n            x: { type: 'number' }\n          }\n        },\n        {\n          type: 'object',\n          additionalProperties: false,\n          required: ['y'],\n          properties: {\n            y: { type: 'number' }\n          }\n        }\n      ]\n    } as const)\n\n    const res = await oneOfSchema.validate({\n      x: '3'\n    })\n\n    assert.deepStrictEqual(res, { x: 3 })\n  })\n\n  it('can handle compound queryProperty', async () => {\n    const formatsSchema = schema(\n      {\n        $id: 'compoundQueryProperty',\n        type: 'object',\n        required: [],\n        additionalProperties: false,\n        properties: {\n          dobString: queryProperty({\n            oneOf: [\n              { type: 'string', format: 'date', convert: true },\n              { type: 'string', format: 'date-time', convert: true },\n              { type: 'object' }\n            ]\n          })\n        }\n      } as const,\n      customAjv\n    )\n\n    const validated = await formatsSchema.validate({\n      dobString: { $gt: '2025-04-25', $lte: new Date('2027-04-25') }\n    })\n\n    assert.ok(validated)\n  })\n\n  it('can still fail queryProperty validation', async () => {\n    const formatsSchema = schema(\n      {\n        $id: 'compoundQueryPropertyFail',\n        type: 'object',\n        required: [],\n        additionalProperties: false,\n        properties: {\n          dobString: queryProperty({ type: 'string' })\n        }\n      } as const,\n      customAjv\n    )\n\n    try {\n      const validated = await formatsSchema.validate({\n        dobString: { $moose: 'test' }\n      })\n      assert(!validated, 'should not have gotten here')\n    } catch (error: any) {\n      assert.ok(error.data?.length > 0)\n    }\n  })\n\n  it('removes default from queryProperty schemas like $gt', async () => {\n    const validator = schema(\n      {\n        $id: 'noDefault$gt',\n        type: 'object',\n        required: [],\n        additionalProperties: false,\n        properties: {\n          someDate: queryProperty({ default: '0000-00-00', type: 'string' })\n        }\n      } as const,\n      customAjv\n    )\n\n    assert.equal(\n      validator.definition.properties.someDate.anyOf[1].properties.$gt.type,\n      'string',\n      'type is found under $gt'\n    )\n    assert(!validator.definition.properties.someDate.anyOf[1].properties.$gt.default, 'no default under $gt')\n  })\n})\n"
  },
  {
    "path": "packages/schema/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/socketio/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n### Bug Fixes\n\n- Reduce usage of lodash ([#3455](https://github.com/feathersjs/feathers/issues/3455)) ([8ce807a](https://github.com/feathersjs/feathers/commit/8ce807a5ca53ff5b8d5107a0656c6329404e6e6c))\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **socketio:** Disconnect socket on app disconnect event ([#2896](https://github.com/feathersjs/feathers/issues/2896)) ([4ba0039](https://github.com/feathersjs/feathers/commit/4ba003907843cfc2655798a568b16f07ff8adb1b))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n### Bug Fixes\n\n- **authentication:** Improve logout and disconnect connection handling ([#2813](https://github.com/feathersjs/feathers/issues/2813)) ([dd77379](https://github.com/feathersjs/feathers/commit/dd77379d8bdcd32d529bef912e672639e4899823))\n- **docs:** Review transport API docs and update Express middleware setup ([#2811](https://github.com/feathersjs/feathers/issues/2811)) ([1b97f14](https://github.com/feathersjs/feathers/commit/1b97f14d474f5613482f259eeaa585c24fcfab43))\n\n### Features\n\n- **cli:** Add authentication client to generated client ([#2801](https://github.com/feathersjs/feathers/issues/2801)) ([bd59f91](https://github.com/feathersjs/feathers/commit/bd59f91b45a01c2eea0c4386e567f4de5aa6ad99))\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Bug Fixes\n\n- **core:** Ensure setup and teardown can be overriden and maintain hook functionality ([#2779](https://github.com/feathersjs/feathers/issues/2779)) ([ab580cb](https://github.com/feathersjs/feathers/commit/ab580cbcaa68d19144d86798c13bf564f9d424a6))\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n### Bug Fixes\n\n- **socketio:** Reinitialize hooks on overriden setup method ([#2722](https://github.com/feathersjs/feathers/issues/2722)) ([5e8e7c4](https://github.com/feathersjs/feathers/commit/5e8e7c442238fdc929a0a36b8b8ca2b230ce761f))\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Features\n\n- **typescript:** Improve params and query typeability ([#2600](https://github.com/feathersjs/feathers/issues/2600)) ([df28b76](https://github.com/feathersjs/feathers/commit/df28b7619161f1df5e700326f52cca1a92dc5d28))\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Features\n\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n### Features\n\n- **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n### Bug Fixes\n\n- **dependencies:** Fix transport-commons dependency and update other dependencies ([#2284](https://github.com/feathersjs/feathers/issues/2284)) ([05b03b2](https://github.com/feathersjs/feathers/commit/05b03b27b40604d956047e3021d8053c3a137616))\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n### Features\n\n- **core:** Public custom service methods ([#2270](https://github.com/feathersjs/feathers/issues/2270)) ([e65abfb](https://github.com/feathersjs/feathers/commit/e65abfb5388df6c19a11c565cf1076a29f32668d))\n- Application service types default to any ([#1566](https://github.com/feathersjs/feathers/issues/1566)) ([d93ba9a](https://github.com/feathersjs/feathers/commit/d93ba9a17edd20d3397bb00f4f6e82e804e42ed6))\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n- **core:** Remove Uberproto ([#2178](https://github.com/feathersjs/feathers/issues/2178)) ([ddf8821](https://github.com/feathersjs/feathers/commit/ddf8821f53317e6a378657f7d66acb03a037ee47))\n\n### BREAKING CHANGES\n\n- **core:** Services no longer extend Uberproto objects and\n  `service.mixin()` is no longer available.\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Features\n\n- **transport-commons:** Remove legacy message format and unnecessary client timeouts ([#1939](https://github.com/feathersjs/feathers/issues/1939)) ([5538881](https://github.com/feathersjs/feathers/commit/5538881a08bc130de42c5984055729d8336f8615))\n\n### BREAKING CHANGES\n\n- **transport-commons:** Removes the old message format and client service timeout\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Features\n\n- **transport-commons:** Remove legacy message format and unnecessary client timeouts ([#1939](https://github.com/feathersjs/feathers/issues/1939)) ([5538881](https://github.com/feathersjs/feathers/commit/5538881a08bc130de42c5984055729d8336f8615))\n\n### BREAKING CHANGES\n\n- **transport-commons:** Removes the old message format and client service timeout\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.5.6](https://github.com/feathersjs/feathers/compare/v4.5.5...v4.5.6) (2020-07-12)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.5.4](https://github.com/feathersjs/feathers/compare/v4.5.3...v4.5.4) (2020-04-29)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n### Features\n\n- **authentication:** Add parseStrategies to allow separate strategies for creating JWTs and parsing headers ([#1708](https://github.com/feathersjs/feathers/issues/1708)) ([5e65629](https://github.com/feathersjs/feathers/commit/5e65629b924724c3e81d7c81df047e123d1c8bd7))\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.3.5](https://github.com/feathersjs/feathers/compare/v4.3.4...v4.3.5) (2019-10-07)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n### Bug Fixes\n\n- Typing improvements ([#1580](https://github.com/feathersjs/feathers/issues/1580)) ([7818aec](https://github.com/feathersjs/feathers/commit/7818aec))\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Expire and remove authenticated real-time connections ([#1512](https://github.com/feathersjs/feathers/issues/1512)) ([2707c33](https://github.com/feathersjs/feathers/commit/2707c33))\n- Use WeakMap to connect socket to connection ([#1509](https://github.com/feathersjs/feathers/issues/1509)) ([64807e3](https://github.com/feathersjs/feathers/commit/64807e3))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n### Bug Fixes\n\n- Use `export =` in TypeScript definitions ([#1285](https://github.com/feathersjs/feathers/issues/1285)) ([12d0f4b](https://github.com/feathersjs/feathers/commit/12d0f4b))\n\n### Features\n\n- Add global disconnect event ([#1355](https://github.com/feathersjs/feathers/issues/1355)) ([85afcca](https://github.com/feathersjs/feathers/commit/85afcca))\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n### Features\n\n- Add params.headers to all transports when available ([#1303](https://github.com/feathersjs/feathers/issues/1303)) ([ebce79b](https://github.com/feathersjs/feathers/commit/ebce79b))\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n- **package:** update debug to version 3.0.0 ([#83](https://github.com/feathersjs/feathers/issues/83)) ([49f1de9](https://github.com/feathersjs/feathers/commit/49f1de9))\n- **package:** update socket.io to version 2.0.0 ([#75](https://github.com/feathersjs/feathers/issues/75)) ([d4a4b71](https://github.com/feathersjs/feathers/commit/d4a4b71))\n\n### chore\n\n- drop support for Node.js 0.10 ([#48](https://github.com/feathersjs/feathers/issues/48)) ([3f7555a](https://github.com/feathersjs/feathers/commit/3f7555a))\n\n### Features\n\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n\n### BREAKING CHANGES\n\n- This module no longer supports Node.js 0.10\n\n## [3.2.9](https://github.com/feathersjs/feathers/compare/@feathersjs/socketio@3.2.8...@feathersjs/socketio@3.2.9) (2019-01-02)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n<a name=\"3.2.8\"></a>\n\n## [3.2.8](https://github.com/feathersjs/feathers/compare/@feathersjs/socketio@3.2.7...@feathersjs/socketio@3.2.8) (2018-12-16)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n<a name=\"3.2.7\"></a>\n\n## [3.2.7](https://github.com/feathersjs/feathers/compare/@feathersjs/socketio@3.2.6...@feathersjs/socketio@3.2.7) (2018-10-25)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n\n<a name=\"3.2.6\"></a>\n\n## [3.2.6](https://github.com/feathersjs/feathers/compare/@feathersjs/socketio@3.2.5...@feathersjs/socketio@3.2.6) (2018-09-21)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n<a name=\"3.2.5\"></a>\n\n## [3.2.5](https://github.com/feathersjs/feathers/compare/@feathersjs/socketio@3.2.4...@feathersjs/socketio@3.2.5) (2018-09-17)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n<a name=\"3.2.4\"></a>\n\n## [3.2.4](https://github.com/feathersjs/feathers/compare/@feathersjs/socketio@3.2.3...@feathersjs/socketio@3.2.4) (2018-09-02)\n\n**Note:** Version bump only for package @feathersjs/socketio\n\n<a name=\"3.2.3\"></a>\n\n## 3.2.3\n\n- Migrate to Monorepo ([feathers#462](https://github.com/feathersjs/feathers/issues/462))\n\n## [v3.2.2](https://github.com/feathersjs/socketio/tree/v3.2.2) (2018-06-03)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v3.2.1...v3.2.2)\n\n**Merged pull requests:**\n\n- Update uberproto to the latest version 🚀 [\\#117](https://github.com/feathersjs/socketio/pull/117) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.2.1](https://github.com/feathersjs/socketio/tree/v3.2.1) (2018-04-04)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v3.2.0...v3.2.1)\n\n**Closed issues:**\n\n- Connection closed before receiving a handshake response [\\#113](https://github.com/feathersjs/socketio/issues/113)\n- `yarn add @feathersjs/socketio` gets stuck [\\#112](https://github.com/feathersjs/socketio/issues/112)\n\n**Merged pull requests:**\n\n- Use latest version of Socket.io \\(2.1.0\\) [\\#115](https://github.com/feathersjs/socketio/pull/115) ([daffl](https://github.com/daffl))\n\n## [v3.2.0](https://github.com/feathersjs/socketio/tree/v3.2.0) (2018-02-09)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v3.1.0...v3.2.0)\n\n**Closed issues:**\n\n- My chat room sometimes the user's text has become????? [\\#109](https://github.com/feathersjs/socketio/issues/109)\n\n**Merged pull requests:**\n\n- Update @feathersjs/transport-commons to the latest version 🚀 [\\#111](https://github.com/feathersjs/socketio/pull/111) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.1.0](https://github.com/feathersjs/socketio/tree/v3.1.0) (2018-01-30)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v3.0.2...v3.1.0)\n\n**Closed issues:**\n\n- How to change 5000ms timeout? [\\#107](https://github.com/feathersjs/socketio/issues/107)\n\n**Merged pull requests:**\n\n- Change dependency to @feathersjs/transport-commons [\\#110](https://github.com/feathersjs/socketio/pull/110) ([daffl](https://github.com/daffl))\n- Update mocha to the latest version 🚀 [\\#108](https://github.com/feathersjs/socketio/pull/108) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.0.2](https://github.com/feathersjs/socketio/tree/v3.0.2) (2018-01-03)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v3.0.1...v3.0.2)\n\n**Closed issues:**\n\n- Updated from feathers-socketio to @feathersjs/socketio; error message [\\#104](https://github.com/feathersjs/socketio/issues/104)\n- How to stop listening to socket server from client service [\\#103](https://github.com/feathersjs/socketio/issues/103)\n- Options are not passed to socket-io [\\#101](https://github.com/feathersjs/socketio/issues/101)\n- feathers / graphql using REST / Sockets [\\#97](https://github.com/feathersjs/socketio/issues/97)\n\n**Merged pull requests:**\n\n- Update Readme to correspond with latest release [\\#106](https://github.com/feathersjs/socketio/pull/106) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#105](https://github.com/feathersjs/socketio/pull/105) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update feathers-memory to the latest version 🚀 [\\#102](https://github.com/feathersjs/socketio/pull/102) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.0.1](https://github.com/feathersjs/socketio/tree/v3.0.1) (2017-11-16)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v3.0.0...v3.0.1)\n\n**Closed issues:**\n\n- Remote address IP is always undefined [\\#96](https://github.com/feathersjs/socketio/issues/96)\n\n**Merged pull requests:**\n\n- Add default export for better ES module \\(TypeScript\\) compatibility [\\#100](https://github.com/feathersjs/socketio/pull/100) ([daffl](https://github.com/daffl))\n- Updating client use example to fix imports [\\#99](https://github.com/feathersjs/socketio/pull/99) ([corymsmith](https://github.com/corymsmith))\n\n## [v3.0.0](https://github.com/feathersjs/socketio/tree/v3.0.0) (2017-11-01)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v2.0.1...v3.0.0)\n\n**Merged pull requests:**\n\n- Update dependencies for release [\\#95](https://github.com/feathersjs/socketio/pull/95) ([daffl](https://github.com/daffl))\n- Throw an error when using an incompatible version of Feathers [\\#94](https://github.com/feathersjs/socketio/pull/94) ([daffl](https://github.com/daffl))\n\n## [v2.0.1](https://github.com/feathersjs/socketio/tree/v2.0.1) (2017-10-31)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v3.0.0-pre.4...v2.0.1)\n\n**Merged pull requests:**\n\n- Add an error when trying to use earlier versions with Feathers v3 [\\#93](https://github.com/feathersjs/socketio/pull/93) ([daffl](https://github.com/daffl))\n\n## [v3.0.0-pre.4](https://github.com/feathersjs/socketio/tree/v3.0.0-pre.4) (2017-10-25)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v3.0.0-pre.3...v3.0.0-pre.4)\n\n## [v3.0.0-pre.3](https://github.com/feathersjs/socketio/tree/v3.0.0-pre.3) (2017-10-22)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v3.0.0-pre.2...v3.0.0-pre.3)\n\n**Merged pull requests:**\n\n- Rename repository and update to using npm scopes [\\#92](https://github.com/feathersjs/socketio/pull/92) ([daffl](https://github.com/daffl))\n- Updates for Feathers v3 \\(Buzzard\\) [\\#91](https://github.com/feathersjs/socketio/pull/91) ([daffl](https://github.com/daffl))\n\n## [v3.0.0-pre.2](https://github.com/feathersjs/socketio/tree/v3.0.0-pre.2) (2017-10-18)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v3.0.0-pre.1...v3.0.0-pre.2)\n\n**Merged pull requests:**\n\n- Some finishing touches for v3 [\\#90](https://github.com/feathersjs/socketio/pull/90) ([daffl](https://github.com/daffl))\n\n## [v3.0.0-pre.1](https://github.com/feathersjs/socketio/tree/v3.0.0-pre.1) (2017-10-17)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v2.0.0...v3.0.0-pre.1)\n\n**Closed issues:**\n\n- Filter service updates by ID [\\#87](https://github.com/feathersjs/socketio/issues/87)\n- An in-range update of mocha is breaking the build 🚨 [\\#86](https://github.com/feathersjs/socketio/issues/86)\n- An in-range update of babel-cli is breaking the build 🚨 [\\#85](https://github.com/feathersjs/socketio/issues/85)\n- Connection closed before receiving a handshake response [\\#84](https://github.com/feathersjs/socketio/issues/84)\n- Maybe acting wrong please look into my test app [\\#81](https://github.com/feathersjs/socketio/issues/81)\n- Connecting to sockets on a path [\\#80](https://github.com/feathersjs/socketio/issues/80)\n- An in-range update of babel-core is breaking the build 🚨 [\\#79](https://github.com/feathersjs/socketio/issues/79)\n- An in-range update of mocha is breaking the build 🚨 [\\#78](https://github.com/feathersjs/socketio/issues/78)\n- Add Socket.io v2 support [\\#77](https://github.com/feathersjs/socketio/issues/77)\n- Any chance for socket.io-p2p support? [\\#37](https://github.com/feathersjs/socketio/issues/37)\n\n**Merged pull requests:**\n\n- Finalizing updates for Feathers v3 [\\#89](https://github.com/feathersjs/socketio/pull/89) ([daffl](https://github.com/daffl))\n- Update mocha to the latest version 🚀 [\\#88](https://github.com/feathersjs/socketio/pull/88) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update debug to the latest version 🚀 [\\#83](https://github.com/feathersjs/socketio/pull/83) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update to latest plugin infrastructure [\\#82](https://github.com/feathersjs/socketio/pull/82) ([daffl](https://github.com/daffl))\n\n## [v2.0.0](https://github.com/feathersjs/socketio/tree/v2.0.0) (2017-05-10)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.6.0...v2.0.0)\n\n**Closed issues:**\n\n- An in-range update of feathers-hooks is breaking the build 🚨 [\\#74](https://github.com/feathersjs/socketio/issues/74)\n- An in-range update of debug is breaking the build 🚨 [\\#73](https://github.com/feathersjs/socketio/issues/73)\n- An in-range update of debug is breaking the build 🚨 [\\#71](https://github.com/feathersjs/socketio/issues/71)\n\n**Merged pull requests:**\n\n- Update socket.io-client to the latest version 🚀 [\\#76](https://github.com/feathersjs/socketio/pull/76) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update socket.io to the latest version 🚀 [\\#75](https://github.com/feathersjs/socketio/pull/75) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update semistandard to the latest version 🚀 [\\#72](https://github.com/feathersjs/socketio/pull/72) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.6.0](https://github.com/feathersjs/socketio/tree/v1.6.0) (2017-04-18)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.5.2...v1.6.0)\n\n**Closed issues:**\n\n- Add headers and remote ip address to socket.feathers [\\#67](https://github.com/feathersjs/socketio/issues/67)\n\n**Merged pull requests:**\n\n- Update feathers-hooks to the latest version 🚀 [\\#70](https://github.com/feathersjs/socketio/pull/70) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Add port argument [\\#69](https://github.com/feathersjs/socketio/pull/69) ([kozzztya](https://github.com/kozzztya))\n- Update dependencies to enable Greenkeeper 🌴 [\\#68](https://github.com/feathersjs/socketio/pull/68) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.5.2](https://github.com/feathersjs/socketio/tree/v1.5.2) (2017-03-03)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.5.1...v1.5.2)\n\n**Merged pull requests:**\n\n- Server-side socketio typedef to allow `import \\* as` syntax when importing [\\#65](https://github.com/feathersjs/socketio/pull/65) ([myknbani](https://github.com/myknbani))\n\n## [v1.5.1](https://github.com/feathersjs/socketio/tree/v1.5.1) (2017-03-02)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.5.0...v1.5.1)\n\n**Closed issues:**\n\n- Typescript definition bug [\\#63](https://github.com/feathersjs/socketio/issues/63)\n\n**Merged pull requests:**\n\n- fix Typescript issue \\(\\#63\\) [\\#64](https://github.com/feathersjs/socketio/pull/64) ([superbarne](https://github.com/superbarne))\n- feathers-hooks@1.8.0 breaks build 🚨 [\\#62](https://github.com/feathersjs/socketio/pull/62) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.5.0](https://github.com/feathersjs/socketio/tree/v1.5.0) (2017-03-01)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.4.3...v1.5.0)\n\n**Merged pull requests:**\n\n- Typescript Definitions [\\#60](https://github.com/feathersjs/socketio/pull/60) ([AbraaoAlves](https://github.com/AbraaoAlves))\n\n## [v1.4.3](https://github.com/feathersjs/socketio/tree/v1.4.3) (2017-02-24)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.4.2...v1.4.3)\n\n**Closed issues:**\n\n- Get data after connection established [\\#59](https://github.com/feathersjs/socketio/issues/59)\n- Unable to use feathers from within React \\(Feathers vs SocketIO implementation setup issue\\) [\\#51](https://github.com/feathersjs/socketio/issues/51)\n\n**Merged pull requests:**\n\n- Add option to set the maxListeners [\\#61](https://github.com/feathersjs/socketio/pull/61) ([Faianca](https://github.com/Faianca))\n- Create .codeclimate.yml [\\#56](https://github.com/feathersjs/socketio/pull/56) ([larkinscott](https://github.com/larkinscott))\n- socket.io@1.7.1 breaks build 🚨 [\\#54](https://github.com/feathersjs/socketio/pull/54) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-memory to version 1.0.0 🚀 [\\#50](https://github.com/feathersjs/socketio/pull/50) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-commons to version 0.8.0 🚀 [\\#49](https://github.com/feathersjs/socketio/pull/49) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.4.2](https://github.com/feathersjs/socketio/tree/v1.4.2) (2016-11-02)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.4.1...v1.4.2)\n\n**Closed issues:**\n\n- Upgrade to socket.io 1.4 [\\#39](https://github.com/feathersjs/socketio/issues/39)\n- Disable/restrict failed request queue? [\\#38](https://github.com/feathersjs/socketio/issues/38)\n- Uncaught \\(in promise\\) Error: Timeout of 5000ms exceeded calling sites::find\\(…\\) [\\#36](https://github.com/feathersjs/socketio/issues/36)\n- Regarding plain websockets [\\#34](https://github.com/feathersjs/socketio/issues/34)\n- Clean way to subscribe to a filtered set of events [\\#32](https://github.com/feathersjs/socketio/issues/32)\n- \"Can't find variable: Reflect\" on bad requests/authentication token missing; react-native [\\#31](https://github.com/feathersjs/socketio/issues/31)\n- Client should convert error objects to feathers-errors [\\#30](https://github.com/feathersjs/socketio/issues/30)\n\n**Merged pull requests:**\n\n- 👻😱 Node.js 0.10 is unmaintained 😱👻 [\\#48](https://github.com/feathersjs/socketio/pull/48) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Swapping rm to rifraf and using relative path to \\_mocha for windows support [\\#47](https://github.com/feathersjs/socketio/pull/47) ([corymsmith](https://github.com/corymsmith))\n- jshint —\\> semistandard [\\#46](https://github.com/feathersjs/socketio/pull/46) ([corymsmith](https://github.com/corymsmith))\n- update feathers dev dependency [\\#45](https://github.com/feathersjs/socketio/pull/45) ([ekryski](https://github.com/ekryski))\n- adding code coverage [\\#44](https://github.com/feathersjs/socketio/pull/44) ([ekryski](https://github.com/ekryski))\n- socket.io-client@1.5.0 breaks build 🚨 [\\#43](https://github.com/feathersjs/socketio/pull/43) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-memory to version 0.8.0 🚀 [\\#35](https://github.com/feathersjs/socketio/pull/35) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update mocha to version 3.0.0 🚀 [\\#33](https://github.com/feathersjs/socketio/pull/33) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.4.1](https://github.com/feathersjs/socketio/tree/v1.4.1) (2016-05-23)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.4.0...v1.4.1)\n\n**Closed issues:**\n\n- README.md broken link to provider documentation [\\#23](https://github.com/feathersjs/socketio/issues/23)\n- Insecure Defaults Allow MITM Over TLS [\\#22](https://github.com/feathersjs/socketio/issues/22)\n\n**Merged pull requests:**\n\n- mocha@2.5.0 breaks build 🚨 [\\#28](https://github.com/feathersjs/socketio/pull/28) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update feathers-socket-commons to version 2.0.0 🚀 [\\#27](https://github.com/feathersjs/socketio/pull/27) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update babel-plugin-add-module-exports to version 0.2.0 🚀 [\\#26](https://github.com/feathersjs/socketio/pull/26) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- fix link in README.md to feathers-socketio API docs [\\#24](https://github.com/feathersjs/socketio/pull/24) ([ElliotPsyIT](https://github.com/ElliotPsyIT))\n\n## [v1.4.0](https://github.com/feathersjs/socketio/tree/v1.4.0) (2016-04-28)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.3.4...v1.4.0)\n\n**Merged pull requests:**\n\n- Client timeout [\\#21](https://github.com/feathersjs/socketio/pull/21) ([daffl](https://github.com/daffl))\n- Update feathers-socket-commons to version 1.0.0 🚀 [\\#20](https://github.com/feathersjs/socketio/pull/20) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- nsp@2.3.2 breaks build 🚨 [\\#18](https://github.com/feathersjs/socketio/pull/18) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- More tests for error cases [\\#16](https://github.com/feathersjs/socketio/pull/16) ([daffl](https://github.com/daffl))\n\n## [v1.3.4](https://github.com/feathersjs/socketio/tree/v1.3.4) (2016-04-16)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.3.3...v1.3.4)\n\n**Merged pull requests:**\n\n- Increase the default number of maximum event listeners [\\#15](https://github.com/feathersjs/socketio/pull/15) ([daffl](https://github.com/daffl))\n- Update feathers-memory to version 0.7.0 🚀 [\\#14](https://github.com/feathersjs/socketio/pull/14) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.3.3](https://github.com/feathersjs/socketio/tree/v1.3.3) (2016-02-18)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.3.2...v1.3.3)\n\n**Closed issues:**\n\n- Needs possibility to pass options to io.listen\\(\\) [\\#12](https://github.com/feathersjs/socketio/issues/12)\n\n**Merged pull requests:**\n\n- Allow to pass Socket.io options [\\#13](https://github.com/feathersjs/socketio/pull/13) ([daffl](https://github.com/daffl))\n\n## [v1.3.2](https://github.com/feathersjs/socketio/tree/v1.3.2) (2016-02-11)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.3.1...v1.3.2)\n\n**Merged pull requests:**\n\n- Allow to instantiate a client instance [\\#11](https://github.com/feathersjs/socketio/pull/11) ([daffl](https://github.com/daffl))\n\n## [v1.3.1](https://github.com/feathersjs/socketio/tree/v1.3.1) (2016-02-09)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.3.0...v1.3.1)\n\n## [v1.3.0](https://github.com/feathersjs/socketio/tree/v1.3.0) (2016-02-09)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.2.0...v1.3.0)\n\n**Merged pull requests:**\n\n- Update feathers-memory to version 0.6.0 🚀 [\\#8](https://github.com/feathersjs/socketio/pull/8) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Update lodash to version 4.0.1 🚀 [\\#7](https://github.com/feathersjs/socketio/pull/7) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- Adding nsp check [\\#6](https://github.com/feathersjs/socketio/pull/6) ([marshallswain](https://github.com/marshallswain))\n\n## [v1.2.0](https://github.com/feathersjs/socketio/tree/v1.2.0) (2016-01-21)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.1.0...v1.2.0)\n\n**Closed issues:**\n\n- Better event filtering [\\#2](https://github.com/feathersjs/socketio/issues/2)\n\n**Merged pull requests:**\n\n- Refactoring to use feathers-socket-commons that support event filtering [\\#5](https://github.com/feathersjs/socketio/pull/5) ([daffl](https://github.com/daffl))\n- Fixing .npmignore entries [\\#3](https://github.com/feathersjs/socketio/pull/3) ([corymsmith](https://github.com/corymsmith))\n\n## [v1.1.0](https://github.com/feathersjs/socketio/tree/v1.1.0) (2016-01-10)\n\n[Full Changelog](https://github.com/feathersjs/socketio/compare/v1.0.0...v1.1.0)\n\n**Merged pull requests:**\n\n- feathers-socketio/client service and tests [\\#1](https://github.com/feathersjs/socketio/pull/1) ([daffl](https://github.com/daffl))\n\n## [v1.0.0](https://github.com/feathersjs/socketio/tree/v1.0.0) (2016-01-03)\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/socketio/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/socketio/README.md",
    "content": "# @feathersjs/socketio\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/socketio.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/socketio)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> The Feathers Socket.io real-time API provider\n\n## Installation\n\n```\nnpm install @feathersjs/socketio --save\n```\n\n## Documentation\n\nRefer to the [Feathers SocketIO API documentation](https://feathersjs.com/api/socketio.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/socketio/package.json",
    "content": "{\n  \"name\": \"@feathersjs/socketio\",\n  \"description\": \"The Feathers Socket.io real-time API provider\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/socketio\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@feathersjs/transport-commons\": \"^5.0.42\",\n    \"socket.io\": \"^4.8.3\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/express\": \"^5.0.42\",\n    \"@feathersjs/memory\": \"^5.0.42\",\n    \"@feathersjs/tests\": \"^5.0.42\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"lodash\": \"^4.17.23\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"socket.io-client\": \"^4.8.3\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/socketio/src/index.ts",
    "content": "import http from 'http'\nimport { Server, ServerOptions } from 'socket.io'\nimport { createDebug } from '@feathersjs/commons'\nimport { Application, RealTimeConnection } from '@feathersjs/feathers'\nimport { socket } from '@feathersjs/transport-commons'\n\nimport { disconnect, params, authentication, FeathersSocket } from './middleware'\n\nconst debug = createDebug('@feathersjs/socketio')\n\ndeclare module '@feathersjs/feathers/lib/declarations' {\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  interface Application<Services, Settings> {\n    io: any\n    listen(options: any): Promise<http.Server>\n  }\n}\n\nfunction configureSocketio(callback?: (io: Server) => void): (app: Application) => void\nfunction configureSocketio(\n  options: number | Partial<ServerOptions>,\n  callback?: (io: Server) => void\n): (app: Application) => void\nfunction configureSocketio(\n  port: number,\n  options?: Partial<ServerOptions>,\n  callback?: (io: Server) => void\n): (app: Application) => void\nfunction configureSocketio(port?: any, options?: any, config?: any) {\n  if (typeof port !== 'number') {\n    config = options\n    options = port\n    port = null\n  }\n\n  if (typeof options !== 'object') {\n    config = options\n    options = {}\n  }\n\n  return (app: Application) => {\n    // Function that gets the connection\n    const getParams = (socket: FeathersSocket) => socket.feathers\n    // A mapping from connection to socket instance\n    const socketMap = new WeakMap<RealTimeConnection, FeathersSocket>()\n    // Promise that resolves with the Socket.io `io` instance\n    // when `setup` has been called (with a server)\n    const done = new Promise((resolve) => {\n      const { listen, setup } = app as any\n\n      Object.assign(app, {\n        async listen(this: any, ...args: any[]) {\n          if (typeof listen === 'function') {\n            // If `listen` already exists\n            // usually the case when the app has been expressified\n            return listen.call(this, ...args)\n          }\n\n          const server = http.createServer()\n\n          await this.setup(server)\n\n          return server.listen(...args)\n        },\n\n        async setup(this: any, server: http.Server, ...rest: any[]) {\n          if (!this.io) {\n            const io = (this.io = new Server(port || server, options))\n\n            io.use(disconnect(app, getParams, socketMap))\n            io.use(params(app, socketMap))\n            io.use(authentication(app, getParams))\n\n            // In Feathers it is easy to hit the standard Node warning limit\n            // of event listeners (e.g. by registering 10 services).\n            // So we set it to a higher number. 64 should be enough for everyone.\n            io.sockets.setMaxListeners(64)\n          }\n\n          if (typeof config === 'function') {\n            debug('Calling SocketIO configuration function')\n            config.call(this, this.io)\n          }\n\n          resolve(this.io)\n\n          return setup.call(this, server, ...rest)\n        }\n      })\n    })\n\n    app.configure(\n      socket({\n        done,\n        socketMap,\n        getParams,\n        emit: 'emit'\n      })\n    )\n  }\n}\n\nexport = configureSocketio\n"
  },
  {
    "path": "packages/socketio/src/middleware.ts",
    "content": "import { Application, Params, RealTimeConnection } from '@feathersjs/feathers'\nimport { createDebug } from '@feathersjs/commons'\nimport { Socket } from 'socket.io'\n\nconst debug = createDebug('@feathersjs/socketio/middleware')\n\nexport type ParamsGetter = (socket: Socket) => any\nexport type NextFunction = (err?: any) => void\nexport interface FeathersSocket extends Socket {\n  feathers?: Params & { [key: string]: any }\n}\n\nexport const disconnect = (\n  app: Application,\n  getParams: ParamsGetter,\n  socketMap: WeakMap<RealTimeConnection, FeathersSocket>\n) => {\n  app.on('disconnect', (connection: RealTimeConnection) => {\n    const socket = socketMap.get(connection)\n    if (socket && socket.connected) {\n      socket.disconnect()\n    }\n  })\n\n  return (socket: FeathersSocket, next: NextFunction) => {\n    socket.on('disconnect', () => app.emit('disconnect', getParams(socket)))\n    next()\n  }\n}\n\nexport const params =\n  (_app: Application, socketMap: WeakMap<RealTimeConnection, FeathersSocket>) =>\n  (socket: FeathersSocket, next: NextFunction) => {\n    socket.feathers = {\n      provider: 'socketio',\n      headers: socket.handshake.headers\n    }\n\n    socketMap.set(socket.feathers, socket)\n\n    next()\n  }\n\nexport const authentication =\n  (app: Application, getParams: ParamsGetter, settings: any = {}) =>\n  (socket: FeathersSocket, next: NextFunction) => {\n    const service = (app as any).defaultAuthentication\n      ? (app as any).defaultAuthentication(settings.service)\n      : null\n\n    if (service === null) {\n      return next()\n    }\n\n    const config = service.configuration\n    const authStrategies = config.parseStrategies || config.authStrategies || []\n\n    if (authStrategies.length === 0) {\n      return next()\n    }\n\n    service\n      .parse(socket.handshake, null, ...authStrategies)\n      .then(async (authentication: any) => {\n        if (authentication) {\n          debug('Parsed authentication from HTTP header', authentication)\n          socket.feathers.authentication = authentication\n          await service.create(authentication, {\n            provider: 'socketio',\n            connection: getParams(socket)\n          })\n        }\n\n        next()\n      })\n      .catch(next)\n  }\n"
  },
  {
    "path": "packages/socketio/test/events.ts",
    "content": "import { strict as assert } from 'assert'\nimport { io, Socket } from 'socket.io-client'\nimport { verify } from '@feathersjs/tests'\nimport { RealTimeConnection } from '@feathersjs/feathers'\n\nexport default (name: string, options: any) => {\n  const call = (method: string, ...args: any[]) => {\n    return new Promise((resolve, reject) => {\n      const { socket } = options\n      const emitArgs = [method, name].concat(args)\n\n      socket.emit(...emitArgs, (error: any, result: any) => (error ? reject(error) : resolve(result)))\n    })\n  }\n\n  const verifyEvent = (done: (err?: any) => void, callback: (data: any) => void) => {\n    return function (data: any) {\n      try {\n        callback(data)\n        done()\n      } catch (error: any) {\n        done(error)\n      }\n    }\n  }\n\n  describe('Basic service events', () => {\n    let socket: Socket\n    let connection: RealTimeConnection\n\n    before((done) => {\n      options.app.once('connection', (conn: RealTimeConnection) => {\n        connection = conn\n\n        options.app.channel('default').join(connection)\n        options.app.publish(() => options.app.channel('default'))\n        done()\n      })\n      socket = io('http://localhost:7886')\n    })\n\n    after((done) => {\n      socket.once('disconnect', () => done())\n      socket.disconnect()\n    })\n\n    it(`${name} created`, (done) => {\n      const original = {\n        name: 'created event'\n      }\n\n      socket.once(\n        `${name} created`,\n        verifyEvent(done, (data) => verify.create(original, data))\n      )\n\n      call('create', original)\n    })\n\n    it(`${name} updated`, (done) => {\n      const original = {\n        name: 'updated event'\n      }\n\n      socket.once(\n        `${name} updated`,\n        verifyEvent(done, (data: any) => verify.update(10, original, data))\n      )\n\n      call('update', 10, original)\n    })\n\n    it(`${name} patched`, (done) => {\n      const original = {\n        name: 'patched event'\n      }\n\n      socket.once(\n        `${name} patched`,\n        verifyEvent(done, (data: any) => verify.patch(12, original, data))\n      )\n\n      call('patch', 12, original)\n    })\n\n    it(`${name} removed`, (done) => {\n      socket.once(\n        `${name} removed`,\n        verifyEvent(done, (data: any) => verify.remove(333, data))\n      )\n\n      call('remove', 333)\n    })\n\n    it(`${name} custom events`, (done) => {\n      const service = options.app.service(name)\n      const original = {\n        name: 'created event'\n      }\n\n      socket.once(\n        `${name} log`,\n        verifyEvent(done, (data: any) => {\n          assert.deepStrictEqual(data, {\n            message: 'Custom log event',\n            data: original\n          })\n        })\n      )\n\n      service.emit('log', {\n        data: original,\n        message: 'Custom log event'\n      })\n    })\n  })\n\n  describe('Event channels', () => {\n    const eventName = `${name} created`\n\n    let connections: RealTimeConnection[]\n    let sockets: any[]\n\n    before((done) => {\n      let counter = 0\n      const handler = (connection: RealTimeConnection) => {\n        counter++\n\n        options.app.channel(connection.channel).join(connection)\n\n        connections.push(connection)\n\n        if (counter === 3) {\n          done()\n          options.app.removeListener('connection', handler)\n        }\n      }\n\n      connections = []\n      sockets = []\n\n      options.app.on('connection', handler)\n\n      sockets.push(\n        io('http://localhost:7886', {\n          query: { channel: 'first' }\n        }),\n\n        io('http://localhost:7886', {\n          query: { channel: 'second' }\n        }),\n\n        io('http://localhost:7886', {\n          query: { channel: 'second' }\n        })\n      )\n    })\n\n    after(() => {\n      sockets.forEach((socket) => socket.disconnect())\n    })\n\n    it(`filters '${eventName}' event for a single channel`, (done) => {\n      const service = options.app.service(name)\n      const [socket, otherSocket] = sockets\n      const onError = () => {\n        done(new Error('Should not get this event'))\n      }\n\n      service.publish('created', (data: any) => options.app.channel(data.room))\n\n      socket.once(eventName, (data: any) => {\n        assert.strictEqual(data.room, 'first')\n        otherSocket.removeEventListener(eventName, onError)\n        done()\n      })\n\n      otherSocket.once(eventName, onError)\n\n      service.create({\n        text: 'Event dispatching test',\n        room: 'first'\n      })\n    })\n\n    it(`filters '${name} created' event for a channel with multiple connections`, (done) => {\n      let counter = 0\n\n      const service = options.app.service(name)\n      const [otherSocket, socketOne, socketTwo] = sockets\n      const onError = () => {\n        done(new Error('Should not get this event'))\n      }\n      const onEvent = (data: any) => {\n        counter++\n        assert.strictEqual(data.room, 'second')\n\n        if (++counter === 2) {\n          otherSocket.removeEventListener(eventName, onError)\n          done()\n        }\n      }\n\n      service.publish('created', (data: any) => options.app.channel(data.room))\n\n      socketOne.once(eventName, onEvent)\n      socketTwo.once(eventName, onEvent)\n      otherSocket.once(eventName, onError)\n\n      service.create({\n        text: 'Event dispatching test',\n        room: 'second'\n      })\n    })\n  })\n}\n"
  },
  {
    "path": "packages/socketio/test/index.test.ts",
    "content": "import { strict as assert } from 'assert'\nimport {\n  feathers,\n  Application,\n  HookContext,\n  NullableId,\n  Params,\n  ApplicationHookContext\n} from '@feathersjs/feathers'\nimport express from '@feathersjs/express'\nimport { Request, Response } from 'express'\nimport omit from 'lodash/omit'\nimport extend from 'lodash/extend'\nimport { io } from 'socket.io-client'\nimport axios from 'axios'\nimport { Server } from 'http'\nimport { Service } from '@feathersjs/tests'\nimport { Socket } from 'socket.io-client'\n\nimport methodTests from './methods'\nimport eventTests from './events'\nimport socketio from '../src'\nimport { FeathersSocket, NextFunction } from '../src/middleware.js'\n\nclass VerifierService {\n  async find(params: Params) {\n    return { params }\n  }\n\n  async create(data: any, params: Params) {\n    return { data, params }\n  }\n\n  async update(id: NullableId, data: any, params: Params) {\n    return { id, data, params }\n  }\n}\n\ndescribe('@feathersjs/socketio', () => {\n  let app: Application\n  let server: Server\n  let socket: Socket\n\n  const socketParams: any = {\n    user: { name: 'David' },\n    provider: 'socketio'\n  }\n  const options = {\n    get app() {\n      return app\n    },\n\n    get socket() {\n      return socket\n    }\n  }\n\n  before((done) => {\n    const errorHook = (hook: HookContext) => {\n      if (hook.params.query.hookError) {\n        throw new Error(`Error from ${hook.method}, ${hook.type} hook`)\n      }\n    }\n\n    app = feathers()\n      .configure(\n        socketio((io) => {\n          io.use(function (socket: FeathersSocket, next: NextFunction) {\n            socket.feathers!.user = { name: 'David' }\n            socketParams.headers = socket.feathers!.headers\n\n            const { channel } = socket.handshake.query as any\n\n            if (channel) {\n              socket.feathers!.channel = channel\n            }\n\n            next()\n          })\n        })\n      )\n      .use('/todo', new Service())\n      .use('/verify', new VerifierService())\n\n    app.service('todo').hooks({\n      before: {\n        get: errorHook\n      }\n    })\n\n    app.hooks({\n      setup: [\n        async (context: ApplicationHookContext, next: NextFunction) => {\n          assert.notStrictEqual(context.app, undefined)\n          await next()\n        }\n      ]\n    })\n\n    app\n      .listen(7886)\n      .then((srv) => {\n        server = srv\n        server.once('listening', () => {\n          app.use('/tasks', new Service())\n          app.service('tasks').hooks({\n            before: {\n              get: errorHook\n            }\n          })\n        })\n      })\n      .catch(done)\n\n    socket = io('http://localhost:7886')\n    socket.on('connect', () => done())\n  })\n\n  after((done) => {\n    socket.disconnect()\n    server.close(done)\n  })\n\n  it('runs io before setup (#131)', (done) => {\n    let counter = 0\n    const app = feathers().configure(\n      socketio(() => {\n        assert.strictEqual(counter, 0)\n        counter++\n      })\n    )\n\n    app.listen(8887).then((srv) => {\n      srv.on('listening', () => srv.close(done))\n    })\n  })\n\n  it('can set MaxListeners', (done) => {\n    const app = feathers().configure(socketio((io) => io.sockets.setMaxListeners(100)))\n\n    app.listen(8987).then((srv) => {\n      srv.on('listening', () => {\n        assert.strictEqual(app.io.sockets.getMaxListeners(), 100)\n        srv.close(done)\n      })\n    })\n  })\n\n  it('expressified app works', async () => {\n    const data = { message: 'Hello world' }\n    const app = express(feathers())\n      .configure(socketio())\n      .use('/test', (_req: Request, res: Response) => res.json(data))\n\n    const srv = await app.listen(8992)\n    const response = await axios({\n      url: 'http://localhost:8992/socket.io/socket.io.js'\n    })\n\n    assert.strictEqual(response.status, 200)\n\n    const res = await axios({\n      url: 'http://localhost:8992/test'\n    })\n\n    assert.deepStrictEqual(res.data, data)\n\n    await new Promise((resolve) => srv.close(() => resolve(srv)))\n  })\n\n  it('can set options (#12)', (done) => {\n    const application = feathers().configure(\n      socketio(\n        {\n          path: '/test/'\n        },\n        (ioInstance) => assert.ok(ioInstance)\n      )\n    )\n\n    application.listen(8987).then((srv) => {\n      srv.on('listening', async () => {\n        const { status } = await axios('http://localhost:8987/test/socket.io.js')\n\n        assert.strictEqual(status, 200)\n        srv.close(done)\n      })\n    })\n  })\n\n  it('passes handshake as service parameters', (done) => {\n    socket.emit('create', 'verify', {}, (error: any, data: any) => {\n      assert.ok(!error)\n      assert.deepStrictEqual(\n        omit(data.params, 'query', 'route', 'connection'),\n        socketParams,\n        'Passed handshake parameters'\n      )\n\n      socket.emit(\n        'update',\n        'verify',\n        1,\n        {},\n        {\n          test: 'param'\n        },\n        (error: any, data: any) => {\n          assert.ok(!error)\n          assert.deepStrictEqual(\n            data.params,\n            extend(\n              {\n                route: {},\n                connection: socketParams,\n                query: {\n                  test: 'param'\n                }\n              },\n              socketParams\n            ),\n            'Passed handshake parameters as query'\n          )\n          done()\n        }\n      )\n    })\n  })\n\n  it('connection and disconnect events (#1243, #1238)', (done) => {\n    const mySocket = io('http://localhost:7886?channel=dctest')\n\n    app.once('connection', (connection) => {\n      assert.strictEqual(connection.channel, 'dctest')\n      app.once('disconnect', (disconnection) => {\n        assert.strictEqual(disconnection.channel, 'dctest')\n        done()\n      })\n      setTimeout(() => mySocket.close(), 100)\n    })\n\n    assert.ok(mySocket)\n  })\n\n  it('app `disconnect` event disconnects socket (#2754)', (done) => {\n    const mySocket = io('http://localhost:7886?channel=dctest')\n\n    app.once('connection', (connection) => {\n      assert.strictEqual(connection.channel, 'dctest')\n      mySocket.once('disconnect', () => done())\n      app.emit('disconnect', connection)\n    })\n\n    assert.ok(mySocket)\n  })\n\n  it('missing parameters in socket call works (#88)', (done) => {\n    socket.emit('find', 'verify', (error: any, data: any) => {\n      assert.ok(!error)\n      assert.deepStrictEqual(\n        omit(data.params, 'query', 'route', 'connection'),\n        socketParams,\n        'Handshake parameters passed on proper position'\n      )\n      done()\n    })\n  })\n\n  describe('Service method calls', () => {\n    describe(\"('method', 'service')  event format\", () => {\n      describe('Service', () => methodTests('todo', options))\n      describe('Dynamic Service', () => methodTests('todo', options))\n    })\n  })\n\n  describe('Service events', () => {\n    describe('Service', () => eventTests('todo', options))\n    describe('Dynamic Service', () => eventTests('tasks', options))\n  })\n})\n"
  },
  {
    "path": "packages/socketio/test/methods.ts",
    "content": "import { strict as assert } from 'assert'\nimport { verify } from '@feathersjs/tests'\n\nexport default (name: string, options: any) => {\n  const call = (method: string, ...args: any[]) =>\n    new Promise((resolve, reject) => {\n      const { socket } = options\n      const prefix = [method, name]\n      const emitArgs = prefix.concat(args)\n\n      socket.emit(...emitArgs, (error: any, result: any) => (error ? reject(error) : resolve(result)))\n    })\n\n  it('invalid arguments cause an error', async () => {\n    await assert.rejects(() => call('find', 1, {}), {\n      message: \"Too many arguments for 'find' method\"\n    })\n  })\n\n  it('.find', () => async () => {\n    await call('find', {}).then((data) => verify.find(data))\n  })\n\n  it('.get', () => async () => {\n    await call('get', 'laundry').then((data) => verify.get('laundry', data))\n  })\n\n  it('.get with error', () => async () => {\n    try {\n      await call('get', 'laundry', { error: true })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.message, 'Something for laundry went wrong')\n    }\n  })\n\n  it('.get with runtime error', () => async () => {\n    try {\n      await call('get', 'laundry', { runtimeError: true })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.message, 'thingThatDoesNotExist is not defined')\n    }\n  })\n\n  it('.get with error in hook', () => async () => {\n    try {\n      await call('get', 'laundry', { hookError: true })\n      assert.fail('Should never get here')\n    } catch (error: any) {\n      assert.strictEqual(error.message, 'Error from get, before hook')\n    }\n  })\n\n  it('.create', async () => {\n    const original = {\n      name: 'creating'\n    }\n\n    const data = await call('create', original, {})\n\n    verify.create(original, data)\n  })\n\n  it('.create without parameters', async () => {\n    const original = {\n      name: 'creating again'\n    }\n\n    const data = await call('create', original)\n\n    verify.create(original, data)\n  })\n\n  it('.update', async () => {\n    const original = {\n      name: 'updating'\n    }\n\n    const data = await call('update', 23, original, {})\n\n    verify.update(23, original, data)\n  })\n\n  it('.update many', async () => {\n    const original = {\n      name: 'updating',\n      many: true\n    }\n\n    const data = await call('update', null, original)\n\n    verify.update(null, original, data)\n  })\n\n  it('.patch', async () => {\n    const original = {\n      name: 'patching'\n    }\n\n    const data = await call('patch', 25, original)\n\n    verify.patch(25, original, data)\n  })\n\n  it('.patch many', async () => {\n    const original = {\n      name: 'patching',\n      many: true\n    }\n\n    const data = await call('patch', null, original)\n\n    verify.patch(null, original, data)\n  })\n\n  it('.remove', () => async () => {\n    const data = await call('remove', 11)\n\n    verify.remove(11, data)\n  })\n\n  it('.remove many', async () => {\n    const data = await call('remove', null)\n\n    verify.remove(null, data)\n  })\n}\n"
  },
  {
    "path": "packages/socketio/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/socketio-client/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.2](https://github.com/feathersjs/feathers/compare/v5.0.1...v5.0.2) (2023-03-23)\n\n### Bug Fixes\n\n- **socketio-client:** Move core dependency to the right spot ([#3117](https://github.com/feathersjs/feathers/issues/3117)) ([6cd66f1](https://github.com/feathersjs/feathers/commit/6cd66f13e4e668defb57074413846550b147a51d))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n### Bug Fixes\n\n- **socketio-client:** Make Socket.io client event target compatible ([#2686](https://github.com/feathersjs/feathers/issues/2686)) ([716c49a](https://github.com/feathersjs/feathers/commit/716c49a270e4be5e5276192092c292f72ffcfa19))\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n### Features\n\n- **cli:** Add typed client to a generated app ([#2669](https://github.com/feathersjs/feathers/issues/2669)) ([5b801b5](https://github.com/feathersjs/feathers/commit/5b801b5017ddc3eaa95622b539f51d605916bc86))\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n### Features\n\n- **client:** Improve client side custom method support ([#2654](https://github.com/feathersjs/feathers/issues/2654)) ([c138acf](https://github.com/feathersjs/feathers/commit/c138acf50affbe6b66177d084d3c7a3e9220f09f))\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Features\n\n- **typescript:** Improve adapter typings ([#2605](https://github.com/feathersjs/feathers/issues/2605)) ([3b2ca0a](https://github.com/feathersjs/feathers/commit/3b2ca0a6a8e03e8390272c4d7e930b4bffdaacf5))\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Features\n\n- **adapter-commons:** Add support for params.adapter option and move memory adapter to @feathersjs/memory ([#2367](https://github.com/feathersjs/feathers/issues/2367)) ([a43e7da](https://github.com/feathersjs/feathers/commit/a43e7da22b6b981a96d1321736ea9a0cb924fb4f))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n### Bug Fixes\n\n- **dependencies:** Fix transport-commons dependency and update other dependencies ([#2284](https://github.com/feathersjs/feathers/issues/2284)) ([05b03b2](https://github.com/feathersjs/feathers/commit/05b03b27b40604d956047e3021d8053c3a137616))\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n- **socketio-client:** Fix client transport-commons reference ([#2164](https://github.com/feathersjs/feathers/issues/2164)) ([3a42c54](https://github.com/feathersjs/feathers/commit/3a42c544058456b19c7e21827226541bfa6ad621))\n\n### Features\n\n- **core:** Public custom service methods ([#2270](https://github.com/feathersjs/feathers/issues/2270)) ([e65abfb](https://github.com/feathersjs/feathers/commit/e65abfb5388df6c19a11c565cf1076a29f32668d))\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n- **transport-commons:** New built-in high performance radix router ([#2177](https://github.com/feathersjs/feathers/issues/2177)) ([6d18065](https://github.com/feathersjs/feathers/commit/6d180651b4eb40289ecea3df3575f207aa6c5d1f))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n### Bug Fixes\n\n- **socketio-client:** Throw an error and show a warning if someone tries to use socket.io-client v3 ([#2135](https://github.com/feathersjs/feathers/issues/2135)) ([cc3521c](https://github.com/feathersjs/feathers/commit/cc3521c935a1cbd690e29b7057998e3898f282db))\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.5.6](https://github.com/feathersjs/feathers/compare/v4.5.5...v4.5.6) (2020-07-12)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.5.4](https://github.com/feathersjs/feathers/compare/v4.5.3...v4.5.4) (2020-04-29)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.3.5](https://github.com/feathersjs/feathers/compare/v4.3.4...v4.3.5) (2019-10-07)\n\n### Bug Fixes\n\n- Change this reference in client libraries to explicitly passed app ([#1597](https://github.com/feathersjs/feathers/issues/1597)) ([4e4d10a](https://github.com/feathersjs/feathers/commit/4e4d10a))\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n### Bug Fixes\n\n- Use `export =` in TypeScript definitions ([#1285](https://github.com/feathersjs/feathers/issues/1285)) ([12d0f4b](https://github.com/feathersjs/feathers/commit/12d0f4b))\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n\n### Features\n\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Allow registering a service at the root level ([#1115](https://github.com/feathersjs/feathers/issues/1115)) ([c73d322](https://github.com/feathersjs/feathers/commit/c73d322))\n- Authentication v3 core server implementation ([#1205](https://github.com/feathersjs/feathers/issues/1205)) ([1bd7591](https://github.com/feathersjs/feathers/commit/1bd7591))\n\n## [1.2.1](https://github.com/feathersjs/feathers/compare/@feathersjs/socketio-client@1.2.0...@feathersjs/socketio-client@1.2.1) (2019-01-02)\n\n### Bug Fixes\n\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n\n<a name=\"1.2.0\"></a>\n\n# [1.2.0](https://github.com/feathersjs/feathers/compare/@feathersjs/socketio-client@1.1.5...@feathersjs/socketio-client@1.2.0) (2018-12-16)\n\n### Features\n\n- Allow registering a service at the root level ([#1115](https://github.com/feathersjs/feathers/issues/1115)) ([c73d322](https://github.com/feathersjs/feathers/commit/c73d322))\n\n<a name=\"1.1.5\"></a>\n\n## [1.1.5](https://github.com/feathersjs/feathers/compare/@feathersjs/socketio-client@1.1.4...@feathersjs/socketio-client@1.1.5) (2018-10-25)\n\n### Bug Fixes\n\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n\n<a name=\"1.1.4\"></a>\n\n## [1.1.4](https://github.com/feathersjs/feathers/compare/@feathersjs/socketio-client@1.1.3...@feathersjs/socketio-client@1.1.4) (2018-09-21)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n<a name=\"1.1.3\"></a>\n\n## [1.1.3](https://github.com/feathersjs/feathers/compare/@feathersjs/socketio-client@1.1.2...@feathersjs/socketio-client@1.1.3) (2018-09-17)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n<a name=\"1.1.2\"></a>\n\n## [1.1.2](https://github.com/feathersjs/feathers/compare/@feathersjs/socketio-client@1.1.1...@feathersjs/socketio-client@1.1.2) (2018-09-02)\n\n**Note:** Version bump only for package @feathersjs/socketio-client\n\n<a name=\"1.1.1\"></a>\n\n## 1.1.1\n\n- Migrate to Monorepo ([feathers#462](https://github.com/feathersjs/feathers/issues/462))\n\n## [v1.1.0](https://github.com/feathersjs/socketio-client/tree/v1.1.0) (2018-02-09)\n\n[Full Changelog](https://github.com/feathersjs/socketio-client/compare/v1.0.3...v1.1.0)\n\n**Closed issues:**\n\n- Non compatible with SSR [\\#11](https://github.com/feathersjs/socketio-client/issues/11)\n- Timeout error, why? [\\#9](https://github.com/feathersjs/socketio-client/issues/9)\n\n**Merged pull requests:**\n\n- Update @feathersjs/transport-commons to the latest version 🚀 [\\#12](https://github.com/feathersjs/socketio-client/pull/12) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.3](https://github.com/feathersjs/socketio-client/tree/v1.0.3) (2018-02-05)\n\n[Full Changelog](https://github.com/feathersjs/socketio-client/compare/v1.0.2...v1.0.3)\n\n**Merged pull requests:**\n\n- Move to use transport-commons [\\#10](https://github.com/feathersjs/socketio-client/pull/10) ([daffl](https://github.com/daffl))\n- Update mocha to the latest version 🚀 [\\#8](https://github.com/feathersjs/socketio-client/pull/8) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.2](https://github.com/feathersjs/socketio-client/tree/v1.0.2) (2018-01-03)\n\n[Full Changelog](https://github.com/feathersjs/socketio-client/compare/v1.0.1...v1.0.2)\n\n**Merged pull requests:**\n\n- Update documentation to correspond with latest release [\\#7](https://github.com/feathersjs/socketio-client/pull/7) ([daffl](https://github.com/daffl))\n- Update semistandard to the latest version 🚀 [\\#6](https://github.com/feathersjs/socketio-client/pull/6) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update feathers-memory to the latest version 🚀 [\\#5](https://github.com/feathersjs/socketio-client/pull/5) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.1](https://github.com/feathersjs/socketio-client/tree/v1.0.1) (2017-11-16)\n\n[Full Changelog](https://github.com/feathersjs/socketio-client/compare/v1.0.0...v1.0.1)\n\n**Merged pull requests:**\n\n- Add default export for better ES module \\(TypeScript\\) compatibility [\\#4](https://github.com/feathersjs/socketio-client/pull/4) ([daffl](https://github.com/daffl))\n\n## [v1.0.0](https://github.com/feathersjs/socketio-client/tree/v1.0.0) (2017-11-01)\n\n[Full Changelog](https://github.com/feathersjs/socketio-client/compare/v1.0.0-pre.3...v1.0.0)\n\n**Merged pull requests:**\n\n- Update dependencies for release [\\#3](https://github.com/feathersjs/socketio-client/pull/3) ([daffl](https://github.com/daffl))\n\n## [v1.0.0-pre.3](https://github.com/feathersjs/socketio-client/tree/v1.0.0-pre.3) (2017-10-23)\n\n[Full Changelog](https://github.com/feathersjs/socketio-client/compare/v1.0.0-pre.2...v1.0.0-pre.3)\n\n**Merged pull requests:**\n\n- Use scoped npm packages [\\#2](https://github.com/feathersjs/socketio-client/pull/2) ([daffl](https://github.com/daffl))\n\n## [v1.0.0-pre.2](https://github.com/feathersjs/socketio-client/tree/v1.0.0-pre.2) (2017-10-19)\n\n[Full Changelog](https://github.com/feathersjs/socketio-client/compare/v1.0.0-pre.1...v1.0.0-pre.2)\n\n**Merged pull requests:**\n\n- Update dependencies to enable Greenkeeper 🌴 [\\#1](https://github.com/feathersjs/socketio-client/pull/1) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v1.0.0-pre.1](https://github.com/feathersjs/socketio-client/tree/v1.0.0-pre.1) (2017-10-18)\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/socketio-client/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/socketio-client/README.md",
    "content": "# @feathersjs/socketio-client\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/socketio-client.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/socketio-client)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Client for Socket.io Feathers connections\n\n## Installation\n\n```\nnpm install @feathersjs/socketio-client --save\n```\n\n## Documentation\n\nRefer to the [Feathers SocketIO API documentation](https://feathersjs.com/api/client/socketio.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/socketio-client/package.json",
    "content": "{\n  \"name\": \"@feathersjs/socketio-client\",\n  \"description\": \"The client for Socket.io through feathers-socketio\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/socketio-client\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"mocha\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\",\n    \"test\": \"npm run mocha\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@feathersjs/transport-commons\": \"^5.0.42\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/memory\": \"^5.0.42\",\n    \"@feathersjs/socketio\": \"^5.0.42\",\n    \"@feathersjs/tests\": \"^5.0.42\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"socket.io-client\": \"^4.8.3\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/socketio-client/src/index.ts",
    "content": "import { Service, SocketService } from '@feathersjs/transport-commons/client'\nimport { Socket } from 'socket.io-client'\nimport {\n  Application,\n  TransportConnection,\n  defaultEventMap,\n  defaultServiceMethods\n} from '@feathersjs/feathers'\n\nexport { SocketService }\n\ndeclare module '@feathersjs/feathers/lib/declarations' {\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  interface FeathersApplication<Services, Settings> {\n    /**\n     * The Socket.io client instance. Usually does not need\n     * to be accessed directly.\n     */\n    io?: Socket\n  }\n}\n\nexport default function socketioClient<Services = any>(connection: Socket, options?: any) {\n  if (!connection) {\n    throw new Error('Socket.io connection needs to be provided')\n  }\n\n  const defaultService = function (this: any, name: string) {\n    const events = Object.values(defaultEventMap)\n    const settings = Object.assign({}, options, {\n      events,\n      name,\n      connection,\n      method: 'emit'\n    })\n\n    return new Service(settings) as any\n  }\n\n  const initialize = function (app: Application<Services>) {\n    if (app.io !== undefined) {\n      throw new Error('Only one default client provider can be configured')\n    }\n\n    app.io = connection as any\n    app.defaultService = defaultService\n    app.mixins.unshift((service, _location, options) => {\n      if (options && options.methods && service instanceof Service) {\n        const customMethods = options.methods.filter((name) => !defaultServiceMethods.includes(name))\n\n        service.methods(...customMethods)\n      }\n    })\n  }\n\n  initialize.Service = Service\n  initialize.service = defaultService\n\n  return initialize as TransportConnection<Services>\n}\n\nif (typeof module !== 'undefined') {\n  module.exports = Object.assign(socketioClient, module.exports)\n}\n"
  },
  {
    "path": "packages/socketio-client/test/index.test.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport { strict as assert } from 'assert'\nimport { Server } from 'http'\nimport { CustomMethod, feathers } from '@feathersjs/feathers'\nimport { io, Socket } from 'socket.io-client'\nimport { clientTests } from '@feathersjs/tests'\n\nimport { createServer } from './server'\nimport socketio, { SocketService } from '../src'\n\ntype ServiceTypes = {\n  '/': SocketService\n  todos: SocketService & {\n    customMethod: CustomMethod<{ message: string }>\n  }\n  [key: string]: any\n}\n\ndescribe('@feathersjs/socketio-client', () => {\n  const app = feathers<ServiceTypes>()\n\n  let socket: Socket\n  let server: Server\n\n  before(async () => {\n    server = await createServer().listen(9988)\n    socket = io('http://localhost:9988')\n\n    const connection = socketio<ServiceTypes>(socket)\n\n    app.configure(connection)\n    app.use('todos', connection.service('todos'), {\n      methods: ['find', 'get', 'create', 'patch', 'customMethod']\n    })\n  })\n\n  after((done) => {\n    socket.disconnect()\n    server.close(done)\n  })\n\n  it('throws an error with no connection', () => {\n    try {\n      // @ts-ignore\n      feathers().configure(socketio())\n      assert.ok(false)\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'Socket.io connection needs to be provided')\n    }\n  })\n\n  it('app has the io attribute', () => {\n    assert.ok((app as any).io)\n  })\n\n  it('throws an error when configured twice', () => {\n    try {\n      app.configure(socketio(socket))\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'Only one default client provider can be configured')\n    }\n  })\n\n  it('can initialize a client instance', async () => {\n    const init = socketio(socket)\n    const totoService = init.service('todos')\n\n    assert.ok(totoService instanceof init.Service, 'Returned service is a client')\n\n    const todos = await totoService.find()\n\n    assert.deepEqual(todos, [\n      {\n        text: 'some todo',\n        complete: false,\n        id: 0\n      }\n    ])\n  })\n\n  it('return 404 for non-existent service', async () => {\n    try {\n      await app.service('not/me').create({})\n      assert.fail('Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, \"Service 'not/me' not found\")\n    }\n  })\n\n  it('is event target compatible', async () => {\n    app.service('todo').addEventListener('created', (data: any) => assert.ok(data))\n  })\n\n  it('calls .customMethod', async () => {\n    const service = app.service('todos')\n    const result = await service.customMethod({ message: 'hi' })\n\n    assert.deepStrictEqual(result, {\n      data: { message: 'hi' },\n      provider: 'socketio',\n      type: 'customMethod'\n    })\n  })\n\n  clientTests(app, 'todos')\n  clientTests(app, '/')\n})\n"
  },
  {
    "path": "packages/socketio-client/test/server.ts",
    "content": "import { feathers, Id, Params } from '@feathersjs/feathers'\nimport socketio from '@feathersjs/socketio'\nimport '@feathersjs/transport-commons'\nimport { MemoryService } from '@feathersjs/memory'\n\n// eslint-disable-next-line no-extend-native\nObject.defineProperty(Error.prototype, 'toJSON', {\n  value() {\n    const alt: any = {}\n\n    Object.getOwnPropertyNames(this).forEach((key: string) => {\n      alt[key] = this[key]\n    }, this)\n\n    return alt\n  },\n  configurable: true,\n  writable: true\n})\n\n// Create an in-memory CRUD service for our Todos\nclass TodoService extends MemoryService {\n  async get(id: Id, params: Params) {\n    if (params.query.error) {\n      throw new Error('Something went wrong')\n    }\n\n    const data = await super.get(id)\n\n    return Object.assign({ query: params.query }, data)\n  }\n\n  async customMethod(data: any, { provider }: Params) {\n    return {\n      data,\n      provider,\n      type: 'customMethod'\n    }\n  }\n}\n\nexport function createServer() {\n  const app = feathers()\n    .configure(socketio())\n    .use('/', new TodoService())\n    .use('/todos', new TodoService(), {\n      methods: ['find', 'get', 'create', 'update', 'patch', 'remove', 'customMethod']\n    })\n  const service = app.service('todos')\n  const rootService = app.service('/')\n  const publisher = () => app.channel('general')\n  const data = {\n    text: 'some todo',\n    complete: false\n  }\n\n  app.on('connection', (connection) => app.channel('general').join(connection))\n\n  rootService.create(data)\n  rootService.publish(publisher)\n\n  service.create(data)\n  service.publish(publisher)\n\n  return app\n}\n"
  },
  {
    "path": "packages/socketio-client/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/tests/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n### Features\n\n- **express, koa:** make transports similar ([#2486](https://github.com/feathersjs/feathers/issues/2486)) ([26aa937](https://github.com/feathersjs/feathers/commit/26aa937c114fb8596dfefc599b1f53cead69c159))\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- **koa:** Use extended query parser for compatibility ([#2397](https://github.com/feathersjs/feathers/issues/2397)) ([b2944ba](https://github.com/feathersjs/feathers/commit/b2944bac3ec6d5ecc80dc518cd4e58093692db74))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n\n### Features\n\n- **core:** Public custom service methods ([#2270](https://github.com/feathersjs/feathers/issues/2270)) ([e65abfb](https://github.com/feathersjs/feathers/commit/e65abfb5388df6c19a11c565cf1076a29f32668d))\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n**Note:** Version bump only for package @feathersjs/tests\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n### Bug Fixes\n\n- Improve authentication parameter handling ([#1333](https://github.com/feathersjs/feathers/issues/1333)) ([6e77204](https://github.com/feathersjs/feathers/commit/6e77204))\n"
  },
  {
    "path": "packages/tests/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/tests/README.md",
    "content": "# @feathersjs/tests\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/tests.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/tests)\n\n> Common tests for Feathers core modules\n"
  },
  {
    "path": "packages/tests/package.json",
    "content": "{\n  \"name\": \"@feathersjs/tests\",\n  \"private\": true,\n  \"description\": \"Feathers core module common tests\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/tests\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"echo \\\"not necessary\\\"\",\n    \"test\": \"echo \\\"not necessary\\\"\",\n    \"compile\": \"shx rm -rf lib/ && tsc\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@types/lodash\": \"^4.17.24\",\n    \"axios\": \"^1.13.6\",\n    \"lodash\": \"^4.17.23\"\n  },\n  \"devDependencies\": {\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  }\n}\n"
  },
  {
    "path": "packages/tests/resources/certificate.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIEBTCCAu2gAwIBAgIUD49sq2fjXZWMlFOp5lCNqVIorZkwDQYJKoZIhvcNAQEL\nBQAwgZExCzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdBbGJlcnRhMRAwDgYDVQQHDAdD\nYWxnYXJ5MREwDwYDVQQKDAhGZWF0aGVyczERMA8GA1UECwwIRmVhdGhlcnMxEzAR\nBgNVBAMMCkZlYXRoZXJzSlMxIzAhBgkqhkiG9w0BCQEWFGhlbGxvQGZlYXRoZXJz\nanMuY29tMB4XDTI2MDIxOTIwNTgwNVoXDTM2MDIxNzIwNTgwNVowgZExCzAJBgNV\nBAYTAkNBMRAwDgYDVQQIDAdBbGJlcnRhMRAwDgYDVQQHDAdDYWxnYXJ5MREwDwYD\nVQQKDAhGZWF0aGVyczERMA8GA1UECwwIRmVhdGhlcnMxEzARBgNVBAMMCkZlYXRo\nZXJzSlMxIzAhBgkqhkiG9w0BCQEWFGhlbGxvQGZlYXRoZXJzanMuY29tMIIBIjAN\nBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA43FIMR2DBk2HQIrx00boWnqjXJP7\nfSOKmDd+YekmhTjnIhgdErthtnuOrR+sv64a6sslKc7OFC40ooCjhdrDQVOoXaOU\nlrLZQ/C/0UqzuzE+zD9Z3nMxopsUQPUtI/BAb30xGNm4VltkxNkjL0g/0wu2jWQQ\nfQY5I/RVX8iKfkFzTDshLxo18bTDAhfeAebNYDWoUCLKbQCf0YF3wUNGuGR2/XCk\nAEedBPXoU7x5VvmPR5M4Xk7V3viXVkgqjchn3REvinTTltfOJZRXqyfsKFKm+z8P\ndDCm1yXgx1omUhmpZ5P7qRWf0rFNh6v63e+62PurrAWuPvpk/tLqishsAQIDAQAB\no1MwUTAdBgNVHQ4EFgQUfMSETLqaqpNhZ4Wg33q0sZ5dqOcwHwYDVR0jBBgwFoAU\nfMSETLqaqpNhZ4Wg33q0sZ5dqOcwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B\nAQsFAAOCAQEAwy5DbsrduML5mpXbyleCBIlRiaNtrl4fpHoZmGstok3kvq1RonAY\nL8/5XDn/aKBc7P0ELBWxC/EjrFNrQp+FFY2o8OQzFEtojB4LXV9Iph8IWErnwPcK\nvxVIV543xZu8dAvSPm+/bAdeOba2WyMkJyMgYFwLAOzzDUG3MBP8plGdXZ05N5zA\nhWde/ntHVqW0E5wkaEveQwzJDAIXMhEDYEbQ8WOKiYty8Zso68HSAsl+iMICxrqQ\nrJoPCW5Eo+S+3K3K1CTDQuozO7HG1uyeFrcR8Dw9EI1875sjj0yQPlf6SlTYYDot\nwDzhAkPkoqhBp6hbAd1Hf6nvJWn+LH5osg==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "packages/tests/resources/privatekey.pem",
    "content": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDjcUgxHYMGTYdA\nivHTRuhaeqNck/t9I4qYN35h6SaFOOciGB0Su2G2e46tH6y/rhrqyyUpzs4ULjSi\ngKOF2sNBU6hdo5SWstlD8L/RSrO7MT7MP1neczGimxRA9S0j8EBvfTEY2bhWW2TE\n2SMvSD/TC7aNZBB9Bjkj9FVfyIp+QXNMOyEvGjXxtMMCF94B5s1gNahQIsptAJ/R\ngXfBQ0a4ZHb9cKQAR50E9ehTvHlW+Y9HkzheTtXe+JdWSCqNyGfdES+KdNOW184l\nlFerJ+woUqb7Pw90MKbXJeDHWiZSGalnk/upFZ/SsU2Hq/rd77rY+6usBa4++mT+\n0uqKyGwBAgMBAAECggEAVKnJCTtmmBSI+c4e6Zo2COQo5l/RmEoAH9xcZ779z06Y\nvzjBrcThwSdqO2iUif+Z1nfLPC5WyO1QO4NuG3gNAcbN4BlxyM0HkkJObO6FS/Ov\nYCFe5y7zNYfLuMhrRrr6iWXNPmZhN4gq0RnQ/ptC4uEz0ZsDhj6oS4l6tD52yzsH\nKtT83fVWdSIgL9qHLtL9EPHgw/erFB5bdxu+Fzo7eQQeOiwh1ITvpFgeJ1nxIc35\nfCCCYD7EA/p0ZPn337It40UQGnoKiZrM96nzBqkdjnJpYcsdvCLUhXAbzHRmi2kr\nIsBKhY99+KG8zVznwNaSmqjmEwabhRkma/7NwK2wrwKBgQD20bZjghJwUcHMroGX\nszi6O4zik7CHPZbSAL/EcycoEaTgmdkAQrH3hKC7cVw8KBdJjs+CN131669o81vS\n9fBFH2fkE4fctzFmwDz9UBL9WU7ysKnmpkP1k8pAwc4Cs+KKdZR2XgXRCeNiXIjE\nUrjsnKLTjWMaHMtzF8hq8vRtLwKBgQDr5w8SkiCknJ8mjlLOBOg+IwHQl/B3BBnf\nTbrJxxwYvaO4Agc9kRKT9/QPoMioONCpK3oTsiTlED+3mRfkixatcUBtS8Nsu4bq\nquu7gBuBQNyDDszCmm0GIjeiYyjzy3eiyhtg8cfngZ+GyMsV3nZ2E0z+jGyFCT+b\n2NniMUNNzwKBgD022eNoGSaeQFCBX0a+fm1B47k2I+wGzGcdJHKWlLmNVrUVswor\ngHQBAtQ6U0PgNZZawwBqtvUNFR4UbUuvD341QdEBPwrwrGHtf7LbrzoCcmAijKDV\nz7kShHD3IB7veloYu094Fj04FJsKlCkM0yxr1L5fLJsHVTYgSeashw6lAoGAGR/u\n1weBOocD3FNkNlUHdza7RsAn+EUTjFj2/+6Y63mnKj3tD32YAPJzqAZz2JbUgnAC\n/H4It+zXHHLNvKWjsK1TM1DSa449fFjf6oRmaYnC8qJs5H0WB4U1b7In9m9BOrFT\n4StfIyUHHI/eMWIUM9cyaBoEpNarU6nw6spcZLkCgYEAkIUZrQhsHyin4YvRPrrN\npbn/ZIuIIFvghPiUucqdt3h1pdCsgebN8Z5DOYGf27EkT41oV24rKvTUXnb8fV6F\nNWbniV6d2YPOqnJ0rCtfou1gQ1fWWQBnAQDK7wn/rPedtxXDWr74raNByppc0P9r\nqBfYqpXj88GVYhhwUR+WVSI=\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "packages/tests/src/client.ts",
    "content": "import { strict as assert } from 'assert'\n\nexport interface Todo {\n  text: string\n  complete?: boolean\n  id?: number\n}\n\nexport function clientTests(app: any, name: string) {\n  const getService = () => (name && typeof app.service === 'function' ? app.service(name) : app)\n\n  describe('Service base tests', () => {\n    it('.find', async () => {\n      const todos = await getService().find()\n\n      assert.deepEqual(todos, [\n        {\n          // eslint-disable-line\n          text: 'some todo',\n          complete: false,\n          id: 0\n        }\n      ])\n    })\n\n    it('.get and params passing', async () => {\n      const query = {\n        some: 'thing',\n        other: ['one', 'two'],\n        nested: { a: { b: 'object' } }\n      }\n\n      const todo = await getService().get(0, { query })\n\n      assert.deepEqual(todo, {\n        // eslint-disable-line\n        id: 0,\n        text: 'some todo',\n        complete: false,\n        query\n      })\n    })\n\n    it('.create', async () => {\n      const todo = await getService().create({\n        text: 'created todo',\n        complete: true\n      })\n\n      assert.deepEqual(todo, {\n        // eslint-disable-line\n        id: 1,\n        text: 'created todo',\n        complete: true\n      })\n    })\n\n    it('.create and created event', (done) => {\n      getService().once('created', (data: Todo) => {\n        assert.strictEqual(data.text, 'created todo')\n        assert.ok(data.complete)\n        done()\n      })\n\n      getService().create({ text: 'created todo', complete: true })\n    })\n\n    it('.update and updated event', (done) => {\n      getService().once('updated', (data: Todo) => {\n        assert.strictEqual(data.text, 'updated todo')\n        assert.ok(data.complete)\n        done()\n      })\n\n      getService()\n        .create({ text: 'todo to update', complete: false })\n        .then((todo: Todo) => {\n          getService().update(todo.id, {\n            text: 'updated todo',\n            complete: true\n          })\n        })\n    })\n\n    it('.patch and patched event', (done) => {\n      getService().once('patched', (data: Todo) => {\n        assert.strictEqual(data.text, 'todo to patch')\n        assert.ok(data.complete)\n        done()\n      })\n\n      getService()\n        .create({ text: 'todo to patch', complete: false })\n        .then((todo: Todo) => getService().patch(todo.id, { complete: true }))\n    })\n\n    it('.remove and removed event', (done) => {\n      getService().once('removed', (data: Todo) => {\n        assert.strictEqual(data.text, 'todo to remove')\n        assert.strictEqual(data.complete, false)\n        done()\n      })\n\n      getService()\n        .create({ text: 'todo to remove', complete: false })\n        .then((todo: Todo) => getService().remove(todo.id))\n        .catch(done)\n    })\n\n    it('.get with error', async () => {\n      const query = { error: true }\n\n      try {\n        await getService().get(0, { query })\n        assert.fail('Should never get here')\n      } catch (error: any) {\n        assert.strictEqual(error.message, 'Something went wrong')\n      }\n    })\n  })\n}\n"
  },
  {
    "path": "packages/tests/src/fixture.ts",
    "content": "import assert from 'assert'\n\nconst clone = (data: any) => JSON.parse(JSON.stringify(data))\n\nconst findAllData = [\n  {\n    id: 0,\n    description: 'You have to do something'\n  },\n  {\n    id: 1,\n    description: 'You have to do laundry'\n  }\n]\n\nexport class Service {\n  events = ['log']\n\n  async find() {\n    return findAllData\n  }\n\n  async get(name: string, params: any) {\n    if (params.query.error) {\n      throw new Error(`Something for ${name} went wrong`)\n    }\n\n    if (params.query.runtimeError) {\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      thingThatDoesNotExist() // eslint-disable-line\n    }\n\n    return Promise.resolve({\n      id: name,\n      description: `You have to do ${name}!`\n    })\n  }\n\n  async create(data: any) {\n    const result = Object.assign({}, clone(data), {\n      id: 42,\n      status: 'created'\n    })\n\n    if (Array.isArray(data)) {\n      result.many = true\n    }\n\n    return result\n  }\n\n  async update(id: any, data: any) {\n    const result = Object.assign({}, clone(data), {\n      id,\n      status: 'updated'\n    })\n\n    if (id === null) {\n      result.many = true\n    }\n\n    return result\n  }\n\n  async patch(id: any, data: any) {\n    const result = Object.assign({}, clone(data), {\n      id,\n      status: 'patched'\n    })\n\n    if (id === null) {\n      result.many = true\n    }\n\n    return result\n  }\n\n  async remove(id: any) {\n    return { id }\n  }\n\n  async customMethod(data: any, params: any) {\n    return {\n      data,\n      method: 'customMethod',\n      provider: params.provider\n    }\n  }\n\n  async internalMethod() {\n    throw new Error('Should never get here')\n  }\n}\n\nexport const verify = {\n  find(data: any) {\n    assert.deepStrictEqual(findAllData, clone(data), 'Data as expected')\n  },\n\n  get(id: any, data: any) {\n    assert.strictEqual(data.id, id, 'Got id in data')\n    assert.strictEqual(data.description, `You have to do ${id}!`, 'Got description')\n  },\n\n  create(original: any, current: any) {\n    const expected = Object.assign({}, clone(original), {\n      id: 42,\n      status: 'created'\n    })\n    assert.deepStrictEqual(expected, clone(current), 'Data ran through .create as expected')\n  },\n\n  update(id: any, original: any, current: any) {\n    const expected = Object.assign({}, clone(original), {\n      id,\n      status: 'updated'\n    })\n    assert.deepStrictEqual(expected, clone(current), 'Data ran through .update as expected')\n  },\n\n  patch(id: any, original: any, current: any) {\n    const expected = Object.assign({}, clone(original), {\n      id,\n      status: 'patched'\n    })\n    assert.deepStrictEqual(expected, clone(current), 'Data ran through .patch as expected')\n  },\n\n  remove(id: any, data: any) {\n    assert.deepStrictEqual({ id }, clone(data), '.remove called')\n  }\n}\n"
  },
  {
    "path": "packages/tests/src/index.ts",
    "content": "export * from './client'\nexport * from './rest'\nexport * from './fixture'\n"
  },
  {
    "path": "packages/tests/src/rest.ts",
    "content": "import assert from 'assert'\nimport axios from 'axios'\n\nimport { verify } from './fixture'\n\nexport function restTests(description: string, name: string, port: number) {\n  describe(description, () => {\n    it('GET .find', async () => {\n      const res = await axios.get<any>(`http://localhost:${port}/${name}`)\n\n      assert.ok(res.status === 200, 'Got OK status code')\n      verify.find(res.data)\n    })\n\n    it('GET .get', async () => {\n      const res = await axios.get<any>(`http://localhost:${port}/${name}/dishes`)\n\n      assert.ok(res.status === 200, 'Got OK status code')\n      verify.get('dishes', res.data)\n    })\n\n    it('POST .create', async () => {\n      const original = {\n        description: 'POST .create'\n      }\n\n      const res = await axios.post<any>(`http://localhost:${port}/${name}`, original)\n\n      assert.ok(res.status === 201, 'Got CREATED status code')\n      verify.create(original, res.data)\n    })\n\n    it('PUT .update', async () => {\n      const original = {\n        description: 'PUT .update'\n      }\n\n      const res = await axios.put(`http://localhost:${port}/${name}/544`, original)\n\n      assert.ok(res.status === 200, 'Got OK status code')\n      verify.update('544', original, res.data)\n    })\n\n    it('PUT .update many', async () => {\n      const original = {\n        description: 'PUT .update',\n        many: true\n      }\n\n      const res = await axios.put(`http://localhost:${port}/${name}`, original)\n      const { data } = res\n\n      assert.ok(res.status === 200, 'Got OK status code')\n      verify.update(null, original, data)\n    })\n\n    it('PATCH .patch', async () => {\n      const original = {\n        description: 'PATCH .patch'\n      }\n\n      const res = await axios.patch(`http://localhost:${port}/${name}/544`, original)\n\n      assert.ok(res.status === 200, 'Got OK status code')\n      verify.patch('544', original, res.data)\n    })\n\n    it('PATCH .patch many', async () => {\n      const original = {\n        description: 'PATCH .patch',\n        many: true\n      }\n\n      const res = await axios.patch(`http://localhost:${port}/${name}`, original)\n\n      assert.ok(res.status === 200, 'Got OK status code')\n      verify.patch(null, original, res.data)\n    })\n\n    it('DELETE .remove', async () => {\n      const res = await axios.delete(`http://localhost:${port}/${name}/233`)\n\n      assert.ok(res.status === 200, 'Got OK status code')\n      verify.remove('233', res.data)\n    })\n\n    it('DELETE .remove many', async () => {\n      const res = await axios.delete(`http://localhost:${port}/${name}`)\n\n      assert.ok(res.status === 200, 'Got OK status code')\n      verify.remove(null, res.data)\n    })\n  })\n}\n"
  },
  {
    "path": "packages/tests/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/transport-commons/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n### Bug Fixes\n\n- **client:** Ensure all client methods require valid ids ([#3661](https://github.com/feathersjs/feathers/issues/3661)) ([bc754d3](https://github.com/feathersjs/feathers/commit/bc754d3666b059b9d93799602dac427cb419ddc6))\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n### Bug Fixes\n\n- **transport-commons:** Fix HTTP status precedence ([#3511](https://github.com/feathersjs/feathers/issues/3511)) ([5d999a0](https://github.com/feathersjs/feathers/commit/5d999a0acddc0cb7692058209dfbc62673ab5a69))\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n### Bug Fixes\n\n- Reduce usage of lodash ([#3455](https://github.com/feathersjs/feathers/issues/3455)) ([8ce807a](https://github.com/feathersjs/feathers/commit/8ce807a5ca53ff5b8d5107a0656c6329404e6e6c))\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n### Bug Fixes\n\n- **socketio:** Handle ackTimeout of socket.io ([#3437](https://github.com/feathersjs/feathers/issues/3437)) ([2642072](https://github.com/feathersjs/feathers/commit/26420721f3eb16f716a9e68ab3ed9f415bab7a9c))\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n- **transport-commons:** Properly delete route data ([#3433](https://github.com/feathersjs/feathers/issues/3433)) ([af01bdb](https://github.com/feathersjs/feathers/commit/af01bdbe050dd428d6fffefa1874e9a6e4182bad))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n### Bug Fixes\n\n- **transport-commons:** Allow case insensitive route lookups ([#3353](https://github.com/feathersjs/feathers/issues/3353)) ([a4a5ab6](https://github.com/feathersjs/feathers/commit/a4a5ab6cb59048176292cd71c04a32aa71ac4642))\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **client:** Replace placeholders in URL with route params ([#3270](https://github.com/feathersjs/feathers/issues/3270)) ([a0624eb](https://github.com/feathersjs/feathers/commit/a0624eb5a7919aa1b179a71beb1c1b9cab574525))\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n### Bug Fixes\n\n- **client:** Add underscored methods to clients ([#3176](https://github.com/feathersjs/feathers/issues/3176)) ([f3c01f7](https://github.com/feathersjs/feathers/commit/f3c01f7b8266bfc642c55b77ba8e5bb333542630))\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n### Bug Fixes\n\n- **transport-commons:** Handle invalid service paths on socket lookups ([#3241](https://github.com/feathersjs/feathers/issues/3241)) ([c397ab3](https://github.com/feathersjs/feathers/commit/c397ab3a0cd184044ae4f73540549b30a396821c))\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n### Bug Fixes\n\n- **core:** Use Symbol.for to instantiate shared symbols ([#3087](https://github.com/feathersjs/feathers/issues/3087)) ([7f3fc21](https://github.com/feathersjs/feathers/commit/7f3fc2167576f228f8183568eb52b077160e8d65))\n- **transport-commons:** Fix dispatching of arrays ([#3075](https://github.com/feathersjs/feathers/issues/3075)) ([98fdda5](https://github.com/feathersjs/feathers/commit/98fdda53187acee88137b39662c766cc62cd7b55))\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **core:** Improve service option usage and method option typings ([#2902](https://github.com/feathersjs/feathers/issues/2902)) ([164d75c](https://github.com/feathersjs/feathers/commit/164d75c0f11139a316baa91f1762de8f8eb7da2d))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n### Bug Fixes\n\n- **docs:** Review transport API docs and update Express middleware setup ([#2811](https://github.com/feathersjs/feathers/issues/2811)) ([1b97f14](https://github.com/feathersjs/feathers/commit/1b97f14d474f5613482f259eeaa585c24fcfab43))\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n### Features\n\n- **cli:** Generate full client test suite and improve typed client ([#2788](https://github.com/feathersjs/feathers/issues/2788)) ([57119b6](https://github.com/feathersjs/feathers/commit/57119b6bb2797f7297cf054268a248c093ecd538))\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **core:** Allow to unregister services at runtime ([#2756](https://github.com/feathersjs/feathers/issues/2756)) ([d16601f](https://github.com/feathersjs/feathers/commit/d16601f2277dca5357866ffdefba2a611f6dc7fa))\n\n# [5.0.0-pre.29](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.28...v5.0.0-pre.29) (2022-09-16)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.28](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.27...v5.0.0-pre.28) (2022-08-03)\n\n### Bug Fixes\n\n- **cli:** Improve generated application and client ([#2701](https://github.com/feathersjs/feathers/issues/2701)) ([bd55ffb](https://github.com/feathersjs/feathers/commit/bd55ffb812e89bf215f4515e7f137656ea888c3f))\n\n# [5.0.0-pre.27](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.26...v5.0.0-pre.27) (2022-07-13)\n\n### Bug Fixes\n\n- **socketio-client:** Make Socket.io client event target compatible ([#2686](https://github.com/feathersjs/feathers/issues/2686)) ([716c49a](https://github.com/feathersjs/feathers/commit/716c49a270e4be5e5276192092c292f72ffcfa19))\n\n# [5.0.0-pre.26](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.25...v5.0.0-pre.26) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.25](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.24...v5.0.0-pre.25) (2022-06-22)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.24](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.23...v5.0.0-pre.24) (2022-06-21)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.23](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.22...v5.0.0-pre.23) (2022-06-06)\n\n### Features\n\n- **client:** Improve client side custom method support ([#2654](https://github.com/feathersjs/feathers/issues/2654)) ([c138acf](https://github.com/feathersjs/feathers/commit/c138acf50affbe6b66177d084d3c7a3e9220f09f))\n\n# [5.0.0-pre.22](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.21...v5.0.0-pre.22) (2022-05-24)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.21](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.20...v5.0.0-pre.21) (2022-05-23)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.20](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.19...v5.0.0-pre.20) (2022-05-04)\n\n### Bug Fixes\n\n- **dependencies:** Lock monorepo package version numbers ([#2623](https://github.com/feathersjs/feathers/issues/2623)) ([5640c10](https://github.com/feathersjs/feathers/commit/5640c1020cc139994e695d658c08bad3494db507))\n\n# [5.0.0-pre.19](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.18...v5.0.0-pre.19) (2022-05-01)\n\n### Bug Fixes\n\n- **transport-commons:** Ensure socket queries are always plain objects ([#2597](https://github.com/feathersjs/feathers/issues/2597)) ([97313e1](https://github.com/feathersjs/feathers/commit/97313e121cfee4199f10012e95b8507557aa507e))\n\n# [5.0.0-pre.18](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.17...v5.0.0-pre.18) (2022-04-11)\n\n### Features\n\n- **transport-commons:** add `context.http.response` ([#2524](https://github.com/feathersjs/feathers/issues/2524)) ([5bc9d44](https://github.com/feathersjs/feathers/commit/5bc9d447043c2e2b742c73ed28ecf3b3264dd9e5))\n\n# [5.0.0-pre.17](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.16...v5.0.0-pre.17) (2022-02-15)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.16](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.15...v5.0.0-pre.16) (2022-01-12)\n\n### Features\n\n- **express, koa:** make transports similar ([#2486](https://github.com/feathersjs/feathers/issues/2486)) ([26aa937](https://github.com/feathersjs/feathers/commit/26aa937c114fb8596dfefc599b1f53cead69c159))\n\n# [5.0.0-pre.15](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.14...v5.0.0-pre.15) (2021-11-27)\n\n### Bug Fixes\n\n- **typescript:** Overall typing improvements ([#2478](https://github.com/feathersjs/feathers/issues/2478)) ([b8eb804](https://github.com/feathersjs/feathers/commit/b8eb804158556d9651a8607e3c3fda15e0bfd110))\n\n### Features\n\n- **core:** add `context.http` and move `statusCode` there ([#2496](https://github.com/feathersjs/feathers/issues/2496)) ([b701bf7](https://github.com/feathersjs/feathers/commit/b701bf77fb83048aa1dffa492b3d77dd53f7b72b))\n- **transport-commons:** Ability to register routes with custom params ([#2482](https://github.com/feathersjs/feathers/issues/2482)) ([497990a](https://github.com/feathersjs/feathers/commit/497990ae4a980e5a52a1f0f932db12cd0e6e254a))\n\n# [5.0.0-pre.14](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.13...v5.0.0-pre.14) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.13](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.12...v5.0.0-pre.13) (2021-10-13)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.12](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.11...v5.0.0-pre.12) (2021-10-12)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.11](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.10...v5.0.0-pre.11) (2021-10-06)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.10](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.9...v5.0.0-pre.10) (2021-09-19)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.9](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.8...v5.0.0-pre.9) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.8](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.7...v5.0.0-pre.8) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.7](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.6...v5.0.0-pre.7) (2021-08-09)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.6](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.5...v5.0.0-pre.6) (2021-08-08)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.4...v5.0.0-pre.5) (2021-06-23)\n\n### Bug Fixes\n\n- **koa:** Use extended query parser for compatibility ([#2397](https://github.com/feathersjs/feathers/issues/2397)) ([b2944ba](https://github.com/feathersjs/feathers/commit/b2944bac3ec6d5ecc80dc518cd4e58093692db74))\n\n# [5.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.3...v5.0.0-pre.4) (2021-05-13)\n\n### Bug Fixes\n\n- **transport-commons:** Fix route placeholder registration and improve radix router performance ([#2336](https://github.com/feathersjs/feathers/issues/2336)) ([4d84dfd](https://github.com/feathersjs/feathers/commit/4d84dfd092ce0510312e975d5cd57e04973fb311))\n\n### Features\n\n- **koa:** KoaJS transport adapter ([#2315](https://github.com/feathersjs/feathers/issues/2315)) ([2554b57](https://github.com/feathersjs/feathers/commit/2554b57cf05731df58feeba9c12faab18e442107))\n\n# [5.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.2...v5.0.0-pre.3) (2021-04-21)\n\n### Bug Fixes\n\n- **typescript:** Improve TypeScript backwards compatibility ([#2310](https://github.com/feathersjs/feathers/issues/2310)) ([f33be73](https://github.com/feathersjs/feathers/commit/f33be73fc46a533efb15df9aab0658e3240d3897))\n\n### Features\n\n- **dependencies:** Remove direct debug dependency ([#2296](https://github.com/feathersjs/feathers/issues/2296)) ([501d416](https://github.com/feathersjs/feathers/commit/501d4164d30c6a126906dc640cdfdc82207ba34a))\n\n# [5.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.1...v5.0.0-pre.2) (2021-04-06)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-beta.1](https://github.com/feathersjs/feathers/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2021-04-03)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [5.0.0-beta.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.1...v5.0.0-beta.0) (2021-03-28)\n\n### Bug Fixes\n\n- **transport-commons:** Do not error when adding an undefined connection to a channel ([#2268](https://github.com/feathersjs/feathers/issues/2268)) ([28114c4](https://github.com/feathersjs/feathers/commit/28114c495d6564868bb3ffbf619bf80b774dce4b))\n- Update Grant usage and other dependencies ([#2264](https://github.com/feathersjs/feathers/issues/2264)) ([7b0f8fa](https://github.com/feathersjs/feathers/commit/7b0f8fad252419ed0ad0bf259cdf3104d322ab60))\n- **socketio-client:** Fix client transport-commons reference ([#2164](https://github.com/feathersjs/feathers/issues/2164)) ([3a42c54](https://github.com/feathersjs/feathers/commit/3a42c544058456b19c7e21827226541bfa6ad621))\n\n### Features\n\n- **core:** Public custom service methods ([#2270](https://github.com/feathersjs/feathers/issues/2270)) ([e65abfb](https://github.com/feathersjs/feathers/commit/e65abfb5388df6c19a11c565cf1076a29f32668d))\n- Application service types default to any ([#1566](https://github.com/feathersjs/feathers/issues/1566)) ([d93ba9a](https://github.com/feathersjs/feathers/commit/d93ba9a17edd20d3397bb00f4f6e82e804e42ed6))\n- Feathers v5 core refactoring and features ([#2255](https://github.com/feathersjs/feathers/issues/2255)) ([2dafb7c](https://github.com/feathersjs/feathers/commit/2dafb7ce14ba57406aeec13d10ca45b1e709bee9))\n- **transport-commons:** New built-in high performance radix router ([#2177](https://github.com/feathersjs/feathers/issues/2177)) ([6d18065](https://github.com/feathersjs/feathers/commit/6d180651b4eb40289ecea3df3575f207aa6c5d1f))\n\n# [5.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.5.11...v5.0.0-pre.1) (2020-12-17)\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Features\n\n- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))\n- **transport-commons:** Remove legacy message format and unnecessary client timeouts ([#1939](https://github.com/feathersjs/feathers/issues/1939)) ([5538881](https://github.com/feathersjs/feathers/commit/5538881a08bc130de42c5984055729d8336f8615))\n\n### BREAKING CHANGES\n\n- **transport-commons:** Removes the old message format and client service timeout\n\n# [5.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v4.5.4...v5.0.0-pre.0) (2020-05-19)\n\n### Features\n\n- **core:** use @feathers/hooks and add async type ([#1929](https://github.com/feathersjs/feathers/issues/1929)) ([a5c4756](https://github.com/feathersjs/feathers/commit/a5c47562eae8410c82fe2f6308f26f8e78b6a3e8))\n- **transport-commons:** Remove legacy message format and unnecessary client timeouts ([#1939](https://github.com/feathersjs/feathers/issues/1939)) ([5538881](https://github.com/feathersjs/feathers/commit/5538881a08bc130de42c5984055729d8336f8615))\n\n### BREAKING CHANGES\n\n- **transport-commons:** Removes the old message format and client service timeout\n\n## [4.5.11](https://github.com/feathersjs/feathers/compare/v4.5.10...v4.5.11) (2020-12-05)\n\n### Bug Fixes\n\n- **socketio-client:** Throw an error and show a warning if someone tries to use socket.io-client v3 ([#2135](https://github.com/feathersjs/feathers/issues/2135)) ([cc3521c](https://github.com/feathersjs/feathers/commit/cc3521c935a1cbd690e29b7057998e3898f282db))\n\n## [4.5.10](https://github.com/feathersjs/feathers/compare/v4.5.9...v4.5.10) (2020-11-08)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.5.9](https://github.com/feathersjs/feathers/compare/v4.5.8...v4.5.9) (2020-10-09)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.5.8](https://github.com/feathersjs/feathers/compare/v4.5.7...v4.5.8) (2020-08-12)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.5.7](https://github.com/feathersjs/feathers/compare/v4.5.6...v4.5.7) (2020-07-24)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.5.5](https://github.com/feathersjs/feathers/compare/v4.5.4...v4.5.5) (2020-07-11)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.5.3](https://github.com/feathersjs/feathers/compare/v4.5.2...v4.5.3) (2020-04-17)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.5.2](https://github.com/feathersjs/feathers/compare/v4.5.1...v4.5.2) (2020-03-04)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.5.1](https://github.com/feathersjs/feathers/compare/v4.5.0...v4.5.1) (2020-01-24)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [4.5.0](https://github.com/feathersjs/feathers/compare/v4.4.3...v4.5.0) (2020-01-18)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.4.3](https://github.com/feathersjs/feathers/compare/v4.4.1...v4.4.3) (2019-12-06)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.4.1](https://github.com/feathersjs/feathers/compare/v4.4.0...v4.4.1) (2019-11-27)\n\n### Bug Fixes\n\n- Gracefully handle errors in publishers ([#1710](https://github.com/feathersjs/feathers/issues/1710)) ([0616306](https://github.com/feathersjs/feathers/commit/061630696762e9dbf1dc4e738094992ba16989fc))\n\n# [4.4.0](https://github.com/feathersjs/feathers/compare/v4.3.11...v4.4.0) (2019-11-27)\n\n### Bug Fixes\n\n- **transport-commons:** Allow to properly chain SocketIo client.off ([#1706](https://github.com/feathersjs/feathers/issues/1706)) ([a4aecbc](https://github.com/feathersjs/feathers/commit/a4aecbcd3578c1cf4ecffb3a58fb6d26e15ee513))\n\n## [4.3.11](https://github.com/feathersjs/feathers/compare/v4.3.10...v4.3.11) (2019-11-11)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.3.10](https://github.com/feathersjs/feathers/compare/v4.3.9...v4.3.10) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.3.9](https://github.com/feathersjs/feathers/compare/v4.3.8...v4.3.9) (2019-10-26)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.3.7](https://github.com/feathersjs/feathers/compare/v4.3.6...v4.3.7) (2019-10-14)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.3.4](https://github.com/feathersjs/feathers/compare/v4.3.3...v4.3.4) (2019-10-03)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.3.3](https://github.com/feathersjs/feathers/compare/v4.3.2...v4.3.3) (2019-09-21)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.3.2](https://github.com/feathersjs/feathers/compare/v4.3.1...v4.3.2) (2019-09-16)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n## [4.3.1](https://github.com/feathersjs/feathers/compare/v4.3.0...v4.3.1) (2019-09-09)\n\n### Bug Fixes\n\n- Fix regression in transport commons ([#1551](https://github.com/feathersjs/feathers/issues/1551)) ([ed9e934](https://github.com/feathersjs/feathers/commit/ed9e934))\n\n# [4.3.0](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.4...v4.3.0) (2019-08-27)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [4.3.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.3...v4.3.0-pre.4) (2019-08-22)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [4.3.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.2...v4.3.0-pre.3) (2019-08-19)\n\n### Bug Fixes\n\n- Expire and remove authenticated real-time connections ([#1512](https://github.com/feathersjs/feathers/issues/1512)) ([2707c33](https://github.com/feathersjs/feathers/commit/2707c33))\n- Update all dependencies ([7d53a00](https://github.com/feathersjs/feathers/commit/7d53a00))\n- Use WeakMap to connect socket to connection ([#1509](https://github.com/feathersjs/feathers/issues/1509)) ([64807e3](https://github.com/feathersjs/feathers/commit/64807e3))\n\n# [4.3.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.3.0-pre.1...v4.3.0-pre.2) (2019-08-02)\n\n### Bug Fixes\n\n- Add getEntityId to JWT strategy and fix legacy Socket authentication ([#1488](https://github.com/feathersjs/feathers/issues/1488)) ([9a3b324](https://github.com/feathersjs/feathers/commit/9a3b324))\n- Improve Params typing ([#1474](https://github.com/feathersjs/feathers/issues/1474)) ([54a3aa7](https://github.com/feathersjs/feathers/commit/54a3aa7))\n\n# [4.3.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.5...v4.3.0-pre.1) (2019-07-11)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [4.0.0-pre.5](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.4...v4.0.0-pre.5) (2019-07-10)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n# [4.0.0-pre.4](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.3...v4.0.0-pre.4) (2019-07-05)\n\n### Bug Fixes\n\n- Clean up hooks code ([#1407](https://github.com/feathersjs/feathers/issues/1407)) ([f25c88b](https://github.com/feathersjs/feathers/commit/f25c88b))\n- Improve transport-commons types ([#1396](https://github.com/feathersjs/feathers/issues/1396)) ([f9d8536](https://github.com/feathersjs/feathers/commit/f9d8536))\n\n# [4.0.0-pre.3](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.2...v4.0.0-pre.3) (2019-06-01)\n\n### Bug Fixes\n\n- Make oAuth paths more consistent and improve authentication client ([#1377](https://github.com/feathersjs/feathers/issues/1377)) ([adb2543](https://github.com/feathersjs/feathers/commit/adb2543))\n- Update dependencies and fix tests ([#1373](https://github.com/feathersjs/feathers/issues/1373)) ([d743a7f](https://github.com/feathersjs/feathers/commit/d743a7f))\n\n# [4.0.0-pre.2](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.1...v4.0.0-pre.2) (2019-05-15)\n\n### Bug Fixes\n\n- Add fallback for legacy socket authenticate event ([#1356](https://github.com/feathersjs/feathers/issues/1356)) ([61b1056](https://github.com/feathersjs/feathers/commit/61b1056))\n- Throw NotAuthenticated on token verification errors ([#1357](https://github.com/feathersjs/feathers/issues/1357)) ([e0120df](https://github.com/feathersjs/feathers/commit/e0120df))\n\n### Features\n\n- Add global disconnect event ([#1355](https://github.com/feathersjs/feathers/issues/1355)) ([85afcca](https://github.com/feathersjs/feathers/commit/85afcca))\n\n# [4.0.0-pre.1](https://github.com/feathersjs/feathers/compare/v4.0.0-pre.0...v4.0.0-pre.1) (2019-05-08)\n\n### Bug Fixes\n\n- Add registerPublisher alias for .publish ([#1302](https://github.com/feathersjs/feathers/issues/1302)) ([98fe8f8](https://github.com/feathersjs/feathers/commit/98fe8f8))\n\n# [4.0.0-pre.0](https://github.com/feathersjs/feathers/compare/v3.2.0-pre.1...v4.0.0-pre.0) (2019-04-21)\n\n### Bug Fixes\n\n- Compare socket event data using lodash's isEqual instead of indexOf ([#1061](https://github.com/feathersjs/feathers/issues/1061)) ([f706db3](https://github.com/feathersjs/feathers/commit/f706db3))\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n- Update all dependencies to latest ([#1206](https://github.com/feathersjs/feathers/issues/1206)) ([e51e0f6](https://github.com/feathersjs/feathers/commit/e51e0f6))\n- **package:** update debug to version 3.0.0 ([#45](https://github.com/feathersjs/feathers/issues/45)) ([9b9bde5](https://github.com/feathersjs/feathers/commit/9b9bde5))\n\n### Features\n\n- Add TypeScript definitions ([#1275](https://github.com/feathersjs/feathers/issues/1275)) ([9dd6713](https://github.com/feathersjs/feathers/commit/9dd6713))\n- Allow registering a service at the root level ([#1115](https://github.com/feathersjs/feathers/issues/1115)) ([c73d322](https://github.com/feathersjs/feathers/commit/c73d322))\n\n## [4.2.1](https://github.com/feathersjs/feathers/compare/@feathersjs/transport-commons@4.2.0...@feathersjs/transport-commons@4.2.1) (2019-01-02)\n\n### Bug Fixes\n\n- Update adapter common tests ([#1135](https://github.com/feathersjs/feathers/issues/1135)) ([8166dda](https://github.com/feathersjs/feathers/commit/8166dda))\n\n<a name=\"4.2.0\"></a>\n\n# [4.2.0](https://github.com/feathersjs/feathers/compare/@feathersjs/transport-commons@4.1.6...@feathersjs/transport-commons@4.2.0) (2018-12-16)\n\n### Features\n\n- Allow registering a service at the root level ([#1115](https://github.com/feathersjs/feathers/issues/1115)) ([c73d322](https://github.com/feathersjs/feathers/commit/c73d322))\n\n<a name=\"4.1.6\"></a>\n\n## [4.1.6](https://github.com/feathersjs/feathers/compare/@feathersjs/transport-commons@4.1.5...@feathersjs/transport-commons@4.1.6) (2018-10-25)\n\n### Bug Fixes\n\n- Compare socket event data using lodash's isEqual instead of indexOf ([#1061](https://github.com/feathersjs/feathers/issues/1061)) ([f706db3](https://github.com/feathersjs/feathers/commit/f706db3))\n- Make Mocha a proper devDependency for every repository ([#1053](https://github.com/feathersjs/feathers/issues/1053)) ([9974803](https://github.com/feathersjs/feathers/commit/9974803))\n\n<a name=\"4.1.5\"></a>\n\n## [4.1.5](https://github.com/feathersjs/feathers/compare/@feathersjs/transport-commons@4.1.4...@feathersjs/transport-commons@4.1.5) (2018-09-21)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n<a name=\"4.1.4\"></a>\n\n## [4.1.4](https://github.com/feathersjs/feathers/compare/@feathersjs/transport-commons@4.1.3...@feathersjs/transport-commons@4.1.4) (2018-09-17)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n<a name=\"4.1.3\"></a>\n\n## [4.1.3](https://github.com/feathersjs/feathers/compare/@feathersjs/transport-commons@4.1.2...@feathersjs/transport-commons@4.1.3) (2018-09-02)\n\n**Note:** Version bump only for package @feathersjs/transport-commons\n\n<a name=\"4.1.2\"></a>\n\n## 4.1.2\n\n- Migrate to Monorepo ([feathers#462](https://github.com/feathersjs/feathers/issues/462))\n\n## [v4.1.1](https://github.com/feathersjs/transport-commons/tree/v4.1.1) (2018-07-03)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v4.1.0...v4.1.1)\n\n**Merged pull requests:**\n\n- Properly dispatch arrays that do not come from Feathers hook events [\\#77](https://github.com/feathersjs/transport-commons/pull/77) ([daffl](https://github.com/daffl))\n\n## [v4.1.0](https://github.com/feathersjs/transport-commons/tree/v4.1.0) (2018-06-28)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v4.0.2...v4.1.0)\n\n**Merged pull requests:**\n\n- Remove empty channels [\\#75](https://github.com/feathersjs/transport-commons/pull/75) ([daffl](https://github.com/daffl))\n\n## [v4.0.2](https://github.com/feathersjs/transport-commons/tree/v4.0.2) (2018-06-12)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v4.0.1...v4.0.2)\n\n**Merged pull requests:**\n\n- Fix looking up invalid path names through sockets [\\#76](https://github.com/feathersjs/transport-commons/pull/76) ([daffl](https://github.com/daffl))\n\n## [v4.0.1](https://github.com/feathersjs/transport-commons/tree/v4.0.1) (2018-05-30)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v4.0.0...v4.0.1)\n\n**Merged pull requests:**\n\n- Update Codeclimate settings [\\#74](https://github.com/feathersjs/transport-commons/pull/74) ([daffl](https://github.com/daffl))\n\n## [v4.0.0](https://github.com/feathersjs/transport-commons/tree/v4.0.0) (2018-02-09)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.2.0...v4.0.0)\n\n**Closed issues:**\n\n- Additional data for client errors [\\#72](https://github.com/feathersjs/transport-commons/issues/72)\n\n**Merged pull requests:**\n\n- Throw a Timeout error on send timeout instead of Error [\\#73](https://github.com/feathersjs/transport-commons/pull/73) ([TimNZ](https://github.com/TimNZ))\n- Pass connection in params [\\#71](https://github.com/feathersjs/transport-commons/pull/71) ([daffl](https://github.com/daffl))\n- Move socket handling into its own file [\\#70](https://github.com/feathersjs/transport-commons/pull/70) ([daffl](https://github.com/daffl))\n\n## [v3.2.0](https://github.com/feathersjs/transport-commons/tree/v3.2.0) (2018-01-30)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.1.5...v3.2.0)\n\n**Closed issues:**\n\n- Publishing to a channel fails after passing safety check [\\#66](https://github.com/feathersjs/transport-commons/issues/66)\n- Feathers Server Ends unexpected if some arg to socket.io is a ipv6 local subnet [\\#65](https://github.com/feathersjs/transport-commons/issues/65)\n\n**Merged pull requests:**\n\n- Rename to @feathersjs/transport-commons [\\#69](https://github.com/feathersjs/transport-commons/pull/69) ([daffl](https://github.com/daffl))\n- Switch to Radix tree based routing [\\#68](https://github.com/feathersjs/transport-commons/pull/68) ([daffl](https://github.com/daffl))\n- Update mocha to the latest version 🚀 [\\#64](https://github.com/feathersjs/transport-commons/pull/64) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update semistandard to the latest version 🚀 [\\#63](https://github.com/feathersjs/transport-commons/pull/63) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.1.5](https://github.com/feathersjs/transport-commons/tree/v3.1.5) (2017-12-12)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.1.4...v3.1.5)\n\n## [v3.1.4](https://github.com/feathersjs/transport-commons/tree/v3.1.4) (2017-12-12)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.1.3...v3.1.4)\n\n**Merged pull requests:**\n\n- Fix dispatching of arrays [\\#62](https://github.com/feathersjs/transport-commons/pull/62) ([daffl](https://github.com/daffl))\n\n## [v3.1.3](https://github.com/feathersjs/transport-commons/tree/v3.1.3) (2017-12-12)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.1.2...v3.1.3)\n\n**Merged pull requests:**\n\n- Make sure that each entry in an array is dispatched as its own even [\\#61](https://github.com/feathersjs/transport-commons/pull/61) ([daffl](https://github.com/daffl))\n\n## [v3.1.2](https://github.com/feathersjs/transport-commons/tree/v3.1.2) (2017-12-06)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.1.1...v3.1.2)\n\n**Merged pull requests:**\n\n- Fix another error when there are no results [\\#60](https://github.com/feathersjs/transport-commons/pull/60) ([daffl](https://github.com/daffl))\n\n## [v3.1.1](https://github.com/feathersjs/transport-commons/tree/v3.1.1) (2017-12-06)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.1.0...v3.1.1)\n\n**Merged pull requests:**\n\n- Always use a combined channel [\\#59](https://github.com/feathersjs/transport-commons/pull/59) ([daffl](https://github.com/daffl))\n\n## [v3.1.0](https://github.com/feathersjs/transport-commons/tree/v3.1.0) (2017-12-06)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.0.1...v3.1.0)\n\n**Merged pull requests:**\n\n- Give channel dispatchers a precedence [\\#58](https://github.com/feathersjs/transport-commons/pull/58) ([daffl](https://github.com/daffl))\n\n## [v3.0.1](https://github.com/feathersjs/transport-commons/tree/v3.0.1) (2017-11-03)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.0.0...v3.0.1)\n\n**Closed issues:**\n\n- Allow socket calls without params and callback [\\#54](https://github.com/feathersjs/transport-commons/issues/54)\n\n**Merged pull requests:**\n\n- Allow socket calls without query and callback [\\#55](https://github.com/feathersjs/transport-commons/pull/55) ([daffl](https://github.com/daffl))\n\n## [v3.0.0](https://github.com/feathersjs/transport-commons/tree/v3.0.0) (2017-11-01)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.0.0-pre.7...v3.0.0)\n\n## [v3.0.0-pre.7](https://github.com/feathersjs/transport-commons/tree/v3.0.0-pre.7) (2017-10-25)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.0.0-pre.6...v3.0.0-pre.7)\n\n**Merged pull requests:**\n\n- Update to better returnHook handling [\\#53](https://github.com/feathersjs/transport-commons/pull/53) ([daffl](https://github.com/daffl))\n\n## [v3.0.0-pre.6](https://github.com/feathersjs/transport-commons/tree/v3.0.0-pre.6) (2017-10-21)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.0.0-pre.5...v3.0.0-pre.6)\n\n**Closed issues:**\n\n- feathers-socket-commons produces error when it get bundled and steal-socket.io gets used as connection [\\#44](https://github.com/feathersjs/transport-commons/issues/44)\n- Surface src/events.js lines 44-69 for feathers-hooks-common/src/filters/combine.js [\\#40](https://github.com/feathersjs/transport-commons/issues/40)\n\n**Merged pull requests:**\n\n- Updates for Feathers v3 \\(Buzzard\\) [\\#52](https://github.com/feathersjs/transport-commons/pull/52) ([daffl](https://github.com/daffl))\n- Rename repository and use npm scope [\\#51](https://github.com/feathersjs/transport-commons/pull/51) ([daffl](https://github.com/daffl))\n\n## [v3.0.0-pre.5](https://github.com/feathersjs/transport-commons/tree/v3.0.0-pre.5) (2017-10-18)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.0.0-pre.4...v3.0.0-pre.5)\n\n**Merged pull requests:**\n\n- Pass events property to the client [\\#50](https://github.com/feathersjs/transport-commons/pull/50) ([daffl](https://github.com/daffl))\n\n## [v3.0.0-pre.4](https://github.com/feathersjs/transport-commons/tree/v3.0.0-pre.4) (2017-10-17)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.0.0-pre.3...v3.0.0-pre.4)\n\n**Merged pull requests:**\n\n- Fix the event name and add some channel debug statements [\\#49](https://github.com/feathersjs/transport-commons/pull/49) ([daffl](https://github.com/daffl))\n\n## [v3.0.0-pre.3](https://github.com/feathersjs/transport-commons/tree/v3.0.0-pre.3) (2017-10-16)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.0.0-pre.2...v3.0.0-pre.3)\n\n**Merged pull requests:**\n\n- Update mocha to the latest version 🚀 [\\#48](https://github.com/feathersjs/transport-commons/pull/48) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v3.0.0-pre.2](https://github.com/feathersjs/transport-commons/tree/v3.0.0-pre.2) (2017-09-28)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v3.0.0-pre.1...v3.0.0-pre.2)\n\n**Merged pull requests:**\n\n- Add feathers-channels [\\#47](https://github.com/feathersjs/transport-commons/pull/47) ([daffl](https://github.com/daffl))\n\n## [v3.0.0-pre.1](https://github.com/feathersjs/transport-commons/tree/v3.0.0-pre.1) (2017-09-08)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v2.4.0...v3.0.0-pre.1)\n\n**Fixed bugs:**\n\n- Socket events don't fire for sub-apps nested more than 2 deep [\\#5](https://github.com/feathersjs/transport-commons/issues/5)\n\n**Closed issues:**\n\n- more tests [\\#38](https://github.com/feathersjs/transport-commons/issues/38)\n\n**Merged pull requests:**\n\n- Prepare v3.0-pre [\\#46](https://github.com/feathersjs/transport-commons/pull/46) ([daffl](https://github.com/daffl))\n- Update debug to the latest version 🚀 [\\#45](https://github.com/feathersjs/transport-commons/pull/45) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update feathers-socketio to the latest version 🚀 [\\#43](https://github.com/feathersjs/transport-commons/pull/43) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update semistandard to the latest version 🚀 [\\#42](https://github.com/feathersjs/transport-commons/pull/42) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n- Update dependencies to enable Greenkeeper 🌴 [\\#41](https://github.com/feathersjs/transport-commons/pull/41) ([greenkeeper[bot]](https://github.com/apps/greenkeeper))\n\n## [v2.4.0](https://github.com/feathersjs/transport-commons/tree/v2.4.0) (2017-01-07)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v2.3.1...v2.4.0)\n\n**Implemented enhancements:**\n\n- support service.json [\\#34](https://github.com/feathersjs/transport-commons/issues/34)\n- Socket event filters should not force returning data [\\#4](https://github.com/feathersjs/transport-commons/issues/4)\n- bootstrap service.filters [\\#37](https://github.com/feathersjs/transport-commons/pull/37) ([slajax](https://github.com/slajax))\n\n**Closed issues:**\n\n- Sockets timed out request - retry on reconnection \\[feat?\\] [\\#32](https://github.com/feathersjs/transport-commons/issues/32)\n\n**Merged pull requests:**\n\n- Normalize arguments when client sends packed data. [\\#39](https://github.com/feathersjs/transport-commons/pull/39) ([devel-pa](https://github.com/devel-pa))\n- Create .codeclimate.yml [\\#33](https://github.com/feathersjs/transport-commons/pull/33) ([larkinscott](https://github.com/larkinscott))\n- Update feathers-commons to version 0.8.0 🚀 [\\#31](https://github.com/feathersjs/transport-commons/pull/31) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- jshint —\\> semistandard [\\#30](https://github.com/feathersjs/transport-commons/pull/30) ([corymsmith](https://github.com/corymsmith))\n- Code coverage [\\#29](https://github.com/feathersjs/transport-commons/pull/29) ([ekryski](https://github.com/ekryski))\n\n## [v2.3.1](https://github.com/feathersjs/transport-commons/tree/v2.3.1) (2016-09-02)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v2.3.0...v2.3.1)\n\n**Merged pull requests:**\n\n- Make service off method be namespaced [\\#26](https://github.com/feathersjs/transport-commons/pull/26) ([t2t2](https://github.com/t2t2))\n- Update mocha to version 3.0.0 🚀 [\\#25](https://github.com/feathersjs/transport-commons/pull/25) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v2.3.0](https://github.com/feathersjs/transport-commons/tree/v2.3.0) (2016-07-24)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v2.2.1...v2.3.0)\n\n**Fixed bugs:**\n\n- Error in filter chain for 'created' event after app.authenticate\\(\\) [\\#12](https://github.com/feathersjs/transport-commons/issues/12)\n\n**Merged pull requests:**\n\n- Skip subsequent filters instead of rejecting the promise [\\#24](https://github.com/feathersjs/transport-commons/pull/24) ([daffl](https://github.com/daffl))\n\n## [v2.2.1](https://github.com/feathersjs/transport-commons/tree/v2.2.1) (2016-07-05)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v2.2.0...v2.2.1)\n\n## [v2.2.0](https://github.com/feathersjs/transport-commons/tree/v2.2.0) (2016-07-05)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v2.1.0...v2.2.0)\n\n**Implemented enhancements:**\n\n- Support native websockets directly [\\#8](https://github.com/feathersjs/transport-commons/issues/8)\n\n**Fixed bugs:**\n\n- Calling `off` on primus fails [\\#7](https://github.com/feathersjs/transport-commons/issues/7)\n\n**Closed issues:**\n\n- Should add other eventEmitter methods [\\#22](https://github.com/feathersjs/transport-commons/issues/22)\n- Patch event sends the whole data back [\\#21](https://github.com/feathersjs/transport-commons/issues/21)\n\n**Merged pull requests:**\n\n- Pass all EventEmitter methods to the client connection [\\#23](https://github.com/feathersjs/transport-commons/pull/23) ([daffl](https://github.com/daffl))\n\n## [v2.1.0](https://github.com/feathersjs/transport-commons/tree/v2.1.0) (2016-05-29)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v2.0.0...v2.1.0)\n\n**Closed issues:**\n\n- Client should convert error objects to feathers-errors [\\#19](https://github.com/feathersjs/transport-commons/issues/19)\n\n**Merged pull requests:**\n\n- Make client convert to feathers-errors [\\#20](https://github.com/feathersjs/transport-commons/pull/20) ([daffl](https://github.com/daffl))\n\n## [v2.0.0](https://github.com/feathersjs/transport-commons/tree/v2.0.0) (2016-05-23)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v1.0.0...v2.0.0)\n\n**Merged pull requests:**\n\n- Better handling of sub-apps and sockets [\\#18](https://github.com/feathersjs/transport-commons/pull/18) ([daffl](https://github.com/daffl))\n- Update babel-plugin-add-module-exports to version 0.2.0 🚀 [\\#17](https://github.com/feathersjs/transport-commons/pull/17) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n- babel-polyfill@6.7.4 breaks build 🚨 [\\#16](https://github.com/feathersjs/transport-commons/pull/16) ([greenkeeperio-bot](https://github.com/greenkeeperio-bot))\n\n## [v1.0.0](https://github.com/feathersjs/transport-commons/tree/v1.0.0) (2016-04-28)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v0.2.3...v1.0.0)\n\n**Implemented enhancements:**\n\n- Support acknowledgement timeouts [\\#9](https://github.com/feathersjs/transport-commons/issues/9)\n\n**Closed issues:**\n\n- Feathers over sockets is totally silent when a hook has errors [\\#13](https://github.com/feathersjs/transport-commons/issues/13)\n- Listener warning when you register your own events on the socket [\\#10](https://github.com/feathersjs/transport-commons/issues/10)\n\n**Merged pull requests:**\n\n- Support timeouts for socket clients [\\#15](https://github.com/feathersjs/transport-commons/pull/15) ([daffl](https://github.com/daffl))\n- Convert errors in socket callbacks [\\#14](https://github.com/feathersjs/transport-commons/pull/14) ([daffl](https://github.com/daffl))\n\n## [v0.2.3](https://github.com/feathersjs/transport-commons/tree/v0.2.3) (2016-04-16)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v0.2.2...v0.2.3)\n\n**Merged pull requests:**\n\n- Remove connection setMaxListeners [\\#11](https://github.com/feathersjs/transport-commons/pull/11) ([daffl](https://github.com/daffl))\n\n## [v0.2.2](https://github.com/feathersjs/transport-commons/tree/v0.2.2) (2016-03-22)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v0.2.1...v0.2.2)\n\n**Merged pull requests:**\n\n- Allow chaining event listeners. [\\#6](https://github.com/feathersjs/transport-commons/pull/6) ([joshuajabbour](https://github.com/joshuajabbour))\n\n## [v0.2.1](https://github.com/feathersjs/transport-commons/tree/v0.2.1) (2016-03-08)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v0.2.0...v0.2.1)\n\n**Merged pull requests:**\n\n- Set connection max listeners and better debug messages [\\#3](https://github.com/feathersjs/transport-commons/pull/3) ([daffl](https://github.com/daffl))\n\n## [v0.2.0](https://github.com/feathersjs/transport-commons/tree/v0.2.0) (2016-02-08)\n\n[Full Changelog](https://github.com/feathersjs/transport-commons/compare/v0.1.0...v0.2.0)\n\n**Merged pull requests:**\n\n- Query params [\\#2](https://github.com/feathersjs/transport-commons/pull/2) ([ekryski](https://github.com/ekryski))\n- Adding nsp check [\\#1](https://github.com/feathersjs/transport-commons/pull/1) ([marshallswain](https://github.com/marshallswain))\n\n## [v0.1.0](https://github.com/feathersjs/transport-commons/tree/v0.1.0) (2016-01-21)\n\n\\* _This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)_\n"
  },
  {
    "path": "packages/transport-commons/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "packages/transport-commons/README.md",
    "content": "# @feathersjs/transport-commons\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/transport-commons.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/transport-commons)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> Shared functionality for Feathers API transports like `@feathers/socketio` and `@feathersjs/primus`. Only intended to be used internally.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/transport-commons/client.d.ts",
    "content": "export * from './lib/client'\n"
  },
  {
    "path": "packages/transport-commons/client.js",
    "content": "module.exports = require('./lib/client');"
  },
  {
    "path": "packages/transport-commons/package.json",
    "content": "{\n  \"name\": \"@feathersjs/transport-commons\",\n  \"description\": \"Shared functionality for websocket providers\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/transport-commons\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"test\": \"npm run mocha\",\n    \"mocha\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"dependencies\": {\n    \"@feathersjs/commons\": \"^5.0.42\",\n    \"@feathersjs/errors\": \"^5.0.42\",\n    \"@feathersjs/feathers\": \"^5.0.42\",\n    \"encodeurl\": \"^2.0.0\",\n    \"lodash\": \"^4.17.23\"\n  },\n  \"devDependencies\": {\n    \"@types/encodeurl\": \"^1.0.3\",\n    \"@types/lodash\": \"^4.17.24\",\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"ts-node\": \"^10.9.2\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/transport-commons/src/channels/channel/base.ts",
    "content": "import { EventEmitter } from 'events'\nimport { RealTimeConnection } from '@feathersjs/feathers'\n\nexport class Channel extends EventEmitter {\n  connections: RealTimeConnection[]\n  data: any\n\n  constructor(connections: RealTimeConnection[] = [], data: any = null) {\n    super()\n\n    this.connections = connections\n    this.data = data\n  }\n\n  get length() {\n    return this.connections.length\n  }\n\n  leave(...connections: RealTimeConnection[]) {\n    connections.forEach((current) => {\n      if (typeof current === 'function') {\n        const callback = current as (connection: RealTimeConnection) => boolean\n\n        this.leave(...this.connections.filter(callback))\n      } else {\n        const index = this.connections.indexOf(current)\n\n        if (index !== -1) {\n          this.connections.splice(index, 1)\n        }\n      }\n    })\n\n    if (this.length === 0) {\n      this.emit('empty')\n    }\n\n    return this\n  }\n\n  join(...connections: RealTimeConnection[]) {\n    connections.forEach((connection) => {\n      if (connection && this.connections.indexOf(connection) === -1) {\n        this.connections.push(connection)\n      }\n    })\n\n    return this\n  }\n\n  filter(fn: (connection: RealTimeConnection) => boolean) {\n    return new Channel(this.connections.filter(fn), this.data)\n  }\n\n  send(data: any) {\n    return new Channel(this.connections, data)\n  }\n}\n"
  },
  {
    "path": "packages/transport-commons/src/channels/channel/combined.ts",
    "content": "import { RealTimeConnection } from '@feathersjs/feathers'\nimport { Channel } from './base'\n\nfunction collectConnections(children: Channel[]) {\n  const mappings = new WeakMap<RealTimeConnection, any>()\n  const connections: RealTimeConnection[] = []\n\n  children.forEach((channel) => {\n    channel.connections.forEach((connection) => {\n      if (!mappings.has(connection)) {\n        connections.push(connection)\n        mappings.set(connection, channel.data)\n      }\n    })\n  })\n\n  return { connections, mappings }\n}\n\nexport class CombinedChannel extends Channel {\n  children: Channel[]\n  mappings: WeakMap<RealTimeConnection, any>\n\n  constructor(children: Channel[], data: any = null) {\n    const { mappings, connections } = collectConnections(children)\n\n    super(connections, data)\n\n    this.children = children\n    this.mappings = mappings\n  }\n\n  refresh() {\n    const collected = collectConnections(this.children)\n\n    return Object.assign(this, collected)\n  }\n\n  leave(...connections: RealTimeConnection[]) {\n    return this.callChildren('leave', connections)\n  }\n\n  join(...connections: RealTimeConnection[]) {\n    return this.callChildren('join', connections)\n  }\n\n  dataFor(connection: RealTimeConnection) {\n    return this.mappings.get(connection)\n  }\n\n  private callChildren(method: string, connections: RealTimeConnection[]) {\n    this.children.forEach((child: any) => child[method](...connections))\n    this.refresh()\n\n    return this\n  }\n}\n"
  },
  {
    "path": "packages/transport-commons/src/channels/index.ts",
    "content": "import { Application, FeathersService, RealTimeConnection, getServiceOptions } from '@feathersjs/feathers'\nimport { createDebug } from '@feathersjs/commons'\nimport flattenDeep from 'lodash/flattenDeep'\nimport { Channel } from './channel/base'\nimport { CombinedChannel } from './channel/combined'\nimport { channelMixin, publishMixin, keys, PublishMixin, Event, Publisher } from './mixins'\nimport EventEmitter from 'events'\n\nconst debug = createDebug('@feathersjs/transport-commons/channels')\nconst { CHANNELS } = keys\n\ndeclare module '@feathersjs/feathers/lib/declarations' {\n  interface ServiceAddons<A, S> extends EventEmitter {\n    // eslint-disable-line\n    publish(publisher: Publisher<ServiceGenericType<S>, A, this>): this\n    publish(event: Event, publisher: Publisher<ServiceGenericType<S>, A, this>): this\n\n    registerPublisher(publisher: Publisher<ServiceGenericType<S>, A, this>): this\n    registerPublisher(event: Event, publisher: Publisher<ServiceGenericType<S>, A, this>): this\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  interface Application<Services, Settings> {\n    // eslint-disable-line\n    channels: string[]\n\n    channel(name: string | string[]): Channel\n    channel(...names: string[]): Channel\n\n    publish<T>(publisher: Publisher<T, this>): this\n    publish<T>(event: Event, publisher: Publisher<T, this>): this\n\n    registerPublisher<T>(publisher: Publisher<T, this>): this\n    registerPublisher<T>(event: Event, publisher: Publisher<T, this>): this\n  }\n\n  interface Params {\n    connection?: RealTimeConnection\n  }\n}\n\nexport { keys }\n\nexport function channels() {\n  return (app: Application) => {\n    if (typeof app.channel === 'function' && typeof app.publish === 'function') {\n      return\n    }\n\n    Object.assign(app, channelMixin(), publishMixin())\n    Object.defineProperty(app, 'channels', {\n      get() {\n        return Object.keys(this[CHANNELS])\n      }\n    })\n\n    app.mixins.push((service: FeathersService, path: string) => {\n      const { serviceEvents } = getServiceOptions(service)\n\n      if (typeof service.publish === 'function') {\n        return\n      }\n\n      Object.assign(service, publishMixin())\n\n      serviceEvents.forEach((event: string) => {\n        service.on(event, function (data, hook) {\n          if (!hook) {\n            // Fake hook for custom events\n            hook = { path, service, app, result: data }\n          }\n\n          debug('Publishing event', event, hook.path)\n\n          const logError = (error: any) => debug(`Error in '${hook.path} ${event}' publisher`, error)\n          const servicePublishers = (service as unknown as PublishMixin)[keys.PUBLISHERS]\n          const appPublishers = (app as unknown as PublishMixin)[keys.PUBLISHERS]\n          // This will return the first publisher list that is not empty\n          // In the following precedence\n          const publisher =\n            // 1. Service publisher for a specific event\n            servicePublishers[event] ||\n            // 2. Service publisher for all events\n            servicePublishers[keys.ALL_EVENTS] ||\n            // 3. App publisher for a specific event\n            appPublishers[event] ||\n            // 4. App publisher for all events\n            appPublishers[keys.ALL_EVENTS] ||\n            // 5. No publisher\n            (() => {})\n\n          try {\n            Promise.resolve(publisher(data, hook))\n              .then((result: any) => {\n                if (!result) {\n                  return\n                }\n\n                const results = Array.isArray(result)\n                  ? flattenDeep(result).filter(Boolean)\n                  : ([result] as Channel[])\n                const channel = new CombinedChannel(results)\n\n                if (channel && channel.length > 0) {\n                  app.emit('publish', event, channel, hook, data)\n                } else {\n                  debug('No connections to publish to')\n                }\n              })\n              .catch(logError)\n          } catch (error: any) {\n            logError(error)\n          }\n        })\n      })\n    })\n  }\n}\n\nexport { Channel, CombinedChannel, RealTimeConnection }\n"
  },
  {
    "path": "packages/transport-commons/src/channels/mixins.ts",
    "content": "/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */\nimport { Application, HookContext, getServiceOptions, defaultServiceEvents } from '@feathersjs/feathers'\nimport { createDebug } from '@feathersjs/commons'\nimport { Channel } from './channel/base'\nimport { CombinedChannel } from './channel/combined'\n\nconst debug = createDebug('@feathersjs/transport-commons/channels/mixins')\nconst PUBLISHERS = Symbol.for('@feathersjs/transport-commons/publishers')\nconst CHANNELS = Symbol.for('@feathersjs/transport-commons/channels')\nconst ALL_EVENTS = Symbol.for('@feathersjs/transport-commons/all-events')\n\nexport const keys = {\n  PUBLISHERS: PUBLISHERS as typeof PUBLISHERS,\n  CHANNELS: CHANNELS as typeof CHANNELS,\n  ALL_EVENTS: ALL_EVENTS as typeof ALL_EVENTS\n}\n\nexport interface ChannelMixin {\n  [CHANNELS]: { [key: string]: Channel }\n  channel(...names: string[]): Channel\n}\n\nexport function channelMixin() {\n  const mixin: ChannelMixin = {\n    [CHANNELS]: {},\n\n    channel(...names: string[]): Channel {\n      debug('Returning channels', names)\n\n      if (names.length === 0) {\n        throw new Error('app.channel needs at least one channel name')\n      }\n\n      if (names.length === 1) {\n        const [name] = names\n\n        if (Array.isArray(name)) {\n          return this.channel(...name)\n        }\n\n        if (!this[CHANNELS][name]) {\n          const channel = new Channel()\n\n          channel.once('empty', () => {\n            channel.removeAllListeners()\n            delete this[CHANNELS][name]\n          })\n\n          this[CHANNELS][name] = channel\n        }\n\n        return this[CHANNELS][name]\n      }\n\n      const channels = names.map((name) => this.channel(name))\n\n      return new CombinedChannel(channels)\n    }\n  }\n\n  return mixin\n}\n\nexport type Event = string | typeof ALL_EVENTS\n\nexport type Publisher<T = any, A = Application, S = any> = (\n  data: T,\n  context: HookContext<A, S>\n) => Channel | Channel[] | void | Promise<Channel | Channel[] | void>\n\nexport interface PublishMixin<T = any> {\n  [PUBLISHERS]: { [ALL_EVENTS]?: Publisher<T>; [key: string]: Publisher<T> }\n  publish(event: Event, publisher: Publisher<T>): this\n  registerPublisher(event: Event, publisher: Publisher<T>): this\n}\n\nexport function publishMixin() {\n  const result: PublishMixin = {\n    [PUBLISHERS]: {},\n\n    publish(...args) {\n      return this.registerPublisher(...args)\n    },\n\n    registerPublisher(event, publisher) {\n      debug('Registering publisher', event)\n\n      if (!publisher && typeof event === 'function') {\n        publisher = event\n        event = ALL_EVENTS\n      }\n\n      const { serviceEvents = defaultServiceEvents } = getServiceOptions(this) || {}\n\n      if (event !== ALL_EVENTS && !serviceEvents.includes(event)) {\n        throw new Error(`'${event.toString()}' is not a valid service event`)\n      }\n\n      const publishers = this[PUBLISHERS]\n\n      publishers[event] = publisher\n\n      return this\n    }\n  }\n\n  return result\n}\n"
  },
  {
    "path": "packages/transport-commons/src/client.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport { BadRequest, convert } from '@feathersjs/errors'\nimport { createDebug } from '@feathersjs/commons'\nimport { Id, NullableId, Params, ServiceInterface } from '@feathersjs/feathers'\n\nconst debug = createDebug('@feathersjs/transport-commons/client')\n\nconst namespacedEmitterMethods = [\n  'addListener',\n  'addEventListener',\n  'emit',\n  'listenerCount',\n  'listeners',\n  'on',\n  'once',\n  'prependListener',\n  'prependOnceListener',\n  'removeAllListeners',\n  'removeEventListener',\n  'removeListener'\n]\nconst otherEmitterMethods = ['eventNames', 'getMaxListeners', 'setMaxListeners']\n\nconst addEmitterMethods = (service: any) => {\n  otherEmitterMethods.forEach((method) => {\n    service[method] = function (...args: any[]) {\n      if (typeof this.connection[method] !== 'function') {\n        throw new Error(`Can not call '${method}' on the client service connection`)\n      }\n\n      return this.connection[method](...args)\n    }\n  })\n\n  // Methods that should add the namespace (service path)\n  namespacedEmitterMethods.forEach((method) => {\n    service[method] = function (name: string, ...args: any[]) {\n      if (typeof this.connection[method] !== 'function') {\n        throw new Error(`Can not call '${method}' on the client service connection`)\n      }\n\n      const eventName = `${this.path} ${name}`\n\n      debug(`Calling emitter method ${method} with ` + `namespaced event '${eventName}'`)\n\n      const result = this.connection[method](eventName, ...args)\n\n      return result === this.connection ? this : result\n    }\n  })\n}\n\ninterface ServiceOptions {\n  name: string\n  connection: any\n  method: string\n  events?: string[]\n}\n\nexport type SocketService<T = any, D = Partial<any>, P extends Params = Params> = Service<T, D, P>\n\nexport class Service<T = any, D = Partial<T>, P extends Params = Params> implements ServiceInterface<\n  T,\n  D,\n  P\n> {\n  events: string[]\n  path: string\n  connection: any\n  method: string\n\n  constructor(options: ServiceOptions) {\n    this.events = options.events\n    this.path = options.name\n    this.connection = options.connection\n    this.method = options.method\n\n    addEmitterMethods(this)\n  }\n\n  send<X = any>(method: string, ...args: any[]) {\n    return new Promise<X>((resolve, reject) => {\n      const route: Record<string, any> = args.pop()\n      let path = this.path\n      if (route) {\n        Object.keys(route).forEach((key) => {\n          path = path.replace(`:${key}`, route[key])\n        })\n      }\n      args.unshift(method, path)\n\n      const socketTimeout = this.connection.flags?.timeout || this.connection._opts?.ackTimeout\n      if (socketTimeout !== undefined) {\n        args.push(function (timeoutError: any, error: any, data: any) {\n          return timeoutError || error ? reject(convert(timeoutError || error)) : resolve(data)\n        })\n      } else {\n        args.push(function (error: any, data: any) {\n          return error ? reject(convert(error)) : resolve(data)\n        })\n      }\n\n      debug(`Sending socket.${this.method}`, args)\n\n      this.connection[this.method](...args)\n    })\n  }\n\n  methods(this: any, ...names: string[]) {\n    names.forEach((method) => {\n      const _method = `_${method}`\n      this[_method] = function (data: any, params: Params = {}) {\n        return this.send(method, data, params.query || {}, params.route || {})\n      }\n      this[method] = function (data: any, params: Params = {}) {\n        return this[_method](data, params, params.route || {})\n      }\n    })\n    return this\n  }\n\n  _find(params: Params = {}) {\n    return this.send<T | T[]>('find', params.query || {}, params.route || {})\n  }\n\n  find(params: Params = {}) {\n    return this._find(params)\n  }\n\n  _get(id: Id, params: Params = {}) {\n    if (id === undefined || id === '') {\n      return Promise.reject(new BadRequest('id for .get is required'))\n    }\n\n    return this.send<T>('get', id, params.query || {}, params.route || {})\n  }\n\n  get(id: Id, params: Params = {}) {\n    return this._get(id, params)\n  }\n\n  _create(data: D, params: Params = {}) {\n    return this.send<T>('create', data, params.query || {}, params.route || {})\n  }\n\n  create(data: D, params: Params = {}) {\n    return this._create(data, params)\n  }\n\n  _update(id: NullableId, data: D, params: Params = {}) {\n    if (id === undefined || id === '') {\n      return Promise.reject(new BadRequest('id for .update is required'))\n    }\n\n    return this.send<T>('update', id, data, params.query || {}, params.route || {})\n  }\n\n  update(id: NullableId, data: D, params: Params = {}) {\n    if (id === undefined || id === '') {\n      return Promise.reject(new BadRequest('id for .update is required'))\n    }\n\n    return this._update(id, data, params)\n  }\n\n  _patch(id: NullableId, data: D, params: Params = {}) {\n    if (id === undefined || id === '') {\n      return Promise.reject(new BadRequest('id for .patch is required'))\n    }\n\n    return this.send<T | T[]>('patch', id, data, params.query || {}, params.route || {})\n  }\n\n  patch(id: NullableId, data: D, params: Params = {}) {\n    return this._patch(id, data, params)\n  }\n\n  _remove(id: NullableId, params: Params = {}) {\n    if (id === undefined || id === '') {\n      return Promise.reject(new BadRequest('id for .remove is required'))\n    }\n\n    return this.send<T | T[]>('remove', id, params.query || {}, params.route || {})\n  }\n\n  remove(id: NullableId, params: Params = {}) {\n    return this._remove(id, params)\n  }\n\n  // `off` is actually not part of the Node event emitter spec\n  // but we are adding it since everybody is expecting it because\n  // of the emitter-component Socket.io is using\n  off(name: string, ...args: any[]) {\n    if (typeof this.connection.off === 'function') {\n      const result = this.connection.off(`${this.path} ${name}`, ...args)\n\n      return result === this.connection ? this : result\n    } else if (args.length === 0) {\n      // @ts-ignore\n      return this.removeAllListeners(name)\n    }\n\n    // @ts-ignore\n    return this.removeListener(name, ...args)\n  }\n}\n"
  },
  {
    "path": "packages/transport-commons/src/http.ts",
    "content": "import { MethodNotAllowed } from '@feathersjs/errors/lib'\nimport { HookContext, NullableId, Params } from '@feathersjs/feathers'\nimport encodeUrl from 'encodeurl'\n\nexport const METHOD_HEADER = 'x-service-method'\n\nexport interface ServiceParams {\n  id: NullableId\n  data: any\n  params: Params\n}\n\nexport const statusCodes = {\n  created: 201,\n  noContent: 204,\n  methodNotAllowed: 405,\n  success: 200,\n  seeOther: 303\n}\n\nexport const knownMethods: { [key: string]: string } = {\n  post: 'create',\n  patch: 'patch',\n  put: 'update',\n  delete: 'remove'\n}\n\nexport function getServiceMethod(_httpMethod: string, id: unknown, headerOverride?: string) {\n  const httpMethod = _httpMethod.toLowerCase()\n\n  if (httpMethod === 'post' && headerOverride) {\n    return headerOverride\n  }\n\n  const mappedMethod = knownMethods[httpMethod]\n\n  if (mappedMethod) {\n    return mappedMethod\n  }\n\n  if (httpMethod === 'get') {\n    return id === null ? 'find' : 'get'\n  }\n\n  throw new MethodNotAllowed(`Method ${_httpMethod} not allowed`)\n}\n\nexport const argumentsFor = {\n  get: ({ id, params }: ServiceParams) => [id, params],\n  find: ({ params }: ServiceParams) => [params],\n  create: ({ data, params }: ServiceParams) => [data, params],\n  update: ({ id, data, params }: ServiceParams) => [id, data, params],\n  patch: ({ id, data, params }: ServiceParams) => [id, data, params],\n  remove: ({ id, params }: ServiceParams) => [id, params],\n  default: ({ data, params }: ServiceParams) => [data, params]\n}\n\nexport function getStatusCode(context: HookContext, body: any, location: string | string[]) {\n  const { http = {} } = context\n\n  if (http.status) {\n    return http.status\n  }\n\n  if (location !== undefined) {\n    return statusCodes.seeOther\n  }\n\n  if (!body) {\n    return statusCodes.noContent\n  }\n\n  if (context.method === 'create') {\n    return statusCodes.created\n  }\n\n  return statusCodes.success\n}\n\nexport function getResponse(context: HookContext) {\n  const { http = {} } = context\n  const body = context.dispatch !== undefined ? context.dispatch : context.result\n\n  let headers = http.headers || {}\n  let location = headers.Location\n\n  if (http.location !== undefined) {\n    location = encodeUrl(http.location)\n    headers = { ...headers, Location: location }\n  }\n\n  const status = getStatusCode(context, body, location)\n\n  return { status, headers, body }\n}\n"
  },
  {
    "path": "packages/transport-commons/src/index.ts",
    "content": "import { socket } from './socket'\nimport { routing } from './routing'\nimport { channels, Channel, CombinedChannel } from './channels'\nimport { RealTimeConnection } from '@feathersjs/feathers'\n\nexport * as http from './http'\nexport { socket, routing, channels, Channel, CombinedChannel, RealTimeConnection }\n"
  },
  {
    "path": "packages/transport-commons/src/routing/index.ts",
    "content": "import { Application, FeathersService, ServiceOptions } from '@feathersjs/feathers'\nimport { Router } from './router'\n\ndeclare module '@feathersjs/feathers/lib/declarations' {\n  interface RouteLookup {\n    service: Service\n    params: { [key: string]: any }\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  interface Application<Services, Settings> {\n    // eslint-disable-line\n    routes: Router<{\n      service: Service\n      params?: { [key: string]: any }\n    }>\n    lookup(path: string): RouteLookup\n  }\n}\n\nexport * from './router'\n\nconst lookup = function (this: Application, path: string) {\n  const result = this.routes.lookup(path)\n\n  if (result === null) {\n    return null\n  }\n\n  const {\n    params: colonParams,\n    data: { service, params: dataParams }\n  } = result\n\n  const params = dataParams ? { ...dataParams, ...colonParams } : colonParams\n\n  return { service, params }\n}\n\nexport const routing = () => (app: Application) => {\n  if (typeof app.lookup === 'function') {\n    return\n  }\n\n  const { unuse } = app\n\n  app.routes = new Router()\n  app.lookup = lookup\n  app.unuse = function (path: string) {\n    app.routes.remove(path)\n    app.routes.remove(`${path}/:__id`)\n    return unuse.call(this, path)\n  }\n\n  // Add a mixin that registers a service on the router\n  app.mixins.push((service: FeathersService, path: string, options: ServiceOptions) => {\n    const { routeParams: params = {} } = options\n\n    app.routes.insert(path, { service, params })\n    app.routes.insert(`${path}/:__id`, { service, params })\n  })\n}\n"
  },
  {
    "path": "packages/transport-commons/src/routing/router.ts",
    "content": "import { stripSlashes } from '@feathersjs/commons'\n\nexport interface LookupData {\n  params: { [key: string]: string }\n}\n\nexport interface LookupResult<T> extends LookupData {\n  data?: T\n}\n\nexport class RouteNode<T = any> {\n  data?: T\n  children: { [key: string]: RouteNode } = {}\n  placeholders: RouteNode[] = []\n\n  constructor(\n    public name: string,\n    public depth: number\n  ) {}\n\n  get hasChildren() {\n    return Object.keys(this.children).length !== 0 || this.placeholders.length !== 0\n  }\n\n  insert(path: string[], data: T): RouteNode<T> {\n    if (this.depth === path.length) {\n      if (this.data !== undefined) {\n        throw new Error(`Path ${path.join('/')} already exists`)\n      }\n\n      this.data = data\n      return this\n    }\n\n    const current = path[this.depth]\n    const nextDepth = this.depth + 1\n\n    if (current.startsWith(':')) {\n      // Insert a placeholder node like /messages/:id\n      const placeholderName = current.substring(1)\n      let placeholder = this.placeholders.find((p) => p.name === placeholderName)\n\n      if (!placeholder) {\n        placeholder = new RouteNode(placeholderName, nextDepth)\n        this.placeholders.push(placeholder)\n      }\n\n      return placeholder.insert(path, data)\n    }\n\n    const child = this.children[current] || new RouteNode(current, nextDepth)\n\n    this.children[current] = child\n\n    return child.insert(path, data)\n  }\n\n  remove(path: string[]) {\n    if (path.length === this.depth) {\n      delete this.data\n      return\n    }\n\n    const current = path[this.depth]\n\n    if (current.startsWith(':')) {\n      const placeholderName = current.substring(1)\n      const placeholder = this.placeholders.find((p) => p.name === placeholderName)\n\n      placeholder.remove(path)\n      this.placeholders = this.placeholders.filter((p) => p !== placeholder)\n    } else if (this.children[current]) {\n      const child = this.children[current]\n\n      child.remove(path)\n\n      if (!child.hasChildren) {\n        delete this.children[current]\n      }\n    }\n  }\n\n  lookup(path: string[], info: LookupData): LookupResult<T> | null {\n    if (path.length === this.depth) {\n      return this.data === undefined\n        ? null\n        : {\n            ...info,\n            data: this.data\n          }\n    }\n\n    const current = path[this.depth]\n    const child = this.children[current]\n\n    if (child) {\n      const lookup = child.lookup(path, info)\n\n      if (lookup !== null) {\n        return lookup\n      }\n    }\n\n    // This will return the first placeholder that matches early\n    for (const placeholder of this.placeholders) {\n      const result = placeholder.lookup(path, info)\n\n      if (result !== null) {\n        result.params[placeholder.name] = current\n        return result\n      }\n    }\n\n    return null\n  }\n}\n\nexport class Router<T = any> {\n  public caseSensitive = true\n\n  constructor(public root: RouteNode<T> = new RouteNode<T>('', 0)) {}\n\n  getPath(path: string) {\n    const result = stripSlashes(path).split('/')\n\n    if (!this.caseSensitive) {\n      return result.map((p) => (p.startsWith(':') ? p : p.toLowerCase()))\n    }\n\n    return result\n  }\n\n  insert(path: string, data: T) {\n    return this.root.insert(this.getPath(path), data)\n  }\n\n  remove(path: string) {\n    return this.root.remove(this.getPath(path))\n  }\n\n  lookup(path: string) {\n    if (typeof path !== 'string') {\n      return null\n    }\n\n    return this.root.lookup(this.getPath(path), { params: {} })\n  }\n}\n"
  },
  {
    "path": "packages/transport-commons/src/socket/index.ts",
    "content": "import { Application, getServiceOptions, Params, RealTimeConnection } from '@feathersjs/feathers'\nimport { channels } from '../channels'\nimport { routing } from '../routing'\nimport { getDispatcher, runMethod } from './utils'\n\nexport interface SocketOptions {\n  done: Promise<any>\n  emit: string\n  socketMap: WeakMap<RealTimeConnection, any>\n  socketKey?: any\n  getParams: (socket: any) => RealTimeConnection\n}\n\nexport function socket({ done, emit, socketMap, socketKey, getParams }: SocketOptions) {\n  return (app: Application) => {\n    const leaveChannels = (connection: RealTimeConnection) => {\n      const { channels } = app\n\n      if (channels.length) {\n        app.channel(app.channels).leave(connection)\n      }\n    }\n\n    app.configure(channels())\n    app.configure(routing())\n\n    app.on('publish', getDispatcher(emit, socketMap, socketKey))\n    app.on('disconnect', leaveChannels)\n    app.on('logout', (_authResult: any, params: Params) => {\n      const { connection } = params\n\n      if (connection) {\n        leaveChannels(connection)\n      }\n    })\n\n    // `connection` event\n    done.then((provider) =>\n      provider.on('connection', (connection: any) => app.emit('connection', getParams(connection)))\n    )\n\n    // `socket.emit('methodName', 'serviceName', ...args)` handlers\n    done.then((provider) =>\n      provider.on('connection', (connection: any) => {\n        const methodHandlers = Object.keys(app.services).reduce((result, name) => {\n          const { methods } = getServiceOptions(app.service(name))\n\n          methods.forEach((method) => {\n            if (!result[method]) {\n              result[method] = (...args: any[]) => {\n                const [path, ...rest] = args\n\n                runMethod(app, getParams(connection), path, method, rest)\n              }\n            }\n          })\n\n          return result\n        }, {} as any)\n\n        Object.keys(methodHandlers).forEach((key) => connection.on(key, methodHandlers[key]))\n      })\n    )\n  }\n}\n"
  },
  {
    "path": "packages/transport-commons/src/socket/utils.ts",
    "content": "import {\n  HookContext,\n  Application,\n  RealTimeConnection,\n  createContext,\n  getServiceOptions\n} from '@feathersjs/feathers'\nimport { NotFound, MethodNotAllowed, BadRequest } from '@feathersjs/errors'\nimport { createDebug } from '@feathersjs/commons'\nimport isEqual from 'lodash/isEqual'\nimport { CombinedChannel } from '../channels/channel/combined'\n\nconst debug = createDebug('@feathersjs/transport-commons')\n\nexport const DEFAULT_PARAMS_POSITION = 1\n\nexport const paramsPositions: { [key: string]: number } = {\n  find: 0,\n  update: 2,\n  patch: 2\n}\n\nexport function normalizeError(e: any) {\n  const hasToJSON = typeof e.toJSON === 'function'\n  const result = hasToJSON ? e.toJSON() : {}\n\n  if (!hasToJSON) {\n    Object.getOwnPropertyNames(e).forEach((key) => {\n      result[key] = e[key]\n    })\n  }\n\n  if (process.env.NODE_ENV === 'production') {\n    delete result.stack\n  }\n\n  delete result.hook\n\n  return result\n}\n\nexport function getDispatcher(emit: string, socketMap: WeakMap<RealTimeConnection, any>, socketKey?: any) {\n  return function (event: string, channel: CombinedChannel, context: HookContext, data?: any) {\n    debug(`Dispatching '${event}' to ${channel.length} connections`)\n\n    channel.connections.forEach((connection) => {\n      // The reference between connection and socket is set in `app.setup`\n      const socket = socketKey ? connection[socketKey] : socketMap.get(connection)\n\n      if (socket) {\n        const eventName = `${context.path || ''} ${event}`.trim()\n\n        let result = channel.dataFor(connection) || context.dispatch || context.result\n\n        // If we are getting events from an array but try to dispatch individual data\n        // try to get the individual item to dispatch from the correct index.\n        if (!Array.isArray(data) && Array.isArray(context.result) && Array.isArray(result)) {\n          result = result.find((resultData) => isEqual(resultData, data))\n        }\n\n        debug(`Dispatching '${eventName}' to Socket ${socket.id} with`, result)\n\n        socket[emit](eventName, result)\n      }\n    })\n  }\n}\n\nexport async function runMethod(\n  app: Application,\n  connection: RealTimeConnection,\n  _path: string,\n  _method: string,\n  args: any[]\n) {\n  const path = typeof _path === 'string' ? _path : null\n  const method = typeof _method === 'string' ? _method : null\n  const trace = `method '${method}' on service '${path}'`\n  const methodArgs = args.slice(0)\n  const callback =\n    // eslint-disable-next-line @typescript-eslint/no-empty-function\n    typeof methodArgs[methodArgs.length - 1] === 'function' ? methodArgs.pop() : function () {}\n\n  debug(`Running ${trace}`, connection, args)\n\n  const handleError = (error: any) => {\n    debug(`Error in ${trace}`, error)\n    callback(normalizeError(error))\n  }\n\n  try {\n    const lookup = app.lookup(path)\n\n    // No valid service was found throw a NotFound error\n    if (lookup === null) {\n      throw new NotFound(path === null ? `Invalid service path` : `Service '${path}' not found`)\n    }\n\n    const { service, params: route = {} } = lookup\n    const { methods } = getServiceOptions(service)\n\n    // Only service methods are allowed\n    if (!methods.includes(method)) {\n      throw new MethodNotAllowed(`Method '${method}' not allowed on service '${path}'`)\n    }\n\n    const position = paramsPositions[method] !== undefined ? paramsPositions[method] : DEFAULT_PARAMS_POSITION\n    const query = Object.assign({}, methodArgs[position])\n    // `params` have to be re-mapped to the query and added with the route\n    const params = Object.assign({ query, route, connection }, connection)\n\n    // `params` is always the last parameter. Error if we got more arguments.\n    if (methodArgs.length > position + 1) {\n      throw new BadRequest(`Too many arguments for '${method}' method`)\n    }\n\n    methodArgs[position] = params\n\n    const ctx = createContext(service, method)\n    const returnedCtx: HookContext = await (service as any)[method](...methodArgs, ctx)\n    const result = returnedCtx.dispatch || returnedCtx.result\n\n    debug(`Returned successfully ${trace}`, result)\n    callback(null, result)\n  } catch (error: any) {\n    handleError(error)\n  }\n}\n"
  },
  {
    "path": "packages/transport-commons/test/channels/channel.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-empty-function */\nimport assert from 'assert'\nimport { feathers, Application, RealTimeConnection } from '@feathersjs/feathers'\nimport { channels, keys } from '../../src/channels'\nimport { Channel } from '../../src/channels/channel/base'\nimport { CombinedChannel } from '../../src/channels/channel/combined'\n\nconst { CHANNELS } = keys\n\ndescribe('app.channel', () => {\n  let app: Application\n\n  beforeEach(() => {\n    app = feathers().configure(channels())\n  })\n\n  describe('base channels', () => {\n    it('creates a new channel, app.channels has names', () => {\n      assert.ok(app.channel('test') instanceof Channel)\n      assert.deepStrictEqual(app.channels, ['test'])\n    })\n\n    it('.join', () => {\n      const test = app.channel('test')\n      const c1 = { id: 1 }\n      const c2 = { id: 2 }\n      const c3 = { id: 3 }\n\n      assert.strictEqual(test.length, 0, 'Initial channel is empty')\n\n      test.join(c1)\n      test.join(c1)\n\n      assert.strictEqual(test.length, 1, 'Joining twice only runs once')\n\n      test.join(c2, c3)\n\n      assert.strictEqual(test.length, 3, 'New connections joined')\n\n      test.join(c1, c2, c3)\n\n      assert.strictEqual(test.length, 3, 'Joining multiple times does nothing')\n    })\n\n    it('.leave', () => {\n      const test = app.channel('test')\n      const c1 = { id: 1 }\n      const c2 = { id: 2 }\n\n      assert.strictEqual(test.length, 0)\n\n      test.join(c1, c2)\n\n      assert.strictEqual(test.length, 2)\n\n      test.leave(c2)\n      test.leave(c2)\n\n      assert.strictEqual(test.length, 1)\n      assert.strictEqual(test.connections.indexOf(c2), -1)\n    })\n\n    it('.leave conditional', () => {\n      const test = app.channel('test')\n      const c1 = { id: 1, leave: true }\n      const c2 = { id: 2 }\n      const c3 = { id: 3 }\n\n      test.join(c1, c2, c3)\n\n      assert.strictEqual(test.length, 3)\n\n      test.leave((connection: RealTimeConnection) => connection.leave)\n\n      assert.strictEqual(test.length, 2)\n      assert.strictEqual(test.connections.indexOf(c1), -1)\n    })\n\n    it('.filter', () => {\n      const test = app.channel('test')\n      const c1 = { id: 1, filter: true }\n      const c2 = { id: 2 }\n      const c3 = { id: 3 }\n\n      test.join(c1, c2, c3)\n\n      const filtered = test.filter((connection) => connection.filter)\n\n      assert.ok(filtered !== test, 'Returns a new channel instance')\n      assert.ok(filtered instanceof Channel)\n      assert.strictEqual(filtered.length, 1)\n    })\n\n    it('.send', () => {\n      const data = { message: 'Hi' }\n\n      const test = app.channel('test')\n      const withData = test.send(data)\n\n      assert.ok(test !== withData)\n      assert.deepStrictEqual(withData.data, data)\n    })\n\n    describe('empty channels', () => {\n      it('is an EventEmitter', () => {\n        const channel = app.channel('emitchannel')\n\n        return new Promise<void>((resolve) => {\n          channel.once('message', (data) => {\n            assert.strictEqual(data, 'hello')\n            resolve()\n          })\n\n          channel.emit('message', 'hello')\n        })\n      })\n\n      it('empty', (done) => {\n        const channel = app.channel('test')\n        const c1 = { id: 1 }\n        const c2 = { id: 2 }\n\n        channel.once('empty', done)\n\n        channel.join(c1, c2)\n        channel.leave(c1)\n        channel.leave(c2)\n      })\n\n      it('removes an empty channel', () => {\n        const channel = app.channel('test')\n        const appChannels = (app as any)[CHANNELS]\n        const c1 = { id: 1 }\n\n        channel.join(c1)\n\n        assert.ok(appChannels.test)\n        assert.strictEqual(Object.keys(appChannels).length, 1)\n        channel.leave(c1)\n\n        assert.ok((app as any)[CHANNELS].test === undefined)\n        assert.strictEqual(Object.keys(appChannels).length, 0)\n      })\n\n      it('removes all event listeners from an empty channel', () => {\n        const channel = app.channel('testing')\n        const connection = { id: 1 }\n\n        channel.on('something', () => {})\n        assert.strictEqual(channel.listenerCount('something'), 1)\n        assert.strictEqual(channel.listenerCount('empty'), 1)\n\n        channel.join(connection).leave(connection)\n\n        assert.ok((app as any)[CHANNELS].testing === undefined)\n\n        assert.strictEqual(channel.listenerCount('something'), 0)\n        assert.strictEqual(channel.listenerCount('empty'), 0)\n      })\n    })\n  })\n\n  describe('combined channels', () => {\n    it('combines multiple channels', () => {\n      const combined = app.channel('test', 'again')\n\n      assert.deepStrictEqual(app.channels, ['test', 'again'])\n      assert.ok(combined instanceof CombinedChannel)\n      assert.strictEqual(combined.length, 0)\n    })\n\n    it('de-dupes connections', () => {\n      const c1 = { id: 1 }\n      const c2 = { id: 2 }\n\n      app.channel('test').join(c1, c2)\n      app.channel('again').join(c1)\n\n      const combined = app.channel('test', 'again')\n\n      assert.ok(combined instanceof CombinedChannel)\n      assert.strictEqual(combined.length, 2)\n    })\n\n    it('does nothing when the channel is undefined (#2207)', () => {\n      const channel = app.channel('test', 'me')\n\n      channel.join(undefined)\n    })\n\n    it('.join all child channels', () => {\n      const c1 = { id: 1 }\n      const c2 = { id: 2 }\n\n      const combined = app.channel('test', 'again')\n\n      combined.join(c1, c2)\n\n      assert.strictEqual(combined.length, 2)\n      assert.strictEqual(app.channel('test').length, 2)\n      assert.strictEqual(app.channel('again').length, 2)\n    })\n\n    it('.leave all child channels', () => {\n      const c1 = { id: 1 }\n      const c2 = { id: 2 }\n\n      app.channel('test').join(c1, c2)\n      app.channel('again').join(c1)\n\n      const combined = app.channel('test', 'again')\n\n      combined.leave(c1)\n\n      assert.strictEqual(app.channel('test').length, 1)\n      assert.strictEqual(app.channel('again').length, 0)\n    })\n\n    it('.leave all child channels conditionally', () => {\n      const c1 = { id: 1 }\n      const c2 = { id: 2, leave: true }\n      const combined = app.channel('test', 'again').join(c1, c2)\n\n      combined.leave((connection: RealTimeConnection) => connection.leave)\n\n      assert.strictEqual(app.channel('test').length, 1)\n      assert.strictEqual(app.channel('again').length, 1)\n    })\n\n    it('app.channel(app.channels)', () => {\n      const c1 = { id: 1 }\n      const c2 = { id: 2 }\n\n      app.channel('test').join(c1, c2)\n      app.channel('again').join(c1)\n\n      const combined = app.channel(app.channels)\n\n      assert.deepStrictEqual(combined.connections, [c1, c2])\n    })\n  })\n})\n"
  },
  {
    "path": "packages/transport-commons/test/channels/dispatch.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-empty-function */\nimport assert from 'assert'\nimport { feathers, Application, HookContext } from '@feathersjs/feathers'\nimport { channels } from '../../src/channels'\nimport { Channel } from '../../src/channels/channel/base'\nimport { CombinedChannel } from '../../src/channels/channel/combined'\n\nclass TestService {\n  events = ['foo']\n\n  async create(payload: any) {\n    return payload\n  }\n}\n\ndescribe('app.publish', () => {\n  let app: Application\n\n  beforeEach(() => {\n    app = feathers().configure(channels())\n  })\n\n  it('throws an error if service does not send the event', () => {\n    try {\n      app.use('/test', {\n        create(data: any) {\n          return Promise.resolve(data)\n        }\n      })\n\n      app.service('test').registerPublisher('created', function () {})\n      app.service('test').registerPublisher('bla', function () {})\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, \"'bla' is not a valid service event\")\n    }\n  })\n\n  describe('registration and `dispatch` event', () => {\n    const c1 = { id: 1, test: true }\n    const c2 = { id: 2, test: true }\n    const data = { message: 'This is a test' }\n\n    beforeEach(() => {\n      app.use('/test', new TestService())\n    })\n\n    it('error in publisher is handled gracefully (#1707)', async () => {\n      app.service('test').publish('created', () => {\n        throw new Error('Something went wrong')\n      })\n\n      try {\n        await app.service('test').create({ message: 'something' })\n      } catch (error: any) {\n        assert.fail('Should never get here')\n      }\n    })\n\n    it('simple event registration and dispatching', (done) => {\n      app.channel('testing').join(c1)\n\n      app.service('test').registerPublisher('created', () => app.channel('testing'))\n\n      app.once('publish', (event: string, channel: Channel, hook: HookContext) => {\n        try {\n          assert.strictEqual(event, 'created')\n          assert.strictEqual(hook.path, 'test')\n          assert.deepStrictEqual(hook.result, data)\n          assert.deepStrictEqual(channel.connections, [c1])\n          done()\n        } catch (error: any) {\n          done(error)\n        }\n      })\n\n      app.service('test').create(data).catch(done)\n    })\n\n    it('app and global level dispatching and precedence', (done) => {\n      app.channel('testing').join(c1)\n      app.channel('other').join(c2)\n\n      app.registerPublisher('created', () => app.channel('testing'))\n      app.registerPublisher(() => app.channel('other'))\n\n      app.once('publish', (_event: string, channel: Channel) => {\n        assert.ok(channel.connections.indexOf(c1) !== -1)\n        done()\n      })\n\n      app.service('test').create(data).catch(done)\n    })\n\n    it('promise event dispatching', (done) => {\n      app.channel('testing').join(c1)\n      app.channel('othertest').join(c2)\n\n      app\n        .service('test')\n        .registerPublisher(\n          'created',\n          () => new Promise((resolve) => setTimeout(() => resolve(app.channel('testing')), 50))\n        )\n      app\n        .service('test')\n        .registerPublisher(\n          'created',\n          () => new Promise((resolve) => setTimeout(() => resolve(app.channel('testing', 'othertest')), 100))\n        )\n\n      app.once('publish', (_event: string, channel: Channel, hook: HookContext) => {\n        assert.deepStrictEqual(hook.result, data)\n        assert.deepStrictEqual(channel.connections, [c1, c2])\n        done()\n      })\n\n      app.service('test').create(data).catch(done)\n    })\n\n    it('custom event dispatching', (done) => {\n      const eventData = { testing: true }\n\n      app.channel('testing').join(c1)\n      app.channel('othertest').join(c2)\n\n      app.service('test').registerPublisher('foo', () => app.channel('testing'))\n\n      app.once('publish', (event: string, channel: Channel, hook: HookContext) => {\n        assert.strictEqual(event, 'foo')\n        assert.deepStrictEqual(hook, {\n          app,\n          path: 'test',\n          service: app.service('test'),\n          result: eventData\n        })\n        assert.deepStrictEqual(channel.connections, [c1])\n        done()\n      })\n\n      app.service('test').emit('foo', eventData)\n    })\n\n    it('does not sent `dispatch` event if there are no dispatchers', (done) => {\n      app.once('publish', () => done(new Error('Should never get here')))\n\n      process.once('unhandledRejection', (error) => done(error))\n\n      app\n        .service('test')\n        .create(data)\n        .then(() => done())\n        .catch(done)\n    })\n\n    it('does not send `dispatch` event if there are no connections', (done) => {\n      app.service('test').registerPublisher('created', () => app.channel('dummy'))\n      app.once('publish', () => done(new Error('Should never get here')))\n\n      app\n        .service('test')\n        .create(data)\n        .then(() => done())\n        .catch(done)\n    })\n\n    it('dispatcher returning an array of channels', (done) => {\n      app.channel('testing').join(c1)\n      app.channel('othertest').join(c2)\n\n      app\n        .service('test')\n        .registerPublisher('created', () => [app.channel('testing'), app.channel('othertest')])\n\n      app.once('publish', (_event: string, channel: Channel, hook: HookContext) => {\n        assert.deepStrictEqual(hook.result, data)\n        assert.deepStrictEqual(channel.connections, [c1, c2])\n        done()\n      })\n\n      app.service('test').create(data).catch(done)\n    })\n\n    it('dispatcher can send data', (done) => {\n      const c1data = { channel: 'testing' }\n\n      app.channel('testing').join(c1)\n      app.channel('othertest').join(c2)\n\n      app\n        .service('test')\n        .registerPublisher('created', () => [app.channel('testing').send(c1data), app.channel('othertest')])\n\n      app.once('publish', (_event: string, channel: CombinedChannel, hook: HookContext) => {\n        assert.deepStrictEqual(hook.result, data)\n        assert.deepStrictEqual(channel.dataFor(c1), c1data)\n        assert.ok(channel.dataFor(c2) === null)\n        assert.deepStrictEqual(channel.connections, [c1, c2])\n        done()\n      })\n\n      app.service('test').create(data).catch(done)\n    })\n\n    it('publisher precedence and preventing publishing', (done) => {\n      app.channel('test').join(c1)\n\n      app.registerPublisher(() => app.channel('test'))\n      app.service('test').registerPublisher('created', (): null => null)\n\n      app.once('publish', () => done(new Error('Should never get here')))\n\n      app\n        .service('test')\n        .create(data)\n        .then(() => done())\n        .catch(done)\n    })\n\n    it('data of first channel has precedence', (done) => {\n      const sendData = { test: true }\n\n      app.channel('testing').join(c1)\n      app.channel('othertest').join(c1)\n\n      app.service('test').registerPublisher('created', () => {\n        return [app.channel('testing'), app.channel('othertest').send(sendData)]\n      })\n\n      app.once('publish', (_event: string, channel: CombinedChannel) => {\n        assert.strictEqual(channel.dataFor(c1), null)\n        assert.deepStrictEqual(channel.connections, [c1])\n        done()\n      })\n\n      app.service('test').create(data).catch(done)\n    })\n  })\n})\n"
  },
  {
    "path": "packages/transport-commons/test/channels/index.test.ts",
    "content": "/* eslint-disable @typescript-eslint/no-empty-function */\nimport assert from 'assert'\nimport { feathers } from '@feathersjs/feathers'\nimport { channels, keys } from '../../src/channels'\n\ndescribe('feathers-channels', () => {\n  it('has app.channel', () => {\n    const app = feathers().configure(channels())\n\n    assert.strictEqual(typeof app.channel, 'function')\n    assert.strictEqual(typeof (app as any)[keys.CHANNELS], 'object')\n    assert.strictEqual(app.channels.length, 0)\n  })\n\n  it('throws an error when called with nothing', () => {\n    const app = feathers().configure(channels())\n\n    try {\n      app.channel()\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'app.channel needs at least one channel name')\n    }\n  })\n\n  it('configuring twice does nothing', () => {\n    feathers().configure(channels()).configure(channels())\n  })\n\n  it('does not add things to the service if `dispatch` exists', () => {\n    const app = feathers()\n      .configure(channels())\n      .use('/test', {\n        async setup() {},\n        publish() {\n          return this\n        }\n      } as any)\n\n    const service: any = app.service('test')\n\n    assert.ok(!service[keys.PUBLISHERS])\n  })\n})\n"
  },
  {
    "path": "packages/transport-commons/test/client.test.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-empty-function */\nimport assert from 'assert'\nimport { EventEmitter } from 'events'\nimport { CustomMethods } from '@feathersjs/feathers'\nimport { NotAuthenticated } from '@feathersjs/errors'\nimport { Service, SocketService } from '../src/client'\n\ndeclare type DummyCallback = (err: any, data?: any) => void\n\ndescribe('client', () => {\n  let connection: any\n  let testData: any\n  let service: SocketService & CustomMethods<{ customMethod: any }> & EventEmitter\n\n  beforeEach(() => {\n    connection = new EventEmitter()\n    testData = { data: 'testing ' }\n    service = new Service({\n      events: ['created'],\n      name: 'todos',\n      method: 'emit',\n      connection\n    }) as any\n  })\n\n  it('sets `events` property on service', () => {\n    assert.ok(service.events)\n  })\n\n  it('throws for .get, .update, .patch and .remove with undefined or empty string id', async () => {\n    try {\n      await service.get(undefined)\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'id for .get is required')\n    }\n\n    try {\n      await service.get('')\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'id for .get is required')\n    }\n\n    try {\n      await service.update(undefined, testData)\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'id for .update is required')\n    }\n\n    try {\n      await service.update('', testData)\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'id for .update is required')\n    }\n\n    try {\n      await service.patch(undefined, testData)\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'id for .patch is required')\n    }\n\n    try {\n      await service.patch('', testData)\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'id for .patch is required')\n    }\n\n    try {\n      await service.remove(undefined)\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'id for .remove is required')\n    }\n\n    try {\n      await service.remove('')\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, 'id for .remove is required')\n    }\n  })\n\n  it('throws an error when the emitter does not have the method', () => {\n    const clientService = new Service({\n      name: 'todos',\n      method: 'emit',\n      connection: {}\n    }) as Service & EventEmitter\n\n    try {\n      clientService.eventNames()\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, \"Can not call 'eventNames' on the client service connection\")\n    }\n\n    try {\n      clientService.on('test', () => {})\n      assert.ok(false, 'Should never get here')\n    } catch (e: any) {\n      assert.strictEqual(e.message, \"Can not call 'on' on the client service connection\")\n    }\n  })\n\n  it('allows chaining event listeners', () => {\n    assert.strictEqual(\n      service,\n      service.on('thing', () => {})\n    )\n    assert.strictEqual(\n      service,\n      service.once('other thing', () => {})\n    )\n  })\n\n  it('initializes and emits namespaced events', (done) => {\n    connection.once('todos test', (data: any) => {\n      assert.deepStrictEqual(data, testData)\n      done()\n    })\n    service.emit('test', testData)\n  })\n\n  it('has other emitter methods', () => {\n    assert.ok(service.eventNames())\n  })\n\n  it('can receive pathed events', (done) => {\n    service.once('thing', (data) => {\n      assert.deepStrictEqual(data, testData)\n      done()\n    })\n\n    connection.emit('todos thing', testData)\n  })\n\n  it('sends all service and custom methods with acknowledgement', async () => {\n    const idCb = (_path: any, id: any, _params: any, callback: DummyCallback) => callback(null, { id })\n    const idDataCb = (_path: any, _id: any, data: any, _params: any, callback: DummyCallback) =>\n      callback(null, data)\n    const dataCb = (_path: any, data: any, _params: any, callback: DummyCallback) => {\n      data.created = true\n      callback(null, data)\n    }\n\n    connection.once('create', dataCb)\n    service.methods('customMethod')\n\n    let res = await service.create(testData)\n\n    assert.ok(res.created)\n\n    connection.once('get', idCb)\n    res = await service.get(1)\n    assert.deepStrictEqual(res, { id: 1 })\n\n    connection.once('remove', idCb)\n    res = await service.remove(12)\n    assert.deepStrictEqual(res, { id: 12 })\n\n    connection.once('update', idDataCb)\n    res = await service.update(12, testData)\n    assert.deepStrictEqual(res, testData)\n\n    connection.once('patch', idDataCb)\n    res = await service.patch(12, testData)\n    assert.deepStrictEqual(res, testData)\n\n    connection.once('customMethod', dataCb)\n    res = await service.customMethod({ message: 'test' })\n    assert.deepStrictEqual(res, {\n      created: true,\n      message: 'test'\n    })\n\n    connection.once('find', (_path: any, params: any, callback: DummyCallback) => callback(null, { params }))\n\n    res = await service.find({ query: { test: true } })\n    assert.deepStrictEqual(res, {\n      params: { test: true }\n    })\n  })\n\n  it('replace placeholder in service paths', async () => {\n    service = new Service({\n      events: ['created'],\n      name: ':slug/todos',\n      method: 'emit',\n      connection\n    }) as any\n\n    const idCb = (path: any, _id: any, _params: any, callback: DummyCallback) => callback(null, path)\n    const idDataCb = (path: any, _id: any, _data: any, _params: any, callback: DummyCallback) =>\n      callback(null, path)\n    const dataCb = (path: any, _data: any, _params: any, callback: DummyCallback) => {\n      callback(null, path)\n    }\n\n    connection.once('create', dataCb)\n    service.methods('customMethod')\n\n    let res = await service.create(testData, {\n      route: {\n        slug: 'mySlug'\n      }\n    })\n\n    assert.strictEqual(res, 'mySlug/todos')\n\n    connection.once('get', idCb)\n    res = await service.get(1, {\n      route: {\n        slug: 'mySlug'\n      }\n    })\n    assert.strictEqual(res, 'mySlug/todos')\n\n    connection.once('remove', idCb)\n    res = await service.remove(12, {\n      route: {\n        slug: 'mySlug'\n      }\n    })\n    assert.strictEqual(res, 'mySlug/todos')\n\n    connection.once('update', idDataCb)\n    res = await service.update(12, testData, {\n      route: {\n        slug: 'mySlug'\n      }\n    })\n    assert.strictEqual(res, 'mySlug/todos')\n\n    connection.once('patch', idDataCb)\n    res = await service.patch(12, testData, {\n      route: {\n        slug: 'mySlug'\n      }\n    })\n    assert.strictEqual(res, 'mySlug/todos')\n\n    connection.once('customMethod', dataCb)\n    res = await service.customMethod(\n      { message: 'test' },\n      {\n        route: {\n          slug: 'mySlug'\n        }\n      }\n    )\n    assert.strictEqual(res, 'mySlug/todos')\n\n    connection.once('find', (path: any, _params: any, callback: DummyCallback) => callback(null, path))\n\n    res = await service.find({\n      query: { test: true },\n      route: {\n        slug: 'mySlug'\n      }\n    })\n    assert.strictEqual(res, 'mySlug/todos')\n  })\n\n  it('converts to feathers-errors (#19)', async () => {\n    connection.once('create', (_path: any, _data: any, _params: any, callback: DummyCallback) =>\n      callback(new NotAuthenticated('Test', { hi: 'me' }).toJSON())\n    )\n\n    await assert.rejects(() => service.create(testData), {\n      name: 'NotAuthenticated',\n      message: 'Test',\n      code: 401,\n      data: { hi: 'me' }\n    })\n  })\n\n  it('converts other errors (#19)', async () => {\n    connection.once('create', (_path: string, _data: any, _params: any, callback: (x: string) => void) => {\n      callback('Something went wrong') // eslint-disable-line\n    })\n\n    await assert.rejects(() => service.create(testData), {\n      message: 'Something went wrong'\n    })\n  })\n\n  it('has all EventEmitter methods', (done) => {\n    const testing = { hello: 'world' }\n    const callback = (data: any) => {\n      assert.deepStrictEqual(data, testing)\n      assert.strictEqual(service.listenerCount('test'), 1)\n      service.removeListener('test', callback)\n      assert.strictEqual(service.listenerCount('test'), 0)\n      done()\n    }\n\n    service.addListener('test', callback)\n\n    connection.emit('todos test', testing)\n  })\n\n  it('properly handles on/off methods', (done) => {\n    const testing = { hello: 'world' }\n\n    const callback1 = (data: any) => {\n      assert.deepStrictEqual(data, testing)\n      assert.strictEqual(service.listenerCount('test'), 3)\n      service.off('test', callback1)\n      assert.strictEqual(service.listenerCount('test'), 2)\n      service.removeAllListeners('test')\n      assert.strictEqual(service.listenerCount('test'), 0)\n      done()\n    }\n    const callback2 = () => {\n      // noop\n    }\n\n    service.on('test', callback1)\n    service.on('test', callback2)\n    service.on('test', callback2)\n\n    connection.emit('todos test', testing)\n  })\n\n  it('forwards namespaced call to .off, returns service instance', () => {\n    // Use it's own connection and service so off method gets detected\n    const conn = new EventEmitter()\n\n    // @ts-ignore\n    conn.off = function (name) {\n      assert.strictEqual(name, 'todos test')\n\n      return this\n    }\n\n    const client = new Service({\n      name: 'todos',\n      method: 'emit',\n      connection: conn\n    })\n\n    assert.strictEqual(client.off('test'), client)\n  })\n\n  it(\"handles socket.io's weird behavior with ackTimeout\", async () => {\n    connection.flags = { timeout: 10000 }\n\n    const dataCb = (\n      _path: any,\n      data: any,\n      _params: any,\n      callback: (timeoutError: any, err: any, data?: any) => void\n    ) => {\n      data.created = true\n      callback(null, null, data)\n    }\n\n    const errorCb = (\n      _path: any,\n      _data: any,\n      _params: any,\n      callback: (timeoutError: any, err: any, _data?: any) => void\n    ) => {\n      callback(null, new Error(), null)\n    }\n\n    const timeoutErrorCb = (\n      _path: any,\n      _data: any,\n      _params: any,\n      callback: (timeoutError: any, err: any, _data?: any) => void\n    ) => {\n      callback(new Error(), null, null)\n    }\n\n    connection.once('create', dataCb)\n\n    let res = await service.create(testData)\n\n    assert.ok(res.created)\n\n    connection.once('create', errorCb)\n\n    try {\n      res = await service.create(testData)\n      assert.fail('should not reach')\n    } catch (e) {\n      assert.ok(e instanceof Error)\n    }\n\n    connection.once('create', timeoutErrorCb)\n\n    try {\n      res = await service.create(testData)\n      assert.fail('should not reach')\n    } catch (e) {\n      assert.ok(e instanceof Error)\n    }\n  })\n})\n"
  },
  {
    "path": "packages/transport-commons/test/http.test.ts",
    "content": "import assert from 'assert'\nimport { HookContext } from '@feathersjs/feathers'\nimport { http } from '../src'\n\ndescribe('@feathersjs/transport-commons HTTP helpers', () => {\n  it('getResponse body', () => {\n    const plainData = { message: 'hi' }\n    const dispatch = { message: 'from dispatch' }\n    const resultContext = {\n      result: plainData\n    }\n    const dispatchContext = {\n      dispatch\n    }\n\n    assert.strictEqual(http.getResponse(resultContext as HookContext).body, plainData)\n    assert.strictEqual(http.getResponse(dispatchContext as HookContext).body, dispatch)\n  })\n\n  it('getResponse status', () => {\n    const statusContext = {\n      http: { status: 202 }\n    }\n    const createContext = {\n      method: 'create',\n      result: {}\n    }\n    const createEmptyContext = {\n      method: 'create'\n    }\n    const redirectContext = {\n      http: { location: '/' }\n    }\n    const redirectCreateContext = {\n      method: 'create',\n      http: { location: '/' }\n    }\n\n    assert.strictEqual(http.getResponse(statusContext as HookContext).status, 202)\n    assert.strictEqual(http.getResponse(createContext as HookContext).status, http.statusCodes.created)\n    assert.strictEqual(http.getResponse(redirectContext as HookContext).status, http.statusCodes.seeOther)\n    assert.strictEqual(\n      http.getResponse(redirectCreateContext as HookContext).status,\n      http.statusCodes.seeOther\n    )\n    assert.strictEqual(http.getResponse({} as HookContext).status, http.statusCodes.noContent)\n    assert.strictEqual(http.getResponse(createEmptyContext as HookContext).status, http.statusCodes.noContent)\n    assert.strictEqual(http.getResponse({ result: true } as HookContext).status, http.statusCodes.success)\n  })\n\n  it('getResponse headers', () => {\n    const headers = { key: 'value' } as any\n    const headersContext = {\n      http: { headers }\n    }\n    const locationContext = {\n      http: { location: '/' }\n    }\n\n    assert.deepStrictEqual(http.getResponse({} as HookContext).headers, {})\n    assert.deepStrictEqual(http.getResponse({ http: {} } as HookContext).headers, {})\n    assert.strictEqual(http.getResponse(headersContext as HookContext).headers, headers)\n    assert.deepStrictEqual(http.getResponse(locationContext as HookContext).headers, {\n      Location: '/'\n    })\n  })\n\n  it('getServiceMethod', () => {\n    assert.strictEqual(http.getServiceMethod('GET', 2), 'get')\n    assert.strictEqual(http.getServiceMethod('GET', null), 'find')\n    assert.strictEqual(http.getServiceMethod('PoST', null), 'create')\n    assert.strictEqual(http.getServiceMethod('PoST', null, 'customMethod'), 'customMethod')\n    assert.strictEqual(http.getServiceMethod('delete', null), 'remove')\n    assert.throws(() => http.getServiceMethod('nonsense', null))\n  })\n})\n"
  },
  {
    "path": "packages/transport-commons/test/routing/index.test.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-ts-comment */\nimport assert from 'assert'\nimport { feathers, Application } from '@feathersjs/feathers'\nimport { routing } from '../../src/routing'\n\ndescribe('app.routes', () => {\n  let app: Application\n\n  beforeEach(() => {\n    app = feathers().configure(routing())\n\n    app.use('/my/service', {\n      get(id: string | number) {\n        return Promise.resolve({ id })\n      }\n    })\n  })\n\n  it('does nothing when configured twice', () => {\n    feathers().configure(routing()).configure(routing())\n  })\n\n  it('has app.lookup and app.routes', () => {\n    assert.strictEqual(typeof app.lookup, 'function')\n    assert.ok(app.routes)\n  })\n\n  it('returns null when nothing is found', () => {\n    const result = app.lookup('me/service')\n\n    assert.strictEqual(result, null)\n  })\n\n  it('returns null for invalid service path', () => {\n    assert.strictEqual(app.lookup(null), null)\n    // @ts-ignore\n    assert.strictEqual(app.lookup({}), null)\n  })\n\n  it('can look up and strips slashes', () => {\n    const result = app.lookup('my/service')\n\n    assert.strictEqual(result.service, app.service('/my/service/'))\n  })\n\n  it('can look up case insensitive', () => {\n    app.routes.caseSensitive = false\n\n    const result = app.lookup('/My/ServicE')\n\n    assert.strictEqual(result.service, app.service('my/service'))\n  })\n\n  it('can look up with id', () => {\n    const result = app.lookup('/my/service/1234')\n\n    assert.strictEqual(result.service, app.service('/my/service'))\n    assert.deepStrictEqual(result.params, {\n      __id: '1234'\n    })\n  })\n\n  it('can look up with params, id and special characters', () => {\n    const path = '/test/:first/my/:second'\n\n    app.use(path, {\n      async get(id: string | number) {\n        return { id }\n      }\n    })\n\n    const result = app.lookup('/test/me/my/::special/testing')\n\n    assert.strictEqual(result.service, app.service(path))\n    assert.deepStrictEqual(result.params, {\n      __id: 'testing',\n      first: 'me',\n      second: '::special'\n    })\n  })\n\n  it('can register routes with preset params', () => {\n    app.routes.insert('/my/service/:__id/preset', {\n      service: app.service('/my/service'),\n      params: { preset: true }\n    })\n\n    const result = app.lookup('/my/service/1234/preset')\n\n    assert.strictEqual(result.service, app.service('/my/service'))\n    assert.deepStrictEqual(result.params, {\n      preset: true,\n      __id: '1234'\n    })\n  })\n\n  it('can pass route params during a service registration', () => {\n    app.use(\n      '/other/service',\n      {\n        async get(id: any) {\n          return id\n        }\n      },\n      {\n        routeParams: { used: true }\n      }\n    )\n\n    const result = app.lookup('/other/service/1234')\n\n    assert.strictEqual(result.service, app.service('/other/service'))\n    assert.deepStrictEqual(result.params, {\n      used: true,\n      __id: '1234'\n    })\n  })\n\n  it('can unregister a service (#2035)', async () => {\n    const result = app.lookup('my/service')\n\n    assert.strictEqual(result.service, app.service('/my/service/'))\n\n    await app.unuse('/my/service')\n\n    assert.strictEqual(app.lookup('my/service'), null)\n  })\n})\n"
  },
  {
    "path": "packages/transport-commons/test/routing/router.test.ts",
    "content": "import assert from 'assert'\nimport { Router } from '../../src/routing'\n\ndescribe('router', () => {\n  it('can lookup and insert a simple path and returns null for invalid path', () => {\n    const r = new Router<string>()\n\n    r.insert('/hello/there/you', 'test')\n\n    const result = r.lookup('hello/there/you/')\n\n    assert.deepStrictEqual(result, {\n      params: {},\n      data: 'test'\n    })\n\n    assert.strictEqual(r.lookup('not/there'), null)\n    assert.strictEqual(r.lookup('not-me'), null)\n  })\n\n  it('can insert data at the root', () => {\n    const r = new Router<string>()\n\n    r.insert('', 'hi')\n\n    const result = r.lookup('/')\n\n    assert.deepStrictEqual(result, {\n      params: {},\n      data: 'hi'\n    })\n  })\n\n  it('can insert with placeholder and has proper specificity', () => {\n    const r = new Router<string>()\n\n    r.insert('/hello/:id', 'one')\n    r.insert('/hello/:id/you', 'two')\n    r.insert('/hello/:id/:other', 'three')\n\n    const first = r.lookup('hello/there/')\n\n    assert.throws(() => r.insert('/hello/:id/you', 'two'), {\n      message: 'Path hello/:id/you already exists'\n    })\n\n    assert.deepStrictEqual(first, {\n      params: { id: 'there' },\n      data: 'one'\n    })\n\n    const second = r.lookup('hello/yes/you')\n\n    assert.deepStrictEqual(second, {\n      params: { id: 'yes' },\n      data: 'two'\n    })\n\n    const third = r.lookup('hello/yes/they')\n\n    assert.deepStrictEqual(third, {\n      params: {\n        id: 'yes',\n        other: 'they'\n      },\n      data: 'three'\n    })\n\n    assert.strictEqual(r.lookup('hello/yes/they/here'), null)\n  })\n\n  it('works with different placeholders in different paths (#2327)', () => {\n    const r = new Router<string>()\n\n    r.insert('/hello/:id', 'one')\n    r.insert('/hello/:test/you', 'two')\n    r.insert('/hello/:test/:two/hi/:three', 'three')\n    r.insert('/hello/:test/:two/hi', 'four')\n\n    assert.deepStrictEqual(r.lookup('/hello/there'), {\n      params: { id: 'there' },\n      data: 'one'\n    })\n    assert.deepStrictEqual(r.lookup('/hello/there/you'), {\n      params: { test: 'there' },\n      data: 'two'\n    })\n    assert.strictEqual(r.lookup('/hello/there/bla'), null)\n    assert.deepStrictEqual(r.lookup('/hello/there/maybe/hi'), {\n      params: { test: 'there', two: 'maybe' },\n      data: 'four'\n    })\n    assert.deepStrictEqual(r.lookup('/hello/there/maybe/hi/test'), {\n      params: { three: 'test', two: 'maybe', test: 'there' },\n      data: 'three'\n    })\n  })\n\n  it('can remove paths (#2035)', () => {\n    const r = new Router<string>()\n\n    r.insert('/hello/:id', 'one')\n    r.insert('/hello/:test/you', 'two')\n    r.insert('/hello/here/thing', 'else')\n\n    assert.deepStrictEqual(r.lookup('hello/there'), { params: { id: 'there' }, data: 'one' })\n\n    r.remove('/hello/:id')\n\n    assert.deepStrictEqual(r.lookup('hello/here/you'), { params: { test: 'here' }, data: 'two' })\n    assert.deepStrictEqual(r.lookup('hello/here/thing'), { params: {}, data: 'else' })\n    assert.strictEqual(r.lookup('hello/there'), null)\n\n    r.remove('/hello/:test/you')\n    assert.deepStrictEqual(r.lookup('hello/here/you'), null)\n    assert.deepStrictEqual(r.lookup('hello/here/thing'), { params: {}, data: 'else' })\n\n    r.remove('/hello/here/thing')\n    assert.ok(!r.root.hasChildren)\n  })\n\n  it('re-initialize a service with children. (#3432)', () => {\n    const r = new Router<string>()\n\n    r.insert('/hello', 'one')\n    r.insert('/hello/world', 'else')\n\n    assert.deepStrictEqual(r.lookup('hello'), { params: {}, data: 'one' })\n\n    r.remove('/hello')\n\n    assert.deepStrictEqual(r.lookup('hello/world'), { params: {}, data: 'else' })\n\n    r.insert('/hello', 'two')\n\n    assert.deepStrictEqual(r.lookup('hello'), { params: {}, data: 'two' })\n    assert.deepStrictEqual(r.lookup('hello/world'), { params: {}, data: 'else' })\n  })\n})\n"
  },
  {
    "path": "packages/transport-commons/test/socket/index.test.ts",
    "content": "import assert from 'assert'\nimport { EventEmitter } from 'events'\nimport { feathers, Application, Id, Params } from '@feathersjs/feathers'\n\nimport { socket as commons, SocketOptions } from '../../src/socket'\n\nclass DummyService {\n  async get(id: Id, params: Params) {\n    return { id, params }\n  }\n\n  async create(data: any, params: Params) {\n    return {\n      ...data,\n      params\n    }\n  }\n\n  async custom(data: any, params: Params) {\n    return {\n      ...data,\n      params,\n      message: 'From custom method'\n    }\n  }\n}\n\ndescribe('@feathersjs/transport-commons', () => {\n  let provider: EventEmitter\n  let options: SocketOptions\n  let app: Application\n  let connection: any\n\n  beforeEach(() => {\n    connection = { testing: true }\n    provider = new EventEmitter()\n\n    options = {\n      emit: 'emit',\n      done: Promise.resolve(provider),\n      socketMap: new WeakMap(),\n      getParams() {\n        return connection\n      }\n    }\n    app = feathers()\n      .configure(commons(options))\n      .use('/myservice', new DummyService(), {\n        methods: ['get', 'create', 'custom']\n      })\n\n    return options.done\n  })\n\n  it('`connection` event', (done) => {\n    const socket = new EventEmitter()\n\n    app.once('connection', (data) => {\n      assert.strictEqual(connection, data)\n      done()\n    })\n\n    provider.emit('connection', socket)\n  })\n\n  describe('method name based socket events', () => {\n    it('.get without params', (done) => {\n      const socket = new EventEmitter()\n\n      provider.emit('connection', socket)\n\n      socket.emit('get', 'myservice', 10, (error: any, result: any) => {\n        try {\n          assert.ok(!error)\n          assert.deepStrictEqual(result, {\n            id: 10,\n            params: Object.assign(\n              {\n                query: {},\n                route: {},\n                connection\n              },\n              connection\n            )\n          })\n          done()\n        } catch (e: any) {\n          done(e)\n        }\n      })\n    })\n\n    it('method with invalid service name and arguments', (done) => {\n      const socket = new EventEmitter()\n\n      provider.emit('connection', socket)\n\n      socket.emit('get', null, (error: any) => {\n        assert.strictEqual(error.name, 'NotFound')\n        assert.strictEqual(error.message, 'Invalid service path')\n        done()\n      })\n    })\n\n    it('method with implicit toString errors properly', (done) => {\n      const socket = new EventEmitter()\n\n      provider.emit('connection', socket)\n\n      socket.emit('get', { toString: '' }, (error: any) => {\n        assert.strictEqual(error.name, 'NotFound')\n        assert.strictEqual(error.message, 'Invalid service path')\n        done()\n      })\n    })\n\n    it('.create with params', (done) => {\n      const socket = new EventEmitter()\n      const data = {\n        test: 'data'\n      }\n\n      provider.emit('connection', socket)\n\n      socket.emit(\n        'create',\n        'myservice',\n        data,\n        {\n          fromQuery: true\n        },\n        (error: any, result: any) => {\n          try {\n            const params = Object.assign(\n              {\n                query: { fromQuery: true },\n                route: {},\n                connection\n              },\n              connection\n            )\n\n            assert.ok(!error)\n            assert.deepStrictEqual(result, Object.assign({ params }, data))\n            done()\n          } catch (e: any) {\n            done(e)\n          }\n        }\n      )\n    })\n\n    it('custom method with params', (done) => {\n      const socket = new EventEmitter()\n      const data = {\n        test: 'data'\n      }\n\n      provider.emit('connection', socket)\n\n      socket.emit(\n        'custom',\n        'myservice',\n        data,\n        {\n          fromQuery: true\n        },\n        (error: any, result: any) => {\n          try {\n            const params = Object.assign(\n              {\n                query: { fromQuery: true },\n                route: {},\n                connection\n              },\n              connection\n            )\n\n            assert.ok(!error)\n            assert.deepStrictEqual(result, {\n              ...data,\n              params,\n              message: 'From custom method'\n            })\n            done()\n          } catch (e: any) {\n            done(e)\n          }\n        }\n      )\n    })\n  })\n})\n"
  },
  {
    "path": "packages/transport-commons/test/socket/utils.test.ts",
    "content": "import assert from 'assert'\nimport { EventEmitter } from 'events'\nimport { feathers, Application, Params, RealTimeConnection } from '@feathersjs/feathers'\nimport { NotAuthenticated } from '@feathersjs/errors'\nimport isPlainObject from 'lodash/isPlainObject'\n\nimport { routing } from '../../src/routing'\nimport { normalizeError, getDispatcher, runMethod } from '../../src/socket/utils'\n\ndescribe('socket commons utils', () => {\n  describe('.normalizeError', () => {\n    it('simple error normalization', () => {\n      const message = 'Something went wrong'\n      const e = new Error(message)\n\n      assert.deepStrictEqual(normalizeError(e), {\n        message,\n        stack: e.stack.toString()\n      })\n    })\n\n    it('calls .toJSON', () => {\n      const json = { message: 'toJSON called' }\n\n      assert.deepStrictEqual(\n        normalizeError({\n          toJSON() {\n            return json\n          }\n        }),\n        json\n      )\n    })\n\n    it('removes `hook` property', () => {\n      const e = {\n        hook: true\n      }\n\n      assert.deepStrictEqual(normalizeError(e), {})\n      assert.ok(e.hook, 'Does not mutate the original object')\n    })\n\n    it('hides stack in production', () => {\n      const oldEnv = process.env.NODE_ENV\n\n      process.env.NODE_ENV = 'production'\n\n      const message = 'Something went wrong'\n      const e = new Error(message)\n      const normalized = normalizeError(e)\n\n      assert.strictEqual(normalized.message, message)\n      assert.ok(!normalized.stack)\n\n      process.env.NODE_ENV = oldEnv\n    })\n  })\n\n  describe('.getDispatcher', () => {\n    it('returns a dispatcher function', () =>\n      assert.strictEqual(typeof getDispatcher('test', new WeakMap()), 'function'))\n\n    it('works with backwards compatible socketKey', (done) => {\n      const socketKey = Symbol('@feathersjs/test')\n      const dispatcher = getDispatcher('emit', undefined, socketKey)\n      const socket = new EventEmitter()\n      const connection = {\n        [socketKey]: socket\n      }\n      const channel: any = {\n        connections: [connection],\n        dataFor(): null {\n          return null\n        }\n      }\n\n      socket.once('testing', (data) => {\n        assert.strictEqual(data, 'hi')\n        done()\n      })\n\n      dispatcher('testing', channel, { result: 'hi' } as any)\n    })\n\n    describe('dispatcher logic', () => {\n      let dispatcher: any\n      let dummySocket: EventEmitter\n      let dummyHook: any\n      let dummyChannel: any\n      let dummyConnection: RealTimeConnection\n      let dummyMap: WeakMap<any, any>\n\n      beforeEach(() => {\n        dummyConnection = {}\n        dummyMap = new WeakMap()\n        dispatcher = getDispatcher('emit', dummyMap)\n        dummySocket = new EventEmitter()\n        dummyHook = { result: 'hi' }\n        dummyChannel = {\n          connections: [dummyConnection],\n          dataFor(): null {\n            return null\n          }\n        }\n        dummyMap.set(dummyConnection, dummySocket)\n      })\n\n      it('dispatches a basic event', (done) => {\n        dummySocket.once('testing', (data) => {\n          assert.strictEqual(data, 'hi')\n          done()\n        })\n\n        dispatcher('testing', dummyChannel, dummyHook)\n      })\n\n      it('dispatches event on a hooks path event', (done) => {\n        dummyHook.path = 'myservice'\n\n        dummySocket.once('myservice testing', (data) => {\n          assert.strictEqual(data, 'hi')\n          done()\n        })\n\n        dispatcher('testing', dummyChannel, dummyHook)\n      })\n\n      it('dispatches `hook.dispatch` instead', (done) => {\n        const message = 'hi from dispatch'\n\n        dummyHook.dispatch = message\n\n        dummySocket.once('testing', (data) => {\n          assert.strictEqual(data, message)\n          done()\n        })\n\n        dispatcher('testing', dummyChannel, dummyHook)\n      })\n\n      it('does nothing if there is no socket', () => {\n        dummyChannel.connections[0].test = null\n\n        dispatcher('testing', dummyChannel, dummyHook)\n      })\n\n      it('dispatches arrays properly hook events', (done) => {\n        const data1 = { message: 'First message' }\n        const data2 = { message: 'Second message' }\n\n        dummyHook.result = [data1, data2]\n\n        dummySocket.once('testing', (data) => {\n          assert.deepStrictEqual(data, data1)\n          dummySocket.once('testing', (result) => {\n            assert.deepStrictEqual(result, data2)\n            done()\n          })\n        })\n\n        dispatcher('testing', dummyChannel, dummyHook, data1)\n        dispatcher('testing', dummyChannel, dummyHook, data2)\n      })\n\n      it('dispatches dispatch arrays properly', (done) => {\n        const data1 = { message: 'First message' }\n        const data2 = { message: 'Second message' }\n\n        dummyHook.result = []\n        dummyHook.dispatch = [data1, data2]\n\n        dummySocket.once('testing', (data) => {\n          assert.deepStrictEqual(data, data1)\n          dummySocket.once('testing', (result) => {\n            assert.deepStrictEqual(result, data2)\n            done()\n          })\n        })\n\n        dispatcher('testing', dummyChannel, dummyHook, data1)\n        dispatcher('testing', dummyChannel, dummyHook, data2)\n      })\n\n      it('dispatches arrays properly for custom events', (done) => {\n        const result = [{ message: 'First' }, { message: 'Second' }]\n\n        dummyHook.result = result\n\n        dummySocket.once('otherEvent', (data) => {\n          assert.deepStrictEqual(data, result)\n          done()\n        })\n\n        dispatcher('otherEvent', dummyChannel, dummyHook, result)\n      })\n    })\n  })\n\n  describe('.runMethod', () => {\n    let app: Application\n\n    beforeEach(() => {\n      app = feathers().configure(routing())\n      app.use('/myservice', {\n        async get(id: number | string, params: Params) {\n          if (params.query.error) {\n            throw new NotAuthenticated('None shall pass')\n          }\n          if (!isPlainObject(params.query)) {\n            throw new Error('Query is not a plain object')\n          }\n\n          return { id }\n        }\n      })\n    })\n\n    describe('running methods', () => {\n      it('basic', (done) => {\n        const callback = (error: any, result: any) => {\n          if (error) {\n            return done(error)\n          }\n\n          assert.deepStrictEqual(result, { id: 10 })\n          done()\n        }\n\n        runMethod(app, {}, 'myservice', 'get', [10, {}, callback])\n      })\n\n      it('queries are always plain objects', (done) => {\n        const callback = (error: any, result: any) => {\n          if (error) {\n            return done(error)\n          }\n\n          assert.deepStrictEqual(result, { id: 10 })\n          done()\n        }\n\n        runMethod(app, {}, 'myservice', 'get', [\n          10,\n          {\n            __proto__: []\n          },\n          callback\n        ])\n      })\n\n      it('merges params with connection and passes connection', (done) => {\n        const connection = {\n          testing: true\n        }\n        const callback = (error: any, result: any) => {\n          if (error) {\n            return done(error)\n          }\n\n          assert.deepStrictEqual(result, {\n            id: 10,\n            params: {\n              connection,\n              query: {},\n              route: {},\n              testing: true\n            }\n          })\n          done()\n        }\n\n        app.use('/otherservice', {\n          get(id, params) {\n            return Promise.resolve({ id, params })\n          }\n        })\n\n        runMethod(app, connection, 'otherservice', 'get', [10, {}, callback])\n      })\n\n      it('with params missing', (done) => {\n        const callback = (error: any, result: any) => {\n          if (error) {\n            return done(error)\n          }\n\n          assert.deepStrictEqual(result, { id: 10 })\n          done()\n        }\n\n        runMethod(app, {}, 'myservice', 'get', [10, callback])\n      })\n\n      it('with params but missing callback', (done) => {\n        app.use('/otherservice', {\n          get(id: number | string) {\n            assert.strictEqual(id, 'dishes')\n\n            return Promise.resolve({ id }).then((res) => {\n              done()\n              return res\n            })\n          }\n        })\n\n        runMethod(app, {}, 'otherservice', 'get', ['dishes', {}])\n      })\n\n      it('with params and callback missing', (done) => {\n        app.use('/otherservice', {\n          get(id: number | string) {\n            assert.strictEqual(id, 'laundry')\n\n            return Promise.resolve({ id }).then((res) => {\n              done()\n              return res\n            })\n          }\n        })\n\n        runMethod(app, {}, 'otherservice', 'get', ['laundry'])\n      })\n    })\n\n    it('throws NotFound for invalid service', (done) => {\n      const callback = (error: any) => {\n        try {\n          assert.deepStrictEqual(error, {\n            name: 'NotFound',\n            message: \"Service 'ohmyservice' not found\",\n            code: 404,\n            className: 'not-found'\n          })\n          done()\n        } catch (e: any) {\n          done(e)\n        }\n      }\n\n      runMethod(app, {}, 'ohmyservice', 'get', [10, callback])\n    })\n\n    it('throws MethodNotAllowed undefined method', (done) => {\n      const callback = (error: any) => {\n        try {\n          assert.deepStrictEqual(error, {\n            name: 'MethodNotAllowed',\n            message: \"Method 'create' not allowed on service 'myservice'\",\n            code: 405,\n            className: 'method-not-allowed'\n          })\n          done()\n        } catch (e: any) {\n          done(e)\n        }\n      }\n\n      runMethod(app, {}, 'myservice', 'create', [{}, callback])\n    })\n\n    it('throws MethodNotAllowed for invalid service method', (done) => {\n      const callback = (error: any) => {\n        try {\n          assert.deepStrictEqual(error, {\n            name: 'MethodNotAllowed',\n            message: \"Method 'blabla' not allowed on service 'myservice'\",\n            code: 405,\n            className: 'method-not-allowed'\n          })\n          done()\n        } catch (e: any) {\n          done(e)\n        }\n      }\n\n      runMethod(app, {}, 'myservice', 'blabla', [{}, callback])\n    })\n\n    it('method error calls back with normalized error', (done) => {\n      const callback = (error: any) => {\n        try {\n          assert.deepStrictEqual(error, {\n            name: 'NotAuthenticated',\n            message: 'None shall pass',\n            code: 401,\n            className: 'not-authenticated'\n          })\n          done()\n        } catch (e: any) {\n          done(e)\n        }\n      }\n\n      runMethod(app, {}, 'myservice', 'get', [42, { error: true }, callback])\n    })\n  })\n})\n"
  },
  {
    "path": "packages/transport-commons/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "packages/typebox/CHANGELOG.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://conventionalcommits.org) for commit guidelines.\n\n## [5.0.42](https://github.com/feathersjs/feathers/compare/v5.0.41...v5.0.42) (2026-03-04)\n\n### Bug Fixes\n\n- Update dependencies ([#3666](https://github.com/feathersjs/feathers/issues/3666)) ([477bf45](https://github.com/feathersjs/feathers/commit/477bf45f9c9dbde77a14a07828aa02300de23ae7))\n\n## [5.0.41](https://github.com/feathersjs/feathers/compare/v5.0.40...v5.0.41) (2026-02-19)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.40](https://github.com/feathersjs/feathers/compare/v5.0.39...v5.0.40) (2026-02-03)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.39](https://github.com/feathersjs/feathers/compare/v5.0.38...v5.0.39) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.38](https://github.com/feathersjs/feathers/compare/v5.0.37...v5.0.38) (2026-01-31)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.37](https://github.com/feathersjs/feathers/compare/v5.0.36...v5.0.37) (2025-11-10)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.36](https://github.com/feathersjs/feathers/compare/v5.0.35...v5.0.36) (2025-11-08)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3625](https://github.com/feathersjs/feathers/issues/3625)) ([2698e4e](https://github.com/feathersjs/feathers/commit/2698e4e2996fbf479d82435938d907bc3d5b583a))\n\n## [5.0.35](https://github.com/feathersjs/feathers/compare/v5.0.34...v5.0.35) (2025-09-09)\n\n### Bug Fixes\n\n- Update all dependencies ([#3613](https://github.com/feathersjs/feathers/issues/3613)) ([5136bbd](https://github.com/feathersjs/feathers/commit/5136bbd2e2eeb4e6579e07c9e914006629542363))\n\n## [5.0.34](https://github.com/feathersjs/feathers/compare/v5.0.33...v5.0.34) (2025-05-03)\n\n### Bug Fixes\n\n- Update dependencies ([#3584](https://github.com/feathersjs/feathers/issues/3584)) ([119fa4e](https://github.com/feathersjs/feathers/commit/119fa4e1ade8b0078aa235083d566e2538b3a084))\n\n## [5.0.33](https://github.com/feathersjs/feathers/compare/v5.0.32...v5.0.33) (2025-02-24)\n\n### Bug Fixes\n\n- **dependencies:** Update dependencies ([#3571](https://github.com/feathersjs/feathers/issues/3571)) ([ad611cb](https://github.com/feathersjs/feathers/commit/ad611cb6ffb1dc31d603ba5817331318c5a23217))\n\n## [5.0.32](https://github.com/feathersjs/feathers/compare/v5.0.31...v5.0.32) (2025-02-01)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.31](https://github.com/feathersjs/feathers/compare/v5.0.30...v5.0.31) (2024-10-31)\n\n### Bug Fixes\n\n- **dependencies:** Update all dependencies ([#3545](https://github.com/feathersjs/feathers/issues/3545)) ([221b92b](https://github.com/feathersjs/feathers/commit/221b92bb0ee5d54fb1036742968797cb02e56da2))\n\n## [5.0.30](https://github.com/feathersjs/feathers/compare/v5.0.29...v5.0.30) (2024-09-02)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.29](https://github.com/feathersjs/feathers/compare/v5.0.28...v5.0.29) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.28](https://github.com/feathersjs/feathers/compare/v5.0.27...v5.0.28) (2024-07-10)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.27](https://github.com/feathersjs/feathers/compare/v5.0.26...v5.0.27) (2024-06-18)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.26](https://github.com/feathersjs/feathers/compare/v5.0.25...v5.0.26) (2024-06-09)\n\n### Bug Fixes\n\n- **typebox:** Add TRecord to getValidator arg1 type ([#3488](https://github.com/feathersjs/feathers/issues/3488)) ([ffbcc0a](https://github.com/feathersjs/feathers/commit/ffbcc0ad0c361f77171f9ad6224006727644433a))\n\n## [5.0.25](https://github.com/feathersjs/feathers/compare/v5.0.24...v5.0.25) (2024-05-03)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.24](https://github.com/feathersjs/feathers/compare/v5.0.23...v5.0.24) (2024-03-13)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.23](https://github.com/feathersjs/feathers/compare/v5.0.22...v5.0.23) (2024-02-25)\n\n### Bug Fixes\n\n- **core:** Update to latest feathersjs/hooks ([#3434](https://github.com/feathersjs/feathers/issues/3434)) ([1499ccc](https://github.com/feathersjs/feathers/commit/1499ccc41fb3ebba97b2c84e0cb19bc48ad3c651))\n\n## [5.0.22](https://github.com/feathersjs/feathers/compare/v5.0.21...v5.0.22) (2024-02-15)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.21](https://github.com/feathersjs/feathers/compare/v5.0.20...v5.0.21) (2024-01-25)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.20](https://github.com/feathersjs/feathers/compare/v5.0.19...v5.0.20) (2024-01-24)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.19](https://github.com/feathersjs/feathers/compare/v5.0.18...v5.0.19) (2024-01-23)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.18](https://github.com/feathersjs/feathers/compare/v5.0.17...v5.0.18) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.17](https://github.com/feathersjs/feathers/compare/v5.0.16...v5.0.17) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.16](https://github.com/feathersjs/feathers/compare/v5.0.15...v5.0.16) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.15](https://github.com/feathersjs/feathers/compare/v5.0.14...v5.0.15) (2024-01-22)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.14](https://github.com/feathersjs/feathers/compare/v5.0.13...v5.0.14) (2024-01-05)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.13](https://github.com/feathersjs/feathers/compare/v5.0.12...v5.0.13) (2023-12-29)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.12](https://github.com/feathersjs/feathers/compare/v5.0.11...v5.0.12) (2023-11-28)\n\n### Bug Fixes\n\n- **schema:** Allow $in and $nin queries to work for arrays ([#3352](https://github.com/feathersjs/feathers/issues/3352)) ([677c214](https://github.com/feathersjs/feathers/commit/677c214a353a7f9a1f90649b9bbec4d0d6517a6f))\n\n## [5.0.11](https://github.com/feathersjs/feathers/compare/v5.0.10...v5.0.11) (2023-10-11)\n\n### Bug Fixes\n\n- **knex:** Update all dependencies and Knex peer ([#3308](https://github.com/feathersjs/feathers/issues/3308)) ([d2f9860](https://github.com/feathersjs/feathers/commit/d2f986036c4741cce2339d8abbcc6b2eb037a12a))\n\n## [5.0.10](https://github.com/feathersjs/feathers/compare/v5.0.9...v5.0.10) (2023-10-03)\n\n### Bug Fixes\n\n- **typebox:** Allow default value in StringEnum ([#3281](https://github.com/feathersjs/feathers/issues/3281)) ([25af09a](https://github.com/feathersjs/feathers/commit/25af09ad065e72768bf88bc8b529b68f2ca4da17))\n\n## [5.0.9](https://github.com/feathersjs/feathers/compare/v5.0.8...v5.0.9) (2023-09-27)\n\n### Bug Fixes\n\n- **typebox:** allow TUnion<TObject[]> inside getValidator ([#3262](https://github.com/feathersjs/feathers/issues/3262)) ([cf9df96](https://github.com/feathersjs/feathers/commit/cf9df96c1011fcf13e9c6d652b06036bb0aac1c3))\n\n## [5.0.8](https://github.com/feathersjs/feathers/compare/v5.0.7...v5.0.8) (2023-07-19)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.7](https://github.com/feathersjs/feathers/compare/v5.0.6...v5.0.7) (2023-07-14)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.6](https://github.com/feathersjs/feathers/compare/v5.0.5...v5.0.6) (2023-06-15)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n## [5.0.5](https://github.com/feathersjs/feathers/compare/v5.0.4...v5.0.5) (2023-04-28)\n\n### Bug Fixes\n\n- **typebox:** Revert to TypeBox 0.25 ([#3183](https://github.com/feathersjs/feathers/issues/3183)) ([cacedf5](https://github.com/feathersjs/feathers/commit/cacedf59e3d2df836777f0cd06ab1b2484ed87c5))\n\n## [5.0.4](https://github.com/feathersjs/feathers/compare/v5.0.3...v5.0.4) (2023-04-12)\n\n### Bug Fixes\n\n- Make sure all Readme files are up to date ([#3154](https://github.com/feathersjs/feathers/issues/3154)) ([a5f0b38](https://github.com/feathersjs/feathers/commit/a5f0b38bbf2a11486415a39533bcc6c67fb51e3e))\n- **typebox:** Implement custom TypeBuilder for backwards compatibility ([#3150](https://github.com/feathersjs/feathers/issues/3150)) ([962bd87](https://github.com/feathersjs/feathers/commit/962bd87217212320b1a68f6556a16b8a6b8f757c))\n\n## [5.0.3](https://github.com/feathersjs/feathers/compare/v5.0.2...v5.0.3) (2023-04-05)\n\n### Bug Fixes\n\n- **authentication:** Ensure authentication.entity configuration can be null ([#3136](https://github.com/feathersjs/feathers/issues/3136)) ([c47349b](https://github.com/feathersjs/feathers/commit/c47349b9dcf2067b7b572c5463b15b2a8fbda972))\n- **dependencies:** Update all dependencies ([#3139](https://github.com/feathersjs/feathers/issues/3139)) ([f24276e](https://github.com/feathersjs/feathers/commit/f24276e9a909e2e58a0730c730258ce1f70f4028))\n- **knex:** Get by id and transactions should work with params.knex ([#3146](https://github.com/feathersjs/feathers/issues/3146)) ([b172b5e](https://github.com/feathersjs/feathers/commit/b172b5ea9b461642874eb7d2ba01dc4cfc275155))\n- **typebox:** Upgrade to TypeBox 0.26.0 ([#3113](https://github.com/feathersjs/feathers/issues/3113)) ([d1d9598](https://github.com/feathersjs/feathers/commit/d1d95984dd94d2b9305e7338421f84f9c4f733fd))\n\n## [5.0.1](https://github.com/feathersjs/feathers/compare/v5.0.0...v5.0.1) (2023-03-15)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n# [5.0.0](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.38...v5.0.0) (2023-02-24)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n# [5.0.0-pre.38](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.37...v5.0.0-pre.38) (2023-02-17)\n\n### Features\n\n- **schema:** Add schema helper for handling Object ids ([#3058](https://github.com/feathersjs/feathers/issues/3058)) ([1393bed](https://github.com/feathersjs/feathers/commit/1393bed81a9ee814de6aab0e537af83e667591a2))\n\n# [5.0.0-pre.37](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.36...v5.0.0-pre.37) (2023-02-09)\n\n### Bug Fixes\n\n- **typebox:** Allow nested or in and queries ([#3029](https://github.com/feathersjs/feathers/issues/3029)) ([39e0b78](https://github.com/feathersjs/feathers/commit/39e0b785238b809aa9b4dea9b95efc3c188c9baa))\n\n# [5.0.0-pre.36](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.35...v5.0.0-pre.36) (2023-01-29)\n\n### Bug Fixes\n\n- **configuration:** Add pool and connection object to SQL database default configuration ([#3023](https://github.com/feathersjs/feathers/issues/3023)) ([092c749](https://github.com/feathersjs/feathers/commit/092c749d43f7da4d019576d1210fe7d3719a44a2))\n- **schema:** Fix TypeBox extension value query syntax inference ([#3010](https://github.com/feathersjs/feathers/issues/3010)) ([f1c7a76](https://github.com/feathersjs/feathers/commit/f1c7a76586bbb8aed66ef866c3dcd666d79f3a24))\n- Update all dependencies ([#3024](https://github.com/feathersjs/feathers/issues/3024)) ([283dc47](https://github.com/feathersjs/feathers/commit/283dc4798d85584bc031e6e54b83b4ea77d1edd0))\n\n# [5.0.0-pre.35](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.34...v5.0.0-pre.35) (2023-01-12)\n\n### Features\n\n- **generators:** Move core code generators to shared generators package ([#2982](https://github.com/feathersjs/feathers/issues/2982)) ([0328d22](https://github.com/feathersjs/feathers/commit/0328d2292153870bc43958f73d2c6f288a8cec17))\n- **schema:** Allow to add additional operators to the query syntax ([#2941](https://github.com/feathersjs/feathers/issues/2941)) ([f324940](https://github.com/feathersjs/feathers/commit/f324940d5795b41e8c6fc113defb0beb7ab03a0a))\n\n# [5.0.0-pre.34](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.33...v5.0.0-pre.34) (2022-12-14)\n\n### Bug Fixes\n\n- **schema:** Allow query schemas with no properties, error on unsupported types ([#2904](https://github.com/feathersjs/feathers/issues/2904)) ([b66c734](https://github.com/feathersjs/feathers/commit/b66c734357478f51b2d38fa7f3eee08640cea26e))\n- **typebox:** Improve query syntax defaults ([#2888](https://github.com/feathersjs/feathers/issues/2888)) ([59f3cdc](https://github.com/feathersjs/feathers/commit/59f3cdca6376e34fe39a7b91db837d0325aeb5db))\n\n# [5.0.0-pre.33](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.32...v5.0.0-pre.33) (2022-11-08)\n\n### Features\n\n- **schema:** Add StringEnum to TypeBox module ([#2827](https://github.com/feathersjs/feathers/issues/2827)) ([65d3665](https://github.com/feathersjs/feathers/commit/65d36656f50a48f633fa3fcabaea10521d04bf1c))\n\n# [5.0.0-pre.32](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.31...v5.0.0-pre.32) (2022-10-26)\n\n**Note:** Version bump only for package @feathersjs/typebox\n\n# [5.0.0-pre.31](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.30...v5.0.0-pre.31) (2022-10-12)\n\n### Features\n\n- **cli:** Improve generated schema definitions ([#2783](https://github.com/feathersjs/feathers/issues/2783)) ([474a9fd](https://github.com/feathersjs/feathers/commit/474a9fda2107e9bcf357746320a8e00cda8182b6))\n\n# [5.0.0-pre.30](https://github.com/feathersjs/feathers/compare/v5.0.0-pre.29...v5.0.0-pre.30) (2022-10-07)\n\n### Features\n\n- **schema:** Make schemas validation library independent and add TypeBox support ([#2772](https://github.com/feathersjs/feathers/issues/2772)) ([44172d9](https://github.com/feathersjs/feathers/commit/44172d99b566d11d9ceda04f1d0bf72b6d05ce76))\n"
  },
  {
    "path": "packages/typebox/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Feathers Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "packages/typebox/README.md",
    "content": "# @feathersjs/typebox\n\n[![CI](https://github.com/feathersjs/feathers/workflows/CI/badge.svg)](https://github.com/feathersjs/feathers/actions?query=workflow%3ACI)\n[![Download Status](https://img.shields.io/npm/dm/@feathersjs/typebox.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/typebox)\n[![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/qa8kez8QBx)\n\n> [TypeBox](https://github.com/sinclairzx81/typebox) integration for @feathersjs/schema\n\n## Installation\n\n```\nnpm install @feathersjs/typebox --save\n```\n\n## Documentation\n\nRefer to the [Feathers TypeBox documentation](https://feathersjs.com/api/schema/typebox.html) for more details.\n\n## License\n\nCopyright (c) 2024 [Feathers contributors](https://github.com/feathersjs/feathers/graphs/contributors)\n\nLicensed under the [MIT license](LICENSE).\n"
  },
  {
    "path": "packages/typebox/package.json",
    "content": "{\n  \"name\": \"@feathersjs/typebox\",\n  \"description\": \"TypeBox integration for @feathersjs/schema\",\n  \"version\": \"5.0.42\",\n  \"homepage\": \"https://feathersjs.com\",\n  \"main\": \"lib/\",\n  \"types\": \"lib/\",\n  \"keywords\": [\n    \"feathers\",\n    \"feathers-plugin\"\n  ],\n  \"license\": \"MIT\",\n  \"funding\": {\n    \"type\": \"github\",\n    \"url\": \"https://github.com/sponsors/daffl\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/feathersjs/feathers.git\",\n    \"directory\": \"packages/schema\"\n  },\n  \"author\": {\n    \"name\": \"Feathers contributors\",\n    \"email\": \"hello@feathersjs.com\",\n    \"url\": \"https://feathersjs.com\"\n  },\n  \"contributors\": [],\n  \"bugs\": {\n    \"url\": \"https://github.com/feathersjs/feathers/issues\"\n  },\n  \"engines\": {\n    \"node\": \">= 12\"\n  },\n  \"files\": [\n    \"CHANGELOG.md\",\n    \"LICENSE\",\n    \"README.md\",\n    \"src/**\",\n    \"lib/**\",\n    \"*.d.ts\",\n    \"*.js\"\n  ],\n  \"scripts\": {\n    \"prepublish\": \"npm run compile\",\n    \"pack\": \"npm pack --pack-destination ../generators/test/build\",\n    \"compile\": \"shx rm -rf lib/ && tsc && npm run pack\",\n    \"mocha\": \"mocha --config ../../.mocharc.json --recursive test/**.test.ts test/**/*.test.ts\",\n    \"test\": \"npm run compile && npm run mocha\"\n  },\n  \"directories\": {\n    \"lib\": \"lib\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@feathersjs/schema\": \"^5.0.42\",\n    \"@sinclair/typebox\": \"^0.25.0\"\n  },\n  \"devDependencies\": {\n    \"@types/mocha\": \"^10.0.10\",\n    \"@types/node\": \"^25.3.3\",\n    \"mocha\": \"^11.7.5\",\n    \"shx\": \"^0.4.0\",\n    \"typescript\": \"^5.9.3\"\n  },\n  \"gitHead\": \"90caf635aec850550b9d37bea2762af959d9e8d5\"\n}\n"
  },
  {
    "path": "packages/typebox/src/default-schemas.ts",
    "content": "import { Type, Static } from '@sinclair/typebox'\n\nexport const authenticationSettingsSchema = Type.Object({\n  secret: Type.String({ description: 'The JWT signing secret' }),\n  entity: Type.Optional(\n    Type.Union([\n      Type.String({ description: 'The name of the authentication entity (e.g. user)' }),\n      Type.Null()\n    ])\n  ),\n  entityId: Type.Optional(Type.String({ description: 'The name of the authentication entity id property' })),\n  service: Type.Optional(Type.String({ description: 'The path of the entity service' })),\n  authStrategies: Type.Array(Type.String(), {\n    description: 'A list of authentication strategy names that are allowed to create JWT access tokens'\n  }),\n  parseStrategies: Type.Optional(\n    Type.Array(Type.String(), {\n      description:\n        'A list of authentication strategy names that should parse HTTP headers for authentication information (defaults to `authStrategies`)'\n    })\n  ),\n  jwtOptions: Type.Optional(Type.Object({})),\n  jwt: Type.Optional(\n    Type.Object({\n      header: Type.String({ default: 'Authorization', description: 'The HTTP header containing the JWT' }),\n      schemes: Type.String({ description: 'An array of schemes to support' })\n    })\n  ),\n  local: Type.Optional(\n    Type.Object({\n      usernameField: Type.String({ description: 'Name of the username field (e.g. `email`)' }),\n      passwordField: Type.String({ description: 'Name of the password field (e.g. `password`)' }),\n      hashSize: Type.Optional(Type.Number({ description: 'The BCrypt salt length' })),\n      errorMessage: Type.Optional(Type.String({ description: 'The error message to return on errors' })),\n      entityUsernameField: Type.Optional(\n        Type.String({\n          description:\n            'Name of the username field on the entity if authentication request data and entity field names are different'\n        })\n      ),\n      entityPasswordField: Type.Optional(\n        Type.String({\n          description:\n            'Name of the password field on the entity if authentication request data and entity field names are different'\n        })\n      )\n    })\n  ),\n  oauth: Type.Optional(\n    Type.Object({\n      redirect: Type.Optional(Type.String()),\n      origins: Type.Optional(Type.Array(Type.String())),\n      defaults: Type.Optional(\n        Type.Object({\n          key: Type.Optional(Type.String()),\n          secret: Type.Optional(Type.String())\n        })\n      )\n    })\n  )\n})\n\nexport const sqlSettingsSchema = Type.Optional(\n  Type.Object({\n    client: Type.String(),\n    connection: Type.Union([\n      Type.String(),\n      Type.Partial(\n        Type.Object({\n          host: Type.String(),\n          port: Type.Number(),\n          user: Type.String(),\n          password: Type.String(),\n          database: Type.String()\n        })\n      )\n    ]),\n    pool: Type.Optional(\n      Type.Object({\n        min: Type.Number(),\n        max: Type.Number()\n      })\n    )\n  })\n)\n\nexport const defaultAppConfiguration = Type.Object(\n  {\n    authentication: Type.Optional(authenticationSettingsSchema),\n    paginate: Type.Optional(\n      Type.Object(\n        {\n          default: Type.Number(),\n          max: Type.Number()\n        },\n        { additionalProperties: false }\n      )\n    ),\n    origins: Type.Optional(Type.Array(Type.String())),\n    mongodb: Type.Optional(Type.String()),\n    mysql: sqlSettingsSchema,\n    postgresql: sqlSettingsSchema,\n    sqlite: sqlSettingsSchema,\n    mssql: sqlSettingsSchema\n  },\n  { $id: 'ApplicationConfiguration', additionalProperties: false }\n)\n\nexport type DefaultAppConfiguration = Static<typeof defaultAppConfiguration>\n"
  },
  {
    "path": "packages/typebox/src/index.ts",
    "content": "import {\n  Type,\n  TObject,\n  TInteger,\n  TOptional,\n  TSchema,\n  ObjectOptions,\n  TIntersect,\n  TUnion,\n  type TRecord\n} from '@sinclair/typebox'\nimport { jsonSchema, Validator, DataValidatorMap, Ajv } from '@feathersjs/schema'\n\nexport * from '@sinclair/typebox'\nexport * from './default-schemas'\n\nexport type TDataSchemaMap = {\n  create: TObject\n  update?: TObject\n  patch?: TObject\n}\n\n/**\n * Returns a compiled validation function for a TypeBox object and AJV validator instance.\n *\n * @param schema The JSON schema definition\n * @param validator The AJV validation instance\n * @returns A compiled validation function\n */\nexport const getValidator = <T = any, R = T>(\n  schema: TObject | TIntersect | TUnion<TObject[]> | TRecord,\n  validator: Ajv\n): Validator<T, R> => jsonSchema.getValidator(schema as any, validator)\n\n/**\n * Returns compiled validation functions to validate data for the `create`, `update` and `patch`\n * service methods. If not passed explicitly, the `update` validator will be the same as the `create`\n * and `patch` will be the `create` validator with no required fields.\n *\n * @param def Either general TypeBox object definition or a mapping of `create`, `update` and `patch`\n * to their respective type object\n * @param validator The Ajv instance to use as the validator\n * @returns A map of validator functions\n */\nexport const getDataValidator = (def: TObject | TDataSchemaMap, validator: Ajv): DataValidatorMap =>\n  jsonSchema.getDataValidator(def as any, validator)\n\n/**\n * A TypeBox utility that converts an array of provided strings into a string enum.\n * @param allowedValues array of strings for the enum\n * @returns TypeBox.Type\n */\nexport function StringEnum<T extends string[]>(allowedValues: [...T], options?: { default: T[number] }) {\n  return Type.Unsafe<T[number]>({ type: 'string', enum: allowedValues, ...options })\n}\n\nconst arrayOfKeys = <T extends TObject>(type: T) => {\n  const keys = Object.keys(type.properties)\n  return Type.Unsafe<(keyof T['properties'])[]>({\n    type: 'array',\n    maxItems: keys.length,\n    items: {\n      type: 'string',\n      ...(keys.length > 0 ? { enum: keys } : {})\n    }\n  })\n}\n\n/**\n * Creates the `$sort` Feathers query syntax schema for an object schema\n *\n * @param schema The TypeBox object schema\n * @returns The `$sort` syntax schema\n */\nexport function sortDefinition<T extends TObject>(schema: T) {\n  const properties = Object.keys(schema.properties).reduce(\n    (res, key) => {\n      const result = res as any\n\n      result[key] = Type.Optional(Type.Integer({ minimum: -1, maximum: 1 }))\n\n      return result\n    },\n    {} as { [K in keyof T['properties']]: TOptional<TInteger> }\n  )\n\n  return Type.Object(properties, { additionalProperties: false })\n}\n\n/**\n * Returns the standard Feathers query syntax for a property schema,\n * including operators like `$gt`, `$lt` etc. for a single property\n *\n * @param def The property definition\n * @param extension Additional properties to add to the property query\n * @returns The Feathers query syntax schema\n */\nexport const queryProperty = <T extends TSchema, X extends { [key: string]: TSchema }>(\n  def: T,\n  extension: X = {} as X\n) =>\n  Type.Optional(\n    Type.Union([\n      def,\n      Type.Partial(\n        Type.Intersect(\n          [\n            Type.Object({\n              $gt: def,\n              $gte: def,\n              $lt: def,\n              $lte: def,\n              $ne: def,\n              $in: def.type === 'array' ? def : Type.Array(def),\n              $nin: def.type === 'array' ? def : Type.Array(def)\n            }),\n            Type.Object(extension)\n          ],\n          { additionalProperties: false }\n        )\n      )\n    ])\n  )\n\ntype QueryProperty<T extends TSchema, X extends { [key: string]: TSchema }> = ReturnType<\n  typeof queryProperty<T, X>\n>\n\n/**\n * Creates a Feathers query syntax schema for the properties defined in `definition`.\n *\n * @param definition The properties to create the Feathers query syntax schema for\n * @param extensions Additional properties to add to a property query\n * @returns The Feathers query syntax schema\n */\nexport const queryProperties = <\n  T extends TObject,\n  X extends { [K in keyof T['properties']]?: { [key: string]: TSchema } }\n>(\n  definition: T,\n  extensions: X = {} as X\n) => {\n  const properties = Object.keys(definition.properties).reduce(\n    (res, key) => {\n      const result = res as any\n      const value = definition.properties[key]\n\n      result[key] = queryProperty(value, extensions[key])\n\n      return result\n    },\n    {} as { [K in keyof T['properties']]: QueryProperty<T['properties'][K], X[K]> }\n  )\n\n  return Type.Optional(Type.Object(properties, { additionalProperties: false }))\n}\n\n/**\n * Creates a TypeBox schema for the complete Feathers query syntax including `$limit`, $skip`, `$or`\n * and `$sort` and `$select` for the allowed properties.\n *\n * @param type The properties to create the query syntax for\n * @param extensions Additional properties to add to the query syntax\n * @param options Options for the TypeBox object schema\n * @returns A TypeBox object representing the complete Feathers query syntax for the given properties\n */\nexport const querySyntax = <\n  T extends TObject,\n  X extends { [K in keyof T['properties']]?: { [key: string]: TSchema } }\n>(\n  type: T,\n  extensions: X = {} as X,\n  options: ObjectOptions = { additionalProperties: false }\n) => {\n  const propertySchema = queryProperties(type, extensions)\n  const $or = Type.Array(propertySchema)\n  const $and = Type.Array(Type.Union([propertySchema, Type.Object({ $or })]))\n\n  return Type.Intersect(\n    [\n      Type.Partial(\n        Type.Object(\n          {\n            $limit: Type.Number({ minimum: 0 }),\n            $skip: Type.Number({ minimum: 0 }),\n            $sort: sortDefinition(type),\n            $select: arrayOfKeys(type),\n            $and,\n            $or\n          },\n          { additionalProperties: false }\n        )\n      ),\n      propertySchema\n    ],\n    options\n  )\n}\n\nexport const ObjectIdSchema = () =>\n  Type.Union([Type.String({ objectid: true }), Type.Object({}, { additionalProperties: true })])\n"
  },
  {
    "path": "packages/typebox/test/index.test.ts",
    "content": "import assert from 'assert'\nimport { ObjectId as MongoObjectId } from 'mongodb'\nimport { Ajv } from '@feathersjs/schema'\nimport {\n  querySyntax,\n  Type,\n  Static,\n  defaultAppConfiguration,\n  getDataValidator,\n  getValidator,\n  ObjectIdSchema\n} from '../src'\n\ndescribe('@feathersjs/schema/typebox', () => {\n  describe('querySyntax', () => {\n    it('basics', async () => {\n      const schema = Type.Object({\n        name: Type.String(),\n        age: Type.Number()\n      })\n      const querySchema = querySyntax(schema)\n\n      type Query = Static<typeof querySchema>\n\n      const query: Query = {\n        name: 'Dave',\n        age: { $gt: 42, $in: [50, 51] },\n        $select: ['age', 'name'],\n        $sort: {\n          age: 1\n        }\n      }\n\n      const validator = new Ajv().compile(querySchema)\n      let validated = (await validator(query)) as any as Query\n\n      assert.ok(validated)\n\n      validated = (await validator({ ...query, something: 'wrong' })) as any as Query\n      assert.ok(!validated)\n    })\n\n    it('querySyntax works with no properties', async () => {\n      const schema = querySyntax(Type.Object({}))\n\n      new Ajv().compile(schema)\n    })\n\n    it('query syntax can include additional extensions', async () => {\n      const schema = Type.Object({\n        name: Type.String(),\n        age: Type.Number()\n      })\n      const querySchema = querySyntax(schema, {\n        age: {\n          $notNull: Type.Boolean()\n        },\n        name: {\n          $ilike: Type.String()\n        }\n      })\n      const validator = new Ajv().compile(querySchema)\n\n      type Query = Static<typeof querySchema>\n\n      const query: Query = {\n        age: {\n          $gt: 10,\n          $notNull: true\n        },\n        name: {\n          $gt: 'David',\n          $ilike: 'Dave'\n        }\n      }\n\n      const validated = (await validator(query)) as any as Query\n\n      assert.ok(validated)\n    })\n  })\n\n  it('$in and $nin works with array type', async () => {\n    const schema = Type.Object({\n      things: Type.Array(Type.Number())\n    })\n    const querySchema = querySyntax(schema)\n    const validator = new Ajv().compile(querySchema)\n\n    type Query = Static<typeof querySchema>\n\n    const query: Query = {\n      things: {\n        $in: [10, 20],\n        $nin: [30]\n      }\n    }\n\n    const validated = (await validator(query)) as any as Query\n\n    assert.ok(validated)\n  })\n\n  it('defaultAppConfiguration', async () => {\n    const configSchema = Type.Intersect([\n      defaultAppConfiguration,\n      Type.Object({\n        host: Type.String(),\n        port: Type.Number(),\n        public: Type.String()\n      })\n    ])\n\n    const validator = new Ajv().compile(configSchema)\n    const validated = await validator({\n      host: 'something',\n      port: 3030,\n      public: './'\n    })\n\n    assert.ok(validated)\n  })\n\n  // Test ObjectId validation\n  it('ObjectId', async () => {\n    const schema = Type.Object({\n      _id: ObjectIdSchema()\n    })\n\n    const validator = new Ajv({\n      strict: false\n    }).compile(schema)\n    const validated = await validator({\n      _id: '507f191e810c19729de860ea'\n    })\n    assert.ok(validated)\n\n    const validated2 = await validator({\n      _id: new MongoObjectId()\n    })\n    assert.ok(validated2)\n  })\n\n  it('validators', () => {\n    assert.strictEqual(typeof getDataValidator(Type.Object({}), new Ajv()), 'object')\n    assert.strictEqual(typeof getValidator(Type.Object({}), new Ajv()), 'function')\n    assert.strictEqual(\n      typeof getValidator(Type.Intersect([Type.Object({}), Type.Object({})]), new Ajv()),\n      'function'\n    )\n  })\n})\n"
  },
  {
    "path": "packages/typebox/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig\",\n  \"include\": [\n    \"src/**/*.ts\"\n  ],\n  \"compilerOptions\": {\n    \"outDir\": \"lib\"    \n  }\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    // TODO: We should remove this but lib types break all the time\n    \"skipLibCheck\": true,\n    /* Basic Options */\n    \"target\": \"es2018\",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */\n    \"module\": \"commonjs\",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */\n    // \"lib\": [],                             /* Specify library files to be included in the compilation. */\n    // \"allowJs\": true,                       /* Allow javascript files to be compiled. */\n    // \"checkJs\": true,                       /* Report errors in .js files. */\n    // \"jsx\": \"preserve\",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */\n    \"declaration\": true,                   /* Generates corresponding '.d.ts' file. */\n    // \"declarationMap\": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */\n    \"sourceMap\": true,                     /* Generates corresponding '.map' file. */\n    // \"outFile\": \"./\",                       /* Concatenate and emit output to single file. */\n    // \"rootDir\": \"./src\",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */\n    // \"composite\": true,                     /* Enable project compilation */\n    // \"removeComments\": true,                /* Do not emit comments to output. */\n    // \"noEmit\": true,                        /* Do not emit outputs. */\n    // \"importHelpers\": true,                 /* Import emit helpers from 'tslib'. */\n    // \"downlevelIteration\": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */\n    // \"isolatedModules\": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */\n\n    /* Strict Type-Checking Options */\n    \"strict\": true,                           /* Enable all strict type-checking options. */\n    // \"noImplicitAny\": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */\n    \"strictNullChecks\": false,              /* Enable strict null checks. */\n    // \"strictFunctionTypes\": true,           /* Enable strict checking of function types. */\n    // \"strictPropertyInitialization\": true,  /* Enable strict checking of property initialization in classes. */\n    // \"noImplicitThis\": true,                /* Raise error on 'this' expressions with an implied 'any' type. */\n    // \"alwaysStrict\": true,                  /* Parse in strict mode and emit \"use strict\" for each source file. */\n\n    /* Additional Checks */\n    \"noUnusedLocals\": true,                /* Report errors on unused locals. */\n    \"noUnusedParameters\": true,            /* Report errors on unused parameters. */\n    \"noImplicitReturns\": true,             /* Report error when not all code paths in function return a value. */\n    // \"noFallthroughCasesInSwitch\": true,    /* Report errors for fallthrough cases in switch statement. */\n\n    /* Module Resolution Options */\n    // \"moduleResolution\": \"node\",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */\n    // \"baseUrl\": \"./\",                       /* Base directory to resolve non-absolute module names. */\n    // \"paths\": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */\n    // \"rootDirs\": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */\n    // \"typeRoots\": [],                       /* List of folders to include type definitions from. */\n    // \"types\": [],                           /* Type declaration files to be included in compilation. */\n    // \"allowSyntheticDefaultImports\": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */\n    \"esModuleInterop\": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */\n    // \"preserveSymlinks\": true,              /* Do not resolve the real path of symlinks. */\n\n    /* Source Map Options */\n    // \"sourceRoot\": \"\",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */\n    // \"mapRoot\": \"\",                         /* Specify the location where debugger should locate map files instead of generated locations. */\n    // \"inlineSourceMap\": true,               /* Emit a single file with source maps instead of having a separate file. */\n    // \"inlineSources\": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */\n\n    /* Experimental Options */\n    // \"experimentalDecorators\": true,        /* Enables experimental support for ES7 decorators. */\n    // \"emitDecoratorMetadata\": true,         /* Enables experimental support for emitting type metadata for decorators. */\n  }\n}"
  }
]